问个有点点难度的问题,如何获取内存中已在执行的DLL中的Class

还想懒够 2006-10-22 01:53:32
我个人认为有点难度,没有写过这方面的东西。请高手解决一下


问题如下:

假定现在有一个DLL工程,名称为Test,里面有一个Class,名称为Class1

Class1中间有一个属性

Dim strTestValue as String

Public Property Get TestValue() As String
TestValue = strTestValue
End Property

Public Property Let TestValue(New_Value As String)
strTestValue = New_Value
End Propery


另外还有一个工程只是一个普通EXE工程了,里面有代码如下
Dim m As Object
Set m = CreateObject("Test.Class1")
m.TestValue = "AAATest"

这个可以放在Form_Load里面

另外,Form里面还可以假定有一个按钮,Click事件里面的代码就包含着问题

Dim o As Object
'就这里开始有问题了
'我该如何写入代码,使下面的结果成立,即需要调用已执行的Test.Class1(该Class并没有结束,因此一直在内存里面)
MsgBox o.TestValue '使其结果返回AAATest


注:第二次是一个新的对象,我必须需要这样操作,因为无法将m定义为一个全局变量,我有可能利用主程序调用自己编写的DLL再来访问Test.Class1


急用,谢谢,二百分送上
...全文
351 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
还想懒够 2006-10-23
  • 打赏
  • 举报
回复
我只是想利用内存中现有的一个组件来连接数据库,因此只需要连接一次就可以了,而不需要每次调用的时候就需要去连接一次数据库,这样也够麻烦的,有时候理不清楚了,连了多少次都有点糊涂了
IamDeane 2006-10-23
  • 打赏
  • 举报
回复
关注一下
pigsanddogs 2006-10-23
  • 打赏
  • 举报
回复
能不能去内存中搜索这个DBEngine的地址,然后再CopyMemory?

呵呵,能力有限,请再指教,谢谢

===========================

不可以, 就算可以, 也不通用, 而且效率底
为什么不放到环境中??
leongwong 2006-10-22
  • 打赏
  • 举报
回复
HOHO,关注!
Hassle 2006-10-22
  • 打赏
  • 举报
回复
哈哈,把问题想复杂了
===================================

标准模块与类模块的比较


在数据存储方式上,类不同于标准模块。标准模块的数据不可能多于一份。这意味着若程序中某个部分改动了标准模块的公共变量,随后程序的其它部分读取该变量会得到该值。

相反,类模块数据则独立存在于每个类的实例中。

应避免使类中的代码依赖于全局数据─ 即标准模块中的公共变量。一个类可能同时存在很多个实例,所有这些对象都共享部件中的全局数据。

静态的类数据
在类模块中使用全局变量不符合面向对象编程的封装概念,因为这种类创建的对象没有包含它所有的数据。不过,有时要让同一个类模块创建的所有对象共享一个数据成员。例如,一个类所创建的所有对象要共享一个属性值,如部件的名称或版本号。

这种对封装的故意违反有时称之为静态的类数据。通过使用 Property 过程设置并返回标准模块中的 Public 数据成员,就可以在 Visual Basic 的类模块中实现静态的类数据,如下面代码段所示:

'返回应用程序名的只读 property。
Property Get ComponentName() As String
'变量 gstrComponentName 存储于标准模块中,声明为 Public。
ComponentName = gstrComponentName
End Property

通过提供一个相关的 Property Let 过程─ 或对包含对象引用的属性使用 Property Set 过程─ 给标准模块中的数据成员赋新值,可以实现非只读的静态的类数据。

重点 在设计使用静态数据的类时,要考虑到所写的部件要为若干个客户端应用程序(如果是进程外部件)或者为一个客户端以及若干个进程内部件(如果是进程内部件)提供对象。即使该类创建的所有对象被不同的客户端使用,但都共享该静态数据。

------------------MSDN
PANBing 2006-10-22
  • 打赏
  • 举报
回复
在Form_Load中保存对象的指针,再在Click中使o指向它,这样不知行不行得通。
Dunzip 2006-10-22
  • 打赏
  • 举报
回复
直接传一个物件给外部控件好了
这样简单些。
Hassle 2006-10-22
  • 打赏
  • 举报
回复
HANDLE CreateFileMapping(
HANDLE hFile, // handle to file to map
LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
// optional security attributes
DWORD flProtect, // protection for mapping object
DWORD dwMaximumSizeHigh, // high-order 32 bits of object size
DWORD dwMaximumSizeLow, // low-order 32 bits of object size
LPCTSTR lpName // name of file-mapping object
);

hFile = (HANDLE)0xFFFFFFFF;

Return Value ERROR_ALREADY_EXISTS可以判断是否已初始化

访问用lpName

Class1中间有一个属性

Dim strTestValue as String '这个不要了

Public Property Get TestValue() As String
TestValue = strTestValue '改为读映射,
End Property

Public Property Let TestValue(New_Value As String)
strTestValue = New_Value '改为写映射
End Propery

类似C++的静态数据,无论该类有多少实例,此数据只有一份

谨供参考
PANBing 2006-10-22
  • 打赏
  • 举报
回复
关注..............
还想懒够 2006-10-22
  • 打赏
  • 举报
回复
能不能去内存中搜索这个DBEngine的地址,然后再CopyMemory?

呵呵,能力有限,请再指教,谢谢
Dunzip 2006-10-22
  • 打赏
  • 举报
回复

楼主是想直接把主程序的DBEngine物件直接传给要调用的DLL1,Dll2,Dll3....,让DLL1,Dll2,Dll3....这些程序可以直接调用资料库,跟主程序一样操作。


