Word automation - opening a document in non-visible mode

Hi all, I need to open a word document and perform various operations on it using Word automation with COM objects in C++. I have succeeded in doing everything I set out to do, except for one problem. When I open the document through my code, the MS Word GUI opens as well. This is achieved my calling the "Open" method with only one parameter - the filename.

I know where the problem is. According to the VBA documentation in MS Word 2007, the Open method in the Documents object takes several other optional parameters. The 13th parameter is a "Visible" flag. The problem is that I can't seem to pass anything more than a single parameter to the Open method without getting a "Type mismatch" error. My code is below:
[code]
HRESULT gveMSWordController::Open(const gveString& in_szFilename)
{
VARIANT result;
HRESULT hr;

VARIANT fname;
VariantInit(&fname);
fname.vt = VT_BSTR; // set variant type to BSTR string
fname.bstrVal = SysAllocString(in_szFilename);

// GetDocuments
hr=OLEMethod(DISPATCH_PROPERTYGET, &result, m_pWApp, L"Documents", 0);
m_pDocumentsCollection = result.pdispVal;

// Open Document
VARIANT l_varOptional;
VariantInit(&l_varOptional);
l_varOptional.vt = VT_ERROR;
l_varOptional.lVal = (long)DISP_E_PARAMNOTFOUND;
VARIANT l_varFalse;
VariantInit(&l_varFalse);
l_varFalse.vt = VT_BOOL;
l_varFalse.boolVal = FALSE;

//hr=OLEMethod(DISPATCH_METHOD, &result, m_pDocumentsCollection, L"Open", 1, fname);
hr=OLEMethod(DISPATCH_METHOD, &result, m_pDocumentsCollection, L"Open", 2, fname, l_varFalse/*, l_varFalse, l_varFalse, l_varOptional, l_varOptional, l_varFalse, l_varOptional, l_varOptional, l_varOptional, l_varOptional, l_varOptional, l_varFalse*/);
m_pDocument = result.pdispVal;

return hr;
}

HRESULT gveMSWordController::OLEMethod(int nType, VARIANT *pvResult, IDispatch *pDisp,LPOLESTR ptName, int cArgs...)
{
if(!pDisp) return E_FAIL;
VariantInit(pvResult);

va_list marker;
va_start(marker, cArgs);

DISPPARAMS dp = { NULL, NULL, 0, 0 };
DISPID dispidNamed = DISPID_PROPERTYPUT;
DISPID dispID;
char szName[200];

// Convert down to ANSI
WideCharToMultiByte(CP_ACP, 0, ptName, -1, szName, 256, NULL, NULL);

// Get DISPID for name passed...
HRESULT hr= pDisp->GetIDsOfNames(IID_NULL, &ptName, 1,
LOCALE_USER_DEFAULT, &dispID);
if(FAILED(hr)) {
return hr;
}
// Allocate memory for arguments...
VARIANT *pArgs = new VARIANT[cArgs+1];
// Extract arguments...
for(int i=0; iInvoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT,
nType, &dp, pvResult, NULL, NULL);
if(FAILED(hr)) {
return hr;
}

// End variable-argument section...
va_end(marker);
delete [] pArgs;
return hr;
}
[/code]
any help would be greatly appreciated. Thanks!

