AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

[Solved] How to send an array with SendMessage
Goto page 1, 2  Next
 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Ask for Help
View previous topic :: View next topic  
Author Message
kapege.de



Joined: 07 Feb 2005
Posts: 186
Location: Munich, Germany

PostPosted: Wed Oct 26, 2005 12:41 pm    Post subject: [Solved] How to send an array with SendMessage Reply with quote

I've to send a message 0x404 (Statusbar "SB_SetParts").

After trying this AHK crashes badly:
Code:
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:
Code:
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)


Last edited by kapege.de on Mon Feb 06, 2006 2:56 pm; edited 1 time in total
Back to top
View user's profile Send private message Visit poster's website
Laszlo



Joined: 14 Feb 2005
Posts: 4016
Location: Pittsburgh

PostPosted: Wed Oct 26, 2005 4:46 pm    Post subject: Reply with quote

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?
Back to top
View user's profile Send private message
shimanov



Joined: 25 Sep 2005
Posts: 612

PostPosted: Wed Oct 26, 2005 5:52 pm    Post subject: Reply with quote

Try the following:

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

Code:
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.
   }
}
Back to top
View user's profile Send private message
Chris
Site Admin


Joined: 02 Mar 2004
Posts: 10467

PostPosted: Wed Oct 26, 2005 6:28 pm    Post subject: Reply with quote

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
Back to top
View user's profile Send private message Send e-mail
Laszlo



Joined: 14 Feb 2005
Posts: 4016
Location: Pittsburgh

PostPosted: Wed Oct 26, 2005 7:47 pm    Post subject: Reply with quote

Beautiful!

Just to be a pain in the neck, the InsertInteger function can be simplified a bit.
Code:
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) )
}
Back to top
View user's profile Send private message
shimanov



Joined: 25 Sep 2005
Posts: 612

PostPosted: Wed Oct 26, 2005 9:04 pm    Post subject: Reply with quote

Chris wrote:
Thanks for posting that.


Just bringing together the disparate [existing] pieces to realize the puzzle, for the community and my own benefit.
Back to top
View user's profile Send private message
Chris
Site Admin


Joined: 02 Mar 2004
Posts: 10467

PostPosted: Thu Oct 27, 2005 12:22 am    Post subject: Reply with quote

Laszlo wrote:
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.
Back to top
View user's profile Send private message Send e-mail
Laszlo



Joined: 14 Feb 2005
Posts: 4016
Location: Pittsburgh

PostPosted: Thu Oct 27, 2005 1:42 am    Post subject: Reply with quote

Here is the odd couple, with testcases.
Code:
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
}
Back to top
View user's profile Send private message
kapege.de



Joined: 07 Feb 2005
Posts: 186
Location: Munich, Germany

PostPosted: Thu Oct 27, 2005 1:16 pm    Post subject: Reply with quote

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)
Back to top
View user's profile Send private message Visit poster's website
kapege.de



Joined: 07 Feb 2005
Posts: 186
Location: Munich, Germany

PostPosted: Mon Feb 06, 2006 2:55 pm    Post subject: Reply with quote

Now here is my complete set of functions to the Statusbar:
Code:

; 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)
Back to top
View user's profile Send private message Visit poster's website
Laszlo



Joined: 14 Feb 2005
Posts: 4016
Location: Pittsburgh

PostPosted: Mon Feb 06, 2006 11:42 pm    Post subject: Reply with quote

Nice and easy to use! I added it to my tools box.

I cannot resist... you can save a few lines:
Code:
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
Back to top
View user's profile Send private message
toralf



Joined: 31 Jan 2005
Posts: 3842
Location: Bremen, Germany

PostPosted: Tue Feb 07, 2006 8:42 am    Post subject: Reply with quote

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
Code:
SB_Segments(segs, GuiID=1) {
   Gui, %GuiID%:+Lastfound

_________________
Ciao
toralf
Back to top
View user's profile Send private message Send e-mail Visit poster's website
toralf



Joined: 31 Jan 2005
Posts: 3842
Location: Bremen, Germany

PostPosted: Tue Feb 07, 2006 9:02 am    Post subject: Reply with quote

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
Back to top
View user's profile Send private message Send e-mail Visit poster's website
toralf



Joined: 31 Jan 2005
Posts: 3842
Location: Bremen, Germany

PostPosted: Tue Feb 07, 2006 9:15 am    Post subject: Reply with quote

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
Back to top
View user's profile Send private message Send e-mail Visit poster's website
toralf



Joined: 31 Jan 2005
Posts: 3842
Location: Bremen, Germany

PostPosted: Tue Feb 07, 2006 10:36 am    Post subject: Reply with quote

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:
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
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Ask for Help All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group