jackchen

Group different Apps on Win 7+ taskbar

6 posts in this topic

#1 ·  Posted (edited)

How to group different apps on Win 7+ taskbar?

I pin my "chrome_portable_loader.exe" on taskbar to launch chrome browser, I wish chrome's icon can group with the "chrome_portable_loader.exe" icon on taskbar.

Here is a solution, https://code.google.com/p/win7appid/, setting the shortcut's AppID the same as chrome window's AppUserModelId. 

see also  http://msdn.microsoft.com/en-us/library/dd378459%28VS.85%29.aspx.

Can someone translate it to Autoit?

Thanks!

//
// Win7AppId
// Author: David Roe (didroe)
// The code's a bit rough and ready but it does the job
//
// Compile with VS 2010 express using command:
//     cl /EHsc /D _UNICODE Win7AppId.cpp /link ole32.lib

#include <windows.h>
#include <shobjidl.h>
#include <propkey.h>
#include <tchar.h>

#include <iostream>

using namespace std;

EXTERN_C const PROPERTYKEY DECLSPEC_SELECTANY PKEY_AppUserModel_ID =
                     { { 0x9F4C2855, 0x9F79, 0x4B39,
                     { 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, } }, 5 };

void die(string message) {
        cout << "Error: " << message.c_str() << endl;
        exit(1);
}

void doOrDie(HRESULT hr, string message) {
        if (!SUCCEEDED(hr)) {
                die(message);
        }
}

int _tmain(int argc, _TCHAR* argv[])
{
        doOrDie(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED),
                        "Failed to initialise COM");

        IShellLink *link;
        doOrDie(CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&link)),
                        "Failed to create ShellLink object");
        
        IPersistFile* file; 
        doOrDie(link->QueryInterface(IID_PPV_ARGS(&file)),
                        "Failed to obtain PersistFile interface"); 

        if (argc > 2) {
                doOrDie(file->Load(argv[1], STGM_READWRITE),
                                "Failed to load shortcut file");
        } else {
                doOrDie(file->Load(argv[1], STGM_READ | STGM_SHARE_DENY_NONE),
                                "Failed to load shortcut file");
        }
    
        IPropertyStore* store; 
        doOrDie(link->QueryInterface(IID_PPV_ARGS(&store)),
                        "Failed to obtain PropertyStore interface"); 

        PROPVARIANT pv;
        doOrDie(store->GetValue(PKEY_AppUserModel_ID, &pv),
                        "Failed to retrieve AppId");
        
        if (pv.vt != VT_EMPTY) {
                if (pv.vt != VT_LPWSTR) {
                        cout << "Type: " << pv.vt << endl;
                        die("Unexpected property value type");
                }

                wcout << "Current AppId: " << pv.pwszVal << endl;
        } else {
                cout << "No current AppId" << endl;
        }
        PropVariantClear(&pv);

        if (argc > 2) {
                wcout << "New AppId: " << argv[2] << endl;

                pv.vt = VT_LPWSTR;
                pv.pwszVal = argv[2];

                doOrDie(store->SetValue(PKEY_AppUserModel_ID, pv),
                                "Failed to set AppId");

        // Not sure if we need to do this
        pv.pwszVal = NULL;
                PropVariantClear(&pv);

                doOrDie(store->Commit(),
                                "Failed to commit AppId property");

                doOrDie(file->Save(NULL, TRUE),
                                "Failed to save shortcut");
        }

        store->Release();
        file->Release();
        link->Release();        

        return 0;
}
 
Edited by jackchen

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

I tried to get / set appid of a .lnk file in a stupid way.I read and parsed the .lnk file directly in binary to get appid info, GetAppId() was ok while SetAppId() failed.

can anyone help?

Codes deleted due to not work in some circumstance.
Edited by jackchen

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

After some days effort I've solved my problem.

I made some udfs to get / set appid for windows or shortcut files.So I can group any windows/taskbar icons as desired.

Some Funcs are from this thread.Thanks to binhnx, LarsJ and others.

Here is the UDF:

#include-once
; file name: AppUserModelId.au3

; #### Title ####
; ================================================================================
; Get / Set AppUserModelId for a window or a shortcut file(*.lnk)
; Thanks to binhnx, LarsJ and others
; - jackchen
; ================================================================================

