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