bootybay

How to prevent multiple GUIs from combining in the taskbar?

14 posts in this topic

There is a main GUI and some secondary GUIs. I want to prevent the secondary GUIs to combine with the main GUI in the taskbar.

The secondary GUIs can stack with eachother in the taskbar as usual.

Is this even possible or does Windows not allow it since it is a single process?

If the question is unclear, tell me what I should specify.

Share this post


Link to post
Share on other sites



Are you talking about interfacing with another GUI here or one that you're creating via Autoit?

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

No just multiple GUIs created via Autoit.

Imagine a main window with some information and some buttons.

There will spawn more GUI windows with detailed info depending on what you used the specific functions on.

And I don't want those additional windows to be combined in the taskbar with the main window.

I want them to split as if the main windows and the secondary windows are 2 different applications.

So it basically looks like this with all windows stacking together: 49fce0acf03677f30b5950f317fb8e9c.png

But I would like the main window be seperated like this: fca50d2f6203a1be9387c2fa7dc751aa.png

(The SciTE icon represents the main window and the autoit Icon the secondary windows. Everything from the same .au3)

Edited by bootybay

Share this post


Link to post
Share on other sites

I think that's just Win 7 behavior for when a given process has multiple windows.  The only way I know of not having overlapped icons like that is to have separate processes with unique process names. There may be a way to do what you want, but I don't know how other than having a second process handle the secondary windows.

Anyone else know another method to accomplish what bootybay wants?
 

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

Spend a few minutes to search the internet and found this article by Microsoft:

https://msdn.microsoft.com/en-us/magazine/dd942846.aspx

According to it, your problem can be solve if you are using Windows 7 or later, using its new 'Taskbar Button' feature. It seems that you are currently using Windows 7, so all we need to do is start writting (porting) code. Yep, porting 6 lines of code in C++ to AutoIt

PROPVARIANT pv;
InitPropVariantFromString(L"MyAppID", &pv);

IPropertyStore* pps;
VERIFY(SHGetPropertyStoreForWindow(hwnd, IID_PPV_ARGS(&pps)));
VERIFY(pps->SetValue(PKEY_AppUserModel_ID, pv));
VERIFY(pps->Commit());

Unluckily, its not easy as it seems to be. Using COM interface in C++ is fast and easy but convert to AutoIt is quite complex. But thanks to tracexx's great ObjCreateInterface function, we can do it much easier. But since it is an experimental function, we want a fallback, which is the boring work. Addition to that, a function is inlined so we cannot using DllCall but rewrite from C++ source. Not much difficult but take a little more time.

But here is all you need:

#include <StructureConstants.au3>
#include <WinAPI.au3>

Global Enum $VT_EMPTY, $VT_NULL, $VT_I2, $VT_I4, $VT_R4, $VT_R8, _
        $VT_CY, $VT_DATE, $VT_BSTR, $VT_DISPATCH, $VT_ERROR, _
        $VT_BOOL, $VT_VARIANT, $VT_UNKNOWN, $VT_DECIMAL, _
        $VT_I1 = 16, $VT_UI1, $VT_UI2, $VT_UI4, $VT_I8, $VT_UI8, $VT_INT, $VT_UINT, _
        $VT_VOID, $VT_HRESULT, $VT_PTR, $VT_SAFEARRAY, $VT_CARRAY, $VT_USERDEFINED, _
        $VT_LPSTR, $VT_LPWSTR, _
        $VT_RECORD = 36, $VT_INT_PTR, $VT_UINT_PTR, _
        $VT_FILETIME = 64, $VT_BLOB, $VT_STREAM, $VT_STORAGE, _
        $VT_STREAMED_OBJECT, $VT_STORED_OBJECT, $VT_BLOB_OBJECT, _
        $VT_CF, $VT_CLSID, $VT_VERSIONED_STREAM, $VT_BSTR_BLOB = 0XFFF, _
        $VT_VECTOR = 0X1000, $VT_ARRAY = 0X2000, $VT_BYREF = 0X4000, $VT_RESERVED = 0X8000, _
        $VT_ILLEGAL = 0XFFFF, $VT_ILLEGALMASKED = 0XFFF, $VT_TYPEMASK = 0XFFF

