C#支持指针,尤其是与COM交互的接口指针。Marshal类可以帮你完成任何事。
如果只是简单的使用IDispatch,用MarshalAsAttribute就可以了:In COM/IDL:
HRESULT FunctionNeedIDispatch([in] IDispatch* disp);
HRESULT FunctionRetIDispatch([out, retval] IDispatch** pdisp);In C#:
void FunctionNeedIDispatch([MarshalAs(UnmanagedType.IDispatch)] Object o);
[MarshalAs(UnmanagedType.IDispatch)]
Object FunctionRetIDispatch();
...
当然,这也要看你具体使用IDispatch的场合,总的来说,你cast成某个CoClass或者其它的Interface (用tlbimp声明的)。
如果只是简单的使用IDispatch,用MarshalAsAttribute就可以了:In COM/IDL:
HRESULT FunctionNeedIDispatch([in] IDispatch* disp);
HRESULT FunctionRetIDispatch([out, retval] IDispatch** pdisp);In C#:
void FunctionNeedIDispatch([MarshalAs(UnmanagedType.IDispatch)] Object o);
[MarshalAs(UnmanagedType.IDispatch)]
Object FunctionRetIDispatch();
...
当然,这也要看你具体使用IDispatch的场合,总的来说,你cast成某个CoClass或者其它的Interface (用tlbimp声明的)。
你提供的方法,只是把IDispatch压进一个对象中。
并且该对象提供获取IDispatch指针的方法而已。
----------
我希望的不是C#代码作为IDispatch传递的媒介。
而是想直接用C#调用IDispatch::Invoke
例如我希望用C#来实现下面代码:STDMETHODIMP CTest::LoadXMLDocument(/*[in]*/BSTR szURL,/*[out,retval]*/LPDISPATCH *lplpDisp)
{
// TODO: Add your implementation code here
HRESULT hres;
CLSID clsidXMLDOM; hres=CLSIDFromProgID(L"Microsoft.XMLDOM",&clsidXMLDOM);
if(FAILED(hres))
return hres; LPDISPATCH lpDisp;
hres=CoCreateInstance(clsidXMLDOM,NULL,CLSCTX_INPROC_SERVER,IID_IDispatch,(LPVOID*)&lpDisp);
if(FAILED(hres))
return hres;
BSTR rgszNames[]={L"async",L"load"};
DISPID Dispid;
DISPPARAMS dps;
VARIANT params[1];
dps.cArgs=1;
dps.cNamedArgs=0;
dps.rgdispidNamedArgs=NULL;
dps.rgvarg=params;
VARIANT vres;
EXCEPINFO ei;
UINT rgui[2]; //xmldom.async=false;
hres=lpDisp->GetIDsOfNames(IID_NULL,&rgszNames[0],1,GetSystemDefaultLCID(),&Dispid);
if(FAILED(hres))
{
lpDisp->Release();
return hres;
}
params[0].vt=VT_BOOL;
params[0].boolVal=FALSE;
hres=lpDisp->Invoke(Dispid,IID_NULL,GetSystemDefaultLCID(),DISPATCH_PROPERTYPUT,&dps,&vres,&ei,rgui);
if(FAILED(hres))
{
lpDisp->Release();
return hres;
} //xmldom.load(szURL);
hres=lpDisp->GetIDsOfNames(IID_NULL,&rgszNames[1],1,GetSystemDefaultLCID(),&Dispid);
if(FAILED(hres))
{
lpDisp->Release();
return hres;
}
params[0].vt=VT_BSTR|VT_BYREF;
params[0].pbstrVal=&szURL;
hres=lpDisp->Invoke(Dispid,IID_NULL,GetSystemDefaultLCID(),DISPATCH_METHOD,&dps,&vres,&ei,rgui);
if(FAILED(hres))
{
lpDisp->Release();
return hres;
} *lplpDisp=lpDisp;
return S_OK;
}
tlbimp c:\winnt\system32\msxml3.dll然后你的目录下会有一个MSXML2.dll,用ildasm查以下,还用Idispatch吗?:)XMLDocument doc = new XMLDocument();
doc.async = ...;
我的意思是,
如过我有一个XML脚本如下:
<var name="url" type="string">
<set-value><value type="string">http://www.host.com/thexml.xml</value></set-value>
</var>
<var name="test" type="object">
<set-value><active-x-object>Microsoft.XMLDOM</active-x-object></set-value>
</var>
<set-property>
<caller><getvar name="test" /></caller>
<property name="async"></property>
<value type="boolean">false</value>
</set-property>
<call-method>
<caller>
<get-var name="test" />
</caller>
<method name="load">
</method>
<arguments>
<param type="string"><get-var name="url" /></param>
</arguments>
</call-method>
我要用这个脚本来处理一些事务(就象游戏脚本一样)
而且我要调用哪个Automation的东西都不知道。
所以我只能用IDispatch
当然,理论上说reflection可以办到,但是... #@$@#不过在.NET的范围内还是可以解决的,VB.NET比C#的优点之一就是late binding,所以只要用vb.net就好了,不用C++介入,编程也方便许多。
可以用VB.NET编译个独立的DLL,吧这部分功能封装起来...
VB.NET我也不是很熟,这是MSDN上的一个例子:
Dim xlApp As Object
xlApp = CreateObject("Excel.Application")
MsgBox(xlApp.Version)
...
VB.NET支持LateBinding是由于它的Runtime (Microsft.VisualBasic)中实现了很多附加的功能,这里是一个完整的程序:Option Explicit On
Option Strict OffImports System
Imports Microsoft.VisualBasicModule Hello
Sub Main()
Dim obj As Object
obj = CreateObject("Word.Application")
Console.WriteLine(obj.Version)
End Sub
End Module我不确定是否可以在C#里面using Microsoft.VisualBasic,然后用Late Binding。