问题描述
COM组件当前以C ++实现,而下一版本必须以C#实现。该组件从C ++(不是CLI)代码中调用。这个很小的组件的主要部分已经移植到C#中,但是我很难弄清楚如何翻译一种特定的方法。
接口定义
IDL中使用了以下导入:
import "oaidl.idl";
import "ocidl.idl";
接口的主要部分已经转换为相应的C#属性,接口和类。大部分都能正常工作。
但是接口成员之一在IDL中定义为
[
object,uuid(<guid>),helpstring("Help"),pointer_default(unique)
]
interface IStuff : IUnkNown
{
...
HRESULT GetShortText([in] int i,[in] BOOL b,[out,string] TCHAR shortText[10]);
...
}
用法
要使用该接口,将传递本地TCHAR[10]
数组作为该数组的名称(因此称为TCHAR*
)。 COM服务器必须在TCHAR数组中放入一个短字符串。
问题
我无法调用该方法。永远不会命中GetShortText
方法中在C#COM服务器中设置的断点。 COM根本无法在.NET中找到我的实现。
解决方法
这种接口可以在 .Net 中通过将参数指定为 IntPtr
并手动编组字符串来实现。完整的演示可以是found on Github。
示例实现:
[ComVisible(true),Guid("E559D616-4C46-4434-9DF7-E9D7C91F3BA5"),InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IStuff
{
void GetShortTest(int i,[MarshalAs(UnmanagedType.Bool)] bool b,IntPtr shortText);
}
[ComVisible(true),ProgId("InProcTargetTest.Class1"),Guid("BA5088D4-7F6A-4C76-983C-EC7F1BA51CAA"),ClassInterface(ClassInterfaceType.None)]
public class Class1 : IStuff
{
public void GetShortTest(int i,bool b,IntPtr shortText)
{
var data = Encoding.Unicode.GetBytes("Hello");
Marshal.Copy(data,shortText,data.Length);
}
}
示例调用者:
if (FAILED(CoInitialize(nullptr))) {
std::cout << "Failed to initialize COM\n";
}
IStuff *pStuff = nullptr;
CLSID clsClass1 = { 0 };
if (FAILED(CLSIDFromProgID(L"InProcTargetTest.Class1",&clsClass1))
|| FAILED(CoCreateInstance(clsClass1,nullptr,CLSCTX_INPROC_SERVER,IID_IStuff,(LPVOID*)&pStuff))) {
std::cout << "Failed to create COM instance\n";
}
TCHAR test[10] = { 0 };
pStuff->GetShortTest(5,true,test);
std::cout << "From C#: " << test << "\n";
IDL 示例:
import "unknwn.idl";
[
odl,uuid(E559D616-4C46-4434-9DF7-E9D7C91F3BA5),version(1.0),pointer_default(unique),custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9,"InProcTargetTest.IStuff")
]
interface IStuff : IUnknown {
HRESULT _stdcall GetShortTest(
[in] long i,[in] BOOL b,[out,string] TCHAR shortText[10]);
};
,
对于这种相当不寻常的结构,我不知道有任何标准的编组方法。但是,您可以执行以下操作:
void GetShortText(int i,[MarshalAs:UnmanagedType.Bool] bool b,IntPtr shortTextPtr)
{
string s = "Test";
byte[] buffer;
if (UseUnicode)
buffer = Encoding.Unicode.GetBytes(s + '\0');
else
buffer = Encoding.Default.GetBytes(s + '\0');
Marshal.Copy(buffer,shortTextPtr,buffer.Length);
}
注意:
- 对缓冲区进行范围检查。应添加长度(对于ANSI,
-
+ '\0'
用于对返回的字符串进行空终止