Ale*_*lex 6 c# c++ com interop
我有一个C#类库,其中包含需要与外部应用程序一起使用的方法.不幸的是,这个外部应用程序仅支持C/C++中的外部API.
现在我设法得到一个非常简单的COM示例在C++ DLL和C#DLL之间工作,但我仍然坚持如何移动数组数据.
这就是我到目前为止所做的,就像我通过COM在网络上找到的一个小例子:
DLL_EXPORT(void) runAddTest(int add1,long *result) {
// Initialize COM.
HRESULT hr = CoInitialize(NULL);
// Create the interface pointer.
IUnitModelPtr pIUnit(__uuidof(UnitModel));
long lResult = 0;
// Call the Add method.
pIUnit->Add(5, 10, &lResult);
*result = lResult;
// Uninitialize COM.
CoUninitialize();
}
Run Code Online (Sandbox Code Playgroud)
这可以在我的C#类中调用add方法.如何修改它以获取并返回双精度数组?(生病也需要用绳子做下去).
我需要获取一个非托管数组,将此数组传递给C#类进行一些计算,然后将结果传递回原始函数调用(非托管)C++中指定的数组引用.
我需要公开这样的函数:
*calcin - 对双精度数组的引用
*calcOut - 对双精度数组的引用
numIN - 输入数组大小的值
DLL_EXPORT(void) doCalc(double *calcIn, int numIn, double *calcOut)
{
//pass the calcIn array to C# class for the calcuations
//get the values back from my C# class
//put the values from the C# class
//into the array ref specified by the *calcOut reference
}
Run Code Online (Sandbox Code Playgroud)
我想我可以使用C++\CLI DLL作为外部应用程序,所以如果这比直接COM更容易,那么我愿意看一下.
请温柔,因为我主要是一个C#开发人员,但已被抛入Interop和C++的深层.
我不久前尝试过这个,但不幸的是忘记了它们是如何组合在一起的……出于我的目的,它速度慢得可怜,所以我放弃了 C# 并回到了所有 C++。当你说你主要是一名 C# 开发人员时,我希望你能理解指针,因为如果你不理解,就没有办法保持温和。
传递数组基本上归结为在 C++ 端使用 CoTaskMemAlloc 系列函数 ( http://msdn.microsoft.com/en-us/library/ms692727(VS.85).aspx ) 和在 C# 端使用 Marshal 类 ( http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.aspx - 其中具有诸如 AllocCoTaskMem 之类的方法。对于 C#,我最终得到了一个实用程序类:
public class serviceUtils
{
unsafe public long stringToCoTaskPtr( ref str thestring )
{
return (long)Marshal.StringToCoTaskMemAnsi(thestring.theString).ToPointer();//TODO : what errors occur from here? handle them
}
unsafe public long bytesToCoTaskPtr( ref bytes thebytes, ref short byteCnt)
{
byteCnt = (short)thebytes.theArray.Length;
IntPtr tmpptr = new IntPtr();
tmpptr = Marshal.AllocCoTaskMem(byteCnt);
Marshal.Copy(thebytes.theArray, 0, tmpptr, byteCnt);
return (long)tmpptr.ToPointer();
}
public void freeCoTaskMemPtr(long ptr)
{
Marshal.FreeCoTaskMem(new IntPtr(ptr));//TODO : errors from here?
}
public string coTaskPtrToString(long theptr)
{
return Marshal.PtrToStringAnsi(new IntPtr(theptr));
}
public byte[] coTaskPtrToBytes(long theptr, short thelen)
{
byte[] tmpbytes = new byte[thelen];
Marshal.Copy(new IntPtr(theptr), tmpbytes, 0, thelen);
return tmpbytes;
}
}
Run Code Online (Sandbox Code Playgroud)
只是为了向您抛出更多代码:这个 c++
#import "..\COMClient\bin\Debug\COMClient.tlb" named_guids raw_interfaces_only
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL); //Initialize all COM Components
COMClient::IComCalculatorPtr pCalc;
// CreateInstance parameters
HRESULT hRes = pCalc.CreateInstance(COMClient::CLSID_ComCalculator);
if (hRes == S_OK) {
long size = 5;
LPVOID ptr = CoTaskMemAlloc( size );
if( ptr != NULL )
{
memcpy( ptr, "12345", size );
short ans = 0;
pCalc->changeBytes( (__int64*)&ptr, &size, &ans );
CoTaskMemFree(ptr);
}
}
CoUninitialize (); //DeInitialize all COM Components
return 0;
}
Run Code Online (Sandbox Code Playgroud)
称之为 c#
public short changeBytes(ref long ptr, ref int arraysize)
{
try
{
IntPtr interopPtr = new IntPtr(ptr);
testservice.ByteArray bytes = new testservice.ByteArray();
byte[] somebytes = new byte[arraysize];
Marshal.Copy(interopPtr, somebytes, 0, arraysize);
bytes.theArray = somebytes;
CalculatorClient client = generateClient();
client.takeArray(ref bytes);
client.Close();
if (arraysize < bytes.theArray.Length)
{
interopPtr = Marshal.ReAllocCoTaskMem(interopPtr, bytes.theArray.Length);//TODO : throws an exception if fails... deal with it
}
Marshal.Copy(bytes.theArray, 0, interopPtr, bytes.theArray.Length);
ptr = interopPtr.ToInt64();
arraysize = bytes.theArray.Length;
//TODO : do we need to free IntPtr? check all code for memory leaks... check for successful allocation
}
catch(Exception e)
{
return 3;
}
return 2;
}
Run Code Online (Sandbox Code Playgroud)
抱歉,但我没有时间解决所有这些问题并正确解释它,希望这能为您指明正确的方向,至少可以谷歌搜索一些东西。祝你好运
PS:我从网上得到了写这些东西的所有信息,所以它就在那里。
| 归档时间: |
|
| 查看次数: |
10045 次 |
| 最近记录: |