Jump to content

Lable text clickable


Recommended Posts

I am doing 2 things here.

1. If VLC found on the machine then the Text will appear in the Form.

2. If VLC text shows up, and if I click on the text, it should give a message. If VLC text is hidden, the msgbox should not auto pop-up.

Can someone please help in getting this fixed?

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

Global $VLC, $filepath

Func VLC()
$filepath = 'C:\Program Files (x86)\VideoLAN\VLC\vlc.exe'
If FileExists($filepath) Then
$VLC = GUICtrlCreateLabel("VLC", 176, 48, 41, 25)
GUICtrlSetFont(-1, 14, 400, 0, "Times New Roman")
GUICtrlSetState($VLC, $GUI_SHOW)
Else
GUICtrlSetState($VLC, $GUI_HIDE)
EndIf
EndFunc

#Region ### START Koda GUI section ### Form=
$Form2 = GUICreate("Form1", 388, 142, 750, 373)
VLC()
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit

        Case $VLC
            MsgBox(0, '', $filepath)
    EndSwitch
WEnd

 

Link to comment
Share on other sites

How about you move that create label before the if check? 

Func VLC()
$filepath = 'C:\Program Files (x86)\VideoLAN\VLC\vlc.exe'
$VLC = GUICtrlCreateLabel("VLC", 176, 48, 41, 25) ;create the label before if
If FileExists($filepath) Then
GUICtrlSetFont(-1, 14, 400, 0, "Times New Roman")
GUICtrlSetState($VLC, $GUI_SHOW)
Else
GUICtrlSetState($VLC, $GUI_HIDE)
EndIf
EndFunc

 

TY.

Link to comment
Share on other sites

I know your question has been solved but here's another one for you. It's a lot more complex and you may not understand it but you may find it useful in the future. (to create hyperlink looking labels)

#include <GUIConstants.au3>
#include <WinAPIShellEx.au3>

