3

私はC++で書かれた外部DLLを持っています。以下の部分は、構造体型と関数を宣言しています。これらは、ポインターが与えられると、この型の変数を埋めます。

enum LimitType { NoLimit, PotLimit, FixedLimit };

struct SScraperState
{
    char        title[512];
    unsigned int    card_common[5];
    unsigned int    card_player[10][2];
    unsigned int    card_player_for_display[2];
    bool        dealer[10];
    bool        sitting_out[10];
    CString     seated[10];
    CString     active[10];
    CString     name[10];
    double      balance[10];
    bool        name_good_scrape[10];
    bool        balance_good_scrape[10];
    double      bet[10];
    double      pot[10];
    CString     button_state[10];
    CString     i86X_button_state[10];
    CString     i86_button_state;
    CString     button_label[10];
    double      sblind;
    double      bblind;
    double      bbet;
    double      ante;
    LimitType   limit;
    double      handnumber;
    bool        istournament;
};

extern "C" {
    SCRAPER_API int ScraperScrape(HWND hwnd, SScraperState *state);
}

Delphiアプリケーションで同様の型を宣言し、上記の関数を呼び出します。

interface

type
  LimitType = (NoLimit, PotLimit, FixedLimit);

  SScraperState = record
    title: Array [0..511] of Char;
    card_common: Array [0..4] of Word;
    card_player: Array [0..9, 0..1] of Word;
    card_player_for_display: Array [0..1] of Word;
    dealer: Array [0..9] of Boolean;
    sitting_out: Array [0..9] of Boolean;
    seated: Array [0..9] of String;
    active: Array [0..9] of String;
    name: Array [0..9] of String;
    balance: Array [0..9] of Double;
    name_good_scrape: Array [0..9] of Boolean;
    balance_good_scrape: Array [0..9] of Boolean;
    bet: Array [0..9] of Double;
    pot: Array [0..9] of Double;
    button_state: Array [0..9] of String;
    i86X_button_state: Array [0..9] of String;
    i86_button_state: String;
    button_label: Array [0..9] of String;
    sblind: Double;
    bblind: Double;
    bbet: Double;
    ante: Double;
    limit: LimitType;
    handnumber: Double;
    istournament: Boolean;
  end;

  pSScraperState = ^SScraperState;

function ScraperScrape(hWnd: HWND; State: pSScraperState): Integer; cdecl; external 'Scraper.dll';

implementation

var
  CurState: SScraperState;
  pCurState: pSScraperState;

  if ScraperScrape(hWnd, pCurState) = 0 then
  ...

関数が呼び出されると、デバッガー例外通知が表示されます。

プロジェクト...モジュール'Scraper.dll'のアドレス10103F68でメッセージ'アクセス違反を伴う例外クラスEAccessViolationを発生させました。アドレスFFFFFFFC'の読み取り。プロセスが停止しました。

同じDLLからエクスポートされた他の関数は正常に動作するため、型宣言を間違えたと思います。私はこの時点で行き詰まっているので、どんなヒントも高く評価されます。

4

3 に答える 3

3

C++ CStringDelphiStringが互換性のない型であるという主な問題ID。

この方法でデータを渡したい場合は、固定長の文字配列またはCスタイルのnullで終了する文字列(DelphiではPChar)のいずれかを使用する必要があります。

C++は次のようになります。

char Dealer[100][10];

間違っている場合は編集してください-Cコーディングを行ってから何年も経ちました

デルファイ

Dealer : packed array[0..9, 0..99] of char; 

また

type 
  TDealer = packed array[0..99] of char;
  ...
  Dealer : arry[0..9] of TDealer;

またはC文字列(APIコードのTCHAR)を使用している場合

Dealer: array[0..9] of PAnsiChar; // or PWideChar if source is UCS-16

また、Delphi 2009では、String、Char(したがって、PChar)がシングルバイトからダブルバイト(UCS 16)に変更されたことにも注意してください。

