[英]Delphi and C/C++ DLL Struct vs.Record
我之前曾問過有關delphi和C / C ++ DLL的問題。
我現在還有一個關於記錄/結構的問題。 DLL應該能夠從MainAPP動態更改指針變量的值。
我的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;
}
由於某些原因,它會崩潰等。我該怎么辦?
感謝幫助。
在C ++代碼分配給TheWideString
指針時,這可能不是崩潰的原因,但是我確實看到了預期的問題...
我注意到您正在將Delphi AWideString
變量指向的字符串數據的地址放入記錄的MyWideString
字段中。 您將記錄傳遞給C ++函數,該函數將新的指針值分配給記錄的TheWideString/MyWideString
字段。 當執行返回到Delphi代碼時,您將輸出AWideString
變量的內容。
您的評論表明您希望C ++函數會更改AWideString變量的內容,但事實並非如此。
C ++函數更改結構中的字段。 它對該字段先前指向的存儲位置沒有任何作用。 AWideString指向的數據將不受C ++函數的影響。
如果C ++代碼將數據復制到字段中包含的地址中,則它將覆蓋AWideString
指向的字符串數據。 由於AWideString
是由Delphi管理的字符串,並且C ++函數將向該字符串存儲區復制比原始字符串已分配空間更多的數據,因此在C ++函數中復制數據將寫入Delphi分配的字符串緩沖區的末尾,並且可能破壞Delphi堆。 稍后可能會發生崩潰。 因此,僅將指針分配給該字段,而不復制數據是一件好事! ;>
若要查看C ++函數發生了什么變化,在調用C ++函數之后,您的Delphi代碼應輸出記錄的MyWideString
字段的內容。
同步結構中的字段順序。 您可以使用錯誤的指針破壞內存堆。 另外,請檢查Delphi和C ++中的對齊方式。
您管理的字符串字段不正確。 PWideChar
和PChar
是不一樣的東西“指針WideString的”和“指針AnsiString類型”。 PWideString
Delphi具有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
)值是非常危險的,特別是如果由於RTL差異,內存管理器差異而使EXE和DLL是在不同版本的Delphi / C ++ Builder中編寫的話,有效負載布局差異等。不過, WideString
可以通過,因為它的內存和布局由操作系統而不是RTL控制。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.