; #### FUNCTIONS ####
; ================================================================================
; _WindowAppId
; _ShortcutAppId
; ================================================================================

#include <WinAPI.au3>

#Region ====================== #### CONSTANTS #### ======================
; https://www.autoitscript.com/forum/topic/161067-get-clsid-from-iid/
Global Const $CLSID_ShellLink = "{00021401-0000-0000-C000-000000000046}"
Global Const $sIID_IShellLinkW = "{000214F9-0000-0000-C000-000000000046}"
Global Const $tag_IShellLinkW = _
  "GetPath hresult(long;long;long;long);" & _
  "GetIDList hresult(long);" & _
  "SetIDList hresult(long);" & _
  "GetDescription hresult(long;long);" & _
  "SetDescription hresult(wstr);" & _
  "GetWorkingDirectory hresult(long;long);" & _
  "SetWorkingDirectory hresult(long;long);" & _
  "GetArguments hresult(long;long);" & _
  "SetArguments hresult(ptr);" & _
  "GetHotkey hresult(long);" & _
  "SetHotkey hresult(word);" & _
  "GetShowCmd hresult(long);" & _
  "SetShowCmd hresult(int);" & _
  "GetIconLocation hresult(long;long;long);" & _
  "SetIconLocation hresult(wstr;int);" & _
  "SetRelativePath hresult(long;long);" & _
  "Resolve hresult(long;long);" & _
  "SetPath hresult(wstr);"

Global Const $tag_IPersist = "GetClassID hresult(long);"
Global Const $sIID_IPersistFile = "{0000010b-0000-0000-C000-000000000046}"
Global Const $tag_IPersistFile = $tag_IPersist & _ ; Inherits from IPersist
  "IsDirty hresult();" & _
  "Load hresult(wstr;dword);" & _
  "Save hresult(wstr;bool);" & _
  "SaveCompleted hresult(long);" & _
  "GetCurFile hresult(long);"

; https://msdn.microsoft.com/en-us/library/windows/desktop/aa380337(v=vs.85).aspx
Global Const $STGM_READ = 0x00000000
Global Const $STGM_READWRITE = 0x00000002
Global Const $STGM_SHARE_DENY_NONE = 0x00000040

; Global Const $tagPROPERTYKEY = $tagGUID & ';DWORD pid'
Global Const $tagPROPERTYKEY = 'struct;ulong Data1;ushort Data2;ushort Data3;byte Data4[8];DWORD pid;endstruct'
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 $sIID_IPropertyStore = '{886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99}'
Global Const $VT_EMPTY = 0, $VT_LPWSTR = 31
#EndRegion ====================== #### CONSTANTS #### ======================