Global Const $sStructFormat = "struct;int iCtrlId;char path[256];endstruct"
Enum $idProcLabel = 9999
Global $hMain = GUICreate("Example")
Global $lblVlc = GUICtrlCreateLabel("VLC", 10, 10, 50, 25)
GUICtrlSetFont(-1, 12, 400, "", "Segoe UI")
Global $lblIE = GUICtrlCreateLabel("Internet Explorer", 10, 45, 150, 25)
GUICtrlSetFont(-1, 12, 400, "", "Segoe UI")
Global $lblGoogle = GUICtrlCreateLabel("https://www.google.com", 10, 80, 175, 25)
GUICtrlSetFont(-1, 12, 400, 4, "Segoe UI")
GUICtrlSetColor(-1, 0x0066CC)
Global $hLblVlc = GUICtrlGetHandle($lblVlc)
Global $hLblIE = GUICtrlGetHandle($lblIE)
Global $hLblGoogle = GUICtrlGetHandle($lblGoogle)
Global $hNewWindowProc = DllCallbackRegister("NewWindowProc", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr")
Global $pNewWindowProc = DllCallbackGetPtr($hNewWindowProc)

; How the DLLStructGetPtr thing works:
;   First call the CreateLabelStruct to create a struct with the ID of the label and the corresponding path to execute
;   Then get a pointer to it and use that in the $dwRefData of the NewWindowProc function
; Subclass the VLC label
_WinAPI_SetWindowSubclass($hLblVlc, $pNewWindowProc, $idProcLabel, DllStructGetPtr(CreateLabelStruct($lblVlc, "C:\Program Files (x86)\VideoLAN\VLC\vlc.exe")))
; Subclass the IE label
_WinAPI_SetWindowSubclass($hLblIE, $pNewWindowProc, $idProcLabel, DllStructGetPtr(CreateLabelStruct($lblIE, @ProgramFilesDir & "\Internet Explorer\iexplore.exe")))
; Subclass the google label
_WinAPI_SetWindowSubclass($hLblGoogle, $pNewWindowProc, $idProcLabel, DllStructGetPtr(CreateLabelStruct($lblGoogle, "https://www.google.com")))

GUISetState(@SW_SHOW, $hMain)

While (True)
    Switch (GUIGetMsg())
        Case $GUI_EVENT_CLOSE
            _WinAPI_RemoveWindowSubclass($hLblVlc, $pNewWindowProc, $idProcLabel)
            _WinAPI_RemoveWindowSubclass($hLblIE, $pNewWindowProc, $idProcLabel)
            _WinAPI_RemoveWindowSubclass($hLblGoogle, $pNewWindowProc, $idProcLabel)
            Exit 0
    EndSwitch
WEnd

; Create and return a struct with the Control ID and the path for this control
Func CreateLabelStruct(Const $iCtrlId, Const $sPath)
    Local $tReturn = DllStructCreate($sStructFormat)
    DllStructSetData($tReturn, 1, $iCtrlId)
    DllStructSetData($tReturn, 2, $sPath)
    Return $tReturn
EndFunc

; Window Procedure
Func NewWindowProc($hWnd, $iMsg, $wParam, $lParam, $uIdSubclass, $dwRefData)
    #forceref $hWnd, $iMsg, $wParam, $lParam, $uIdSubclass, $dwRefData
    Local $tData = DllStructCreate($sStructFormat, $dwRefData)

    ; If the subclass ID is the label
    Switch ($uIdSubclass)
        Case $idProcLabel
            ; Switch on the window message
            Switch ($iMsg)
                ; User left clicked
                Case $WM_LBUTTONUP
                    ; If the file exists or it's a valid URL
                    If (FileExists(DllStructGetData($tData, 2)) or _WinAPI_UrlIs(DllStructGetData($tData, 2))) Then ShellExecute(DllStructGetData($tData, 2))
                ; User right clicked
                Case $WM_RBUTTONUP
                    ; If the file exists or it's a valid URL
                    If (FileExists(DllStructGetData($tData, 2)) or _WinAPI_UrlIs(DllStructGetData($tData, 2))) Then ClipPut(DllStructGetData($tData, 2))
                ; User hovered over the label
                Case $WM_SETCURSOR
                    ; If the file exists or it's a valid URL
                    If (FileExists(DllStructGetData($tData, 2)) or _WinAPI_UrlIs(DllStructGetData($tData, 2))) Then GUICtrlSetCursor(DllStructGetData($tData, 1), 0)
            EndSwitch
    EndSwitch

    Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>NewWindowProc

A lot more complex but essentially I created a struct using the control id and a path for that control (first two used local files, third uses google.com) and then use a pointer to that struct for the subclass. (This is retrieved in the $dwRefData in the NewWindowProc function. I use this to re-create the same struct to get the data for that label, without having to create a case for each label in the NewWindowProc function)

A simpler method would be to have a switch based on the $hWnd (This will correspond to the $hLbl* values where I got the GUICtrlGetHandle). But storing everything I need in a struct that will never be used outside of the NewWindowProc function looks cleaner and requires less lines of code!

Edited by InunoTaishou
Forgot to call _WinApi_RemoveWindowSubclass for each label
Link to comment
Share on other sites

@InunoTaishou thanks for sharing, should the Internet Explorer label open Internet Explorer or have I read it wrong, I thought this could be useful in a project I'm working on for opening third-party apps but it didn't appear to do anything?  For Internet labels I've always used the following:

#include <GUIConstants.au3>

$hMain = GUICreate("Example")
$lblGoogle = GUICtrlCreateLabel("https://www.google.com", 10, 80, 175, 25)
    GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)
    GUICtrlSetFont(-1, 12, 400, 4, "Segoe UI")
    GUICtrlSetColor(-1, 0x0066CC)
    GUICtrlSetCursor(-1, 0)

GUISetState()

While 1
    Switch (GUIGetMsg())
        Case $GUI_EVENT_CLOSE
            Exit 0
        Case $lblGoogle
            ShellExecute(GUICtrlRead($lblGoogle))
    EndSwitch
WEnd

 

Link to comment
Share on other sites

