Script crashing, assuming access violation, not sure. Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
KuroiLight
Posts: 327
Joined: 12 Apr 2015, 20:24
Contact:

Script crashing, assuming access violation, not sure.

Post by KuroiLight » 25 Dec 2017, 23:06

Im trying to move my custom notification code into its own script so I can better manage how/when notifications popup from multiple scripts, heres where Im at:
Function included in calling scripts:

Code: Select all

Notify(message, timeout := 2500) {
    static NSW_WinName := "NotificationOperator - 0xF505 @ ZZ9PZA"
    NSW_ID := WinExist(NSW_WinName)

    if(!NSW_ID) {
        for i, v in Array("\lib\CNS.ahk", "\CNS.ahk", "\..\CNS.ahk") {
            if(FileExist(A_ScriptDir . v)) {
                Run, % A_ScriptDir . v, A_ScriptDir, UseErrorLevel, CNS_PID
                if(!ErrorLevel and CNS_PID) {
                    WinWait, %NSW_WinName%,,
                    NSW_ID := WinExist(NSW_WinName)
                    break
                }
            }
        }
        if(!NSW_ID) {
            ToolTip, % message
            return
        }
    }

    ;ToolTip, % SHOWNOTIFICATION . "`n" . message . "`n" . &message . "`n" . NSW_ID
    SendMessage, %SHOWNOTIFICATION%, &message, %timeout%,, ahk_id %NSW_ID%
}
The notification script:

Code: Select all

;Centralized Notification System
;Version: 1.0
;Author: KuroiLight/klomb
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

#NoEnv
#SingleInstance, force
#Persistent

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

DetectHiddenWindows, On
global SCRIPT_TITLE := "NotificationOperator - 0xF505 @ ZZ9PZA"
WinSetTitle, ahk_id %A_ScriptHwnd%,, %SCRIPT_TITLE%

global SHOWNOTIFICATION := 0xF505
RemainingTick := 0
TickSize := 250
Notification_Visible := false
Notify_Window := 0x0

BgColor := "282828"
FrColor := "EEEEEE"
FontSize := "12"

OnMessage(SHOWNOTIFICATION, "Show_Notification")
SetTimer, Hide_Notification, %TickSize%

Initialize()

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
return

Initialize() {
    global base_x, base_y

    if(WinExist("ahk_class Shell_TrayWnd")) {
        WinGetPos, shell_x, shell_y, shell_w, shell_h, ahk_class Shell_TrayWnd
        base_x := shell_x + shell_w
        base_y := shell_y
    } else {
        SysGet, Primary_M, MonitorPrimary
        SysGet, Monitor_, Monitor, %Primary_M%
        base_x := Monitor_Right
        base_y := Monitor_Left
    }

    base_x -= 10
    base_y -= 10
}

Hide_Notification() {
    global RemainingTick, Notification_Visible, Notify_Window, TickSize
    if(!Notify_Window)
        return

    if(RemainingTick >= 1) {
        RemainingTick -= TickSize
    } else {
        if(Notification_Visible) {
            Gui, %Notify_Window%: Hide
            Notification_Visible := false
        }
    }
}

