我之前问了一个关于delphi和C / C ++ DLL的问题。
我现在有另一个关于记录/结构的问题。 DLL应该能够动态地从MainAPP更改指针变量的VALUE。
我的delphi MAINAPP有以下记录:
type MyRec = record MyInteger : Pointer; MyWideString : pwidechar; MyString : pchar; MyBool : Pointer end; type TMyFunc = function ( p : pointer ): pointer; stdcall; procedure test; var MyFunction : TMyFunc; TheRecord : MyRec; AnInteger : Integer; AWideString : WideString; AString : String; ABool : Bool; begin AnInteger := 1234; AWideString := 'hello'; AString := 'hello2'; ABool := TRUE; TheRecord.MyInteger := @AnInteger; TheRecord.MyWideString := pwidechar(AWideString); TheRecord.AString := pchar(AString); TheRecord.ABool := @ABool; [...] @MyFunction := GetProcAddress... [...] MyFunction (@TheRecord); // now the DLL should be able to change the values dynamically. MessageBoxW (0, pwidechar(AWideString), '', 0); // Show the results how the DLL changed the String to... end;
C / C ++代码(仅举例)
typedef struct _TestStruct{ void *TheInteger; // Pointer to Integer wchar_t *TheWideString; // Pointer to WideString char *TheAnsiString; // Pointer to AnsiString bool *TheBool // Pointer to Bool }TestStruct; __declspec(dllexport) PVOID __stdcall MyExportedFunc (TestStruct *PTestStruct) { MessageBoxW(0 ,PTestStruct->TheWideString, L"Debug" , 0); // We read the value. PTestStruct->TheWideString = L"Let me change the value here."; return 0; }
由于某些原因它崩溃等。我做错了什么?
感谢帮助。
您正在管理字符串字段。 PWideChar
和PChar
与“指向WideString”和“指向AnsiString”的指针不同。 Delphi PWideString
提供了PWideString
( WideString*
)和PAnsiString
( AnsiString*
)类型。 您还应该使用Delphi的PInteger
( int*
)和PBoolean
( bool*
)类型而不是Pointer
( void*
)。 Delphi和C ++都是类型安全的语言。 尽可能远离无类型指针,您的代码将更好。
type PMyRec = ^MyRec; MyRec = record MyInteger : PInteger; MyWideString : PWideString; MyAnsiString : PAnsiString; MyBool : PBoolean; end; TMyFunc = function ( p : PMyRec ): Integer; stdcall; procedure test; var MyFunction : TMyFunc; TheRecord : MyRec; AnInteger : Integer; AWideString : WideString; AAnsiString : AnsiString; ABool : Bool; begin AnInteger := 1234; AWideString := 'hello'; AAnsiString := 'hello2'; ABool := TRUE; TheRecord.MyInteger := @AnInteger; TheRecord.MyWideString := @AWideString; TheRecord.MyAnsiString := @AAnsiString; TheRecord.MyBool := @ABool; [...] @MyFunction := GetProcAddress... [...] MyFunction (@TheRecord); MessageBoxW (0, PWideChar(AWideString), '', 0); end;
。
typedef struct _MyRec { int *MyInteger; // Pointer to Integer WideString *MyWideString; // Pointer to WideString AnsiString *MyAnsiString; // Pointer to AnsiString bool *MyBool; // Pointer to Bool } MyRec, *PMyRec; __declspec(dllexport) int __stdcall MyExportedFunc (PMyRec PRec) { MessageBoxW(NULL, PRec->MyWideString->c_bstr(), L"Debug" , 0); *(PRec->MyWideString) = L"Let me change the value here."; return 0; }
话虽如此,在这样的DLL边界上操作AnsiString
(和UnicodeString
)值是非常危险的,特别是如果EXE和DLL由于RTL差异而在Delphi / C ++ Builder的不同版本中编写,内存管理器的差异但是,有效载荷布局的差异等等, WideString
可以传递,因为它的内存和布局是由操作系统控制的,而不是RTL。
这可能不是C ++代码分配给TheWideString
指针时崩溃的原因,但我确实看到了期望的问题……
我注意到您将Delphi AWideString
变量指向的字符串数据的地址放入记录的MyWideString
字段中。 您将记录传递给C ++函数,该函数将新指针值分配给记录的TheWideString/MyWideString
字段。 当执行返回到Delphi代码时,输出AWideString
变量的内容。
您的注释表明您希望通过C ++函数更改AWideString变量的内容,但这不会发生。
C ++函数更改结构中的字段。 它对该字段先前指向的内存位置没有任何作用。 AWideString指向的数据不受C ++函数的影响。
如果C ++代码将数据复制到字段中包含的地址中,那么它将覆盖AWideString
指向的字符串数据。 由于AWideString
是一个Delphi托管字符串,并且C ++函数将更多数据复制到该字符串内存区域而不是原始字符串分配空间,因此在C ++函数中复制数据将写入Delphi分配的字符串缓冲区的末尾并且可能腐蚀Delphi堆。 一段时间后可能会发生崩溃。 所以你只是将指针分配给字段而不是复制数据是一件好事! ;>
要查看C ++函数的更改,Delphi代码应在调用C ++函数后输出记录的MyWideString
字段的内容。
同步结构中的字段顺序。 您可以使用错误的指针来破坏内存堆。 另外,检查Delphi和C ++中的对齐方式。
以上就是c/c++开发分享Delphi和C / C ++ DLL Struct vs.Record相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/560685.html