我有一个用C ++编写的dll。它看起来像这样:
头文件:
CSpeedTreeRT* NewSpeedTree(void) {
return new CSpeedTreeRT();
}
void DeleteTree(CSpeedTreeRT* handle) {
delete handle;
}
bool LoadTree(CSpeedTreeRT* handle, const unsigned char* pBlock, unsigned int nNumBytes) {
return handle->LoadTree(pBlock, nNumBytes);
}
cpp文件:
TNewSpeedTreeFunc = function (): Cardinal; cdecl;
TLoadTreeFunc = function (AHandle: Cardinal; const ABlock: String; ANumBytes: Cardinal): Boolean; cdecl;
TDeleteTreeFunc = procedure (AHandle: Integer); cdecl;
Delphi类型定义:
DllHandle: Cardinal;
NewSPeedTreeFunc : TNewSpeedTreeFunc;
LoadTreeFunc: TLoadTreeFunc;
DeleteTreeFunc: TDeleteTreeFunc;
DllHandle := LoadLibrary('SpeedTreeFT.dll');
@NewSpeedTreeFunc := GetProcAddress(DllHandle, 'NewSpeedTree');
@LoadTreeFunc := GetProcAddress(DllHandle, 'LoadTree');
@DeleteTreeFunc := GetProcAddress(DllHandle, 'DeleteTree');
SpeedTreeHandle := NewSpeedTreeFunc;
... call other functions here ...
DeleteTreeFunc(SpeedTreeHandle);
FreeLibrary(DLLHandle);
然后我使用LoadLibrary将dll加载到delphi应用程序中。
DECLARE
@CapitalizeAmount DECIMAL(18,12),
@SheduleAmount DECIMAL(36,12),
@NewRebate DECIMAL(18,12),
@LostInterst DECIMAL(18,8)=0,
@RebateRate DECIMAL(18,12)
SELECT @SheduleAmount= SUM(A.IntBalance)
FROM destinity_LE_FacShedule AS A
WHERE A.facno =@FacNo
AND A.Status IN ('N','S')
AND CAST(A.DueDate AS DATE) > CAST(@CurrentDate AS DATE) --0X00001
AND A.RefCode IN ('RE','PP')
SET @NewRebate =(@RebateRate *1.00000000000 *((@SheduleAmount- @LostInterst)/@SheduleAmount))
SET @NewRebate=(case when @NewRebate<0 then 0 else @NewRebate END)
SET @RebateRate =@NewRebate
IF @RebateRate IS NULL
BEGIN
RAISERROR('REBATE RATE IS NULL!',16,1)
END
UPDATE destinity_LE_FACTermination
SET OldRebate =@RebateRate
FROM destinity_LE_FACTermination
WHERE facno =@FacNo AND TerminationNo=@TerminationNo
除了LoadTree之外,Dll还会导出其他功能,为了清楚起见,我只是删除了它们。
如果我运行一次,一切正常,我可以调用dll中的其他函数,我得到了预期的结果。当我第二次运行它时,我在调用NewSpeedTree时遇到了Access Violation异常。我还注意到对DeleteTree的调用不会从应用程序中释放内存。
我是否在dll中以正确的方式进行操作?可能导致这个问题的原因是什么?
EDIT1:在代码块中提供了更多信息。
答案 0 :(得分:3)
最大的问题似乎是您宣布pBlock
为string
!
宣言:
bool LoadTree(CSpeedTreeRT* handle, const unsigned char* pBlock, unsigned int nNumBytes);
应翻译为:
type
TLoadTreeFunc = function(Handle: THandle; const pBlock: PByte;
nNumBytes: Cardinal): LongBool cdecl;
unsigned char
是Byte
,指向它的指针是PByte
。要使用它,只需将指针传递给您保留的块的第一个字节(例如,使用TBytes
设置为适当长度的SetLength
。
类似的东西:
var
Block: TBytes;
begin
SetLength(Block, the_required_length);
if LoadTree(SpeedTreeHandle, @Block[0], Length(Block)) then
// etc...
string
是Delphi类型,在Delphi 2009或更高版本中,它甚至是UnicodeString
。但即使它是2009年之前,字符串是AnsiString
,传递它也是错误的。 AnsiString
和UnicodeString
都是特定于Delphi的,不能用作用C ++编写的DLL的参数类型。所以永远不要将char *
或unsigned char *
声明为string
,但始终分别为PAnsiChar
或PByte
。
我的这些文章中的更多信息:"DLL dos and don'ts"和"Pitfalls of converting"。