Change Windows 7 taskbar location automatically based on screen shape or on docking status Change Windows 7 taskbar location automatically based on screen shape or on docking status windows windows

Change Windows 7 taskbar location automatically based on screen shape or on docking status


//Normal augment on why this is not a good idea on someone else's machine omitted

A scripting language may not be a good choice here, you need something that pumps the message to listen to WM_DISPLAYCHANGE.

When you get the message you need to calculate the desired orientation of the task bar based on the resolutions of your monitors. Then you use RmShutdown to close Windows Explorer.

//undocumented behavior begins, may break anytime

The taskbar docking edge is stored in byte 13 (as one of the ABE values from APPBARDATA ) and the position is stored in byte 25-40 as a win32 RECT. You can modify the setting before restarting the explorer.

//undocumented behavior ends

Sample code (full source at https://github.com/jiangsheng/Samples/tree/master/AppBarTest):

//returns the process id and create time for the oldest explorer.exe RM_UNIQUE_PROCESS GetExplorerApplication(){    RM_UNIQUE_PROCESS  result={0};    DWORD bytesReturned=0;    DWORD processIdSize=4096;    std::vector<DWORD> processIds;    processIds.resize(1024);    EnumProcesses(processIds.data(),processIdSize,&bytesReturned);    while(bytesReturned==processIdSize)    {        processIdSize+=processIdSize;        processIds.resize(processIdSize/4);        EnumProcesses(processIds.data(),processIdSize,&bytesReturned);    }    std::for_each(processIds.begin(), processIds.end(), [&result] (DWORD processId) {         HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,                                   FALSE, processId);         if (hProcess) {            std::wstring imageName;            imageName.resize(4096);            if(GetProcessImageFileName (hProcess,(LPWSTR)imageName.data(),4096)>0)            {                if(wcscmp(L"explorer.exe",PathFindFileName(imageName.data()))==0)                {                    //this is assmuing the user is not running elevated and won't see explorer processes in other sessions                    FILETIME ftCreate, ftExit, ftKernel, ftUser;                    if (GetProcessTimes(hProcess, &ftCreate, &ftExit,&ftKernel, &ftUser))                    {                        if(result.dwProcessId==0)                        {                            result.dwProcessId=processId;                            result.ProcessStartTime=ftCreate;                        }                        else if(CompareFileTime(&result.ProcessStartTime,&ftCreate)>0)                        {                            result.dwProcessId=processId;                            result.ProcessStartTime=ftCreate;                        }                    }                }            }            CloseHandle(hProcess);         }    });    return result;}    //taskbar position calculating code omitted    DWORD dwSession=0;    WCHAR szSessionKey[CCH_RM_SESSION_KEY+1] = { 0 };    DWORD dwError = RmStartSession(&dwSession, 0, szSessionKey);    if (dwError == ERROR_SUCCESS) {        RM_UNIQUE_PROCESS rgApplications[1]={GetExplorerApplication()};        dwError=RmRegisterResources(            dwSession,0,NULL,1,rgApplications,0,NULL);        DWORD dwReason;        UINT nProcInfoNeeded;        UINT nProcInfo = 10;        RM_PROCESS_INFO rgpi[10];        dwError = RmGetList(dwSession, &nProcInfoNeeded,                       &nProcInfo, rgpi, &dwReason);        if(dwReason==RmRebootReasonNone)//now free to restart explorer        {            RmShutdown(dwSession,RmForceShutdown,NULL);//important, if we change the registry before shutting down explorer will override our change            //using undocumented setting structure, could break any time            //edge setting is stored at HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\StuckRects2!Settings            HKEY hKey={0};            DWORD result=0;            result=::RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StuckRects2"),                    0, KEY_READ|KEY_WRITE, &hKey) ;            if (result== ERROR_SUCCESS)            {                std::vector<BYTE> data;                data.resize(256);                TCHAR settingValue[]= _T("Settings");                DWORD dwKeyDataType=0;                DWORD dwDataBufSize=data.size();                result=::RegQueryValueEx(hKey,settingValue, NULL, &dwKeyDataType,                    (LPBYTE) data.data(), &dwDataBufSize);                while(ERROR_MORE_DATA==result)                {                    data.resize(256+data.size());                    dwDataBufSize=data.size();                    result=::RegQueryValueEx(hKey,settingValue, NULL, &dwKeyDataType,                         (LPBYTE) data.data(), &dwDataBufSize);                }                data.resize(dwDataBufSize);                if(result==ERROR_SUCCESS)                {                    switch ( dwKeyDataType )                    {                        case REG_BINARY:                            if(data.size()==40)                            {                                BYTE taskbarPosition=data[12];                                taskbarPosition=edge;                                data[12]=taskbarPosition;                                RECT* taskbarRect=(RECT*)&data[24];                                CopyRect (taskbarRect,&abd.rc);                                result=::RegSetValueEx(hKey,settingValue,0,REG_BINARY,(LPBYTE) data.data(), dwDataBufSize);                            }                            break;                    }                }                ::RegCloseKey( hKey );            }            RmRestart (dwSession,0,NULL);        }    }    RmEndSession(dwSession);


You can do this in a simple batch or from a script.Set the registry value to position the taskbar based on the current resolution of your screen (if in the docking it will be higher) and then restart explorer.exe.So eg a batch to set the taskbar at the left of your screen would be (assuming you have the bottom.reg file in the d:\scripts folder)

reg add d:\scripts\Bottom.reg@echo off taskkill /f /IM explorer.exeexplorer.exe

The contents of bottom.reg are

Windows Registry Editor Version 5.00[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\StuckRects2]"Settings"=hex:28,00,00,00,ff,ff,ff,ff,02,00,00,00,03,00,00,00,3e,00,00,00,2e,\  00,00,00,00,00,00,00,82,04,00,00,80,07,00,00,b0,04,00,00

and for left.reg

Windows Registry Editor Version 5.00[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\StuckRects2]"Settings"=hex:28,00,00,00,ff,ff,ff,ff,02,00,00,00,00,00,00,00,3e,00,00,00,2e,\  00,00,00,00,00,00,00,00,00,00,00,3e,00,00,00,b0,04,00,00

You will have some flickering but since you will do this when you start windows that won't be a problem i suppose. I tested this on Windows 7.

EDIT: made a vbscript that does the same thing based on screen resolution

HKEY_CURRENT_USER = &H80000001Set WshShell = CreateObject("WScript.Shell")strComputer = "."Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")Set ObjRegistry = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\default:StdRegProv")'Get curr. user nameSet colItems = objWMIService.ExecQuery("Select * From Win32_ComputerSystem")For Each objItem in colItems  strCurrentUserName = objItem.UserNameNextSet colItems = objWMIService.ExecQuery("Select * From Win32_DesktopMonitor where DeviceID = 'DesktopMonitor1'",,0) For Each objItem in colItems   intHorizontal = objItem.ScreenWidth   intVertical = objItem.ScreenHeight Next bottom = Array(&H28,&H00,&H00,&H00,&Hff,&Hff,&Hff,&Hff,&H02,&H00,&H00,&H00,&H03,&H00,&H00,&H00,&H3e,&H00,&H00,&H00,&H2e,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H82,&H04,&H00,&H00,&H80,&H07,&H00,&H00,&Hb0,&H04,&H00,&H00)left_   = Array(&H28,&H00,&H00,&H00,&Hff,&Hff,&Hff,&Hff,&H02,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H3e,&H00,&H00,&H00,&H2e,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00,&H3e,&H00,&H00,&H00,&Hb0,&H04,&H00,&H00)if intHorizontal >= 1920 then  regdata = bottomelse  regdata = left_end ifObjRegistry.SetBinaryValue HKEY_CURRENT_USER, "Software\Microsoft\Windows\CurrentVersion\Explorer\StuckRects2\", "Settings", regdata'Restart user shellSet colProcessList = objWMIService.ExecQuery("Select * from Win32_Process Where Name = 'Explorer.exe'")For Each objProcess in colProcessList    colProperties = objProcess.GetOwner(strNameOfUser,strUserDomain)  wscript.echo colProperties    If strUserDomain & "\" & strNameOfUser = strCurrentUserName then    wscript.echo "restarting"        objProcess.Terminate()    end ifNext