<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>this.Pose() as Expert - UAC</title>
    <link>http://chrison.net/</link>
    <description />
    <language>en-us</language>
    <copyright>Christoph Wille</copyright>
    <lastBuildDate>Mon, 04 Jun 2007 08:34:52 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.3.9074.18820</generator>
    <managingEditor>christoph.wille@gmail.com</managingEditor>
    <webMaster>christoph.wille@gmail.com</webMaster>
    <item>
      <trackback:ping>http://chrison.net/Trackback.aspx?guid=406befc0-334e-4a9d-8812-d840d5869617</trackback:ping>
      <pingback:server>http://chrison.net/pingback.aspx</pingback:server>
      <pingback:target>http://chrison.net/PermaLink,guid,406befc0-334e-4a9d-8812-d840d5869617.aspx</pingback:target>
      <dc:creator>Christoph Wille</dc:creator>
      <wfw:comment>http://chrison.net/CommentView,guid,406befc0-334e-4a9d-8812-d840d5869617.aspx</wfw:comment>
      <wfw:commentRss>http://chrison.net/SyndicationService.asmx/GetEntryCommentsRss?guid=406befc0-334e-4a9d-8812-d840d5869617</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Microsoft <a href="http://www.microsoft.com/downloads/details.aspx?familyid=2cd92e43-6cda-478a-9e3b-4f831e899433&amp;displaylang=en&amp;tm">released
a UAC demo</a>. It is just basic process elevation (read: save the time by not downloading
it), which I described in more detail (with more reuseability) in <a href="http://chrison.net/UACElevationInManagedCodeStartingElevatedProcesses.aspx">UAC
Elevation in Managed Code: Starting Elevated Processes</a>.
</p>
        <img width="0" height="0" src="http://chrison.net/aggbug.ashx?id=406befc0-334e-4a9d-8812-d840d5869617" />
      </body>
      <title>MS Sample for Starting Elevated Processes (UAC)</title>
      <guid isPermaLink="false">http://chrison.net/PermaLink,guid,406befc0-334e-4a9d-8812-d840d5869617.aspx</guid>
      <link>http://chrison.net/MSSampleForStartingElevatedProcessesUAC.aspx</link>
      <pubDate>Mon, 04 Jun 2007 08:34:52 GMT</pubDate>
      <description>&lt;p&gt;
Microsoft &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=2cd92e43-6cda-478a-9e3b-4f831e899433&amp;amp;displaylang=en&amp;amp;tm"&gt;released
a UAC demo&lt;/a&gt;. It is just basic process elevation (read: save the time by not downloading
it), which I described in more detail (with more reuseability) in &lt;a href="http://chrison.net/UACElevationInManagedCodeStartingElevatedProcesses.aspx"&gt;UAC
Elevation in Managed Code: Starting Elevated Processes&lt;/a&gt;.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://chrison.net/aggbug.ashx?id=406befc0-334e-4a9d-8812-d840d5869617" /&gt;</description>
      <comments>http://chrison.net/CommentView,guid,406befc0-334e-4a9d-8812-d840d5869617.aspx</comments>
      <category>.NET</category>
      <category>Vista</category>
      <category>UAC</category>
    </item>
    <item>
      <trackback:ping>http://chrison.net/Trackback.aspx?guid=110bfeb2-3676-438a-a5af-57c5921e1862</trackback:ping>
      <pingback:server>http://chrison.net/pingback.aspx</pingback:server>
      <pingback:target>http://chrison.net/PermaLink,guid,110bfeb2-3676-438a-a5af-57c5921e1862.aspx</pingback:target>
      <dc:creator>Christoph Wille</dc:creator>
      <wfw:comment>http://chrison.net/CommentView,guid,110bfeb2-3676-438a-a5af-57c5921e1862.aspx</wfw:comment>
      <wfw:commentRss>http://chrison.net/SyndicationService.asmx/GetEntryCommentsRss?guid=110bfeb2-3676-438a-a5af-57c5921e1862</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This is <a href="http://www.microsoft.com/downloads/details.aspx?familyid=ba73b169-a648-49af-bc5e-a2eebb74c16b&amp;displaylang=en&amp;tm">v2
of the Vista UAC development requirements document</a>. From the TOC:
</p>
        <ul>
          <li>
Why User Account Control? 
</li>
          <li>
How UAC Works 
</li>
          <li>
Will UAC Affect Your Application? 
</li>
          <li>
Designing Applications for Windows Vista 
</li>
          <li>
Deploying and Patching Applications for Standard Users 
</li>
          <li>
Troubleshooting Common Issues 
</li>
          <li>
References</li>
        </ul>
        <img width="0" height="0" src="http://chrison.net/aggbug.ashx?id=110bfeb2-3676-438a-a5af-57c5921e1862" />
      </body>
      <title>Windows Vista Application Development Requirements for User Account Control Compatibility</title>
      <guid isPermaLink="false">http://chrison.net/PermaLink,guid,110bfeb2-3676-438a-a5af-57c5921e1862.aspx</guid>
      <link>http://chrison.net/WindowsVistaApplicationDevelopmentRequirementsForUserAccountControlCompatibility.aspx</link>
      <pubDate>Wed, 21 Feb 2007 08:48:17 GMT</pubDate>
      <description>&lt;p&gt;
This is &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=ba73b169-a648-49af-bc5e-a2eebb74c16b&amp;amp;displaylang=en&amp;amp;tm"&gt;v2
of the Vista UAC development requirements document&lt;/a&gt;. From the TOC:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Why User Account Control? 
&lt;li&gt;
How UAC Works 
&lt;li&gt;
Will UAC Affect Your Application? 
&lt;li&gt;
Designing Applications for Windows Vista 
&lt;li&gt;
Deploying and Patching Applications for Standard Users 
&lt;li&gt;
Troubleshooting Common Issues 
&lt;li&gt;
References&lt;/li&gt;
&lt;/ul&gt;
&lt;img width="0" height="0" src="http://chrison.net/aggbug.ashx?id=110bfeb2-3676-438a-a5af-57c5921e1862" /&gt;</description>
      <comments>http://chrison.net/CommentView,guid,110bfeb2-3676-438a-a5af-57c5921e1862.aspx</comments>
      <category>Security</category>
      <category>UAC</category>
      <category>Vista</category>
    </item>
    <item>
      <trackback:ping>http://chrison.net/Trackback.aspx?guid=07f52abe-5ebe-4f41-97b4-7d1aa32ec09c</trackback:ping>
      <pingback:server>http://chrison.net/pingback.aspx</pingback:server>
      <pingback:target>http://chrison.net/PermaLink,guid,07f52abe-5ebe-4f41-97b4-7d1aa32ec09c.aspx</pingback:target>
      <dc:creator>Christoph Wille</dc:creator>
      <wfw:comment>http://chrison.net/CommentView,guid,07f52abe-5ebe-4f41-97b4-7d1aa32ec09c.aspx</wfw:comment>
      <wfw:commentRss>http://chrison.net/SyndicationService.asmx/GetEntryCommentsRss?guid=07f52abe-5ebe-4f41-97b4-7d1aa32ec09c</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
In my last blog entry <a href="http://chrison.net/UACElevationInManagedCodeANETCOMComponentElevated.aspx">UAC
Elevation in Managed Code: A .NET COM Component Elevated</a> I showed how to get up
and running with an all-managed code solution for UAC and COM elevation. Today I want
close out my series on UAC with some information on how to properly organize
the project plus present a library you can reuse to get up and running quickly - without
many of the manual and tedious steps from the previous proof of concept example.
</p>
        <p>
Speaking of the previous sample: it is still the basis for this best practice, so
the following directory layout will look familiar to you:
</p>
        <p>
          <img src="http://chrison.net/content/binary/xplatformdirlayout.png" border="0" />
        </p>
        <p>
Before diving into code, I want to start out with the SampleSetup directory, which
contains the executables. As you can guess, the starting point is Step1Register. It
contains register.bat, which you have to execute:
</p>
        <p>
          <img src="http://chrison.net/content/binary/xplatformregistration.png" border="0" />
        </p>
        <p>
Note that on machines without the .NET Framework SDK, there is no gacutil.exe. In
that case, you have to drag &amp; drop ManagedElevator.dll to c:\windows\assembly. 
</p>
        <p>
And in case you have been wondering from this screenshot, yes, the application now
also plays nicely on Windows XP:
</p>
        <p>
          <img src="http://chrison.net/content/binary/xplatformrunxp.png" border="0" />
        </p>
        <p>
Of course, there is no consent UI popping up, nor is there a shield icon like there
is on Windows Vista:
</p>
        <p>
          <img src="http://chrison.net/content/binary/xplatformrunvista.png" border="0" />
        </p>
        <p>
The magic for this cross-platform functionality is hidden in the UACHelper project
- which brings us to the source section of this blog post:
</p>
        <p>
          <img src="http://chrison.net/content/binary/xplatformuachelpercd.png" border="0" />
        </p>
        <p>
All the necessary COM elevation magic is now moved to this neat little library - including
the adapted UAC bits of VistaBridgeLibrary (no longer necessary). The names already
give away the purpose of each class and where they are used:
</p>
        <ul>
          <li>
            <strong>COMRegistration</strong> Used by the elevated component to automatically register
the necessary registry keys. 
</li>
          <li>
            <strong>ShieldButton</strong> Used by the client to display a button with a shield
icon (on Vista). For XP, no shield is rendered. 
</li>
          <li>
            <strong>COMElevation</strong> Starts the requested component with admin privileges. 
</li>
          <li>
            <strong>ElevatedProcess</strong>
            <a href="http://chrison.net/UACElevationInManagedCodeStartingElevatedProcesses.aspx">If
you want to start a simple process elevated</a>. Not used in this guidance.</li>
        </ul>
        <p>
The first customer of this library is the elevated component, so we start discussing
this guy next:
</p>
        <p>
          <img src="http://chrison.net/content/binary/xplatformmanagedelevatorcd.png" border="0" />
        </p>
        <p>
At first glance, this is similar to the previous POC implementation. The main difference
now is that I have broken down the functionality by feature area into namespaces:
</p>
        <ul>
          <li>
The "main" namespace 
</li>
          <li>
The .Components namespace 
</li>
          <li>
The .Guids namespace 
</li>
          <li>
The .InterOp namespace</li>
        </ul>
        <p>
Let's look at these one by one.
</p>
        <p>
          <strong>The "main" namespace</strong>
        </p>
        <p>
Here, we have one class only:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">class</span> RegisterFunctions<br />
{<br />
  [ComRegisterFunction]<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
public</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">static</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">void</span> CustomRegister(Type
t)<br />
  {<br />
    COMRegistration.RegisterForElevation(Assembly.GetExecutingAssembly().Location,<br />
       SampleComponent.ClassToElevate,<br />
       Global.AppId,<br />
       100);<br /><br /><span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">    //
add additional "for elevation" components here by duplicating the above</span><br />
  }<br /><br />
  [ComUnregisterFunction]<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
public</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">static</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">void</span> CustomUnregister(Type
t)<br />
  {<br />
    COMRegistration.UnRegisterFromElevation(Assembly.GetExecutingAssembly().Location, 
<br />
        Global.AppId);<br />
  }<br />
}</span>
        </p>
        <p>
