【问题标题】:Need convert VC code to Delphi需要将VC代码转换为Delphi
【发布时间】:2010-01-14 07:28:33
【问题描述】:

我需要在我的delphi代码中调用一个DLL文件,这里是DLL头文件的代码sn-p:

#define BookInfoDLL __declspec(dllexport)

struct _BookTime
{
    unsigned char day;
    unsigned char month;
    unsigned short year;
};

struct _stBookData
{
    unsigned char encrypt;
    _BookTime bkTime;
    unsigned int  PageCount;
};

int BookInfoDLL UpdateBooks(const char * const pBookID, 
  const char cBookTypeWord, 
  const _stBookData * const pBookData, 
  const int nBookDataCounter);

我需要在我的 delphi 代码中调用 dll 函数“UpdateBooks”。 我怎样才能将这些代码转换成d​​elphi?谢谢!

【问题讨论】:

  • 什么是 sizeof(_BookTime) 和 sizeof(_stBookData) ?记录被打包或对齐到机器字边界?
  • Leo,翻译的哪一部分有问题?要求翻译这个特定的代码会使这个问题面临被“过于本地化”而被关闭的危险。全世界的普通观众并不关心如何翻译这个特定的代码。也许你想知道“struct”是什么意思,或者 Delphi 类型“unsigned char”对应什么,或者那个宏做了什么,或者所有那些“const”修饰符有什么效果。问一个可能很容易应用于其他一些 C++ 代码以及此代码的问题。

标签: delphi dll visual-c++


【解决方案1】:

使用h2pas!虽然它是一个 freepascal 工具,但它应该可以生成与 Delphi 兼容的代码。

【讨论】:

    【解决方案2】:

    非托管 Delphi 代码的片段(未经测试,但根据 cmets 中的建议进行编译和更改):

    interface
    
    type
    
      TBookTime = packed record
        day   : byte; // unsigned 8-bit  
        month : byte;
        year  : word; // unsigned 16-bit
       end;
    
      TBookData = packed record
        encrypt   : byte;
        bkTime    : TBookTime;
        PageCount : LongWord;   // unsigned 32-bit
      end;
    
      TBookDataPtr = ^TBookData;
    
    function UpdateBooks(
               pBookID          : PChar;
               cBookTypeWord    : byte;
               pBookData        : TBookDataPtr;
               nBookDataCounter : integer
             ) : integer; stdcall; external 'dll_file_name.dll' name 'UpdateBooks';
    
    implementation
    
     // ... 
    
    end;
    

    从 delphi 代码简单调用 UpdateBooks(...)


    更新:代码已更改,感谢您的评论!

    下面是用于示例调用的 sn-ps ...

    所有sn-ps的通用函数和常量:

    // --- Test data fill utility and constants -----------------------------------
    
    const
      BOOK_ID         = 'Test Book ID';
      BOOK_TYPE_WORD  = 'T';
      BOOK_DATA_COUNT = 5;
    
    procedure FillTestBookData(pBookData : TBookDataPtr; iTestNum : integer);
    begin
      if(pBookData = nil) then exit;
    
      pBookData^.encrypt := iTestNum;
      pBookData^.bkTime.day := iTestNum;
      pBookData^.bkTime.month := iTestNum;
      pBookData^.bkTime.year := 2000 + iTestNum;
      pBookData^.PageCount := iTestNum;
    
    end;
    

    常用Delphi风格的调用函数:

    // --- Test procedure in Delphi style -----------------------------------------
    
    procedure TestBookUpdate_DelphiStyle;
    var
      bookArray   : array of TBookData;
      iBookNumber : integer;
    begin
    
      SetLength(bookArray, BOOK_DATA_COUNT);
      try
    
        for iBookNumber := Low(bookArray) to High(bookArray) do begin
          FillTestBookData( @(bookArray[iBookNumber]), iBookNumber );
        end;
    
        UpdateBooks( 
          PChar(BOOK_ID), ord(BOOK_TYPE_WORD), 
          @(bookArray[Low(bookArray)]), BOOK_DATA_COUNT 
        );
    
      finally
        SetLength(bookArray, 0); // no explicit requirement to include in code
      end;
    
    end;
    

    奖励:C 风格和 Pascal 风格的相同测试调用 :-)

    // --- Test procedure in Old Delphi (plain Pascal) style ----------------------
    
    type
      TBookDataOldArray = array[0..0] of TBookData;
      TBookDataOldArrayPtr = ^TBookDataOldArray;
    
    // Store range checking compiler option state
    {$IFOPT R+}
      {$DEFINE RANGE_CHECK_ON}
    {$ENDIF}
    
    procedure TestBookUpdate_OldDelphiStyle;
    var
      bookArrayPtr : TBookDataOldArrayPtr;
      iBookNumber  : integer;
    begin
    
      GetMem(bookArrayPtr, BOOK_DATA_COUNT*sizeof(TBookData));
      try
        // Disable range checking compiler option
        {$R-}
    
        for iBookNumber := 0 to BOOK_DATA_COUNT - 1 do begin
          FillTestBookData(@(bookArrayPtr^[iBookNumber]), iBookNumber);
        end;
    
        // Restore range checking compiler option if turned on before disabling
        {$IFDEF RANGE_CHECK_ON}{$R+}{$ENDIF}
    
        UpdateBooks(
          PChar(BOOK_ID), ord(BOOK_TYPE_WORD), TBookDataPtr(bookArrayPtr), BOOK_DATA_COUNT
        );
    
      finally
        FreeMem(bookArrayPtr);
      end;
    
    end;
    
    // --- Test procedure in C style ---------------------------------------------
    
    procedure TestBookUpdate_CStyle;
    var
      bookArrayPtr  : TBookDataPtr;
      curBookPtr    : TBookDataPtr;
      curBookNumber : integer;
    begin
    
      bookArrayPtr := AllocMem( BOOK_DATA_COUNT * sizeof(TBookData) );
      try
        curBookNumber := 0;
        curBookPtr := bookArrayPtr;
        while(curBookNumber < BOOK_DATA_COUNT) do begin
          FillTestBookData( curBookPtr, curBookNumber );
          inc(curBookNumber);
          inc(curBookPtr, 1);
          // Another pointer increment solution is :
          // curBookPtr := PChar(curBookPtr) + sizeof(TBookData);
        end;
    
        UpdateBooks( PChar(BOOK_ID), ord(BOOK_TYPE_WORD), bookArrayPtr, BOOK_DATA_COUNT );
    
      finally
        FreeMem(bookArrayPtr);
      end;
    
    end;
    

    【讨论】:

    • 参数“pBookdata”可能包含多个TBookData结构,“nBookDataCounter”指出TBookData结构的数量。
    • Leo,这不一定是 ThinkJet 翻译的问题,但它会使函数调用看起来有点奇怪。您将拥有一个数组,但您只需将第一个元素传递给函数:UpdateBooks(..., BookData[0], Length(BookData))。 ThinkJet,C++中的指针参数最好直接翻译成Delphi中的指针参数。
    • 记录对齐?应该是需要打包的。此外,我认为删除除 pbookdata 之外的所有 CONST,因为为此删除了取消引用 (*)。
    • 感谢所有评论员!代码根据cmets改了,欢迎下次复习! :)
    【解决方案3】:

    我昨天结束了我的第一次 C 标头转换。 TeamB 成员 Rudy Velthuis 的文章和工具对我非常非常有帮助,特别是

    Pitfalls of converting

    Conversion Helper Package

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-18
      • 2015-07-15
      • 1970-01-01
      • 2012-08-12
      • 1970-01-01
      相关资源
      最近更新 更多