Show_Notification(ptr_message, lParam, msg, hwnd) {
    ;ToolTip, % ptr_message . "`n" . lParam . "`n" . msg
    Critical
    if(!msg == SHOWNOTIFICATION or !ptr_message)
        return 0

    message := StrGet(ptr_message)

    global RemainingTick, Notification_Visible, Notify_Window, MainLbl, base_x, base_y
    global BgColor, FrColor, FontSize
    RemainingTick := lParam

    if(!Notify_Window) {
        Gui, New, +AlwaysOnTop +Border -Caption -Resize +ToolWindow +HwndNotify_Window, %SCRIPT_TITLE%
        Gui, %Notify_Window%: Color, %BgColor%
        Gui, %Notify_Window%: Font, c%FrColor% s%FontSize%
        Gui, %Notify_Window%: Margin, 5, 5
        Gui, %Notify_Window%: Add, Text, +HwndMainLbl, %message%
        if(!Notify_Window)
            Throw, "Failure to create GUI."
    } else {
        DllCall("User32\DestroyWindow", "UInt", MainLbl)
        Gui, %Notify_Window%: Add, Text, X5 Y5 +HwndMainLbl, %message%
    }

    Gui, %Notify_Window%: Show, Hide AutoSize NoActivate
    WinGetPos,,, N_W, N_H, ahk_id %Notify_Window%
    New_X := base_x - N_W
    New_Y := base_y - N_H
    Gui, %Notify_Window%: Show, AutoSize NoActivate X%New_X% Y%New_Y%
    return (Notification_Visible := true)
}
I'm not sure but I assume its an access violation from StrGet, unfortunetly the script just crashes with the generic APPCRASH (in the event log) as soon as Notify is called.. Any ideas?
Windows 10, Ryzen 1600, 16GB G.Skill DDR4, 8GB RX 480 | [MyScripts][MySublimeSettings] [Unlicense][MIT License]
01/24/18
[/color]

Rindis
Posts: 213
Joined: 23 Dec 2013, 13:58
Location: Norway
Contact:

Re: Script crashing, assuming access violation, not sure.

Post by Rindis » 26 Dec 2017, 03:35

what is the error message you get?
[edit] read the last line....

teadrinker
Posts: 4331
Joined: 29 Mar 2015, 09:41
Contact:

Re: Script crashing, assuming access violation, not sure.

Post by teadrinker » 26 Dec 2017, 06:29

Hi, KuroiLight,

I suppose, the problem is here:

Code: Select all

SendMessage, %SHOWNOTIFICATION%, &message, %timeout%,, ahk_id %NSW_ID%
You are trying to send the pointer from one process to another. It doesn't make sence, since a pointer is only valid in its own process. If you want to send a string from one script to another, use WM_COPYDATA.

User avatar
KuroiLight
Posts: 327
Joined: 12 Apr 2015, 20:24
Contact:

Re: Script crashing, assuming access violation, not sure.

Post by KuroiLight » 26 Dec 2017, 17:30

teadrinker wrote:Hi, KuroiLight,

I suppose, the problem is here:

Code: Select all

SendMessage, %SHOWNOTIFICATION%, &message, %timeout%,, ahk_id %NSW_ID%
You are trying to send the pointer from one process to another. It doesn't make sence, since a pointer is only valid in its own process. If you want to send a string from one script to another, use WM_COPYDATA.
That's what I figured, strange that it's worked before, I'm guessing in this case the string is being disposed before StrGet can read it.
Windows 10, Ryzen 1600, 16GB G.Skill DDR4, 8GB RX 480 | [MyScripts][MySublimeSettings] [Unlicense][MIT License]
01/24/18
[/color]

User avatar
KuroiLight
Posts: 327
Joined: 12 Apr 2015, 20:24
Contact:

Re: Script crashing, assuming access violation, not sure.

Post by KuroiLight » 26 Dec 2017, 18:03

Well updated to use a copy structure, but it still crashes on receive: :?
updated notify function:

Code: Select all

Notify(message, timeout := 2500) {
    static NSW_WinName := "NotificationOperator - 0xF505 @ ZZ9PZA"
    static script_local := "", SHOWNOTIFICATION := 0xF505
    A_DHW := A_DetectHiddenWindows
    DetectHiddenWindows, On

    if(!WinExist(NSW_WinName)) {
        if(!script_local) {
            for i, v in Array("\lib\CNS.ahk", "\CNS.ahk", "\..\CNS.ahk")
                if(FileExist(A_ScriptDir . v))
                    script_local := A_ScriptDir . v
        }

        Run, %script_local%, UseErrorLevel, CNS_PID
        if(ErrorLevel or !CNS_PID) {
            ToolTip, %message%, 0, 0
            return
        } else {
            WinWait, %NSW_WinName%
        }
    }

    ;build WM_COPYDATA structure
    VarSetCapacity(CDStruct, 3*A_PtrSize, 0)
    NumPut((StrLen(message) + 1) * (A_IsUnicode ? 2 : 1), CDStruct, A_PtrSize)
    NumPut(&message, CDStruct, 2*A_PtrSize)

    SendMessage, %SHOWNOTIFICATION%, &CDStruct, %timeout%,, %NSW_WinName%
    MsgBox, % "SendMessage:`n" . SHOWNOTIFICATION . "`n" . &CDStruct . "`n" . timeout . "`n" . NSW_WinName . "`nResult: " . ErrorLevel
    DetectHiddenWindows, %A_DHW%
}
updated CNS script:

Code: Select all

;Centralized Notification System
;Version: 1.0
;Author: KuroiLight/klomb
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

#NoEnv
#SingleInstance, force
#Persistent

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

DetectHiddenWindows, On
SCRIPT_TITLE := "NotificationOperator - 0xF505 @ ZZ9PZA"
if(WinExist(SCRIPT_TITLE))
    WinKill
WinSetTitle, ahk_id %A_ScriptHwnd%,, %SCRIPT_TITLE%

global SHOWNOTIFICATION := 0xF505
RemainingTick := 0
TickSize := 250
Notification_Visible := false
Notify_Window := 0x0

BgColor := "282828"
FrColor := "EEEEEE"
FontSize := "12"

OnMessage(SHOWNOTIFICATION, "Show_Notification")
SetTimer, Hide_Notification, %TickSize%

Initialize()

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
return

Initialize() {
    global base_x, base_y

    if(WinExist("ahk_class Shell_TrayWnd")) {
        WinGetPos, shell_x, shell_y, shell_w, shell_h, ahk_class Shell_TrayWnd
        base_x := shell_x + shell_w
        base_y := shell_y
    } else {
        SysGet, Primary_M, MonitorPrimary
        SysGet, Monitor_, Monitor, %Primary_M%
        base_x := Monitor_Right
        base_y := Monitor_Left
    }

    base_x -= 10
    base_y -= 10
}

Hide_Notification() {
    global RemainingTick, Notification_Visible, Notify_Window, TickSize
    if(!Notify_Window)
        return

    if(RemainingTick >= 1) {
        RemainingTick -= TickSize
    } else {
        if(Notification_Visible) {
            Gui, %Notify_Window%: Hide
            Notification_Visible := false
        }
    }
}

Show_Notification(ptr_message, lParam, msg, hwnd) {
    ToolTip, % ptr_message . "`n" . lParam . "`n" . msg
    Critical
    if(!msg == SHOWNOTIFICATION or !ptr_message)
        return 0

    message := StrGet(NumGet(ptr_message + 2*A_PtrSize))

    global RemainingTick, Notification_Visible, Notify_Window, MainLbl, base_x, base_y
    global BgColor, FrColor, FontSize
    RemainingTick := lParam

    if(!Notify_Window) {
        Gui, New, +AlwaysOnTop +Border -Caption -Resize +ToolWindow +HwndNotify_Window, %SCRIPT_TITLE%
        Gui, %Notify_Window%: Color, %BgColor%
        Gui, %Notify_Window%: Font, c%FrColor% s%FontSize%
        Gui, %Notify_Window%: Margin, 5, 5
        Gui, %Notify_Window%: Add, Text, +HwndMainLbl, %message%
        if(!Notify_Window)
            Throw, "Failure to create GUI."
    } else {
        DllCall("User32\DestroyWindow", "UInt", MainLbl)
        Gui, %Notify_Window%: Add, Text, X5 Y5 +HwndMainLbl, %message%
    }

    Gui, %Notify_Window%: Show, Hide AutoSize NoActivate
    WinGetPos,,, N_W, N_H, ahk_id %Notify_Window%
    New_X := base_x - N_W
    New_Y := base_y - N_H
    Gui, %Notify_Window%: Show, AutoSize NoActivate X%New_X% Y%New_Y%
    return (Notification_Visible := true)
}
Windows 10, Ryzen 1600, 16GB G.Skill DDR4, 8GB RX 480 | [MyScripts][MySublimeSettings] [Unlicense][MIT License]
01/24/18
[/color]

