I bet u need a fusion powered shuttle to reach my place...
Posts
963
Return an object(late-bind) by giving an object pointer - How?
Let's say I've an object pointer.
I want a function that returns an object to me by simply giving it
an object pointer. Then I'll set it to an Object variable.
Then I'll use its function the late-bind way.
Is this possible?
ASM,C,C++,BASIC,VB,JAVA,VBS,HTML,ASP,PHP,mySQL,VB.NET,MATLAB
Programming is fun, but only if you're not on a tight deadline
So I consider all those working engineers sad people
Could you elaborate a little more on this statement please?
Here is a simplistic example:
VB Code:
' cMyTest Class
' Just a simple class to test using ObjPtr and CopyMemory.
Option Explicit
Private Type MyUDT
ID As Long
Description As String
End Type
Private mudtData As MyUDT
Public Property Get ID() As Long
ID = mudtData.ID
End Property
Public Property Let ID(ByVal Value As Long)
mudtData.ID = Value
End Property
Public Property Get Description() As String
Description = mudtData.Description
End Property
Public Property Let Description(ByVal Value As String)
mudtData.Description = Value
End Property
VB Code:
' frmMyTest form
' Just a simple form to test using ObjPtr and CopyMemory.
Option Explicit
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
' The object that we will be instantiating and setting its state.
Private mobjSrc As cMyTest
' The object that we will not be instantiating but setting its state
' using CopyMemory.
Private mobjDest As cMyTest
Private Sub Command1_Click()
' Show what we have in the Source instance.
With mobjSrc
Debug.Print .ID
Debug.Print .Description
End With
End Sub
Private Sub Command2_Click()
Dim lngSource As Long
' Obtain the Source instance's address in memory
lngSource = ObjPtr(mobjSrc)
' Copy the state of Source to create and set the state of Dest.
' Note: We have not instantiated the Destination.
CopyMemory mobjDest, lngSource, 4
' Show what we have in the Destination instance.
With mobjDest
Debug.Print .ID
Debug.Print .Description
End With
End Sub
Private Sub Form_Load()
' Create the Source instance and set its state.
Set mobjSrc = New cMyTest
With mobjSrc
.ID = 1001
.Description = "This is a test"
End With
End Sub
It may not work for complex classes encapsulating other objects (although I will be testing this more to confirm), but using ObjPtr and CopyMemory does work (with at least simple objects).
I didn't think that it would always work, like you said, with objects encapsulating objects, and so forth. Granted I have never really found the need to do such a thing, so I haven't invested much time in testing it. But if it can be done, then it can be done. What can I say?
Laugh, and the world laughs with you. Cry, and you just water down your vodka.
I've completed some testing on the subject and have found that it will work for encapsulated objects and to jian2587's original question, it will work with late-binding.
VB Code:
' cMyTestSub
Option Explicit
Private Type MySubUDT
SubID As Long
SubDescription As String
End Type
Private mudtData As MySubUDT
Public Property Get SubID() As Long
SubID = mudtData.SubID
End Property
Public Property Let SubID(ByVal Value As Long)
mudtData.SubID = Value
End Property
Public Property Get SubDescription() As String
SubDescription = mudtData.SubDescription
End Property
Public Property Let SubDescription(ByVal Value As String)
mudtData.SubDescription = Value
End Property
VB Code:
' cMyTest
Option Explicit
Private Type MyUDT
ID As Long
Description As String
End Type
Private mudtData As MyUDT
Private mobjSub As cMyTestSub
Private mcolSubs As Collection
Public Property Get ID() As Long
ID = mudtData.ID
End Property
Public Property Let ID(ByVal Value As Long)
mudtData.ID = Value
End Property
Public Property Get Description() As String
Description = mudtData.Description
End Property
Public Property Let Description(ByVal Value As String)
mudtData.Description = Value
End Property
Public Property Get EncapsulatedObject() As cMyTestSub
Set EncapsulatedObject = mobjSub
End Property
Public Property Set EncapsulatedObject(ByVal Instance As cMyTestSub)
Set mobjSub = Instance
End Property
Public Property Get Subs() As Collection
Set Subs = mcolSubs
End Property
Private Sub Class_Initialize()
Set mcolSubs = New Collection
End Sub
VB Code:
' frmMyTest
Option Explicit
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
one other thing to test is what happens when the
source object goes out of scope...
the ref count is not incremented with copymemory
so if you hung onto just the pointer to long, or the
dest object you could run into problems with invalid
pointer in some situations
you could get around this by copymemory to a temp
object then returning another one taken from the
temp with set= to increment the ref count (assuming
valid pointer passed in)
I bet u need a fusion powered shuttle to reach my place...
Posts
963
Nice codes!
I haven't tested the code...but from what I see, apart from some
nice and good codes, is that the codes looks more like creating a
new copy of object than returning an object to me. But anyway
I'd be glad to know how to do that! Lots of thanks to rlwhealdon!
and dzzie, nice advice! I never knew that...
And one more question, if the object I want to refer is out of my
own process, is it possible to use rlwhealdon's method?
ASM,C,C++,BASIC,VB,JAVA,VBS,HTML,ASP,PHP,mySQL,VB.NET,MATLAB
Programming is fun, but only if you're not on a tight deadline
So I consider all those working engineers sad people
I bet u need a fusion powered shuttle to reach my place...
Posts
963
Apparently I was wrong.
It did return an object to me instead of creating a new one.
I just found out that it's actually changing the destination object
to point to the source object.
If the source object is out of my process, can I refer it?
Or is there a workaround for this?
ASM,C,C++,BASIC,VB,JAVA,VBS,HTML,ASP,PHP,mySQL,VB.NET,MATLAB
Programming is fun, but only if you're not on a tight deadline
So I consider all those working engineers sad people
I don't believe that you can set an instance of an Object variable to an instance of another class/object just by its pointer. To achieve this, you will need to create a copy using the methods demonstrated.
With something like:
VB Code:
Set mobjTest2 = ObjPtr(mobjTest1)
You will get a Type Mismatch error because your are telling VB to set an instance of an Object to the value of a Long.
I have not tested this across processes, but my gut is telling me that since each process is running its own address space, that the memory address returned by ObjPtr in one process will not relate to the same memory address in another process. I could be wrong, and will need to test it to confirm.
I bet u need a fusion powered shuttle to reach my place...
Posts
963
Well yes that's what I mean.
But it's not really creating another copy, it's still pointing to the
source object.
So if I modify the destination object, the source object will be
modified as well, because both is pointing to the very same object
And BTW, thx rlwhealdon! u've been gr8 hlp!
and thx for doing research on that!
ASM,C,C++,BASIC,VB,JAVA,VBS,HTML,ASP,PHP,mySQL,VB.NET,MATLAB
Programming is fun, but only if you're not on a tight deadline
So I consider all those working engineers sad people
Private Declare Function OpenProcess Lib "Kernel32.dll" (ByVal dwDesiredAccessas As Long, ByVal bInheritHandle As Long, ByVal dwProcId As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function GetCurrentProcessId Lib "kernel32" () As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)
Private Const PROCESS_VM_READ As Long = &H10
Private Type mtypDataStruct
Pointer As Long
Length As Long
End Type
Dim marBuffer() As Byte
Dim mudtStruct As mtypDataStruct
Public Function ReadMemory(ByVal ProcessID As Long, ByVal Pointer As Long) As Byte()
Public Function PtrObj(ByVal Pointer As Long) As Object
Dim objObject As Object
CopyMemory objObject, Pointer, 4&
Set PtrObj = objObject
CopyMemory objObject, 0&, 4&
End Function
Public Sub KillProcess(ByVal ProcessName As String)
TerminateEXE ProcessName
End Sub
Well using the above I read Byte arrays from different processes...I am sure that this can be modified slightly so return an object...will it work...??? Hmmmm dunno...give it a go
Yes, that is my general term for cleaning up after one's self.
As I stated in a previous post in this thread. Once I've created a new reference to an object based on its memory address, issuing a:
VB Code:
Set objObject = Nothing
results in an "Unhandled Exception".
If I remove the statement, then the exception is not thrown.
I personally don't like having things left around waiting for VB to determine that they have gone out of scope.
When you posted your first response in this thread, you included a line that in essense, is cleaning up (setting the value of the object instance to 0&, aka Null, aka Nothing) after itself.
VB Code:
CopyMemory objObject, 0&, 4&
If I have mis-interpretted the intent of this statement, then please by all means set me straight.
That line destroys the object...however, since it's private to that function it will get destroyed when the function looses scope anyways...but using that line destroys it anyways...
put msgbox in class_terminate and watch when
it pops
with copy memory you arent creating a new class
or destroying one, you are getting a valid reference
to the com object from its pointer value.
so its not cleanup in the set = nothing sense
because the ref count was never incremented
when you copymemory obj, 0 , 4
you are just removing the reference
to the valid class in the tmp variable
if the objptr was not 0 , then when the
variable goes out of scope, vb would automatically
call the equilivent set obj= nothing to decrement its
ref count
if the object we to nolonger exist then you would get
the invalid memory error.
But it "is" cleaned up in the sense that testing the object variable against Nothing returns true. It's state is now the equivelant of the object variable had I issued the "Set ObjectInstance = Nothing" statement.
VB Code:
CopyMemory mobjTest1, 0&, 4&
CopyMemory mobjTest2, 0&, 4&
MsgBox mobjTest1 Is Nothing
MsgBox mobjTest2 Is Nothing
Both display True.
I understand that VB will eventually handle this for you. I however, am very anal. If I open it, then I try to close it. If I create it, then I try to destroy it. Regardless of whether or not I "need" to.
Actually, I am quite suprised that a simple thank you to Wokawidget for inadvertantly feeding my anal retentiveness, has exploded in the manner that it has.
I don't believe that I have misunderstood what has been communicated here. If any of my posts have given the impression to the contrary, then I guess that I need to work more on my communication skills.
Well the Terminate event is not going to get fired is it, considering there is still a reference to that object...
Create 2 objects...set one = to a valid object, use the PtrObj method I posted either, destroy the 1st object using SET , then Use the copy memory API to destroy the 2nd object and the terminate event will get fired...
So it does destroy the object
It works...
Did anyone manage to copy an object from another process using the code I provided???
Woka
PS Cheers...I have always been god, but just not let on
Does't work...Hahahahahahahahaha
Somewhere along the line my code has been mashed. I'm glad you spotted that....however I am confused where my original code has gone too
Anyways, the function should be:
VB Code:
Public Function PtrObj(ByVal Pointer As Long) As Object
Dim objObject As Object
CopyMemory objObject, Pointer, 4&
Set PtrObj = objObject
CopyMemory ObjPtr(objObject), 0&, 4&
End Function
The destination has to be the POINTER of the object, and not the object itself...just passing the object causes a memory leak
I think you had it right the first time. Your modified version, copying 0& to the pointer of the object results in an unhandled exception, where the previous version did not.
Change the code in that form, in the zip I posted, to:
VB Code:
Option Explicit
Private objOne As clsWoof
Private objTwo As clsWoof
Private Sub Command1_Click()
Set objOne = New clsWoof
objOne.Username = "Growling Weasel"
Set objTwo = PtrObj(ObjPtr(objOne))
MsgBox ObjPtr(objTwo)
Set objOne = Nothing
CopyMemory ObjPtr(objTwo), 0&, 4&
End Sub
Suggests that the object DOESN'T get destroyed...I am not God
However
VB Code:
CopyMemory ObjPtr(objTwo), 0&, 4&
Does allow the object to be destroyed once the function is was defined in gets destroyed...
The CopyMemory only destroys the pointer to the object and not the contents on the object....Hmmmmmmm
How can you find the length of an Object in bytes???
Can't find any API for it
Originally posted by rlwhealdon I think you had it right the first time. Your modified version, copying 0& to the pointer of the object results in an unhandled exception, where the previous version did not.
Errr....so my ZIP file I posted gives you an error??? I don't get an error....but the object gets destroyed when the sub ends...
Just passing the object to copymemory does not terminate the object when the sub finishes, but when the process gets terminated...passing the pointer of the object terminates the object when, and ONLY when, the scope of the object runs out, ie when the form is unloaded, or when the sub finishes
Hmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm...
I thought I had this wrapped up months ago....yet this thread has proved otherwise...Hmmmm cool! back to the drawing board...
I bet u need a fusion powered shuttle to reach my place...
Posts
963
Yes, an object is only destroyed when it's out of scope.
But it's also destroyed when all reference to it is destroyed.
Woka,
if u add in Set objTwo = Nothing as well, the object will get
destroyed b4 the scope runs out, in this case, the form.
because all references to the object(both objOne and objTwo) is
destroyed.
I realized that if you create an object through CopyMemory,
u've to destroy it through CopyMemory Obj, 0&, 4&
and not Set Obj = Nothing
The same thing if you create an object by Set Obj = ObjSrc.
U've to Set Obj = Nothing instead of CopyMemory Obj, 0&, 4&
Because u create ObjTwo by Set ObjTwo = objObject, VB knows
there's another reference to it, and thus even Set ObjOne =
Nothing wouldn't destroy the object.
Different thing if u point the object urself through CopyMemory.
VB doesn't know it and lots errors crop up when u try to Set it to
Nothing.
ASM,C,C++,BASIC,VB,JAVA,VBS,HTML,ASP,PHP,mySQL,VB.NET,MATLAB
Programming is fun, but only if you're not on a tight deadline
So I consider all those working engineers sad people