Global $tagPROPVARIANT = 'USHORT vt;' & _ ;typedef unsigned short VARTYPE; - in WTypes.h
        'WORD wReserved1;' & _
        'WORD wReserved2;' & _
        'WORD wReserved3;' & _
        'LONG;PTR'  ;union, use the largest member (BSTRBLOB, which is 96-bit in x64)

Global Const $tagPROPERTYKEY = $tagGUID & ';DWORD pid'

; Optinal setting. Default to True (use newer, experimental method). Set to False to use old, stupid but safe method.
Global Const $__OPT_EXPERIMENTAL_OBJCREATEINTERFACE = True

; This function is not exposed in any dll, but inlined in propvarutil.h so we need to rewrite it entirely in AutoIt
Func _WinAPI_InitPropVariantFromString($sUnicodeString, ByRef $tPROPVARIANT)
    Static $nPropVariantDataIndex = 8
    ; = DllStructGetSize(DllStructCreate('USHORT vt;WORD wReserved1;WORD wReserved2;WORD wReserved3'))

    DllStructSetData($tPROPVARIANT, 'vt', $VT_LPWSTR)
    Local $aRet = DllCall('Shlwapi.dll', 'LONG', 'SHStrDupW', _
            'WSTR', $sUnicodeString, 'PTR', DllStructGetPtr($tPROPVARIANT) + $nPropVariantDataIndex)

    If @error Then Return SetError(@error, @extended, False)
    Local $bSuccess = $aRet[0] = 0? True : False

    ; If fails, zero memory of the current PROPVARIANT struct
    If (Not $bSuccess) Then $tPROPVARIANT = DllStructCreate($tagPROPVARIANT)
    Return SetExtended($aRet[0], $bSuccess)
EndFunc

Func _WinAPI_SHGetPropertyStoreForWindow($hWnd, $sIID, ByRef $tPointer)
    Local $tIID = _WinAPI_GUIDFromString($sIID)
    Local $pp = IsPtr($tPointer)? $tPointer : DllStructGetPtr($tPointer)
    Local $aRet = DllCall('Shell32.dll', 'LONG', 'SHGetPropertyStoreForWindow', _
            'HWND', $hWnd, 'STRUCT*', $tIID, 'PTR', $pp)
    If @error Then Return SetError(@error, @extended, False)
    Return SetExtended($aRet[0], ($aRet[0] = 0))
EndFunc

Global Const $tagPointer = 'PTR'
Global Const $tagIUnknown = 'PTR QueryInterface;PTR AddRef;PTR Release'
Global Const $tagIPropertyStore = $tagIUnknown & _
        ';PTR GetCount;' & _        ;HRESULT GetCount([Out] DWORD* cProps)
        'PTR GetAt;' & _        ;HRESULT GetAt([In] DWORD iProp, [Out] PROPERTYKEY* pKey)
        'PTR GetValue;' & _     ;HRESULT GetValue([In] PROPERTYKEY& key, [Out] PROPVARIANT * pv)
        'PTR SetValue;' & _     ;HRESULT SetValue([In] PROPERTYKEY& key, [In] PROPVARIANT& propvar)
        'PTR Commit'            ;HRESULT Commit()

Func _Win7Helper_PKEY_AppUserModel_ID()
    Local $tPROPERTYKEY = DllStructCreate($tagPROPERTYKEY)
    ;PKEY_AppUserModel_ID = { {0x9F4C2855, 0x9F79, 0x4B39,
    ;   {0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3}}, 5 }
    _WinAPI_GUIDFromStringEx('{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}', _
            DllStructGetPtr($tPROPERTYKEY))
    DllStructSetData($tPROPERTYKEY, 'pid', 5)
    Return $tPROPERTYKEY
EndFunc