; #FUNCTION# ;===============================================================================
; Name...........: _WindowAppId
; Description ...: Get / Set AppUerModelId(AppId) of a window
; Syntax.........: _WindowAppId($hWnd, $appid = Default)
; Parameters ....: $hWnd - Handle of a window.
;                  $appid - [optional] AppId to set.
; Return values .: Success - Returns current AppId
;                  Failure - Returns "" and sets @error:
; Author ........: binhnx, jackchen
; Link ..........: https://www.autoitscript.com/forum/topic/168099-how-to-prevent-multiple-guis-from-combining-in-the-taskbar/
;============================================================================================
Func _WindowAppId($hWnd, $appid = Default)
    Local $tpIPropertyStore = DllStructCreate('ptr')
    _WinAPI_SHGetPropertyStoreForWindow($hWnd, $sIID_IPropertyStore, $tpIPropertyStore)
    Local $pPropertyStore = DllStructGetData($tpIPropertyStore, 1)
    Local $oPropertyStore = ObjCreateInterface($pPropertyStore, $sIID_IPropertyStore, _
            'GetCount HRESULT(PTR);GetAt HRESULT(DWORD; PTR);GetValue HRESULT(PTR;PTR);' & _
            'SetValue HRESULT(PTR;PTR);Commit HRESULT()')
    If Not IsObj($oPropertyStore) Then Return SetError(1, 0, '')

    Local $tPKEY = _PKEY_AppUserModel_ID()
    Local $tPROPVARIANT = DllStructCreate($tagPROPVARIANT)
    Local $sAppId
    If $appid = Default Then
        $oPropertyStore.GetValue(DllStructGetPtr($tPKEY), 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
        If DllStructGetData($tPROPVARIANT, 'vt') <> $VT_EMPTY Then
            Local $buf = DllStructCreate('wchar[128]')
            DllCall('Propsys.dll', 'long', 'PropVariantToString', _
                    'ptr', DllStructGetPtr($tPROPVARIANT), _
                    'ptr', DllStructGetPtr($buf), _
                    'uint', DllStructGetSize($buf))
            If Not @error Then
                $sAppId = DllStructGetData($buf, 1)
            EndIf
        EndIf
    Else
        _WinAPI_InitPropVariantFromString($appId, $tPROPVARIANT)
        $oPropertyStore.SetValue(DllStructGetPtr($tPKEY), DllStructGetPtr($tPROPVARIANT))
        $oPropertyStore.Commit()
        $sAppId = $appid
    EndIf

    ;$oPropertyStore.Release() ; this line crashes Autoit
    Return SetError(($sAppId == '')*2, 0, $sAppId)
EndFunc


; #FUNCTION# ;===============================================================================
; Name...........: _ShortcutAppId
; Description ...: Get AppUerModelId(AppId) from a .lnk shortcut file or
;                  set the shortcut's AppId if $appid is provided.
; Syntax.........: _ShortcutAppId($lnkfile, $appid = Default)
; Parameters ....: $lnkfile - path of shortcut file.
;                  $appid - [optional] AppId to set.
; Return values .: Success - Returns current AppId
;                  Failure - Returns "" and sets @error:
; Author ........: jackchen
; Linlk .........: https://code.google.com/p/win7appid/
;============================================================================================
Func _ShortcutAppId($lnkfile, $appid = Default)
    Local $oIShellLinkW = ObjCreateInterface($CLSID_ShellLink , $sIID_IShellLinkW, $tag_IShellLinkW )
    If Not IsObj( $oIShellLinkW ) Then Return SetError(1, 0, '')

    Local $pIPersistFile, $oIPersistFile, $ret, $sAppId
    Local $tRIID_IPersistFile = _WinAPI_GUIDFromString( $sIID_IPersistFile )
    $oIShellLinkW.QueryInterface( $tRIID_IPersistFile, $pIPersistFile )
    $oIPersistFile = ObjCreateInterface( $pIPersistFile, $sIID_IPersistFile, $tag_IPersistFile )
    If IsObj( $oIPersistFile ) Then
        If $appid == Default Then ; read only
            $ret = $oIPersistFile.Load($lnkfile, BitOR($STGM_READ, $STGM_SHARE_DENY_NONE))
        Else
            $ret = $oIPersistFile.Load($lnkfile, $STGM_READWRITE)
        EndIf
        If $ret = 0 Then
            Local $tPKEY = _PKEY_AppUserModel_ID()
            Local $tPROPVARIANT = DllStructCreate($tagPROPVARIANT)

            $tRIID_IPropertyStore = _WinAPI_GUIDFromString($sIID_IPropertyStore)

            Local $pPropertyStore
            $oIShellLinkW.QueryInterface($tRIID_IPropertyStore, $pPropertyStore)

            Local $oPropertyStore = ObjCreateInterface($pPropertyStore, $sIID_IPropertyStore, _
                    'GetCount HRESULT(PTR);GetAt HRESULT(DWORD;PTR);GetValue HRESULT(PTR;PTR);' & _
                    'SetValue HRESULT(PTR;PTR);Commit HRESULT()')
            If IsObj($oPropertyStore) Then
                If $appid == Default Then ; get appid
                    $oPropertyStore.GetValue(DllStructGetPtr($tPKEY), DllStructGetPtr($tPROPVARIANT))
                    If DllStructGetData($tPROPVARIANT, 'vt') <> $VT_EMPTY Then
                        ; 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))
                        $sAppId = DllStructGetData($buf, 1)
                    EndIf
                Else ; set appid
                    _WinAPI_InitPropVariantFromString($appid, $tPROPVARIANT)
                    $oPropertyStore.SetValue(DllStructGetPtr($tPKEY), DllStructGetPtr($tPROPVARIANT))
                    $oPropertyStore.Commit()
                    $oIPersistFile.Save($lnkfile, True)
                    $sAppId = $appid
                EndIf
            EndIf
        EndIf
    EndIf
    If IsObj($oPropertyStore) Then $oPropertyStore.Release()
    If IsObj($oIPersistFile) Then $oIPersistFile.Release()
    If IsObj($oIShellLinkW) Then $oIShellLinkW.Release()
    Return SetError(($sAppId == '')*2, 0, $sAppId)
