2007-04-16
C#-like 的 DLL 封装
关键字: DLL 动态库
一个类似 C# 的 DllImport 实现,用于“半”动态加载 DLL。用起来比我以前写的 DLLWrapper 要麻烦一些,但是 DLLWrapper 由于使用一个 Tuple 来存储函数声明,会造成超长的标识符导致编译错误,这个 DllImport 避免了这个问题。
这个实现有一个缺陷是每次调用API函数的时候都会执行一次 GetProcAddress,效率比较低.... 谁能告诉我怎么避免该死的 CTFE?
这个实现有一个缺陷是每次调用API函数的时候都会执行一次 GetProcAddress,效率比较低.... 谁能告诉我怎么避免该死的 CTFE?
代码
- // 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);
- }
评论
DavidL
2007-04-20
可以直接用bindings里的win32/winuser.d来调用这些dll吧
qiezi
2007-04-17
方法名字只能用其它方式得到,比如stringof
oldrev
2007-04-17
我查了 ClassInfo 类,没有方法名字,只有类的名字
qiezi
2007-04-17
class有classinfo,它包括名字,struct我就不清楚了,应该也有。不过这些好像是运行时的,编译时可以用模板的alias参数去取,前面我提到过几次了,pyd里面用了这种方法取的参数名字。
oldrev
2007-04-17
有没有办法可以反射出一个struct或class的方法的名字
qiezi
2007-04-17
Dll!("user32.dll") user32;
user32.DllImport!("MessageBoxA", int function(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType))MessageBox;
或者:
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
问题是 DMD 限制标识符为 4k 个字符,上一版只要稍微多定义几个函数就出错了
qiezi
2007-04-17
我觉得上一版使用更方便呢,效率应该也会高一些吧。
oldrev
2007-04-17
为了杜绝零回复.....
0.0.0.0.0.2 版,要稍微高效一点:
0.0.0.0.0.2 版,要稍微高效一点:
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);
}
发表评论
- 浏览: 105138 次
- 性别:

- 来自: 昆明

- 详细资料
搜索本博客
我的相册
Screenshot
共 1 张
共 1 张
最近加入圈子
最新评论
-
出色的开源项目管理软件— ...
我也是前几天刚刚从trac换到redmine,感觉好多了,trac有的redmi ...
-- by danielking -
转贴:鲁迅未收入全集的文 ...
借问酒家何处有,牧童遥指杏花村
-- by hqs7636 -
Range Coding 的 D 实现
引用oldrev 2008-01-12LZMA SDK 只是一个 LZMA 算法 ...
-- by oldrev -
D 静态数组初始化大bug
看看日期好伐?
-- by oldrev -
D新闻组里的天才代码
没看过产生的汇编代码,测试了是可行的。如果用宏来实现就完美了
-- by oldrev






评论排行榜