Pergunta

Eu tenho uma DLL externo escrito em C ++. A peça abaixo declara um struct tipo e uma função, que, sendo dado um ponteiro, preenche uma variável deste tipo:

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);
}

Eu declarar um tipo semelhante na minha Delphi aplicação e chamar a função acima:

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

Quando a função é chamada fico Debugger Notificação Exceção:

Project ... levantou exceção classe EAccessViolation com a mensagem 'Violação de acesso no endereço 10103F68 no módulo 'Scraper.dll'. Leia de endereço FFFFFFFC'. Processo parou.

Outras funções exportadas a partir da mesma multa trabalho DLL, então o meu palpite é que cometi um erro na declaração do tipo. Todas as dicas serão muito apreciados, como eu estou morto preso neste momento.

Foi útil?

Solução

A principal id problema que C ++ CString e Delphi Cordas são tipos incompatíveis.

Se você quiser passar dados dessa maneira, você deve usar arrays de caracteres de comprimento, quer fixos ou C-Style terminada nula cordas (PChar em Delphi).

C ++ seria algo como:

char Dealer[100][10];

Por favor edite se errado - Há muitos anos que eu fiz qualquer C codificação

Delphi

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

ou

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

ou se estiver usando C-string (TCHAR em código API)

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

De referir ainda que a corda, Char (e, portanto, PChar) alterado de byte para byte duplo (UCS 16) em Delphi 2009.

Outros tipos de dados podem ser diferentes, por exemplo, como bem Em Delphi de palavra é de 16 bits, mas pode ser diferente em C ++. Se os tipos possíveis utilização específicos que são comuns na API do Windows, tais como USHORT em vez de "int não assinado" e Word

Outras dicas

A primeira coisa que você precisa fazer é se certificar de suas definições de struct são os mesmos. A menos que você estiver usando um compilador de 16 bits C ++, o tipo unsigned int definitivamente não é um tipo de 16 bits, e ainda tipo Word da Delphi é. Use Cardinal vez. Se você tiver Delphi 2009 ou mais tarde, então o seu tipo Char é um tipo de dois bytes; uso AnsiChar vez.

Mesmo com essas mudanças, no entanto, você está condenado. Seu tipo C ++ usa o tipo de CString específico da Microsoft. Não há equivalente a isso em Delphi ou qualquer outra linguagem não-Microsoft-C ++. Você já tentou usar tipo string da Delphi em seu lugar, mas eles são apenas semelhante em seus nomes. Seu layout binário na memória não é o mesmo em todos.

Não há nada que você pode com essa definição struct.

Se você ou alguém em sua organização é o autor desse DLL, então alterá-lo a olhar mais como qualquer outro DLL que você já usou. Passe ponteiros de caracteres ou matrizes, e não qualquer tipo de classe. Se o DLL é de outro partido, em seguida, solicitar o autor a alterá-lo para você. Essa escolha de API foi irresponsável e míope.

Se você não pode fazer isso, então você terá que escrever um wrapper DLL em C ++ que leva o struct C ++ e converte-lo para outro struct que é mais amigável para não-C ++ idiomas.

Enquanto só a leitura de dados a partir da DLL e não tentando gravar dados a ele, em seguida, tentar substituir CString com PAnsiChar (ou PWideChar se a DLL foi compilado para Unicode), ou seja:

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; 

Com o que disse, o acidente você está enfrentando é mais provável resultado do ponteiro não inicializado que você está passando para ScraperScrape (). Você precisa mudar o seu código Delphi para inicializar essa variável, isto é:

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

Melhor seria se livrar da variável pCurState por completo:

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

Melhor seria para se livrar do alias pSScraperState por completo:

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

var
  CurState: SScraperState;        
begin        
  if ScraperScrape(hWnd, CurState) = 0 then  
    ...
end;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top