Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

[Solved] How to send an array with SendMessage


  • Please log in to reply
18 replies to this topic
kapege.de
  • Members
  • 192 posts
  • Last active: Jan 16 2012 12:34 PM
  • Joined: 07 Feb 2005
I've to send a message 0x404 (Statusbar "SB_SetParts").

After trying this AHK crashes badly:
SendMessage, 0x404, 3, "10,20,30",, ahk_id %BarHWND%
The SB_SETPARTS is as LPARAM an array expecting. How can I send one?

This wont work either:
array1 = 1
array2 = 2
array3 = 3
SendMessage, 0x404, 3, array,, ahk_id %BarHWND%
Who has an idea?
Peter

Wisenheiming for beginners: KaPeGe (German only, sorry)

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
The third parameter must be a 32-bit integer. If sending 3 separate messages fails, how about putting the three binary numbers in a variable and sending its address?

shimanov
  • Members
  • 610 posts
  • Last active: Jul 18 2006 08:35 PM
  • Joined: 25 Sep 2005
Try the following:

It uses Chris's Status Bar example with his InsertInteger function.

Gui, +Resize
Gui, Add, Edit, x5 y5 w300 h20 vMyEdit, This is the text to display in the bar.
Gui, Add, Button, Default, Submit
Gui, Add, Text, Hidden, xxxxxxx  ; Reserves space for bar; for use with "Gui Show".
Gui, Show, w310

Gui +LastFound  ; For use with WinExist() below.
; WS_CHILD (0x40000000) + WS_VISIBLE (0x10000000) = 0x50000000:
BarHWND := DllCall("CreateStatusWindow", int, 0x50000000, str, "Bar's Text", UInt, WinExist(), UInt, 5555)

VarSetCapacity( parts, 4*3 )
InsertInteger( 100, parts, 0 )
InsertInteger( 200, parts, 4 )
InsertInteger( -1, parts, 8 )

; SB_SETPARTS
SendMessage, 0x404, 3, &parts,, ahk_id %BarHWND%
return

ButtonSubmit:
GuiControlGet, MyEdit
SendMessage, 0x401, 0, &MyEdit,, ahk_id %BarHWND%  ; 0x401 is SB_SETTEXT
return

GuiSize:  ; This allows the bar to resize along with the window.
SendMessage, 5, 0, 0,, ahk_id %BarHWND%  ; 5 is WM_SIZE
return

GuiClose:
ExitApp

InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4)
; To preserve any existing contents in pDest, only pSize number of bytes starting at pOffset
; are altered in it. The caller must ensure that pDest has sufficient capacity.
{
	mask := 0xFF  ; This serves to isolate each byte, one by one.
	Loop %pSize%  ; Copy each byte in the integer into the structure as raw binary data.
	{
		DllCall("RtlFillMemory", UInt, &pDest + pOffset + A_Index - 1, UInt, 1  ; Write one byte.
			, UChar, (pInteger & mask) >> 8 * (A_Index - 1))
		mask := mask << 8  ; Set it up for isolation of the next byte.
	}
}


Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
Thanks for posting that. It had been on my to-do list to research it and reply, but I'd been procrastinating to try to catch up on other work.

By the way, if anyone needs to update the text in a part of the bar other the first, update the following line in the script above. Replace the number 0 with 1 to use the second part, 2 to use the third, etc:

SendMessage, 0x401, 0, &MyEdit,, ahk_id %BarHWND% ; 0x401 is SB_SETTEXT

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Beautiful!

Just to be a pain in the neck, the InsertInteger function can be simplified a bit.
PutInteger(ByRef pDest, Integer, Offset = 0, Size = 4)
{                          ; Dest must have enough capacity!
   Loop %Size%             ; Copy each byte in Integer into Dest, as binary
      DllCall("RtlFillMemory", UInt, &pDest + Offset + A_Index-1, UInt, 1  ; Write one byte
             , UChar, (Integer >> 8*(A_Index-1) & 0xFF) )
}


shimanov
  • Members
  • 610 posts
  • Last active: Jul 18 2006 08:35 PM
  • Joined: 25 Sep 2005

Thanks for posting that.


Just bringing together the disparate [existing] pieces to realize the puzzle, for the community and my own benefit.

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004

Just to be a pain in the neck, the InsertInteger function can be simplified a bit.

Simplification is good because although it might make the function less understandable, I think the performance benefit is well worth it in this case. I'll try to apply your change to InsertInteger in the help file. Thanks.

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Here is the odd couple, with testcases.
z = AAAA

PutInt(z,55,0,1)  ; AAAA -> 7AAA

MsgBox % GetUint(z,0,1) "`n" z





PutInt(ByRef pDest, Integer, Offset = 0, Size = 4)

{                          ; Dest must have enough capacity!

   Loop %Size%             ; Copy each byte in Integer into the Dest, as binary

      DllCall("RtlFillMemory", UInt, &pDest + Offset + A_Index-1, UInt, 1  ; Write one byte

             , UChar, (Integer >> 8*(A_Index-1) & 0xFF) )

}



GetUInt(ByRef pSource, Offset = 0, Len = 4)

{

   Loop %Len%

      result += *(&pSource+Offset+A_Index-1) << 8*(A_Index-1)

   return result  ; += works w/o init

}


kapege.de
  • Members
  • 192 posts
  • Last active: Jan 16 2012 12:34 PM
  • Joined: 07 Feb 2005
Thanx pals for your help!
Now I'm looking forward to complete my set of functions to control the status bar. :wink:
Peter

Wisenheiming for beginners: KaPeGe (German only, sorry)

kapege.de
  • Members
  • 192 posts
  • Last active: Jan 16 2012 12:34 PM
  • Joined: 07 Feb 2005
Now here is my complete set of functions to the Statusbar:
; SB_Segments: Initiates a Status Bar and divides it into segments. Depends on "VarSetCapacity" and "InsertInteger".
; Usage: You put the positions of your segments into a string like this "10,20,100,200,-1". The numbers determins the right edge of the segment, "-1" means 'make a final segment filling the remaining space until the rightmost border'
; If the string is empty ("") you'll only see the size grip (see sample below)
; Sample: SB_Segments("20,44,200,350,450,-1")
; To get the correct GUI for a status bar you should have to do a 'Gui +LastFound' before calling 'SB_Segments'
; To resize the Statusbar with the Gui:
;           guisize:
;           SendMessage, 5, 0, 0,, ahk_id %BarHWND%  ; 5 is WM_SIZE
;           return 
SB_Segments(segs)
{
global BarHWND
; WS_CHILD (0x40000000) + WS_VISIBLE (0x10000000) = 0x50000000:
BarHWND := DllCall("CreateStatusWindow", int, 0x50000000, str, "", UInt, WinExist(), UInt, 5555)
if (segs = "") {
        VarSetCapacity(parts, 4)  ; Create 'parts' and make it 4 Byte times n segments large
        SendMessage, 0x404, 1, &parts,, ahk_id %BarHWND%  ; Sends the number of segments and its positions to the status bar
        return, BarHWND
    } else {
        n = 0
        loop, Parse, segs, CSV         ; How many segments are needed -> n
            n++
        VarSetCapacity( parts, 4*n )   ; Create 'parts' and make it 4 Byte times n segments large
        loop, Parse, segs, CSV         ; Fill the var 'parts' with content (the postitons)
            InsertInteger( A_LoopField, parts, 4 * ( A_Index - 1 ) ) ; Reserves 4 Bytes per run in the string "parts"
        SendMessage, 0x404, %n%, &parts,, ahk_id %BarHWND%           ; Sends the number of segments and its positions to the status bar
        return, BarHWND
    }
}

; SB_Icon: Adds an icon to a specific segment within a status bar
; SEG is the number of the segment (the first segment is 1, the second 2...)
; NAME is the filename of the graphic to show
; Sample: SB_Icon(1, "icon.ico")  This puts the file 'icon.ico' into the first segment of your status bar
SB_Icon(seg, name)
{
    global BarHWND
    seg-- ; subs 1 from the segment, because it starts with zero
    hicon := DllCall("LoadImage", UInt, NULL, Str, name, UInt, 1, Int, 16, Int, 16, UInt, 0x10|0x2000)
    if hicon
        SendMessage, 0x40F, seg, hicon,, ahk_id %BarHWND%  ; 0x40F is SB_SETICON
    return
}