User avatar
KuroiLight
Posts: 327
Joined: 12 Apr 2015, 20:24
Contact:

Re: Script crashing, assuming access violation, not sure.

Post by KuroiLight » 26 Dec 2017, 18:15

According to OnMessage Docs both this^ and the previous way I did it should work just fine? I don't understand. Is this another quirk/bug in AHK or just me?
Windows 10, Ryzen 1600, 16GB G.Skill DDR4, 8GB RX 480 | [MyScripts][MySublimeSettings] [Unlicense][MIT License]
01/24/18
[/color]

BoBo
Posts: 6564
Joined: 13 May 2014, 17:15

Re: Script crashing, assuming access violation, not sure.

Post by BoBo » 27 Dec 2017, 02:27

Is this another quirk/bug in AHK or just me?
[pun intented] Let's guess that our fellow AHK member just me can't be hold accountable for that thing. :lol: :mrgreen: [/pun intended]

teadrinker
Posts: 4331
Joined: 29 Mar 2015, 09:41
Contact:

Re: Script crashing, assuming access violation, not sure.  Topic is solved

Post by teadrinker » 27 Dec 2017, 06:18

KuroiLight wrote:

Code: Select all

    ;build WM_COPYDATA structure
    VarSetCapacity(CDStruct, 3*A_PtrSize, 0)
    NumPut((StrLen(message) + 1) * (A_IsUnicode ? 2 : 1), CDStruct, A_PtrSize)
    NumPut(&message, CDStruct, 2*A_PtrSize)

    SendMessage, %SHOWNOTIFICATION%, &CDStruct, %timeout%,, %NSW_WinName%
Why do you keep using SHOWNOTIFICATION instead of WM_COPYDATA? To send COPYDATASTRUCT you must only using WM_COPYDATA.
An example:
Sender1.ahk

Code: Select all

DetectHiddenWindows, On
SetTitleMatchMode, 2

if !WinExist("Receiver1.ahk ahk_class AutoHotkey")  {
   Run, %A_ScriptDir%\Receiver1.ahk
   WinWait, Receiver1.ahk ahk_class AutoHotkey
}
hWnd := WinExist()

Notify("Hello from Sender1.ahk!", hWnd)

Notify(string, hWnd)  {
   VarSetCapacity(message, size := StrPut(string, "UTF-16")*2, 0)
   StrPut(string, &message, "UTF-16")
   
   VarSetCapacity(COPYDATASTRUCT, A_PtrSize*3)
   NumPut(size, COPYDATASTRUCT, A_PtrSize, "UInt")
   NumPut(&message, COPYDATASTRUCT, A_PtrSize*2)
   
   DllCall("SendMessage", Ptr, hWnd, UInt, WM_COPYDATA := 0x4A, Ptr, 0, Ptr, &COPYDATASTRUCT)
}
Receiver1.ahk

Code: Select all

OnMessage(0x4A, "WM_COPYDATA")
Return

WM_COPYDATA(wp, lp)  {
; don't work with data here, only read it and immediately return true
   string := StrGet(NumGet(lp + A_PtrSize*2), "UTF-16")
   timer := Func("DataHandling").Bind(string)
   SetTimer, % timer, -10
   Return true
}

DataHandling(data)  {
   MsgBox, % data
}
However, you could send a pointer, like in your first script, but to get data, you need to read memory of the process, which contains it:
Sender2.ahk

Code: Select all

DetectHiddenWindows, On
SetTitleMatchMode, 2

if !WinExist("Receiver2.ahk ahk_class AutoHotkey")  {
   Run, %A_ScriptDir%\Receiver2.ahk
   WinWait, Receiver2.ahk ahk_class AutoHotkey
}
hWnd := WinExist()

Notify("Hello from Sender2.ahk!", hWnd)

