Welcome to MSDN Blogs Sign in | Join | Help

Teaching Children to Program

I was playing Robozzle with my oldest and he was having a blast and loved that he was programming like Dad does.  (He did let me know he wants to be policeman though. :)  It’s a fun way to introduce kids to programming and reminds me a little of the little logo turtle. 

I didn’t start out programming that way – I got into programming because my Dad was too busy to start the games I wanted to play on a computer.  Funny how one things leads to another – I ended up learning how to start the games, then I wanted more games which meant I had to program them from books (basic on the TI, don’t remember the other languages).  And eventually we learned how to make the computer do stuff (little Tron games on an apple IIe that my Grandpa had, that kind of thing).  We had a lot of fun with it, and I was way ahead when I took my first programming class – so much so that I finished very early and spent the time playing various computer games (full circle :).  So I’m a big believer in teaching kids skills through games (more fun for you, too).

What games have you found that do this for programming?  What really easy programming experiences are out there?  I would love to hear what you’ve found, and recommend that you give Robozzle a try (and contribute more easy puzzles so kids have more puzzles before things get too tricky).

Posted by jamesfinnigan | 0 Comments
Filed under: ,

Hyper-V review

The hypervisor support in Server 2008 is now out in beta and it's great to see the product hitting the street.  Virtualization is a huge change for the industry that can do a lot for everyone from data-centers to software houses, to people who just want to be able to run programs without worrying as much (yes, yes, escape exploits would remain a concern).

Here's a review from Windows IT Pro.  Of course, this isn't what I actually work on - I work on the Virtual Machine Manager.  Sadly, our product is still behind closed doors - I can't wait to get it out to customers.

To follow along until then, enjoy Rakesh's blog, which explains such decisions as Why we decided to manage VMWare.

Cheers,

James

Beginning again - and hiring

Well, fun times.  I've taken a position on the Virtual Machine Manager team.  I'll be one of the lead developers working on the next version.  It's an exciting space, with a lot of players and a lot of new technologies.

I'm also hiring.  So if you're interested we have a number of interesting positions UI and non-UI related (as you might imagine :)). 

