DwmGetWindowAttribute does not work on child window, is it true? - dwm

I'm trying DwmGetWindowAttribute to get a window's real, physical, pixel location on screen. It works well for top-level windows. But I find that it does not work for child windows, in which case it returns just E_HANDLE (0x80070006).
However, MSDN does not state anything about such child-window limitation. So I'm in baffle.
Can any one confirm this behavior? Thank you.
This is my C++ test code (DwmBounds.cpp):
#include <stdio.h>
#include <windows.h>
#include <dwmapi.h>
int main()
{
DWORD winerr = 0;
HWND hwndTop = FindWindow(L"Notepad", NULL);
if(!hwndTop)
{
wprintf(L"Cannot find a Notepad window.\n");
return 4;
}
RECT rc = {};
HRESULT hr = DwmGetWindowAttribute(hwndTop, DWMWA_EXTENDED_FRAME_BOUNDS, &rc, sizeof(rc));
if (hr != S_OK)
{
wprintf(L"Fail to call DwmGetWindowAttribute() on Notepad window. HRESULT=0x%08X\r\n",
(DWORD)hr);
return 4;
}
wprintf(L"Notepad DWMWA_EXTENDED_FRAME_BOUNDS: LT(%d, %d) RB(%d, %d)\r\n",
rc.left, rc.top, rc.right, rc.bottom);
HWND hwndEdit = FindWindowEx(hwndTop, nullptr, L"Edit", nullptr);
if (!hwndEdit)
return 4;
hr = DwmGetWindowAttribute(hwndEdit, DWMWA_EXTENDED_FRAME_BOUNDS, &rc, sizeof(rc));
if(hr != S_OK)
{
// Always get HRESULT=0x80070006 (E_HANDLE), why?
wprintf(L"Get DWMWA_EXTENDED_FRAME_BOUNDS fails on child window(0x%08X), HRESULT=0x%08X\n",
(DWORD)hwndEdit, (DWORD)hr);
return 4;
}
wprintf(L"Editbox DWMWA_EXTENDED_FRAME_BOUNDS: LT(%d, %d) RB(%d, %d)\r\n",
rc.left, rc.top, rc.right, rc.bottom);
return 0;
}
This is its output:
The benefit of DwmGetWindowAttribute is: Whatever the setting of DPI_AWARENESS_CONTEXT on the calling thread, DwmGetWindowAttribute always reports physical screen coordinate. On the other hand, GetWindowRect just reports the "virtual" coordinates relating to calling thread's DPI-awareness-context. So, I am wondering whether I can use DwmGetWindowAttribute to get each top-level window and child window's physical coordinates.

Related

linux X11, how to create transparent and insensitive to events window, non-dependant of window manager

Hi everyone! I've created such a window (thanks to X11/Xlib: Create "GlassPane"-Window), that is on always on top, semitransparent, and doesn't consume any events. It works fine on some distributions, for example, on ubuntu or debian (after proper set of composite manager). On some distro mouse events can't penetrate through my window (with GNOME WM), on others both mouse and keyboard events can't go through. I am still testing os dependance of my app. Could you give me any tips, why my program is os dependant, is it only wm problem? Is there other way to solve my task and create universal utility that works on all linux distro? Appreciate any help!
/* for corrent exit on termination */
#include <signal.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/shape.h>
#include <X11/extensions/Xfixes.h>
#include <stdio.h>
#include <string.h> // strncmp
#include <unistd.h> // usleep
// all required elements for drawing
struct TXLibConfig
{
Display *dpy;
Window w;
XSetWindowAttributes attr;
XGCValues gcv;
XVisualInfo vinfo;
GC gc;
XserverRegion region;
int winWidth, winHeight;
};
int must_quit = 0;
// Define the function to be called when ctrl-c (SIGINT) is sent to process
void signal_callback_handler(int signum) {
must_quit = 1;
}
int XInit(TXLibConfig *txlibPtr);
int main(int argc, char *argv[]) {
// exit by Ctrl+C and pkill
signal(SIGINT, signal_callback_handler);
signal(SIGTERM, signal_callback_handler);
TXLibConfig tXlibCfg = {0};
XInit(&tXlibCfg);
int ctr = 0;
while(1) {
XClearWindow(tXlibCfg.dpy,tXlibCfg.w);
XSetForeground(tXlibCfg.dpy, tXlibCfg.gc, 0x01808020);
XRectangle rct[] = {300, 300, 200, 200};
XFillRectangles(tXlibCfg.dpy, tXlibCfg.w, tXlibCfg.gc, rct, 1);
XSetForeground(tXlibCfg.dpy, tXlibCfg.gc, 0xf0010140);
XRectangle rectan[] = {350, 350, 10*(ctr % 10 + 1), 10*(ctr % 10 + 1)};
XFillRectangles(tXlibCfg.dpy, tXlibCfg.w, tXlibCfg.gc, rectan, 1);
XFlush(tXlibCfg.dpy);
XSync(tXlibCfg.dpy, True);
ctr++;
usleep(200000);
if (must_quit == 1) break;
}
XClearWindow(tXlibCfg.dpy,tXlibCfg.w);
XDestroyWindow(tXlibCfg.dpy, tXlibCfg.w);
XCloseDisplay(tXlibCfg.dpy);
return 0;
}
int XInit(TXLibConfig *txlibPtr)
{
txlibPtr->dpy = XOpenDisplay(NULL);
if (!txlibPtr->dpy) printf("cannot open display '%s'", XDisplayName(0));
// Get screen resolution >>>>>
int snum;
snum = DefaultScreen(txlibPtr->dpy);
txlibPtr->winWidth = DisplayWidth(txlibPtr->dpy, snum);
txlibPtr->winHeight = DisplayHeight(txlibPtr->dpy, snum);
// Get screen resolution <<<<<
XMatchVisualInfo(txlibPtr->dpy, DefaultScreen(txlibPtr->dpy), 32, TrueColor, &txlibPtr->vinfo);
txlibPtr->attr.colormap = XCreateColormap(txlibPtr->dpy, DefaultRootWindow(txlibPtr->dpy), txlibPtr->vinfo.visual, AllocNone);
txlibPtr->attr.border_pixel = 0;
txlibPtr->attr.background_pixel = 0;
txlibPtr->w = XCreateWindow(txlibPtr->dpy, DefaultRootWindow(txlibPtr->dpy), 0, 0,
txlibPtr->winWidth, txlibPtr->winHeight, 10, txlibPtr->vinfo.depth,
NoEventMask, txlibPtr->vinfo.visual, CWColormap | CWBorderPixel | CWBackPixel, &txlibPtr->attr);
// Ignore any input for passing events to other windows >>>>>
txlibPtr->region = XFixesCreateRegion (txlibPtr->dpy, NULL, 0);
XFixesSetWindowShapeRegion (txlibPtr->dpy, txlibPtr->w, ShapeBounding, 0, 0, 0);
XFixesSetWindowShapeRegion (txlibPtr->dpy, txlibPtr->w, ShapeInput, 0, 0, txlibPtr->region);
XFixesDestroyRegion (txlibPtr->dpy, txlibPtr->region);
// Ignore any input for passing events to other windows <<<<<
txlibPtr->gcv.line_width = 1;
txlibPtr->gc = XCreateGC(txlibPtr->dpy, txlibPtr->w, GCLineWidth, &txlibPtr->gcv);
XSelectInput(txlibPtr->dpy, txlibPtr->w, ExposureMask);
long value = XInternAtom(txlibPtr->dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);
XChangeProperty(txlibPtr->dpy, txlibPtr->w, XInternAtom(txlibPtr->dpy, "_NET_WM_WINDOW_TYPE", False),
6, 32, PropModeReplace, (unsigned char *) &value, 1);
XMapWindow(txlibPtr->dpy, txlibPtr->w);
XFlush(txlibPtr->dpy);
usleep(100000);
return 0;
};

WinAPI + Cmake + Aero

