Jump to content

Recommended Posts

Posted (edited)

I made a hook to an application and this application crashes for some reason. I do not understand why. Cannot find what am I doing wrong.

Declaration.

Global Const $tagCWPRETSTRUCT = "lresult lResult;lparam lParam;wparam wParam;uint message;hwnd hwnd"
Global Const $WM_MEASUREITEM = 0x002C
Global $hHook

Here i registered a hook.

MessageCaptured = 0
$MyNULL = 0
$hStub_GetMenuTextProc = DllCallbackRegister("_GetMenuTextProc", "lresult", "int;wparam;lparam")
$hmod = _WinAPI_GetModuleHandle(0)
$hHook = _WinAPI_SetWindowsHookEx($WH_CALLWNDPROCRET, DllCallbackGetPtr($hStub_GetMenuTextProc), $hmod, _WinAPI_GetWindowThreadProcessId(WinGetHandle($WT_Main), $MyNULL))

Callback and freeing.

Func _GetMenuTextProc($nCode, $wParam, $lParam)
    Local $tRETSTRUCT
    $tRETSTRUCT = DllStructCreate($tagCWPRETSTRUCT, $lParam)
    If $nCode < 0 Then
        Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    EndIf

    If DllStructGetData($tRETSTRUCT, "message") = $WM_MEASUREITEM Then
        $MessageCaptured = 1
    EndIf

    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
EndFunc   ;==>_GetMenuTextProc

Func OnAutoItExit()
    _WinAPI_UnhookWindowsHookEx($hHook)
    DllCallbackFree($hStub_GetMenuTextProc)
EndFunc   ;==>OnAutoItExit
Edited by Amate
Posted (edited)

Is the thread of the $WT_Main window belongs to a different process, other than yours? If so, the hook procedure must reside in a DLL file. Also, the structure is not correct, it should be:

Global Const $tagCWPRETSTRUCT = "int_ptr lResult;int_ptr lParam;uint_ptr wParam;uint message;hwnd hwnd"

You could check if the dll struct is correct by inspecting the @error value or using DllStructGetSize(). Refer to this topic about the hooking process, just scroll down to the accepted solution. You can ignore the shared data segment as it's not a system-wide procedure, nonetheless, the hook procedure must reside in a DLL (if I'm not wrong)

Edited by Authenticity
Posted

Is the thread of the $WT_Main window belongs to a different process, other than yours?

Yes, That is right.

If so, the hook procedure must reside in a DLL file.

That is not the only solution. It is enough that all the handles are in shared section. I have no idea how to do it with AutoIT. Please advice.

Also, the structure is not correct, it should be:

Global Const $tagCWPRETSTRUCT = "int_ptr lResult;int_ptr lParam;uint_ptr wParam;uint message;hwnd hwnd"

You could check if the dll struct is correct by inspecting the @error value or using DllStructGetSize().

Thank you. I've corrected my code. But this is not the reason why $WT_Main application crashes.

Refer to this topic about the hooking process, just scroll down to the accepted solution. You can ignore the shared data segment as it's not a system-wide procedure, nonetheless, the hook procedure must reside in a DLL (if I'm not wrong)

I cannot view the solution. I cannot use trial period because they demand credit card and do not accept my Visa Electron. Please copy\paste the solution here.
Posted

I reviewed the solution.

How can I make DLL with AutoIT? How can I manage shared memory with AutoIT?

Please advice.

Is there any way I could perform my task with AutoIT only?

My task is as follows. I need to get main menu item names from Delphi written application. Main menu control items set as owner drawn. So I need to intercept WM_MEASUREITEM message on return from owner so I can get long pointer to MEASUREITEMSTRUCT.

/----------
// Main.cpp
//----------
#include <windows.h>
#include <iostream.h>
#include <stdlib.h>
#include <conio.h>

bool setHook(DWORD threadId);
bool removeHook();

void main(int argc,char* argv[])
{
   if(setHook(0)) {
      cout<<"Press Enter to quit"<<endl;
      _getch();
      cout<<removeHook()<<endl;
   }  
}

//----------
// Hook.dll
//----------