It is called when the assembly is regasm'ed, and it is here where you call into COMRegistration.RegisterForElevation
to add all the necessary registry keys for elevation:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">public</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">static</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">void</span> RegisterForElevation(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">string</span> assemblyLocation,<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">   
string</span> classToElevate,<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">   
string</span> appId,<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">   
int</span> localizedStringId)<br />
{<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> if</span> (!UACHelperFunctions.IsUACEnabledOS()) <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">return</span>;<br /><br /><span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> //
[HKEY_CLASSES_ROOT\CLSID\{71E050A7-AF7F-42dd-BE00-BF955DDD13D4}]</span><br /><span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> //
"AppID"="{75AB90B0-8B9C-45c9-AC55-C53A9D718E1A}"</span><br /><span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> //
"LocalizedString"="@E:\\Daten\\Firma\\Konferenzen und Talks\\..."</span><br />
 RegistryKey classKey <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> Registry.ClassesRoot.OpenSubKey(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">@"CLSID\{"</span><span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">+</span> classToElevate <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">+</span><span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"}"</span>, <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">true</span>);<br />
 classKey.SetValue(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"AppId"</span>, <span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"{"</span><span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">+</span> appId <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">+</span><span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"}"</span>,
RegistryValueKind.String);<br />
 classKey.SetValue(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"LocalizedString"</span>, <span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"@"</span><span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">+</span> assemblyLocation <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">+</span><span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">",-"</span><span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">+</span> localizedStringId.ToString(),
RegistryValueKind.String);<br /><br /><span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> //
[HKEY_CLASSES_ROOT\CLSID\{71E050A7-AF7F-42dd-BE00-BF955DDD13D4}\Elevation]</span><br /><span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> //
"Enabled"=dword:00000001</span><br />
 RegistryKey elevationKey <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> classKey.CreateSubKey(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"Elevation"</span>);<br />
 elevationKey.SetValue(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"Enabled"</span>,
1, RegistryValueKind.DWord);<br />
 elevationKey.Close();<br /><br />
 classKey.Close();<br /><br /><span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> //
[HKEY_CLASSES_ROOT\AppID\{75AB90B0-8B9C-45c9-AC55-C53A9D718E1A}]</span><br /><span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> //
@="ManagedElevator"</span><br /><span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> //
"DllSurrogate"=""</span><br />
 RegistryKey hkcrappId <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> Registry.ClassesRoot.OpenSubKey(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"AppID"</span>, <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">true</span>);<br />
 RegistryKey appIdKey <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> hkcrappId.CreateSubKey(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"{"</span><span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">+</span> appId <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">+</span><span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"}"</span>);<br />
 appIdKey.SetValue(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">null</span>,
Path.GetFileNameWithoutExtension(assemblyLocation));<br />
 appIdKey.SetValue(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"DllSurrogate"</span>, <span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">""</span>,
RegistryValueKind.String);<br />
 appIdKey.Close();<br /><br /><span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> //
[HKEY_CLASSES_ROOT\AppID\ManagedElevator.dll]</span><br /><span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> //
"AppID"="{75AB90B0-8B9C-45c9-AC55-C53A9D718E1A}"</span><br />
 RegistryKey asmKey <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> hkcrappId.CreateSubKey(Path.GetFileName(assemblyLocation));<br />
 asmKey.SetValue(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"AppID"</span>, <span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"{"</span><span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">+</span> appId <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">+</span><span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"}"</span>,
RegistryValueKind.String);<br />
 asmKey.Close();<br /><br />
 hkcrappId.Close();<br />
}</span>
        </p>
        <p>
Please take note that when the component is registered on eg Windows XP, no registry
entries are written. After all, they are not needed.
</p>
        <p>
          <strong>The .Components namespace</strong>
        </p>
        <p>
Not much of a change - it contains the administrative component(s).
</p>
        <p>
          <strong>The .Guids namespace</strong>
        </p>
        <p>
The guids have been moved to a separate namespace. The reason? That way you can reference
the assembly in the client project and use the guids directly - no magic strings anywhere
any more.
</p>
        <p>
          <strong>The .InterOp namespace</strong>
        </p>
        <p>
This is the most important change with regards to the POC project - defining the correct
ComImport'ed interface is now the responsibility of the implementer of the elevated
component. That way, anyone needing access to this component only needs to reference
the assembly and they are good to go. It is a bad idea to have this interface part
of the client codebase!
</p>
        <p>
Speaking of the client... here is the button code for DemoForm.cs:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">private</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">void</span> cmdLaunch_Click(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">object</span> sender,
EventArgs e)<br />
{<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> if</span> (UACHelperFunctions.IsUACEnabledOS())<br />
 {<br />
   IHelloWorld ihw <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> COMElevation.Start&lt;IHelloWorld&gt;(<br />
        SampleComponent.ClassToElevate, SampleComponent.IHelloWorld);<br />
   ihw.SayHello();<br />
   COMElevation.Release(ihw);<br />
 }<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> else</span><br />
 { 
<br />
   ManagedElevator.Components.ClassToElevate c <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> ManagedElevator.Components.ClassToElevate();<br />
   c.SayHello();<br />
 }<br />
}</span>
        </p>
        <p>
What looks interesting at first is COMElevation.Start as well as Release:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">public</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">class</span> COMElevation<br />
{<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> public</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">static</span> TIFace
Start&lt;TIFace&gt;(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">string</span> IID_Class, <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">string</span> IID_Interface)<br />
 {<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">  return</span> Start&lt;TIFace&gt;(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> Guid(IID_Class), <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> Guid(IID_Interface));<br />
 }<br /><br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> public</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">static</span> TIFace
Start&lt;TIFace&gt;(Guid IID_Class, Guid IID_Interface)<br />
 {<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
object</span> o <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> UACManager.LaunchElevatedCOMObject(IID_Class,
IID_Interface);<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
return</span> (TIFace)o;<br />
 }<br /><br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> public</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">static</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">void</span> Release(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">object</span> o)<br />
 {<br />
  Marshal.ReleaseComObject(o);<br />
 }<br />
}</span>
        </p>
        <p>
Actually all it does is encapsulate the necessary calls to UACManager and Marshal.
Why is there no if / else using IsUACEnabledOS here? Well, at first I thought I'd
build such a switch, but then I thought again: why would I use COM InterOp if I don't
have to? I already referenced the assembly for the component (for the guids and interop
interface), so why not use managed all the way and save time? That's what I did in
the cmdLaunch_Click event handler.
</p>
        <p>
That's it for the code folks, now a little discussion at the end on why in the world
would you even think about doing this in a cross-platform way, or why it is a stupid
idea all along:
</p>
        <p>
This approach is only sensible if your application runs as administrative user on
XP, otherwise all the calls in the administrative component will fail. However, the
cross-platform part is only there to make it a complete best practice, there is no
"you must use it cross-platform" - if you build applications for Windows Vista with
the eventual need to elevate a task, then UACHelper is definitely for you! (and forget
about that it would even work on XP)
</p>
        <p>
Oh, and I almost forgot - here is the complete download, source code included of course
(my code is BSD licensed):
</p>
        <p>
          <a href="http://chrison.net/content/binary/AutomaticRegistration.zip">AutomaticRegistration.zip
(91.92 KB)</a>
        </p>
        <img width="0" height="0" src="http://chrison.net/aggbug.ashx?id=07f52abe-5ebe-4f41-97b4-7d1aa32ec09c" />
      </body>
      <title>UAC Elevation in Managed Code: Guidance for Implementing COM Elevation</title>
      <guid isPermaLink="false">http://chrison.net/PermaLink,guid,07f52abe-5ebe-4f41-97b4-7d1aa32ec09c.aspx</guid>
      <link>http://chrison.net/UACElevationInManagedCodeGuidanceForImplementingCOMElevation.aspx</link>
      <pubDate>Fri, 16 Feb 2007 07:02:29 GMT</pubDate>
      <description>&lt;p&gt;
In my last blog entry &lt;a href="http://chrison.net/UACElevationInManagedCodeANETCOMComponentElevated.aspx"&gt;UAC
Elevation in Managed Code: A .NET COM Component Elevated&lt;/a&gt; I showed how to get up
and running with an all-managed code solution for UAC and COM elevation. Today I want
close out my series on UAC with&amp;nbsp;some information on how to properly organize
the project plus present a library you can reuse to get up and running quickly - without
many of the manual and tedious steps from the previous proof of concept&amp;nbsp;example.
&lt;/p&gt;
&lt;p&gt;
Speaking of the previous sample: it is still the basis for this best practice, so
the following directory layout will look familiar to you:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://chrison.net/content/binary/xplatformdirlayout.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Before diving into code, I want to start out with the SampleSetup directory, which
contains the executables. As you can guess, the starting point is Step1Register. It
contains register.bat, which you have to execute:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://chrison.net/content/binary/xplatformregistration.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Note that on machines without the .NET Framework SDK, there is no gacutil.exe. In
that case, you have to drag &amp;amp; drop ManagedElevator.dll to c:\windows\assembly. 
&lt;/p&gt;
&lt;p&gt;
And in case you have been wondering from this screenshot, yes, the application now
also plays nicely on Windows XP:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://chrison.net/content/binary/xplatformrunxp.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Of course, there is no consent UI popping up, nor is there a shield icon like there
is on Windows Vista:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://chrison.net/content/binary/xplatformrunvista.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
The magic for this cross-platform functionality is hidden in the UACHelper project
- which brings us to the source section of this blog post:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://chrison.net/content/binary/xplatformuachelpercd.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
All the necessary COM elevation magic is now moved to this neat little library - including
the adapted UAC bits of VistaBridgeLibrary (no longer necessary). The names already
give away the purpose of each class and where they are used:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;COMRegistration&lt;/strong&gt; Used by the elevated component to automatically register
the necessary registry keys. 
&lt;li&gt;
&lt;strong&gt;ShieldButton&lt;/strong&gt; Used by the client to display a button with a shield
icon (on Vista). For XP, no shield is rendered. 
&lt;li&gt;
&lt;strong&gt;COMElevation&lt;/strong&gt; Starts the requested component with admin privileges. 
&lt;li&gt;
&lt;strong&gt;ElevatedProcess&lt;/strong&gt; &lt;a href="http://chrison.net/UACElevationInManagedCodeStartingElevatedProcesses.aspx"&gt;If
you want to start a simple process elevated&lt;/a&gt;. Not used in this guidance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
The first customer of this library is the elevated component, so we start discussing
this guy next:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://chrison.net/content/binary/xplatformmanagedelevatorcd.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
At first glance, this is similar to the previous POC implementation. The main difference
now is that I have broken down the functionality by feature area into namespaces:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
The "main" namespace 
&lt;li&gt;
The .Components namespace 
&lt;li&gt;
The .Guids namespace 
&lt;li&gt;
The .InterOp namespace&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Let's look at these one by one.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;The "main" namespace&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
Here, we have one class only:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;class&lt;/span&gt; RegisterFunctions&lt;br&gt;
{&lt;br&gt;
&amp;nbsp; [ComRegisterFunction]&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;static&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;void&lt;/span&gt; CustomRegister(Type
t)&lt;br&gt;
&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; COMRegistration.RegisterForElevation(Assembly.GetExecutingAssembly().Location,&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SampleComponent.ClassToElevate,&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Global.AppId,&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 100);&lt;br&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//
add additional "for elevation" components here by duplicating the above&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp; [ComUnregisterFunction]&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;static&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;void&lt;/span&gt; CustomUnregister(Type
t)&lt;br&gt;
&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; COMRegistration.UnRegisterFromElevation(Assembly.GetExecutingAssembly().Location, 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Global.AppId);&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
It is called when the assembly is regasm'ed, and it is here where you call into COMRegistration.RegisterForElevation
to add all the necessary registry keys for elevation:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;static&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;void&lt;/span&gt; RegisterForElevation(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;string&lt;/span&gt; assemblyLocation,&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
string&lt;/span&gt; classToElevate,&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
string&lt;/span&gt; appId,&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
int&lt;/span&gt; localizedStringId)&lt;br&gt;
{&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;if&lt;/span&gt; (!UACHelperFunctions.IsUACEnabledOS()) &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;return&lt;/span&gt;;&lt;br&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;//
[HKEY_CLASSES_ROOT\CLSID\{71E050A7-AF7F-42dd-BE00-BF955DDD13D4}]&lt;/span&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;//
"AppID"="{75AB90B0-8B9C-45c9-AC55-C53A9D718E1A}"&lt;/span&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;//
"LocalizedString"="@E:\\Daten\\Firma\\Konferenzen und Talks\\..."&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;RegistryKey classKey &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; Registry.ClassesRoot.OpenSubKey(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;@"CLSID\{"&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;+&lt;/span&gt; classToElevate &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;+&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"}"&lt;/span&gt;, &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;true&lt;/span&gt;);&lt;br&gt;
&amp;nbsp;classKey.SetValue(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"AppId"&lt;/span&gt;, &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"{"&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;+&lt;/span&gt; appId &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;+&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"}"&lt;/span&gt;,
RegistryValueKind.String);&lt;br&gt;
&amp;nbsp;classKey.SetValue(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"LocalizedString"&lt;/span&gt;, &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"@"&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;+&lt;/span&gt; assemblyLocation &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;+&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;",-"&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;+&lt;/span&gt; localizedStringId.ToString(),
RegistryValueKind.String);&lt;br&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;//
[HKEY_CLASSES_ROOT\CLSID\{71E050A7-AF7F-42dd-BE00-BF955DDD13D4}\Elevation]&lt;/span&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;//
"Enabled"=dword:00000001&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;RegistryKey elevationKey &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; classKey.CreateSubKey(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"Elevation"&lt;/span&gt;);&lt;br&gt;
&amp;nbsp;elevationKey.SetValue(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"Enabled"&lt;/span&gt;,
1, RegistryValueKind.DWord);&lt;br&gt;
&amp;nbsp;elevationKey.Close();&lt;br&gt;
&lt;br&gt;
&amp;nbsp;classKey.Close();&lt;br&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;//
[HKEY_CLASSES_ROOT\AppID\{75AB90B0-8B9C-45c9-AC55-C53A9D718E1A}]&lt;/span&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;//
@="ManagedElevator"&lt;/span&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;//
"DllSurrogate"=""&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;RegistryKey hkcrappId &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; Registry.ClassesRoot.OpenSubKey(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"AppID"&lt;/span&gt;, &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;true&lt;/span&gt;);&lt;br&gt;
&amp;nbsp;RegistryKey appIdKey &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; hkcrappId.CreateSubKey(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"{"&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;+&lt;/span&gt; appId &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;+&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"}"&lt;/span&gt;);&lt;br&gt;
&amp;nbsp;appIdKey.SetValue(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;null&lt;/span&gt;,
Path.GetFileNameWithoutExtension(assemblyLocation));&lt;br&gt;
&amp;nbsp;appIdKey.SetValue(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"DllSurrogate"&lt;/span&gt;, &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;""&lt;/span&gt;,
RegistryValueKind.String);&lt;br&gt;
&amp;nbsp;appIdKey.Close();&lt;br&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;//
[HKEY_CLASSES_ROOT\AppID\ManagedElevator.dll]&lt;/span&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;//
"AppID"="{75AB90B0-8B9C-45c9-AC55-C53A9D718E1A}"&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;RegistryKey asmKey &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; hkcrappId.CreateSubKey(Path.GetFileName(assemblyLocation));&lt;br&gt;
&amp;nbsp;asmKey.SetValue(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"AppID"&lt;/span&gt;, &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"{"&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;+&lt;/span&gt; appId &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;+&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"}"&lt;/span&gt;,
RegistryValueKind.String);&lt;br&gt;
&amp;nbsp;asmKey.Close();&lt;br&gt;
&lt;br&gt;
&amp;nbsp;hkcrappId.Close();&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
Please take note that when the component is registered on eg Windows XP, no registry
entries are written. After all, they are not needed.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;The .Components namespace&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
Not much of a change - it contains the administrative component(s).
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;The .Guids namespace&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
The guids have been moved to a separate namespace. The reason? That way you can reference
the assembly in the client project and use the guids directly - no magic strings anywhere
any more.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;The .InterOp namespace&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
This is the most important change with regards to the POC project - defining the correct
ComImport'ed interface is now the responsibility of the implementer of the elevated
component. That way, anyone needing access to this component only needs to reference
the assembly and they are good to go. It is a bad idea to have this interface part
of the client codebase!
&lt;/p&gt;
&lt;p&gt;
Speaking of the client... here is the button code for DemoForm.cs:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;private&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;void&lt;/span&gt; cmdLaunch_Click(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;object&lt;/span&gt; sender,
EventArgs e)&lt;br&gt;
{&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;if&lt;/span&gt; (UACHelperFunctions.IsUACEnabledOS())&lt;br&gt;
&amp;nbsp;{&lt;br&gt;
&amp;nbsp;&amp;nbsp; IHelloWorld ihw &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; COMElevation.Start&amp;lt;IHelloWorld&amp;gt;(&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SampleComponent.ClassToElevate, SampleComponent.IHelloWorld);&lt;br&gt;
&amp;nbsp;&amp;nbsp; ihw.SayHello();&lt;br&gt;
&amp;nbsp;&amp;nbsp; COMElevation.Release(ihw);&lt;br&gt;
&amp;nbsp;}&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;else&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;{ 
&lt;br&gt;
&amp;nbsp;&amp;nbsp; ManagedElevator.Components.ClassToElevate c &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; ManagedElevator.Components.ClassToElevate();&lt;br&gt;
&amp;nbsp;&amp;nbsp; c.SayHello();&lt;br&gt;
&amp;nbsp;}&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
What looks interesting at first is COMElevation.Start as well as Release:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;class&lt;/span&gt; COMElevation&lt;br&gt;
{&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;static&lt;/span&gt; TIFace
Start&amp;lt;TIFace&amp;gt;(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;string&lt;/span&gt; IID_Class, &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;string&lt;/span&gt; IID_Interface)&lt;br&gt;
&amp;nbsp;{&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;return&lt;/span&gt; Start&amp;lt;TIFace&amp;gt;(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; Guid(IID_Class), &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; Guid(IID_Interface));&lt;br&gt;
&amp;nbsp;}&lt;br&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;static&lt;/span&gt; TIFace
Start&amp;lt;TIFace&amp;gt;(Guid IID_Class, Guid IID_Interface)&lt;br&gt;
&amp;nbsp;{&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
object&lt;/span&gt; o &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; UACManager.LaunchElevatedCOMObject(IID_Class,
IID_Interface);&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
return&lt;/span&gt; (TIFace)o;&lt;br&gt;
&amp;nbsp;}&lt;br&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;static&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;void&lt;/span&gt; Release(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;object&lt;/span&gt; o)&lt;br&gt;
&amp;nbsp;{&lt;br&gt;
&amp;nbsp; Marshal.ReleaseComObject(o);&lt;br&gt;
&amp;nbsp;}&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
Actually all it does is encapsulate the necessary calls to UACManager and Marshal.
Why is there no if / else using IsUACEnabledOS here? Well, at first I thought I'd
build such a switch, but then I thought again: why would I use COM InterOp if I don't
have to? I already referenced the assembly for the component (for the guids and interop
interface), so why not use managed all the way and save time? That's what I did in
the cmdLaunch_Click event handler.
&lt;/p&gt;
&lt;p&gt;
That's it for the code folks, now a little discussion at the end on why in the world
would you even think about doing this in a cross-platform way, or why it is a stupid
idea all along:
&lt;/p&gt;
&lt;p&gt;
This approach is only sensible if your application runs as administrative user on
XP, otherwise all the calls in the administrative component will fail. However, the
cross-platform part is only there to make it a complete best practice, there is no
"you must use it cross-platform" - if you build applications for Windows Vista with
the eventual need to elevate a task, then UACHelper is definitely for you! (and forget
about that it would even work on XP)
&lt;/p&gt;
&lt;p&gt;
Oh, and I almost forgot - here is the complete download, source code included of course
(my code is BSD licensed):
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://chrison.net/content/binary/AutomaticRegistration.zip"&gt;AutomaticRegistration.zip
(91.92 KB)&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://chrison.net/aggbug.ashx?id=07f52abe-5ebe-4f41-97b4-7d1aa32ec09c" /&gt;</description>
      <comments>http://chrison.net/CommentView,guid,07f52abe-5ebe-4f41-97b4-7d1aa32ec09c.aspx</comments>
      <category>Security</category>
      <category>UAC</category>
      <category>Use the source Luke</category>
      <category>Vista</category>
    </item>
    <item>
      <trackback:ping>http://chrison.net/Trackback.aspx?guid=1392e674-8b58-407b-b101-903d7e9d95a8</trackback:ping>
      <pingback:server>http://chrison.net/pingback.aspx</pingback:server>
      <pingback:target>http://chrison.net/PermaLink,guid,1392e674-8b58-407b-b101-903d7e9d95a8.aspx</pingback:target>
      <dc:creator>Christoph Wille</dc:creator>
      <wfw:comment>http://chrison.net/CommentView,guid,1392e674-8b58-407b-b101-903d7e9d95a8.aspx</wfw:comment>
      <wfw:commentRss>http://chrison.net/SyndicationService.asmx/GetEntryCommentsRss?guid=1392e674-8b58-407b-b101-903d7e9d95a8</wfw:commentRss>
      <slash:comments>7</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I admit it: <a href="http://chrison.net/UACElevationInManagedCodeTalkingToAnElevatedProcessViaWCF.aspx">UAC
Elevation in Managed Code: "Talking" to an Elevated Process via WCF</a> is a kludge.
The reason why I dabbled with this approach at all is that I failed to implement COM
elevation with managed code (not <a href="http://chrison.net/UACElevationInManagedCodeStartingElevatedCOMComponents.aspx">elevating
a COM component</a>, but the COM component itself). However, at long last, I succeeded
in that respect too: I now present you the all-managed code solution to UAC elevation!
</p>
        <p>
Once again I built myself a small demo frontend application:
</p>
        <p>
          <img src="http://chrison.net/content/binary/comelevationincsharp.png" border="0" />
        </p>
        <p>
As you can guess, the first button does plain vanilla COM InterOp without any UAC
elevation. Thus its code is rather simple:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">private</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">void</span> simpleCallButton_Click(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">object</span> sender,
EventArgs e)<br />
{<br />
  Type t <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> Type.GetTypeFromCLSID(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> Guid(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"71E050A7-AF7F-42dd-BE00-BF955DDD13D4"</span>));<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
object</span> o <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> Activator.CreateInstance(t);<br />
  t.InvokeMember(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"SayHello"</span>,
BindingFlags.InvokeMethod, <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">null</span>,
o, <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">null</span>);<br />
}</span>
        </p>
        <p>
Why this reflection magic? Well, the COM component I am calling here is implemented
in .NET - and <a href="http://chrison.net/AReferenceToCouldNotBeAdded.aspx">both
VS as well as tlbimp balk at reimporting the exported type library</a>.
</p>
        <p>
The COM component in question has been regasm'ed &amp; gacutil'ed (ManagedElevator
project in the download). Although the name implies that I am after elevation, it
is pretty much a standard COM component written using C#:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">public</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">class</span> TheGuids<br />
{<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
public</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">const</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">string</span> IHelloWorld <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"B8CD5C09-9ACD-49b0-BF6F-C7B0F29795F9"</span>;<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
public</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">const</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">string</span> ClassToElevate <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"71E050A7-AF7F-42dd-BE00-BF955DDD13D4"</span>;<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
public</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">const</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">string</span> AppId <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"75AB90B0-8B9C-45c9-AC55-C53A9D718E1A"</span>;<br />
}<br /><br />
[Guid(TheGuids.IHelloWorld)]<br />
[InterfaceType(ComInterfaceType.InterfaceIsDual)]<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">public</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">interface</span> IHelloWorld<br />
{<br />
  [ComVisible(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">true</span>)]<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
void</span> SayHello();<br />
}<br /><br />
[Guid(TheGuids.ClassToElevate)]<br />
[ClassInterface(ClassInterfaceType.None)]<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">public</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">class</span> ClassToElevate
: IHelloWorld<br />
{<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> public</span> ClassToElevate()<br />
 {<br />
 }<br /><br />
 [ComVisible(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">true</span>)]<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> public</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">void</span> SayHello()<br />
 {<br />
  MessageBox.Show(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"Hello
World"</span>);<br />
 }<br />
}<br /></span>
        </p>
        <p>
So how do you go from "standard" "plain-vanilla" COM component to COM elevation? The
part that stumped me for so long was the ClassInterface attribute - if you forget
this guy, you'll end up with an InvalidCastException thrown by UACManager.LaunchElevatedCOMObject.
</p>
        <p>
But that's not quite all to get up and running with COM elevation: in addition, you
need to modify the default registration for this component - specifically, you need
to configure the DllSurrogate. This is where the AppId GUID comes into play: it isn't
used in code (kept there for documentation purposes only), but in registryadditions.reg.
It binds the various registry keys. And speaking of this .reg file, please take note
of the LocalizedString value: it contains the text for the UAC prompt (also check
out UACPrompts.rc, resource.h, compilerc.bat as well as the properties of the ManagedElevator
project where the compiled .res file is referenced). 
</p>
        <p>
          <strong>Note</strong> Before importing the .reg file into the registry make sure to
fix the file path contained in LocalizedString! And if you create your own elevated
COM component DO NOT reuse any of my three GUIDs - use guidgen.exe to create your
personal ones.
</p>
        <p>
From there, UAC elevation is smooth sailing. The Reflection version of COM elevation
looks very similar to non-elevated calls:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">private</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">void</span> managedElevation_Click(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">object</span> sender,
EventArgs e)<br />
{<br /><span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
// CLSID</span><br />
  Guid classId <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> Guid(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"71E050A7-AF7F-42dd-BE00-BF955DDD13D4"</span>);<br /><br /><span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
// Interface ID</span><br />
  Guid interfaceId <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> Guid(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"B8CD5C09-9ACD-49b0-BF6F-C7B0F29795F9"</span>);<br /><br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
object</span> o <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> UACManager.LaunchElevatedCOMObject(classId,
interfaceId);<br /><br />
  Type t <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> o.GetType();<br />
  t.InvokeMember(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"SayHello"</span>,
BindingFlags.InvokeMethod, <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">null</span>,
o, <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">null</span>);<br /><br />
  Marshal.ReleaseComObject(o);<br />
}</span>
        </p>
        <p>
Of course this is not really a good solution (late binding). So instead I manually
imported the IHelloWorld interface:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">[<br />
ComImport(), 
<br />
Guid(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"B8CD5C09-9ACD-49b0-BF6F-C7B0F29795F9"</span>), 
<br />
InterfaceType(ComInterfaceType.InterfaceIsDual)<br />
]<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
interface</span> IHelloWorld<br />
  {<br />
   [<br />
   MethodImpl(MethodImplOptions.InternalCall, MethodCodeType <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> MethodCodeType.Runtime),<br />
   PreserveSig<br />
   ]<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">   
void</span> SayHello();<br />
  }</span>
        </p>
        <p>
Which makes calls into the elevated COM object much easier and cleaner:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">private</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">void</span> managedElevationInterface_Click(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">object</span> sender,
EventArgs e)<br />
{<br />
  Guid classId <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> Guid(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"71E050A7-AF7F-42dd-BE00-BF955DDD13D4"</span>);<br />
  Guid interfaceId <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> Guid(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"B8CD5C09-9ACD-49b0-BF6F-C7B0F29795F9"</span>);<br /><br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
object</span> o <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> UACManager.LaunchElevatedCOMObject(classId,
interfaceId);<br /><br />
  IHelloWorld ihw <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> (IHelloWorld)o;<br />
  ihw.SayHello();<br /><br />
  Marshal.ReleaseComObject(o);<br />
}</span>
        </p>
        <p>
So why should you use the COM elevation solution instead of starting the process?
Well, there are a couple of reasons:
</p>
        <ul>
          <li>
You can package more than one component into a DLL and still have custom UAC prompts
thanks to LocalizedString 
</li>
          <li>
Your users don't get "an unidentified program..." warnings. Thank you COM registration 
</li>
          <li>
If you ever need to talk more extensively with the elevated process then this approach
can be adapted more easily</li>
        </ul>
        <p>
          <strong>The source code</strong>
        </p>
        <p>
          <a href="http://chrison.net/content/binary/ConsumeMyElevatedCOM.zip">ConsumeMyElevatedCOM.zip
(97.56 KB)</a>
        </p>
        <p>
You will find a file aptly named notes.txt in the ManagedElevator project that describes
all the necessary steps to get up and running. 
</p>
        <p>
I hope you find this sample useful and not have to spend as much time as I did. Cheers!
</p>
        <img width="0" height="0" src="http://chrison.net/aggbug.ashx?id=1392e674-8b58-407b-b101-903d7e9d95a8" />
      </body>
      <title>UAC Elevation in Managed Code: A .NET COM Component Elevated</title>
      <guid isPermaLink="false">http://chrison.net/PermaLink,guid,1392e674-8b58-407b-b101-903d7e9d95a8.aspx</guid>
      <link>http://chrison.net/UACElevationInManagedCodeANETCOMComponentElevated.aspx</link>
      <pubDate>Mon, 05 Feb 2007 21:41:46 GMT</pubDate>
      <description>&lt;p&gt;
I admit it: &lt;a href="http://chrison.net/UACElevationInManagedCodeTalkingToAnElevatedProcessViaWCF.aspx"&gt;UAC
Elevation in Managed Code: "Talking" to an Elevated Process via WCF&lt;/a&gt; is a kludge.
The reason why I dabbled with this approach at all is that I failed to implement COM
elevation with managed code (not &lt;a href="http://chrison.net/UACElevationInManagedCodeStartingElevatedCOMComponents.aspx"&gt;elevating
a COM component&lt;/a&gt;, but the COM component itself). However, at long last, I succeeded
in that respect too: I now present you the all-managed code solution to UAC elevation!
&lt;/p&gt;
&lt;p&gt;
Once again I built myself a small demo frontend application:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://chrison.net/content/binary/comelevationincsharp.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
As you can guess, the first button does plain vanilla COM InterOp without any UAC
elevation. Thus its code is rather simple:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;private&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;void&lt;/span&gt; simpleCallButton_Click(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;object&lt;/span&gt; sender,
EventArgs e)&lt;br&gt;
{&lt;br&gt;
&amp;nbsp; Type t &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; Type.GetTypeFromCLSID(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; Guid(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"71E050A7-AF7F-42dd-BE00-BF955DDD13D4"&lt;/span&gt;));&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
object&lt;/span&gt; o &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; Activator.CreateInstance(t);&lt;br&gt;
&amp;nbsp; t.InvokeMember(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"SayHello"&lt;/span&gt;,
BindingFlags.InvokeMethod, &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;null&lt;/span&gt;,
o, &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;null&lt;/span&gt;);&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
Why this reflection magic? Well, the COM component I am calling here is implemented
in .NET - and&amp;nbsp;&lt;a href="http://chrison.net/AReferenceToCouldNotBeAdded.aspx"&gt;both
VS&amp;nbsp;as well as&amp;nbsp;tlbimp balk at reimporting the exported type library&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
The COM component in question has been regasm'ed &amp;amp; gacutil'ed (ManagedElevator
project in the download). Although the name implies that I am after elevation, it
is pretty much a standard COM component written using C#:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;class&lt;/span&gt; TheGuids&lt;br&gt;
{&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;const&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;string&lt;/span&gt; IHelloWorld &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"B8CD5C09-9ACD-49b0-BF6F-C7B0F29795F9"&lt;/span&gt;;&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;const&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;string&lt;/span&gt; ClassToElevate &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"71E050A7-AF7F-42dd-BE00-BF955DDD13D4"&lt;/span&gt;;&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;const&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;string&lt;/span&gt; AppId &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"75AB90B0-8B9C-45c9-AC55-C53A9D718E1A"&lt;/span&gt;;&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
[Guid(TheGuids.IHelloWorld)]&lt;br&gt;
[InterfaceType(ComInterfaceType.InterfaceIsDual)]&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;interface&lt;/span&gt; IHelloWorld&lt;br&gt;
{&lt;br&gt;
&amp;nbsp; [ComVisible(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;true&lt;/span&gt;)]&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
void&lt;/span&gt; SayHello();&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
[Guid(TheGuids.ClassToElevate)]&lt;br&gt;
[ClassInterface(ClassInterfaceType.None)]&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;class&lt;/span&gt; ClassToElevate
: IHelloWorld&lt;br&gt;
{&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;public&lt;/span&gt; ClassToElevate()&lt;br&gt;
&amp;nbsp;{&lt;br&gt;
&amp;nbsp;}&lt;br&gt;
&lt;br&gt;
&amp;nbsp;[ComVisible(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;true&lt;/span&gt;)]&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;void&lt;/span&gt; SayHello()&lt;br&gt;
&amp;nbsp;{&lt;br&gt;
&amp;nbsp; MessageBox.Show(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"Hello
World"&lt;/span&gt;);&lt;br&gt;
&amp;nbsp;}&lt;br&gt;
}&lt;br&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
So how do you go from "standard" "plain-vanilla" COM component to COM elevation? The
part that stumped me for so long was the ClassInterface attribute - if you forget
this guy, you'll end up with an InvalidCastException thrown by UACManager.LaunchElevatedCOMObject.
&lt;/p&gt;
&lt;p&gt;
But that's not quite all to get up and running with COM elevation: in addition, you
need to modify the default registration for this component - specifically, you need
to configure the DllSurrogate. This is where the AppId GUID comes into play: it isn't
used in code (kept there for documentation purposes only), but in registryadditions.reg.
It binds the various registry keys. And speaking of this .reg file, please take note
of the LocalizedString value: it contains the text for the UAC prompt (also check
out UACPrompts.rc, resource.h, compilerc.bat as well as the properties of the ManagedElevator
project where the compiled .res file is referenced). 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Note&lt;/strong&gt; Before importing the .reg file into the registry make sure to
fix the file path contained in LocalizedString! And if you create your own elevated
COM component DO NOT reuse any of my three GUIDs - use guidgen.exe to create your
personal ones.
&lt;/p&gt;
&lt;p&gt;
From there, UAC elevation is smooth sailing. The Reflection version of COM elevation
looks very similar to non-elevated calls:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;private&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;void&lt;/span&gt; managedElevation_Click(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;object&lt;/span&gt; sender,
EventArgs e)&lt;br&gt;
{&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
// CLSID&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; Guid classId &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; Guid(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"71E050A7-AF7F-42dd-BE00-BF955DDD13D4"&lt;/span&gt;);&lt;br&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
// Interface ID&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; Guid interfaceId &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; Guid(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"B8CD5C09-9ACD-49b0-BF6F-C7B0F29795F9"&lt;/span&gt;);&lt;br&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
object&lt;/span&gt; o &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; UACManager.LaunchElevatedCOMObject(classId,
interfaceId);&lt;br&gt;
&lt;br&gt;
&amp;nbsp; Type t &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; o.GetType();&lt;br&gt;
&amp;nbsp; t.InvokeMember(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"SayHello"&lt;/span&gt;,
BindingFlags.InvokeMethod, &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;null&lt;/span&gt;,
o, &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;null&lt;/span&gt;);&lt;br&gt;
&lt;br&gt;
&amp;nbsp; Marshal.ReleaseComObject(o);&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
Of course this is not really a good solution (late binding). So instead I manually
imported the IHelloWorld interface:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;[&lt;br&gt;
ComImport(), 
&lt;br&gt;
Guid(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"B8CD5C09-9ACD-49b0-BF6F-C7B0F29795F9"&lt;/span&gt;), 
&lt;br&gt;
InterfaceType(ComInterfaceType.InterfaceIsDual)&lt;br&gt;
]&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
interface&lt;/span&gt; IHelloWorld&lt;br&gt;
&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp; [&lt;br&gt;
&amp;nbsp;&amp;nbsp; MethodImpl(MethodImplOptions.InternalCall, MethodCodeType &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; MethodCodeType.Runtime),&lt;br&gt;
&amp;nbsp;&amp;nbsp; PreserveSig&lt;br&gt;
&amp;nbsp; &amp;nbsp;]&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
void&lt;/span&gt; SayHello();&lt;br&gt;
&amp;nbsp; }&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
Which makes calls into the elevated COM object much easier and cleaner:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;private&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;void&lt;/span&gt; managedElevationInterface_Click(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;object&lt;/span&gt; sender,
EventArgs e)&lt;br&gt;
{&lt;br&gt;
&amp;nbsp; Guid classId &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; Guid(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"71E050A7-AF7F-42dd-BE00-BF955DDD13D4"&lt;/span&gt;);&lt;br&gt;
&amp;nbsp; Guid interfaceId &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; Guid(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"B8CD5C09-9ACD-49b0-BF6F-C7B0F29795F9"&lt;/span&gt;);&lt;br&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
object&lt;/span&gt; o &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; UACManager.LaunchElevatedCOMObject(classId,
interfaceId);&lt;br&gt;
&lt;br&gt;
&amp;nbsp; IHelloWorld ihw &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; (IHelloWorld)o;&lt;br&gt;
&amp;nbsp; ihw.SayHello();&lt;br&gt;
&lt;br&gt;
&amp;nbsp; Marshal.ReleaseComObject(o);&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
So why should you use the COM elevation solution instead of starting the process?
Well, there are a couple of reasons:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
You can package more than one component into a DLL and still have custom UAC prompts
thanks to LocalizedString 
&lt;li&gt;
Your users don't get "an unidentified program..." warnings. Thank you COM registration 
&lt;li&gt;
If you ever need to talk more extensively with the elevated process then this approach
can be adapted more easily&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;strong&gt;The source code&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://chrison.net/content/binary/ConsumeMyElevatedCOM.zip"&gt;ConsumeMyElevatedCOM.zip
(97.56 KB)&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
You will find a file aptly named notes.txt in the ManagedElevator project that describes
all the necessary steps to get up and running. 
&lt;/p&gt;
&lt;p&gt;
I hope you find this sample useful and not have to spend as much time as I did. Cheers!
&lt;/p&gt;
&lt;img width="0" height="0" src="http://chrison.net/aggbug.ashx?id=1392e674-8b58-407b-b101-903d7e9d95a8" /&gt;</description>
      <comments>http://chrison.net/CommentView,guid,1392e674-8b58-407b-b101-903d7e9d95a8.aspx</comments>
      <category>.NET</category>
      <category>Security</category>
      <category>UAC</category>
      <category>Vista</category>
    </item>
    <item>
      <trackback:ping>http://chrison.net/Trackback.aspx?guid=a860d58a-d4c5-4073-9fee-b3e5fab629bf</trackback:ping>
      <pingback:server>http://chrison.net/pingback.aspx</pingback:server>
      <pingback:target>http://chrison.net/PermaLink,guid,a860d58a-d4c5-4073-9fee-b3e5fab629bf.aspx</pingback:target>
      <dc:creator>Christoph Wille</dc:creator>
      <wfw:comment>http://chrison.net/CommentView,guid,a860d58a-d4c5-4073-9fee-b3e5fab629bf.aspx</wfw:comment>
      <wfw:commentRss>http://chrison.net/SyndicationService.asmx/GetEntryCommentsRss?guid=a860d58a-d4c5-4073-9fee-b3e5fab629bf</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
In the blog post <a href="http://chrison.net/UACElevationInManagedCodeStartingElevatedProcesses.aspx">UAC
Elevation in Managed Code: Starting Elevated Processes</a> I talked about how to start
an elevated process. However, just starting a process might not cut the mustard, for
example if you need to hand over data to the elevated process. You could achieve this
by passing, let's say, some data as command line arguments to ProcessInfo before starting
the elevated process. But that seriously limits communication.
</p>
        <p>
So how can you perform communication with an elevated process? My first idea was to
use .NET Remoting. Once I thought through the multi-instance scenario, I quickly realized
that this meant the server had to be running in the non-elevated application, because
only it could properly choose a port. And because I am not a fan of Remoting anyways,
I decided to give WCF (Windows Communication Foundation, a pillar of .NET 3.0) a try.
</p>
        <p>
It looked like smooth sailing at first, but then I realized that with WCF too I needed
to implement the service inside the non-elevated application. This time, however,
the reason was "How do I know when the elevated application has initialized before
I can actually start communicating with it?". Back to the drawing board.
</p>
        <p>
The final solution now looks like this: the non-elevated application starts a service.
The operations contract specifies a callback, which, once the elevated application
has signalled its readiness, can be used by the non-elevated application to "talk"
with the elevated application. I didn't intend to go duplex, but hey, if there's no
other way I am willing to take plunge. Speaking of tricks of the trade: I am using
imperative binding to a named pipe. Reason? Well, WS bindings won't work (see <a href="http://dotnet.org.za/armand/archive/2006/06/14/53390.aspx">here</a> and <a href="http://blogs.msdn.com/drnick/archive/2006/10/16/configuring-http-for-windows-vista.aspx">here</a>),
and the TCP channel would pop up a firewall warning. That's why.
</p>
        <p>
Let's look at the applications - first the non-elevated one:
</p>
        <p>
          <img src="http://chrison.net/content/binary/uacwcfpoc1.png" border="0" />
        </p>
        <p>
This time I forfeited eye candy (the shield button). Same (missing eye candy) goes
for the elevated application as it is a console application only:
</p>
        <p>
          <img src="http://chrison.net/content/binary/uacwcfpoc3.png" border="0" />
        </p>
        <p>
Solution-wise, this simple two-application scenario is split into four projects:
</p>
        <p>
          <img src="http://chrison.net/content/binary/uacwcfpoc2.png" border="0" />
        </p>
        <p>
So where do we start? With the easy part inside ElevationContract:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">[ServiceContract(Namespace <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"http://Christoph.Wille.Samples"</span>,<br />
CallbackContract <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">typeof</span>(IElevatedProcess))]<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">public</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">interface</span> IWaitForElevatedProcess<br />
{<br />
  [OperationContract(IsOneWay <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">false</span>)]<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
void</span> ElevatedProcessStarted();<br />
}<br /><br />
[ServiceContract(Namespace <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"http://Christoph.Wille.Samples"</span>)]<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">public</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">interface</span> IElevatedProcess<br />
{<br />
  [OperationContract(IsOneWay <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">false</span>)]<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
void</span> SayHello(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">string</span> message);<br />
}</span>
        </p>
        <p>
The interface IWaitForElevatedProcess is implemented in StandardUserApp. It is the
service endpoint that is initialized before the elevated process is started - and
once the elevated application is up and running, it calls into ElevatedProcessStarted.
And we are in business for using the IElevatedProcess callback that is implemented
in the ElevatedProcess console application.
</p>
        <p>
So how is the service endpoint intialized - let's take a look inside:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">private</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">const</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">string</span> theProcess <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">@"..\..\..\ElevatedProcess\bin\Debug\ElevatedProcess.exe"</span>;<br /><br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">private</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">void</span> tryitButton_Click(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">object</span> sender,
EventArgs e)<br />
{<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
string</span> channelIdentifier <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> MiscHelpers.CreateRandomString(64);<br />
  MyUACServiceHost.StartService(channelIdentifier);<br /><br /><span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
// starting it modal doesn't work (obviously - unless we have more threads, of course)</span><br />
  ElevatedProcess.Start(theProcess, channelIdentifier);<br />
}</span>
        </p>
        <p>
Interesting tidbit #1 is CreateRandomString: it creates a random string to use for
the address. Why? Well, if multiple instances of our application are running and trying
to elevate a process, we are in trouble. Which brings me to StartService:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">internal</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">static</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">void</span> StartService(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">string</span> pipeEndPoint)<br />
{<br />
  NetNamedPipeBinding binding <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> NetNamedPipeBinding();<br />
  binding.Name <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"uacbinding"</span>;<br />
  binding.Security.Mode <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> NetNamedPipeSecurityMode.Transport;<br /><br />
  Uri baseAddress <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> Uri(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"net.pipe://localhost/uac/"</span><span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">+</span> pipeEndPoint);<br /><br />
  myServiceHost <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> ServiceHost(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">typeof</span>(SampleService),
baseAddress);<br />
  myServiceHost.AddServiceEndpoint(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">typeof</span>(IWaitForElevatedProcess),
binding, baseAddress);<br />
  myServiceHost.Open();<br />
}</span>
        </p>
        <p>
As I said before, I am doing it imperatively (no configuration in app.config necessary).
That's all there is to getting the service up and running.
</p>
        <p>
Now let's switch to the console application's Main method:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">static</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">void</span> Main(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">string</span>[]
args)<br />
{<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
if</span> (args.Length !<span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> 1)<br />
  {<br />
    Console.WriteLine(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"One
argument expected - the channel identifier"</span>);<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">  
 return</span>;<br />
  } 
<br /><br />
  NetNamedPipeBinding binding <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> NetNamedPipeBinding();<br />
  binding.Name <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"uacbinding"</span>;<br />
  binding.Security.Mode <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> NetNamedPipeSecurityMode.Transport;<br /><br />
  String url <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"net.pipe://localhost/uac/"</span><span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">+</span> args[0];<br />
  EndpointAddress address <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> EndpointAddress(url);<br /><br />
  WaitForElevatedProcess client <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> WaitForElevatedProcess(<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">     
new</span> InstanceContext(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> SampleCallback()),<br />
      binding,<br />
      address);<br /><br />
  client.ElevatedProcessStarted();<br /><br />
  Console.WriteLine(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"The
elevated process is now ready"</span>);<br />
  Console.ReadLine();<br /><br />
  client.Close();<br />
}</span>
        </p>
        <p>
Similar to normal client WCF code, however, with the duplex twist hidden inside WaitForElevatedProcess:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">public</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">class</span> WaitForElevatedProcess
: DuplexClientBase&lt;IWaitForElevatedProcess&gt;, IWaitForElevatedProcess<br />
{<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
public</span> WaitForElevatedProcess(System.ServiceModel.InstanceContext callbackInstance,</span>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> <br />
    System.ServiceModel.Channels.Binding binding, 
<br />
    System.ServiceModel.EndpointAddress remoteAddress)<br />
       : <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">base</span>(callbackInstance,
binding, remoteAddress)<br />
  {<br />
  }<br /><br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
public</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">void</span> ElevatedProcessStarted()<br />
  {<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">   
base</span>.Channel.ElevatedProcessStarted();<br />
  }<br />
}</span>
        </p>
        <p>
Once the channel is connected, this elevated process calls back into the service piece
which lives in the non-elevated application, namely SampleService:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">[ServiceBehavior(ConcurrencyMode <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> ConcurrencyMode.Reentrant, 
<br />
      InstanceContextMode <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> InstanceContextMode.PerSession)]<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">public</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">class</span> SampleService
: IWaitForElevatedProcess<br />
{<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
public</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">void</span> ElevatedProcessStarted()<br />
  {<br />
    OperationContext.Current.GetCallbackChannel&lt;IElevatedProcess&gt;().SayHello(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"Chris"</span>);<br />
  }<br />
}</span>
        </p>
        <p>
This method is the workhorse where I can talk to the elevated process - if only my
callback interface had more as well as more serious methods ;-) 
</p>
        <p>
Speaking of talking, I owe you the code for the callee in the console application:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">[CallbackBehavior(ConcurrencyMode <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> ConcurrencyMode.Reentrant)]<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">public</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">class</span> SampleCallback
: IElevatedProcess<br />
{<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
public</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">void</span> SayHello(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">string</span> message)<br />
  {<br />
    Console.WriteLine(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"Hello
world "</span><span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">+</span> message);<br />
  }<br />
}</span>
        </p>
        <p>
That's it - to recap: first, we initialize the WCF service. Then elevate a process.
This process, once initialized, calls into our service and leaves a callback. And
then we are in business talking to the elevated process (setting data, being notified
when the elevated application quits and why, ...).
</p>
        <p>
Sample warnings before you download: MyUACServiceHost definitely should be instance
instead of static. And, more restricting - starting the elevated process modal won't
allow communication <strong>unless</strong> you start the service on a separate thread.
For simplicity reasons I didn't do this for the POC.
</p>
        <p>
          <a href="http://chrison.net/content/binary/ElevateProcessTalkWCF.zip">ElevateProcessTalkWCF.zip
(27 KB)</a>
        </p>
        <p>
Before concluding I wanted to add a few words: my ideal implementation for UAC would
be COM elevation. That way, one can put more than one component into a single DLL,
and still get a meaningful UAC prompt thanks to the LocalizedString registry key -
which is per component, and not per executable (which is the case for this solution
if you add multiple actions). If you need differing prompts for each administrative
action, there is only one course of action you can take with processes: create multiple
executables. Not very pretty, but I failed with writing an elevatable (not a word,
I am sure) managed (C#) COM component.
</p>
        <img width="0" height="0" src="http://chrison.net/aggbug.ashx?id=a860d58a-d4c5-4073-9fee-b3e5fab629bf" />
      </body>
      <title>UAC Elevation in Managed Code: "Talking" to an Elevated Process via WCF</title>
      <guid isPermaLink="false">http://chrison.net/PermaLink,guid,a860d58a-d4c5-4073-9fee-b3e5fab629bf.aspx</guid>
      <link>http://chrison.net/UACElevationInManagedCodeTalkingToAnElevatedProcessViaWCF.aspx</link>
      <pubDate>Sun, 04 Feb 2007 21:23:45 GMT</pubDate>
      <description>&lt;p&gt;
In the blog post &lt;a href="http://chrison.net/UACElevationInManagedCodeStartingElevatedProcesses.aspx"&gt;UAC
Elevation in Managed Code: Starting Elevated Processes&lt;/a&gt; I talked about how to start
an elevated process. However, just starting a process might not cut the mustard, for
example if you need to hand over data to the elevated process. You could achieve this
by passing, let's say, some data as command line arguments to ProcessInfo before starting
the elevated process. But that seriously limits communication.
&lt;/p&gt;
&lt;p&gt;
So how can you perform communication with an elevated process? My first idea was to
use .NET Remoting. Once I thought through the multi-instance scenario, I quickly realized
that this meant the server had to be running in the non-elevated application, because
only it could properly choose a port. And because I am not a fan of Remoting anyways,
I decided to give WCF (Windows Communication Foundation, a pillar of .NET 3.0) a try.
&lt;/p&gt;
&lt;p&gt;
It looked like smooth sailing at first, but then I realized that with WCF too I needed
to implement the service inside the non-elevated application. This time, however,
the reason was "How do I know when the elevated application has initialized before
I can actually start communicating with it?". Back to the drawing board.
&lt;/p&gt;
&lt;p&gt;
The final solution now looks like this: the non-elevated application starts a service.
The operations contract specifies a callback, which, once the elevated application
has signalled its readiness, can be used by the non-elevated application to "talk"
with the elevated application. I didn't intend to go duplex, but hey, if there's no
other way I am willing to take plunge. Speaking of tricks of the trade: I am using
imperative binding to a named pipe. Reason? Well, WS bindings won't work (see &lt;a href="http://dotnet.org.za/armand/archive/2006/06/14/53390.aspx"&gt;here&lt;/a&gt; and &lt;a href="http://blogs.msdn.com/drnick/archive/2006/10/16/configuring-http-for-windows-vista.aspx"&gt;here&lt;/a&gt;),
and the TCP channel would pop up a firewall warning. That's why.
&lt;/p&gt;
&lt;p&gt;
Let's look at the applications - first the non-elevated one:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://chrison.net/content/binary/uacwcfpoc1.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
This time I forfeited eye candy (the shield button). Same (missing eye candy) goes
for the elevated application as it is a console application only:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://chrison.net/content/binary/uacwcfpoc3.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Solution-wise, this simple two-application scenario is split into four projects:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://chrison.net/content/binary/uacwcfpoc2.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
So where do we start? With the easy part inside ElevationContract:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;[ServiceContract(Namespace &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"http://Christoph.Wille.Samples"&lt;/span&gt;,&lt;br&gt;
CallbackContract &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;typeof&lt;/span&gt;(IElevatedProcess))]&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;interface&lt;/span&gt; IWaitForElevatedProcess&lt;br&gt;
{&lt;br&gt;
&amp;nbsp; [OperationContract(IsOneWay &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;false&lt;/span&gt;)]&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
void&lt;/span&gt; ElevatedProcessStarted();&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
[ServiceContract(Namespace &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"http://Christoph.Wille.Samples"&lt;/span&gt;)]&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;interface&lt;/span&gt; IElevatedProcess&lt;br&gt;
{&lt;br&gt;
&amp;nbsp; [OperationContract(IsOneWay &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;false&lt;/span&gt;)]&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
void&lt;/span&gt; SayHello(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;string&lt;/span&gt; message);&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
The interface IWaitForElevatedProcess is implemented in StandardUserApp. It is the
service endpoint that is initialized before the elevated process is started - and
once the elevated application is up and running, it calls into ElevatedProcessStarted.
And we are in business for using the IElevatedProcess callback that is implemented
in the ElevatedProcess console application.
&lt;/p&gt;
&lt;p&gt;
So how is the service endpoint intialized - let's take a look inside:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;private&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;const&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;string&lt;/span&gt; theProcess &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;@"..\..\..\ElevatedProcess\bin\Debug\ElevatedProcess.exe"&lt;/span&gt;;&lt;br&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;private&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;void&lt;/span&gt; tryitButton_Click(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;object&lt;/span&gt; sender,
EventArgs e)&lt;br&gt;
{&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
string&lt;/span&gt; channelIdentifier &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; MiscHelpers.CreateRandomString(64);&lt;br&gt;
&amp;nbsp; MyUACServiceHost.StartService(channelIdentifier);&lt;br&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
// starting it modal doesn't work (obviously - unless we have more threads, of course)&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; ElevatedProcess.Start(theProcess, channelIdentifier);&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
Interesting tidbit #1 is CreateRandomString: it creates a random string to use for
the address. Why? Well, if multiple instances of our application are running and trying
to elevate a process, we are in trouble. Which brings me to StartService:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;internal&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;static&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;void&lt;/span&gt; StartService(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;string&lt;/span&gt; pipeEndPoint)&lt;br&gt;
{&lt;br&gt;
&amp;nbsp; NetNamedPipeBinding binding &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; NetNamedPipeBinding();&lt;br&gt;
&amp;nbsp; binding.Name &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"uacbinding"&lt;/span&gt;;&lt;br&gt;
&amp;nbsp; binding.Security.Mode &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; NetNamedPipeSecurityMode.Transport;&lt;br&gt;
&lt;br&gt;
&amp;nbsp; Uri baseAddress &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; Uri(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"net.pipe://localhost/uac/"&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;+&lt;/span&gt; pipeEndPoint);&lt;br&gt;
&lt;br&gt;
&amp;nbsp; myServiceHost &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; ServiceHost(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;typeof&lt;/span&gt;(SampleService),
baseAddress);&lt;br&gt;
&amp;nbsp; myServiceHost.AddServiceEndpoint(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;typeof&lt;/span&gt;(IWaitForElevatedProcess),
binding, baseAddress);&lt;br&gt;
&amp;nbsp; myServiceHost.Open();&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
As I said before, I am doing it imperatively (no configuration in app.config necessary).
That's all there is to getting the service up and running.
&lt;/p&gt;
&lt;p&gt;
Now let's switch to the console application's Main method:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;static&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;void&lt;/span&gt; Main(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;string&lt;/span&gt;[]
args)&lt;br&gt;
{&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
if&lt;/span&gt; (args.Length !&lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; 1)&lt;br&gt;
&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"One
argument expected - the channel identifier"&lt;/span&gt;);&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;
&amp;nbsp;return&lt;/span&gt;;&lt;br&gt;
&amp;nbsp; } 
&lt;br&gt;
&lt;br&gt;
&amp;nbsp; NetNamedPipeBinding binding &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; NetNamedPipeBinding();&lt;br&gt;
&amp;nbsp; binding.Name &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"uacbinding"&lt;/span&gt;;&lt;br&gt;
&amp;nbsp; binding.Security.Mode &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; NetNamedPipeSecurityMode.Transport;&lt;br&gt;
&lt;br&gt;
&amp;nbsp; String url &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"net.pipe://localhost/uac/"&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;+&lt;/span&gt; args[0];&lt;br&gt;
&amp;nbsp; EndpointAddress address &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; EndpointAddress(url);&lt;br&gt;
&lt;br&gt;
&amp;nbsp; WaitForElevatedProcess client &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; WaitForElevatedProcess(&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
new&lt;/span&gt; InstanceContext(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; SampleCallback()),&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; binding,&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; address);&lt;br&gt;
&lt;br&gt;
&amp;nbsp; client.ElevatedProcessStarted();&lt;br&gt;
&lt;br&gt;
&amp;nbsp; Console.WriteLine(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"The
elevated process is now ready"&lt;/span&gt;);&lt;br&gt;
&amp;nbsp; Console.ReadLine();&lt;br&gt;
&lt;br&gt;
&amp;nbsp; client.Close();&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
Similar to normal client WCF code, however, with the duplex twist hidden inside WaitForElevatedProcess:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;class&lt;/span&gt; WaitForElevatedProcess
: DuplexClientBase&amp;lt;IWaitForElevatedProcess&amp;gt;, IWaitForElevatedProcess&lt;br&gt;
{&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
public&lt;/span&gt; WaitForElevatedProcess(System.ServiceModel.InstanceContext callbackInstance,&lt;/span&gt;&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; System.ServiceModel.Channels.Binding binding, 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; System.ServiceModel.EndpointAddress remoteAddress)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; : &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;base&lt;/span&gt;(callbackInstance,
binding, remoteAddress)&lt;br&gt;
&amp;nbsp; {&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;void&lt;/span&gt; ElevatedProcessStarted()&lt;br&gt;
&amp;nbsp; {&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;
base&lt;/span&gt;.Channel.ElevatedProcessStarted();&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
Once the channel is connected, this elevated process calls back into the service piece
which lives in the non-elevated application, namely SampleService:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;[ServiceBehavior(ConcurrencyMode &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; ConcurrencyMode.Reentrant, 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; InstanceContextMode &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; InstanceContextMode.PerSession)]&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;class&lt;/span&gt; SampleService
: IWaitForElevatedProcess&lt;br&gt;
{&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;void&lt;/span&gt; ElevatedProcessStarted()&lt;br&gt;
&amp;nbsp;&amp;nbsp;{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; OperationContext.Current.GetCallbackChannel&amp;lt;IElevatedProcess&amp;gt;().SayHello(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"Chris"&lt;/span&gt;);&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
This method is the workhorse where I can talk to the elevated process - if only my
callback interface had more as well as more serious methods ;-) 
&lt;/p&gt;
&lt;p&gt;
Speaking of talking, I owe you the code for the callee in the console application:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;[CallbackBehavior(ConcurrencyMode &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; ConcurrencyMode.Reentrant)]&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;class&lt;/span&gt; SampleCallback
: IElevatedProcess&lt;br&gt;
{&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;void&lt;/span&gt; SayHello(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;string&lt;/span&gt; message)&lt;br&gt;
&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"Hello
world "&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;+&lt;/span&gt; message);&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
That's it - to recap: first, we initialize the WCF service. Then elevate a process.
This process, once initialized, calls into our service and leaves a callback. And
then we are in business talking to the elevated process (setting data, being notified
when the elevated application quits and why, ...).
&lt;/p&gt;
&lt;p&gt;
Sample warnings before you download: MyUACServiceHost definitely should be instance
instead of static. And, more restricting - starting the elevated process modal won't
allow communication &lt;strong&gt;unless&lt;/strong&gt; you start the service on a separate thread.
For simplicity reasons I didn't do this for the POC.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://chrison.net/content/binary/ElevateProcessTalkWCF.zip"&gt;ElevateProcessTalkWCF.zip
(27 KB)&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
Before concluding I wanted to add a few words: my ideal implementation for UAC would
be COM elevation. That way, one can put more than one component into a single DLL,
and still get a meaningful UAC prompt thanks to the LocalizedString registry key -
which is per component, and not per executable (which is the case for this solution
if you add multiple actions). If you need differing prompts for each administrative
action, there is only one course of action you can take with processes: create multiple
executables. Not very pretty, but I failed with writing an elevatable (not a word,
I am sure) managed (C#) COM component.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://chrison.net/aggbug.ashx?id=a860d58a-d4c5-4073-9fee-b3e5fab629bf" /&gt;</description>
      <comments>http://chrison.net/CommentView,guid,a860d58a-d4c5-4073-9fee-b3e5fab629bf.aspx</comments>
      <category>.NET</category>
      <category>3.0</category>
      <category>Security</category>
      <category>UAC</category>
      <category>Vista</category>
      <category>WCF</category>
    </item>
    <item>
      <trackback:ping>http://chrison.net/Trackback.aspx?guid=0b4c5137-0b5c-475b-9f6b-e013dc9c7d5f</trackback:ping>
      <pingback:server>http://chrison.net/pingback.aspx</pingback:server>
      <pingback:target>http://chrison.net/PermaLink,guid,0b4c5137-0b5c-475b-9f6b-e013dc9c7d5f.aspx</pingback:target>
      <dc:creator>Christoph Wille</dc:creator>
      <wfw:comment>http://chrison.net/CommentView,guid,0b4c5137-0b5c-475b-9f6b-e013dc9c7d5f.aspx</wfw:comment>
      <wfw:commentRss>http://chrison.net/SyndicationService.asmx/GetEntryCommentsRss?guid=0b4c5137-0b5c-475b-9f6b-e013dc9c7d5f</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
The previous installment <a href="http://chrison.net/UACElevationInManagedCodeStartingElevatedProcesses.aspx">UAC
Elevation in Managed Code: Starting Elevated Processes</a> dealt with starting executables
with the "real" administrative token. In this blog post, we deal with starting a COM
component with elevated privileges. For in-depth background information, please consult
Kenny Kerr's absolutely excellent post on <a href="http://weblogs.asp.net/kennykerr/archive/2006/09/29/Windows-Vista-for-Developers-_1320_-Part-4-_1320_-User-Account-Control.aspx">Windows
Vista for Developers – Part 4 – User Account Control</a>.
</p>
        <p>
To start with, we need a COM component. Instead of writing an ATL C++ COM component
from scratch, I took the MyElevateCom sample from <a href="http://blogs.msdn.com/vistacompatteam/archive/2006/09/28/CoCreateInstanceAsAdmin-or-CreateElevatedComObject-sample.aspx">CoCreateInstanceAsAdmin
or CreateElevatedComObject sample</a> from the <a href="http://blogs.msdn.com/vistacompatteam/">Vista
Compatibility Team Blog</a>. Note that for building it, check out my post <a href="http://chrison.net/VisualStudioOnVistaNotSoFast.aspx">Visual
Studio on Vista: Not so Fast!</a></p>
        <p>
Assuming that you built and successfully registered the COM component (it is built
to the instuctions from Kenny's post), you can go about and write the managed caller.
First, we need a reference to the component:
</p>
        <p>
          <img src="http://chrison.net/content/binary/atladdcomreference.png" border="0" />
        </p>
        <p>
Then comes the tricky part - actually instantiating the COM component. When you take
a look at the C++ example, you see that quite some "moniker magic" is involved that
cannot be replicated by simply newing up the component. So how to mimic this behavior
in managed code? The <a href="http://www.microsoft.com/downloads/details.aspx?familyid=c2b1e300-f358-4523-b479-f53d234cdccf&amp;displaylang=en">Microsoft®
Windows® Software Development Kit for Windows Vista™ and .NET Framework 3.0 Runtime
Components</a> comes to the rescue: inside, you find C:\Program Files\Microsoft SDKs\Windows\v6.0\Samples\CrossTechnologySamples.zip,
which contains the VistaBridge sample. 
</p>
        <p>
From that, I took the VistaBridgeLibary, and modified the static UACManager.LaunchElevatedCOMObject
method a bit:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">[<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">return</span>:
MarshalAs(UnmanagedType.Interface)]<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">public</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">static</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">object</span> LaunchElevatedCOMObject(Guid
Clsid, Guid InterfaceID)<br />
{<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
string</span> CLSID <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> Clsid.ToString(<span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"B"</span>); 
<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
string</span> monikerName <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"Elevation:Administrator!new:"</span><span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">+</span> CLSID;<br /><br />
  NativeMethods.BIND_OPTS3 bo <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> NativeMethods.BIND_OPTS3();<br />
  bo.cbStruct <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> (<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">uint</span>)Marshal.SizeOf(bo);<br />
  bo.hwnd <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> IntPtr.Zero;<br />
  bo.dwClassContext <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> (<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">int</span>)NativeMethods.CLSCTX.CLSCTX_LOCAL_SERVER;<br /><br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
object</span> retVal <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> UnsafeNativeMethods.CoGetObject(monikerName, <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">ref</span> bo,
InterfaceID);<br /><br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">  return</span> (retVal);<br />
}</span>
        </p>
        <p>
Modifications: the method is now public instead of internal, and CLSCTX changed to
local server (otherwise it wouldn't work).
</p>
        <p>
Next, we need a UI:
</p>
        <p>
          <img src="http://chrison.net/content/binary/uacstartatlcomponent.png" border="0" />
        </p>
        <p>
This button is the CommandLinkWinForms control from VistaBridgeLibary, with the ShieldIcon
property set to true. 
</p>
        <p>
Let's hook up the event code:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">private</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">void</span> tryItButton_Click(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">object</span> sender,
EventArgs e)<br />
{<br />
 Guid IID_ITheElevated <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
new</span> Guid(0x5EFC3EFB, 0xC7D3, 0x4D00, 0xB7, 0x2E, 0x2F, 0x86, 0x4A, 0x1E, 0xAD,
0x06);<br /><br />
 Guid CLSID_TheElevated <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
new</span> Guid(0x253E7696, 0xA524, 0x4E49, 0x9E, 0x50, 0xBF, 0xCC, 0x29, 0x91, 0x31,
0x23);<br /><br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> object</span> o <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> UACManager.LaunchElevatedCOMObject(CLSID_TheElevated,
IID_ITheElevated);<br /><br />
 ITheElevated iface <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> (ITheElevated)o;<br /><br /><span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> //
Call the method on the interface just like in the C++ example</span><br />
 iface.ShowMe();<br /><br /><span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> //
Release the object</span><br />
 Marshal.ReleaseComObject(o);<br />
}</span>
        </p>
        <p>
The interface ID as well as class ID guids come directly from the C++ project (it
is always a good idea to "speak" more than one language), but you could obtain those
from the type library or registry as well if you don't have the source code of the
component handy.
</p>
        <p>
Object creation is handled via LaunchElevatedCOMObject, and the resultant object is
cast to the interface from the imported type library. Noteable (and important) is
the last line: because the object wasn't created by the runtime, we have to take care
of its destruction (the created interface doesn't have a Release() method, so we use
Marshal.ReleaseComObject).
</p>
        <p>
That's it - your managed code is now instantiating an elevated COM object that has
full reign over the system.
</p>
        <p>
          <a href="http://chrison.net/content/binary/ElevateCOMComponentSample.zip">ElevateCOMComponentSample.zip
(117.07 KB)</a>
        </p>
        <img width="0" height="0" src="http://chrison.net/aggbug.ashx?id=0b4c5137-0b5c-475b-9f6b-e013dc9c7d5f" />
      </body>
      <title>UAC Elevation in Managed Code: Starting Elevated COM Components</title>
      <guid isPermaLink="false">http://chrison.net/PermaLink,guid,0b4c5137-0b5c-475b-9f6b-e013dc9c7d5f.aspx</guid>
      <link>http://chrison.net/UACElevationInManagedCodeStartingElevatedCOMComponents.aspx</link>
      <pubDate>Tue, 30 Jan 2007 09:14:50 GMT</pubDate>
      <description>&lt;p&gt;
The previous installment &lt;a href="http://chrison.net/UACElevationInManagedCodeStartingElevatedProcesses.aspx"&gt;UAC
Elevation in Managed Code: Starting Elevated Processes&lt;/a&gt; dealt with starting executables
with the "real" administrative token. In this blog post, we deal with starting a COM
component with elevated privileges. For in-depth background information, please consult
Kenny Kerr's absolutely excellent post on &lt;a href="http://weblogs.asp.net/kennykerr/archive/2006/09/29/Windows-Vista-for-Developers-_1320_-Part-4-_1320_-User-Account-Control.aspx"&gt;Windows
Vista for Developers – Part 4 – User Account Control&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
To start with, we need a COM component. Instead of writing an ATL C++ COM component
from scratch, I took the MyElevateCom sample from &lt;a href="http://blogs.msdn.com/vistacompatteam/archive/2006/09/28/CoCreateInstanceAsAdmin-or-CreateElevatedComObject-sample.aspx"&gt;CoCreateInstanceAsAdmin
or CreateElevatedComObject sample&lt;/a&gt; from the &lt;a href="http://blogs.msdn.com/vistacompatteam/"&gt;Vista
Compatibility Team Blog&lt;/a&gt;. Note that for building it, check out my post &lt;a href="http://chrison.net/VisualStudioOnVistaNotSoFast.aspx"&gt;Visual
Studio on Vista: Not so Fast!&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
Assuming that you built and successfully registered the COM component (it is built
to the instuctions from Kenny's post), you can go about and write the managed caller.
First, we need a reference to the component:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://chrison.net/content/binary/atladdcomreference.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Then comes the tricky part - actually instantiating the COM component. When you take
a look at the C++ example, you see that quite some "moniker magic" is involved that
cannot be replicated by simply newing up the component. So how to mimic this behavior
in managed code? The &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=c2b1e300-f358-4523-b479-f53d234cdccf&amp;amp;displaylang=en"&gt;Microsoft®
Windows® Software Development Kit for Windows Vista™ and .NET Framework 3.0 Runtime
Components&lt;/a&gt; comes to the rescue: inside, you find C:\Program Files\Microsoft SDKs\Windows\v6.0\Samples\CrossTechnologySamples.zip,
which contains the VistaBridge sample. 
&lt;/p&gt;
&lt;p&gt;
From that, I took the VistaBridgeLibary, and modified the static UACManager.LaunchElevatedCOMObject
method a bit:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;[&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;return&lt;/span&gt;:
MarshalAs(UnmanagedType.Interface)]&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;static&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;object&lt;/span&gt; LaunchElevatedCOMObject(Guid
Clsid, Guid InterfaceID)&lt;br&gt;
{&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
string&lt;/span&gt; CLSID &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; Clsid.ToString(&lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"B"&lt;/span&gt;); 
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
string&lt;/span&gt; monikerName &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"Elevation:Administrator!new:"&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;+&lt;/span&gt; CLSID;&lt;br&gt;
&lt;br&gt;
&amp;nbsp; NativeMethods.BIND_OPTS3 bo &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; NativeMethods.BIND_OPTS3();&lt;br&gt;
&amp;nbsp; bo.cbStruct &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; (&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;uint&lt;/span&gt;)Marshal.SizeOf(bo);&lt;br&gt;
&amp;nbsp; bo.hwnd &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; IntPtr.Zero;&lt;br&gt;
&amp;nbsp; bo.dwClassContext &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; (&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;int&lt;/span&gt;)NativeMethods.CLSCTX.CLSCTX_LOCAL_SERVER;&lt;br&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
object&lt;/span&gt; retVal &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; UnsafeNativeMethods.CoGetObject(monikerName, &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;ref&lt;/span&gt; bo,
InterfaceID);&lt;br&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;return&lt;/span&gt; (retVal);&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
Modifications: the method is now public instead of internal, and CLSCTX changed to
local server (otherwise it wouldn't work).
&lt;/p&gt;
&lt;p&gt;
Next, we need a UI:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://chrison.net/content/binary/uacstartatlcomponent.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
This button is the CommandLinkWinForms control from VistaBridgeLibary, with the ShieldIcon
property set to true. 
&lt;/p&gt;
&lt;p&gt;
Let's hook up the event code:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;private&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;void&lt;/span&gt; tryItButton_Click(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;object&lt;/span&gt; sender,
EventArgs e)&lt;br&gt;
{&lt;br&gt;
&amp;nbsp;Guid IID_ITheElevated &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
new&lt;/span&gt; Guid(0x5EFC3EFB, 0xC7D3, 0x4D00, 0xB7, 0x2E, 0x2F, 0x86, 0x4A, 0x1E, 0xAD,
0x06);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;Guid CLSID_TheElevated &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; 
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
new&lt;/span&gt; Guid(0x253E7696, 0xA524, 0x4E49, 0x9E, 0x50, 0xBF, 0xCC, 0x29, 0x91, 0x31,
0x23);&lt;br&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;object&lt;/span&gt; o &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; UACManager.LaunchElevatedCOMObject(CLSID_TheElevated,
IID_ITheElevated);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;ITheElevated iface &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; (ITheElevated)o;&lt;br&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;//
Call the method on the interface just like in the C++ example&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;iface.ShowMe();&lt;br&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: green; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;//
Release the object&lt;/span&gt;
&lt;br&gt;
&amp;nbsp;Marshal.ReleaseComObject(o);&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
The interface ID as well as class ID guids come directly from the C++ project (it
is always a good idea to "speak" more than one language), but you could obtain those
from the type library or registry as well if you don't have the source code of the
component handy.
&lt;/p&gt;
&lt;p&gt;
Object creation is handled via LaunchElevatedCOMObject, and the resultant object is
cast to the interface from the imported type library. Noteable (and important) is
the last line: because the object wasn't created by the runtime, we have to take care
of its destruction (the created interface doesn't have a Release() method, so we use
Marshal.ReleaseComObject).
&lt;/p&gt;
&lt;p&gt;
That's it - your managed code is now instantiating an elevated COM object that has
full reign over the system.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://chrison.net/content/binary/ElevateCOMComponentSample.zip"&gt;ElevateCOMComponentSample.zip
(117.07 KB)&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://chrison.net/aggbug.ashx?id=0b4c5137-0b5c-475b-9f6b-e013dc9c7d5f" /&gt;</description>
      <comments>http://chrison.net/CommentView,guid,0b4c5137-0b5c-475b-9f6b-e013dc9c7d5f.aspx</comments>
      <category>.NET</category>
      <category>Security</category>
      <category>UAC</category>
      <category>Use the source Luke</category>
      <category>Vista</category>
    </item>
    <item>
      <trackback:ping>http://chrison.net/Trackback.aspx?guid=8f54c1c4-56df-4965-a1fd-20c1bd9932ae</trackback:ping>
      <pingback:server>http://chrison.net/pingback.aspx</pingback:server>
      <pingback:target>http://chrison.net/PermaLink,guid,8f54c1c4-56df-4965-a1fd-20c1bd9932ae.aspx</pingback:target>
      <dc:creator>Christoph Wille</dc:creator>
      <wfw:comment>http://chrison.net/CommentView,guid,8f54c1c4-56df-4965-a1fd-20c1bd9932ae.aspx</wfw:comment>
      <wfw:commentRss>http://chrison.net/SyndicationService.asmx/GetEntryCommentsRss?guid=8f54c1c4-56df-4965-a1fd-20c1bd9932ae</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
When you are working with Windows Vista, you know that even the administrative users
are stripped ("filtered") of their privileges for normal operations, and that when
you have to perform tasks requiring administrative privileges, you are presented with
an UAC elevation prompt. The idea of this blog post series is to provide you with
working samples on how to work with elevation from inside managed applications (you
might also want to read <a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=ba73b169-a648-49af-bc5e-a2eebb74c16b&amp;DisplayLang=en">Windows
Vista Application Development Requirements for User Account Control Compatibility</a>).
</p>
        <p>
I want to side-step the really easy part - providing a manifest to start the entire
application elevated (a good idea if the application makes no sense at all unless
it has administrative rights, like regedit.exe). You can find information on those
topics in <a href="http://blogs.msdn.com/shawnfa/archive/2006/04/06/568563.aspx">Adding
a UAC Manifest to Managed Code</a> and <a href="http://www.danielmoth.com/Blog/2006/07/vista-user-account-control.html">Vista:
User Account Control</a>.
</p>
        <p>
Now back to the topic of this post: App A needs to start App B with administrative
rights (because App B e.g. needs to write to HKLM or Program Files). Therefore, we
somehow must run App B as an administrative user (or with the non-filtered token of
the current user). So how do we go about it?
</p>
        <p>
First, some eye candy. You definitely already saw those nice shield icons before:
</p>
        <p>
          <img src="http://chrison.net/content/binary/uacstartprocess.png" border="0" />
        </p>
        <p>
Those shield icons are stock on Windows Vista and indicate to the user that the action
that hides behind the button requires elevation. I didn't create a button control
myself - instead, I reused one that is readily available on the Web: <a href="http://www.brethorsting.com/uidesign/2006/11/add_a_uac_shield_to_your_winfo.html">Add
a UAC Shield to your Winforms buttons in C#</a>.
</p>
        <p>
All I had to do myself was to start the Process ("App B"):
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">private</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">void</span> startProcess_Click(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">object</span> sender,
EventArgs e)<br />
{<br />
  ProcessStartInfo psi <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> ProcessStartInfo();<br />
  psi.FileName <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> theProcess;<br />
  psi.Verb <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"runas"</span>;<br />
  Process.Start(psi);<br />
}</span>
        </p>
        <p>
The ticket (so to speak) for the elevation prompt is setting the Verb to "runas"
in the ProcessStartInfo instance - this will pop up the elevation prompt if necessary
when Process.Start is called.
</p>
        <p>
This simplistic approach has a problem though - once App B is started, users can switch
back to App A, because it App B isn't "modal" for App A. To solve this problem, I
incorporated the approach from Daniel Moth outlined in his post <a href="http://www.danielmoth.com/Blog/2006/12/launch-elevated-and-modal-too.html">Launch
elevated and modal too</a>:
</p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">private</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">void</span> launchModal_Click(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">object</span> sender,
EventArgs e)<br />
{<br />
  ProcessStartInfo psi <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> ProcessStartInfo();<br />
  psi.FileName <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> theProcess;<br />
  psi.Verb <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"runas"</span>;<br /><br />
  psi.ErrorDialog <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">true</span>;<br />
  psi.ErrorDialogParentHandle <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">this</span>.Handle;<br /><br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
try</span><br />
  {<br />
    Process p <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> Process.Start(psi);<br />
    p.WaitForExit();<br />
  }<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"> 
catch</span> (Exception ex)<br />
  {<br />
    MessageBox.Show(ex.ToString());<br />
  }<br />
}</span>
        </p>
        <p>
And that's it - App B is now modal. Once App B quits, control is relinquished to App
A (which still doesn't run with administrative rights). 
</p>
        <p>
          <a href="http://chrison.net/content/binary/ElevateProcessSample.zip">ElevateProcessSample.zip
(21.1 KB)</a>
        </p>
        <img width="0" height="0" src="http://chrison.net/aggbug.ashx?id=8f54c1c4-56df-4965-a1fd-20c1bd9932ae" />
      </body>
      <title>UAC Elevation in Managed Code: Starting Elevated Processes</title>
      <guid isPermaLink="false">http://chrison.net/PermaLink,guid,8f54c1c4-56df-4965-a1fd-20c1bd9932ae.aspx</guid>
      <link>http://chrison.net/UACElevationInManagedCodeStartingElevatedProcesses.aspx</link>
      <pubDate>Tue, 30 Jan 2007 07:14:31 GMT</pubDate>
      <description>&lt;p&gt;
When you are working with Windows Vista, you know that even the administrative users
are stripped ("filtered") of their privileges for normal operations, and that when
you have to perform tasks requiring administrative privileges, you are presented with
an UAC elevation prompt. The idea of this blog post series is to provide you with
working samples on how to work with elevation from inside managed applications (you
might also want to read &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=ba73b169-a648-49af-bc5e-a2eebb74c16b&amp;amp;DisplayLang=en"&gt;Windows
Vista Application Development Requirements for User Account Control Compatibility&lt;/a&gt;).
&lt;/p&gt;
&lt;p&gt;
I want to side-step the really easy part - providing a manifest to start the entire
application elevated (a good idea if the application makes no sense at all unless
it has administrative rights, like regedit.exe). You can find information on those
topics in &lt;a href="http://blogs.msdn.com/shawnfa/archive/2006/04/06/568563.aspx"&gt;Adding
a UAC Manifest to Managed Code&lt;/a&gt; and &lt;a href="http://www.danielmoth.com/Blog/2006/07/vista-user-account-control.html"&gt;Vista:
User Account Control&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
Now back to the topic of this post: App A needs to start App B with administrative
rights (because App B e.g. needs to write to HKLM or Program Files). Therefore, we
somehow must run App B as an administrative user (or with the non-filtered token of
the current user). So how do we go about it?
&lt;/p&gt;
&lt;p&gt;
First, some eye candy. You definitely already saw those nice shield icons before:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://chrison.net/content/binary/uacstartprocess.png" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Those shield icons are stock on Windows Vista and indicate to the user that the action
that hides behind the button requires elevation. I didn't create a button control
myself - instead, I reused one that is readily available on the Web: &lt;a href="http://www.brethorsting.com/uidesign/2006/11/add_a_uac_shield_to_your_winfo.html"&gt;Add
a UAC Shield to your Winforms buttons in C#&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
All I had to do myself was to start the Process ("App B"):
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;private&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;void&lt;/span&gt; startProcess_Click(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;object&lt;/span&gt; sender,
EventArgs e)&lt;br&gt;
{&lt;br&gt;
&amp;nbsp; ProcessStartInfo psi &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; ProcessStartInfo();&lt;br&gt;
&amp;nbsp; psi.FileName &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; theProcess;&lt;br&gt;
&amp;nbsp; psi.Verb &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"runas"&lt;/span&gt;;&lt;br&gt;
&amp;nbsp; Process.Start(psi);&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
The ticket (so to speak)&amp;nbsp;for the elevation prompt is setting the Verb to "runas"
in the ProcessStartInfo instance - this will pop up the elevation prompt if necessary
when Process.Start is called.
&lt;/p&gt;
&lt;p&gt;
This simplistic approach has a problem though - once App B is started, users can switch
back to App A, because it App B isn't "modal" for App A. To solve this problem, I
incorporated the approach from Daniel Moth outlined in his post &lt;a href="http://www.danielmoth.com/Blog/2006/12/launch-elevated-and-modal-too.html"&gt;Launch
elevated and modal too&lt;/a&gt;:
&lt;/p&gt;
&lt;p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;private&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;void&lt;/span&gt; launchModal_Click(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;object&lt;/span&gt; sender,
EventArgs e)&lt;br&gt;
{&lt;br&gt;
&amp;nbsp; ProcessStartInfo psi &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; ProcessStartInfo();&lt;br&gt;
&amp;nbsp; psi.FileName &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; theProcess;&lt;br&gt;
&amp;nbsp; psi.Verb &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"runas"&lt;/span&gt;;&lt;br&gt;
&lt;br&gt;
&amp;nbsp; psi.ErrorDialog &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;true&lt;/span&gt;;&lt;br&gt;
&amp;nbsp; psi.ErrorDialogParentHandle &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;this&lt;/span&gt;.Handle;&lt;br&gt;
&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
try&lt;/span&gt;
&lt;br&gt;
&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Process p &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; Process.Start(psi);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; p.WaitForExit();&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;
catch&lt;/span&gt; (Exception ex)&lt;br&gt;
&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; MessageBox.Show(ex.ToString());&lt;br&gt;
&amp;nbsp; }&lt;br&gt;
}&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
And that's it - App B is now modal. Once App B quits, control is relinquished to App
A (which still doesn't run with administrative rights). 
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://chrison.net/content/binary/ElevateProcessSample.zip"&gt;ElevateProcessSample.zip
(21.1 KB)&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://chrison.net/aggbug.ashx?id=8f54c1c4-56df-4965-a1fd-20c1bd9932ae" /&gt;</description>
      <comments>http://chrison.net/CommentView,guid,8f54c1c4-56df-4965-a1fd-20c1bd9932ae.aspx</comments>
      <category>Security</category>
      <category>UAC</category>
      <category>Use the source Luke</category>
      <category>Vista</category>
    </item>
    <item>
      <trackback:ping>http://chrison.net/Trackback.aspx?guid=16957842-8624-4513-a236-1b2c342f7bbe</trackback:ping>
      <pingback:server>http://chrison.net/pingback.aspx</pingback:server>
      <pingback:target>http://chrison.net/PermaLink,guid,16957842-8624-4513-a236-1b2c342f7bbe.aspx</pingback:target>
      <dc:creator>Christoph Wille</dc:creator>
      <wfw:comment>http://chrison.net/CommentView,guid,16957842-8624-4513-a236-1b2c342f7bbe.aspx</wfw:comment>
      <wfw:commentRss>http://chrison.net/SyndicationService.asmx/GetEntryCommentsRss?guid=16957842-8624-4513-a236-1b2c342f7bbe</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
        </p>
        <p>
I don't recommend turning off UAC (User Account Control) on Windows Vista, but there
might be valid reasons to shut it off once in a while for testing purposes (like in
a VM). That is where <a href="http://www.tweak-uac.com/what-is-tweak-uac/">TweakUAC</a> comes
in handy:
</p>
        <p>
          <img src="http://chrison.net/content/binary/tweakuac.png" border="0" />
        </p>
        <img width="0" height="0" src="http://chrison.net/aggbug.ashx?id=16957842-8624-4513-a236-1b2c342f7bbe" />
      </body>
      <title>TweakUAC</title>
      <guid isPermaLink="false">http://chrison.net/PermaLink,guid,16957842-8624-4513-a236-1b2c342f7bbe.aspx</guid>
      <link>http://chrison.net/TweakUAC.aspx</link>
      <pubDate>Thu, 25 Jan 2007 09:32:21 GMT</pubDate>
      <description>&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
I don't recommend turning off UAC (User Account Control) on Windows Vista, but there
might be valid reasons to shut it off once in a while for testing purposes (like in
a VM). That is where &lt;a href="http://www.tweak-uac.com/what-is-tweak-uac/"&gt;TweakUAC&lt;/a&gt; comes
in handy:
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://chrison.net/content/binary/tweakuac.png" border=0&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://chrison.net/aggbug.ashx?id=16957842-8624-4513-a236-1b2c342f7bbe" /&gt;</description>
      <comments>http://chrison.net/CommentView,guid,16957842-8624-4513-a236-1b2c342f7bbe.aspx</comments>
      <category>Security</category>
      <category>UAC</category>
      <category>Vista</category>
    </item>
  </channel>
</rss>