Results 1 to 22 of 22

Thread: SubClassing a class module...think it involves creating a handle?

  1. #1

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632

    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?

  2. #2
    Frenzied Member MerrionComputin's Avatar
    Join Date
    Apr 2001
    Location
    Dublin, Ireland
    Posts
    1,616
    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...
    ----8<---------------------------------------
    NEW - The .NET printer queue monitor component
    ----8<---------------------------------------
    Now with Examples of use

  3. #3
    Retired VBF Adm1nistrator plenderj's Avatar
    Join Date
    Jan 2001
    Location
    Dublin, Ireland
    Posts
    10,359
    Do you ever do anything the easy way ?
    Microsoft MVP : Visual Developer - Visual Basic [2004-2005]

  4. #4
    Frenzied Member MerrionComputin's Avatar
    Join Date
    Apr 2001
    Location
    Dublin, Ireland
    Posts
    1,616
    Me? or him?
    ----8<---------------------------------------
    NEW - The .NET printer queue monitor component
    ----8<---------------------------------------
    Now with Examples of use

  5. #5

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632
    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

  6. #6

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632
    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:
    1. For lngIndex = 1 To 7
    2.    Set objUsers = New clsUsers
    3.    objUsers.Load
    4. Next lngIndex
    ...in 875 ms, but that is INCLUDING the code:
    VB Code:
    1. Do
    2.    Sleep 100
    3.    strBuffer = MailSlotRead(ClientSlot)
    4. 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

  7. #7

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632
    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

  8. #8
    Frenzied Member KayJay's Avatar
    Join Date
    Jul 2001
    Location
    Chennai
    Posts
    1,849
    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

  9. #9

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632
    Originally posted by KayJay
    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
    Now, now, no need for sarcasm Hahahahahaha
    The only problem with that method is that I've lost the 2 most significant bits to the washing machine god

    Anyways, SendMessage is the way to go as I have just found a fatal floor with MailSlots which I can't fix.
    For the Client to communicate with the connection app I need to use:
    VB Code:
    1. mlngServerSlot = CreateFileNoSecurity(SERVER_SLOT_NAME, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
    But if I already have a client open then this function fails and it returns a -1
    This means that only 1 client can use the connection object at anyone time. This is poo

    Woka

  10. #10
    Frenzied Member MerrionComputin's Avatar
    Join Date
    Apr 2001
    Location
    Dublin, Ireland
    Posts
    1,616
    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.
    ----8<---------------------------------------
    NEW - The .NET printer queue monitor component
    ----8<---------------------------------------
    Now with Examples of use

  11. #11

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632
    Yea, But in my client I have:
    VB Code:
    1. objUsers.Load
    2. 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

  12. #12
    Frenzied Member MerrionComputin's Avatar
    Join Date
    Apr 2001
    Location
    Dublin, Ireland
    Posts
    1,616
    In that case you need SendmessageCallback e.g.:

    VB Code:
    1. Option Explicit
    2.  
    3. 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
    4.  
    5. Public Sub AsyncmessageDealtWith(ByVal TargetWnd As Long, ByVal msg As Long, ByVal lpData As Long, ByVal lRes As Long)
    6.  
    7. '\\ The windoiw (TargetWindow) dealt with the message and send back the answer lRes
    8. MsgBox "Woof return was " & lRes
    9.  
    10. End Sub
    11.  
    12. Public Sub CallAsyncThing()
    13.  
    14. Call SendMessageCallback(hwndtarget, MSG_USER, 0, 0, AddressOf AsyncmessageDealtWith, 100)
    15.  
    16. End Sub

    Then if you have code like...
    VB Code:
    1. 'do x
    2. Call CallAsyncThing()
    3. '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.
    ----8<---------------------------------------
    NEW - The .NET printer queue monitor component
    ----8<---------------------------------------
    Now with Examples of use

  13. #13

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632
    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

  14. #14

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632
    Although, is there anyway I could modify:
    VB Code:
    1. Public Sub CallAsyncThing()
    2.  
    3. Call SendMessageCallback(hwndtarget, MSG_USER, 0, 0, AddressOf AsyncmessageDealtWith, 100)
    4.  
    5. End Sub
    To have the WaitForSingleObject API in it, and it waits UNTIL a response is sent back?

    Woka

  15. #15

  16. #16
    Frenzied Member MerrionComputin's Avatar
    Join Date
    Apr 2001
    Location
    Dublin, Ireland
    Posts
    1,616
    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....
    ----8<---------------------------------------
    NEW - The .NET printer queue monitor component
    ----8<---------------------------------------
    Now with Examples of use

  17. #17

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632
    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:
    1. Public Type mtypClient
    2.     hWnd   As Long
    3.     AppName   As String
    4. End Type
    Then how would I send a message to another window with info about this type?
    I used:
    VB Code:
    1. SendMessage mlngServerHWND, WMAttachClient, VarPtr(udtClient), LenB(udtClient) / 2
    Then on my subclassed server I have:
    VB Code:
    1. 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

  18. #18
    Frenzied Member MerrionComputin's Avatar
    Join Date
    Apr 2001
    Location
    Dublin, Ireland
    Posts
    1,616
    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.....
    ----8<---------------------------------------
    NEW - The .NET printer queue monitor component
    ----8<---------------------------------------
    Now with Examples of use

  19. #19

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632
    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

  20. #20

  21. #21
    Frenzied Member MerrionComputin's Avatar
    Join Date
    Apr 2001
    Location
    Dublin, Ireland
    Posts
    1,616
    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:
    1. Public Enum ProcessAccessPriviledges
    2.      PROCESS_TERMINATE = &H1
    3.      PROCESS_CREATE_THREAD = &H2
    4.      PROCESS_SET_SESSIONID = &H4
    5.      PROCESS_VM_OPERATION = &H8
    6.      PROCESS_VM_READ = &H10
    7.      PROCESS_VM_WRITE = &H20
    8.      PROCESS_DUP_HANDLE = &H40
    9.      PROCESS_CREATE_PROCESS = &H80
    10.      PROCESS_SET_QUOTA = &H100
    11.      PROCESS_SET_INFORMATION = &H200
    12.      PROCESS_QUERY_INFORMATION = &H400
    13.      PROCESS_SYNCHRONISE = &H100000
    14.      PROCESS_ALL_ACCESS = &H100FFF
    15. End Enum
    16. Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As ProcessAccessPriviledges, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
    17.  
    18. '...
    19. hProc = OpenProcess(PROCESS_VM_READ, False, ProcessId)

    Then read from that handle for a given string address:
    VB Code:
    1. 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
    2.  
    3. Public Function StringFromOutOfProcessPointer(ByVal hProcess As Long, ByVal lpString As Long, ByVal Length As Long, ByVal Unicode As Boolean) As String
    4.  
    5. Dim buf() As Byte
    6. Dim lRet As Long
    7. Dim lBytesWritten As Long
    8. Dim sTemp As String
    9.  
    10. ReDim buf(Length) As Byte
    11.  
    12. lRet = ReadProcessMemoryBytes(hProcess, lpString, buf(0), Length, lBytesWritten)
    13. If lBytesWritten = 0 And Err.LastDllError = 0 Then
    14.     While lBytesWritten = 0 And Length > 0
    15.         Length = Length - 1
    16.         lRet = ReadProcessMemoryBytes(hProcess, lpString, buf(0), Length, lBytesWritten)
    17.     Wend
    18. Else
    19.     If Err.LastDllError Then
    20.         Debug.Print LastSystemError
    21.     End If
    22. End If
    23. If lRet <> 0 Then
    24.     If Unicode Then
    25.         StringFromOutOfProcessPointer = StrConv(buf, vbFromUnicode)
    26.     Else
    27.         For lRet = 0 To lBytesWritten
    28.             If buf(lRet) = 0 Then
    29.                 Exit For
    30.             End If
    31.             sTemp = sTemp & Chr$(buf(lRet))
    32.         Next lRet
    33.         StringFromOutOfProcessPointer = sTemp
    34.     End If
    35. Else
    36.     If Err.LastDllError Then
    37.         Debug.Print LastSystemError
    38.     End If
    39. 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:
    1. Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
    2. 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.
    ----8<---------------------------------------
    NEW - The .NET printer queue monitor component
    ----8<---------------------------------------
    Now with Examples of use

  22. #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
  •  



Click Here to Expand Forum to Full Width