Comments

  • According to

    [link=http://support.microsoft.com/kb/196776]http://support.microsoft.com/kb/196776[/link]

    omitted optional arguments should be initialized as:

    [code]VARIANT varOpt;
    varOpt.vt = VT_ERROR;
    varOpt.scode = DISP_E_PARAMNOTFOUND;[/code]

    that is, DISP_E_PARAMNOTFOUND should be assigned to varOpt.scode

    One other thing. Your OLEMethod seems to be based on AutoWrap in

    [link=http://support.microsoft.com/kb/238393]http://support.microsoft.com/kb/238393[/link]

    and there's a note there which I too missed at first:

    [color=Blue]Therefore, when you use call AutoWrap to invoke a function with more than one argument, you must pass them in reverse order as illustrated in the sample with the call to invoke DocumentProperties::Add:
    [/color]

    Oh and the Visible argument seems to be the 12th, not 13th.

    hope that solves your problem

  • I have the same exact problem
    I can successfully open a word document when passing 1 argument
    But I cannot open a word document using the full 17 argument call
    I reversed the order (see below code)

    I believe that the MS documentation is wrong.
    Maybe what they say is optional is actually required
    What are legal values for some of these parameters

    Say for the Format parameter
    The MS Documentation says:
    Can be one of the following WdOpenFormat constants
    Where can I get a C header file listing these constants?

    Is there a way to get the actual error message?
    IE: you have the wrong number of parameters
    The format of parameter X is wrong
    Calling the system routine GetLastError() doesn't help

    I have MS-Word 2002

    Please help
    Email me for the full sample program
    Thanks



    VARIANT result;
    VariantInit(&result);

    VARIANT fname;
    VariantInit(&fname);
    fname.vt = VT_BSTR;
    fname.bstrVal = ::SysAllocString("c:\temp\test.doc");

    VARIANT vTrue;
    vTrue.vt = VT_BOOL;
    vTrue.boolVal = TRUE;

    VARIANT vFalse;
    vFalse.vt = VT_BOOL;
    vFalse.boolVal = FALSE;

    VARIANT vOptional;
    VariantInit(&vOptional);
    vOptional.vt = VT_ERROR;
    vOptional.scode = DISP_E_PARAMNOTFOUND;

    //hr = AutoWrap1(DISPATCH_METHOD, &result, pDocs, L"Open", fname);
    hr = AutoWrap(DISPATCH_METHOD, &result, pDocs, L"Open", 17,
    vTrue, // 16 optional NoEncodingDialog
    vOptional, // 15 ??? DocumentDirection
    vFalse, // 14 optional OpenAndRepair
    vOptional, // 13 optional OpenConflictDocument
    vFalse, // 12 optional Visible
    vOptional, // 11 optional Encoding
    vOptional, // 10 Required??? Format
    vOptional, // 9 optional Format
    vOptional, // 8 optional WritePasswordTemplate
    vOptional, // 7 optional WritePasswordDocument
    vFalse, // 6 optional Revert
    vOptional, // 5 optional PasswordTemplate
    vOptional, // 4 optional PasswordDocument
    vFalse, // 3 optional AddToRecentFiles
    vTrue, // 2 optional ReadOnly
    vFalse, // 1 optional ConfirmConversions
    fname);

  • The open method actually takes 16 arguments. The Format parameter is listed twice in the documentation (I don't know why). The final 2 arguments are for [link=http://msdn.microsoft.com/es-es/library/microsoft.office.interop.word.documents.open2002(office.11).aspx]internal[/link] use only, so you shouldn't use them in your code.

    [code]
    hr = AutoWrap(DISPATCH_METHOD, &result, pDocs, L"Open", 14,
    vFalse, // 14 optional OpenAndRepair
    vOptional, // 13 optional OpenConflictDocument
    vFalse, // 12 optional Visible
    vOptional, // 11 optional Encoding
    vOptional, // 10 optional Format
    vOptional, // 9 optional WritePasswordTemplate
    vOptional, // 8 optional WritePasswordDocument
    vFalse, // 7 optional Revert
    vOptional, // 6 optional PasswordTemplate
    vOptional, // 5 optional PasswordDocument
    vFalse, // 4 optional AddToRecentFiles
    vTrue, // 3 optional ReadOnly
    vFalse, // 2 optional ConfirmConversions
    fname);
    [/code]

    You can find the WdOpenFormat constants in the Word VBA help file, or you can google WdOpenFormat.
    Also to get the actual error message you can google the error code. e.g. 0x80010105


  • Thanks, your code worked

    But the primary reason why I called the full version of "Open" is so that the file is not added to the Recently Used list. The "Open" routine is correctly NOT adding the file to the MRU.

    I noticed that when calling Document->Close that the file is added to the recently used list. The document shows 3 parameters, but no matter what I try, I cannot stop the close routine from adding the file to the MRU list.

    What are the proper variants to call "Close" so that the file is not added to the MRU

    Thank you
  • It seems the problem is not with closing but saving the document.
    This worked for me:

    [code]
    AutoWrap(DISPATCH_METHOD, NULL, pDoc, L"SaveAs", 5, vFalse, vOptional, vOptional, vOptional, fname);

    VARIANT x;
    x.vt = VT_I4;
    x.lVal = 0; //wdDoNotSaveChanges
    AutoWrap(DISPATCH_METHOD, NULL, pDoc, L"Close", 1, x);
    [/code]

    Call SaveAs with vFalse for AddToRecentFiles
    then close without saving changes.

  • This doesn't work

    I am opening pDoc->BuiltinDocumentProperties
    and getting each property

    I set a breakpoint at the pDoc->Close
    The test.doc file is NOT in the MRU

    I then step past the pDoc->Close
    The test.doc file is then added to the MRU

    I actually wrote code to delete the MRU shortcut from the "recent" folder - doesn't work?

    Please help
  • I tested the code and it's working fine. I have Visual Studio 2008 and Office 2007, but I don't think that has anything to do with it.
    Here's my code. I renamed the document to test4.doc because test.doc was already in the MRU:

    [code]
    int main(int argc, char* argv[])
    {
    // Initialize COM for this thread...
    CoInitialize(NULL);

    // Get CLSID for Word.Application...
    CLSID clsid;
    HRESULT hr = CLSIDFromProgID(L"Word.Application", &clsid);
    if(FAILED(hr)) {
    ::MessageBox(NULL, "CLSIDFromProgID() failed", "Error",
    0x10010);
    return -1;
    }

    // Start Word and get IDispatch...
    IDispatch *pWordApp;
    hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER,
    IID_IDispatch, (void **)&pWordApp);
    if(FAILED(hr)) {
    ::MessageBox(NULL, "Word not registered properly",
    "Error", 0x10010);
    return -2;
    }

    // Make Word visible
    {
    VARIANT x;
    x.vt = VT_I4;
    x.lVal = 1;
    AutoWrap(DISPATCH_PROPERTYPUT, NULL, pWordApp, L"Visible", 1,
    x);
    }

    // Get Documents collection
    IDispatch *pDocs;
    {
    VARIANT result;
    VariantInit(&result);
    AutoWrap(DISPATCH_PROPERTYGET, &result, pWordApp, L"Documents",
    0);

    pDocs = result.pdispVal;
    }

    // Call Documents.Open() to open C:Doc1.doc
    IDispatch *pDoc;
    {
    VARIANT result;
    VariantInit(&result);

    VARIANT fname;
    VariantInit(&fname);
    fname.vt = VT_BSTR;
    fname.bstrVal = ::SysAllocString(L"c:\temp\test4.doc");

    VARIANT vTrue;
    vTrue.vt = VT_BOOL;
    vTrue.boolVal = TRUE;

    VARIANT vFalse;
    vFalse.vt = VT_BOOL;
    vFalse.boolVal = FALSE;

    VARIANT vOptional;
    vOptional.vt = VT_ERROR;
    vOptional.scode = DISP_E_PARAMNOTFOUND;

    hr = AutoWrap(DISPATCH_METHOD, &result, pDocs, L"Open", 14,
    vFalse, // 14 optional OpenAndRepair
    vOptional, // 13 optional OpenConflictDocument
    vFalse, // 12 optional Visible
    vOptional, // 11 optional Encoding
    vOptional, // 10 optional Format
    vOptional, // 9 optional WritePasswordTemplate
    vOptional, // 8 optional WritePasswordDocument
    vOptional, // 7 optional Revert
    vOptional, // 6 optional PasswordTemplate
    vOptional, // 5 optional PasswordDocument
    vFalse, // 4 optional AddToRecentFiles
    vOptional, // 3 optional ReadOnly
    vOptional, // 2 optional ConfirmConversions
    fname);

    pDoc = result.pdispVal;
    SysFreeString(fname.bstrVal);
    }

    // Get BuiltinDocumentProperties collection
    IDispatch *pProps;
    {
    VARIANT result;
    VariantInit(&result);
    AutoWrap(DISPATCH_PROPERTYGET, &result, pDoc,
    L"BuiltinDocumentProperties", 0);
    pProps = result.pdispVal;
    }

    // Get "Subject" from BuiltInDocumentProperties.Item("Subject")
    IDispatch *pPropSubject;
    {
    VARIANT result;
    VariantInit(&result);
    VARIANT x;
    x.vt = VT_BSTR;
    x.bstrVal = ::SysAllocString(L"Subject");
    AutoWrap(DISPATCH_PROPERTYGET, &result, pProps, L"Item", 1, x);
    pPropSubject = result.pdispVal;
    SysFreeString(x.bstrVal);
    }

    // Get the Value of the Subject property and display it
    {
    VARIANT result;
    VariantInit(&result);
    AutoWrap(DISPATCH_PROPERTYGET, &result, pPropSubject, L"Value",
    0);
    char buf[512];
    wcstombs(buf, result.bstrVal, 512);
    ::MessageBox(NULL, buf, "Subject", 0x10000);

    }

    // Set the Value of the Subject DocumentProperty
    {
    VARIANT x;
    x.vt = VT_BSTR;
    x.bstrVal = ::SysAllocString(L"This is my subject");
    AutoWrap(DISPATCH_PROPERTYPUT, NULL, pPropSubject, L"Value", 1,
    x);
    ::MessageBox(NULL,
    "Subject property changed, examine document.",
    "Subject", 0x10000);
    SysFreeString(x.bstrVal);
    }

    // Get CustomDocumentProperties collection
    IDispatch *pCustomProps;
    {
    VARIANT result;
    VariantInit(&result);
    AutoWrap(DISPATCH_PROPERTYGET, &result, pDoc,
    L"CustomDocumentProperties", 0);
    pCustomProps = result.pdispVal;
    }

    // Add a new property named "CurrentYear"
    {
    VARIANT parm1, parm2, parm3, parm4;
    parm1.vt = VT_BSTR;
    parm1.bstrVal = SysAllocString(L"CurrentYear");
    parm2.vt = VT_BOOL;
    parm2.boolVal = false;
    parm3.vt = VT_I4;
    parm3.lVal = 1; //msoPropertyTypeNumber = 1
    parm4.vt = VT_I4;
    parm4.lVal = 1999;

    AutoWrap(DISPATCH_METHOD, NULL, pCustomProps, L"Add", 4, parm4,
    parm3, parm2, parm1);
    ::MessageBox(NULL, "Custom property added, examine document.",
    "Custom Property", 0x10000);
    SysFreeString(parm1.bstrVal);
    }

    // Get the custom property "CurrentYear" and delete it
    IDispatch *pCustomProp;
    {
    VARIANT result;
    VariantInit(&result);
    VARIANT x;
    x.vt = VT_BSTR;
    x.bstrVal = ::SysAllocString(L"CurrentYear");
    AutoWrap(DISPATCH_PROPERTYGET, &result, pCustomProps, L"Item",
    1, x);
    pCustomProp = result.pdispVal;
    SysFreeString(x.bstrVal);
    AutoWrap(DISPATCH_METHOD, NULL, pCustomProp, L"Delete", 0);
    ::MessageBox(NULL,
    "Custom property removed, examine document.",
    "Custom Property", 0x10000);
    }

    // Close the document without saving changes and quit Word
    {
    VARIANT fname;
    VariantInit(&fname);
    fname.vt = VT_BSTR;
    fname.bstrVal = ::SysAllocString(L"c:\temp\test4.doc");

    VARIANT vTrue;
    vTrue.vt = VT_BOOL;
    vTrue.boolVal = TRUE;

    VARIANT vFalse;
    vFalse.vt = VT_BOOL;
    vFalse.boolVal = FALSE;

    VARIANT vOptional;
    vOptional.vt = VT_ERROR;
    vOptional.scode = DISP_E_PARAMNOTFOUND;

    AutoWrap(DISPATCH_METHOD, NULL, pDoc, L"SaveAs", 5, vFalse, vOptional, vOptional, vOptional, fname);

    VARIANT x;
    x.vt = VT_I4;
    x.lVal = 0; //wdDoNotSaveChanges
    AutoWrap(DISPATCH_METHOD, NULL, pDoc, L"Close", 1, x);
    AutoWrap(DISPATCH_METHOD, NULL, pWordApp, L"Quit", 0);
    }

    // Cleanup
    pCustomProp->Release();
    pCustomProps->Release();
    pPropSubject->Release();
    pProps->Release();
    pDoc->Release();
    pDocs->Release();
    pWordApp->Release();


    // Uninitialize COM for this thread...
    CoUninitialize();

    return 0;
    }
    [/code]

    Hope that helps.

  • The call to SaveAs fails in AutoWrap.Invoke

    I am using Word 2003

    I still have the problem of having the file added to the Most Recently Used list after to call to pDoc->Close

    I will have to call DeleteFile to delete the shortcut
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories