'Embedding MS-Office Documents Into AutoCAD Drawings Using Design Automation

I have a need to embed MS-Office documents (Excel, Word) into AutoCAD using Design Automation. Searching around the web, it seems that this is not possible because the MS-Office applications, which would act as an OLE Client, would need to be running on the Forge Server. Could someone confirm that this is the case?

If I am correct in my above statement, my next best alternative would be to embed .EMF files created from each page of the document I want to embed; alternatively using raster images would also be acceptable. Creating the .EMF or raster files is not a problem. I just can't find a solution for embedding the file that does not involve copying them to the clipboard and using the PASTECLIP command. This approach has worked for me in the AutoCAD application using a C# AutoCAD.NET plugin, an OLE2Frame object is created, but it fails in accoreconsole (because PASTECLIP uses a UI class which is not available). This leads me to think that the same would occur while running the bundle in Design Automation.

The best I have been able achieve so far is to write a raster image files to the working directory and linking the raster images to the AutoCAD document using RasterImageDef and RasterImage (code below). Is this the only way I can do this? Can I do something similar using an EMF image, which is vector based, instead of a raster image? Or is there a way to actually embed an EMF (preferred) or raster image instead of just linking the images?

The code below fails if I use .EMF files, because RasterImageDef and RasterImage do not support the the EMF file; the EMF file being a vector format, not a raster format?

[CommandMethod("TEST")]
public void Test()
{
    Document doc = Application.DocumentManager.MdiActiveDocument;
    Database db = doc.Database;
    Editor ed = doc.Editor;

    // Get the file name of the image using the editor to prompt for the file name
    // Create the prompt
    PromptOpenFileOptions options = new PromptOpenFileOptions("Enter Sequence file path");
    options.PreferCommandLine = true;

    // Get the file name, use no quotes
    PromptFileNameResult result = null;
    try { result = ed.GetFileNameForOpen(options); }
    catch (System.Exception ex)
    {
        DisplayLogMessage($"Could not get sequence file location. Exception: {ex.Message}.", ed);
        return;
    }

    // Get the rtf filename from the results
    string filename = result.StringResult;

    DisplayLogMessage($"Got sequence filename: {filename}", ed);

    // Load the Sequence.rtf document
    Aspose.Words.Document seq;
    using (FileStream st = new FileStream(filename, FileMode.Open))
    {
        seq = new Aspose.Words.Document(st);
        st.Close();
    }

    DisplayLogMessage($"Aspose.Words Loaded: {filename}", ed);

    Transaction trans = db.TransactionManager.StartTransaction();

    // Get or create the image dictionary
    ObjectId imageDictId = RasterImageDef.GetImageDictionary(db);
    if (imageDictId != null)
        imageDictId = RasterImageDef.CreateImageDictionary(db);

    // Open the Image Dictonary
    DBDictionary imageDict = (DBDictionary)trans.GetObject(imageDictId, OpenMode.ForRead);

    double x = 0.0;
    double y = 0.0;

    try
    {
        // For each page in the Sequence.
        for (int i = 0; i < seq.PageCount; i++)
        {

            DisplayLogMessage($"Starting page {i + 1}", ed);

            // extract the page.
            Aspose.Words.Document newSeq = seq.ExtractPages(i, 1);
            Aspose.Words.Saving.ImageSaveOptions imgOptions = new Aspose.Words.Saving.ImageSaveOptions(Aspose.Words.SaveFormat.Emf);
            imgOptions.Resolution = 300;

            DisplayLogMessage($"Extracted page {i + 1}", ed);

            string dictName = Guid.NewGuid().ToString();
            filename = Path.Combine(Path.GetDirectoryName(doc.Name), dictName + ".Emf");

            // Save the image
            SaveOutputParameters sp = newSeq.Save(filename, imgOptions);
            DisplayLogMessage($"Saved {dictName}.Emf", ed);

            RasterImageDef imageDef = null;
            ObjectId imageDefId;

            // see if my guid is in there
            if (imageDict.Contains(dictName))
                imageDefId = (ObjectId)imageDict.GetAt(dictName);
            else
            {

                // Create an image def
                imageDef = new RasterImageDef();
                imageDef.SourceFileName = $"./{dictName}.Emf";
                // load the image
                imageDef.Load();
                imageDict.UpgradeOpen();
                imageDefId = imageDict.SetAt(dictName, imageDef);
                trans.AddNewlyCreatedDBObject(imageDef, true);
            }

            // create raster image to reference the definition
            RasterImage image = new RasterImage();
            image.ImageDefId = imageDefId;

            // Prepare orientation
            Vector3d uCorner = new Vector3d(8.5, 0, 0);
            Vector3d vOnPlane = new Vector3d(0, 11, 0);
            Point3d ptInsert = new Point3d(x, y, 0);
            x += 8.5;
            CoordinateSystem3d coordinateSystem = new CoordinateSystem3d(ptInsert, uCorner, vOnPlane);
            image.Orientation = coordinateSystem;
            
            // some other stuff
            image.ImageTransparency = true;
            image.ShowImage = true;                    

            // Add the image to ModelSpace
            BlockTable bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead);
            BlockTableRecord btr = (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
            btr.AppendEntity(image);
            trans.AddNewlyCreatedDBObject(image, true);

            // Create a reactor between the RasterImage
            // and the RasterImageDef to avoid the "Unreferenced"
            // warning the XRef palette
            RasterImage.EnableReactors(true); // in the original was true
            image.AssociateRasterDef(imageDef);

        }
        trans.Commit();
    }
    catch (System.Exception ex)
    {
        DisplayLogMessage("ERROR: " + ex.Message,ed);
        trans.Abort();
    }            

}


Solution 1:[1]

Raster images are always linked. There's no way to embed them. The only way to embed an image is to use AcDbOle2Frame (C++) or Autodesk.AutoCAD.DatabaseServices.Ole2Frame (C#). In theory, it is possible to create these objects without the "OLE server" being present but I haven't tried so I don't know if enough APIs are exposed to make it happen. You should try it and see how far you can get.

Albert

Solution 2:[2]

There is way to embed raster image, it is not straightforeward, you need to use C++\ObjectARX API, please refer this https://github.com/MadhukarMoogala/EmbedRasterImage/tree/EmbedRasterImageUsingDBX

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Albert Szilvasy
Solution 2 Madhukar Moogala