获取和删除在DLL中创建的对象

时间:2018-04-02 14:48:36

标签: delphi interop

我有一个用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:在代码块中提供了更多信息。

1 个答案:

答案 0 :(得分:3)

最大的问题似乎是您宣布pBlockstring

宣言:

bool LoadTree(CSpeedTreeRT* handle, const unsigned char* pBlock, unsigned int nNumBytes);

应翻译为:

type
  TLoadTreeFunc = function(Handle: THandle; const pBlock: PByte;
                    nNumBytes: Cardinal): LongBool cdecl;

unsigned charByte,指向它的指针是PByte。要使用它,只需将指针传递给您保留的块的第一个字节(例如,使用TBytes设置为适当长度的SetLength

类似的东西:

var
  Block: TBytes;
begin
  SetLength(Block, the_required_length);
  if LoadTree(SpeedTreeHandle, @Block[0], Length(Block)) then
    // etc...

将类型字符串传递给(非Delphi)DLL

string是Delphi类型,在Delphi 2009或更高版本中,它甚至是UnicodeString。但即使它是2009年之前,字符串是AnsiString,传递它也是错误的。 AnsiStringUnicodeString都是特定于Delphi的,不能用作用C ++编写的DLL的参数类型。所以永远不要将char *unsigned char *声明为string,但始终分别为PAnsiCharPByte

我的这些文章中的更多信息:"DLL dos and don'ts""Pitfalls of converting"