他のデータ型も異なる場合があります。たとえば、DelphiではWordは16ビットですが、C++では異なる場合があります。可能であれば、「unsigned int」やWordの代わりにUSHORTなど、WindowsAPIで一般的な特定の型を使用してください。

于 2009-11-10T01:07:40.347 に答える
3

最初に行う必要があるのは、構造体の定義が同じであることを確認することです。16ビットC++コンパイラを使用していない限り、型unsigned intは間違いなく16ビット型ではありませんが、DelphiのWord型は16ビット型です。Cardinal代わりに使用してください。Delphi 2009以降を使用している場合、Charタイプは2バイトタイプです。AnsiChar代わりに使用してください。

しかし、それらの変更があっても、あなたは運命にあります。C ++タイプは、Microsoft固有のタイプを使用しますCString。Delphiやその他のMicrosoft-C++以外の言語に相当するものはありません。代わりにDelphiの型を使用しようとしましstringたが、名前が似ているだけです。メモリ内のそれらのバイナリレイアウトはまったく同じではありません。

その構造体定義でできることは何もありません。

あなたまたは組織内の他の誰かがそのDLLの作成者である場合は、これまでに使用した他のすべてのDLLのように見えるように変更します。クラスタイプではなく、文字ポインタまたは配列を渡します。DLLが別のパーティからのものである場合は、作成者に変更を依頼してください。そのAPIの選択は無責任で、近視眼的でした。

それができない場合は、C++構造体を取得して非C++言語に適した別の構造体に変換するラッパーDLLをC++で作成する必要があります。

于 2009-11-10T01:10:30.670 に答える
2

DLLからデータを読み取るだけで、データを書き込もうとしない限り、CStringをPAnsiChar(またはDLLがUnicode用にコンパイルされている場合はPWideChar)に置き換えてみてください。

type
  LimitType = ( NoLimit, PotLimit, FixedLimit );

  SScraperState = record
    title: array[0..511] of AnsiChar;
    card_common: array[0..4] of Cardinal;
    card_player: array[0..9, 0..1] of Cardinal;
    card_player_for_display: array[0..1] of Cardinal;
    dealer: array[0..9] of Boolean;
    sitting_out: array[0..9] of Boolean;
    seated: array[0..9] of PAnsiChar;
    active: array[0..9] of PAnsiChar;
    name: array[0..9] of PAnsiChar;
    balance: array[0..9] of Double;
    name_good_scrape[0..9] of Boolean;
    balance_good_scrape[0..9] of Boolean;
    bet: array[0..9] of Double;
    pot: array[0.99]: Double;
    button_state: array[0.9] of PAnsiChar;
    i86X_button_state: array[0..9] of PAnsiChar;
    i86_button_state: PAnsiChar;
    button_label: array[0..9] of PAnsiChar;
    sblind: Double;
    bblind: Double;
    bbet: Double;
    ante: Double;
    limit: LimitType;
    handnumber: Double;
    istournament: Boolean; 
  end; 

そうは言っても、発生しているクラッシュは、ScraperScrape()に渡した初期化されていないポインターの結果である可能性が高くなります。その変数を初期化するには、Delphiコードを変更する必要があります。

...
pSScraperState = ^SScraperState;       

function ScraperScrape(wnd: HWND; state: pSScraperState): Integer; cdecl; external 'Scraper.dll';  

...

var
  CurState: SScraperState;        
  pCurState: pSScraperState;        
begin        
  pCurState := @CurState;
  if ScraperScrape(hWnd, pCurState) = 0 then  
    ...
end;

pCurState変数を完全に削除することをお勧めします。

var
  CurState: SScraperState;        
begin        
  if ScraperScrape(hWnd, @CurState) = 0 then  
    ...
end;

pSScraperStateエイリアスを完全に削除することをお勧めします。

function ScraperScrape(wnd: HWND; var state: SScraperState): Integer; cdecl; external 'Scraper.dll';  

var
  CurState: SScraperState;        
begin        
  if ScraperScrape(hWnd, CurState) = 0 then  
    ...
end;
于 2009-11-10T01:31:53.900 に答える