views:

645

answers:

4

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?

+7  A: 

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...

Shog9
Thank you Shog. You nailed it. I was assuming (without realizing it) that windows always have regions.I rewrote it. Now, when GetWindowRgn fails, it sets a region based on the window rect. Works perfectly.This is the best answer I've gotten on a forum in a long time. /salute
FreddieHKN
+1  A: 

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.

HitScan
I did test on my own app. It was the first thing I did. Also, as I mentioned (with an unfortunate typo) I elevated privilege level to debug.Also, I knew when I posted earlier that SetWindowRgn works fine in Vista. I thought it was unlikely that Vista allows setting but disallows getting.
FreddieHKN
+1  A: 

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>
Martin Plante
As Freddie so nicely pointed it out, this does not answer HIS problem. This manifest is required if you are targettting elevated or isolated (e.g. IE7) processes from a non-elevated process.
Martin Plante
A: 

As I explained in a comment, Shog9 answered correctly. Shog9's advice allowed me to rewrite the code so it works perfectly on Vista. Thank you.

HitScan's answer seems reasonable but as I explained in a comment, I had already considered it and had concluded for two reasons that it was probably not the cause of the problem. Thank you for trying.

SlimCODE's answer is just plain wrong (when taken as an answer to my question, which is what it is). It's possible to call GetWindowRgn and SetWindowRgn in Vista on other processes's windows without running as admin and without doing anything that SlimCODE describes. I think it's fine to guess or speculate in an answer as long as the guess or speculation is labeled as such. But for an author to assert something categorically like this, obviously without testing, seems rude to me because it's likely to make the reader waste time coding something that won't work. If I could vote down SlimCODE's answer I would, but I don't have enough reputation points.

FreddieHKN
"seems rude to me" - I'm very sorry! It wasn't my intend to be "rude". Vista does require uiAccess elevation for GetWindowRng (and SetWindowRng) when targetting elevated or isolated (e.g. Internet Explorer 7) processes. That was my mistake. If you don't need this, then I'm glad Shog9 helped you.
Martin Plante