Hi,
I have tried the tool Dll2lib from http://www.binary-soft.com/ to convert my Delphi 7 DLL to a static library.
However, no matter what i try, i always get linker error
error LNK2001: unresolved external symbol _AddNumbers@8
My delphi dll looks like this
library MyDLL;
{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }
uses
//ShareMem,
SysUtils,
Classes,
Windows,
Controls,
Forms,
ImgList,
Unit1 in 'Unit1.pas' {Form1};
function AddNumbers(a:Integer;b:Integer):Integer;stdcall;forward;
exports AddNumbers;
{$R *.res}
function AddNumbers(a:Integer;b:Integer):Integer ; stdcall;
begin
Result := a + b;
end;
end.
MASM calling
includelib MyDLL.lib ;The one generated by dll2lib.
AddNumbers PROTO :DWORD,:DWORD
invoke AddNumbers,1,2
I have also tried this one here http://www.ionicwind.com/forums/index.php?topic=1361.0
I got the same result about linking error.
Does anyone know if this is possible at all?
Write a little module that contains AddNumbers, and link the obj file together with the obj file obtained from the DLL.
The problem is that Delphi does not generate COFF obj file format but rather OMF obj format.
I have already converted it to COFF obj file with objconv tool. When i link this converted obj file, it still unable to resolve the external symbols.
Quote from: 2B||!2B on November 05, 2018, 08:59:37 PMWhen i link this converted obj file, it still unable to resolve the external symbols.
Well... do you link it with a module that does contain the correctly prototyped AddNumbers? Try something like this:
.486 ; create 32 bit code
.model flat, stdcall ; 32 bit memory model
.code
AddNumbers proc int1, int2
mov eax, int1
add eax, int2
ret
AddNumbers endp
end
Try dumping the .lib to see how AddNumbers is declared. Maybe this will work?
_imp__AddNumbers@8 PROTO :dword,:dword
AddNumbers TEXTEQU <_imp__AddNumbers@8>
Hi, to be or not to be!
look here (https://wasm.in/threads/masm-64-sborka.32766/#post-400919) I think that much will be clear without translation, but in the extreme case, you can use the online service Google Translator
Quote from: jj2007 on November 05, 2018, 09:09:16 PM
Quote from: 2B||!2B on November 05, 2018, 08:59:37 PMWhen i link this converted obj file, it still unable to resolve the external symbols.
Well... do you link it with a module that does contain the correctly prototyped AddNumbers? Try something like this:
.486 ; create 32 bit code
.model flat, stdcall ; 32 bit memory model
.code
AddNumbers proc int1, int2
mov eax, int1
add eax, int2
ret
AddNumbers endp
end
Yes, i did. Both .lib and obj gives the same linking error.
Quote from: sinsi on November 05, 2018, 09:24:54 PM
Try dumping the .lib to see how AddNumbers is declared. Maybe this will work?
_imp__AddNumbers@8 PROTO :dword,:dword
AddNumbers TEXTEQU <_imp__AddNumbers@8>
It does not work. It also shows the linking error with this function name but rather with double @8
Quote from: Mikl__ on November 05, 2018, 09:40:17 PM
Hi, to be or not to be!
look here (https://wasm.in/threads/masm-64-sborka.32766/#post-400919) I think that much will be clear without translation, but in the extreme case, you can use the online service Google Translator
Hey Mikl__,
Thanks for your link. I will have to read this carefully after translating it. See if i can get anywhere.
I have attached the example if someone might want to take a look at it.
It contains the dll and the static library.
MyDLL.lib - generated by dll2lib
Delphi dll exports undecorated function names, so converter can't know that decorated name.
EDIT:library MyDLL;
function AddNumbers(a:Integer;b:Integer):Integer;stdcall;forward;
exports
AddNumbers, AddNumbers name '_AddNumbers@8';
function AddNumbers(a:Integer;b:Integer):Integer ; stdcall;
begin
Result := a + b;
end;
end.
EDIT: Dll to Dll can use dll's import library.
You may have more than one problem.
Microsoft (R) Incremental Linker Version 5.12.8078
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
MyDLL.lib(MyDLL.obj) : warning LNK4078: multiple ".edata" sections found with different attributes (50100040)
MyDLL.lib(MyDLL.obj) : warning LNK4078: multiple ".rsrc" sections found with different attributes (50100040)
LINK : fatal error LNK1104: cannot open file "LIBC.lib"
Added this code
prAddNumbers TYPEDEF PROTO STDCALL :DWORD,:DWORD
PAddNumbers TYPEDEF PTR prAddNumbers
EXTERNDEF AddNumbers:PAddNumbers
No complaints about AddNumbers
edit: using "includelib libc.lib" then complains about a missing oldnames.lib (libc is in the masm32\lib folder but oldnames isn't)
I guess it depends on the type of lib you want to get from the DLL. I would imagine that am import library would be no big deal if you can match the calling convention but a static library derived from a DLL is far more problematic in what you have to do to get it to work. The conversion tool has to be able to identify the start and end of each procedure, correctly identify any function it imports from system DLLs and get all of the OFFSETs right.
An old friend of mine years ago (Jeremy Collake) was writing tools like this but they were always problematic as the form of DLLs is very diverse, particularly if you are using Borland compilers which differ from Microsoft compilers.
I use Delphi since immemorial times, last version I purchased was XE2 which supports the COFF format. Previous versions use the OMF as you know. If this helps in any way, I have never been able to make a proper OMF to COFF conversion using any utility including objconv. There is an article in CodeProject (https://www.codeproject.com/Articles/264103/Using-COFF-C-object-files-with-Delphi-X2) that may help you somehow.
Hi 2B||!2B,
The OMF format is an antique specification dating from the late 70s. It's possible to employ DLLs like "static libraries" The trick is to write your own custom PE loader.
Quote from: TimoVJL on November 05, 2018, 11:05:42 PM
Delphi dll exports undecorated function names, so converter can't know that decorated name.
EDIT:library MyDLL;
function AddNumbers(a:Integer;b:Integer):Integer;stdcall;forward;
exports
AddNumbers, AddNumbers name 'AddNumbers@8';
function AddNumbers(a:Integer;b:Integer):Integer ; stdcall;
begin
Result := a + b;
end;
end.
I don't think this is the problem. I have tried to use the name AddNumbers@8 but it still has the same linking error.
Quote from: sinsi on November 05, 2018, 11:14:51 PM
You may have more than one problem.
Microsoft (R) Incremental Linker Version 5.12.8078
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
MyDLL.lib(MyDLL.obj) : warning LNK4078: multiple ".edata" sections found with different attributes (50100040)
MyDLL.lib(MyDLL.obj) : warning LNK4078: multiple ".rsrc" sections found with different attributes (50100040)
LINK : fatal error LNK1104: cannot open file "LIBC.lib"
Added this code
prAddNumbers TYPEDEF PROTO STDCALL :DWORD,:DWORD
PAddNumbers TYPEDEF PTR prAddNumbers
EXTERNDEF AddNumbers:PAddNumbers
No complaints about AddNumbers
edit: using "includelib libc.lib" then complains about a missing oldnames.lib (libc is in the masm32\lib folder but oldnames isn't)
Hi sinsi,
Very good way of fixing this :greenclp:
oldnames.lib is found in C:\Program Files\Microsoft Visual Studio\VC98\Lib if you have the VC6.0
It worked fine with me without the need of linking libc and oldnames.lib. However, there is one issue
the compiled exe turned out to use a call to a pointer rather than a direct call to the function using the Invoke keyword.
00401000 > 6A 0A PUSH 0A
00401002 6A 0A PUSH 0A
00401004 FF15 B2104000 CALL DWORD PTR DS:[4010B2]
But at 4010B2 is the function itself not a pointer to function
4010B2 - AddNumbers successfully compiled
004010B2 55 PUSH EBP
004010B3 8BEC MOV EBP,ESP
004010B5 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
004010B8 0345 0C ADD EAX,DWORD PTR SS:[EBP+C]
004010BB 5D POP EBP ; kernel32.7742EE6C
004010BC C2 0800 RETN 8
Quote from: hutch-- on November 06, 2018, 01:19:02 AM
I guess it depends on the type of lib you want to get from the DLL. I would imagine that am import library would be no big deal if you can match the calling convention but a static library derived from a DLL is far more problematic in what you have to do to get it to work. The conversion tool has to be able to identify the start and end of each procedure, correctly identify any function it imports from system DLLs and get all of the OFFSETs right.
An old friend of mine years ago (Jeremy Collake) was writing tools like this but they were always problematic as the form of DLLs is very diverse, particularly if you are using Borland compilers which differ from Microsoft compilers.
Hi hutch,
I think you are right. Delphi is very diverse in it's way of laying out the resources, the classes, and the forms.
Take a look here https://stackoverflow.com/questions/16892601/omf-format-to-coff-format (https://stackoverflow.com/questions/16892601/omf-format-to-coff-format)
Quote from: AW on November 06, 2018, 03:30:56 AM
I use Delphi since immemorial times, last version I purchased was XE2 which supports the COFF format. Previous versions use the OMF as you know. If this helps in any way, I have never been able to make a proper OMF to COFF conversion using any utility including objconv. There is an article in CodeProject (https://www.codeproject.com/Articles/264103/Using-COFF-C-object-files-with-Delphi-X2) that may help you somehow.
Hi AW,
Thanks for the link.
Yes, you are right. I found Delphi 7 To be different in many ways. Haven't used Delphi X2
See the stackoverflow link i posted above to hatch.
Quote from: Vortex on November 06, 2018, 05:08:50 AM
Hi 2B||!2B,
The OMF format is an antique specification dating from the late 70s. It's possible to employ DLLs like "static libraries" The trick is to write your own custom PE loader.
Hi Vortex,
Do you mean loading the DLL directly to memory and then resolve imports/exports/relocs etc and then call the functions directly in memory?
QuoteDo you mean loading the DLL directly to memory and then resolve imports/exports/relocs etc and then call the functions directly in memory?
Exactly. You can check the DLLmem example in the attachment.
Quote from: 2B||!2B on November 06, 2018, 07:24:39 AM
Quote from: TimoVJL on November 05, 2018, 11:05:42 PM
Delphi dll exports undecorated function names, so converter can't know that decorated name.
EDIT:library MyDLL;
function AddNumbers(a:Integer;b:Integer):Integer;stdcall;forward;
exports
AddNumbers, AddNumbers name 'AddNumbers@8';
function AddNumbers(a:Integer;b:Integer):Integer ; stdcall;
begin
Result := a + b;
end;
end.
I don't think this is the problem. I have tried to use the name AddNumbers@8 but it still has the same linking error.
My bad,
exports
AddNumbers, AddNumbers name '_AddNumbers@8';
I made a test ;)
EDIT: Dll2Lib support import lib for decorated names.
EDIT: A test program in C:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "msvcrt.lib")
//#pragma comment(lib, "MyDll.lib")
#pragma comment(lib, "MyDllS.lib")
int __stdcall AddNumbers(int, int);
void mainCRTStartup(void) {exit(main());}
int __cdecl main(void)
{
int n = AddNumbers(1,2);
printf("n=%d\n", n);
return 0;
}
Quote from: Vortex on November 06, 2018, 07:33:59 AM
QuoteDo you mean loading the DLL directly to memory and then resolve imports/exports/relocs etc and then call the functions directly in memory?
Exactly. You can check the DLLmem example in the attachment.
Thanks for the library Vortex. I will have to consider this option if all other options fail.
Quote from: TimoVJL on November 06, 2018, 09:25:11 AM
Quote from: 2B||!2B on November 06, 2018, 07:24:39 AM
Quote from: TimoVJL on November 05, 2018, 11:05:42 PM
Delphi dll exports undecorated function names, so converter can't know that decorated name.
EDIT:library MyDLL;
function AddNumbers(a:Integer;b:Integer):Integer;stdcall;forward;
exports
AddNumbers, AddNumbers name 'AddNumbers@8';
function AddNumbers(a:Integer;b:Integer):Integer ; stdcall;
begin
Result := a + b;
end;
end.
I don't think this is the problem. I have tried to use the name AddNumbers@8 but it still has the same linking error.
My bad,
exports
AddNumbers, AddNumbers name '_AddNumbers@8';
I made a test ;)
Nice work there Timo.
How did you get it to work?
I can't seem to get rid of the linking error even with your dll!
Are there any specific options you have chosen in DLL2LIB?
Which version are you using? i am on 3.0.
EDIT:
For some reason, i have to use this one to get it working
exports
AddNumbers name 'AddNumbers@8';
Very nice work Timo! :greenclp: