Jump to content

Recommended Posts

Could not find any example how I actually get the return  value of the _SendMessage call...

I've got (testing) simple message handler which would just put integer to the Message result value depending on the situation.
 

procedure TWindow.WmStatus(var Msg: TMessage);
var
  LResult: NativeInt;
begin
  LResult := 1;

  if Assigned(FObjectReference) then
    if FObjectReference.Status = mpFinished then
      LResult := 2;

  Msg.Result := LResult;
end;



How I get that Result value at the AutoIT side?

-Tee-

Edited by Tee
Link to post
Share on other sites

You should post code like that.

What's this language (sry I can't reconize that, I still have lot to learn). Edit: should be Delphi/Lazarus ?

Where your procedure is called ?

Anyway, according to msdn :

LRESULT CALLBACK WindowProc(
  _In_ HWND   hwnd,
  _In_ UINT   uMsg,
  _In_ WPARAM wParam,
  _In_ LPARAM lParam
);

// synchronous: call the WindowProc and 'halt' until return
LRESULT SendMessage(
  HWND   hWnd,
  UINT   Msg,
  WPARAM wParam,
  LPARAM lParam
);

LRESULT LRESULT DefWindowProcA(
  HWND   hWnd,
  UINT   Msg,
  WPARAM wParam,
  LPARAM lParam
);

If you're not returning the LRESULT inside your window proc there's no (simple) way you can get the result, also always return at end the default WndProc (DefWindowProcA) that handle basic messages needed to interact with the window (as destroy, change data, etc), or maybe your langage automatically handle that, idk.

From autoit pov _SendMessage will return the LRESULT when $iReturn is set to 0 (default value)

Edited by 636C65616E
Link to post
Share on other sites

I've done some tests with Lazarus, but i'm not familiar enought with Pascal, anyway i guess you need to override something like that (Delphi):

procedure TWindow.WndProc(var Msg: TMessage);
begin
  // do your stuff
  Inherited WndProc(Msg);
end;

Short example in pure AutoIt:

One programm to create a window with a custom WindowProc handling a custom 0x401 msg :

#cs
FROM MSDN:
Application-Defined Messages
An application can create messages to be used by its own windows or to communicate with windows in other processes.
If an application creates its own messages, the window procedure that receives them must interpret the messages and provide appropriate processing.
Message-identifier values are used as follows:
- The system reserves message-identifier values in the range 0x0000 through 0x03FF (the value of WM_USER  – 1) for system-defined messages.
  Applications cannot use these values for private messages.
- Values in the range 0x0400 (the value of WM_USER) through 0x7FFF are available for message identifiers for private window classes.
- If your application is marked version 4.0, you can use message-identifier values in the range 0x8000 (WM_APP) through 0xBFFF for private messages.
- The system returns a message identifier in the range 0xC000 through 0xFFFF when an application calls the RegisterWindowMessage function to register a message.
  The message identifier returned by this function is guaranteed to be unique throughout the system.
  Use of this function prevents conflicts that can arise if other applications use the same message identifier for different purposes.
#ce

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <StaticConstants.au3>
#include <WinAPI.au3>

$form  = GUICreate('TestWnd', 174, 102, -1, -1,  BitOR($WS_CAPTION, $WS_SYSMENU))
$label = GUICtrlCreateLabel('received: ', 32, 24, 108, 49, BitOR($SS_CENTER,$SS_CENTERIMAGE))
GUISetState(@SW_SHOW)

; to handle native AutoIt stuff
$oldproc = _WinAPI_GetWindowLong($form, $GWL_WNDPROC)

func WndProc($hwnd, $uMsg, $wParam, $lParam)
    static $count = 0
    switch $uMsg
        case 0x401
            $count += 1
            GUICtrlSetData($label, 'received: ' & $count)
            return 0x452
    endswitch
    ; ConsoleWrite('msg = ' & ptr($uMsg) & @CRLF)
    ; return _WinAPI_DefWindowProc($hwnd, $uMsg, $wParam, $lParam)
    local $res = DllCallAddress('LRESULT', $oldproc, 'HWND', $hwnd, 'UINT', $uMsg, 'WPARAM', $wParam, 'LPARAM', $lParam)
    if @ERROR <> 0 then
        ConsoleWrite('ERROR: ' & @ERROR & @CRLF)
        return 0
    endif
    return $res[0]