; The application id is an up-to-128-characters string
Func _Win7Helper_SetWindowAppId($hWnd, $sId)
    ; This variable is not change. You can use a global const but a local static is prefered due to it scope
    Local Static $tPROPERTYKEY = _Win7Helper_PKEY_AppUserModel_ID()

    ; Create and int PROPVARIANT variable
    Local $tPROPVARIANT = DllStructCreate($tagPROPVARIANT)
    _WinAPI_InitPropVariantFromString($sId, $tPROPVARIANT)

    ; Now create an instance of IPropertyStore interface. We must pass a void** (pointer to pointer)
    ; We can do it in AutoIt by using a pointer to a struct which have only 1 pointer member.
    Local $tpIPropertyStore = DllStructCreate($tagPointer)
    $ret = _WinAPI_SHGetPropertyStoreForWindow($hWnd, '{886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99}', $tpIPropertyStore)

    ; Retrieve the IPropertyStore pointer from result
    Local $pPropertyStoreObject = DllStructGetData($tpIPropertyStore, 1)

    ; Now we have a pointer to an IPropertyStore object.
    ; If you use a new AutoIt version, thank to elegant ObjCreateInterface by tracexx,;
    ; we can easily call method from the pointer we have
    If ($__OPT_EXPERIMENTAL_OBJCREATEINTERFACE) Then
        Local $oPropertyStoreObject = ObjCreateInterface($pPropertyStoreObject, _
                '{886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99}', _
                'GetCount HRESULT(PTR);GetAt HRESULT(DWORD; PTR);GetValue HRESULT(PTR; PTR);' & _
                'SetValue HRESULT(PTR; PTR);Commit HRESULT()')
        $oPropertyStoreObject.SetValue(DllStructGetPtr($tPROPERTYKEY), DllStructGetPtr($tPROPVARIANT))
        $oPropertyStoreObject.Commit()
    Else
        ; But if you don't want to use an experimental function, we can do it manually
        ; First retrieve the v-table of the object. IPropertyStore is directly inherited from IUnknown
        ; so we have only one v-table data, merge of IUnknown and IPropertyStore,
        ; located at the beginning of the object address
        Local $pIPropertyStore = DllStructGetData(DllStructCreate($tagPointer, $pPropertyStoreObject), 1)
        Local $tIPropertyStore = DllStructCreate($tagIPropertyStore, $pIPropertyStore)
        ; With the v-table, we can call methods (yes we use another advanced function,
        ; but not a beta function so its safe as much as we use it correctly
        ; We simulate a c++ method, first parameter should be pointer to object itself.
        ; SetValue
        DllCallAddress('LONG', DllStructGetData($tIPropertyStore, 'SetValue'), _
                'PTR', $pPropertyStoreObject, _ ; pThis
                'PTR', DllStructGetPtr($tPROPERTYKEY), _
                'PTR', DllStructGetPtr($tPROPVARIANT))
        DllCallAddress('LONG', DllStructGetData($tIPropertyStore, 'Commit'), 'PTR', $pPropertyStoreObject)
    EndIf
EndFunc

; Demo
$hWnd1 = GUICreate('Test1')
$hWnd2 = GUICreate('Test2')
$hWnd3 = GUICreate('Test3')
; The application id should be unique so it not effect any other application.
; Better use a format like MyCompany(orMyName).MyApplication.WindowId
_Win7Helper_SetWindowAppId($hWnd1, 'MyGreatCompany.MyAwesomeApplication.MyElegantWindow1')
_Win7Helper_SetWindowAppId($hWnd2, 'MyGreatCompany.MyAwesomeApplication.OhImNotAWindowImAnAlien')
_Win7Helper_SetWindowAppId($hWnd3, 'MyGreatCompany.MyAwesomeApplication.MyElegantWindow1')
GUISetState(@SW_SHOW, $hWnd1)
GUISetState(@SW_SHOW, $hWnd2)
GUISetState(@SW_SHOW, $hWnd3)

Sleep(10000)
Edited by binhnx
1 person likes this

99 little bugs in the code

99 little bugs!

Take one down, patch it around

117 little bugs in the code!

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

Thank you for your elaborate response.
I have some trouble executing the code though since shows me following errors:

"C:\TEST.au3"(86,47) : error: _WinAPI_SHGetPropertyStoreForWindow() called with Const or expression on ByRef-param(s).
            DllStructGetPtr($tpIPropertyStore))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
