1
votes

I am using Microsoft.Office.Interop.Word package to add a table in Word Document.

I have already created a table OUTERTABLE *(3*3)*.

Now I want to include another table INNERTABLE (2*2) inside this OUTERTABLE at cell(2,2).

Following is the code I have:

        public object InvokeMethod(object obj, string memberName, object[] objParam)
        {
            return InvokeMember(obj, memberName, BindingFlags.InvokeMethod, objParam);
        }

        public object SetProperty(object obj, string memberName, object[] objParam)
        {
            return InvokeMember(obj, memberName, BindingFlags.SetProperty, objParam);
        }

        public object GetProperty(object obj, string memberName, object[] objParam)
        {
            return InvokeMember(obj, memberName, BindingFlags.GetProperty, objParam);
        }

        public object InvokeMember(object obj, string memberName, BindingFlags flag, object[] objParam)
        {
            // mzimmers 2015 06 29: needed this for something I can't now remember.
            try
            {
                return obj.GetType().InvokeMember(memberName, flag, null, obj, objParam);
            }
            catch(Exception ex)
            {
                throw ex;
            }
        }
                object oOuterTable = InvokeMethod(oDocTables, "Add", new object[] { wrdRng, 3, 3, oMissing, oMissing });

                //Word.Table oTable = oDoc.Tables.Add(wrdRng, ai_row, ai_col, ref oMissing, ref oMissing);
                oGalleryOuterTable = oOuterTable;

                object objCell = InvokeMethod(oGalleryOuterTable, "Cell", new object[] { 2, 2 });
                object objTR = GetProperty(objCell, "Range", null);

                SetProperty(objTR, "Start", new object[] { });

                object tblRng = InvokeMethod(objCell, "SetRange", new object[] { objTR, objTR });


                object oTable = InvokeMethod(oGalleryOuterTable, "Add", new object[] { tblRng, ai_row, ai_col, oMissing, oMissing });

I Googled and found this article:

https://social.msdn.microsoft.com/Forums/vstudio/en-US/2d31deb7-1874-4c14-8928-ad97456e8dad/insert-table-to-specific-cell-in-microsoftofficeinteropword?forum=vsto

wrdRng.SetRange(OUTERTABLE.Cell(2, 2).Range.Start, OUTERTABLE.Cell(2, 2).Range.Start);

I want to replicate the above method by using objects and above Get, Set, Invoke Methods. I am stuck at setting "Range.Start" part.

Not sure how to fix this. Can anyone help me on this? I am not sure about the solution given in that link either.

2
The solution in the link is still correct. I could give you some sample code, but from the code you show us it's not clear whether you intend to use the Word object model with early or with late binding? You mix direct calls with PInvoke - any particular reason? And is C# really allowing that last line without an explicit conversion from object to Word.Table? - Cindy Meister
I use late binding - blackfury
You've marked the other contribution as the Answer - do you still need the code using PInvoke? - Cindy Meister
@CindyMeister: yeah, that would help a lot... I am still trying to use the below answer to as a reference and havnt found success yet - blackfury

2 Answers

1
votes

According to your comments, I've updated my solution so it's only using PInvoke I've also added some new Get/SetProperty constructors

 class Program
{
    public static object GetProperty(object obj, string memberName, object[] objParam)
    {
        return InvokeMember(obj, memberName, BindingFlags.GetProperty, objParam);
    }
    public static object SetProperty(object obj, string memberName, object[] objParam)
    {
        return InvokeMember(obj, memberName, BindingFlags.SetProperty, objParam);
    }

    public static void SetProperty(object obj, string sProperty, object oValue)
    {
        object[] oParam = new object[1];
        oParam[0] = oValue;
       obj.GetType().InvokeMember(sProperty, BindingFlags.SetProperty, null, obj, oParam);
    }

    public static object InvokeMethod(object obj, string memberName, object[] objParam)
    {
        return InvokeMember(obj, memberName, BindingFlags.InvokeMethod, objParam);
    }

