Here it is! A tool to convert simple dll's into static library.
This is the first version, so all here is simple: the user interface has all controls on one page, you are able to access only named exports, and the dll is notified only with process attach/detach.
TLS initialization is not yet supported, module functions will always fail (GetModuleHandle...).
The dll is loaded to memory not as dll, but as code+data (using the MemoryModule loader with small modifications to operate on HMODULE instead MEMORYMODULE*)
Note: every converted dll you must manually initialize and deinitialize by single call to the loader. Every converted dll has its own (un)loader.
You can find a example usage for dx3d9r.dll with landscape.src modification.
Have fun! ;D
(http://img226.imageshack.us/img226/2473/dll2libvz6.th.jpg) (http://img226.imageshack.us/my.php?image=dll2libvz6.jpg)
edit: version 2.0.0.2 supports names up to 16320 characters
Thank you :)
Once again you have proven how amazing your programming skills are!
looks like a great tool ;)
will give this a go as soon as i have time !
sapero -> check pm please.
Doesn't work on rakknet.dll, get ahold of that and try it with your application, problem is, there names are VERY LONG, and you have a character limit for length of name of the exported items.
I've uploaded second version that supports names up to 16320 characters (previous limit was 260). I do not belive this is not enough ;)
The raknet has been converted ok,and the simple main() with loader only ran successfully.
// todo: undecorate names
You rock!
I bow to Sapero's mastery. Fantastic work! Thank you for sharing it with us, lesser programming mortals.
Barney
Great !
Sapero You are the man as usual
That's a great program.
I'd be glad to see an Ebasic version. ;)
The created library should work fine with Emergence.
i've created a template for the (GUI) second edition. It uses tabbed property sheet, and looks better than the first version, i think so :D
The resource script was created using ResEd from Shantanu site (http://www.radasm.com/).
What do you think? It may be not correctly categorized, so please reply with any suggestions.
Looks very nice.
BTW,
I looked at the dialog editor of ResEd and it looks very appealing.
How do you get the data from the dialog editor?
(controls placement and their various styles and Exstyles?)
Haim
The ResEd was created for MASM, but here is a Visual Studio version (http://www.masm32.com/board/index.php?topic=6422.msg47950#msg47950).
In options menu select "C defines" as output format to easier use the script with Aurora.
Secundo: I've found a bug in MemoryModule module. Sections with IMAGE_SCN_MEM_DISCARDABLE flag can be released after calling the dll entry point.
Some packed dll's (like bass) are calculating crc32, and probably my small modification causes MemoryLoadLibrary to fail (i'm saving MEMORYMODULE pointer in dos stub).
I'll look into it, and add a option to disable releasing of discardable sections.
Thanks Sapero!
sapero
Here comes a question to display my ignorance.
What's the difference between using your utility and the make lib feature of the IDE.
Why would I want to use your program?
Again, my ignorance.
EDIT:
Okay, let's see if I'm right.
The lib made in the IDE just gives locations of functions in the DLL so you have to send people the dll with your exe.
Your program creates a static lib that loads the functions into your compiled exe so that you don't have to send a dll with your exe.
The price that is paid is that you have to call "load" and "unload" functions to get the lib functions to work.
How close did I get?
If I'm correct then here's my next question.
If I want to create some wrappers for the functions in the first dll I do the following:
1) use your program to create a static lib of the 1st dll
2) write my wrapper functions including "open" and "close" fucntions to call the "load" and "unload" for the static lib.
3) compile my wrapper module as a dll
4) use your program to create a static lib of my dll along with the "load" and "unload" for it.
5) write my application:
If 1st calls the "load" for my wrappers
Then calls the "open" function in my wrappers to call the "load" for the 1st dll functions.
6) at the end of my application:
call the "close" function in my wrappers to call the "unload" for the 1st dll functions.
call the "unload" for my wrappers
Can you "nest" them like that.
The ansver for first question:
QuoteDLL to Lib is a magical tool which can convert a DLL file into its equivalent static library file. After that, you can replace the original DLL with the static library file, rebuild your application, and distribute it without the DLL! The most exciting thing is that the conversion process DOES NOT require any source codes of the DLL! All works are done from binary to binary. DLL to Lib will rebuild programming interface identical to the functions exported by the DLL and reconstruct the necessary symbol tables, string tables and reference tables from the DLL to make a valid static library for you! Incredible?
Yes, you can nest it as well. Here is a working sample:
first dll:
// dll 1
export GetOnePlusNine;
sub GetOnePlusNine(),int
{
return 1+9;
}
// compile as GetOnePlusNine.dll and convert it to static library GetOnePlusNine_m.lib
second dll that loads the first dll:
// dll 2 - uses GetOnePlusNine_m.lib to wrap GetOnePlusNine()
export GetOnePlusNine_wrapped;
#use "GetOnePlusNine_m.lib" // link to static library you created from GetOnePlusNine.dll
#use "zlib.lib" // use static library
// the function we want to wrap
declare import, GetOnePlusNine(),int;
// functions to load and decompress the first dll
extern int __LoadGetOnePlusNine_dll();
extern void __UnloadGetOnePlusNine_dll();
sub GetOnePlusNine_wrapped(),int
{
__LoadGetOnePlusNine_dll();
int result = GetOnePlusNine();
__UnloadGetOnePlusNine_dll();
return result;
}
// compile as GetOnePlusNine_wrapped.dll and convert it to static library GetOnePlusNine_wrapped_m.lib
the main program:
// exe main
#use "GetOnePlusNine_wrapped_m.lib"
#use "zlib.lib"
extern int __LoadGetOnePlusNine_wrapped_dll();
extern void __UnloadGetOnePlusNine_wrapped_dll();
declare import,GetOnePlusNine_wrapped(),int;
sub main(),int
{
__LoadGetOnePlusNine_wrapped_dll();
MessageBox(0, str$(GetOnePlusNine_wrapped()), "");
__UnloadGetOnePlusNine_wrapped_dll();
return 0;
}
When the exe starts, it loads the wrapped (second) dll and calls a function, where another dll is loaded (the first one) to return some value.
Thanks a million sapero.
You're the man as usual. ;D
Yeah!!
Very interesting.
This helps understanding better how it all works!!
Thanks Sapero ;)
Sapero
I'm using EBasic instead of Aurora and ran into a little problem.
I coverted your example above to EBasic.
Made the first dll and converted it to lib
Tried to compile the second and it won't compile.
It's not liking stricmp in crtdll.lib.
I looked at the 2 crtdll.libs (1 in Ebasic\libs and other in Aurora\libs.
They are not the same.
Got any idea how I can fix it?
I was going to mention that problem ;D
I tried to compile the seconde DLL in AURORA but failed too
There may be something wrong in the second DLL code ???
here is what i got
Compiling...
GetOnePlusNine_wrapped.src
No Errors
Generating Exports
Linking...
Aurora Linker v1.0 Copyright ÂÃ,©2005,2006 Ionic Wind Software
Unresolved external __LoadGetOnePlusNine_dll
Error: Unresolved extern __LoadGetOnePlusNine_dll
Error: Unresolved extern __UnloadGetOnePlusNine_dll
Error(s) in linking C:\Program Files\Aurora\examples\dll to lib example\GetOnePlusNine_wrapped.dll
Cheers!
In EBasic
If I make dll's with EBasic crtdll.lib then there is a problem with crtdll\stricmp
If I substitute Aurora crtdll.lib then there is a problem with sprintf
Any ideas how to fix?
McCaughn, I remember this from IB :)
Open up your LIBS folder, find crtdll.lib and create a backup or rename it.
Run the EB GUI and from menu select Tools->Create import library. Find crtdll.dll and click ok, then ansver YES for "replace existing library" prompt.
Return to LIBS folder and rename the new crtdll.lib to _crtdll.lib, then restore the original crtdll.lib.
Now append a $use "_crtdll.lib" so it should compile now.
pistol350, in your libs folder should be the new lib file with embedded dll, try with #use "name.lib".
Optionally the lib file can be located inside your project directory, but should be added to project (menu->project->insert library).
I wouldn't have dreamed of that in a hundred years.
Thanks
And there is a reason they are different. When I was creating IBasic Pro I wanted to be able to use static libraries created with VC++ 5.0 which prepends an underscore to all C library functions. So I made a special version of crtdll.lib that would link against VC libs. In order to make Emergence compatible with IBasic source code I used the same import library.
In Aurora that was no longer a priority as it already has OOP, and a more robust object set,and better COM handling, etc, etc. So the stock crtdll.lib which contains no prepended underscores was used. In other words I had no need to link to static libs created with VC++
Paul.
sapero
What I use your program to convert the 1st dll to a static lib.
I use that in a 2nd src file and create a static lib of the 2nd file
Will the 2nd static lib be a standalone lib that I can distribute to users without any other files?
Larry
If the second lib has references to the first, someone will get unresolved externals. Try to rename the first one, then compile using the second lib, to check this.
If you checked the "compression" option, you need also to share zlib.lib.
Optionally you can merge two, or more libraries to one library, using the commandline ar.exe or link.exe tool, depending on library format.
Dll2Lib doesn't work with unicode dlls in EmergencyBasic.
I think, you have to change in MemoryGetProcAddress the second parameter, this should allways the functionname in ascii.
WinAPI GetProcAddress doesn't support Unicode, but I am not sure whether this is the mistake
greetings
Thomas
I can't help without additional informations - which dll? Any code?
This tool has nothing to do with the code inside target dll, it reads only the exported names (always ascii) and creates import library wrapper that calls directry to memory, the dll code is untouched, but the IMAGE_DOS_HEADER is modified - one DWORD is used to store a pointer to internal structure.
Sorry sapero, my mistake, i have defined UNICODE on the wrong place :-[
It works as aspected
Sapero
I tried to use your converter on the attached dll.
Everything convertered and when I compiled and linked it into my application it did that fine.
However, when I ran my application it crashed with the "tell MS all about it" message box.
Any ideas.
Larry
Hey Larry, great tool. Thanks for sharing. ;D
Reference the post above. I am very sorry for changing your name to Larry. I was chatting with a friend at the time and switched your name with his. Again, I am very sorry and I hope you will forgive me. Ken. ;D
Larry, Olly shows that this dll calls (and relies on) GetModuleFileName, searches for last '.' (_mbsrchr) and writes a NULL to that address.
GetModuleFileName fails with memory only modules, _mbsrchr returns NULL, and the code writes NULL byte to NULL pointer.
DllMain(hinstance)
{
GetModuleFileName(hinstance, bufer, ...); // set bufer to path\image323.dll
char *p = _mbsrchr(bufer, '.'); // find last '.'
*p = 0; // remove extension
You may hook the GetModuleFileName api before calling __Loadimage323_dll.
Here is working exception handler: it copies dll name to the buffer provided for GetModuleFileName and resumes execution
#use "image323_m.lib"
#use "zlib.lib"
extern int __Loadimage323_dll();
extern void __Unloadimage323_dll();
#include "windows.inc"
declare import, About();
sub main(),int
{
LPTOP_LEVEL_EXCEPTION_FILTER OldFilter = SetUnhandledExceptionFilter(&Loadimage323Filter);
// load the dll from memory
__Loadimage323_dll();
SetUnhandledExceptionFilter(OldFilter);
// call some functions here
About();
// finally free the dll from memory
__Unloadimage323_dll();
return 0;
}
sub Loadimage323Filter(EXCEPTION_POINTERS* ExceptionInfo),LONG
{
EXCEPTION_RECORD *rec = ExceptionInfo->ExceptionRecord;
CONTEXT *ctx = ExceptionInfo->ContextRecord;
/*
73DC9CB2 MOV EBX,104
73DC9CB7 PUSH EBX
73DC9CB8 LEA EAX,[EBP+84]
73DC9CBE PUSH EAX
73DC9CBF PUSH [DWORD ESI+6C]
73DC9CC2 CALL [<&KERNEL32.GetModuleFileNameA>]
73DC9CC8 LEA EAX,[EBP+84] <- resume here
73DC9CCE PUSH 2E
73DC9CD0 PUSH EAX
73DC9CD1 CALL [<&msvcrt._mbsrchr>]
73DC9CD7 POP ECX
73DC9CD8 POP ECX
73DC9CD9 MOV [EBP-80],EAX
73DC9CDC MOV [BYTE EAX],0 <- exception
*/
// copy image323.dll to [EBP+0x84]
string *pModuleName = ctx->Ebp + 0x84;
*pModuleName = "image323.dll";
// resume execution after GetModuleFileNameA
const RESUMEOFFSET = 0x73DC9CDC - 0x73DC9CC8;
ctx->Eip = rec->ExceptionAddress - RESUMEOFFSET;
// continue execution
return EXCEPTION_CONTINUE_EXECUTION;
}
Sapero
Although this is the Aurora forum I'm trying to use this in EB. Will the above code convert over to EB?
Larry
Sure.$use "d:\\aurora\\libs\\image323_m.lib" /* change this*/
$use "zlib.lib"
declare extern __Loadimage323_dll(),int
declare extern __Unloadimage323_dll()
$include "windows.inc"
declare import, About()
main()
sub main()
LPTOP_LEVEL_EXCEPTION_FILTER OldFilter
OldFilter= SetUnhandledExceptionFilter(&Loadimage323Filter)
' load the dll from memory
__Loadimage323_dll()
SetUnhandledExceptionFilter(OldFilter)
' call some functions here
About()
' finally free the dll from memory
__Unloadimage323_dll()
return
endsub
sub Loadimage323Filter(EXCEPTION_POINTERS ExceptionInfo),LONG
pointer rec, ctx, pModuleName
rec = ExceptionInfo.ExceptionRecord
ctx = ExceptionInfo.ContextRecord
settype rec, EXCEPTION_RECORD
settype ctx, CONTEXT
' copy "image323.dll" to [EBP+0x84]
pModuleName = *ctx.Ebp + 0x84
*<STRING>pModuleName = "image323.dll"
' resume execution after GetModuleFileNameA
const RESUMEOFFSET = 0x73DC9CDC - 0x73DC9CC8
*ctx.Eip = *rec.ExceptionAddress - RESUMEOFFSET
' continue execution
return EXCEPTION_CONTINUE_EXECUTION
endsub
Thanks again, Sapero
Larry