endfunc

$WndProc = DllCallbackRegister(WndProc, 'LRESULT', 'HWND;UINT;WPARAM;LPARAM;')
_WinAPI_SetWindowLong($form, $GWL_WNDPROC, DllCallbackGetPtr($WndProc))

while 1
    switch GUIGetMsg()
        case $GUI_EVENT_CLOSE
            ExitLoop
    endswitch
wend

GUIDelete($form)
DllCallbackFree($WndProc)

One program to interact with it (notice that sending 0x10 will close the 1st one as it is the WM_CLOSE), here the custom msg is 0x401:

#include <SendMessage.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>

$hwnd = WinWait('TestWnd', '', 1)
if ($hwnd = 0) then
    MsgBox(0x10, 'Error', 'Cant find the TestWnd')
    Exit
endif

$form  = GUICreate('SENDER', 196, 128, -1, -1, BitOR($WS_CAPTION, $WS_SYSMENU))
$send  = GUICtrlCreateButton('SEND', 16, 46, 161, 33)
$input = GUICtrlCreateInput('0x401', 50, 17, 126, 21)
$disp  = GUICtrlCreateLabel('-', 18, 94, 157, 17, $SS_CENTERIMAGE)
GUICtrlCreateLabel("Msg:", 17, 16, 35, 22, $SS_CENTERIMAGE)
GUISetBkColor(0xB9D1EA)
GUISetState(@SW_SHOW)

while 1
    switch GUIGetMsg()
        case $GUI_EVENT_CLOSE
            Exit
        case $send
            local $msg = Number(GUICtrlRead($input),1)
            local $res = _SendMessage($hwnd, $msg)
            GUICtrlSetData($disp, '[0x' & hex($msg,4) & '] ' & ptr($res))
    endswitch
wend

For some obscure reason selecting the window also post a WM_USER message, that's why I use 0x401 instead of simply 0x400

Edited by 636C65616E
Link to post
Share on other sites
Posted (edited)

I think I was not very clear what I am looking for.

I have message handler like in first message if shown. It should work. (I could use L/WPAram also, if can pass the value in those also.

I am planning to do in AutoIT because one of our application window is hard to detect when it is finished. So I would sen message in the loop like

So something Like this would be needed in AutoIT side, just can't find example on getting the result...

Local Const $WM_USER_CUSTOM_STATUS = $WM_USER + 666

while $LResult <> 2
  _SendMessage($hWnd, $WM_USER_CUSTOM_STATUS...)
  If $LResult <> 2 Then
    Sleep(100)
  EndIf
EEnd

When the Delphi coded message handler returns 2 we would know that that window is done it's work, and we know that we can start to interact with it.

Now we kind of hack in place I don'ät like (We disable Toolbar until it's finished working, and enable it then), and AutoIT script will poll the status of the component. That works well, but it'll cause visual flickering of the toolbar, and that is bit ugly.

AutoIT help on _SendMEssage is bit hard for me to decode:

_SendMessage ( $hWnd, $iMsg [, $wParam = 0 [, $lParam = 0 [, $iReturn = 0 [, $wParamType = "wparam" [, $lParamType = "lparam" [, $sReturnType = "lresult"]]]]]] )

I think I need (As someone mentioned)   $iReturn as 0, and should get return value from the $sReturnType parameter. Just confused about what  $sReturnType = "lresult" means?? And reference to the "[optional] See DllCall in Related" 

