Results 1 to 11 of 11

Thread: When Subclassing what is an error 5?

  1. #1

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

    When Subclassing what is an error 5?

    I have this:
    VB Code:
    1. SetLastError 0
    2.         .oldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf WndProc)
    3.         MsgBox GetLastError
    I have no idea why it doesn't work, but the error returned is number 5?! *sigh*
    Anyone got any tips?

  2. #2
    Frenzied Member MerrionComputin's Avatar
    Join Date
    Apr 2001
    Location
    Dublin, Ireland
    Posts
    1,616
    Purpose
    When using the API, Visual basic does not throw exceptions in the usual manner. Instead it is up to the programmer to check the value of the intrinsic Err.LastDLLError after each call to the API to see if an error has occured.
    However, this number should be converted into a string message to make it easier to understand what went wrong.

    VB Code:
    1. '\ API Error decoding
    2. Private Declare Function FormatMessage Lib "kernel32" Alias "FormatMessageA" (ByVal dwFlags As Long, lpSource As Any, ByVal dwMessageId As Long, ByVal dwLanguageId As Long, ByVal lpBuffer As String, ByVal nSize As Long, Arguments As Long) As Long
    3.  
    4.  
    5. '\ -- [ LastSystemError ]----------------------------------
    6. '\ Returns the message from the system which describes the
    7. '\ last dll error to occur, as
    8. '\ held in Err.LastDllError. This function should be
    9. '\ called as soon after the API call
    10. '\ which might have errored, as this member can be reset
    11. '\ to zero by subsequent API calls.
    12. '\ --------------------------------------------------------
    13. Public Function LastSystemError() As String
    14.  
    15. Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000
    16. Dim sError As String * 500 '\ Preinitilise a string buffer to put any error message into
    17. Dim lErrNum As Long
    18. Dim lErrMsg As Long
    19.  
    20. lErrNum = Err.LastDllError
    21.  
    22. lErrMsg = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, ByVal 0&, lErrNum, 0, sError, Len(sError), 0)
    23.  
    24. LastSystemError = Trim(sError)
    25.  
    26. End Function
    ----8<---------------------------------------
    NEW - The .NET printer queue monitor component
    ----8<---------------------------------------
    Now with Examples of use

  3. #3

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632
    Yea, I did try that, cut and paste code from AllAPI.Net, but the format command crashed my app
    Yours seems to work for some reason...

    My error is "Access Denied"...WHY?! Trying to subclass a window in from one project, in another...Access Denied???!!!

    You're a subclassing API expert...any clue?

    Woka

  4. #4
    Frenzied Member MerrionComputin's Avatar
    Join Date
    Apr 2001
    Location
    Dublin, Ireland
    Posts
    1,616
    You can't subclass a window that is in a different process than you are in.

    Every process has it's own reserved memory and it addresses that memory using local pointers - kinda like door numbers in a street. These addresses are meaningless outside of the current process so if you pass one to another process and say "use this as your windproc" it will look at that address relative to it's memory and fail to find a Wndproc there.

    The only way to subclass somebody else's program is to make that program load a dll that has your subclassing code in it and then (because the dll will be loaded in it's address space) you can use SetWindowLong as normal.

    However the phrase make that program load a dll that has your subclassing code in it hides a world of grey hair and blue screens of death.
    ----8<---------------------------------------
    NEW - The .NET printer queue monitor component
    ----8<---------------------------------------
    Now with Examples of use

  5. #5
    Fanatic Member crispin's Avatar
    Join Date
    Aug 2000
    Location
    2 clicks west of a Quirkafleeg...Cornwall, England
    Posts
    754
    The window you're trying to subclass - do you own it? if you dont.....then you cant.
    Crispin
    VB6 ENT SP5
    VB.NET
    W2K ADV SVR SP3
    WWW.BLOCKSOFT.CO.UK

    [Microsoft Basic: 1976-2001, RIP]

  6. #6

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632
    Right OK, undertand now. It would have worked if I had used a DLL instead of EXE...d'oh!
    Ok, since I know the parent windows handle in the activeX EXE, from the client when the picture box resizes, I can just call a Refresh function in the object, and that can use API, to get rect size and move window...anyway, that way work...not exactally what I wanted but hey, beggers can't be choosers

    Cheers for your help...

    Woka

  7. #7
    Frenzied Member MerrionComputin's Avatar
    Join Date
    Apr 2001
    Location
    Dublin, Ireland
    Posts
    1,616
    If you wrote both ActiveX exes you can communicate between them by posting registered messages as per this article
    ----8<---------------------------------------
    NEW - The .NET printer queue monitor component
    ----8<---------------------------------------
    Now with Examples of use

  8. #8

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632
    Yea, that was my next move...So I could theorectically have a WM that looked like:

    NEW_SEARCH SELECT * FROM TABLE ORDER BY PK_ID

    Then when I trap is I check to see if NEW_SEARCH is at the start of the message, and if it is then I strip out the select statement and execute it...?
    Is that correct?

    Woka

    Cheers for the help

  9. #9
    Frenzied Member MerrionComputin's Avatar
    Join Date
    Apr 2001
    Location
    Dublin, Ireland
    Posts
    1,616
    How I would do this:

    Application 1 uses RegisterWindowsMessage to register a new message "NEW_SEARCH"

    Application 2 registers a new message called "NEW_SEARCH_RESPONSE"

    When a new search is performed application #1 uses GlobalAddAtom to add the string to the global atom table and stores it's atom handle in a variable.

    Application #1 sends application#2 a "NEW_SEARCH" message with it's reply to hwnd in the lParam and the global atom identifier in the wParam.

    Application #2 gets that message and reads the search parameter with GlobalGetAtom and sends back a "NEW_SERACH_RESPONSE" message with that same atom id in the wParam

    Application #1 removes the atom from the atom table

    This way you don't have to worry about allocating memory that both processes can read and controlling access to it etc.

    HTH,
    Duncan
    ----8<---------------------------------------
    NEW - The .NET printer queue monitor component
    ----8<---------------------------------------
    Now with Examples of use

  10. #10

  11. #11
    Frenzied Member MerrionComputin's Avatar
    Join Date
    Apr 2001
    Location
    Dublin, Ireland
    Posts
    1,616
    In a module shared by both projects add the following code:

    VB Code:
    1. Declare Function RegisterWindowMessage Lib "user32" Alias "RegisterWindowMessageA" (ByVal lpString As String) As Long
    2.  
    3. Public Function WM_NEW_SEARCH() As Long
    4.  
    5.   WM_NEW_SEARCH = RegisterWindowMessage("NEW_SEARCH")
    6.  
    7. End Function
    8.  
    9. Public Function WM_NEW_SEARCH_RESPONSE() As Long
    10.  
    11.   WM_NEW_SEARCH = RegisterWindowMessage("NEW_SEARCH_RESPONSE")
    12.  
    13. End Function

    Then in the application that does the searching stuff (hereafter the app#1):
    VB Code:
    1. Declare Function GlobalAddAtom Lib "kernel32" Alias "GlobalAddAtomA" (ByVal lpString As String) As Integer
    2.  
    3. Declare Function GlobalDeleteAtom Lib "kernel32" Alias "GlobalDeleteAtom" (ByVal nAtom As Integer) As Integer
    4.  
    5. Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    6.  
    7. 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
    8.  
    9.  
    10. Public Function myWndProc(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    11.  
    12. If msg = WM_NEW_SEARCH_RESPONSE() Then
    13.    '\\ We got a response back - delete the global atom
    14.    Call GlobalDeleteAtom(wParam)
    15. Else
    16.   '\\ Pass this message on to the previous wndproc
    17.    myWndProc = CallWindowproc(mlpPrevWndProc, hwnd,wMsg,wParam, lParam)
    18. End If
    19.  
    20. End Function
    21.  
    22. Public Sub NewSearch(ByVal SearchString As String)
    23.  
    24. Dim hAtom As Integer
    25.  
    26. hAtom = GlobalAddAtom(SearchString)
    27. '\\ Post this to our other application
    28. Call PostMessage(hwndClient , WM_NEW_SEARCH(), hAtom, hwndReturn)
    29.  
    30. End Sub

    And in APP#2
    VB Code:
    1. Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    2.  
    3. 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
    4.  
    5.  
    6. Declare Function GlobalGetAtomName Lib "kernel32" Alias "GlobalGetAtomNameA" (ByVal nAtom As Integer, ByVal lpBuffer As String, ByVal nSize As Long) As Long
    7.  
    8. Public Function myWndProc(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    9.  
    10. Dim sSearch As String, lRet As Long
    11.  
    12. If msg = WM_NEW_SEARCH() Then
    13.    '\\ We got a new search..
    14.    '\\ 1 - read the global atom
    15.     sSearch = String$(255,0)
    16.     lRet = GlobalGetAtomName(wParam, sSearch, Len(sSearch))
    17.     If lRet > 0 Then
    18.       sSearch = Left$(sSearch)
    19.       '\\ Do whatever action with the search strinmg here....
    20.  
    21.    End If
    22.    '\\ 2 - Acknowledge it's reciept...
    23.    Call PostMessage(lParam, WM_NEW_SEARCH_RESPONSE() ,wParam, 0)
    24. Else
    25.   '\\ Pass this message on to the previous wndproc
    26.    myWndProc = CallWindowproc(mlpPrevWndProc, hwnd,wMsg,wParam, lParam)
    27. End If
    28.  
    29. End Function

    You need to use FindWindow to get the hwndClient which is the window handle subclassed in app#2, and hwndReturn is the window handle of the window subclassed by myWndProc in app#1

    Hope this helps,
    Duncan
    ----8<---------------------------------------
    NEW - The .NET printer queue monitor component
    ----8<---------------------------------------
    Now with Examples of use

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