C++进行COM 自动化调用时的命名参数调用方法
C++使用COM自动化组件时,通过获取IDispatch接口,然后通过Invoke方法对COM组件的方法进行调用。在对Office组件的编程中,我们会经常性的使用这一方法。
在VBA中,存在一种命名参数的调用法。如Word的Documents对象中的Open方法:
Documents.Open( FileName, ConfirmConversions, ReadOnly, AddToRecentFiles, PasswordDocument, PasswordTemplate, Revert, WritePasswordDocument, WritePasswordTemplate, Format, Encoding, Visible, OpenConflictDocument, OpenAndRepair, DocumentDirection, NoEncodingDialog)
其中只有FileName参数为必须的参数,其他参数都为可选的参数。在进行调用时,VBA中可通过指定可选参数名称来向Documents传输任意的可选参数,如下
其中的pDispParams用于方法的参数传递,声明如下
在VBA中,存在一种命名参数的调用法。如Word的Documents对象中的Open方法:
Documents.Open( FileName, ConfirmConversions, ReadOnly, AddToRecentFiles, PasswordDocument, PasswordTemplate, Revert, WritePasswordDocument, WritePasswordTemplate, Format, Encoding, Visible, OpenConflictDocument, OpenAndRepair, DocumentDirection, NoEncodingDialog)
其中只有FileName参数为必须的参数,其他参数都为可选的参数。在进行调用时,VBA中可通过指定可选参数名称来向Documents传输任意的可选参数,如下
'
以只读方式打开文档 MyDoc.doc。
Sub OpenDoc()
Documents.Open FileName: = " C:\MyFiles\MyDoc.doc " , ReadOnly : = True
End Sub
那么,在C++中,我们应该如何进行这种调用?先看看Invoke方法的声明
Sub OpenDoc()
Documents.Open FileName: = " C:\MyFiles\MyDoc.doc " , ReadOnly : = True
End Sub
HRESULT Invoke(
DISPID dispIdMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS FAR * pDispParams,
VARIANT FAR * pVarResult,
EXCEPINFO FAR * pExcepInfo,
unsigned int FAR * puArgErr
);
DISPID dispIdMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS FAR * pDispParams,
VARIANT FAR * pVarResult,
EXCEPINFO FAR * pExcepInfo,
unsigned int FAR * puArgErr
);
其中的pDispParams用于方法的参数传递,声明如下
typedef
struct
FARSTRUCT tagDISPPARAMS{
VARIANTARG FAR * rgvarg; // Array of arguments.
DISPID FAR * rgdispidNamedArgs; // Dispatch IDs of named arguments.
unsigned int cArgs; // Number of arguments.
unsigned int cNamedArgs; // Number of named arguments.
} DISPPARAMS;
通过rgdispidNamedArgs可指定传入的命名参数,因此可以将上述VBA代码转化为下面的C++代码(这里使用了ATL),实现命名参数的调用
VARIANTARG FAR * rgvarg; // Array of arguments.
DISPID FAR * rgdispidNamedArgs; // Dispatch IDs of named arguments.
unsigned int cArgs; // Number of arguments.
unsigned int cNamedArgs; // Number of named arguments.
} DISPPARAMS;
CComPtr
<
Word::Documents
>
qpDocuments;
m_qpApplication -> get_Documents( & qpDocuments);
CComDispatchDriver qpDocsDisp = qpDocuments;
CComVariant varFilename(L " C:\MyFiles\MyDoc.doc " );
CComVariant varTrue( true );
CComVariant varDisp;
DISPID dispids[ 3 ];
LPOLESTR names[] = {L " Open " , L " FileName " , L " ReadOnly " };
hr = qpDocsDisp -> GetIDsOfNames(IID_NULL, names, 3 , LOCALE_USER_DEFAULT, dispids);
DISPPARAMS dispParams;
dispParams.cArgs = 2 ;
dispParams.cNamedArgs = 2 ;
dispParams.rgdispidNamedArgs = & dispids[ 1 ];
VARIANT varParam[ 2 ];
::VariantInit( & varParam[ 0 ]);
::VariantInit( & varParam[ 1 ]);
varParam[ 0 ] = varFilename;
varParam[ 1 ] = varTrue;
dispParams.rgvarg = varParam;
hr = qpDocsDisp -> Invoke(dispids[ 0 ], IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, & dispParams, & varDisp, NULL, NULL);
m_qpApplication -> get_Documents( & qpDocuments);
CComDispatchDriver qpDocsDisp = qpDocuments;
CComVariant varFilename(L " C:\MyFiles\MyDoc.doc " );
CComVariant varTrue( true );
CComVariant varDisp;
DISPID dispids[ 3 ];
LPOLESTR names[] = {L " Open " , L " FileName " , L " ReadOnly " };
hr = qpDocsDisp -> GetIDsOfNames(IID_NULL, names, 3 , LOCALE_USER_DEFAULT, dispids);
DISPPARAMS dispParams;
dispParams.cArgs = 2 ;
dispParams.cNamedArgs = 2 ;
dispParams.rgdispidNamedArgs = & dispids[ 1 ];
VARIANT varParam[ 2 ];
::VariantInit( & varParam[ 0 ]);
::VariantInit( & varParam[ 1 ]);
varParam[ 0 ] = varFilename;
varParam[ 1 ] = varTrue;
dispParams.rgvarg = varParam;
hr = qpDocsDisp -> Invoke(dispids[ 0 ], IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, & dispParams, & varDisp, NULL, NULL);