If last param can be just a "Integer" variable then I think I can get this to work... (I just don't personally have test setup and that's why I did not just try, because coworker has to do the testing and need to have some idea that it could work first. Don't want to bother him in vain.)

-Tee-

Edited by Tee
Link to post
Share on other sites

Well you never assign the return value, so ... yeah you will have some struggle. The data is not transferred via a magic object working around in background ^^

$lResult = _SendMessage($hWnd, $WM_USER_CUSTOM_STATUS)

no more complicated than that

Futhermore don't forget to include the appropriate library and to define the WM_USER

#include <SendMessage.au3>
; $WM_USER = 0x400 ; <<< this is defined inside WindowsConstants.au3
#include <WindowsConstants.au3>

EDIT:

11 hours ago, Tee said:

If last param can be just a "Integer" variable then I think I can get this to work... (I just don't personally have test setup and that's why I did not just try, because coworker has to do the testing and need to have some idea that it could work first. Don't want to bother him in vain.)

Installing AutoIt and running a script is a matter of few minutes ...

Also the AutoIt _SendMessage prototype is exactly the same as the one from Microsoft with default value 0 for wParam and lParam:

$lResult = _SendMessage($hWnd, $uMsg, $wParam = 0, $lParam = 0)

Don't get distracted by the other parameters, they are made to mimic the real SendMessage format by default (but they give you the option to change it).

Edited by 636C65616E
Link to post
Share on other sites
On 8/13/2021 at 10:33 AM, 636C65616E said:

Well you never assign the return value, so ... yeah you will have some struggle. The data is not transferred via a magic object working around in background ^^

$lResult = _SendMessage($hWnd, $WM_USER_CUSTOM_STATUS)

 

Result and Return are  different things, right?

in my pseudocode 

; _SendMessage ( $hWnd, $iMsg [, $wParam = 0 [, $lParam = 0 [, $iReturn = 0 [, $wParamType = "wparam" [, $lParamType = "lparam" [, $sReturnType = "lresult"]]]]]] )

_SendMessage($hWnd, $WM_USER_CUSTOM_STATUS, 0, 0, $lResult, 0, 0, 0)

So that should work, maybe? I have really hard time to understand the documentation,  What are the last parameters, and what to put in them,, very last Return type, shoudl it affect to the Return or Result value?

Of cource I shoudl do something like

$LReturn = _SendMessage($hWnd, $WM_USER_CUSTOM_STATUS, 0, 0, $lResult)

And handle $LReturn and $lResult values. But I just can't find any confirmation that if I assign the Result value of the Windows message in Delphi side, I can receive it in AutoIT at the Result parameter

or, Now that I read that more I have feelinf that it shopudl be:

; _SendMessage ( $hWnd, $iMsg [, $wParam = 0 [, $lParam = 0 [, $iReturn = 0 [, $wParamType = "wparam" [, $lParamType = "lparam" [, $sReturnType = "lresult"]]]]]] )

$LReturnTypoe = 0 ;  0 - Return value from DLL call
$lResult = _SendMessage($hWnd, $WM_USER_CUSTOM_STATUS, 0, 0, $LReturnTypoe)

And Change the Delphi sire that I could get the Return value I want, not the Result bit of the Windows message, have to ask around at Delphi side also.

Link to post
Share on other sites

well i linked you the official msdn documentation ...

there's no lReturn, i also send you the exact prototype of the function :

On 8/13/2021 at 9:33 AM, 636C65616E said:
$lResult = _SendMessage($hWnd, $uMsg, $wParam = 0, $lParam = 0)

just use that, the function return the lResult. the 'iReturn' in the _sendmessage (i you read the doc it could be clear) is a flag indicating thr function which data it should return, with default parameter 0 it returns the lResult, so once again use the prototype i posted just before and read the msdn doc

Edited by 636C65616E
Link to post
Share on other sites
8 hours ago, Tee said:

Documentation has little weird syntax (to me).

It's C/C++ syntax, so yeah if you only code in Delphi/Pascal it may be a bit weird, anyway that's pretty standard (at least all window API is in cpp so, get used to it if you want to use it ;))

Link to post
Share on other sites

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
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...