|
-
Mar 28th, 2003, 06:13 AM
#1
SubClassing a class module...think it involves creating a handle?
'ello
I have a class module, that will use SendMessage to communicate with another application...
what I want is for that application to be able to SendMessage back to the class module...
How do I create a handle/window blah blah for a class module and subclass it?
-
Mar 28th, 2003, 06:17 AM
#2
Frenzied Member
Check out the aricle: Inter process communication using registered messages from Visual Basic - this deals with creating windows specifically for the purpose of sending/receiving messages...
-
Mar 28th, 2003, 06:21 AM
#3
Retired VBF Adm1nistrator
Do you ever do anything the easy way ?
Microsoft MVP : Visual Developer - Visual Basic [2004-2005]
-
Mar 28th, 2003, 06:24 AM
#4
Frenzied Member
-
Mar 28th, 2003, 06:25 AM
#5
Just the person...
heers, good site...I have a question.
At the moment I am using MailSlots to communicate with a generic connection application...These however have a few downsides...looping in my app to wait for a response, if the app crashes I have to reboot the PC...blah blah blah.
Anyways, I was looking at communicating using SendMessage as this returns once the function has been completed, no looping for a response required...
However, I have a question...
What happens if I subclass my connection application and it retrieve a "LOAD_USERS" message? What I mean is I trap for the message, communicate with the DB, retrieve the data, then return the WinProc thingy...since NO message will be handled while my app is communicating with the DB will this pose any problems???
Woka
-
Mar 28th, 2003, 06:31 AM
#6
Originally posted by plenderj
Do you ever do anything the easy way ?
Well...errr...no! Easy is crap 
What I have at the moment is:
Clients (multiple) all communicating with the same Connection Application by means of MailSlots, which in turns contacts a server app by means of TCP/IP...
I have a class called clsUsers which is a collection of clsUser, I can load 100 users, 7 times in a row, ie:
VB Code:
For lngIndex = 1 To 7
Set objUsers = New clsUsers
objUsers.Load
Next lngIndex
...in 875 ms, but that is INCLUDING the code:
VB Code:
Do
Sleep 100
strBuffer = MailSlotRead(ClientSlot)
Loop Until (strBuffer <> vbNullString) Or (GetTickCount - lngStart > TIMEOUT)
Which waits for a return response from the Connection App.
If the client communicated with the connection app using SendMessage then it would remove the need for the looping above, and thus speed up the data access 
Woka
-
Mar 28th, 2003, 06:34 AM
#7
Actually I have just increased the number of users to 204, and it's still taking 875ms to retrieve the data 
This means that the slow buit is communication betyween the client and the connection object...
Woka
-
Mar 28th, 2003, 06:36 AM
#8
Frenzied Member
Do you ever do anything the easy way ?
Which waits for a return response from the Connection App.
If the client communicated with the connection app using SendMessage then it would remove the need for the looping above, and thus speed up the data access
U could also push the least significant bit 2 bits to the right and pop the semi - significant bit 4 bits to left and the move the most significant bit right out of its memory space! That would speed things even faster
"Brothers, you asked for it."
...Francisco Domingo Carlos Andres Sebastian D'Anconia
-
Mar 28th, 2003, 06:42 AM
#9
-
Mar 28th, 2003, 06:49 AM
#10
Frenzied Member
What happens if I subclass my connection application and it retrieve a "LOAD_USERS" message? What I mean is I trap for the message, communicate with the DB, retrieve the data, then return the WinProc thingy...since NO message will be handled while my app is communicating with the DB will this pose any problems???
No problem that I can think of - messages are queued and the queue is a decent size so you shouldn't have any probs waiting for your message.
Your application will appear as "not responding" in task manager because this works by the OS sending a particular message (with a timeout) to your app and seeing if it times out. Also you should not specify WS_EX_APPWINDOW when creating your window or it will be included in the task bar / alt+tab list and that can have undesirable effects if your window proc is blocked.
You can implement asynchronous communication (which is faster if you have many-to-one type communication) by using PostMessage instead of SendMessage as well.
-
Mar 28th, 2003, 06:58 AM
#11
Yea, But in my client I have:
VB Code:
objUsers.Load
MsgBox "Woof"
If I use postmesaage then Woof would get displayed BEFORE the data is loaded. To get round this I would have to loop in my client app...
Is there anyways I could use SendMessage, but the the app that it's being sent to to carry ob processing other message while certain DB stuff is going on, and when it's finished then return a result for sendmessage?
Woka
-
Mar 28th, 2003, 07:34 AM
#12
Frenzied Member
In that case you need SendmessageCallback e.g.:
VB Code:
Option Explicit
Declare Function SendMessageCallback Lib "user32" Alias "SendMessageCallbackA" (ByVal hwnd As Long, ByVal msg As Long, ByVal wParam As Long, ByVal lParam As Long, ByVal lpResultCallBack As Long, ByVal dwData As Long) As Long
Public Sub AsyncmessageDealtWith(ByVal TargetWnd As Long, ByVal msg As Long, ByVal lpData As Long, ByVal lRes As Long)
'\\ The windoiw (TargetWindow) dealt with the message and send back the answer lRes
MsgBox "Woof return was " & lRes
End Sub
Public Sub CallAsyncThing()
Call SendMessageCallback(hwndtarget, MSG_USER, 0, 0, AddressOf AsyncmessageDealtWith, 100)
End Sub
Then if you have code like...
VB Code:
'do x
Call CallAsyncThing()
'do y
Then the caller will not bloc (i.e. it will proceed on to do y) but as soon as the callee returns then the message "woof" will be displayed.
-
Mar 28th, 2003, 07:55 AM
#13
Errrr...I don't want y to be executed UNTIL SendMessage has a return value, but on the other hand, I want my connection app to continue processing other messages, ie Paint, Move and other system messages as well as buffering other DB message WHILE doing DB processing...
Not possible is it?
I am going to have to be forced to have NotResponding in my TaskBar 
Woka
-
Mar 28th, 2003, 07:57 AM
#14
Although, is there anyway I could modify:
VB Code:
Public Sub CallAsyncThing()
Call SendMessageCallback(hwndtarget, MSG_USER, 0, 0, AddressOf AsyncmessageDealtWith, 100)
End Sub
To have the WaitForSingleObject API in it, and it waits UNTIL a response is sent back?
Woka
-
Mar 28th, 2003, 08:26 AM
#15
Is it possibel to create 2 windows with the same title using those API commands you suggested?
Woka
-
Mar 28th, 2003, 08:30 AM
#16
Frenzied Member
Errrr...I don't want y to be executed UNTIL SendMessage has a return value
Put "y" in the proc AsyncmessageDealtWith and it will then be called when there is a return value to deal with.
To have the WaitForSingleObject API in it, and it waits UNTIL a response is sent back?
Avoid WaitForSingleObject - it completely blocks the caller thread so will prevent form painting, timer events etc.
Is it possible to create 2 windows with the same title using those API commands you suggested?
Yes - although this would make FindWindow less useful....
-
Mar 28th, 2003, 10:34 AM
#17
I have been having a little problem, and I can't work out why 
I have tried everything, but it just won't seem to work...
If have a public type:
VB Code:
Public Type mtypClient
hWnd As Long
AppName As String
End Type
Then how would I send a message to another window with info about this type?
I used:
VB Code:
SendMessage mlngServerHWND, WMAttachClient, VarPtr(udtClient), LenB(udtClient) / 2
Then on my subclassed server I have:
VB Code:
CopyMemory udtClient, mParam, lParam
This terminated the app...
I even tried using property bags and getting the address and length of a byte array of it's contents and passed them, reconstructed a byte array, but it gave me an error when trying to populate the contents of a property bag 
Woka
-
Mar 28th, 2003, 10:52 AM
#18
Frenzied Member
This terminated the app...
I'm not really suprised - to read memory from *another* process you need to use Readprocessmemory which is more complicated.
The thing is that each process has it's own memory space and the addresses in this are unique to that process. You can conceptualise this as each process being a street and address being the door number. If you give me an address of #42 then if we are on the same street we will be talking about the same address - but if I am in a different street to you I will go to the wrong #42.....
-
Mar 28th, 2003, 10:58 AM
#19
Bugger! 
So how would I pass the handle and appname of my app across to the connection thread???
At the moment I am using MailSlots, but I want to subclass and use API...
Woka
-
Mar 28th, 2003, 11:04 AM
#20
I can't find anything on ReadProcessmemory in AllAPI
-
Mar 28th, 2003, 11:15 AM
#21
Frenzied Member
AllApi kinda runs out of steam round about where Dan Appleman's book does...only the deeply suspicious would make any connection 
Reading a string from another process:
First you need to get a handle to the external process which allows you to read it:
VB Code:
Public Enum ProcessAccessPriviledges
PROCESS_TERMINATE = &H1
PROCESS_CREATE_THREAD = &H2
PROCESS_SET_SESSIONID = &H4
PROCESS_VM_OPERATION = &H8
PROCESS_VM_READ = &H10
PROCESS_VM_WRITE = &H20
PROCESS_DUP_HANDLE = &H40
PROCESS_CREATE_PROCESS = &H80
PROCESS_SET_QUOTA = &H100
PROCESS_SET_INFORMATION = &H200
PROCESS_QUERY_INFORMATION = &H400
PROCESS_SYNCHRONISE = &H100000
PROCESS_ALL_ACCESS = &H100FFF
End Enum
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As ProcessAccessPriviledges, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
'...
hProc = OpenProcess(PROCESS_VM_READ, False, ProcessId)
Then read from that handle for a given string address:
VB Code:
Private Declare Function ReadProcessMemoryBytes Lib "kernel32" Alias "ReadProcessMemory" (ByVal hProcess As Long, ByVal lpBaseAddress As Long, lpBuffer As Byte, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Public Function StringFromOutOfProcessPointer(ByVal hProcess As Long, ByVal lpString As Long, ByVal Length As Long, ByVal Unicode As Boolean) As String
Dim buf() As Byte
Dim lRet As Long
Dim lBytesWritten As Long
Dim sTemp As String
ReDim buf(Length) As Byte
lRet = ReadProcessMemoryBytes(hProcess, lpString, buf(0), Length, lBytesWritten)
If lBytesWritten = 0 And Err.LastDllError = 0 Then
While lBytesWritten = 0 And Length > 0
Length = Length - 1
lRet = ReadProcessMemoryBytes(hProcess, lpString, buf(0), Length, lBytesWritten)
Wend
Else
If Err.LastDllError Then
Debug.Print LastSystemError
End If
End If
If lRet <> 0 Then
If Unicode Then
StringFromOutOfProcessPointer = StrConv(buf, vbFromUnicode)
Else
For lRet = 0 To lBytesWritten
If buf(lRet) = 0 Then
Exit For
End If
sTemp = sTemp & Chr$(buf(lRet))
Next lRet
StringFromOutOfProcessPointer = sTemp
End If
Else
If Err.LastDllError Then
Debug.Print LastSystemError
End If
End If
Alternatively there is a hack (isn't there always)..which relies on the fat that our communication windows were created by ourselves and are not shown therefore you can pass a string between processes by setting the caption of these windows - use GetWindowText/SetWindowText...
VB Code:
Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Declare Function SetWindowText Lib "user32" Alias "SetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String) As Long
Hope this helps,
Duncan
Last edited by MerrionComputin; Mar 28th, 2003 at 11:43 AM.
-
Mar 28th, 2003, 11:34 AM
#22
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|