AutoHotkey Community

It is currently May 27th, 2012, 10:23 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 59 posts ]  Go to page Previous  1, 2, 3, 4
Author Message
 Post subject:
PostPosted: December 31st, 2010, 11:42 am 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
I don't think thats all that important, but it should return true.

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 2nd, 2011, 1:25 am 
Offline

Joined: January 8th, 2007, 1:14 pm
Posts: 83
majkinetor wrote:
I don't think thats all that important, but it should return true.


Yea it is really not that important but i thought i'd mention it.

I've been tinkering with the two example scripts and trying to run these in 64-bit but i'm having some pretty weird results.

Here are the changes i've made.

IPC.ahk
Code:
   if (DataSize = "")
       DataSize := (StrLen(Data)+1) * (!!A_IsUnicode + 1), pData := &Data, Port := -Port         ;use negative port for textual messages
   else pData := Data         
   
   VarSetCapacity(COPYDATA, 8+A_PtrSize)
    , NumPut(Port,      COPYDATA, 0, "Int")
    , NumPut(DataSize, COPYDATA, 4, "UInt")
    , NumPut(pData,   COPYDATA, 8, "Ptr")


Script1.ahk / Script2.ahk
Code:
   port := NumGet(Lparam+0, 0, "Int"), data := NumGet(Lparam+8, 0, "Ptr")
   if port < 0
       data := DllCall("MulDiv", "Int", data, "Int",1, "Int", 1, "str"), port := -port
   else size := NumGet(LParam+4, 0, "UInt")


In 32-bit builds these changes work without problem but in 64-bit the "IPC_onCopyData" appears to lock, OnMessage handler function no longer "fires", randomly. Usually this happens after second sent message or right from the start, either in both scripts or only in one etc. Also it's sluggish in processing the message.

Two things that seem to fix this. One is to use the original COPYDATA structure or remove/comment any NumGet/StrGet from the OnMessage called function (IPC_onCopyData). Neither seems particularly good solution. Note that once the script hits the NumGet the first time, nothing after that gets processed and from there on it "locks" i.e. OnMessage handler no longer is working.

Also i've only tested the 64-bit version in compiled form only. Using Autohotkey 1.0.91.05, Windows 7 (x64).

Not sure if my COPYDATA structure is wrong or something, i'm assuming it has to be at least bigger in 64-bit than in 32-bit at least for the data pointer?

Any help/comments/etc. are appreciated!


Last edited by Mystiq on January 2nd, 2011, 4:41 am, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 2nd, 2011, 1:41 am 
Offline
User avatar

Joined: December 5th, 2010, 7:19 pm
Posts: 311
This is awesome for multimonitored computers. i know a school that has all there computers linked up to make multi screens. they just select a monitor and send the window to it.

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 3rd, 2011, 2:42 am 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
Mistiq, I can't reproduce your problem, altho I tried only briefly. When I find time I will check out more.

Since Lexikos fixed the module, I still didn't use it in 64x environment apart from basic working tests.

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 3rd, 2011, 3:54 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
Note that the dwData field is ULONG_PTR, i.e. 64-bit. Since the struct contains 64-bit fields, it is aligned to 64-bit boundaries by default; i.e. there are 32 bits of padding between cbData and lpData.
Code:
   VarSetCapacity(COPYDATA, 3*A_PtrSize)
    , NumPut(Port,      COPYDATA, 0, "Int")
    , NumPut(DataSize, COPYDATA, A_PtrSize, "UInt")
    , NumPut(pData,   COPYDATA, 2*A_PtrSize, "Ptr")
Code:
   port := NumGet(Lparam+0, 0, "Int"), data := NumGet(Lparam+2*A_PtrSize, 0, "Ptr")
   if port < 0
       data := DllCall("MulDiv", "Int", data, "Int",1, "Int", 1, "str"), port := -port
   else size := NumGet(LParam+A_PtrSize, 0, "UInt")
Untested.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 4th, 2011, 12:30 am 
Offline

Joined: January 8th, 2007, 1:14 pm
Posts: 83
Lexikos wrote:
Note that the dwData field is ULONG_PTR, i.e. 64-bit. Since the struct contains 64-bit fields, it is aligned to 64-bit boundaries by default; i.e. there are 32 bits of padding between cbData and lpData.


Aaah, well that explains it. I got the impression that the size might be 64-bit for the two and 32-bit for the cbData one, which is actually wrong in the example i gave. Just goes to show how much i really know about these things, which is not much! :)

I tested the code and it works perfectly, no problems at all. Thanks to both of you!


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 4th, 2011, 3:17 am 
Offline

Joined: January 8th, 2007, 1:14 pm
Posts: 83
Now that this works in 64-bit i'd like to share my changes, which also includes the various fixes from previous posters.