"C:\TEST.au3"(45,72) : REF: definition of _WinAPI_SHGetPropertyStoreForWindow().
Func _WinAPI_SHGetPropertyStoreForWindow($hWnd, $sIID, ByRef $tPointer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
C:\TEST.au3 - 1 error(s), 0 warning(s)

And thanks to your formatting I just learned that you can connect multiple lines with underscore.
 
EDIT: Small change made it work:

; Now create an instance of IPropertyStore interface. We must pass a void** (pointer to pointer)
    ; We can do it in AutoIt by using a pointer to a struct which have only 1 pointer member.
    Local $tpIPropertyStore = DllStructCreate($tagPointer)
    Local $DLLtpIPropertyStore = DllStructGetPtr($tpIPropertyStore)
    $ret = _WinAPI_SHGetPropertyStoreForWindow($hWnd, '{886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99}', _
            $DLLtpIPropertyStore)

This is exactly what I was looking for. Thank you very much for making that effort.

I will have to spend some time understanding your code.

Please fix the few lines in your code and I'll mark the topic as solved.

Edited by bootybay

Share this post


Link to post
Share on other sites

Edited :)

I didn't notice that since my AutoIt version can run my script without problems


99 little bugs in the code

99 little bugs!

Take one down, patch it around

117 little bugs in the code!

Share this post


Link to post
Share on other sites

Edited :)

I didn't notice that since my AutoIt version can run my script without problems

 

have no idea what you're saying there lol

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

Edited :)

I didn't notice that since my AutoIt version can run my script without problems

binhnx,

I'd like to get a window's appid by it's hWnd,is it possible?

It would be appreciated if you would add the udf,let's say, _Win7Helper_GetWindowAppId($hWnd).

 

Edited by jackchen

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

If I understand it right ...

I use much simpler way to achieve what OP wants.

I just use hWnd of my main GUI as Parent parameter in GUICreate() of another GUI forms in my application ;-)

The same apply also for standard Win32 dialogs, for example MessageBox() - use your main GUI's hWnd as Parent parameter for it to avoid multiple icons in taskbar.

Edited by Zedna

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

I've added a Func _Win7Helper_GetWindowAppId($hWnd) to binhnx's codes to get a window's AppId.

Func _Win7Helper_GetWindowAppId($hWnd)
    Local Static $tPROPERTYKEY = _Win7Helper_PKEY_AppUserModel_ID()
    Local $tPROPVARIANT = DllStructCreate($tagPROPVARIANT)

    Local $tpIPropertyStore = DllStructCreate('ptr')
    _WinAPI_SHGetPropertyStoreForWindow($hWnd, '{886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99}', $tpIPropertyStore)
    Local $pPropertyStoreObject = DllStructGetData($tpIPropertyStore, 1)
    Local $oPropertyStoreObject = ObjCreateInterface($pPropertyStoreObject, _
            '{886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99}', _
            'GetCount HRESULT(PTR);GetAt HRESULT(DWORD; PTR);GetValue HRESULT(PTR; PTR);' & _
            'SetValue HRESULT(PTR; PTR);Commit HRESULT()')
    If Not IsObj($oPropertyStoreObject) Then Return SetError(1, 0, '')
    $oPropertyStoreObject.GetValue(DllStructGetPtr($tPROPERTYKEY), DllStructGetPtr($tPROPVARIANT))

    ; Extracts a string value from a PROPVARIANT structure
    ; http://deletethis.net/dave/dev/setappusermodelid/
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb776559(v=vs.85).aspx
    Local $buf = DllStructCreate('wchar[128]')
    DllCall('Propsys.dll', 'long', 'PropVariantToString', _
            'ptr', DllStructGetPtr($tPROPVARIANT), _
            'ptr', DllStructGetPtr($buf), _
            'uint', DllStructGetSize($buf))

    If @error Then
        Return SetError(@error, @extended, "")
    Else
        Return DllStructGetData($buf, 1)
    EndIf
