我以前问一个关于一个Delphi和C / C ++ DLL问题。
我现在已经大约记录/结构的另一个问题。 该DLL应能够动态地改变从MainAPP指针瓦尔的价值。
我的德尔福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类型”。 德尔福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;
}
随着中说,它可以是非常危险的操作AnsiString
(和UnicodeString
)值跨越这样一个DLL边界,特别是如果EXE和DLL被写入由于RTL差异,存储器管理器的差异不同版本的Delphi / C ++生成器的,有效载荷布局的差异等WideString
是确定以绕过,但因为它的内存和布局由操作系统,而不是RTL控制。
这可能是不是在C ++代码分配给该点的崩溃的原因TheWideString
指针,但我确实看到了期待的一个问题...
我注意到,你把字符串数据的地址德尔福AWideString
变量指向到MyWideString
的记录的字段。 传递记录到C ++函数,这一个新的指针值指定给TheWideString/MyWideString
的记录的字段中。 当执行返回到Delphi代码,你输出的内容AWideString
变量。
您的评论表明您期望的AWideString变量的内容由C ++函数被改变,但这不是会发生什么。
C ++函数改变了结构中的字段。 当然这并不能认为场先前指向的内存位置。 该AWideString点的数据,以将不被C ++函数的影响。
如果C ++代码复制的数据到包含在字段中的地址,那么它会覆盖在字符串数据AWideString
点。 由于AWideString
是一个Delphi管理的字符串,C ++函数将复制更多的数据比原来的字符串,字符串存储区已分配的空间,在C ++函数复制数据会写过去德尔福的最后分配的字符串缓冲区,可能腐败德尔福堆。 崩溃后可能会出现一段时间。 所以这是一个很好的,你只分配指针到外地,而不是复制数据! ;>
要查看C ++函数改变了什么,你的Delphi代码应输出的内容MyWideString
记录的字段中调用C ++函数之后。
同步字段才能在结构。 您可以使用错误的三分球打破内存堆。 此外,检查在两者Delphi和C ++对准。