Most notable thing i've changed is that it no longer uses window handles, instead i'm using process name or id. Not sure how good idea this is but it appears to work just fine and no longer deals with GUI(s) or window handles. Also this one does handle the SendMessage more strictly, as i think it might be better to know whether the target process actually processed the message or not. For example if you are accidentally sending to a wrong process/window, one that is not handling the WM_COPYDATA message, then there was no feedback if the message was really received.

Another one is that instead of passing the window handle as the SendMessage wParam, i'm using the process id. According to WM_COPYDATA it is suppose to be the window handle, but i've not seen any side effects of using the process id instead. Not sure if this such a good idea(?)

Also IPC_Send returns empty/false on success and error message string on failure.

I've tested mostly between two AHK programs and with the DotNet examples. However the DotNet ones do not work perfectly as it does not appear to use Unicode(??), at least the message is cut off after the first letter. Also since this version handles the return value of the SendMessage more strictly, AHK script will say that the send failed, when in fact the DotNet program did receive and display the message (well, part of it...).

I've update both the example script(s) and IPC.ahk.

IPC.ahk
Code:
/*
 Function:    Send
          Send the message to another process (receiver).

 Parameters:
          PidOrName   - Process name or ID
          Data      - Data to be sent, by default empty. Optional.
          Port      - Port, by default 100. Positive integer. Optional.
          DataSize    - If this parameter is used, Data contains pointer to the buffer holding binary data.
                  Omit this parameter to send textual messages to the receiver.               

 Remarks:
         The data being passed must not contain pointers or other references to objects not accessible to the script receiving the data.
         While this message is being sent, the referenced data must not be changed by another thread of the sending process.
         The receiving script should consider the data read-only. The receiving script should not free the memory referenced by Data parameter.
         If the receiving script must access the data after function returns, it must copy the data into a local buffer.

 Returns:
         Returns EMPTY / FALSE on success. Error message on failure.
 */
IPC_Send(PidOrName, Data="", Port=100, DataSize="") {
   static WM_COPYDATA = 74, INT_MAX=2147483647
   if Port not between 0 AND %INT_MAX%
      return A_ThisFunc "> Port number is not in a positive integer range: " Port
   
   Process, Exist, %PidOrName%
   if (!PidOrName || !(PID := ErrorLevel))
      return A_ThisFunc "> Process not found: " PidOrName
   
   if (DataSize = "")
      DataSize := (StrLen(Data)+1) * (!!A_IsUnicode + 1), pData := &Data, Port := -Port         ;use negative port for textual messages
   else pData := Data

   VarSetCapacity(COPYDATA, 3*A_PtrSize)
    , NumPut(Port,      COPYDATA, 0, "Int")
    , NumPut(DataSize, COPYDATA, A_PtrSize, "UInt")
    , NumPut(pData,   COPYDATA, 2*A_PtrSize, "Ptr")
      
   PrevDetectHiddenWindows := A_DetectHiddenWindows
   DetectHiddenWindows, On
   SendMessage, WM_COPYDATA, DllCall("GetCurrentProcessId"), &COPYDATA,, ahk_pid %PID%
   DetectHiddenWindows, %PrevDetectHiddenWindows%
   
   return ErrorLevel="FAIL" || !ErrorLevel ? A_ThisFunc "> SendMessage failed, ErrorLevel=" ErrorLevel : false
}

/*
  Function:    SetHandler
           Set the data handler.
 
  Parameters:
           Handler - Function that will be called when data is received.                
 
  Handler:
  >          Handler(PID, Data, Port, DataSize)

          PID   - Process ID of the process passing data.
          Data   - Data that is received.
          Port   - Data port.
          DataSize - If DataSize is not empty, Data is pointer to the actuall data. Otherwise Data is textual message.
 */
IPC_SetHandler( Handler ){
   static WM_COPYDATA = 74

   if !IsFunc( Handler )
      return A_ThisFunc "> Invalid handler: " Handler
   
   OnMessage(WM_COPYDATA, "IPC_onCopyData")
   IPC_onCopyData(Handler, "")
}


IPC_onCopyData(WParam, LParam) {
   static Handler
   if Lparam =
      return  Handler := WParam
      
   port := NumGet(Lparam+0, 0, "Int"), data := NumGet(Lparam+2*A_PtrSize, 0, "Ptr")
   if port < 0
      data := DllCall("MulDiv", "Int", data, "Int",1, "Int", 1, "str"), port := -port
   else size := NumGet(LParam+A_PtrSize, 0, "UInt")

   %handler%(WParam, data, port, size)
   return 1
}


Script1.ahk / Script2.ahk

Remember to change the "target" variable!