The Internet Explorer just opens internet explorer (at least it should, unless your iexplorer.exe is in a different path). It will only execute the ShellExecute if the file exists or it's a valid URL. I set the path to iexplorer.exe when I did the second second call to _WinApi_SetWindowSubclass.

With my subclassing example you can set the label text to be whatever you want, you set the path to execute in the struct. It's exactly like creating a hyperlink (which is the whole reason why I created that in the first place, I wanted a hyperlink looking label and didn't want to create a richedit label). A quick look at the 4th parameter for _WinApi_SetWindowSubclass is

Quote
$pData [optional] The reference data. This value is passed to the subclass procedure. The meaning of this value is determined by the calling application.

It will take a pointer (or int value, I mention this because in the past I've done the same thing except used the control id returned from GUICtrlCreate*). What this means is you can create a struct and set the data in the struct, get a pointer to that struct and then use that for you $pData, and you won't have to keep a global variable of that data. You could get pretty crazy with something like this. Even storing some kind of function call in the struct or even execute a whole script when you click a label, or hover over a picture. (Although you'll be limited to the size of one char array in the struct, anything over [266] and I get errors. But this could be overcome by having multiple char arrays in the struct and combining them all)

This is what I mean

#include <GUIConstants.au3>
#include <WinAPIShellEx.au3>

Global Const $sStructFormat = "struct;int iCtrlId;char data[256];endstruct"
Enum $idProcLabel = 9999
Global $hMain = GUICreate("Example")
Global $lblMsgBox = GUICtrlCreateLabel("MsgBox Example", 10, 10, 150, 25)
GUICtrlSetFont(-1, 12, 400, "", "Segoe UI")
Global $lblPingExample = GUICtrlCreateLabel("Ping Example", 10, 45, 150, 25)
GUICtrlSetFont(-1, 12, 400, "", "Segoe UI")
Global $hLblMsgBox = GUICtrlGetHandle($lblMsgBox)
Global $hLblPing = GUICtrlGetHandle($lblPingExample)
Global $hNewWindowProc = DllCallbackRegister("NewWindowProc", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr")
Global $pNewWindowProc = DllCallbackGetPtr($hNewWindowProc)

_WinAPI_SetWindowSubclass($hLblMsgBox, $pNewWindowProc, $idProcLabel, DllStructGetPtr(CreateLabelStruct($lblMsgBox, "MsgBox::64||Example||This is an example call to a function inside my subclass")))
_WinAPI_SetWindowSubclass($hLblPing, $pNewWindowProc, $idProcLabel, DllStructGetPtr(CreateLabelStruct($lblPingExample, "Run::" & @ComSpec & " /c ping -t www.google.com")))

GUISetState(@SW_SHOW, $hMain)

While (True)
    Switch (GUIGetMsg())
        Case $GUI_EVENT_CLOSE
            _WinAPI_RemoveWindowSubclass($hLblMsgBox, $pNewWindowProc, $idProcLabel)
            _WinAPI_RemoveWindowSubclass($hLblPing, $pNewWindowProc, $idProcLabel)
            Exit 0
    EndSwitch
WEnd

; Create and return a struct with the Control ID and the path for this control
Func CreateLabelStruct(Const $iCtrlId, Const $sPath)
    Local $tReturn = DllStructCreate($sStructFormat)
    DllStructSetData($tReturn, 1, $iCtrlId)
    DllStructSetData($tReturn, 2, $sPath)
    Return $tReturn
EndFunc   ;==>CreateLabelStruct

; Window Procedure
Func NewWindowProc($hWnd, $iMsg, $wParam, $lParam, $uIdSubclass, $dwRefData)
    #forceref $hWnd, $iMsg, $wParam, $lParam, $uIdSubclass, $dwRefData
    Local $tData = DllStructCreate($sStructFormat, $dwRefData)

    ; If the subclass ID is the label
    Switch ($uIdSubclass)
        Case $idProcLabel
            ; Switch on the window message
            Switch ($iMsg)
                ; User left clicked
                Case $WM_LBUTTONUP
                    ConsoleWrite(DllStructGetData($tData, 2) & @LF)
                    Local $aSplit = StringSplit(DllStructGetData($tData, 2), "::", $STR_NOCOUNT + $STR_ENTIRESPLIT)
                    If (Not @error) Then
                        Local $sFunction = $aSplit[0]
                        Local $aParams = StringSplit("CallArgArray||" & $aSplit[1], "||", $STR_NOCOUNT + $STR_ENTIRESPLIT)
                        Call($sFunction, $aParams)
                    EndIf
                    ; User right clicked
                Case $WM_RBUTTONUP
                    ; If the file exists or it's a valid URL
                    ;If (FileExists(DllStructGetData($tData, 2)) or _WinAPI_UrlIs(DllStructGetData($tData, 2))) Then ClipPut(DllStructGetData($tData, 2))
                    ; User hovered over the label
                Case $WM_SETCURSOR
                    ; If the file exists or it's a valid URL
                    ;If (FileExists(DllStructGetData($tData, 2)) or _WinAPI_UrlIs(DllStructGetData($tData, 2))) Then GUICtrlSetCursor(DllStructGetData($tData, 1), 0)
            EndSwitch
    EndSwitch

    Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>NewWindowProc

Since AutoIt doesn't have pointers to functions I have to use Call. I chose to have the parameters follow the double semicolon (double to allow my arguments to have a semicolon), then when I do the call to StringSplit on the parameters, I put the special string at the beginning to let the Call function know I'm gonna pass an array for parameters (since I don't know how many there might be) and split using double pipe (||, to allow my arguments to have a single pipe without interfering with the call)

Edited by InunoTaishou
Link to comment
Share on other sites

Thanks for the explanation, I just get STX in console when I run the code above, was expecting msgbox, with your first code the issue with IE was the code behaviour if I opened Google (Chrome) it wouldn't open IE, if I opened IE it wouldn't open Google (Chrome).  However this only happens every three or four attempts.

Link to comment
Share on other sites

(I copied and pasted the wrong code, just updated it)

Could be the OS? I've got Windows 10 x64 and [256] for my char array hasn't failed. Strange though, it's just a string to the path to IE. Try doing a ConsoleWrite of the DLLStructGetData($tData, 2) in the example where I have IE and see what path it gives.

Link to comment
Share on other sites

Thanks Msgbox code is now working and cmd.

It seems that the IE code is losing it's data, for example:

Case $WM_RBUTTONUP
    ConsoleWrite(DLLStructGetData($tData, 2) & @CRLF)

Results - Alternate Right Clicking on IE and Google labels returns any of the following, usually first time is always correct although I sometimes receive eot in which case nothing works.

C:\Program Files (x86)\Internet Explorer\iexplore.exe
https://www.google.com
s://www.google.com
www.google.com
google.com
le.com
eot
e

Windows 10 Enterprise x64 32GB Ram

Link to comment
Share on other sites

Ah i had that same issue when i went over 256 in the array.

Try reducing the array until it works properly. Lmk what number you get to where it works. Would be useful info to have for anyone using struct on Windows 10 x64 and x86

It's strange that it happens in the first place though. Makes me wonder if there's some limitation of DLLStructCreate or if it's a memory issue when using the Subclass. If I remember correctly the maximum size an array should be somewhere around 2^16 bytes, which should be a pretty large number, and since I used char (not wchar) that's a 65k byte array. I wouldn't think it'd be the $dwRefData since it's just a pointer to the internal memory address of the application that holds the struct with the data. I'm wondering where the data is getting jumbled/lost/corrupt.

Maybe one of the more experienced AutoIt VIPs could chime in a bit more about char[] structs.

 

Side note:

Went around to find the snippit. I said it doesn't have to be a pointer to a struct, you can use an int or a handle too. Here's the snippit where I subclass labels and make them send their messages to the corresponding checkbox instead. I pass the handle to the checkbox as the $dwRefData because I used _SendMessage but you can pass the control id as the $dwRefData and interact with the control using GUICtrl* functions

 

Edited by InunoTaishou
Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...