EndFunc

 And below is the full codes with examples:

; https://www.autoitscript.com/forum/topic/168099-how-to-prevent-multiple-guis-from-combining-in-the-taskbar/
; http://stackoverflow.com/questions/28228042/shgetpropertystoreforwindow-how-to-set-properties-on-existing-system-appusermo
#include <StructureConstants.au3>
#include <WinAPI.au3>

Global Enum $VT_EMPTY, $VT_NULL, $VT_I2, $VT_I4, $VT_R4, $VT_R8, _
        $VT_CY, $VT_DATE, $VT_BSTR, $VT_DISPATCH, $VT_ERROR, _
        $VT_BOOL, $VT_VARIANT, $VT_UNKNOWN, $VT_DECIMAL, _
        $VT_I1 = 16, $VT_UI1, $VT_UI2, $VT_UI4, $VT_I8, $VT_UI8, $VT_INT, $VT_UINT, _
        $VT_VOID, $VT_HRESULT, $VT_PTR, $VT_SAFEARRAY, $VT_CARRAY, $VT_USERDEFINED, _
        $VT_LPSTR, $VT_LPWSTR, _
        $VT_RECORD = 36, $VT_INT_PTR, $VT_UINT_PTR, _
        $VT_FILETIME = 64, $VT_BLOB, $VT_STREAM, $VT_STORAGE, _
        $VT_STREAMED_OBJECT, $VT_STORED_OBJECT, $VT_BLOB_OBJECT, _
        $VT_CF, $VT_CLSID, $VT_VERSIONED_STREAM, $VT_BSTR_BLOB = 0XFFF, _
        $VT_VECTOR = 0X1000, $VT_ARRAY = 0X2000, $VT_BYREF = 0X4000, $VT_RESERVED = 0X8000, _
        $VT_ILLEGAL = 0XFFFF, $VT_ILLEGALMASKED = 0XFFF, $VT_TYPEMASK = 0XFFF

Global $tagPROPVARIANT = 'USHORT vt;' & _ ;typedef unsigned short VARTYPE; - in WTypes.h
        'WORD wReserved1;' & _
        'WORD wReserved2;' & _
        'WORD wReserved3;' & _
        'LONG;PTR'  ;union, use the largest member (BSTRBLOB, which is 96-bit in x64)

Global Const $tagPROPERTYKEY = $tagGUID & ';DWORD pid'

; Optinal setting. Default to True (use newer, experimental method). Set to False to use old, stupid but safe method.
Global Const $__OPT_EXPERIMENTAL_OBJCREATEINTERFACE = True

; This function is not exposed in any dll, but inlined in propvarutil.h so we need to rewrite it entirely in AutoIt
Func _WinAPI_InitPropVariantFromString($sUnicodeString, ByRef $tPROPVARIANT)
    Static $nPropVariantDataIndex = 8
    ; = DllStructGetSize(DllStructCreate('USHORT vt;WORD wReserved1;WORD wReserved2;WORD wReserved3'))

    DllStructSetData($tPROPVARIANT, 'vt', $VT_LPWSTR)
    Local $aRet = DllCall('Shlwapi.dll', 'LONG', 'SHStrDupW', _
            'WSTR', $sUnicodeString, 'PTR', DllStructGetPtr($tPROPVARIANT) + $nPropVariantDataIndex)

    If @error Then Return SetError(@error, @extended, False)
    Local $bSuccess = $aRet[0] = 0? True : False

    ; If fails, zero memory of the current PROPVARIANT struct
    If (Not $bSuccess) Then $tPROPVARIANT = DllStructCreate($tagPROPVARIANT)
    Return SetExtended($aRet[0], $bSuccess)
EndFunc

Func _WinAPI_SHGetPropertyStoreForWindow($hWnd, $sIID, ByRef $tPointer)
    Local $tIID = _WinAPI_GUIDFromString($sIID)
    Local $pp = IsPtr($tPointer)? $tPointer : DllStructGetPtr($tPointer)
    Local $aRet = DllCall('Shell32.dll', 'LONG', 'SHGetPropertyStoreForWindow', _
            'HWND', $hWnd, 'STRUCT*', $tIID, 'PTR', $pp)
    If @error Then Return SetError(@error, @extended, False)
    Return SetExtended($aRet[0], ($aRet[0] = 0))
