开发者

Delphi: Access violation after calling function from external DLL (C++)

There's a function, written in C++ and compiled as DLL, which I want to use in my Delphi application.

Scraper.cpp:

SCRAPER_API bool ScraperGetWinList(SWin winList[100])
{
    iCurrWin=0;
    memset(winList,0,100 * sizeof(SWin));
    return EnumWindows(EnumProcTopLevelWindowList, (LPARAM) winList);
}

Scraper.h:

#ifdef SCRAPER_EXPORTS
#define SCRAPER_API __declspec(dllexport)
#else
#define SCRAPER_API __declspec(dllimport)
#endif

struct SWin
{
    char title[512];
    HWND hwnd;
};

extern "C" {
    SCRAPER_API bool ScraperGetWinList(SWin winList[100]);
}

This is how I declare the function in the Delphi application:

type
  tWin = record
    Title: Array [0..511] of Char;
    hWnd: HWND;
  end;

  tWinList = Array [0..99] of tWin;

function ScraperGetWinList(var WinList: tWinList): Boolean; stdcall; external 'Scraper.dll';

The function works, but when it's finished, I receive Debugger Fault Notification: Project ... faulted with message: ''access violation at 0x0012f773: write of address 0xffffffc0'. Process Stopped. Use Step or Run to continue.

If I add __stdcall (after SCRA开发者_StackOverflowPER_API bool) in Scraper.cpp and Scraper.h, then the Delphi application doesn't start at all: The procedure entry point ScraperGetWinList could not be located in the dynamic link library Scraper.dll.


You need to put __stdcall after bool. The complete declaration, after all macros expand, should look like this:

extern "C"
{
    __declspec(dllexport)
    bool __stdcall ScraperGetWinList(SWin winList[100]);
}

EDIT: Looks like you'll also need a .def file there. It's a file that lists every function exported in the DLL, and in this case it's needed only to force C++ compiler not mangle the exported names. Contents would be this:

EXPORTS
ScraperGetWinList

I'm not sure which C++ compiler you're using, but normally you'd just specify the .def file along with .cpp; for example, the following works for VC++:

cl.exe foo.cpp foo.def

Also, you will need to tell Delphi to use stdcall as well, by inserting stdcall keyword right before external in your Delphi function declaration.


If you use a packed array[1..512] of char you will not need the ConvertToString() function.

"packed array of char" is assignment compatible with Delphi string (this goes back to very early forms of Pascal - packed array of char WAS the string type). You nmay need to scab the result for a null ($0) char to find the end of the C-string

Also what Delphi version are you using? if Delphi 2009 + you will need to use packed array[1..512] of AnsiChar ;


It would be good to know where exactly your access violation occurs. What variable/memory location is your runtime trying to access?

Then find out if this location should actually be accessible, and if so, why it's not.

My suspicion: you access an array element that isn't initialized correctly.

  Index := 0;
  S := ConvertToString(myWinList[Index].Title); 
  while S <> '' do
  begin
    WinListMemo.Lines.Add(S);
    Inc(Index);
    //////// Is Index pointing to a valid entry here?  No check!
    S := ConvertToString(myWinList[Index].Title);
  end;

Either

  • the dll does not initialize it correctly,
  • or there is another way to find out the last element.
  • or you simply ran off the array altogether: the 101th element is also dereferenced. and the 102nd, if that memory location happens to contain a 0 character.


Check that the definition of your Delphi function matches what you are declaring the C++ function as too. In particular, make sure that you have stdcall at the end, and that your bool values are going to be consistent. C++ and Delphi use different values and sizes for bool, depending on the C++ compiler, so it may be better to use an appropriately sized Integer. As the size of the bool may not match the C++ size, this can affect the stack, and thus cause access violations.

[edited to remove mixed language duff response]

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