I have this:
I have no idea why it doesn't work, but the error returned is number 5?! *sigh*VB Code:
SetLastError 0 .oldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf WndProc) MsgBox GetLastError
Anyone got any tips?
Printable View
I have this:
I have no idea why it doesn't work, but the error returned is number 5?! *sigh*VB Code:
SetLastError 0 .oldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf WndProc) MsgBox GetLastError
Anyone got any tips?
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:
'\ API Error decoding 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 '\ -- [ LastSystemError ]---------------------------------- '\ Returns the message from the system which describes the '\ last dll error to occur, as '\ held in Err.LastDllError. This function should be '\ called as soon after the API call '\ which might have errored, as this member can be reset '\ to zero by subsequent API calls. '\ -------------------------------------------------------- Public Function LastSystemError() As String Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000 Dim sError As String * 500 '\ Preinitilise a string buffer to put any error message into Dim lErrNum As Long Dim lErrMsg As Long lErrNum = Err.LastDllError lErrMsg = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, ByVal 0&, lErrNum, 0, sError, Len(sError), 0) LastSystemError = Trim(sError) End Function
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???!!! :mad:
You're a subclassing API expert...any clue?
Woka
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.
The window you're trying to subclass - do you own it? if you dont.....then you cant.
Right OK, undertand now. It would have worked if I had used a DLL instead of EXE...d'oh! :D
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 :D
Cheers for your help...
Woka
If you wrote both ActiveX exes you can communicate between them by posting registered messages as per this article
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 :D
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
Think I undertsnad that...:confused:
In a module shared by both projects add the following code:
VB Code:
Declare Function RegisterWindowMessage Lib "user32" Alias "RegisterWindowMessageA" (ByVal lpString As String) As Long Public Function WM_NEW_SEARCH() As Long WM_NEW_SEARCH = RegisterWindowMessage("NEW_SEARCH") End Function Public Function WM_NEW_SEARCH_RESPONSE() As Long WM_NEW_SEARCH = RegisterWindowMessage("NEW_SEARCH_RESPONSE") End Function
Then in the application that does the searching stuff (hereafter the app#1):
VB Code:
Declare Function GlobalAddAtom Lib "kernel32" Alias "GlobalAddAtomA" (ByVal lpString As String) As Integer Declare Function GlobalDeleteAtom Lib "kernel32" Alias "GlobalDeleteAtom" (ByVal nAtom As Integer) As Integer 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 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 Public Function myWndProc(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long If msg = WM_NEW_SEARCH_RESPONSE() Then '\\ We got a response back - delete the global atom Call GlobalDeleteAtom(wParam) Else '\\ Pass this message on to the previous wndproc myWndProc = CallWindowproc(mlpPrevWndProc, hwnd,wMsg,wParam, lParam) End If End Function Public Sub NewSearch(ByVal SearchString As String) Dim hAtom As Integer hAtom = GlobalAddAtom(SearchString) '\\ Post this to our other application Call PostMessage(hwndClient , WM_NEW_SEARCH(), hAtom, hwndReturn) End Sub
And in APP#2
VB Code:
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 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 Declare Function GlobalGetAtomName Lib "kernel32" Alias "GlobalGetAtomNameA" (ByVal nAtom As Integer, ByVal lpBuffer As String, ByVal nSize As Long) As Long Public Function myWndProc(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Dim sSearch As String, lRet As Long If msg = WM_NEW_SEARCH() Then '\\ We got a new search.. '\\ 1 - read the global atom sSearch = String$(255,0) lRet = GlobalGetAtomName(wParam, sSearch, Len(sSearch)) If lRet > 0 Then sSearch = Left$(sSearch) '\\ Do whatever action with the search strinmg here.... End If '\\ 2 - Acknowledge it's reciept... Call PostMessage(lParam, WM_NEW_SEARCH_RESPONSE() ,wParam, 0) Else '\\ Pass this message on to the previous wndproc myWndProc = CallWindowproc(mlpPrevWndProc, hwnd,wMsg,wParam, lParam) End If 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