Notify(string, hWnd)  {
   static MyPID := DllCall("GetCurrentProcessId")
   VarSetCapacity(message, size := StrPut(string, "UTF-16")*2, 0)
   StrPut(string, &message, "UTF-16")
   DllCall("SendMessage", Ptr, hWnd, UInt, SHOWNOTIFICATION := 0xF505, Ptr, &message, Ptr, (size << 16)|MyPID)
}
Receiver2.ahk

Code: Select all

OnMessage(0xF505, "ReadData")
Return

ReadData(wp, lp)  {
; don't work with data here, only read it and immidiately return true
   pData := wp
   senderPID := lp & 0xFFFF
   dataSize := lp >> 16
   
   if !hProcess := DllCall("OpenProcess", UInt, PROCESS_VM_READ := 0x10, UInt, 0, UInt, senderPID, Ptr)  {
      MsgBox, Failed to open process. Error: %A_LastError%
      Return
   }
   VarSetCapacity(buff, dataSize, 0)
   if (!DllCall("ReadProcessMemory", Ptr, hProcess, Ptr, pData, Ptr, &buff, Ptr, dataSize, PtrP, read) && error := true)
      MsgBox, Failed to read process memory. Error: %A_LastError%
   DllCall("CloseHandle", Ptr, hProcess)
   if error
      Return
   
   string := StrGet(&buff, "UTF-16")
   timer := Func("SHOWNOTIFICATION").Bind(string)
   SetTimer, % timer, -10
   Return true
}

SHOWNOTIFICATION(string)  {
   MsgBox, % string
}

User avatar
KuroiLight
Posts: 327
Joined: 12 Apr 2015, 20:24
Contact:

Re: Script crashing, assuming access violation, not sure.

Post by KuroiLight » 27 Dec 2017, 13:52

@teadrinker
The MSDN states "Contains data to be passed to another application by the WM_COPYDATA message., I guess I assumed this wasn't a hard requirement and I can't seem to find any info on whether or not the message codes are significant beyond being an identifier. Do you know of a doc/tutorial about this?
What you posted makes more sense, I will try that.
@BoBo lol
Windows 10, Ryzen 1600, 16GB G.Skill DDR4, 8GB RX 480 | [MyScripts][MySublimeSettings] [Unlicense][MIT License]
01/24/18
[/color]

User avatar
KuroiLight
Posts: 327
Joined: 12 Apr 2015, 20:24
Contact:

Re: Script crashing, assuming access violation, not sure.

Post by KuroiLight » 27 Dec 2017, 14:55

Ok changing the message to WM_COPYDATA worked.
In-case anyone is wondering here's what I ended up with:
CNS.ahk

Code: Select all

;Centralized Notification System
;Version: 1.0
;Author: KuroiLight/klomb
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

#Include %A_ScriptDIr%\includes\CommonCode.ahk
#NoEnv
#SingleInstance, force
#Persistent

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

DetectHiddenWindows, On
SCRIPT_TITLE := "NotificationOperator - 0xF505 @ ZZ9PZA"
if(WinExist(SCRIPT_TITLE))
    WinKill
WinSetTitle, ahk_id %A_ScriptHwnd%,, %SCRIPT_TITLE%

RemainingTick := 0
TickSize := 250
Notification_Visible := false
Notify_Window := 0x0

BgColor := "282828"
FrColor := "EEEEEE"
FontSize := "12"

OnMessage(WM_COPYDATA, "_WM_COPYDATA")
SetTimer, Hide_Notification, %TickSize%

Initialize()

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
return

Initialize() {
    global base_x, base_y

    if(WinExist("ahk_class Shell_TrayWnd")) {
        WinGetPos, shell_x, shell_y, shell_w, shell_h, ahk_class Shell_TrayWnd
        base_x := shell_x + shell_w
        base_y := shell_y
    } else {
        SysGet, Primary_M, MonitorPrimary
        SysGet, Monitor_, Monitor, %Primary_M%
        base_x := Monitor_Right
        base_y := Monitor_Left
    }

    base_x -= 10
    base_y -= 10
}

