D语言中国主页  D语言编辑器SciTE4D   DWin库 D语言官方网站
D语言编译器1.x最新版 OpenSource   Tango   webnews  Wiki

查看完整版本: C#-like 的 DLL 封装

yidabu 2007-4-27 19:03

C#-like 的 DLL 封装

C#-like 的 DLL 封装知识若不分享 实在没有意义 http://www.d-programming-language-china.org 20070427点击下面网址查看原文:http://www.d-programming-language-china.org        by:        oldrev        from:        http://oldrev.javaeye.com/blog/71604        一个类似 C# 的 DllImport 实现,用于“半”动态加载 DLL。用起来比我以前写的 DLLWrapper 要麻烦一些,但是 DLLWrapper 由于使用一个 Tuple 来存储函数声明,会造成超长的标识符导致编译错误,这个 DllImport 避免了这个问题。        这个实现有一个缺陷是每次调用API函数的时候都会执行一次 GetProcAddress,效率比较低.... 谁能告诉我怎么避免该死的 CTFE?        [Copy to clipboard] [ - ]CODE:                                // DllImport - A C#-like DLL Wrapper                // written by oldrev (wstring#gmail.com)                // License: BSD                                import std.stdio;                import std.typetuple;                import std.utf;                import std.c.windows.windows;                import std.traits;                import std.string;                                import singleton;                                extern(Windows)                {                    HMODULE LoadLibraryW(LPCWSTR libPath);                }                                                private static class ModuleManager                {                    private static HMODULE    [char[]]    m_modules;                                    private this()                    {                    }                                    static public ~this()                    {                        foreach(h; m_modules)                        {                            FreeLibrary(h);                        }                    }                                    private static HMODULE registerModule(char[] name)                    {                        char[] lname = tolower(name);                        HMODULE h = LoadLibraryW(toUTF16z(lname));                        if(h is null)                            throw new Exception("Failed to load DLL: " ~ name);                        m_modules[lname] = h;                        return h;                    }                                    public static HMODULE getHandle(char[] name)                    {                        return m_modules[name];                    }                                    public static ProcType getSymbol(ProcType)(char[] moduleName, char[] procName)                    {                        HMODULE handle = null;                        if(moduleName in m_modules)                            handle = m_modules[moduleName];                        else                            handle = registerModule(moduleName);                                        assert(handle !is null);                        return cast(ProcType)GetProcAddress(handle, toStringz(procName));                    }                }                                struct DllImport(char[] ModuleName, char[] ProcName, FT)                {                    extern(Windows) alias ReturnType!(FT)                        function(ParameterTypeTuple!(FT))    FunctionType;                                    // 非要这样重新绑定 extern(Windows),是不是编译器的 bug?                    // extern(Windows) alias FT FunctionType; // 这样就不行                                                    //怎么避免 CTFE?                                    //FIXME:                    //FunctionType m_funcPtr = ModuleManager.getSymbol!(FunctionType)(ModuleName, ProcName);                                    public ReturnType!(FunctionType) opCall(ParameterTypeTuple!(FunctionType) args)                    {                        FunctionType m_funcPtr = ModuleManager.getSymbol!(FunctionType)(ModuleName, ProcName);                        return m_funcPtr(args);                    }                }                                                                void main()                {                    DllImport!("user32.dll", "MessageBoxA",                            int function(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)) MessageBox;                    MessageBox(null, "Text", "Title", MB_OK);                }                0.0.0.0.0.2 版,要稍微高效一点:        [Copy to clipboard] [ - ]CODE:                                import std.typetuple;                import std.c.windows.windows;                import std.traits;                import std.string;                import std.utf;                                extern(Windows)                {                    HMODULE LoadLibraryW(LPCWSTR libPath);                }                                private static class ModuleManager                {                    private static HMODULE    [char[]]    m_modules;                                    private this()                    {                    }                                    static public ~this()                    {                        foreach(h; m_modules)                        {                            FreeLibrary(h);                        }                    }                                    private static HMODULE registerModule(char[] name)                    {                        char[] lname = tolower(name);                        HMODULE h = LoadLibraryW(toUTF16z(lname));                        if(h is null)                            throw new Exception("Failed to load DLL: " ~ name);                        m_modules[lname] = h;                        return h;                    }                                    public static HMODULE getHandle(char[] name)                    {                        return m_modules[name];                    }                                    public static ProcType getSymbol(ProcType)(char[] moduleName, char[] procName)                    {                        HMODULE handle = null;                        if(moduleName in m_modules)                            handle = m_modules[moduleName];                        else                            handle = registerModule(moduleName);                                        assert(handle !is null);                        ProcType proc = cast(ProcType)GetProcAddress(handle, toStringz(procName));                        if(proc is null)                            throw new Exception("Cannot to get the address of " ~ procName);                        return proc;                    }                }                                struct DllImport(char[] ModuleName, char[] ProcName, FT)                {                    extern(Windows) alias ReturnType!(FT)                        function(ParameterTypeTuple!(FT))    FunctionType;                    alias DllImport!(ModuleName, ProcName, FT) SelfType;                                    //FIXME: avoid the CTFE?                    private FunctionType m_funcPtr = null;                                    public ReturnType!(FunctionType) opCall(ParameterTypeTuple!(FunctionType) args)                    {                        if(m_funcPtr is null)                            m_funcPtr = ModuleManager.getSymbol!(FunctionType)(ModuleName, ProcName);                        return m_funcPtr(args);                    }                }                                void main()                {                    DllImport!("user32.dll", "MessageBoxA",                            int function(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)) MessageBox;                                    MessageBox(null, "Text", "Title", MB_OK);                }                qiezi        2007-04-17 10:31        我觉得上一版使用更方便呢,效率应该也会高一些吧。        oldrev        2007-04-17 11:31        问题是 DMD 限制标识符为 4k 个字符,上一版只要稍微多定义几个函数就出错了        qiezi        2007-04-17 11:59( 本文出处: http://www.d-programming-language-china.org )        代码        [Copy to clipboard] [ - ]CODE:                                Dll!("user32.dll") user32;                user32.DllImport!("MessageBoxA", int function(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType))MessageBox;                或者:        [Copy to clipboard] [ - ]CODE:                                DllImport!(user32, "MessageBoxA", int function(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType))MessageBox;                改成这种呢?我不大喜欢HMODULE [char[]] m_modules这种用字符串作key的,相对路径和绝对路径都无法统一处理。        另外DLL里面没有指定必须是stdcall调用吧?如果是cdecl怎么办?还得加一个调用约定参数吧?        oldrev        2007-04-17 13:32        有没有办法可以反射出一个struct或class的方法的名字        qiezi        2007-04-17 13:45        class有classinfo,它包括名字,struct我就不清楚了,应该也有。不过这些好像是运行时的,编译时可以用模板的alias参数去取,前面我提到过几次了,pyd里面用了这种方法取的参数名字。( 本文出处: http://www.d-programming-language-china.org )        oldrev        2007-04-17 14:37        我查了 ClassInfo 类,没有方法名字,只有类的名字        qiezi        2007-04-17 15:06        方法名字只能用其它方式得到,比如stringof        DavidL        2007-04-20 13:26        可以直接用bindings里的win32/winuser.d来调用这些dll吧( lastupdate:20070427 最新文章请访问http://www.d-programming-language-china.org )关于一大步成功社区:yidabu提倡在交流中学习,在分享中提高收集感兴趣的知识,写下心得,通过网络与别人一起分享理解一点就实践一步,收获什么就分享什么,成功就是这样一点点一步步累积起来的网络只是一个工具,只有自己身心提高才是实实在在的。d-programming-language-china.org为大家提供一个学习交流各种知识的平台
页: [1]
查看完整版本: C#-like 的 DLL 封装