digitalmars.D.learn - A Simple DLL Wrapper
- oldrev (93/93) Feb 22 2007 I wrote a DLL wrapper template, but why it cannot work fine?
- David L. Davis (10/10) Feb 22 2007 You're example template/mixin complies and runs fine with dmd v1.007 und...
- Bill Baxter (11/17) Feb 22 2007 That is pretty cool!
- oldrev (81/81) Feb 22 2007 The better version:
- kris (4/107) Feb 22 2007 That is really, really slick ... would you be willing to donate this to
- Wei Li (74/86) Feb 23 2007 Of course, this is my honor. Use it freely.
- Kristian Kilpi (3/82) Feb 23 2007 Very nice indeed! :)
- torhu (21/34) Feb 23 2007 Pretty cool. Reminds me abit of the python module called ctypes.
I wrote a DLL wrapper template, but why it cannot work fine? import std.c.windows.windows; import std.stdio; import std.traits; import std.string; import std.utf; struct Symbol(char[] SymName, Ret, Params...) { alias Params Parameters; alias Ret ReturnValue; const char[] Name = SymName; alias extern(Windows) ReturnValue function (Params) FunctionType; } private template SymbolToTypeString(S) { const char[] SymbolToTypeString = S.ReturnValue.stringof ~ " function" ~ S.Parameters.stringof; } // FP_Function private template MixinMember(S) //S = Symbol template { //mixin("public alias extern(C) " ~ SymbolToTypeString!(S) ~ " FP_" ~ S.Name ~ ";"); //mixin("public FP_" ~ S.Name ~ " " ~ S.Name ~ " = null;"); mixin("public alias S.FunctionType FP_" ~ S.Name ~ ";"); mixin("public S.FunctionType " ~ S.Name ~ ";"); } private template MixinAllMembers(S, V...) { mixin MixinMember!(S); static if(V.length > 0) { mixin MixinAllMembers!(V); } } class Module(char[] Path, Symbols...) { private HMODULE m_handle = null; public mixin MixinAllMembers!(Symbols); public this() { load(Path); initMembers(); } public ~this() { free(); } private void initMembers() { foreach (i, S; Symbols) { mixin(S.Name ~ " = getSymbol!(FP_" ~ S.Name ~ ")(S.Name);"); } } void load(char[] path) { // m_handle = LoadLibraryW(toUtf16z(path)); m_handle = LoadLibraryA(toStringz(path)); assert(m_handle); } void free() { if(m_handle != null) { FreeLibrary(m_handle); m_handle = null; } } public T getSymbol(T)(char[] sym) { return cast(T)getSymbol1(sym); } public void* getSymbol1(char[] sym) { return GetProcAddress(m_handle, toStringz(sym)); } } void main() { // int MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType); // HWND GetDesktopWindow(); auto dll = new Module!("User32.dll", Symbol!("MessageBoxW", int, HWND, LPCWSTR, LPCWSTR, UINT), Symbol!("GetDesktopWindow", HWND)); dll.MessageBoxW(null, toUTF16z("Hello! DLL!"), null, MB_OKCANCEL); //dll.MessageBoxW(null, toUTF16z("Hello! DLL!"), toUTF16z("fdsfas"), MB_OKCANCEL); HWND h = dll.GetDesktopWindow(); writefln(h); }
Feb 22 2007
You're example template/mixin complies and runs fine with dmd v1.007 under WinXP SP2...I see the Messagebox message and the handle ID number in the console area for the main windows' desktop. Tis pretty Kool what you've done! Good work. :) So what's problem you're seeing? David L. ------------------------------------------------------------------- "Dare to reach for the Stars...Dare to Dream, Build, and Achieve!" ------------------------------------------------------------------- MKoD: http://spottedtiger.tripod.com/D_Language/D_Main_XP.html
Feb 22 2007
David L. Davis wrote:You're example template/mixin complies and runs fine with dmd v1.007 under WinXP SP2...I see the Messagebox message and the handle ID number in the console area for the main windows' desktop. Tis pretty Kool what you've done! Good work. :) So what's problem you're seeing?That is pretty cool! It almost works! It seems only the first two parameters are actually passed correctly -- which makes me thing that maybe the extern(Windows) is getting ignored or handled incorrectly somehow. Could this be related? http://d.puremagic.com/issues/show_bug.cgi?id=962 Actually you can remove the extern(Windows) completely from your code and you get the same result. So it probably is getting ignored. --bb
Feb 22 2007
The better version: import std.c.windows.windows; import std.stdio; import std.traits; import std.string; import std.utf; struct Symbol(char[] SymName, Ret, Params...) { alias Params Parameters; alias Ret ReturnValue; const char[] Name = SymName; extern(Windows) alias ReturnValue function(Params) FunctionType; } // FP_Function private template MixinMember(S) //S = Symbol template { mixin("public alias S.FunctionType FP_" ~ S.Name ~ ";"); mixin("public S.FunctionType " ~ S.Name ~ ";"); } private template MixinAllMembers(S, V...) { mixin MixinMember!(S); static if(V.length > 0) { mixin MixinAllMembers!(V); } } final class Module(char[] Path, Symbols...) { private HMODULE m_handle = null; public mixin MixinAllMembers!(Symbols); public this() { load(Path); initMembers(); } public ~this() { free(); } private void initMembers() { foreach (i, S; Symbols) { mixin(S.Name ~ " = getSymbol!(FP_" ~ S.Name ~ ")(S.Name);"); } } void load(char[] path) { // m_handle = LoadLibraryW(toUtf16z(path)); m_handle = LoadLibraryA(toStringz(path)); assert(m_handle); } void free() { if(m_handle != null) { FreeLibrary(m_handle); m_handle = null; } } public T getSymbol(T)(char[] sym) { return cast(T)getSymbol1(sym); } public void* getSymbol1(char[] sym) { return GetProcAddress(m_handle, toStringz(sym)); } } void main() { auto dll = new Module!("User32.dll", Symbol!("MessageBoxW", int, HWND, LPCWSTR, LPCWSTR, UINT), Symbol!("MessageBoxA", int, HWND, LPCSTR, LPCSTR, UINT) ); dll.MessageBoxW(null, "Hello! DLL! W", "Title W", MB_OK); dll.MessageBoxA(null, "Hello! DLL! A", "Title A", MB_OK); }
Feb 22 2007
oldrev wrote:The better version: import std.c.windows.windows; import std.stdio; import std.traits; import std.string; import std.utf; struct Symbol(char[] SymName, Ret, Params...) { alias Params Parameters; alias Ret ReturnValue; const char[] Name = SymName; extern(Windows) alias ReturnValue function(Params) FunctionType; } // FP_Function private template MixinMember(S) //S = Symbol template { mixin("public alias S.FunctionType FP_" ~ S.Name ~ ";"); mixin("public S.FunctionType " ~ S.Name ~ ";"); } private template MixinAllMembers(S, V...) { mixin MixinMember!(S); static if(V.length > 0) { mixin MixinAllMembers!(V); } } final class Module(char[] Path, Symbols...) { private HMODULE m_handle = null; public mixin MixinAllMembers!(Symbols); public this() { load(Path); initMembers(); } public ~this() { free(); } private void initMembers() { foreach (i, S; Symbols) { mixin(S.Name ~ " = getSymbol!(FP_" ~ S.Name ~ ")(S.Name);"); } } void load(char[] path) { // m_handle = LoadLibraryW(toUtf16z(path)); m_handle = LoadLibraryA(toStringz(path)); assert(m_handle); } void free() { if(m_handle != null) { FreeLibrary(m_handle); m_handle = null; } } public T getSymbol(T)(char[] sym) { return cast(T)getSymbol1(sym); } public void* getSymbol1(char[] sym) { return GetProcAddress(m_handle, toStringz(sym)); } } void main() { auto dll = new Module!("User32.dll", Symbol!("MessageBoxW", int, HWND, LPCWSTR, LPCWSTR, UINT), Symbol!("MessageBoxA", int, HWND, LPCSTR, LPCSTR, UINT) ); dll.MessageBoxW(null, "Hello! DLL! W", "Title W", MB_OK); dll.MessageBoxA(null, "Hello! DLL! A", "Title A", MB_OK); }That is really, really slick ... would you be willing to donate this to the Tango library? - Kris
Feb 22 2007
kris Wrote:oldrev wrote:Of course, this is my honor. Use it freely. The final version: // dll.d // A simple DLL wrapper // Author: Wei Li (wstring gmail.com) import std.c.windows.windows; import std.stdio; import std.traits; import std.string; struct Symbol(char[] Sym, Func) { const char[] Name = Sym; extern(Windows) alias ReturnType!(Func) function(ParameterTypeTuple!(Func)) FunctionType; // extern(Windows) alias FuncType FunctionType // Why is this Invalid? DMD's bug? } private template MixinMembers(S, V...) { mixin("alias S.FunctionType FP_" ~ S.Name ~ ";"); mixin("S.FunctionType " ~ S.Name ~ ";"); static if(V.length > 0) mixin MixinMembers!(V); } final class Module(char[] Path, Symbols...) { private HMODULE m_handle = null; public mixin MixinMembers!(Symbols); public this() { load(); initSymbols(); } public ~this() { free(); } private void initSymbols() { foreach (i, S; Symbols) { mixin(S.Name ~ " = getSymbol!(FP_" ~ S.Name ~ ")(S.Name);"); } } private void load() { m_handle = LoadLibraryA(toStringz(Path)); assert(m_handle); } private void free() { FreeLibrary(m_handle); } public T getSymbol(T)(char[] sym) { return cast(T)getSymbolAddress(sym); } public void* getSymbolAddress(char[] sym) { return GetProcAddress(m_handle, toStringz(sym)); } } void main() { scope auto dll = new Module!("User32.dll", Symbol!("MessageBoxW", int function(HWND, LPCWSTR, LPCWSTR, UINT)), Symbol!("MessageBoxA", int function(HWND, LPCSTR, LPCSTR, UINT)) ); dll.MessageBoxW(null, "Hello! DLL! ", "Hello from MessageBoxW", MB_OK); dll.MessageBoxA(null, "Hello! DLL! ", "Hello from MessageBoxA", MB_OK); } - Wei LiThe better version: import std.c.windows.windows; import std.stdio; import std.traits; import std.string; ......That is really, really slick ... would you be willing to donate this to the Tango library? - Kris
Feb 23 2007
On Fri, 23 Feb 2007 08:39:57 +0200, oldrev <wstring gmail.com> wrote:The better version: import std.c.windows.windows; import std.stdio; import std.traits; import std.string; import std.utf; struct Symbol(char[] SymName, Ret, Params...) { alias Params Parameters; alias Ret ReturnValue; const char[] Name =3D SymName; extern(Windows) alias ReturnValue function(Params) FunctionType; } // FP_Function private template MixinMember(S) //S =3D Symbol template { mixin("public alias S.FunctionType FP_" ~ S.Name ~ ";"); mixin("public S.FunctionType " ~ S.Name ~ ";"); } private template MixinAllMembers(S, V...) { mixin MixinMember!(S); static if(V.length > 0) { mixin MixinAllMembers!(V); } } final class Module(char[] Path, Symbols...) { private HMODULE m_handle =3D null; public mixin MixinAllMembers!(Symbols); public this() { load(Path); initMembers(); } public ~this() { free(); } private void initMembers() { foreach (i, S; Symbols) { mixin(S.Name ~ " =3D getSymbol!(FP_" ~ S.Name ~ ")(S.Name)=;");} } void load(char[] path) { // m_handle =3D LoadLibraryW(toUtf16z(path)); m_handle =3D LoadLibraryA(toStringz(path)); assert(m_handle); } void free() { if(m_handle !=3D null) { FreeLibrary(m_handle); m_handle =3D null; } } public T getSymbol(T)(char[] sym) { return cast(T)getSymbol1(sym); } public void* getSymbol1(char[] sym) { return GetProcAddress(m_handle, toStringz(sym)); } } void main() { auto dll =3D new Module!("User32.dll", Symbol!("MessageBoxW", int, HWND, LPCWSTR, LPCWSTR, UINT),=Symbol!("MessageBoxA", int, HWND, LPCSTR, LPCSTR, UINT) ); dll.MessageBoxW(null, "Hello! DLL! W", "Title W", MB_OK); dll.MessageBoxA(null, "Hello! DLL! A", "Title A", MB_OK); }Very nice indeed! :)
Feb 23 2007
oldrev wrote: <snip>void main() { auto dll = new Module!("User32.dll", Symbol!("MessageBoxW", int, HWND, LPCWSTR, LPCWSTR, UINT), Symbol!("MessageBoxA", int, HWND, LPCSTR, LPCSTR, UINT) ); dll.MessageBoxW(null, "Hello! DLL! W", "Title W", MB_OK); dll.MessageBoxA(null, "Hello! DLL! A", "Title A", MB_OK); }Pretty cool. Reminds me abit of the python module called ctypes. Here's the equivalent of your main() using that: from ctypes import windll MB_OK = 0 windll.user32.MessageBoxA(None, "Hello! DLL! ", "Hello from MessageBoxA", MB_OK) windll.user32.MessageBoxW(None, u"Hello! DLL! ", u"Hello from MessageBoxW", MB_OK) windll is an object that loads a dll file, and expects functions to use the stdcall conventions. cdll excpects regular C calling conventions. Arguments are converted correctly according to their types, only works for ansi and utf8 string, and ints for now. You have to specify other types explicitly. Functions are assumed to return int unless otherwise specified. You can do pointless stuff like this too: http://python.net/crew/theller/ctypes/tutorial.html (use google cache if down) http://docs.python.org/lib/module-ctypes.html
Feb 23 2007