我正在忙着编写一个为主机应用程序提供多个功能的DLL。 该应用程序动态调用dll,在每次函数调用后加载并释放它。
我无法控制主机应用。我只能在dll中工作。 有没有办法可以将某些变量保存在内存中,以便我可以在每个函数中重用它们?当主机应用程序卸载dll时,显然会清除全局变量。 将dll保存到文件听起来非常混乱!
有人能建议一种分配变量的方法,我可以保持全局吗?
由于
答案 0 :(得分:4)
警告,脏黑客:
你可以加载自己。
每次调用LoadLibrary
都会增加一个引用计数器,FreeLibrary
会减少它。仅当计数器达到零时,才会卸载DLL。
因此,如果您的DLL第一次加载,您只需再次加载库,从而增加引用计数器。如果调用应用程序调用{{1}},则引用计数器会递减,但DLL不会被卸载。
编辑:正如mghi指出的那样,如果进程终止,DLL将被卸载,无论引用计数是否为零。
答案 1 :(得分:4)
我认为你有两个主要选择。
提供你的两个版本的函数,你现在拥有的版本,以及另一个版本,它们传入一个缓冲区(记录,无论如何),你可以读取之前的状态,当然还有状态更新。将此称为函数的高性能版本。他们会想要使用它。
保存状态就像你在一个文件中的cookie一样(基本上就是这样)。
选项1需要修改主机应用程序,但主机应用程序开发人员可以利用这一功能,选项2不需要对主机应用程序进行任何更改,但效率不高。
我个人不会倾向于开始讨论引用计数,可能是主机应用程序正在卸载是有原因的,如果我是主机应用程序开发,那会让我烦恼。
答案 2 :(得分:2)
如果要共享大量全局数据,另一种解决方案是创建一个“缓存”状态数据的Windows服务。您还需要实现某种跨过程边界的IPC,例如内存映射文件,邮箱,COM(本例中为单实例),TCP / IP等。您可能会发现这种开销不仅仅是将状态写入文件,这就是为什么我只推荐这种方法,如果状态数据量过多,或者只针对每个请求处理部分内容进入你的dll。
对于COM方法,除了请求(并保持)将用于维护状态的com对象的实例之外,服务不必做很多事情。由于它是单实例com对象,因此所有请求都将发送到同一实例,从而允许您在请求之间保存状态。对对象的请求是序列化的,因此如果您有多个客户端同时在同一台计算机上请求数据,则可能会出现性能问题。
答案 3 :(得分:1)
最好的方法是使用包含“globals”的类。您实例化一个对象并将其作为参数提供给dll函数。但这对您没有帮助,因为您无法更改通话应用程序。
如果必须将全局数据保存在dll中,解决方法是将它们写入文件。但这对性能产生了严重影响。
答案 4 :(得分:0)
如果我是你,我会将这些全局变量的值保存到dd被释放的文件中,并在初始化时加载它们。我没有理由在磁盘上保存dll的内存转储。
答案 5 :(得分:0)
在释放DLL时将值写入注册表,并在加载DLL时从注册表中读取值。当读取发现尚未设置密钥时,请不要忘记提供默认值。
-Al。
答案 6 :(得分:0)
我同意之前关于全球国家信息危险的评论,尽管我可以想象可能需要它。
我提出了DR的肮脏黑客的更清洁版本,没有像skamradt的答案那样具有永久性的缺点:
一个非常小的应用程序:
它没有任何外观,它不会在任务栏上显示。
任务#1:加载DLL
任务#2:拿它的命令行,运行它并等待它终止。
任务#3:卸载DLL
任务#4:退出。
安装程序:
它找到主应用程序的快捷方式并修改它们以便小应用程序运行,快捷方式指向的原始位置成为第一个参数。
结果:只要主应用程序正在运行,DLL就会保留在内存中,但每次程序转储它时都不会卸载它。
答案 7 :(得分:0)
这也可能有用
option 1:
创建一个共享内存区域,用于保存由分页文件支持的变量 - 如果您能够打开该共享内存区域,则您的dll先前已加载(假设为“私有”共享内存名称,可能名称为process_id_yourdllname) - 如果可以的话打开它,然后你第一次创建并初始化它。如果你创建它,那么你不打扰删除它 - 但如果你打开它,你会关闭它 - 卸载时。我相信该区域将在应用程序关闭时释放,因为没有其他应用程序应该具有此特定“私有”共享内存区域的句柄。
option 2:
创建第二个.dll,仅用于管理全局变量。你的dll A可以加载那个dll B,而不是释放它,放入dll B,无论你需要管理全局变量。当应用程序消失时它应该消失,我认为你可能不需要关心所涉及的(可能是无用的)引用计数(因为你不会卸载dll B)。