    public static object InvokeMember(object obj, string memberName, BindingFlags flag, object[] objParam)
    {
        try
        {
            return obj.GetType().InvokeMember(memberName, flag, null, obj, objParam);
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
    public static  object InvokeMethod(object obj, string sProperty, object oValue)
    {
        object[] oParam = new object[1];
        oParam[0] = oValue;
        return obj.GetType().InvokeMember
        (sProperty, BindingFlags.InvokeMethod, null, obj, oParam);
    }
    public static  object GetProperty(object obj, string sProperty, object oValue)
    {
        object[] oParam = new object[1];
        oParam[0] = oValue;
        return obj.GetType().InvokeMember
            (sProperty, BindingFlags.GetProperty, null, obj, oParam);
    }
    public static object GetProperty(object obj, string sProperty)
    {
        return obj.GetType().InvokeMember
        (sProperty, BindingFlags.GetProperty, null, obj, null);
    }
    static void Main(string[] args)
    {

        Application oWord = new Application();
        try
        {
            Document oDoc;

            oWord.Visible = true;
            object oMissing = System.Reflection.Missing.Value;
            object oEndOfDoc = "\\endofdoc"; /* \endofdoc is a predefined bookmark */

            oDoc = oWord.Documents.Add(ref oMissing, ref oMissing,
               ref oMissing, ref oMissing);
            Range wrdRng = oDoc.Bookmarks.get_Item(ref oEndOfDoc).Range;
            object outerTables = GetProperty(wrdRng, "Tables");
            object oTable = InvokeMethod(outerTables, "Add", new object[] { wrdRng, 3, 3, oMissing, oMissing });

            var outerBorders = GetProperty(oTable, "Borders");

            SetProperty(outerBorders, "OutsideLineStyle", 1);//WdLineStyle.wdLineStyleSingle = 1
            SetProperty(outerBorders, "OutsideColor", 0); //WdColor.wdColorBlack = 0
            SetProperty(oTable, "TableDirection",1 );//WdTableDirection.wdTableDirectionLtr=1
            SetProperty(outerBorders, "InsideLineStyle", 1);//WdLineStyle.wdLineStyleSingle=1
            SetProperty(outerBorders, "InsideColor", 0);//WdColor.wdColorBlack = 0
            object oDocTables = oDoc.Tables;
            object oOuterTable = InvokeMethod(oDocTables, "Add", new object[] { wrdRng, 3, 3, oMissing, oMissing });

            object objCell = InvokeMethod(oTable, "Cell", new object[] { 2, 2 });
            object objTR = GetProperty(objCell, "Range", null);

            object Start = GetProperty(objTR, "Start", null);
           InvokeMethod(wrdRng, "SetRange", new object[] { Start, Start });
            object innerTables = GetProperty(oOuterTable, "Tables", null);


            object iTable = InvokeMethod(innerTables, "Add", new object[] { wrdRng, 2, 2, oMissing, oMissing });
            var  innerBorders = GetProperty(iTable, "Borders");

           SetProperty(innerBorders, "OutsideLineStyle", 1);
            SetProperty(innerBorders, "OutsideColor", 0);
            SetProperty(iTable, "TableDirection", 1);
            SetProperty(innerBorders, "InsideLineStyle", 1);
            SetProperty(innerBorders, "InsideColor", 0);


        }
        catch (Exception ex)
        {

            throw ex;
        }
        finally
        {
           // oWord.Quit();
        }
    }

}

which results in :

screenshot

1
votes

Well, here is everything using PInvoke, except getting the document object, since you don't show us how you do that.

I note that your code, as well as that of Xavave, uses a member of the Word object model rather than a object from PInvoke for the target Range for the inserted table. I understood you wanted everything in PInvoke... and you ask explicitly for the way to get the Range.

I also don't see how the additional rows are inserted in the other Answer - as far as I can see, that code isn't there. But it's also clear that this was run in a newer version of Word that may not have the limitation.

Anyway, my code uses PInvoke throughout... I leave out the code for setting borders, as it's extraneous to your question of how to add table rows to a newly created nested table and distracts from the main question.

        object oDoc = (object) doc;
        object[] oArgs = null;
        object[] oArgsItem = {1};
        object oDocTables = oDoc.GetType().InvokeMember("Tables", BindingFlags.GetProperty, null, oDoc, oArgs);
        object oOuterTable = InvokeMethod(oDocTables, "Item", oArgsItem);
        object oTargetCell = InvokeMethod(oOuterTable, "Cell", new object[] { 2, 2 });
        object oCellRange = InvokeMember(oTargetCell, "Range", BindingFlags.GetProperty, oArgs);
        object oNestedTable = InvokeMethod(oDocTables, "Add", new object[] {oCellRange, 3, 3, missing, missing} );
        object oTableRows = InvokeMember(oNestedTable, "Rows", BindingFlags.GetProperty, oArgs);
        InvokeMethod(oTableRows, "Add", new object[] { });