Cannot use DLL (written in C ++) in Delphi: procedure entry point could not be found

I built the DLL in Visual Studio (C ++ source code that I hardly understand). Here is a snippet of Scraper.h :

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

SCRAPER_API bool ScraperGetWinList(SWin winList[100]);

      

Now I am trying to use the above function in a Delphi application:

type
  tWin = record
    title: String;
    hwnd: HWND;
  end;

function ScraperGetWinList(var WinList: Array of tWin): Boolean; external 'Scraper.dll';

var
  myWinList: Array [1..100] of tWin;

procedure TMainForm.GetWinListButtonClick(Sender: TObject);
begin
  ScraperGetWinList(myWinList);
  ...

      

The project does not compile and I receive the following message: The entry point of the ScraperGetWinList procedure cannot be located in the dynamic link library: Scraper.dll.

What am I doing wrong?

+2


source to share


4 answers


From my experience with Linux, I would say that you are facing a " name-mangling . The entry point to your routine is not called" ScraperGetWinList ", but something like" _ZN18ScraperGetWinListEpN4SWin ".

The point is that, unlike C, in C ++ the entry point name is not the same as the function name. Not surprising: suppose you have a set of overloaded functions; they should have different entry points to your DLL. This is where the title comes into play.

The most common solution to this problem is to define the interface of your library so that it will use the C calling convention. After that, the interface functions will not be executed with the interface functions.

Note that you do not need to write the entire library in C, you only need to declare functions in order for them to call entry points of type C.



It is usually written like this:

extern "C" {

SCRAPER_API bool ScraperGetWinList(SWin winList[100]);
// More functions

}

      

Recompile your library and use it in Delphi without issue.

Note that you must also tweak the calling conventions (stdcall or cdecl) to match the C ++ and Delphi headers. However, this is best explained in another question.

+6


source


Most likely a problem with the name mangling. The name mangling is usually done, it is C ++ code, and when writing a C ++ DLL to be used by code in another langauge, you must use the outer "C" construct, as Pavel Shved already suggested.

When using DLLs, especially when you click on other languages, you should also look at calls. I suggest you point in delphi and C ++ to use stdcall causing convstion. This is the calling convention used by the windows api as well, so it guarantees better compatibility between different compilers.

This would mean

extern "C" {

SCRAPER_API __stdcall bool ScraperGetWinList (SWin winList [100]);

}

and



ScraperGetWinList function (var WinList: tWin array): Boolean; external 'Scraper.dll';

But that's not all, the convention of calling stdcall affects the mangling name, and it turns out to be something like _ScraperGetWinList @ 4 (where 4 is the parameter size, where the array will have a pointer to the first element, so 4 bytes)

To confirm the correct characters to use, I suggest Dependency Walker ( http://www.dependencywalker.com/ ) shows that it is the function names that are exported by the DLL. After confirming the name "_ScraperGetWinList @ 4", add it to delpgi as follows:

ScraperGetWinList function (var WinList: tWin array): Boolean; external 'Scraper.dll' name '_ScraperGetWinList @ 4';

+4


source


Also make sure C ++ and delphi use the same calling convention. Take a look at jn's answer here and here

+2


source


Did you actually export the entry point function to C ++ code? This actually got in the way of me the first time I compiled a C ++ dll in Visual Studio for use in a dotnet application.

For example, I needed to expose a print driver in unmanaged code so that some other developers could access it in VB.net. This is what I did.

In foo.cpp:

extern "c" {
  ___declspec(dllexport) bool FooBar()
  {
     // Call some code on my cpp objects to implement foobar
  }
}

      

Then, in a file called foo.def:

LIBRARY   "mylib"

EXPORTS
        FooBar 
        AnyOtherFunctionsItExports

      

This is how I got it working. I may not be doing my best. I have a little bit of C ++ experience and also mostly don't work on windows.

+1


source







All Articles