`
oldrev
  • 浏览: 233726 次
  • 性别: 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);
}

相关推荐

    DevExpress8.3 C# 所有dll

    DLL(Dynamic Link Library)是Windows操作系统中的一个重要组成部分,它封装了特定的功能或服务,可供多个程序同时调用,减少了内存占用和提高了代码复用性。在C#开发中,使用DevExpress的DLL可以轻松地添加高级UI...

    C#自定义控件库

    这通常涉及资源文件的使用,以及通过样式表(CSS-like)来定义控件的样式。 7. **性能优化**:在设计自定义控件时,要考虑性能因素,避免不必要的重绘和计算。合理使用双缓冲技术可以减少闪烁,而优化重绘逻辑则...

    C#麦克风插拔检测, 热插拔

    ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_SoundDevice WHERE DeviceID LIKE '%wave%in%'"); ManagementObjectCollection devices = searcher.Get(); foreach ...

    有关C#和数据库的培训WorkReport

    **面向对象编程(OOP)**是C#的一大特色,它强调将数据和操作数据的方法封装在一起,形成对象。培训中,重点学习了类与对象的定义、继承、多态、接口、抽象类等OOP关键概念,掌握了如何利用C#构建复杂的数据结构和逻辑...

    WPF Color Picker Like Office 2007

    **WPF Color Picker Like Office 2007** 在Windows Presentation Foundation(WPF)中创建一个类似Office 2007的颜色选择器是一项常见的任务,它涉及到用户界面设计和交互体验的优化。Office 2007的色彩选择器以其...

    liprary-open-mp3.zip_Visual_C++_

    1. **Kmadxlib.cpp**:这可能是一个包含C++封装libmad的源代码文件,可能用于简化在C++项目中使用libmad的工作。 2. **test.cpp**:这是一个测试文件,通常用于验证库的功能和正确性。开发者可能在这里编写代码来...

    asp.net从入门到精通课后答案【练一练】

    3. **namelike‘张%’and namelike‘%奇%’**:SQL查询语句,用于搜索名字中既包含“张”又包含“奇”的记录。 4. **Insert、Update、Delete**:这些是SQL语言中的关键字,分别用于插入、更新和删除数据。 5. **...

    横瓜数据库全文检索中间件

    你无需对自己的数据库文件做任何更改,就可以为数据库文件创建可供编程语言调用的ActiveX DLL全文检索接口,可用于任何与数据库检索有关的查询,例如全文搜索、垂直搜索、海量数据库LIKE式快速查询等。软件主要特点...

    ASP.NET-[整站程序]Personal.NETPortal个人门户系统.zip

    在ASP.NET中,开发者可以使用多种编程语言,如C#、VB.NET等,来编写代码。该框架支持事件驱动编程模型,使得网页交互更加直观和高效。 【个人门户系统】 个人门户系统是一种集成了多种信息资源和服务的平台,允许...

    网上书店asp.net源码

    3. 搜索与分类:用户可以根据关键词、作者、类别等条件进行搜索,实现这一功能通常需要用到SQL查询和Like操作。 4. 购物车:用户可以添加书籍到购物车,购物车数据通常保存在Session或Cookie中,以保持用户会话状态...

Global site tag (gtag.js) - Google Analytics