I have a CMake project with an executable and a static library (linked to the exe). The library is responsible for implementing the creation of the window (using WinAPI for Windows OS), and the executable contains the main entry point (in this case a simple int main(...) function).
I've been googling for a day but cannot find a way to create a window with Aero support (can maximize by dropping to the top, the title bar is a little bit transparent, etc). I've read the Enabling Visual Styles MSDN article but I'm not sure how I should handle this with CMake. Especially that the window implementation is hidden to the client (since it's implemented in the library).
The windowing code is really basic right now for simplicity. Some of the code will be refactored, the point is not that right now. Here is the (almost) full code for creating the window.
bool WindowsWindow::create(const WindowCreateInfo& info)
{
// register custom window class
{
WNDCLASSEX wnd = { 0 };
wnd.cbSize = sizeof(wnd);
wnd.lpszClassName = CLASS_NAME;
wnd.hInstance = GetModuleHandle(nullptr);
wnd.lpfnWndProc = wndProc;
wnd.style = CS_OWNDC;
wnd.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW);
wnd.hCursor = LoadCursor(NULL, IDC_ARROW);
if (RegisterClassEx(&wnd) == 0) {
return false;
}
hInstance = wnd.hInstance;
}
HMONITOR monitor = MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY);
MONITORINFO monitorInfo;
monitorInfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(monitor, &monitorInfo);
LONG style = 0;
LONG exStyle = WS_EX_APPWINDOW;
int x = CW_USEDEFAULT;
int y = CW_USEDEFAULT;
int width = info.width;
int height = info.height;
if (info.isWindowed) {
style = WS_OVERLAPPED | WS_BORDER | WS_CAPTION;
if (info.hasSysMenu) {
style |= WS_SYSMENU;
}
if (info.allowMinimize) {
style |= WS_MINIMIZEBOX;
}
if (info.allowMaximize) {
style |= WS_MAXIMIZEBOX;
}
// ... positioning, adjusting size, etc.
} else {
style = WS_POPUP;
x = monitorInfo.rcMonitor.left;
y = monitorInfo.rcMonitor.top;
width = monitorInfo.rcMonitor.right - x;
height = monitorInfo.rcMonitor.bottom - y;
}
handle = CreateWindowEx(
exStyle,
CLASS_NAME,
info.title,
style,
x,
y,
width,
height,
HWND_DESKTOP,
nullptr,
hInstance,
nullptr
);
if (!handle) {
return false;
}
running = true;
ShowWindow(handle, SW_SHOW);
return true;
}
The loop is the standard Peek-Translate-Dispatch trio and the WndProc only handles the WM_CLOSE message, otherwise returns with DefWindowProc.
How could I enable the Aero support in this kind of setup?
If the proper manifest file would be the solution, how should I handle it correctly? I mean the client (the executable) should not care that the underlying library is using WinAPI or not
A CMake example would be really helpful
Current solution
I was able to find an example (actually from a Vulkan SDK) that pointed out that I need the WS_THICKFRAME style (a resize border) in order to my window become modern looking (Aero-like).

Force a DLL to be loaded above 2GB (0x80000000) in a 32-bit process on Windows

