`
oldrev
  • 浏览: 229904 次
  • 性别: Icon_minigender_1
  • 来自: 昆明
社区版块
存档分类
最新评论

C#-like 的 DLL 封装

阅读更多
一个类似 C# 的 DllImport 实现,用于“半”动态加载 DLL。用起来比我以前写的 DLLWrapper 要麻烦一些,但是 DLLWrapper 由于使用一个 Tuple 来存储函数声明,会造成超长的标识符导致编译错误,这个 DllImport 避免了这个问题。

这个实现有一个缺陷是每次调用API函数的时候都会执行一次 GetProcAddress,效率比较低.... 谁能告诉我怎么避免该死的 CTFE?

代码
  1. // DllImport - A C#-like DLL Wrapper
  2. // written by oldrev (wstring#gmail.com)
  3. // License: BSD
  4. import std.stdio;
  5. import std.typetuple;
  6. import std.utf;
  7. import std.c.windows.windows;
  8. import std.traits;
  9. import std.string;
  10. import singleton;
  11. extern(Windows)
  12. {
  13. HMODULE LoadLibraryW(LPCWSTR libPath);
  14. }
  15. private static class ModuleManager
  16. {
  17. private static HMODULE [char[]] m_modules;
  18. private this()
  19. {
  20. }
  21. static public ~this()
  22. {
  23. foreach(h; m_modules)
  24. {
  25. FreeLibrary(h);
  26. }
  27. }
  28. private static HMODULE registerModule(char[] name)
  29. {
  30. char[] lname = tolower(name);
  31. HMODULE h = LoadLibraryW(toUTF16z(lname));
  32. if(h is null)
  33. throw new Exception("Failed to load DLL: " ~ name);
  34. m_modules[lname] = h;
  35. return h;
  36. }
  37. public static HMODULE getHandle(char[] name)
  38. {
  39. return m_modules[name];
  40. }
  41. public static ProcType getSymbol(ProcType)(char[] moduleName, char[] procName)
  42. {
  43. HMODULE handle = null;
  44. if(moduleName in m_modules)
  45. handle = m_modules[moduleName];
  46. else
  47. handle = registerModule(moduleName);
  48. assert(handle !is null);
  49. return cast(ProcType)GetProcAddress(handle, toStringz(procName));
  50. }
  51. }
  52. struct DllImport(char[] ModuleName, char[] ProcName, FT)
  53. {
  54. extern(Windows) alias ReturnType!(FT)
  55. function(ParameterTypeTuple!(FT)) FunctionType;
  56. // 非要这样重新绑定 extern(Windows),是不是编译器的 bug?
  57. // extern(Windows) alias FT FunctionType; // 这样就不行
  58. //怎么避免 CTFE?
  59. //FIXME:
  60. //FunctionType m_funcPtr = ModuleManager.getSymbol!(FunctionType)(ModuleName, ProcName);
  61. public ReturnType!(FunctionType) opCall(ParameterTypeTuple!(FunctionType) args)
  62. {
  63. FunctionType m_funcPtr = ModuleManager.getSymbol!(FunctionType)(ModuleName, ProcName);
  64. return m_funcPtr(args);
  65. }
  66. }
  67. void main()
  68. {
  69. DllImport!("user32.dll", "MessageBoxA",
  70. int function(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)) MessageBox;
  71. MessageBox(null, "Text", "Title", MB_OK);
  72. }
分享到:
评论
9 楼 DavidL 2007-04-20  
可以直接用bindings里的win32/winuser.d来调用这些dll吧
8 楼 qiezi 2007-04-17  
方法名字只能用其它方式得到,比如stringof
7 楼 oldrev 2007-04-17  
我查了 ClassInfo 类,没有方法名字,只有类的名字
6 楼 qiezi 2007-04-17  
class有classinfo,它包括名字,struct我就不清楚了,应该也有。不过这些好像是运行时的,编译时可以用模板的alias参数去取,前面我提到过几次了,pyd里面用了这种方法取的参数名字。
5 楼 oldrev 2007-04-17  
有没有办法可以反射出一个struct或class的方法的名字
4 楼 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怎么办?还得加一个调用约定参数吧?
3 楼 oldrev 2007-04-17  
问题是 DMD 限制标识符为 4k 个字符,上一版只要稍微多定义几个函数就出错了
2 楼 qiezi 2007-04-17  
我觉得上一版使用更方便呢,效率应该也会高一些吧。
1 楼 oldrev 2007-04-17  
为了杜绝零回复.....

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);
}

相关推荐

Global site tag (gtag.js) - Google Analytics