Here's a link to a UI programmer position, but please feel free to send me a message if you're interested.  And again, I'm hiring for non-UI positions as well - the link is just to show a little more information about the team and the direction that we're headed.   (We are a C# shop.)

If you're interested in hearing more, you can follow along on the team blog.

Posted by jamesfinnigan | 0 Comments
Filed under: , ,

The Shell Extensions Approved list is *not* a complete list of shell extensions on the system

I've noticed that a number of different programs just look at the Approved list of shell extensions [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved] and figure that all shell extensions will be in that list.  It's not true, because lots of folks don't really care about that policy.  I don't know how often it's used - it doesn't really make your system more secure as far as I can tell.  (It may reduce the TCO related to folks installing poorly written shell extensions.)

It also doesn't apply to all shell extensions.  There are many of them (probably some of them with HKCU extensibility) that haven't been moved to the policy system yet.  (So you should always register your shell extensions there, even if it doesn't seem to be necessary.)

(That said, it certainly does give you quite a few of them for very little work. On my system, it finds about 325/400 - about 80%.  Because of that, if you're thinking about turning on this policy consider the fact that you'll be disabling 1 in 5 shell extensions; will that generate more or less support calls?)

Posted by jamesfinnigan | 0 Comments
Filed under: ,

Supplemental Registrations (aka. Context Menu Handers (etc) - where are they loaded from...)

I've been thinking about the registration problem where you want to add a context menu (much of this applies to static verbs as well) to a file type (we'll say .ogg).  You don't want the default verb, you just want to add some verbs.  Because you don't want the default, you shouldn't put your progid in the HKCR\.ogg default value, so you put an entry under HKCR\.ogg\shellex\ContextMenuHandler.  And this works great.. until someone comes along and puts a progid in HKCR\.ogg's default value.  Look at the fallthrough logic below - #2 (where we registered), and #3 are only used if there is no progid! 

Fallthrough logic when loading context menu handlers (static verbs and then context menu handlers are collected from the following places):

(DO NOT USE THIS LOGIC IN YOUR CODE - it is a simplification of the real logic and it will change.  Instead, use IQueryAssociations or AssocQuery* for all these kinds of file association related things.)

  1. HKCR\<ProgID>
  2. HKCR\<.ext> (only if #1 does not exist)
  3. HKCR\Unknown (only if #1 does not exist)
  4. HKCR\SystemFileAssociations\<.ext>
  5. HKCR\SystemFileAssociations\<PerceivedType>
  6. HKCR\Folder (only used if the selected item has the SFGAO_FOLDER attribute, such as a folder, zip, cab, etc.)
  7. HKCR\*
  8. HKCR\AllFilesystemObjects

But there is a way!  You can register supplemental verbs associated with the SystemFileAssociations key.  Note that those keys (#4 and #5) are folded in regardless of the association having a progid registered.  In our example, that would be HKCR\SystemFileAssociations\.ogg\shellex\ContextMenuHandler

The important thing here is that you should never put the registration under HKCR\<.ext>(!) because you should either be putting it under your progid (#1), or in SystemFileAssociations (#4).  Why do we disable #2 and #3 in those cases?  If folks are interested, I'll talk more about that later - or feel free to guess. :)

(A quick comment about #5 - I think it is often misused.  Applications don't know how to handle very many perceived types (one exception is text).  How are you going to handle the "video" perceived type?  I guarantee that we'll come out with more codecs/container formats, etc.  Unless you can guarantee that you can handle everything that will map into the perceived type, don't register for it - instead register for the individual associations that you really can handle.)

This technique is used for a lot of other things besides context menu handlers.  It's also used for Property Handlers for Windows Search, Windows Imaging Component codecs, etc, etc, etc.

Cheers,
James

[Update: finished the sentence beginning "In our example, that would be..."]

Posted by jamesfinnigan | 7 Comments
Filed under: ,

Installing shell extensions - please complain here

So... I've been looking more closely at Wix and I think I'm going to build some custom actions to do a really good job installing shell extensions.  Which ones do you find most problematic?  I realize this is a bit of a change of pace for the blog, so I'll probably hit a few other forums, but please feel free to add comments/complaints about which extensions are problematic.

Maybe you've already done the work to install these properly, but in some cases that can be quite complicated and I could see a lot of folks just accepting some minor bugs and moving on.

I'll start:

Protocol Handlers (http://msdn2.microsoft.com/en-us/library/bb266527.aspx) and Schema Extensions (http://msdn2.microsoft.com/en-us/library/ms647576.aspx).  Both of these require custom actions to be installed correctly - and there's no standard for it so everyone is probably doing it themselves which is going to lead to some really inconsistent behavior.  None of that is going to help system stability at all.

Another one I came across recently was installing a shell folder that should appear on the desktop.  I added it to the desktop namespace but until the user refreshes the desktop it isn't going to appear.  You need to send a SHChangeNotify to get it to show up without user intervention.  Anyway, there's no standard action for that.  So unless you can accept a shortcut to the shell folder (which sends a notification), you'll want a CA there as well.  And there again, you want to send as minimal a notification as possible to avoid having the system reload everything when all that you needed is a new icon to show up.

File Associations:
This one is going to be a bit of a laundry list of issues, but I'll start off the first couple issues.

  1. If previous handlers didn't register under openwith then your registration may blow away any record that they wanted to handle that file association.
  2. If you register under a meta-type like TXTFile and then someone else claims .txt then you don't get invoked at all.
  3. Man that thing is complicated.  Way, way complicated. (I'm still learning the subtleties - feel free to correct me if I miss a beat.)

So there's a start - let me know as you come across other issues.

Cheers,
James

 

Posted by jamesfinnigan | 9 Comments
Filed under: , , , , ,

Summer Fun, Full House

(Normally this kind of post is reserved for my other blog where I mostly blog about non-tech - so don't worry, I won't be boring you with stories of how incrediby smart and cute my little boys are (obviously my wife's DNA is doing overtime).)

We've been enjoying our summer, with lots of friends around and good weather.  We've got my sister-in-law staying with us while she gets her dental certification.  Our youngest probably doesn't even remember life before she came to live with us.  And for a few weeks we had a friend of mine from college crashing at our place for a bit while they worked out their housing situation.  (Because John's doing his residency and needs to be very close to a number of hospitals, he needed to be in a very narrow corridor and had trouble finding folks who wanted to rent to someone out-of-state when there were plently of applicants in-state.)  And the weather has been hot, but nice.

John is an eye surgeon and sees some pretty crazy stuff.  Every once in a while I'll pick up his texts and look at something I hope never happens to me and be glad that someone is helping those folks.  For example, the 4th of July had some obligatory fireworks mishaps.  His days are pretty different from mine - I'm a little jealous of how closely he gets to work with the people he's helping.  (I couldn't resist asking him if Scrubs had any parts that resembled reality - Apparently not. :) 

Anyway his kids are about the same age and they spent all their time together.  Now that John and crew are settled in their new house, we're looking forward to hitting some cool places around here with them.  It's a little limiting with small children (I have to wait before they're ready to go rock climbing with me :)), but I'm in no hurry for them to grow up.  If you have any recommendations for good 2-5 year old destinations, I'd love to hear them.

Cheers,
James

Posted by jamesfinnigan | 2 Comments
Filed under:

The best way to make UAC shut up for a while

Let's say you want to install a few things and want UAC to stop bugging you while you install them.  Should you turn off UAC and install the apps?  Since that disables UAC's virtualization, it can destabilize things that depend on data written to those virtual locations.  Here's an alternative that keeps all the virtualization intact while getting UAC to lay off for a while.

Fire up gpedit.msc and adjust this policy (pictured below):

image

Change it to be Elevate without prompting:

image

Of course, remember to turn it back when you're done! :)

Cheers,

James

[Update: how to do this without using gpedit.msc]

Run this command (from an elevated command prompt) to make UAC elevate without prompting:

reg ADD HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v ConsentPromptBehaviorAdmin /t REG_DWORD /d 0 /f

When you're done, run this command (from an elevated command prompt) to set it back to the default:

reg ADD HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v ConsentPromptBehaviorAdmin /t REG_DWORD /d 2 /f

Posted by jamesfinnigan | 2 Comments
Filed under: , , , ,

How to stop WinDbg from going crazy and loading all the symbols

One of my favorite features of WinDbg is that it doesn't load all the symbols up-front.  That's a huge part of what makes it so much faster than Visual Studio.  However, every once in a while you can do things that cause WinDbg to go crazy and load all the symbols in a desperate attempt to resolve a symbol that it just isn't finding.  Oftentimes this is because of a typo, or because you forgot to scope the symbol to a module.  It's annoying - but it's not something that you have to live with.

To tell WinDbg not to do it's whole-hog symbol search use this command:

.symopt+ 100

If you find yourself in a situation where you don't want to wait for the debugger to finish resolving symbols before issuing the command, you can just start windbg with the -snul parameter.  In some cases, the reason this is happening is some goofy breakpoint you set, or something in your watch window - it's not going away.  If you don't want to take the time to track it down, you can bail on the workspace by starting windbg with the -WX parameter, and saving whatever you put into the first one.

Here's what the documentation has to say on the topic:

SYMOPT_NO_UNQUALIFIED_LOADS
This symbol option disables the symbol handler's automatic loading of modules. When this option is set and the debugger attempts to match a symbol, it will only search modules [whose symbols] have already been loaded.
This option can be used as a defense against mistyping a symbol name. Normally, a mistyped symbol will cause the debugger to pause while it searches all unloaded symbol files. When this option is active, a mistyped symbol will not be found in the loaded modules, and then the search will terminate.
This option is off by default. It can be activated by using the -snul command-line option. Once the debugger is running, it can be turned on or off by using .symopt+0x100 or .symopt-0x100, respectively


All postings are provided "AS IS" with no warranties, and confers no rights. Use of included script samples are subject to the terms specified at http://www.microsoft.com/info/cpyright.htm
Posted by jamesfinnigan | 0 Comments
Filed under: ,

Breaking when the instruction pointer leaves the module

The problem is to skip out of a kernel driver that we don't have symbols for - what's the best way to break on calls out of that driver.

If you used pc (step until the next call instruction), you would hit calls that are inside that driver.

Here's another approach (using an example from Pavel Lebedynskiy) - step until the ip address moves outside that module:

.while (@eip > fee50000 & @eip < feef1000) { t; reip }

If you want to skip the output, you can use setting the instruction pointer instead like we did in the last post using a .while trick.


All postings are provided "AS IS" with no warranties, and confers no rights. Use of included script samples are subject to the terms specified at http://www.microsoft.com/info/cpyright.htm

Posted by jamesfinnigan | 0 Comments
Filed under: ,

Finding where a bad HRESULT is returned

I've looked at this a couple times, but here's another way to break when the error code you're looking at is being returned.

.while(@eax != 0xc0000005) { t ; reax }

If you want to avoid the output noise, you can do something like this:

.while(@eax != 0xc0000005) { t ; r @eip = @eip}; r eax


All postings are provided "AS IS" with no warranties, and confers no rights. Use of included script samples are subject to the terms specified at http://www.microsoft.com/info/cpyright.htm

Posted by jamesfinnigan | 0 Comments
Filed under: ,

How to only break on a jump when it will be taken

Here's a question that came up a work a little bit back - thought I would share the result around.

There is a coding pattern (that I don't ever really use so I may be messing it up) that works like this:

T1 res1;
T2 res2;
T3 res3;

res1 = GetRes1();
if (!res1) goto Cleanup;

res2 = res1.GetRes2();
if (!res2) goto Cleanup;

res3 = res2.GetRes3();

Cleanup:
if (res3) CleanupRes3(res3);
if (res2) CleanupRes3(res2);
if (res1) CleanupRes3(res1);

So what if you wanted to break when you are at Cleanup because res2 was null?  You can set a breakpoint with a conditional that will only break when the jump to Cleanup from res2 is going to be taken.  You could base it on the symbols and do the comparison yourself. However, in optimized code the debuggers understanding of local variable information is often incorrect (the compiler doesn't emit enough information in the pdb to make this possible).  In that case, it may be most convenient to make a conditional breakpoint using the x86 flags (described in detail in the help file that comes with windbg under the topic x86 Architecture).

Here's an example:

ntdll!RtlUnlockModuleSection+0x23a:
77937c71 8b4590          mov     eax,dword ptr [ebp-70h]
77937c74 6683785c01      cmp     word ptr [eax+5Ch],1
77937c79 7416            je      ntdll!RtlUnlockModuleSection+0x25a (77937c91)

0:000> bu ntdll!RtlEncodePointer+0x21a ".if (@ZF=1) { gc } "
0:000> g
ChildEBP RetAddr
WARNING: Stack unwind information not available. Following frames may be wrong.
0011f678 77945ad7 ntdll!RtlEncodePointer+0x21a
0011f6e4 7794a980 ntdll!RtlGetNtVersionNumbers+0x83
0011f6f4 00000000 ntdll!LdrInitializeThunk+0x10
eax=00000002 ebx=7ffde000 ecx=779a00dd edx=77970f34 esi=00000000 edi=779d5d14
eip=77944bef esp=0011f534 ebp=0011f678 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
ntdll!RtlEncodePointer+0x21a:
77944bef 740d            je      ntdll!RtlEncodePointer+0x229 (77944bfe) [br=0]

ZF=1 is the flag for a comparison (which is a subtraction that sets flags) that was equal (so a subtraction would naturally result in 0 - setting the zero flag).  In this second example we're interested in breaking when it is not equal, so we used gc (to continue execution) when ZF=1.

 

Cheers!

James

Posted by jamesfinnigan | 0 Comments
Filed under: ,

Making an MSI that doesn't need a UAC/LUA prompt

The goal

I think that most things don't need to require a UAC prompt to install - just install it for that user.  Why not make the MSI so it doesn't prompt and your users get a smoother experience?  (Also, I feel much better installing a program that doesn't require elevation to install - at a minimum I know it's not disabling my anti-malware software.)  Ideally, with that same package you could optionally install per-machine (which requires elevation).  Here's some information on how to make it happen...

Background

I was recently asked to make an MSI for an extremely minimal replacement of the Run As menu item that was removed in Vista (by calling runas.exe).  Although I doubt we would ever ship something like that I decided to make an installation that didn't elevate, or that could elevate and install per-machine.  It was an interesting experience, although I didn't entirely get the behavior I was going for - there are some limitations that make it impossible to do with a MSI in Windows Vista, but still possible in a single download.  (More on that later).

The technical details

All MSIs elevate on Windows Vista by default.  However there is a flag that you can set that will tell MSI that you don't need to elevate.  The 3rd bit of the word count summary property can be set by using the msiinfo tool (comes with the platform SDK).  Since I also used an embedded cab, that means my word count summary property should be set to 10 (8 | 2 == 10).

msiinfo RunAsNewUser.msi -w 10

You need to have the feature include both the per-user and per-machine information if you're trying to put both in one package like I did (not a best practice - more on that later). 

    <Feature Id='RunAsNewUser' Title='Run as New User' Level='1'>
      <ComponentRef Id='pm.runasnewuser.cmd' />
      <ComponentRef Id='pm.runasnewuser.reg.exe' />
      <ComponentRef Id='pm.runasnewuser.reg.msc' />
      <ComponentRef Id='pu.runasnewuser.cmd' />
      <ComponentRef Id='pu.runasnewuser.reg.exe' />
      <ComponentRef Id='pu.runasnewuser.reg.msc' />
    </Feature>

Your standard MSI that installs to the system directories doesn't face the (fairly simple) issues involved.  Here's the per-machine version of my components (you need two versions of the components in order to put them in different directories(*). [I build all my MSIs using Wix - it gives me fine-grained control for making really solid MSIs and it tends to match the way I want to think about MSIs.]

      <!-- We need a per-machine version as well, with seperate components -->
      <Directory Id='ProgramFilesFolder' Name='AdTools'>
        <Directory Id='pm.Microsoft' Name='Microsoft'>
          <Directory Id='pm.Runas' Name='RunAs'>
            <Component Id='pm.runasnewuser.cmd' Guid='9D448C8B-AF67-423B-9622-D9720770B61E'>
              <File Id='pm.runasnewuser.cmd' Name='runasnewuser.cmd' DiskId='1' Source='runasnewuser.cmd' KeyPath='yes' />
              <Condition>ALLUSERS</Condition>
            </Component>
            <Component Id='pm.runasnewuser.reg.exe' Guid='98A7DE3E-EF1D-434F-80CB-2F878CD0E9F5'>
              <RegistryKey Id='pm.runasnewuser.reg.exe' Key='SystemFileAssociations\.exe\shell\Run as new user...\command' Root='HKCR' Action='createAndRemoveOnUninstall'>
                <RegistryValue Id='pm.runasnewuserCommand.exe' Type='expandable' Value='"[#pm.runasnewuser.cmd]" "%1" %*' KeyPath='yes'/>
              </RegistryKey>
              <Condition>ALLUSERS</Condition>
            </Component>
            <Component Id='pm.runasnewuser.reg.msc' Guid='20D758CC-2774-4532-BD6D-E7C378761C90'>
              <RegistryKey Id='pm.runasnewuser.reg.msc' Key='SystemFileAssociations\.msc\shell\Run as new user...\command' Root='HKCR' Action='createAndRemoveOnUninstall'>
                <RegistryValue Id='pm.runasnewuserCommand.msc' Type='expandable' Value='"[#pm.runasnewuser.cmd]" "%1" %*' KeyPath='yes'/>
              </RegistryKey>
              <Condition>ALLUSERS</Condition>
            </Component>
          </Directory>
        </Directory>
      </Directory>

Notice that I made these components conditional on ALLUSERS.  We'll make the per-user version conditional on NOT (ALLUSERS).  This is pretty basic stuff, and is more or less simply specifying what goes where without much specialized stuff.  You can do a per-user setup that looks quite similar by putting it somewhere that isn't off the user's profile.  I decided to put mine in the user's profile which means a little extra baggage.

So we're basically done right?  Well, not really, no.  We've disabled the elevation, but now you need to make your installation not require elevation.  Things like installing to Program Files require admin rights, so we'll need to install to somewhere else.  I'm not really sure where that should be - probably %UserProfile%\ProgramFiles or something like that.  In this example, I installed to LocalAppData.

      <Directory Id='LocalAppDataFolder' Name='AdTools'>
        <Directory Id='pu.Microsoft' Name='Microsoft'>
          <Directory Id='pu.Runas' Name='RunAs'>
            <Component Id='pu.runasnewuser.cmd' Guid='06A57A74-7639-4A96-A1FF-6C434ED50CEF'>
              <File Id='pu.runasnewuser.cmd' Name='runasnewuser.cmd' DiskId='1' Source='runasnewuser.cmd' />
              <RegistryValue Id='pu.runasnewuser.cmd.keypath' Root='HKCU' Key='Software\Microsoft\RunAs\KeyPaths' Type='string' Value='RunAsNewUser.cmd' KeyPath='yes' />
              <RemoveFolder Id='pu.Runas' Directory='pu.Runas' On='uninstall'/>
              <RemoveFolder Id='pu.Microsoft' Directory='pu.Microsoft' On='uninstall'/>
              <Condition>NOT (ALLUSERS)</Condition>
            </Component>
            <Component Id='pu.runasnewuser.reg.exe' Guid='C0DB0776-441A-4AB9-871A-5AF1F326FA0A'>
              <RegistryKey Id='pu.runasnewuser.reg.exe' Key='SystemFileAssociations\.exe\shell\Run as new user...\command' Root='HKCR' Action='createAndRemoveOnUninstall'>
                <RegistryValue Id='pu.runasnewuserCommand.exe' Type='expandable' Value='"[#pu.runasnewuser.cmd]" "%1" %*' />
              </RegistryKey>
              <RegistryValue Id='pu.runasnewuser.reg.keypath' Root='HKCU' Key='Software\Microsoft\RunAs\KeyPaths' Type='string' Value='RunAsNewUser.reg' KeyPath='yes' />
              <Condition>NOT (ALLUSERS)</Condition>
            </Component>
            <Component Id='pu.runasnewuser.reg.msc' Guid='C5B94A3B-7D87-4FC0-AC28-111B86679251'>
              <RegistryKey Id='pu.runasnewuser.reg.msc' Key='SystemFileAssociations\.msc\shell\Run as new user...\command' Root='HKCR' Action='createAndRemoveOnUninstall'>
                <RegistryValue Id='pu.runasnewuserCommand.msc' Type='expandable' Value='"[#pu.runasnewuser.cmd]" "%1" %*' />
              </RegistryKey>
              <RegistryValue Id='pu.runasnewuser.reg.msc.keypath' Root='HKCU' Key='Software\Microsoft\RunAs\KeyPaths' Type='string' Value='RunAsNewUser.reg.msc' KeyPath='yes' />
              <Condition>NOT (ALLUSERS)</Condition>
            </Component>
          </Directory>
        </Directory>
      </Directory>

The extra baggage is the HKCU keypath RegistryValue, and the RemoveFolder entries.  Nothing crazy, but a little extra to be aware of.  These are necessary because of things like roaming profiles.

The experience

 You can install it and it goes through without any elevation.  The installation is per-user by default.  (Yay! Per-user works and has a smokin' experience, and supports all kinds of scenarios.)

If you want to install it per-machine, you need to launch it via this command:

msiexec /i RunAsNewUser.msi ALLUSERS=1

This is obviously not ideal - but there's a hidden hiccup.  I thought that it would prompt for elevation if you specified ALLUSERS=1 - it does not.  You get this error message:

You do not have sufficient privileges to complete this installation for all usrs of the machine.

It's not the end of the world.  If you run the same command from an already elevated process (e.g. an elevated command prompt) the installation goes through just fine (as the error message implies).  It's a bit of a shame, but I've confirmed with Carolyn that you can't build a single package that will elevate sometimes and sometimes not (because the flag is in the MSI summary information it can't be changed in-flight).

The best practice for building a per-user (without elevation) and per-machine app (with elevation)

Because of the limitations noted above, here's what is the best practice for building a per-user and per-machine app:  Have a bootstrapper exe, and two separate MSIs (one per-user package and one per-machine package).  If these are embedded in the bootstrapper exe as resources that are extracted at install, then you can a single download that installs either as per-machine or per-user.

Why?  Well, not many folks are trying to do this at the moment.  Of course, more will as Vista is on more and more computers - ultimately I think this is a huge step forward for keeping your computer free of malware.  I think it's worth saying twice: I feel much better installing a program that doesn't require elevation to install - at a minimum I know it's not disabling my anti-malware software.

Other Resources

http://blogs.msdn.com/windows_installer_team/ - Get it straight from the horse's mouth

http://blogs.msdn.com/astebner/archive/2006/12/13/some-useful-things-i-have-learned-about-windows-installer-and-uac.aspx - Good intro article that doesn't bury you in information like Roberts' (great) blog entries

http://blogs.msdn.com/rflaming/archive/2006/10/01/uac-in-msi-notes-answers-to-questions-in-comments-from-earlier-blog-posts.aspx - Summary of Robert's huge series about MSI and UAC

http://blogs.msdn.com/rflaming/archive/2006/09/30/778690.aspx - Robert gives his take on the question: Should I write my installer as a Standard User install? If yes, how?


* I imagine that you don't really need two versions of the components because I imagine that you could change the directory location using a custom action that set it, but I just found things a lot simpler if I used two different components

Posted by jamesfinnigan | 6 Comments
Filed under: , , , , ,

How to launch an un-elevated process from an elevated process

This question has come up a fair amount lately.  The short answer is that you don't* - instead you should:

  1. first launch an unelevated process
  2. have that unelevated process launch an elevated process and wait for it to finish (or use some form of IPC)
  3. have that unelevated process then do what you wanted the elevated process to un-elevate and do

OK, but why?  When you elevated there's a good chance that you also changed users.  If you simply had a way to generate the split token associated with the elevated user, then you would be running as the wrong user.

This is all documented, of course, in the Windows Vista Application Development Requirements for User Account Control Compatibility document (I hate sentence names).

* Caveat:  There is still a way to launch a process as that original user with the split token - use task scheduler (see the linked document for the source code).  I don't recommend using task scheduler (I recommend the process above), but there are times when your choices are limited.

Posted by jamesfinnigan | 0 Comments
Filed under: , , ,

UAC UI on oldnewthing - what the colors mean

I mentioned recently that I was the new owner of the UAC UI (from the dev side).  Well, today I found that Raymond Chen's blog has brought up the topic of what the colors mean.  I hadn't even really noticed that the dialogs changed much before taking ownership of the code, and due to the ease of repurposing attacks there is little comfort in seeing that a particular item is signed.  It's a good first pass, but I definitely think we have room for improvement in creating valuable distinctions and conveying that information to the user.

Posted by jamesfinnigan | (Comments Off)
Filed under: ,
More Posts Next page »
 
Page view tracker