EndFunc

Global Const $tagIUnknown = 'PTR QueryInterface;PTR AddRef;PTR Release'
Global Const $tagIPropertyStore = $tagIUnknown & _
        ';PTR GetCount;' & _        ;HRESULT GetCount([Out] DWORD* cProps)
        'PTR GetAt;' & _        ;HRESULT GetAt([In] DWORD iProp, [Out] PROPERTYKEY* pKey)
        'PTR GetValue;' & _     ;HRESULT GetValue([In] PROPERTYKEY& key, [Out] PROPVARIANT * pv)
        'PTR SetValue;' & _     ;HRESULT SetValue([In] PROPERTYKEY& key, [In] PROPVARIANT& propvar)
        'PTR Commit'            ;HRESULT Commit()

Func _Win7Helper_PKEY_AppUserModel_ID()
    Local $tPROPERTYKEY = DllStructCreate($tagPROPERTYKEY)
    ;PKEY_AppUserModel_ID = { {0x9F4C2855, 0x9F79, 0x4B39,
    ;   {0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3}}, 5 }
    _WinAPI_GUIDFromStringEx('{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}', _
            DllStructGetPtr($tPROPERTYKEY))
    DllStructSetData($tPROPERTYKEY, 'pid', 5)
    Return $tPROPERTYKEY
EndFunc

