我在C#中的以下接口与一个同名的类(无我)实现它。
[ComVisible(true)]
[Guid("B2B134CC-70A6-43CD-9E1E-B3A3D9992C3E")]
public interface IOrder
{
long GetQuantity();
long GetOrderType();
long GetPositionType();
}
公共类的执行顺序:IOrder是个私营领域,并需要3个参数的构造函数。
其他地方,我有一个结果下面的方法与我想在C ++非托管代码内工作,通过COM和.TLB / .tlh文件传输那里。
public ScOrder[] GetOrders()
{
//constant return value for simplicity
return new Order[] {
new Order(1, 2, 3),
new Order(4, 5, 6)
};
}
我已经设法使用C#托管代码的C ++非托管代码的基础工作。
但是级阵列被证明是一个不同的challange ...
我承认,对我来说,COM是新的和残酷的混乱和C ++早已被人遗忘......,但我正在开发两个库,所以我不会放弃; 我想在C ++ DLL为一些节目和我的C#代码之间的代理工作。
澄清:我使用的既不是MFC也不ATL。 我使用#import在C ++代码获取C#生成的接口和类指针和其他COM东西,我不太明白呢。
研发的小时之后,我只是在这里乞讨求助>。<
以下是我想要实现的C ++代码。
//this is how the instance of C# gets created, read it from the internets
//this type has the method GetOrders
IProxyPtr iPtr;
CoInitialize(NULL);
iPtr.CreateInstance(CLSID_Proxy);
IOrderPtr* ordArr;
//IOrderPtr is just a pointer to the interface type transferred
//right? So IOrderPtr* should represent the array of those pointers, right?
SAFEARRAY* orders;
iPtr->GetOrders(&orders);
现在,在这一点上,我需要一些COM魔法我还没有理解来转换SAFEARRAY *至* IOrderPtr或东西,所以我可以遍历整个数组返回并调用类型为“订单”的方法
- GetQuantity()
- GetOrderType()
- GetPositionType()
因此,对于第一个周期,我会得到值1,2,3和第二个周期,我会得到值4,5,6。
因为我是C ++和C#库的作者,我可以跳过这一切COM疯狂的东西,使方法获取集合计数等方法获得的财产上的某些指标值。
但是,这只是似乎并不好看。 我怀疑什么,我想很容易的机制,但所有我对谷歌总是缺少的东西找到了答案。
不知道您是否使用MFC,ATL或其他一些图书馆在C ++客户端,这是很难简化它,所以我会用的Win32 API(这些图书馆提供SAFEARRAYS的简单使用辅助类)
不过,我会假设你使用过C#的lib #import
互操作类型库的,所以你可以使用生成的智能指针类。 我也假设你回到IUnknowns的SAFEARRAY,而不是变体包含IUnknowns的SAFEARRAY - 这可以通过指定相应的编组上你的属性C#接口,例如进行修改:
[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)]
// [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)]
IOrder[] GetOrders();
下面是C#类型的实现(链路到样品溶液处于答案的底部):
[ComVisible(true)]
[Guid("F3071EE2-84C9-4347-A5FC-E72736FC441F")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IProxy
{
[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)]
IOrder[] GetOrders();
}
[ComVisible(true)]
[Guid("8B6EDB6B-2CF0-4eba-A756-B6E92A71A48B")]
[ClassInterface(ClassInterfaceType.None)]
public class Proxy : IProxy
{
public IOrder[] GetOrders() { return new[] {new Order(3), new Order(4)}; }
}
[ComVisible(true)]
[Guid("CCFF9FE7-79E7-463c-B5CA-B1A497843333")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOrder
{
long GetQuantity();
}
[ComVisible(true)]
[Guid("B0E866EB-AF6D-432c-9560-AFE7D171B0CE")]
[ClassInterface(ClassInterfaceType.None)]
public class Order : IOrder
{
private int m_quantity;
public Order(int quantity) { m_quantity = quantity; }
public long GetQuantity() { return m_quantity; }
}
服务器必须建立与注册Regasm
。 为简单起见,我会做regasm /codebase /tlb $path
,以避免签约并在GAC注册。
客户端代码想是这样的:
#import "Server.tlb" no_namespace // you should use namespaces! this is a demo
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL); // init COM
IProxyPtr proxy(__uuidof(Proxy)); // instantiate the proxy
SAFEARRAY* orders = proxy->GetOrders(); // to return orders
LPUNKNOWN* punks;
HRESULT hr = SafeArrayAccessData(orders, (void**)&punks); // direct access to SA memory
if (SUCCEEDED(hr))
{
long lLBound, lUBound; // get array bounds
SafeArrayGetLBound(orders, 1 , &lLBound);
SafeArrayGetUBound(orders, 1, &lUBound);
long cElements = lUBound - lLBound + 1;
for (int i = 0; i < cElements; ++i) // iterate through returned objects
{
LPUNKNOWN punk = punks[i]; // for VARIANTs: punk = punks[i].punkVal
IOrderPtr order(punk); // access the object via IOrder interface
long q = order->GetQuantity(); // and voila!
std::cout << "order " << i + 1 << ": Quantity " << q << std::endl;
}
SafeArrayUnaccessData(orders);
}
SafeArrayDestroy(orders);
return 0;
}
示例项目可以在这里找到 。 请注意,您必须手动注册您构建它的.TLB第一次,该项目并没有做到这一点,但如果你愿意,你可以添加一个生成后步骤
与SAFEARRAYS工作是在颈部疼痛。 还有它周围还有没有办法。
由于SAFEARRAY是你不能只是投以一个方便IOrder *阵列和工作与项目的结构,你在C#中会。
这里有几件事情谷歌拿给我。 他们看起来非常有益的。
http://edn.embarcadero.com/article/22016
http://digital.ni.com/public.nsf/allkb/7382E67B95238D2B862569AD005977F0
如果你在你的C使用ATL ++项目,您已经有了一个CComSafeArray包装:
http://msmvps.com/blogs/gdicanio/archive/2011/02/04/simplifying-safearray-programming-with-ccomsafearray.aspx
文章来源: Convert/cast SAFEARRAY of IUnknowns to an iterable array of interface pointers