www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - A Simple DLL Wrapper

reply oldrev <wstring gmail.com> writes:
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
next sibling parent reply "David L. Davis" <SpottedTiger yahoo.com> writes:
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
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
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
prev sibling parent reply oldrev <wstring gmail.com> writes:
Content-Type: text/plain

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
next sibling parent reply kris <foo bar.com> writes:
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
parent Wei Li <wstring gmail.com> writes:
Content-Type: text/plain

kris Wrote:

 oldrev wrote:
 The better version:
 
 import std.c.windows.windows;
 import std.stdio;
 import std.traits;
 import std.string;
 ......

the Tango library? - Kris

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 Li
Feb 23 2007
prev sibling next sibling parent "Kristian Kilpi" <kjkilpi gmail.com> writes:
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
prev sibling parent torhu <fake address.dude> writes:
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: cdll.msvcrt.strlen("123") # returns 3 http://python.net/crew/theller/ctypes/tutorial.html (use google cache if down) http://docs.python.org/lib/module-ctypes.html
Feb 23 2007