从Delphi应用程序调用外部函数(C+;+;)时发生访问冲突 我有一个用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应用程序调用外部函数(C+;+;)时发生访问冲突 我有一个用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); },c++,delphi,types,dllimport,access-violation,C++,Delphi,Types,Dllimport,Access Violation,我在我的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; car

我在我的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处的访问冲突”。读取地址FFFFFFF C'。进程已停止


从同一DLL导出的其他函数工作正常,因此我猜我在类型声明中犯了错误。任何技巧都将被高度赞赏,因为我已经死在这一点上。

< P>主要问题ID是C++ +强> CString < /String >和Delphi < Strige> String 是不兼容类型。p> 如果希望以这种方式传递数据,则应使用固定长度字符数组或C样式的空终止字符串(Delphi中的PChar)

C++将类似于:

char Dealer[100][10];
请编辑,如果错误-这是许多年以来,我做任何C编码

德尔菲

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

或者如果使用C字符串(API代码中的TCHAR)

还请注意,在Delphi2009中,字符串、字符(以及PChar)从单字节更改为双字节(UCS 16)


<> P>其他数据类型可能不同,例如在Delphi Word中是16位,但在C++中可能不同。如果可能,请使用Windows API中常见的特定类型,例如USHORT而不是“unsigned int”和Word,您需要做的第一件事是确保结构定义相同。除非你使用的是一个16位C++编译器,否则类型<代码>未签名的int 绝对不是16位类型,而Delphi的 Word 类型是。改为使用
Cardinal
。如果您有Delphi 2009或更高版本,那么您的
Char
类型是两字节类型;改用AnsiChar

即使有了这些变化,你也注定要失败。您的C++类型使用微软特定的<代码> cSnc>代码>类型。没有与Delphi或任何其他非Microsoft-C++语言中的等效语言。您试图使用Delphi的
string
类型来代替它,但它们只是名称相似。它们在内存中的二进制布局完全不同

您无法使用该结构定义

如果您或组织中的其他人是该DLL的作者,请将其更改为与您使用过的其他DLL更相似。传递字符指针或数组,而不是任何类类型。如果DLL来自另一方,请请求作者为您更改它。选择API是不负责任和短视的


如果你不能这样做,那么你必须在C++中编写一个包装器DLL,它采用C++结构,并将它转换成另一个对非C++语言更友好的结构。

< P>只要你只从DLL读取数据,而不尝试向它写入数据,那么你就可以尝试用PAnsiChar替换cStand。(如果DLL是针对Unicode编译的,则为PWideChar),即:

话虽如此,您遇到的崩溃更有可能是由于您传递给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;
function ScraperScrape(wnd: HWND; var state: SScraperState): Integer; cdecl; external 'Scraper.dll';  

var
  CurState: SScraperState;        
begin        
  if ScraperScrape(hWnd, CurState) = 0 then  
    ...
end;
最好是完全去掉pSScraperState别名:

var
  CurState: SScraperState;        
begin        
  if ScraperScrape(hWnd, @CurState) = 0 then  
    ...
end;
function ScraperScrape(wnd: HWND; var state: SScraperState): Integer; cdecl; external 'Scraper.dll';  

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

你能把调试器附加到你的刮削器.dl文件中,找出代码中的哪一行代码,即擦除刮除< /代码>函数是否触发异常?你应该显示什么是“刮削器API宏”,这样我们就可以检查你的调用约定是否匹配。亚当,通过注释/不注释C++代码,我发现问题是由cScript引起的。变量,我在Delphi code.dangph中声明为PAnsiChar数组,调用约定不是问题。它们过去是,但在我的前一个问题中已经解决了:-)我已经根据上述内容更改了类型声明以及函数的声明和调用,但是我仍然收到一条访问冲突错误消息(虽然现在有不同的地址)。是的,这个问题似乎是由CString变量引起的。我想我必须请求对C++代码进行一些更改。谢谢
function ScraperScrape(wnd: HWND; var state: SScraperState): Integer; cdecl; external 'Scraper.dll';  

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