Delphi: Access violation after calling a function from an external DLL (C ++)
There is a function there, written in C ++ and compiled as a DLL, that 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 a function in a 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 finished, I get a debugger error: Project ... with an error with the message: "Access violation at 0x0012f773: writing address 0xffffffc0". The process has been stopped. Use Step or Run to continue.
If I add __stdcall
(after SCRAPER_API bool
) to Scraper.cpp and Scraper.h, then the Delphi application does not start at all: the entry point to the ScraperGetWinList procedure cannot be located in the Scraper .dll dynamic link library.
source to share
You need to put __stdcall
after bool
. The complete declaration, after expanding the macros, should look like this:
extern "C"
{
__declspec(dllexport)
bool __stdcall ScraperGetWinList(SWin winList[100]);
}
EDIT: Looks like you also need a .def file. This is the file that lists all the functions exported to the DLL, in which case it only needed to force the C ++ compiler not to interfere with the exported names. The content will be as follows:
EXPORTS
ScraperGetWinList
I'm not sure which C ++ compiler you are using, but usually you just specify the .def file along with the .cpp; for example the following works for VC ++:
cl.exe foo.cpp foo.def
In addition, you will need to tell Delphi to use stdcall by adding the keyword stdcall
just before external
the Delphi function declaration.
source to share
If you are using a packed array [1..512] of char, you do not need the ConvertToString () function.
"packed char array" is a Delphi string compatible assignment (this refers to the very early forms of pascal array from char WAS string type). You will need a scrab result for a null ($ 0) char to find the end of the C string
Also which version of Delphi are you using? if Delphi 2009+ you need to use packed array [1..512] from AnsiChar ;
source to share
It would be good to know exactly where your access violation is happening. What variable / memory location is your work environment trying to access?
Then find out if the location should really be available, and if so, why it isn't.
My suspicion: you are accessing an array element that is not 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;
Or
- dll does not initialize it correctly,
- or is there another way to find out the last item.
- or you just deleted the array completely: element 101 is dereferenced as well. and 102nd if this memory location contains character 0.
source to share
Make sure your Delphi function definition matches what you also declare a C ++ function. In particular, make sure you have a stdcall at the end and that your bool values ββare consistent. C ++ and Delphi use different values ββand sizes for bool, depending on the C ++ compiler, so it's better to use an appropriate Integer size. Since the bool size may not match the C ++ size, it can affect the stack and therefore cause access violations.
[edited to remove mixed language mixing reaction]
source to share