首先,我对COM技术不太熟悉,这是我第一次用它来忍受我自己。我正在尝试从C#调用一个COM对象函数。
这是idl文件中的接口:
[id(6), helpstring("vConnectInfo=ConnectInfoType")]
HRESULT ConnectTarget([in,out] VARIANT* vConnectInfo);这是我在运行tlbimp之后获得的interop接口:
void ConnectTarget(ref object vConnectInfo);COM对象中的目标函数的c++代码:
STDMETHODIMP PCommunication::ConnectTarget(VARIANT* vConnectInfo)
{
if (!((vConnectInfo->vt & VT_ARRAY) && (vConnectInfo->vt & VT_BYREF)))
{
return E_INVALIDARG;
}
ConnectInfoType *pConnectInfo = (ConnectInfoType *)((*vConnectInfo->pparray)->pvData);
...
}此COM对象在另一个进程中运行,它不在dll中.
我可以补充说,COM对象也来自用C++编写的另一个程序。在这种情况下,没有问题,因为在C++中创建了一个变量,并且pparray->pvData被设置为connInfo数据结构,然后以变量作为参数调用COM-对象。
在C#中,正如我所理解的那样,我的结构应该被自动编组为一个变体。
这是我一直在使用的两种方法(或者实际上我尝试了更多.)要从C#调用此方法:
private void method1_Click(object sender, EventArgs e)
{
pcom.PCom PCom = new pcom.PCom();
pcom.IGeneralManagementServices mgmt = (pcom.IGeneralManagementServices)PCom;
m_ci = new ConnectInfoType();
fillConnInfo(ref m_ci);
mgmt.ConnectTarget(m_ci);
}在上述情况下,结构被编组为VT_UNKNOWN。这是一个简单的情况,如果参数不是一个结构(例如。为int工作)。
private void method4_Click(object sender, EventArgs e)
{
ConnectInfoType ci = new ConnectInfoType();
fillConnInfo(ref ci);
pcom PCom = new pcom.PCom();
pcom.IGeneralManagementServices mgmt = (pcom.IGeneralManagementServices)PCom;
ParameterModifier[] pms = new ParameterModifier[1];
ParameterModifier pm = new ParameterModifier(1);
pm[0] = true;
pms[0] = pm;
object[] param = new object[1];
param[0] = ci;
object[] args = new object[1];
args[0] = param;
mgmt.GetType().InvokeMember("ConnectTarget", BindingFlags.InvokeMethod, null, mgmt, args, pms, null, null);
}在本例中,它被编组为VT_ARRAY _ VT_BYREF _VT_BYREF_ VT_VARIANT。问题是,在调试“目标函数”ConnectTarget时,我无法找到我在SAFEARRAY-struct中发送的数据(或者在内存中的任何其他地方)。
我该怎么处理VT_VARIANT?
对如何得到我的结构数据有什么想法吗?
更新:
ConnectInfoType结构:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class ConnectInfoType
{
public short network;
public short nodeNumber;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 51)]
public string connTargPassWord;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
public string sConnectId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string sConnectPassword;
public EnuConnectType eConnectType;
public int hConnectHandle;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
public string sAccessPassword;
};以及c++中相应的结构:
typedef struct ConnectInfoType
{
short network;
short nodeNumber;
char connTargPassWord[51];
char sConnectId[8];
char sConnectPassword[16];
EnuConnectType eConnectType;
int hConnectHandle;
char sAccessPassword[8];
} ConnectInfoType;发布于 2013-11-05 15:50:06
我找到了一个可以接受的解决办法/解决办法。我将结构转换为字节数组,然后将接收到的数据转换为ConnectInfoType结构。
// C#
private void method3_Click(object sender, EventArgs e)
{
pcom.PCom PCom = new pcom.PCom();
pcom.IGeneralManagementServices mgmt = (pcom.IGeneralManagementServices)PCom;
ConnectInfoType ci = new ConnectInfoType();
fillConnInfo(ref ci);
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(ci));
Marshal.StructureToPtr(ci, ptr, false);
byte[] arr = new byte[Marshal.SizeOf(ci)];
Marshal.Copy(ptr, arr, 0, Marshal.SizeOf(ci));
mgmt.ConnectTarget(arr);
}这将被编组为VT_ARRAY |VT_UI1,因此我已经将c++代码更改为:
// C++
STDMETHODIMP PCommunication::ConnectTarget(VARIANT* vConnectInfo)
{
if (!((vConnectInfo->vt & VT_ARRAY) && (vConnectInfo->vt & VT_UI1)))
{
return E_INVALIDARG;
}
ConnectInfoType *pConnectInfo = (ConnectInfoType *)(vConnectInfo->parray->pvData);
...
}如果有人知道更好的解决方案,可以随意添加。
发布于 2013-11-05 12:09:10
使用这个类http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.variantwrapper%28v=vs.110%29.aspx包装它,然后调用所需的方法。
你能发布"ConnectInfoType“类型的ConnectInfoType源代码吗?
https://stackoverflow.com/questions/19710072
复制相似问题