; SB_Text: Puts a text into a segment of your status bar
; SEG is the number of the segment (the first segment is 1, the second 2...)
; TEXT is the text to display. Put it into doublequotes
; Sample: SB_Text(1,"Hello World!")
SB_Text(seg, text)
{
    global BarHWND
    seg--
    SendMessage, 0x401, %seg%, &text,, ahk_id %BarHWND%  ; 0x401 is SB_SETTEXT
    return
}

InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4)
; To preserve any existing contents in pDest, only pSize number of bytes starting at pOffset
; are altered in it. The caller must ensure that pDest has sufficient capacity.
{
   mask := 0xFF  ; This serves to isolate each byte, one by one.
   Loop %pSize%  ; Copy each byte in the integer into the structure as raw binary data.
   {
      DllCall("RtlFillMemory", UInt, &pDest + pOffset + A_Index - 1, UInt, 1, UChar, (pInteger & mask) >> 8 * (A_Index - 1))
      mask := mask << 8  ; Set it up for isolation of the next byte.
   }
}
; ----- Sample with empty bar (shows only the size grip)
#singleinstance force

gui, +resize
gui, show, h50 w200

; add statusbar control:
gui, +lastfound
SB_Segments("")
return

guisize:
SendMessage, 5, 0, 0,, ahk_id %BarHWND%  ; 5 is WM_SIZE
return
I put the code here to link it with the wiki.
Peter

Wisenheiming for beginners: KaPeGe (German only, sorry)

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Nice and easy to use! I added it to my tools box.

I cannot resist... you can save a few lines:
Gui +Resize
Gui Show, h50 w200

BarHWND := SB_Segments("20,44,99,-1")
SB_Icon(BarHWND, 2, "XX.ICO")    ; <-- put here your icon file
SB_Text(BarHWND, 2, "OK?")
Return

