2009-11-10 91 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

相关问题