从Delphi返回动态数组到C#和C++
2017-05-20 15:55
471 查看
经过很多尝试, Delphi/pascal无法将array of integer这样的数组返回给C#,只能传数组的地址过去, C#以IntPtr类型的参数接收, 然后通过Marshal将指针所指的内容复制出来
delphi的dll声明:
C#的import声明:
====================
而用VC调用,则可以做到无缝连接,直接引用指针:
定义function指针:
typedef bool(__stdcall* _dumpRegisters)(PINT&, WORD&);
上述方法应该于内存在dll里面管理的情况, 如果内存块在主程序里面先申请的,调用如下 :
dll 代码:
function dumpRegisters(pvOut: PInteger; out pvSize: word): boolean; stdcall;export;
begin
sendDebug('dumpRegisters.');
result:=false;
if (gdm=nil) then begin
sendDebug('dumpRegisters, failed');
exit;
end;
//pvOut:=@gdm.FRegisterValues[0];
pvSize:=length(gdm.FRegisterValues);
sendDebugFmt('dumpRegisters, source addr:%p, target addr:%p,size:%d',[@gdm.FRegisterValues[0],pvOut,pvSize]);
sendDebugFmt('before size:%d',[pvSize]);
move(gdm.FRegisterValues[0],pvOut^,sizeof(Integer)*pvSize); //复制数据到主程序的内存pvOut
sendDebugFmt('after size:%d',[pvSize]);
result:=true;
sendDebugFmt('dumpRegisters, OK, out:%p, size:%d',[pvOut,pvSize]);
end;
VC的调用:
typedef bool(__stdcall* _dumpRegisters)(PINT, WORD&);
C#的调用:
[DllImport("modbusapi.dll", EntryPoint = "dumpRegisters", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private static extern byte dumpRegisters([In, Out]
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] int[] pvAddr,
out UInt16 pvSize);
UInt16 lvSize = routines.getResiterSize();
int[] registers = new int[lvSize];
dumpRegisters(registers, out lvSize);
delphi的dll声明:
function dumpRegisters(out pvOut: PInteger; out pvSize: word): boolean; stdcall;export; begin sendDebug('dumpRegisters.'); result:=false; if (gdm=nil) then begin sendDebug('dumpRegisters, failed'); exit; end; pvOut:=@gdm.FRegisterValues[0]; pvSize:=length(gdm.FRegisterValues); result:=true; sendDebugFmt('dumpRegisters, OK, out:%p, size:%d',[pvOut,pvSize]); end;
C#的import声明:
public static extern void setRoutines(IntPtr pvRoutines); [DllImport("modbusapi.dll", EntryPoint = "dumpRegisters", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] public static extern byte dumpRegisters(out IntPtr pvAddr, out UInt16 pvSize);然后通过这个函数转换:
public static int[] IntPtr2RegisterData(IntPtr pvAddr,ushort pvSize) { int[] lvRegisters = new int[pvSize]; Marshal.Copy(pvAddr, lvRegisters,0, pvSize); return lvRegisters; }例子:
IntPtr lvPtr; ushort lvSize; int[] lvRet = null; if (ModBus.dumpRegisters(out lvPtr, out lvSize) != 0) lvRet = ModBus.IntPtr2RegisterData(lvPtr, lvSize); StringBuilder sb = new StringBuilder(); for (int i = 0; i < lvSize; i++) { sb.Append(String.Format("Register:{0}, value: {1}\r\n", i, lvRet[i])); } textBox1.AppendText(sb.ToString()); }
====================
而用VC调用,则可以做到无缝连接,直接引用指针:
定义function指针:
typedef bool(__stdcall* _dumpRegisters)(PINT&, WORD&);
bool ModBus::readRegisters(PINT& pvOut, WORD& pvSize) { if (mHnd == 0) return false; //_dumpRegisters dumpRegisters = (_dumpRegisters)GetProcAddress(mHnd, "dumpRegisters"); _dumpRegisters dumpRegisters = (_dumpRegisters)GetProcAddress(mHnd, "dumpRegisters"); WORD lvSize = 0; PINT lvAddr = NULL; if (dumpRegisters(lvAddr, lvSize)) { pvOut = lvAddr; pvSize = lvSize; } }调用:
PINT lvRegisters = NULL; WORD lvSize = 0; char lvOut[1024*10]; int lvLen = 0; if (modbus.readRegisters(lvRegisters, lvSize)) { for (int i = 0; i < lvSize; i++) { try { lvLen += sprintf_s(lvOut + lvLen, 1024 * 10 - lvLen, "Register:%d, Value:%d \r\n", i, lvRegisters[i]); } catch (const std::exception& e) { } } CString lvT(lvOut); ed_log.SetWindowTextW(lvT); }
上述方法应该于内存在dll里面管理的情况, 如果内存块在主程序里面先申请的,调用如下 :
dll 代码:
function dumpRegisters(pvOut: PInteger; out pvSize: word): boolean; stdcall;export;
begin
sendDebug('dumpRegisters.');
result:=false;
if (gdm=nil) then begin
sendDebug('dumpRegisters, failed');
exit;
end;
//pvOut:=@gdm.FRegisterValues[0];
pvSize:=length(gdm.FRegisterValues);
sendDebugFmt('dumpRegisters, source addr:%p, target addr:%p,size:%d',[@gdm.FRegisterValues[0],pvOut,pvSize]);
sendDebugFmt('before size:%d',[pvSize]);
move(gdm.FRegisterValues[0],pvOut^,sizeof(Integer)*pvSize); //复制数据到主程序的内存pvOut
sendDebugFmt('after size:%d',[pvSize]);
result:=true;
sendDebugFmt('dumpRegisters, OK, out:%p, size:%d',[pvOut,pvSize]);
end;
VC的调用:
typedef bool(__stdcall* _dumpRegisters)(PINT, WORD&);
_dumpRegisters dumpRegisters = (_dumpRegisters)GetProcAddress(mHnd, "dumpRegisters"); PINT lvAddr = NULL; mRegisterSize = mRoutines->getRegisterSize(); PINT mRegisters = new int[mRegisterSize]; dumpRegisters(mRegisters, pvSize); .....delete [] mRegisters;
C#的调用:
[DllImport("modbusapi.dll", EntryPoint = "dumpRegisters", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private static extern byte dumpRegisters([In, Out]
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] int[] pvAddr,
out UInt16 pvSize);
UInt16 lvSize = routines.getResiterSize();
int[] registers = new int[lvSize];
dumpRegisters(registers, out lvSize);
相关文章推荐
- c++返回结构数组给c#
- C++函数返回数组及动态建立二维数组的方法
- c#调用c++写成的dll文件,返回char*,返回数组,用ref接收,byte[]
- c#调用c++写成的dll文件,返回char*,返回数组,用ref接收,byte[] (zz)
- c#调用c++写成的dll文件,返回char*,返回数组,用ref接收,byte[] (zz)
- C++动态数组
- C#调用C++方法,C#使用c++方法返回类或结构体
- C++中二维动态数组的创建
- C#调用C++方法,C#使用c++方法返回类或结构体
- C++:多维数组的动态分配(new)和释放(delete)
- c++函数返回数组
- 动态数组的C++实现(转)
- Java、C#、C++定义数组区别
- C++动态数组分配
- C++中如何使函数返回数组
- C# 调用C++ DLL 返回类型为字符的接口 出现异常 解决办法
- C++带有指针数组的结构体转换为C#可用的结构体
- C#调用C++DLL传递结构体数组的终极解决方案
- C#反射动态调用dll中的方法,并返回结果
- C#/C++ 中字节数组与int类型转换