我有一个 C# 类库,其中包含需要与外部应用程序一起使用的方法。不幸的是,此外部应用程序仅支持 C/C++ 中的外部 API。
现在,我已经设法获得了一个在 C++ dll 和 C# DLL 之间工作的非常简单的 COM 示例,但我对如何移动数组数据一筹莫展。
这就是我到目前为止所得到的,就像我在网络上找到的一个通过 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();
}
这可以很好地调用我的 C# 类中的添加方法。我如何修改它以获取并返回一个 double 组? (我还需要用字符串来完成)。
我需要获取一个非托管数组,将此数组传递给 C# 类进行一些计算,然后将结果传递回原始函数调用(非托管)C++ 中指定的数组引用。
我需要公开这样一个函数:
*calcin - 对 double 组的引用
*calcOut - 对 double 组的引用
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
}
我认为我可以为外部应用程序使用 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;
}
}
只是为了向您抛出更多代码: 这个 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;
}
调用这个 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;
}
抱歉,但我没有时间解决所有这些问题并正确解释它,希望这会为您提供正确方向的指示,至少是一些可以谷歌搜索的内容。祝你好运
PS:我从网上得到了写这些东西的所有信息,所以它就在那里。
关于c# - 将数组从 C++ 移动到 C#、修改它并将其传递回 C++ 的最简单方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/575455/
我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代
我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby数组,我们在StackOverflow上找到一
我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这
这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife
我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat
我正在尝试在Ruby中制作一个cli应用程序,它接受一个给定的数组,然后将其显示为一个列表,我可以使用箭头键浏览它。我觉得我已经在Ruby中看到一个库已经这样做了,但我记不起它的名字了。我正在尝试对soundcloud2000中的代码进行逆向工程做类似的事情,但他的代码与SoundcloudAPI的使用紧密耦合。我知道cursesgem,我正在考虑更抽象的东西。广告有没有人见过可以做到这一点的库或一些概念证明的Ruby代码可以做到这一点? 最佳答案 我不知道这是否是您正在寻找的,但也许您可以使用我的想法。由于我没有关于您要完成的工作
有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url
我使用Ember作为我的前端和GrapeAPI来为我的API提供服务。前端发送类似:{"service"=>{"name"=>"Name","duration"=>"30","user"=>nil,"organization"=>"org","category"=>nil,"description"=>"description","disabled"=>true,"color"=>nil,"availabilities"=>[{"day"=>"Saturday","enabled"=>false,"timeSlots"=>[{"startAt"=>"09:00AM","endAt"=>