EndFunc

; https://www.autoitscript.com/forum/topic/168099-how-to-prevent-multiple-guis-from-combining-in-the-taskbar/
; 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)
    DllStructSetData($tPROPVARIANT, 'vt', $VT_LPWSTR)
    Local $aRet = DllCall('Shlwapi.dll', 'LONG', 'SHStrDupW', _
            'WSTR', $sUnicodeString, 'PTR', DllStructGetPtr($tPROPVARIANT) + 8)

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

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

; https://www.autoitscript.com/forum/topic/168099-how-to-prevent-multiple-guis-from-combining-in-the-taskbar/
Func _PKEY_AppUserModel_ID()
    Local $tPKEY = 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($tPKEY))
    DllStructSetData($tPKEY, 'pid', 5)
    Return $tPKEY
EndFunc

; https://www.autoitscript.com/forum/topic/168099-how-to-prevent-multiple-guis-from-combining-in-the-taskbar/
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

And here are some examples:

#include "AppUserModelId.au3"



; Example 1
; search .lnk files in user pinned taskbar dir and show appid info
$TaskbarDir = @AppDataDir & "\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar"
$hSearch = FileFindFirstFile($TaskbarDir & "\*.lnk")
If $hSearch = -1 Then Exit
While 1
    $file = FileFindNextFile($hSearch)
    If @error Then ExitLoop

    $ShellObj = ObjCreate("WScript.Shell")
    $objShortcut = $ShellObj.CreateShortCut($TaskbarDir & "\" & $file)
    $path = $objShortcut.TargetPath
    $ShellObj = ""
    $objShortcut = ""

    ConsoleWrite($file &':' & @crlf & _
        $path & @CRLF & _
        _ShortcutAppId($TaskbarDir & "\" & $file))
    ConsoleWrite(@CRLF & @CRLF)
WEnd
FileClose($hSearch)
MsgBox(0, "Example 1", "Take a look at console for AppId info of user pinned Apps!")


; Example 2
; group 2 of 3 windows
$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
_WindowAppId($hWnd1, 'MyGreatCompany.MyAwesomeApplication.MyElegantWindow1')
_WindowAppId($hWnd2, 'MyGreatCompany.MyAwesomeApplication.OhImNotAWindowImAnAlien')
_WindowAppId($hWnd3, 'MyGreatCompany.MyAwesomeApplication.MyElegantWindow1')
GUISetState(@SW_SHOW, $hWnd1)
GUISetState(@SW_SHOW, $hWnd2)
GUISetState(@SW_SHOW, $hWnd3)

$appid1 = _WindowAppId($hWnd1)
$appid3 = _WindowAppId($hWnd3)
MsgBox(0, 'Example 2', '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
GUIDelete($hWnd1)
GUIDelete($hWnd2)
GUIDelete($hWnd3)

Example 3:

Script of example 3 should be compiled to exe and pinned to taskbar before test.

#include "AppUserModelId.au3"

; Example 3
; --> Compile this script to compiled_script.exe before test
; --> Pin compiled_script.exe to taskbar
; --> click compiled_script.exe icon on taskbar to start notepad
; --> notepad's icon should be grouped with compiled_script.exe icon

$appid_to_set = "MyNotepad.123456"
; DllCall("Shell32.dll", "long", "SetCurrentProcessExplicitAppUserModelID", "wstr", $appid_to_set)

$TaskbarDir = @AppDataDir & "\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar"
$lnkfile = $TaskbarDir & "\" & StringTrimRight(@ScriptName, 4) & ".lnk"
If Not FileExists($lnkfile) Then
    MsgBox(0, "Example 3", "Please compile this script to exe" & @CRLF & "and pin to taskbar before test Example 3!")
    Exit
EndIf

Run("Notepad.exe")
WinWait("[REGEXPCLASS:(?i)Notepad]", "", 15)
$hWnd = WinGetHandle('[REGEXPCLASS:(?i)Notepad]')

MsgBox(0, "Example 3", "Notepad should be launched." & @CRLF & _
    "Press OK to combine Notepad's icon!", 0, $hWnd)

; Get the window's appid, normaly Notepad's window has no appid.
; so we set a predefined appid for it.
$window_appid = _WindowAppId($hWnd)
If Not $window_appid Then
    $window_appid = _WindowAppId($hWnd, $appid_to_set)
EndIf

; We set the same appid for the lnk file
$shortcut_appid = _ShortcutAppId($lnkfile)
If $shortcut_appid <> $window_appid Then
    $shortcut_appid = _ShortcutAppId($lnkfile, $window_appid)
EndIf

MsgBox(0, "Example 3", "Notepad's taskbar icon should be combined with this script's icon now!", 0, $hWnd)

 

Edited by jackchen

Share this post


Link to post
Share on other sites

I'm not sure is it related but I'm using:

_WinAPI_SetCurrentProcessExplicitAppUserModelID()

 


Signature beginning:   Wondering who uses AutoIT and what it can be used for ?
* GHAPI UDF - modest begining - comunication with GitHub REST API *
ADO.au3 UDF     POP3.au3 UDF     XML.au3 UDF    How to use IE.au3  UDF with  AutoIt v3.3.14.x  for other useful stuff click the following button

Spoiler

Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind. 

My contribution (my own projects): * Debenu Quick PDF Library - UDF * Debenu PDF Viewer SDK - UDF * Acrobat Reader - ActiveX Viewer * UDF for PDFCreator v1.x.x * XZip - UDF * AppCompatFlags UDF * CrowdinAPI UDF * _WinMergeCompare2Files() * _JavaExceptionAdd() * _IsBeta() * Writing DPI Awareness App - workaround * _AutoIt_RequiredVersion() * Chilkatsoft.au3 UDF * TeamViewer.au3 UDF * JavaManagement UDF * VIES over SOAP * WinSCP UDF * GHAPI UDF - modest begining - comunication with GitHub REST API *

My contribution to others projects or UDF based on  others projects: * _sql.au3 UDF  * POP3.au3 UDF *  RTF Printer - UDF * XML.au3 - BETA * ADO.au3 UDF SMTP Mailer UDF *

Useful links: * Forum Rules * Forum etiquette *  Forum Information and FAQs * How to post code on the forum * AutoIt Online Documentation * AutoIt Online Beta Documentation * SciTE4AutoIt3 getting started * Convert text blocks to AutoIt code * Games made in Autoit * Programming related sites * Polish AutoIt Tutorial * DllCall Code Generator * 

Wiki: Expand your knowledge - AutoIt Wiki * Collection of User Defined Functions * How to use HelpFile * Best coding practices * 

IE Related:  * How to use IE.au3  UDF with  AutoIt v3.3.14.x * Why isn't Autoit able to click a Javascript Dialog? * Clicking javascript button with no ID * IE document >> save as MHT file * IETab Switcher (by LarsJ ) * HTML Entities * _IEquerySelectorAll() (by uncommon) * 

I encourage you to read: * Global Vars * Best Coding Practices * Please explain code used in Help file for several File functions * OOP-like approach in AutoIt * UDF-Spec Questions *  EXAMPLE: How To Catch ConsoleWrite() output to a file or to CMD *

"Homo sum; humani nil a me alienum puto" - Publius Terentius Afer
"Program are meant to be read by humans and only incidentally for computers and execute" - Donald Knuth, "The Art of Computer Programming"
:naughty:  :ranting:, be  :) and       \\//_.

Anticipating Errors :  "Any program that accepts data from a user must include code to validate that data before sending it to the data store. You cannot rely on the data store, ...., or even your programming language to notify you of problems. You must check every byte entered by your users, making sure that data is the correct type for its field and that required fields are not empty."

Signature last update: 2017-06-04

Share this post


Link to post
Share on other sites

I'm not sure is it related but I'm using:

_WinAPI_SetCurrentProcessExplicitAppUserModelID()

 

mLipok,it's related but I think it's impossible to combine your script's icon/window with the icon/window of Notepad or other app only using  

WinAPI_SetCurrentProcessExplicitAppUserModelID()

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