chuangyejufa 2006-10-22
  • 打赏
  • 举报
回复
与楼主有同样的问题,
pigsanddogs 2006-10-22
  • 打赏
  • 举报
回复
一样的阿。
只要你保证这个dbengine是内存中存在
也就是我第一个帖说明的问题, 如果非要在exe的form_load中createobject, 那么需要把这个
对象的objptr取出来, 并把这个局部对象的objptr给0值防止释放对象, 如果是在exe的
全局中定义的object, 那么则没有这个问题.

现在假设你这个dbengine是在内存中存在了.


那么你的active dll2, 就是你需要copy内存执行debegine的的dll, 也必须引用dll1,
这样你在dll2中 dim o as object o.dbenginemethod 的时候才能有效.
因为你在dll2中引用了dll1, 那么dll1中有包含了 dbenginemethod这个方法,
又得到了objptr, 那么vb才能知道怎么去call那么虚表.

现在还有一个, 就是如何得到这个objptr,
显然你的exe中得到了objptr,如我第一帖所说,你把他保存到exe的全局变量中去了.
你要把这个objptr传给dll2, 并且又不能显式的传送, 那么最佳的方法是放到环境中,
然后在dll2中从环境中取(我上一个帖子的tlsgetvalue并不是好方法, 因为
不能确定那个index, 主要是用在不同线程的特例化中)

用 api GetEnvironmentVariable 和 SetEnvironmentVariable 来实现.
注意这2个api用string表示, string同样能表示一个long的objptr.
还想懒够 2006-10-22
  • 打赏
  • 举报
回复
是这样的,我主程序运行后,就需要调用一个自己写的DLL(假定为DBEngine),这个DLL里面包含着数据库连接等信息.当我使用这个EXE调用另外一个DLL来执行某些功能,需要用到数据库信息我就直接定义一个DBEngine,然后不需要再去重新连接数据库了,直接Copy内存中已运行的就可以了(想法是这样的),因为我的主EXE没有退出,所以DBEngine因此也没有Terminate,我想这样应当理论上成立吧,就是不知道该如何实现.
myvicy 2006-10-22
  • 打赏
  • 举报
回复
学习
pigsanddogs 2006-10-22
  • 打赏
  • 举报
回复
没有太明白你的程序构架.

你是一个exe, 需要用到2个active dll吗.
然后在一个dll中用另外一个dll对象吗? (中途通过exe来中转)

这3个工程都是你建立的吗?

因为active dll跟vb在一个线程中,
并且dll是在第一次使用createobject的时候才loadlibrary的.
你可以在from_load中用TlsSetValue,
在你的active dll 2 的初始化中用TlsGetValue来得到那个 object ptr.
还想懒够 2006-10-22
  • 打赏
  • 举报
回复
感谢pigsanddogs

这只是将Form_Load和Command1_Click放在一个工程里面使用

但如果我有另外一个ActiveX Dll,里面添加一个Form,再加一个Command,我在主程序的Form_Load里面赋值,但在不给Dll传入参数的情况下,我怎么在另外一个Dll中调用?谢谢
pigsanddogs 2006-10-22
  • 打赏
  • 举报
回复
在Form_Load中保存对象的指针,再在Click中使o指向它,这样不知行不行得通。

===============
行不通, 因为在form_load 定义的对象m, 这是一个栈中变量,
那么当他离开了form_load的作用域时, m就会调用release操作, 即把m对象所指向
的对象的引用计数减1, 如果一个对象的引用次数减到了0的时候, 那么这个对象就被析够了.
显然, 在form_load退出的时候, 新createobject的对象已经不存在了.
这个时候, 就算你保存了指针, 你在click的时候使用他, 一样非法操作.
给个保存指针操作的例子证明一下:




Option Explicit
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Long, ByVal Source As Long, ByVal Length As Long)

Dim value As Long
Dim val0 As Long


Private Sub Command1_Click()
Dim o As Object
CopyMemory VarPtr(o), VarPtr(value), 4
MsgBox o.TestValue
CopyMemory VarPtr(o), VarPtr(0), 4
End Sub

Private Sub Form_Load()
Dim m As Object
val0 = 0
Set m = CreateObject("test.Class1")
CopyMemory VarPtr(value), VarPtr(m), 4
m.TestValue = "AAATest"
End Sub

当执行click的时候, 一定非法操作.
如果把 dim m as object 放到全局定义, 那么是能成功的.

现在的关键问题就是, 让m离开他的作用域释放的时候, 不会把实际这个对象的引用计数
减1, 其实实现也很简单, 让m的指针为0即可.
即在form_load 的最后加上一条语句
CopyMemory VarPtr(m), VarPtr(val0), 4



以下是完整原代码

Option Explicit
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Long, ByVal Source As Long, ByVal Length As Long)

Dim value As Long
Dim val0 As Long


Private Sub Command1_Click()
Dim o As Object
CopyMemory VarPtr(o), VarPtr(value), 4 '指针操作.
MsgBox o.TestValue
CopyMemory VarPtr(o), VarPtr(0), 4 '为了不让对象给析构!!
End Sub

Private Sub Form_Load()
Dim m As Object
val0 = 0
Set m = CreateObject("project1.Class1")
CopyMemory VarPtr(value), VarPtr(m), 4 '保存操作指针
m.TestValue = "AAATest"
CopyMemory VarPtr(m), VarPtr(val0), 4 '为了不让对象给析构!!
End Sub

7,763

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