Code:
#SingleInstance, off   ;allow multiple instances

   target := "Script2"
   ;target := "Script1"
   stress := 1000,   x:=300
   ;========================

   Gui, +LastFound     +AlwaysOnTop
   CPID := DllCall("GetCurrentProcessId")
   
   Gui, Font, s10
   Gui, Add, Edit,       vMyMsg  w200 , Message to %target%
   Gui, Add, Edit,  x+0 vMyPort w50, 100

   Gui, Font, s8
   Gui, Add, Button, x+5   gOnSend        , Send
   Gui, Add, Button, x+5   gOnSendBinary , Send Binary
   Gui, Add, Button, x+5   gOnStress     , Stress

   Gui, Add, ListBox,xm w440 h300 vMyLB,

   Gui, Show, x%x%   AutoSize
   GuiControl, , MyLB, This script PID: %CPID%
   IPC_SetHandler("OnData")
return

OnData(PID, Data, Port, Size) {
   global myLB

   if Size =
       s = %Port%      PID: %PID%      Message: %Data%
   else {       
        x := NumGet(Data+0), y := NumGet(Data+4)
        s = %Port%     PID: %PID%      Binary Data: POINT (%x%, %y%)      DataSize: %Size%
   }   
   GuiControl, , MyLB, %s%
}


OnSend:
   Gui, Submit, NoHide
   WinGet, TPID, PID, %target%
   if IPC_Send(TPID, MyMsg, MyPort)
      MsgBox Sending failed
return

OnStress:
   Gui, Submit, NoHide
   WinGet, TPID, PID, %target%
   if !(TPID)
      MsgBox Host process doesn't exist
   loop, %stress%
      IPC_Send(TPID, MyMsg " : " A_Index, MyPort)
return

OnSendBinary:
   Gui, Submit, NoHide
   VarSetCapacity(POINT, 8), NumPut(2000, POINT), NumPut(8000, POINT, 4)
   WinGet, TPID, PID, %target%
   if IPC_Send(TPID, &POINT, MyPort, 8)
      MsgBox Sending failed
return

GuiClose:
   ExitApp
return

#include ..\IPC.ahk


Again, feedback is much appreciated!


Last edited by Mystiq on January 4th, 2011, 6:45 pm, edited 2 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 4th, 2011, 2:41 pm 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
Quote:
target := "Script2.exe"

How can this work since there is no "Script2.exe" but Ahk.exe with Script2.ahk as parameter ? (unless u compiled scripts).

About process id, its probably good idea since script doesn't need to have Gui.

About C# include, its not unicode:
Code:
 ea.Text = Marshal.PtrToStringAnsi(CD.lpData, CD.cbData);

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 4th, 2011, 6:27 pm 
Offline

Joined: January 8th, 2007, 1:14 pm
Posts: 83
majkinetor wrote:
Quote:
target := "Script2.exe"

How can this work since there is no "Script2.exe" but Ahk.exe with Script2.ahk as parameter ? (unless u compiled scripts).


Yea, it's meant to be compiled. I might have needlessly done it that way since you can just get the process id from window title as it was in the original example scripts.

I updated the example script so that it now works like the original ones. No compiling needed. :)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 5th, 2011, 10:58 am 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
I am thinking to support only Unicode string from now on. What do you think ?
That means that AHK Basic will no longer be supported but user can download old version if they need it. Alternatively, AHK Basic can be recognized and its ANSI strings could be converted to Unicode first. If that is not done, C# app can not know to what kind of AHK it sends data so we need to have another property or two in IPC class and/or methods - those that will send/receive text as Unicode.

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 5th, 2011, 12:45 pm 
Offline

Joined: January 8th, 2007, 1:14 pm
Posts: 83
majkinetor wrote:
I am thinking to support only Unicode string from now on. What do you think ?


I would go for Unicode only simply because that's what I'm going to be using anyways, unless forced otherwise (very unlikely). If you know how to do the ANSI conversion thing properly without much effort then maybe?


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 5th, 2011, 1:03 pm 
Offline

Joined: May 24th, 2006, 2:49 pm
Posts: 4511
Location: Belgrade
Its not a problem how to convert, but I wouldn't like to impose extra complexity because of outdated format.

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 8th, 2011, 9:11 am 
Offline

Joined: January 8th, 2007, 1:14 pm
Posts: 83
If there is no huge demand for the ANSI thing then i wouldn't bother with it.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 11th, 2011, 1:55 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
This script hasn't been updated to support Unicode yet, has it?
majkinetor wrote:
I am thinking to support only Unicode string from now on. What do you think ?
I think it's the best way to go, even for ANSI builds. However, you don't necessarily need to drop AutoHotkey Basic support. You can use StrPut/StrGet (or borrow code from that script).


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 59 posts ]  Go to page Previous  1, 2, 3, 4

All times are UTC [ DST ]


Who is online

Users browsing this forum: XX0 and 25 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group