To test a corner case in our debugger, I need to come up with a program which has a DLL loaded above 2GB (0x80000000). Current test case is a multi-GB game which loads >700 DLLs, and I'd like to have something simpler and smaller. Is there a way to achieve it reliably without too much fiddling? I assume I need to use /LARGEADDRESSAWARE and somehow consume enough of the VA space to bump the new DLLs above 2GB but I'm fuzzy on the details...
Okay, it took me a few tries but I managed to come up with something working.
// cl /MT /Ox test.cpp /link /LARGEADDRESSAWARE
// occupy the 2 gigabytes!
#define ALLOCSIZE (64*1024)
#define TWOGB (2*1024ull*1024*1024)
#include <windows.h>
#include <stdio.h>
int main()
{
int nallocs = TWOGB/ALLOCSIZE;
for ( int i = 0; i < nallocs+200; i++ )
{
void * p = VirtualAlloc(NULL, ALLOCSIZE, MEM_RESERVE, PAGE_NOACCESS);
if ( i%100 == 0)
{
if ( p != NULL )
printf("%d: %p\n", i, p);
else
{
printf("%d: failed!\n", i);
break;
}
}
}
printf("finished VirtualAlloc. Loading a DLL.\n");
//getchar();
HMODULE hDll = LoadLibrary("winhttp");
printf("DLL base: %p.\n", hDll);
//getchar();
FreeLibrary(hDll);
}
On Win10 x64 produces:
0: 00D80000
100: 03950000
200: 03F90000
[...]
31800: 7FBC0000
31900: 00220000
32000: 00860000
32100: 80140000
32200: 80780000
32300: 80DC0000
32400: 81400000
32500: 81A40000
32600: 82080000
32700: 826C0000
32800: 82D00000
32900: 83340000
finished VirtualAlloc. Loading a DLL.
DLL base: 83780000.
for your own DLL you need set 3 linker option:
/LARGEADDRESSAWARE
/DYNAMICBASE:NO
/BASE:"0x********"
note that link.exe allow only image full located bellow 3GB (0xC0000000) for 32-bit image. in other word, he want that ImageBase + ImageSize <= 0xC0000000
so say /BASE:0xB0000000 will be ok, /BASE:0xBFFF0000 only if your image size <= 0x10000 and for /BASE:0xC0000000 and higher we always got error LNK1249 - image exceeds maximum extent with base address address and size size
also EXE mandatory must have /LARGEADDRESSAWARE too, because are all 4GB space available for wow64 process based only on EXE options.
if we want do this for external DLL - here question more hard. first of all - are this DLL can correct handle this situation (load base > 0x80000000) ? ok. let test this. any api (including most low level LdrLoadDll) not let specify base address, for DLL load. here only hook solution exist.
when library loaded, internal always called ZwMapViewOfSection and it 3-rd parameter BaseAddress - Pointer to a variable that receives the base address of the view. if we set this variable to 0 - system yourself select loaded address. if we set this to specific address - system map view (DLL image in our case) only at this address, or return error STATUS_CONFLICTING_ADDRESSES.
working solution - hook call to ZwMapViewOfSection and replace value of variable, to which point BaseAddress. for find address > 0x80000000 we can use VirtualAlloc with MEM_TOP_DOWN option. note - despite ZwMapViewOfSection also allow use MEM_TOP_DOWN in AllocationType parameter, here it will be have not needed effect - section anyway will be loaded by preferred address or top-down from 0x7FFFFFFF not from 0xFFFFFFFF. but with VirtualAlloc the MEM_TOP_DOWN begin search from 0xFFFFFFFF if process used 4Gb user space. for know - how many memory need for section - we can call ZwQuerySection with SectionBasicInformation - despite this is undocumented - for debug and test - this is ok.
for hook of course can be used some detour lib, but possible do hook with DRx breakpoint - set some Drx register to NtMapViewOfSection address. and set AddVectoredExceptionHandler - which handle exception. this will be perfect work, if process not under debugger. but under debugger it break - most debuggers alwas stop under single step exception and usually no option not handle it but pass to application. of course we can start program not under debugger, and attach it later - after dll load. or possible do this task in separate thread and hide this thread from debugger. disadvantage here - that debugger not got notify about dll load in this case and not load symbols for this. however for external (system dll) for which you have not src code - this in most case can be not a big problem. so solution exit, if we can implement it ). possible code:
PVOID pvNtMapViewOfSection;
LONG NTAPI OnVex(::PEXCEPTION_POINTERS ExceptionInfo)
{
if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP &&
ExceptionInfo->ExceptionRecord->ExceptionAddress == pvNtMapViewOfSection)
{
struct MapViewOfSection_stack
{
PVOID ReturnAddress;
HANDLE SectionHandle;
HANDLE ProcessHandle;
PVOID *BaseAddress;
ULONG_PTR ZeroBits;
SIZE_T CommitSize;
PLARGE_INTEGER SectionOffset;
PSIZE_T ViewSize;
SECTION_INHERIT InheritDisposition;
ULONG AllocationType;
ULONG Win32Protect;
} * stack = (MapViewOfSection_stack*)(ULONG_PTR)ExceptionInfo->ContextRecord->Esp;
if (stack->ProcessHandle == NtCurrentProcess())
{
SECTION_BASIC_INFORMATION sbi;
if (0 <= ZwQuerySection(stack->SectionHandle, SectionBasicInformation, &sbi, sizeof(sbi), 0))
{
if (PVOID pv = VirtualAlloc(0, (SIZE_T)sbi.Size.QuadPart, MEM_RESERVE|MEM_TOP_DOWN, PAGE_NOACCESS))
{
if (VirtualFree(pv, 0, MEM_RELEASE))
{
*stack->BaseAddress = pv;
}
}
}
}
// RESUME_FLAG ( 0x10000) not supported by xp, but anyway not exist 64bit xp
ExceptionInfo->ContextRecord->EFlags |= RESUME_FLAG;
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
struct LOAD_DATA {
PCWSTR lpLibFileName;
HMODULE hmod;
ULONG dwError;
};
ULONG WINAPI HideFromDebuggerThread(LOAD_DATA* pld)
{
NtSetInformationThread(NtCurrentThread(), ThreadHideFromDebugger, 0, 0);
ULONG dwError = 0;
HMODULE hmod = 0;
if (PVOID pv = AddVectoredExceptionHandler(TRUE, OnVex))
{
::CONTEXT ctx = {};
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
ctx.Dr7 = 0x404;
ctx.Dr1 = (ULONG_PTR)pvNtMapViewOfSection;
if (SetThreadContext(GetCurrentThread(), &ctx))
{
if (hmod = LoadLibraryW(pld->lpLibFileName))
{
pld->hmod = hmod;
}
else
{
dwError = GetLastError();
}
ctx.Dr7 = 0x400;
ctx.Dr1 = 0;
SetThreadContext(GetCurrentThread(), &ctx);
}
else
{
dwError = GetLastError();
}
RemoveVectoredExceptionHandler(pv);
}
else
{
dwError = GetLastError();
}
pld->dwError = dwError;
return dwError;
}
HMODULE LoadLibHigh(PCWSTR lpLibFileName)
{
BOOL bWow;
HMODULE hmod = 0;
if (IsWow64Process(GetCurrentProcess(), &bWow) && bWow)
{
if (pvNtMapViewOfSection = GetProcAddress(GetModuleHandle(L"ntdll"), "NtMapViewOfSection"))
{
LOAD_DATA ld = { lpLibFileName };
if (IsDebuggerPresent())
{
if (HANDLE hThread = CreateThread(0, 0, (PTHREAD_START_ROUTINE)HideFromDebuggerThread, &ld, 0, 0))
{
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
}
else
{
HideFromDebuggerThread(&ld);
}
if (!(hmod = ld.hmod))
{
SetLastError(ld.dwError);
}
}
}
else
{
hmod = LoadLibrary(lpLibFileName);
}
return hmod;
}

Screen size in inches on Windows

I am developing a multi-platform game that runs on iOS as well as desktops (Windows, Mac, Linux). I want the game to be able to resize certain UI elements depending on the resolution of the screen in inches. The idea is that if a button should be, say, around 1/2 inch across in any interface, it will be scaled automatically that size.
Now for iOS devices this problem is reasonably well solvable using brute force techniques. You can look up the type of the device and use a hard-coded table to determine the screen size in inches for each device. Not the most elegant solution, but sufficient.
Desktops are the tricky ones. What I wish and hope exists is a mechanism by which (some?) monitors report to operating systems their actual screen size in inches. If that mechanism exists and I can access it somehow, I can get good numbers at least for some monitors. But I've never come across any such concept in any of the major OS APIs.
Is there a way to ask for the screen size in inches in Win32? If so, are there monitors that actually provide this information?
(And if the answer is no: Gosh, doesn't this seem awfully useful?)
For Windows, first see SetProcessDPIAware() for a discussion on turning off automatic scaling, and then call GetDeviceCaps( LOGPIXELSX ) and GetDeviceCaps( LOGPIXELSY ) on your HDC to determine the monitor's DPI. Divide the screen resolution on your active monitor by those settings and you've got the size.
Also see this article for a similar discussion on DPI aware apps.
Here is a method I found at the web address "https://ofekshilon.com/2011/11/13/reading-monitor-physical-dimensions-or-getting-the-edid-the-right-way/".
Authour says that measurement is in millimeters.
Does not give you the precise width and height but better approximation than HORSIZE and VERTSIZE. In which I tried on two different monitors and got a max difference of 38 cm (measured screen size - calculated screen size).
#include <SetupApi.h>
#pragma comment(lib, "setupapi.lib")
#define NAME_SIZE 128
const GUID GUID_CLASS_MONITOR = {0x4d36e96e, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18};
// Assumes hDevRegKey is valid
bool GetMonitorSizeFromEDID(const HKEY hDevRegKey, short& WidthMm, short& HeightMm)
{
DWORD dwType, AcutalValueNameLength = NAME_SIZE;
TCHAR valueName[NAME_SIZE];
BYTE EDIDdata[1024];
DWORD edidsize=sizeof(EDIDdata);
for (LONG i = 0, retValue = ERROR_SUCCESS; retValue != ERROR_NO_MORE_ITEMS; ++i)
{
retValue = RegEnumValueA ( hDevRegKey, i, &valueName[0],
&AcutalValueNameLength, NULL, &dwType,
EDIDdata, // buffer
&edidsize); // buffer size
if (retValue != ERROR_SUCCESS || 0 != strcmp(valueName,"EDID"))
continue;
WidthMm = ((EDIDdata[68] & 0xF0) << 4) + EDIDdata[66];
HeightMm = ((EDIDdata[68] & 0x0F) << 8) + EDIDdata[67];
return true; // valid EDID found
}
return false; // EDID not found
}
// strange! Authour requires TargetDevID argument but does not use it
bool GetSizeForDevID(const char *TargetDevID, short& WidthMm, short& HeightMm)
{
HDEVINFO devInfo = SetupDiGetClassDevsExA(
&GUID_CLASS_MONITOR, //class GUID
NULL, //enumerator
NULL, //HWND
DIGCF_PRESENT, // Flags //DIGCF_ALLCLASSES|
NULL, // device info, create a new one.
NULL, // machine name, local machine
NULL);// reserved
if (NULL == devInfo) return false;
bool bRes = false;
for (ULONG i=0; ERROR_NO_MORE_ITEMS != GetLastError(); ++i)
{
SP_DEVINFO_DATA devInfoData;
memset(&devInfoData,0,sizeof(devInfoData));
devInfoData.cbSize = sizeof(devInfoData);
if (SetupDiEnumDeviceInfo(devInfo,i,&devInfoData))
{
HKEY hDevRegKey = SetupDiOpenDevRegKey(devInfo,&devInfoData,DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
if(!hDevRegKey || (hDevRegKey == INVALID_HANDLE_VALUE)) continue;
bRes = GetMonitorSizeFromEDID(hDevRegKey, WidthMm, HeightMm);
RegCloseKey(hDevRegKey);
}
}
SetupDiDestroyDeviceInfoList(devInfo);
return bRes;
}
int main(int argc, CHAR* argv[])
{
short WidthMm, HeightMm;
DISPLAY_DEVICE dd;
dd.cb = sizeof(dd);
DWORD dev = 0; // device index
int id = 1; // monitor number, as used by Display Properties > Settings
char DeviceID[1024];
bool bFoundDevice = false;
while (EnumDisplayDevices(0, dev, &dd, 0) && !bFoundDevice)
{
DISPLAY_DEVICE ddMon = {sizeof(ddMon)};
DWORD devMon = 0;
while (EnumDisplayDevices(dd.DeviceName, devMon, &ddMon, 0) && !bFoundDevice)
{
if (ddMon.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP &&
!(ddMon.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
{
sprintf(DeviceID,"%s", ddMon.DeviceID+8);
for(auto it=DeviceID; *it; ++it)
if(*it == '\\') { *it = 0; break; }
bFoundDevice = GetSizeForDevID(DeviceID, WidthMm, HeightMm);
}
devMon++;
ZeroMemory(&ddMon, sizeof(ddMon));
ddMon.cb = sizeof(ddMon);
}
ZeroMemory(&dd, sizeof(dd));
dd.cb = sizeof(dd);
dev++;
}
return 0;
}

Change background color of Solution Explorer in Visual Studio

Is there any way to change the background color of the Solution Explorer in Visual Studio using a Theme? - or any other way for that matter?
I can change it by changing windows-wide color settings, but obviously that affects too much.
Just created VS extension for that in under an hour, search extension manager for "SExColor". Enjoy ;)
#aloneguid ...should have seen this long time ago.. thank you sir !
#ver (regarding vs 2008 solution for solution;) - a B52 type of approach, carpet bombing on anything that is SysTreeView32 inside a devenv.exe. Possible extra param for desired color, otherwise RGB(220,220,220) - works best for me
#include <windows.h>
#include "psapi.h"
#include "shlwapi.h"
#include "commctrl.h"
COLORREF clr = RGB(220,220,220);
BOOL CALLBACK wenum( HWND hwnd, LPARAM lParam)
{
const UINT cb = 261;
static wchar_t name[] = L"SysTreeView32",
tmp[cb] = {0};
if( ::GetClassNameW( hwnd, tmp, 260 ) && 0 == _wcsicmp( name, tmp ) )
{
::SendMessageW( hwnd, TVM_SETBKCOLOR, 0, (LPARAM)clr );
}
return TRUE;
}
BOOL CALLBACK EnumTops(HWND hwnd, LPARAM lParam)
{
DWORD dwThreadId = 0,
dwProcessId = 0;
HINSTANCE hInstance;
static wchar_t derVS[] = L"devenv.exe";
wchar_t name[_MAX_PATH] = {0},
*exe = 0;
HANDLE hProcess;
if (!hwnd) return TRUE; // Not a window
if (!::IsWindowVisible(hwnd)) return TRUE; // Not visible
if (!SendMessage(hwnd, WM_GETTEXT, sizeof(name), (LPARAM)name))
return TRUE; // No window title
dwThreadId = GetWindowThreadProcessId(hwnd, &dwProcessId);
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if( !GetModuleFileNameEx(hProcess, 0, name, sizeof(name))) goto exit;
exe = ::PathFindFileNameW( name );
if( (void*)exe == (void*)name ) goto exit; // mhm? maybe not exit?
if( _wcsicmp( derVS, exe ) ) goto exit;
EnumChildWindows( hwnd, wenum, (LPARAM)hProcess );
exit:
CloseHandle(hProcess);
int res = GetLastError();
return res;
}
int wmain(int argc, wchar_t * argv[])
{
if( argc >= 2 )
{
wchar_t *end = 0;
long l = wcstol( argv[1], &end, 16 );
clr = (DWORD)l;
}
::EnumWindows(EnumTops, NULL);
return 0;
}
Even changing the standard Windows background color does not work for the Solution Explorer. This Visual Studio bug report mentions the issue. Microsoft has marked this as "Closed -- Won't Fix."
Which is very irritating! Using a dark theme and having a bright white Solution Explorer hanging on the side of the screen is extremely annoying.
One possible solution is to not use the Solution Explorer at all. The Productivity Power Tools provides a Solution Explorer replacement called the "Solution Navigator." It currently is also hard-coded to white. But I think there is probably a better chance of getting the developers of that tool to add support for modifying colors than of getting Microsoft to do it in Visual Studio. (even though Microsoft created the PPTs.)
Not by any means of configuration from Visual Studio itself.
You can however probably "hack" the window object from the Win32 API (look up "window enumeration"). Once you have the window handle, you can set all characterstics you want.
Regards
/Robert
You could use other extenssion, you have quite big possibilities to do your Visual Studio more good looking ;) (but I'm not sure if there you could change Solution Explorer background)
http://visualstudiogallery.msdn.microsoft.com/20cd93a2-c435-4d00-a797-499f16402378

Resources