// Cannot use WH_GETMESSAGE, because WM_NCPAINT is *sent*, but not *posted*.

#include <windows.h>

#pragma data_seg(".shared")
HHOOK hHook=0;
#pragma data_seg()
#pragma comment(linker,"/SECTION:.shared,RWS")

HINSTANCE hDll;

void onNCPaint(CWPRETSTRUCT& msg)
{
  // Do whatever you want.
}


LRESULT CALLBACK hookProc(int code,WPARAM wParam,LPARAM lParam)
{
   if(code==HC_ACTION) {
      CWPRETSTRUCT* msg=(CWPRETSTRUCT*)(lParam);
      if(msg->message==WM_NCPAINT) {
         onNCPaint(*msg);
      }
   }
   return CallNextHookEx(hHook,code,wParam,lParam);
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID)
{
   if(fdwReason==DLL_PROCESS_ATTACH)
      hDll=hinstDLL;
   return TRUE;
}

_declspec(dllexport) bool setHook(DWORD threadId)
{
   if(hHook==0)
      hHook=SetWindowsHookEx(WH_CALLWNDPROCRET,hookProc,hDll,threadId);
   return hHook!=0;
}

_declspec(dllexport) bool removeHook()
{
   bool r=true;
   if(hHook) {
      r=UnhookWindowsHookEx(hHook);
      hHook=0;
   }
   return r;
}
Posted

Currently, you can't write dlls in AutoIt (and maybe not so currently). You can use the free ones though, including BloodShed, Code::Blocks, or VS2008 or VS2005 the express edition. Do you want to intercept the message to be able to get the data (string) because it's an owner-drawn and otherwise you can't?

Posted

Do you want to intercept the message to be able to get the data (string) because it's an owner-drawn and otherwise you can't?

Seems I cannot do it bacause the structure contains mainly size of the owner drawn item but not the string, but anyway i can get itemID and custom data from itemData field and this allows me to identify the menu item unambiguously. I need this bacause for some reason the menu items may be ordered different ways on different computers so i cannot use zero position id and be sure I execute the same menu item on different computers. My current code for menu follows.

$hMenu = _GUICtrlMenu_GetMenu(WinGetHandle($WT_Main))
$hDoc = _GUICtrlMenu_GetItemSubMenu($hMenu, $MM_Doc)
$hCash = _GUICtrlMenu_GetItemSubMenu($hDoc, $MM_Cash)

_GUICtrlMenu_SetItemText($hMenu, $MM_Doc, "Doc")
_GUICtrlMenu_SetItemText($hDoc, $MM_Cash, "Cash")
_GUICtrlMenu_SetItemText($hCash, $MM_Credit, "Credit")

WinMenuSelectItem($WT_Main, "", "Doc", "Cash", "Credit")

This code works in different ways on different computers because it uses zero bazed index ($MM_Credit). I need to make it work the same way on any computer.

Posted

You can get the menu and sub-menus items and items ids into a two-dimensional array and use the ID instead, assuming the items strings don't change.

#include <GUIMenu.au3>

Local $hWnd = WinGetHandle("")
Local $hMenu = _GUICtrlMenu_GetMenu($hWnd)
Local $hSubMenu

For $i = 0 To _GUICtrlMenu_GetItemCount($hMenu)-1
    
    ConsoleWrite(_GUICtrlMenu_GetItemText($hMenu, $i) & @CRLF)
    $hSubMenu = _GUICtrlMenu_GetItemSubMenu($hMenu, $i)
    
    For $j = 0 To _GUICtrlMenu_GetItemCount($hSubMenu)-1
        ConsoleWrite(@TAB &  _GUICtrlMenu_GetItemText($hSubMenu, $j) & " " & _GUICtrlMenu_GetItemID($hSubMenu, $j) & @CRLF)
    Next
Next
Posted

As I mentioned above this is owner drawn menu, so _GUICtrlMenu_GetItemText returns "". That is the reason I must name menu items myself to select menu item. Anyway _GUICtrlMenu_GetItemID returns valid ID so I'll try using it. Thank you for you time.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...