SB_Segments(segs) ; Create Status Bar for Last GUI, divide it into segments, return its handle
{                 ; segs = right-edge positions of segments in string "10,20,-1" (-1 = right border)
   Gui +Lastfound                ;  \/ WS_CHILD (0x40000000) + WS_VISIBLE (0x10000000)
   BarHWND := DllCall("CreateStatusWindow", int, 0x50000000, str, "", UInt, WinExist(), UInt, 5555)
   IfEqual segs,, SetEnv segs,-1
   StringReplace segs,segs,`,,`,,UseErrorLevel
   n := ErrorLevel + 1           ; # segments
   VarSetCapacity( parts, 4*n )  ; Reserve 4 Bytes for each segment
   Loop Parse, segs, `,          ; Fill the var 'parts' with the positions
      InsertInteger( A_LoopField, &parts + 4*A_Index-4 )
   SendMessage 0x404,%n%,&parts,,ahk_id %BarHWND%  ; Send number of segments, positions to status bar
   Return BarHWND
}

SB_Icon(BarHWND, seg, file)      ; Add icon from 'file' to segment 'seg' = 0,1.. in the status bar
{
   hicon := DllCall("LoadImage", UInt, NULL, Str, file, UInt, 1, Int, 16, Int, 16, UInt, 0x2010)
   If hicon
      SendMessage 0x40F,seg,hicon,,ahk_id %BarHWND% ; 0x40F = SB_SETICON
}

SB_Text(BarHWND, seg, text)      ; Add 'text' to segment 'seg' = 0,1.. in the status bar
{
   SendMessage 0x401,%seg%,&text,,ahk_id %BarHWND%   ; 0x401 = SB_SETTEXT
}

InsertInteger(pInteger, pAddress, pSize = 4)
{                                ; Copy bytes in pInteger into pAddress as raw binary data
   Loop %pSize%
      DllCall("RtlFillMemory", UInt,pAddress+A_Index-1, UInt,1, UChar, pInteger >> 8*A_Index-8 & 0xFF )
}

GuiSize:                         ; Called when the GUI is resized
   SendMessage 5,0,0,,ahk_id %BarHWND% ; 5 = WM_SIZE
Return


toralf
  • Moderators
  • 4035 posts
  • Last active: Aug 20 2014 04:23 PM
  • Joined: 31 Jan 2005
I would suggest to extend the SB_Segments(segs) to contain a GUIID which defaults to 1, so you could use it for multiple GUIs
SB_Segments(segs, GuiID=1) {

   Gui, %GuiID%:+Lastfound

Ciao
toralf
 
I use the latest AHK version (1.1.15+)
Please ask questions in forum on ahkscript.org. Why?
For online reference please use these Docs.

toralf
  • Moderators
  • 4035 posts
  • Last active: Aug 20 2014 04:23 PM
  • Joined: 31 Jan 2005
And if you set a default for segs (e.g. SB_Segments(segs = -1, GuiID = 1)) you can even leave out the line "IfEqual segs,, SetEnv segs,-1"

BTW: Nice mod, laszlo. I'll use it, put it to my tool box as well. Thanks KaPeGe for the research and your work.
Ciao
toralf
 
I use the latest AHK version (1.1.15+)
Please ask questions in forum on ahkscript.org. Why?
For online reference please use these Docs.

toralf
  • Moderators
  • 4035 posts
  • Last active: Aug 20 2014 04:23 PM
  • Joined: 31 Jan 2005
And another mod: If you put "% seg-1" (instead of just "%seg%" or "seg") into the SendMessage commands for Image and Text, the segments start to count from 1. Which might be ease the handling of the functions, since in AHK normally everything starts with 1 and not with 0.
Ciao
toralf
 
I use the latest AHK version (1.1.15+)
Please ask questions in forum on ahkscript.org. Why?
For online reference please use these Docs.

toralf
  • Moderators
  • 4035 posts
  • Last active: Aug 20 2014 04:23 PM
  • Joined: 31 Jan 2005
And BTW: KaPeGe, please post your code (maybe with the improvements) in the script and fucntions section. It is very dufficult to find in this topic, I lost it and just found it again.

I searched for it since I discovered a problem. Please try this code:
Gui, 1:+Resize 
Gui, 1:Add, Button, vB2, Test Button2 
Gui, 1:Add, Text,, This is a test 
Gui, 1:Add, Text,, ... another test... 
Gui, 1:Show, ;h300

BarHWND := SB_Segments("50,50,-1") 
SB_Text(BarHWND, 1, "OK?")
Return 

GuiSize:
  SendMessage 5,0,0,,ahk_id %BarHWND%
Return

SB_Segments(segs = -1, GuiID = 1){
    Gui, %GuiID%:+Lastfound
    BarHWND := DllCall("CreateStatusWindow", int, 0x50000000, str, "", UInt, WinExist(), UInt, 5555) 
    StringReplace segs,segs,`,,`,,UseErrorLevel 
    n := ErrorLevel + 1
    VarSetCapacity( parts, 4*n )
    Loop Parse, segs, `,        
        InsertInteger( A_LoopField, &parts + 4*A_Index-4 ) 
    SendMessage 0x404,%n%,&parts,,ahk_id %BarHWND%
    Return BarHWND 
  } 

SB_Text(BarHWND, seg, XXXtextXXX){
    SendMessage 0x401,% seg-1,&XXXtextXXX,,ahk_id %BarHWND%
  } 

InsertInteger(pInteger, pAddress, pSize = 4){
    Loop %pSize% 
        DllCall("RtlFillMemory", UInt,pAddress+A_Index-1, UInt,1, UChar, pInteger >> 8*A_Index-8 & 0xFF ) 
  }
The test "... another test... " gets permanently shown in the Statusbar, even if you resize the GUI. If you set a hight for the GUI (e.g. h300) so that the text is not below the statusbar it works ok.
Is there a way around that? The only solution I can think of is to enlarge the GUI prior to adding a Statusbar.
Ciao
toralf
 
I use the latest AHK version (1.1.15+)
Please ask questions in forum on ahkscript.org. Why?
For online reference please use these Docs.