3

I created a function in delphi as below: function CheckResult():integer; stdcall; export;

The compiler is Delphi 64 and the output is CheckFunctions.dll

Then in the VC++ project (VS 2012), I write: extern "C" __declspec(dllimport) int __stdcall CheckResult();

and use it in a function, then I get the compiler error in C++ project:

error LINK2019: unresolved external symbol __imp_CheckResult referenced in function *

How can I do? Thanks

Arioch 'The
  • 15,799
  • 35
  • 62
frank
  • 1,252
  • 1
  • 12
  • 17
  • You can use NTCore CFF Explorer to look into your DLL and check if it is really win64 and if it really exports your function and under which name it was exported. – Arioch 'The May 30 '13 at 15:30
  • possible duplicate of [How to dllimport in C++](http://stackoverflow.com/questions/4041149/how-to-dllimport-in-c) – Arioch 'The May 30 '13 at 15:36
  • Useful articles: http://stackoverflow.com/questions/4041149/how-to-dllimport-in-c and http://www.rsdn.ru/article/baseserv/dlluse.xml – Arioch 'The May 30 '13 at 15:38

3 Answers3

4

You are missing an import library (.lib file) for the DLL. That's why the linker is giving that error message. Unfortunately Delphi won't generate a .lib file which is a bit of a weakness in my view.

You can solve the problem by either:

  1. Linking with LoadLibrary/GetProcAddress.
  2. Generate a suitable .lib file.

Option 2 is easy enough. Create a fake DLL project in Visual Studio. Arrange for it to export the same functions as your Delphi DLL. Implement these functions with empty stubs. Use a .def file rather than __declspec(dllexport) to avoid name decoration of your exports.

It's really obvious really. Make a fake DLL that has an identical interface to the real DLL. The same name, the same functions. The fake DLL needs no implementation because all you are doing is getting the MS tools to make the .lib file that Delphi cannot.

More details here: http://support.microsoft.com/kb/131313


FWIW I believe that the Delphi export modifier is ignored. Use an exports clause instead.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • weakness ? does def-file has any information that is not already contained in .dll ? i think that C++ relying on that def file is rather weakness. DRY. – Arioch 'The May 30 '13 at 15:57
  • @Arioch You aren't following. The weakness is that Delphi doesn't export the .lib file. Doing so would make it easier to interop with other languages. The fact that .lib files may be needless is irrelevant. C++ compilers use them and so Delphi would be better if it made them. – David Heffernan May 30 '13 at 16:00
  • 1
    There is an easier way to create a .lib import file for an existing .dll file. Use VC's command-line [LIB](http://http://msdn.microsoft.com/en-US/library/0b9xe492.aspx) utility, which is similar to C++Builder's command-line IMPLIB utility. – Remy Lebeau May 30 '13 at 18:20
  • 1
    According to the MS KB article that I linked to, this won't get the job done for stdcall functions. You need to stub out the functions in that case. – David Heffernan May 30 '13 at 18:47
  • You still use LIB to create the actual .lib file after compiling the stub, so my comment still stands. – Remy Lebeau May 30 '13 at 20:40
  • @Remy Your comment starts: "There is an easier way." How is it easier? – David Heffernan May 30 '13 at 21:21
  • Loaidng with GetProcAddress is not only easier, it fails in a nicer way. Implibs will result in your main app failing to start if the DLL cannot be found. Hardly any fun. Go with David's option #1, dear original poster. – Warren P May 30 '13 at 23:22
  • 1
    @WarrenP: if you use delay loading, you get the best of both worlds. Static linking to DLL functions without having to call `GetProcAddress()` manually (still requires an import .lib), and run-time loading of the DLL when an exported function is called for the first time rather than at process creation. – Remy Lebeau May 31 '13 at 00:10
  • Thank you, with your idea, I can call the delphi dll with LoadLibrary/GetProcAddress successfully. But I haven't try the second way, does it mean that I creat a fake c++ project which has the same deaclearation as delphi and compile it, then VS will generate the lib file automaticlly? – frank May 31 '13 at 01:39
  • You generate it with a command line tool. In C++ Builder it's IMPLIB.EXE, in Visual C++ it's LIB.EXE. Moskito-x's answer below has all the detailed blow by blow instructions on that technique. Personally I just stick with the manual stuff. Let's me load when I want to load, check for errors, set a global variable saying "Feature Plugin X enabled", etc. – Warren P May 31 '13 at 12:57
  • 1
    @Warren Moskito's answer doesn't get the job done. With stdcall you need to export functions with decorated names with @n suffixes. In order to avoid that and use plain names you need to use the stubbing method that I described. – David Heffernan May 31 '13 at 13:07
  • True but he does describe the implib tool a bit more than your answer did. So does Remy. – Warren P Jun 01 '13 at 16:02
  • @Warren I chose not to because it doesn't do the job. Because of decoration issues. Would work well with cdecl functions. – David Heffernan Jun 01 '13 at 16:12
2

Use VC's command-line LIB utility to create a VC-compatible import .lib file for the DLL, then add that file to your VC project.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    According to the MS KB article that I linked to, this won't get the job done for stdcall functions. You need to stub out the functions in that case. – David Heffernan May 30 '13 at 18:45
  • There is nothing in that article that says it will not work with stdcall functions. Considering that the entire Win32 API (save for a few functions) uses stdcall, so it would be stupid for it NOT to support stdcall. Besides, even if you go the stub approach, you still use the LIB utilty to compile the actual .lib file using the compiled stub .obj file, so my answer still stands. – Remy Lebeau May 30 '13 at 20:39
  • 1
    From the article "Specifically, the functions need to have been declared to use the C calling convention." The Win32 .lib files can be built from source since MS have that. No need there to reverse engineer the .lib files. When I last looked at this, the only solution I found was stubbing. For x86 you can use implib then omf2coff IIRC correctly. For x64 I think stubbing is needed. – David Heffernan May 30 '13 at 21:29
  • And yes, you can use cl + lib but the key is stubbing. Which you've not mentioned since you believe it's not needed. – David Heffernan May 30 '13 at 21:30
0

With __declspec(dllimport) a __imp__ before the named method is set.

In the generated delphi CheckFunctions.dll there is only a function named CheckResult .
VS C++ 2010 is looking for __imp__CheckResult . Therefore, the linker VS C++ can not find this function.

You have to create a .lib file.
With the program lib.exe this .lib file can be created very easily.
Run LIB.exe from the Visual-studio command-prompt.

LIB creates standard libraries, import libraries, and export files you can use with LINK when building a program.

Overview of LIB

If we have created, with the Visual-studio command-prompt>

C:\VisualStudio100\VC>lib /def:C:\CheckFunctions.def /OUT:C:\CheckFunctions.lib

the CheckFunctions.lib file __imp__CheckResult can be found.

enter image description here

You can test it with following steps
with Delphi5 and Win xp 32 it works.

CheckFunctions.dpr

library CheckFunctions;

uses
  SysUtils,
  Classes;

{$R *.RES}

function CheckResult:integer; stdcall;
begin
   result:=12000;
end;

exports
CheckResult;

begin
end.

Create the def file
CheckFunctions.def

EXPORTS
CheckResult

Create the lib file
Visual Studio command

C:\Programme\VisualStudio100\VC>lib /def:C:\pathToProject\CheckFunctions.def /OUT:C:\pathToProject\CheckFunctions.lib

Copy CheckFunctions.exp and CheckFunctions.lib to
your Visual C++ 2010 Project folder

Visual C++ 2010 CallDll.cpp

#include "stdafx.h"

#define MY_DLL __declspec(dllimport)

extern "C"
{
MY_DLL int CheckResult();
} ;

int _tmain(int argc, _TCHAR* argv[])
{
    int myint = CheckResult();
    printf ("Decimals: %d \n", myint );
    return 0;
}

Update: if you want it with __stdcall

NEW Visual C++ 2010 CallDll.cpp

#include "stdafx.h"

#define MY_DLL __declspec(dllimport)

extern "C"
{
MY_DLL int __stdcall CheckResult();
} ;

int _tmain(int argc, _TCHAR* argv[])
{
    int myint = CheckResult();
    printf ("Decimals: %d \n", myint );
    return 0;
}

change delphi exports

exports
CheckResult name 'CheckResult@0';

Change
CheckFunctions.def

EXPORTS
CheckResult@0
  • Create a new CheckFunctions.lib

That works too.

moskito-x
  • 11,832
  • 5
  • 47
  • 60
  • The calling convention doesn't match. And why are you not explaining anything? Please explain what the problem is that the asker is facing. – David Heffernan May 30 '13 at 21:24
  • Your explanation is wrong, and the calling convention still does not match. Did you think my answer was wrong? – David Heffernan May 30 '13 at 22:02
  • I don't see how that could help. The C++ linker still needs an import lib. – David Heffernan May 30 '13 at 22:17
  • That's why I'm creating a `CheckFunctions.lib` in my answer look at "Create the lib file". – moskito-x May 30 '13 at 22:34
  • 1
    The __imp__XXX is not a DLL entry point. It's the name of the stub in the import lib. – David Heffernan May 30 '13 at 22:41
  • I know ! What does in OP's question mean ? `unresolved external symbol __imp_CheckResult referenced in function` . Therefore you must create a .lib file with the Visual Command : `lib /def:F:\stack\DllCall\CheckFunctions.def /OUT:F:\stack\DllCall\CheckFunctions.lib` . – moskito-x May 30 '13 at 22:49
  • I said all that long ago. I also linked to an article that says your use of lib only works for cdecl functions. The question uses stdcall. I've told you twice now that your answer gets calling convention wrong. Your C++ code uses cdecl instead of stdcall. You need to create stubs as I explained in my answer. – David Heffernan May 30 '13 at 22:53
  • @DavidHeffernan Please look at my Update with `__stdcall`. Works the same. – moskito-x May 30 '13 at 23:31
  • Well yes, but you need to decorate the names now with stdcall decoration. This is what you avoid with stubbing. – David Heffernan May 31 '13 at 07:12