Question

I'm writing a program that uses SetWindowRgn to make transparent holes in a window that belongs to another process. (This is done only when the user explicitly requests it.)

The program has to assume that the target window may already have holes which need to be preserved, so before it calls SetWindowRgn, it calls GetWindowRgn to get the current region, then combines the current region with the new one and calls SetWindowRgn:

HRGN rgnOld = CreateRectRgn ( 0, 0, 0, 0 );
int regionType = GetWindowRgn ( hwnd, rgnOld ); 

This works fine in XP, but the call to GetWindowRgn fails in Vista. I've tried turning off Aero and elevating my thread's privilege to SE_DEBUG_NAME with AdjustTokenPrivileges, but neither helps.

GetLastError() doesn't seem to return a valid value for GetWindowRgn -- it returns 0 on one machine and 5 (Access denied) on another.

Can anyone tell me what I'm doing wrong or suggest a different approach?

Was it helpful?

Solution

Are you sure your window has a region? Most top-level windows in XP do, simply because the default theme uses them for round corners... but this is still a bad assumption to be making, and may very well not hold once you get to Vista.

If you haven't set a region yet, and the call fails, use a sensible default (the window rect) and don't let it ruin your life. Now, if SetWindowRgn() fails...

OTHER TIPS

Under Vista, in order for a process that does not run as administrator to target a window from another process, it must:

  • Embed a manifest file with uiAccess="true" (example below)
  • Digitally sign the application
  • Install and execute it from a "safe" place, like "Program Files"

Here's a sample manifest:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="yourAssemblyNameWithoutExtension" type="win32"/>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="asInvoker" uiAccess="true" />
      </requestedPrivileges>
    </security>
  </trustInfo>
</assembly>

You mention that you're trying to get the region of the window of another process. Vista tightened up the security of a lot of cross-process Win32 calls. I can't find any documentation one way or the other for GetWindowRgn(), but you could test it simply enough. Make a simple project that sets it's own region, and try to use your original app to get the simple app's region. If it works, then it's just going to be annoying and people can't use your app on just anything. If it doesn't work, there's a chance that your app won't work at all on Vista.


My answer (based on my experience) regarding the Windows API function ::GetWindowRgn(...)

This function fails in Vista and in Windows 7, that is, it returns ERROR.

But this function works good in Windows XP.

Therefore, I would advice the following non-complex solution: If you use this function within an application expected to run under different Windows, provide the test like this: int nResultOfRgnOperation = ::GetWindowRegion(...); if (nResultOfRgnOperation != ERROR) < Use further the entire window's region determined by this function > else < Find the bounding rectangle for the entire window and use further that bounding rectangle instead of the window's region. In needed, you can create a rectangular region which represents the bounding rectangle. >

Please use corresponding code in the places marked above as <...>

Thank you for your enthusiasm.


Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top