; The application id is an up-to-128-characters string
Func _Win7Helper_SetWindowAppId($hWnd, $sId)
    ; This variable is not change. You can use a global const but a local static is prefered due to it scope
    Local Static $tPROPERTYKEY = _Win7Helper_PKEY_AppUserModel_ID()

    ; Create and int PROPVARIANT variable
    Local $tPROPVARIANT = DllStructCreate($tagPROPVARIANT)
    _WinAPI_InitPropVariantFromString($sId, $tPROPVARIANT)

    ; Now create an instance of IPropertyStore interface. We must pass a void** (pointer to pointer)
    ; We can do it in AutoIt by using a pointer to a struct which have only 1 pointer member.
    Local $tpIPropertyStore = DllStructCreate('PTR')
    $ret = _WinAPI_SHGetPropertyStoreForWindow($hWnd, '{886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99}', $tpIPropertyStore)

    ; Retrieve the IPropertyStore pointer from result
    Local $pPropertyStoreObject = DllStructGetData($tpIPropertyStore, 1)

    ; Now we have a pointer to an IPropertyStore object.
    ; If you use a new AutoIt version, thank to elegant ObjCreateInterface by tracexx,;
    ; we can easily call method from the pointer we have
    If ($__OPT_EXPERIMENTAL_OBJCREATEINTERFACE) Then
        Local $oPropertyStoreObject = ObjCreateInterface($pPropertyStoreObject, _
                '{886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99}', _
                'GetCount HRESULT(PTR);GetAt HRESULT(DWORD; PTR);GetValue HRESULT(PTR; PTR);' & _
                'SetValue HRESULT(PTR; PTR);Commit HRESULT()')
        If Not IsObj($oPropertyStoreObject) Then Return SetError(1, 0, '')
        $oPropertyStoreObject.SetValue(DllStructGetPtr($tPROPERTYKEY), DllStructGetPtr($tPROPVARIANT))
        $oPropertyStoreObject.Commit()
    Else
        ; But if you don't want to use an experimental function, we can do it manually
        ; First retrieve the v-table of the object. IPropertyStore is directly inherited from IUnknown
        ; so we have only one v-table data, merge of IUnknown and IPropertyStore,
        ; located at the beginning of the object address
        Local $pIPropertyStore = DllStructGetData(DllStructCreate('PTR', $pPropertyStoreObject), 1)
        Local $tIPropertyStore = DllStructCreate($tagIPropertyStore, $pIPropertyStore)
        ; With the v-table, we can call methods (yes we use another advanced function,
        ; but not a beta function so its safe as much as we use it correctly
        ; We simulate a c++ method, first parameter should be pointer to object itself.
        ; SetValue
        DllCallAddress('LONG', DllStructGetData($tIPropertyStore, 'SetValue'), _
                'PTR', $pPropertyStoreObject, _ ; pThis
                'PTR', DllStructGetPtr($tPROPERTYKEY), _
                'PTR', DllStructGetPtr($tPROPVARIANT))
        DllCallAddress('LONG', DllStructGetData($tIPropertyStore, 'Commit'), 'PTR', $pPropertyStoreObject)
    EndIf
EndFunc


Func _Win7Helper_GetWindowAppId($hWnd)
    Local Static $tPROPERTYKEY = _Win7Helper_PKEY_AppUserModel_ID()
    Local $tPROPVARIANT = DllStructCreate($tagPROPVARIANT)

    Local $tpIPropertyStore = DllStructCreate('ptr')
    _WinAPI_SHGetPropertyStoreForWindow($hWnd, '{886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99}', $tpIPropertyStore)
    Local $pPropertyStoreObject = DllStructGetData($tpIPropertyStore, 1)
    Local $oPropertyStoreObject = ObjCreateInterface($pPropertyStoreObject, _
            '{886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99}', _
            'GetCount HRESULT(PTR);GetAt HRESULT(DWORD; PTR);GetValue HRESULT(PTR; PTR);' & _
            'SetValue HRESULT(PTR; PTR);Commit HRESULT()')
    If Not IsObj($oPropertyStoreObject) Then Return SetError(1, 0, '')
    $oPropertyStoreObject.GetValue(DllStructGetPtr($tPROPERTYKEY), DllStructGetPtr($tPROPVARIANT))

    ; Extracts a string value from a PROPVARIANT structure
    ; http://deletethis.net/dave/dev/setappusermodelid/
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb776559(v=vs.85).aspx
    Local $buf = DllStructCreate('wchar[128]')
    DllCall('Propsys.dll', 'long', 'PropVariantToString', _
            'ptr', DllStructGetPtr($tPROPVARIANT), _
            'ptr', DllStructGetPtr($buf), _
            'uint', DllStructGetSize($buf))

    If @error Then
        Return SetError(@error, @extended, "")
    Else
        Return DllStructGetData($buf, 1)
    EndIf
EndFunc

#cs
; SetCurrentProcessExplicitAppUserModelID
DllCall("Shell32.dll", "long", "SetCurrentProcessExplicitAppUserModelID", _
        "wstr", "MyGreatCompany.MyAwesomeApplication.MyElegantWindow1")
#ce


; Demo
$hWnd1 = GUICreate('Test1', 400, 200, 0, 100)
$hWnd2 = GUICreate('Test2', 400, 200, 500, 100)
$hWnd3 = GUICreate('Test3', 400, 200, 1000, 100)
; The application id should be unique so it not effect any other application.
; Better use a format like MyCompany(orMyName).MyApplication.WindowId
_Win7Helper_SetWindowAppId($hWnd1, 'MyGreatCompany.MyAwesomeApplication.MyElegantWindow1')
_Win7Helper_SetWindowAppId($hWnd2, 'MyGreatCompany.MyAwesomeApplication.OhImNotAWindowImAnAlien')
_Win7Helper_SetWindowAppId($hWnd3, 'MyGreatCompany.MyAwesomeApplication.MyElegantWindow1')
GUISetState(@SW_SHOW, $hWnd1)
GUISetState(@SW_SHOW, $hWnd2)
GUISetState(@SW_SHOW, $hWnd3)

$appid1 = _Win7Helper_GetWindowAppId($hWnd1)
$appid3 = _Win7Helper_GetWindowAppId($hWnd3)
MsgBox(0, 'AppUserModelId', 'AppId of Test1 Window: ' & @CRLF & $appid1 & @CRLF & @CRLF & _
        'AppId of Test3 Window: ' & $appid3 & @CRLF & @CRLF & _
        'Their AppIds are the same, so their icons should be grouped together.', 0, $hWnd1)

Do
Until GUIGetMsg() = -3


#cs
; Another example -- get Google Chrome's AppId
; Start Chrome and use AU3Info to get the handle
$hWnd = HWnd('0x00000000001002CC')

$appid = _Win7Helper_GetWindowAppId($hWnd)
ConsoleWrite('Old AppId = ' & $appid & @CRLF)

_Win7Helper_SetWindowAppId($hWnd, 'chrome.123456')

$appid = _Win7Helper_GetWindowAppId($hWnd)
ConsoleWrite('New AppId = ' & $appid & @CRLF)
#ce

This Func can get AppId of a window created by Autoit in this example.

I tried to get other window's AppId,such as IE, Google Chrome, Firefox, successfully got Google Chrome's AppId , "Chrome.ZABMGAMPWEKMYFXAM6OVHWYM.UserData.Default", while others failed.I don't know why.

Edited by jackchen

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

An example:

$hGUI_Parent = GUICreate("Parent", 600, 400)
GUISetState()
$hGUI_Child1 = GUICreate("Child1", 300, 200, 100)
GUISetState()
$hGUI_Child2 = GUICreate("Child2", 300, 200, 1200)
GUISetState()
Do
Until GUIGetMsg() = -3
GUIDelete($hGUI_Child2)
GUIDelete($hGUI_Child1)
GUIDelete($hGUI_Parent)

Sleep(1000)
$hGUI_Parent = GUICreate("Parent", 600, 400)
GUISetState()
$hGUI_Child1 = GUICreate("Child1", 300, 200, 100, -1, -1, -1, $hGUI_Parent)
GUISetState()
$hGUI_Child2 = GUICreate("Child2", 300, 200, 1200, -1, -1, -1, $hGUI_Parent)
GUISetState()
MsgBox(0, "Info", "Only one GUI in the task bar", 0, $hGUI_Parent)
Do
Until GUIGetMsg() = -3

 

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

#13 ·  Posted (edited)

An example:

$hGUI_Parent = GUICreate("Parent", 600, 400)
GUISetState()
$hGUI_Child1 = GUICreate("Child1", 300, 200, 100)
GUISetState()
$hGUI_Child2 = GUICreate("Child2", 300, 200, 1200)
GUISetState()
Do
Until GUIGetMsg() = -3
GUIDelete($hGUI_Child2)
GUIDelete($hGUI_Child1)
GUIDelete($hGUI_Parent)

Sleep(1000)
$hGUI_Parent = GUICreate("Parent", 600, 400)
GUISetState()
$hGUI_Child1 = GUICreate("Child1", 300, 200, 100, -1, -1, -1, $hGUI_Parent)
GUISetState()
$hGUI_Child2 = GUICreate("Child2", 300, 200, 1200, -1, -1, -1, $hGUI_Parent)
GUISetState()
MsgBox(0, "Info", "Only one GUI in the task bar", 0, $hGUI_Parent)
Do
Until GUIGetMsg() = -3

 

UEZ,Thanks for your example which is exactly what the OP needs.

Actually my request is maybe the reverse, I need combine other window's icon with my loader icon. 

I made a chrome_portable_loader.exe in autoit.If I pin the loader to taskbar and click the icon to launch Google Chrome browser,the browser's icon will on the right side of loader.

20150710195741.thumb.png.db9f58ab5941b4b

I hope the browser's icon can combine with my loader's icon on taskbar.It's absolutley possible.I got the appid of chrome window via _Win7Helper_GetWindowAppId($hWnd) in Autoit, set the same appid for chrome_portable_loader.lnk in @AppDataDir & "\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar", then both icons were combined.I set .lnk file's appid using Win7AppId which is coded in c++.I should convert those code to Autoit,but that's not easy for me.

 

Edited by jackchen

Share this post


Link to post
Share on other sites

#14 ·  Posted (edited)

I'v made a UDF based on some codes of binhnx and solved my problem, Group different Apps on Win 7+ taskbar.

Thanks to binhnx, LarsJ and others.

Edited by jackchen

Share this post


Link to post
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