Hide_Notification() {
    global RemainingTick, Notification_Visible, Notify_Window, TickSize
    if(!Notify_Window)
        return

    if(RemainingTick >= 1) {
        RemainingTick -= TickSize
    } else {
        if(Notification_Visible) {
            Gui, %Notify_Window%: Hide
            Notification_Visible := false
        }
    }
}

_WM_COPYDATA(wParam, lParam, msg, hwnd) {
    message_raw := StrGet(NumGet(lParam + 2*A_PtrSize))
    if(RegExMatch(message_raw, "iS)(?P<timeout>\d+)\:(?P<message>.+)", data_))
        AsyncFunction("Show_Notification", [data_message, data_timeout]*)
    return 1
}

Show_Notification(message, timeout) {
    Critical
    if(!timeout or !message)
        return 0

    global RemainingTick, Notification_Visible, Notify_Window, MainLbl, base_x, base_y
    global BgColor, FrColor, FontSize
    RemainingTick := timeout

    if(!Notify_Window) {
        Gui, New, +AlwaysOnTop +Border -Caption -Resize +ToolWindow +HwndNotify_Window, %SCRIPT_TITLE%
        Gui, %Notify_Window%: Color, %BgColor%
        Gui, %Notify_Window%: Font, c%FrColor% s%FontSize%
        Gui, %Notify_Window%: Margin, 5, 5
        Gui, %Notify_Window%: Add, Text, +HwndMainLbl, %message%
        if(!Notify_Window)
            Throw, "Failure to create GUI."
    } else {
        DllCall("User32\DestroyWindow", "UInt", MainLbl)
        Gui, %Notify_Window%: Add, Text, X5 Y5 +HwndMainLbl, %message%
    }

    Gui, %Notify_Window%: Show, Hide AutoSize NoActivate
    WinGetPos,,, N_W, N_H, ahk_id %Notify_Window%
    New_X := base_x - N_W
    New_Y := base_y - N_H
    Gui, %Notify_Window%: Show, AutoSize NoActivate X%New_X% Y%New_Y%
    return (Notification_Visible := true)
}
Notify function

Code: Select all

Notify(message, timeout := 2500) {
    static NSW_WinName := "NotificationOperator - 0xF505 @ ZZ9PZA", script_local := ""
    A_DHW := A_DetectHiddenWindows
    DetectHiddenWindows, On

    if(!WinExist(NSW_WinName)) {
        if(!script_local) {
            for i, v in Array("\lib\CNS.ahk", "\CNS.ahk", "\..\CNS.ahk")
                if(FileExist(A_ScriptDir . v))
                    script_local := A_ScriptDir . v
        }

        Run, %script_local%, UseErrorLevel,
        if(ErrorLevel != 0) {
            ToolTip, %message%, 0, 0
            return
        } else {
            WinWait, %NSW_WinName%,, 2
            if(ErrorLevel == 1) {
                ToolTip, %message%, 0, 0
                return
            }
        }
    }

    message := timeout . ":" . message
    VarSetCapacity(CDStruct, 3*A_PtrSize, 0)
    NumPut((StrLen(message) + 1) * (A_IsUnicode ? 2 : 1), CDStruct, A_PtrSize)
    NumPut(&message, CDStruct, 2*A_PtrSize)
    SendMessage, %WM_COPYDATA%, %A_ScriptHwnd%, &CDStruct,, %NSW_WinName%

    DetectHiddenWindows, %A_DHW%
}
Windows 10, Ryzen 1600, 16GB G.Skill DDR4, 8GB RX 480 | [MyScripts][MySublimeSettings] [Unlicense][MIT License]
01/24/18
[/color]

teadrinker
Posts: 4331
Joined: 29 Mar 2015, 09:41
Contact:

Re: Script crashing, assuming access violation, not sure.

Post by teadrinker » 28 Dec 2017, 00:42

KuroiLight wrote:I guess I assumed this wasn't a hard requirement and I can't seem to find any info on whether or not the message codes are significant beyond being an identifier. Do you know of a doc/tutorial about this?
A message identifier defines what an application should do when receives that message, and what values of message parameters mean. You could read about messages here.

Post Reply

Return to “Ask for Help (v1)”