2009-11-10 23 views
3

我有用C++編寫的外部DLL。下面的片聲明一個結構類型和功能,這,報錯一個指針,滿足了這一類型的變量:從Delphi應用程序調用外部函數(C++)時的訪問衝突

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 
    ... 

當函數被調用時,我得到調試例外通知:

項目...引發的異常類EAccessViolation'模塊'Scraper.dll'中地址爲10103F68的消息'訪問衝突。閱讀地址FFFFFFFC'。進程停止。

從同一個DLL導出的其他函數工作正常,所以我的猜測是我在類型聲明中犯了一個錯誤。任何提示將高度讚賞,因爲我死在這一點上。

+0

您可以將調試器附加到您的Scraper.dll文件並找出'ScraperScrape'函數中的哪行代碼觸發異常? – 2009-11-10 00:38:20

+0

您應該顯示SCRAPER_API宏是什麼,以便我們可以檢查您的調用約定是否匹配。 – 2009-11-10 04:08:21

+0

Adam,通過評論/取消註釋C++代碼,我發現問題是由CString變量引起的,我在Delphi代碼中聲明它爲PAnsiChar數組。 – Mikhail 2009-11-10 23:30:00

回答

3

C++的主要問題ID CString和Delphi 字符串是不兼容的類型。

如果您想以這種方式傳遞數據,您應該使用固定長度的字符數組或C樣式空終止的字符串(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; 

或if使用C-串(TCHAR在API代碼)

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

還要注意的是字符串,字符(並因此PChar類型)從單個字節在Delphi改變爲雙字節(UCS 16)2009年

其他數據類型也可能不同,例如在Delphi中,Word是16位,但在C++中可能不同。如果可能,請使用Windows API中常見的特定類型,例如USHORT而不是「unsigned int」和Word

+0

是的,這個問題似乎是由CString變量引起的。我想我必須要求對C++代碼進行一些更改。謝謝。 – Mikhail 2009-11-10 23:33:11

3

您需要做的第一件事是確保您的結構定義相同。除非您使用16位C++編譯器,否則unsigned int類型絕對不是16位類型,但Delphi的Word類型是。改爲使用Cardinal。如果你有Delphi 2009或更高版本,那麼你的Char類型是一個雙字節類型;改爲使用AnsiChar

儘管有了這些變化,但你註定了。您的C++類型使用特定於Microsoft的CString類型。在Delphi或任何其他非Microsoft-C++語言中都沒有這種功能。您試圖使用德爾福的string類型,但它們的名稱只有相似之處。他們在內存中的二進制佈局並不相同。

沒有什麼可以與該結構定義。

如果您或您組織中的其他人是該DLL的作者,則將其更改爲您曾使用過的其他任何DLL。傳遞字符指針或數組,而不是任何類類型。如果DLL來自另一方,則請求作者爲您更改它。 API的選擇是不負責任和短視的。

如果你不能這樣做,那麼你必須在C++中編寫一個包裝DLL,它接受C++結構並將其轉換爲另一個對非C++語言更友好的結構。

2

只要你只能從DLL讀取數據,而不是試圖向其中寫入數據,然後嘗試用PAnsiChar替代CString的(或PWideChar如果DLL被編譯爲Unicode)的,即:

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; 
+0

我已經改變了類型聲明以及根據上面的函數的聲明和調用,但仍然收到訪問衝突錯誤消息(儘管現在使用不同的地址)。 – Mikhail 2009-11-10 03:31:20

相關問題