1.準(zhǔn)備工作
使用OLEView.exe查看本機(jī)安裝的COM組件CLSID和接口Guid
??COM組件的提供者沒(méi)有提供CLSID等信息或信息提供不全時(shí),可以使用OleView.exe來(lái)查看其類(lèi)和接口的GUID. OLEView.exe全稱(chēng)是OLE-COM Object Viewer,是Microsoft SDK中包含的一個(gè)工具,可以用來(lái)查看本機(jī)安裝的所有COM組件的信息,包括CLSID、ProgID等。如果是完整的開(kāi)發(fā)環(huán)境,其位置在C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin,非開(kāi)發(fā)環(huán)境下也可以到網(wǎng)上下載該程序和它依賴(lài)的一個(gè)IVIEWERS.DLL.
??在All Objets中查看COM組件的CLSID,右鍵可以直接復(fù)制CLSID. 右鍵選中項(xiàng),點(diǎn)擊ViewTypeInfo可查看詳細(xì)接口列表和接口的Guid。本次使用的COM組件只有一個(gè)callJson接口,一個(gè)字符串類(lèi)型的輸入?yún)?shù)([in]),一個(gè)輸出參數(shù)作為返回值([out,retval])。
2.三種不同的引用方式
方式1 使用tlbimp生成類(lèi)庫(kù)直接引用
常見(jiàn)的COM組件是dll形式,在VS中可以直接添加引用,VS會(huì)自動(dòng)生成一個(gè)Interop.xxx.dll類(lèi)庫(kù)。項(xiàng)目中使用的第三方COM組件是exe形式,可以使用tlbimp.exe手動(dòng)轉(zhuǎn)換。在Visual Studio的工具庫(kù)中找到并打開(kāi)VS的命令提示符,按格式輸入指令tlbimp FILENAME /out:OUTPUT
生成類(lèi)庫(kù),類(lèi)庫(kù)生成之后就可以在VS中添加引用,然后像其他類(lèi)庫(kù)一樣直接調(diào)用其中的接口。
方式2 使用CLSID和反射動(dòng)態(tài)調(diào)用
已知COM類(lèi)的CLISID時(shí)可以直接使用Type.GetTypeFromCLSID方法來(lái)獲取COM組件的Type,然后動(dòng)態(tài)創(chuàng)建對(duì)象調(diào)用接口。
private string CallJson(string input)
{
string ret = "";
Type dycomType = Type.GetTypeFromCLSID(new Guid("xxxxxx"));
if (dycomType != null)
{
//創(chuàng)建類(lèi)實(shí)例
dynamic dycomObject = Activator.CreateInstance(dycomType);
//調(diào)用
ret = dycomObject?.callJson(input);
}
return ret;
}
也可以使用ProgId來(lái)獲取:
Type t = Type.GetTypeFromProgID("TestComServer.TestComVisibleClass");
dynamic o = Activator.CreateInstance(t);
方式3 ComImport方式引用
使用ComImport標(biāo)簽引用COM組件,需要寫(xiě)明類(lèi)的Guid和接口的Guid:
[ComImport, Guid("xxxxxxxxxxxx")]
class DycomObject
{
}
// Declare IMediaControl as a COM interface which
// derives from the IDispatch interface.
[Guid("xxxxxxxx"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
interface IDycomObject // cannot list any base interfaces here
{
// Note that the members of IUnknown and Interface are NOT
// listed here
//
[return: MarshalAs(UnmanagedType.BStr)]
object callJson(
[In, MarshalAs(UnmanagedType.BStr)] string request);
}
調(diào)用:?
?
private string CallJson(string input)
{
string ret = "";
Console.WriteLine("創(chuàng)建類(lèi)實(shí)例");
DycomObject dy = new DycomObject();
IDycomObject iDy = (IDycomObject)dy;
Console.WriteLine("調(diào)用");
ret = (string)iDy.callJson(input);
return ret;
}
實(shí)際項(xiàng)目中的問(wèn)題
??上述三種方式的接口格式都是一個(gè)輸入?yún)?shù)對(duì)應(yīng)COM接口的[in]參數(shù),一個(gè)返回值對(duì)應(yīng)[out,retval]參數(shù),按照第三方接口描述,返回值中包含接口調(diào)用結(jié)果和錯(cuò)誤碼。實(shí)際使用中發(fā)現(xiàn),調(diào)用出錯(cuò)時(shí),接口會(huì)返回一個(gè)非零的HRESULT,同時(shí)把錯(cuò)誤信息傳給[out,retval]參數(shù),但.Net會(huì)把非零的HRESULT轉(zhuǎn)換為一個(gè)異常拋出,導(dǎo)致以上三種寫(xiě)法的返回值都為null,無(wú)法獲取錯(cuò)誤信息。在社區(qū)發(fā)帖問(wèn)到了解決方法,就是需要修改方式3的引用方式,使用[PreserveSig]取消COM互操作期間的HRESULT和retval簽名轉(zhuǎn)換,讓錯(cuò)誤信息可以被正常接收到:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-441068.html
[ComImport, Guid("xxxxxx")]
class DycomObject
{
}
[ComVisible(true), ComImport, Guid("xxxxxx")]
interface IDycomObject
{
[PreserveSig]
int callJson(
[In,MarshalAs(UnmanagedType.BStr)]
string request,
[Out,MarshalAs(UnmanagedType.BStr)]
out string response);
}
private string CallJson(string input)
{
string ret = "";
Console.WriteLine("創(chuàng)建類(lèi)實(shí)例");
DycomObject dy = new DycomObject();
IDycomObject iDy = (IDycomObject)dy;
Console.WriteLine("調(diào)用");
var code = iDy.callJson(input,out ret);
return ret;
}
?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-441068.html
到了這里,關(guān)于C#調(diào)用COM接口的三種方式的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!