<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>JEDI Windows API &#187; manifest</title>
	<atom:link href="http://blog.delphi-jedi.net/tag/manifest/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.delphi-jedi.net</link>
	<description>Joint Endeavor of Delphi Innovators of Windows Programming</description>
	<lastBuildDate>Wed, 19 Oct 2011 18:52:10 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Elevate application on Vista with JWSCL</title>
		<link>http://blog.delphi-jedi.net/2008/03/18/elevate-application-on-vista-with-jwscl/</link>
		<comments>http://blog.delphi-jedi.net/2008/03/18/elevate-application-on-vista-with-jwscl/#comments</comments>
		<pubDate>Tue, 18 Mar 2008 13:00:44 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[JEDI Windows Security Code Lib]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[elevate]]></category>
		<category><![CDATA[JWSCL]]></category>
		<category><![CDATA[manifest]]></category>
		<category><![CDATA[UAC]]></category>
		<category><![CDATA[Vista]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/2008/03/18/elevate-application-on-vista-with-jwscl/</guid>
		<description><![CDATA[This little article shows you how to elevate an application using JWSCL. There are two possible ways to elevate an application : Elevate the application from the beginning Elevate special parts of your application Both ways needs a manifest to be included into your application. 1. Elevate the application from the beginning The easiest way [...]]]></description>
			<content:encoded><![CDATA[<p>This little article shows you how to elevate an application using <strong>JWSCL</strong>.<br />
There are two possible ways to elevate an application :</p>
<ol>
<li>Elevate the application from the beginning</li>
<li>Elevate special parts of your application</li>
</ol>
<p>Both ways needs a manifest to be included into your application.</p>
<p><u>1. Elevate the application from the beginning</u></p>
<p>The easiest way to elevate an application is to tell Windows to do it for you. This is done by applying a manifest.</p>
<blockquote><p>A manifest is a text resource that tells Windows what needs to be prepared before your application starts. This includes theme support and privileges your application needs. Developers maybe know it from Windows XP where it enables themed window controls.</p></blockquote>
<p>Telling Windows to start your application as an administrator is done by using &#8220;requireAdministrator&#8221; as required security level in the manifest. However the code below is just an excerpt. You can get a full version of the manifest with a <a href="#ManifestCode" title="Find the whole manifest data.">warning</a>.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="sc3"><span class="re1">&lt;security<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;requestedPrivileges<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;requestedExecutionLevel</span> <span class="re0">level</span>=<span class="st0">&quot;requireAdministrator&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/requestedPrivileges<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/security<span class="re2">&gt;</span></span></span></div>
<p>If you are going to use this manifest in your application, you have to consider that your application needs to be elevated all the time. Thus users without administrator access cannot launch your application at all.</p>
<p>However there is a second way which does not need a manifest at all. Some applications do start their own process with elevated rights. They start a second instance, close the actual one and go on elevated.<br />
Examples are :</p>
<ul>
<li>the <em>Taskmanager </em>can elevate itself by clicking &#8220;Show processes from all users&#8221;<br />
<img src="http://blog.delphi-jedi.net/wp-content/uploads/2008/03/bild-13.jpg" alt="Bild" height="35" width="212" /></li>
<li><a href="http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx"><em>ProcessExplorer</em></a><br />
<img src="http://blog.delphi-jedi.net/wp-content/uploads/2008/03/bild-15.jpg" alt="Bild" height="141" width="267" /></li>
</ul>
<p>JWSCL contains a unit called <a href="http://jwscldoc.delphi-jedi.net/JwsclElevation.html"><em>JwsclElevation</em></a> which provides the necessary functions to allow this simple elevation.</p>
<p>function <em><a href="http://jwscldoc.delphi-jedi.net/JwsclElevation.html#JwShellExecute">JwShellExecute</a></em>(const hWnd: HWND; FileName, Parameters,<br />
Directory: TJwString; ShowCmd: Integer): HINST;<br />
This function just works like the usual ShellExecute but let&#8217;s you elevate any program or your application. The return value In the following way you can start the command line prompt with elevated privileges.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">var</span> hProc : <span class="kw4">THandle</span>;<br />
<span class="kw1">begin</span><br />
&nbsp; hProc := JwShellExecute<span class="br0">&#40;</span><span class="nu0">0</span>, <span class="st0">&#8216;cmd&#8217;</span>, <span class="st0">&#8221;</span>, <span class="st0">&#8221;</span>, SW_SHOW<span class="br0">&#41;</span>;<br />
&nbsp; <span class="kw1">if</span> hProc &lt;&gt; <span class="nu0">0</span> <span class="kw1">then</span><br />
&nbsp; &nbsp; CloseHandle<span class="br0">&#40;</span>hProc<span class="br0">&#41;</span>;</div>
<p>The developer version (revision &gt; 317) does have some more extension, less bugs and a different behavior.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">function</span> JwShellExecute<span class="br0">&#40;</span><span class="kw1">const</span> hWnd: HWND;<br />
&nbsp; &nbsp; FileName,<br />
&nbsp; &nbsp; Parameters,<br />
&nbsp; &nbsp; Directory: TJwString;<br />
&nbsp; &nbsp; ShowCmd: <span class="kw4">Integer</span>;<br />
&nbsp; &nbsp; Flags : TJwShellExecuteFlags = <span class="br0">&#91;</span>sefNoClosehProcess<span class="br0">&#93;</span><span class="br0">&#41;</span>: HANDLE;</div>
<p>Let me list the differences :</p>
<ul>
<li><em>JwShellExecute</em> raises <em><a href="http://jwscldoc.delphi-jedi.net/JwsclExceptions.EJwsclWinCallFailedException.html">EJwsclWinCallFailedException</a></em> when the call to ShellExecuteEx fails.</li>
<li>The new optional parameter Flags controls some aspects
<ul>
<li><strong>sefNoUi </strong>does not allow ShellExecute to show error messages on the user&#8217;s screen</li>
<li><strong>sefIgnoreElevationIfNotAvailable</strong>. Usually JwShellExecute checks whether the user is already elevated and if so just starts the application. However this call will fail on preVista systems. If this flag is set the function will not fail on preVista systems and just execute the application.</li>
<li><strong>sefFixDirWithRunAs</strong>. ShellExecute ignores the directory parameter if it is called with the &#8220;runas&#8221; verb. However with this flag set, the JEDI function uses a trick to start the application in the correct directory. In this way there maybe a command window visible.</li>
<li><strong>sefNoClosehProcess</strong>. The newer version of JwShellExecute closes the returned process handle for you if this flag is not set. If you need that process handle (e.g. waiting for the process to end) you should remove it.</li>
</ul>
</li>
<li>The return value is a handle to the process. It is now automatically closed for your if you do not deny it through the flag parameter.</li>
</ul>
<p>The following code shows how to start the application with elevated privileges from whithin the same app.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">var</span> NewProcessHandle : HANDLE;<br />
<span class="kw1">begin</span><br />
&nbsp; <span class="kw1">try</span><br />
&nbsp; &nbsp; NewProcessHandle := JwShellExecute<span class="br0">&#40;</span>ForeGroundWindow,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">ParamStr</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span>, Parameter, Directory, SW_NORMAL,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span>sefNoUi, sefFixDirWithRunAs,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;sefIgnoreElevationIfNotAvailable, sefNoClosehProcess<span class="br0">&#93;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="kw1">except</span><br />
&nbsp; &nbsp; <span class="kw1">On</span> E : EJwsclWinCallFailedException <span class="kw1">do</span><br />
&nbsp; &nbsp; <span class="kw1">begin</span><br />
&nbsp; &nbsp; &nbsp; LastError := E.<span class="me1">LastError</span>;<br />
&nbsp; &nbsp; &nbsp; <span class="co1">//do error stuff here</span><br />
&nbsp; &nbsp; &nbsp;<span class="kw3">exit</span>;<br />
&nbsp; &nbsp; <span class="kw1">end</span>;<br />
&nbsp; <span class="kw1">end</span>;<br />
&nbsp; <span class="co1">//make sure the app has started</span><br />
&nbsp; <span class="kw1">if</span> NewProcessHandle &lt;&gt; <span class="nu0">0</span> <span class="kw1">then</span><br />
&nbsp; <span class="kw1">begin</span><br />
&nbsp; &nbsp; <span class="co1">//wait for the app to be initialized and read to get user input</span><br />
&nbsp; &nbsp; <span class="co1">//or just remove it &#8211; what you like</span><br />
&nbsp; &nbsp; WaitForInputIdle<span class="br0">&#40;</span>NewProcessHandle, yourTimeHere<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; CloseHandle<span class="br0">&#40;</span>NewProcessHandle<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="co1">//terminate your application here</span><br />
&nbsp; <span class="kw1">end</span>;<br />
&#8230;</div>
<p><u>2. Elevate special parts of your application</u></p>
<p>To elevate special parts of your application is the prefered way for a Vista application. This is done by separate the parts of your application that needs administrative rights, into an external process. We do not need to create a new application and do the inter-process communication stuff. Windows Vista uses an external COM process for this task. So the solutions goes with a COM DLL that we have to implement. In addition to that we also have to add a manifest &#8211; of course.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="sc3"><span class="re1">&lt;security<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;requestedPrivileges<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;requestedExecutionLevel</span> <span class="re0">level</span>=<span class="st0">&quot;asInvoker&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/requestedPrivileges<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/security<span class="re2">&gt;</span></span></span></div>
<p>I will not tell the whole story about how to create a COM DLL and do all the stuff that has to be done. You should read <a href="http://developersoven.blogspot.com/2007/02/leveraging-vistas-uac-with-delphi-part.html">Aleksander Oven&#8217;s tutorial</a> how to accomplish that.<br />
I&#8217;m going to show you how you can use the <strong>JWSCL</strong> methods.</p>
<p>Create your COM Dll and implement the COM interface. This may look like this (from the <a href="http://blog.delphi-jedi.net/2008/03/13/run-a-program-elevated/">RunEl</a> example in JWSCL):</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">uses</span> jwaWindows, ActiveX, Dialogs,<br />
&nbsp; Classes, ComObj, RunElCOM_TLB, StdVcl; &nbsp; &nbsp; &nbsp;</p>
<p><span class="kw1">type</span><br />
&nbsp;TJwRunElevated = <span class="kw1">class</span><span class="br0">&#40;</span>TTypedComObject, IJwRunElevated<span class="br0">&#41;</span><br />
&nbsp;<span class="kw1">protected</span><br />
&nbsp; <span class="kw1">function</span> RunAppElevated<span class="br0">&#40;</span>AppName: <span class="kw4">PWideChar</span>;<br />
&nbsp; &nbsp; &nbsp;Parameter: <span class="kw4">PWideChar</span>; Dir: <span class="kw4">PWideChar</span>;<br />
&nbsp; &nbsp; &nbsp;ClientProcessID: <span class="kw4">LongWord</span>; out NewThreadHandle: <span class="kw4">LongWord</span>;<br />
&nbsp; &nbsp; &nbsp;out NewProcessHandle: <span class="kw4">LongWord</span>;<br />
&nbsp; &nbsp; &nbsp;out ResultValue: <span class="kw4">LongWord</span><span class="br0">&#41;</span>: HResult; &nbsp;<span class="kw1">stdcall</span>; <span class="kw1">end</span>;<br />
&#8230;</div>
<p>The important stuff comes here.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">initialization</span><br />
&nbsp; TElevationClassFactory.<span class="me1">Create</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; @ElevationDescription, <span class="kw2">true</span>,<br />
&nbsp; &nbsp; ComServer, TJwRunElevated,<br />
&nbsp; &nbsp; CLASS_JwRunElevated,<br />
&nbsp; &nbsp; iMultiInstance<span class="br0">&#41;</span>;</div>
<p>Use the <a href="http://jwscldoc.delphi-jedi.net/JwsclElevation.TElevationClassFactory.html"><em>TElevationClassFactory</em></a> or <em>TJwElevationClassFactory</em> (in developer version &gt; 317) for registering the COM class in Windows. After you registered the COM class using regsvr32 (see Tutorial) you can retrieve an instance of the COM class with <em><a href="http://jwscldoc.delphi-jedi.net/JwsclElevation.html#JwCoCreateInstanceAsAdmin">JwCoCreateInstanceAsAdmin</a></em>.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">var</span><br />
&nbsp; ElevatedObject: IJwRunElevated;<br />
&nbsp; Result : HRESULT;<br />
<span class="kw1">begin</span><br />
&nbsp; Result := JwCoCreateInstanceAsAdmin<span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;ForeGroundWindow,<br />
&nbsp; &nbsp; &nbsp; &nbsp;CLASS_JwRunElevated,<br />
&nbsp; &nbsp; &nbsp; &nbsp;IID_IJwRunElevated,<br />
&nbsp; &nbsp; &nbsp; &nbsp;ElevatedObject<span class="br0">&#41;</span>;</div>
<p>If the thread has already elevated privileges the function JwCoCreateInstanceAsAdmin simply returns an instance without using the elevation prompt.</p>
<p>In developer version (revision &gt; 317) the returned result value can contain information about the status.</p>
<ul>
<li><strong>ERROR_SUCCESS</strong> &#8211; No error</li>
<li>(revision &gt; 317) <strong>ERROR_CANCELLED</strong> &#8211; the user has canceled the UAC prompt.</li>
<li>(revision &gt; 317) <strong>E_CLASS_IS_NOT_SETUP</strong> &#8211; the requested COM class has not been setup to be used for elevation.</li>
<li><em>CoGetObject (if elevation is required) </em>or <em>CoCreateInstance </em>(if elevation is not required) may return an error value</li>
</ul>
<p><u><strong>Be warned:<br />
</strong></u>If you try to execute this function on a preVista system, the function is going to fail with EJwsclUnsupportedWindowsVersionException.</p>
<hr size="2" width="100%" />You can find the shown source code in the repository of <strong>JWSCL</strong>. The library has two sample applications that use the technics describes above:</p>
<ul>
<li><a href="http://blog.delphi-jedi.net/2008/03/13/run-a-program-elevated/">RunEl</a> (<em>JwShellExecute </em>and COM DLL) or <a href="https://jedi-apilib.svn.sourceforge.net/svnroot/jedi-apilib/jwscl/trunk/examples/runel/">Current repository</a>.</li>
<li>VistaElevation (COM DLL). <a href="http://blog.delphi-jedi.net/category/downloads/jwscl-downloads/">Download JWSCL</a> or <a href="https://jedi-apilib.svn.sourceforge.net/svnroot/jedi-apilib/jwscl/trunk/examples/VistaElevation/">Current repository</a>.</li>
</ul>
<p><u><strong>Warning:</strong></u><a name="ManifestCode" title="ManifestCode"></a><br />
There is a problem with the manifest scanner on Windows XP. If you try to start an application with a manifest created for Vista you&#8217;re goingt to probably have a <a href="http://en.wikipedia.org/wiki/BSOD"><font color="#0000ff">Blue Screen of Death</font></a>. So you have to get a correct manifest from <a href="http://www.delphipraxis.net/topic130450_vista+uac+programm+mit+adminrechten+starten.html">here</a> (<a href="http://translate.google.com/translate?u=http%3A%2F%2Fwww.delphipraxis.net%2Ftopic130450_vista%2Buac%2Bprogramm%2Bmit%2Badminrechten%2Bstarten.html&amp;langpair=de%7Cen&amp;hl=de&amp;ie=UTF-8">english translation</a>).</p>
<p><strong>Tell me how you liked this blog entry by adding a comment.</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2008/03/18/elevate-application-on-vista-with-jwscl/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Why aren&#8217;t dialogs themed in elevated COM methods.</title>
		<link>http://blog.delphi-jedi.net/2008/03/14/why-arent-dialogs-themed-in-elevated-com-methods/</link>
		<comments>http://blog.delphi-jedi.net/2008/03/14/why-arent-dialogs-themed-in-elevated-com-methods/#comments</comments>
		<pubDate>Fri, 14 Mar 2008 14:07:33 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[JEDI Windows Security Code Lib]]></category>
		<category><![CDATA[callback]]></category>
		<category><![CDATA[COM]]></category>
		<category><![CDATA[dialog]]></category>
		<category><![CDATA[DLL]]></category>
		<category><![CDATA[factory]]></category>
		<category><![CDATA[interface]]></category>
		<category><![CDATA[mailinglist]]></category>
		<category><![CDATA[manifest]]></category>
		<category><![CDATA[ProcessExplorer]]></category>
		<category><![CDATA[Theme]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/2008/03/14/why-arent-dialogs-themed-in-elevated-com-methods/</guid>
		<description><![CDATA[I found this question in the borland mailinglist: &#8230; I get my dialog and all runs well &#8211; *except* I&#8217;ve lost theming on this particular dialog. This means the application&#8217;s main windows shows up correctly themed, the progress dialog does not. I&#8217;ve already added the XP manifest to the progress dialog, too, but to no [...]]]></description>
			<content:encoded><![CDATA[<p>I found this question in the <a href="news://newsgroups.borland.com:119/borland.public.delphi.language.delphi.win32">borland mailinglist</a>:</p>
<blockquote><p>&#8230; I get my dialog and all runs well &#8211; *except* I&#8217;ve lost theming<br />
on this particular dialog. This means the application&#8217;s main windows shows<br />
up correctly themed, the progress dialog does not. I&#8217;ve already added the<br />
XP manifest to the progress dialog, too, but to no avail so far.</p></blockquote>
<p>A theme is only applied if an EXE or DLL file has a manifest that explicitly enables theme support. If Windows cannot find this manifest, the process is only shown with the regular window design.</p>
<p><span id="more-47"></span></p>
<p><img src="http://blog.delphi-jedi.net/wp-content/uploads/2008/03/bild-9-1-small.jpg" alt="Bild" height="168" width="225" /><img src="http://blog.delphi-jedi.net/wp-content/uploads/2008/03/bild-12-small.jpg" alt="Bild" height="168" width="225" /></p>
<p>However the Vista elevation is done by creating a COM object and offers its methods through a seperate process. A seperate process is necessary because the same process cannot get assigned the ncessary administrator token. In our case a service in the service container svchost.exe has the task to host the COM object. The contained service is called dllhost.exe (service name: &#8220;COMSysApp&#8221;) and does not run until requested. It does not matter whether the service is deactivated or not because it is started directly by svchost.</p>
<p><a href="http://blog.delphi-jedi.net/wp-content/uploads/2008/03/bild-6.jpg"><img src="http://blog.delphi-jedi.net/wp-content/uploads/2008/03/bild-6-small.jpg" alt="Bild" height="100" width="450" /></a></p>
<p>The COM method and the dialog will run in the process space of the newly elevated dllhost.exe. And because there is no manifest information in this file you cannot get a themed dialog layout.</p>
<p><img src="http://blog.delphi-jedi.net/wp-content/uploads/2008/03/bild-7.jpg" alt="Bild" height="105" width="215" /></p>
<p>So how can you get a themed dialog anyhow?</p>
<p>The task is done by using the basic principles of COM. COM knowns Callback interfaces and other stuff. By using a Callback interface you can turn around the server &#8211; client principle.</p>
<ol>
<li>Define a well known interface that is implemented by the client only. But also known to the server.</li>
<li>Add a parameter to your elevated COM method that receives a pointer to this interface.</li>
<li>Before calling an elevated method, create the interface and</li>
<li>apply a pointer to the method&#8217;s parameter you added.</li>
<li>Call the method and use the methods in the given callback interface. COM will automatically transfer the method calls to your non-elevated process. In this way you can create themed windows, do window management stuff (progress bar) and eventually close the window.</li>
</ol>
<p>If you prefer to read code instead of text you should study this code excerpts.</p>
<p>Define a callback interface for your client and add it to the server&#8217;s TypeLib. Delphi will generate code for it automatically in a file called &lt;Name&gt;_TLB.pas (TLB Header). Do not create the interface by using the Delphi&#8217;s ActiveX expert. Just add it manually.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">type</span><br />
&nbsp; IMyCallback = <span class="kw1">interface</span><span class="br0">&#40;</span><span class="kw4">IUnknown</span><span class="br0">&#41;</span><br />
&nbsp; <span class="br0">&#91;</span>MYCALLBACK_GUID<span class="br0">&#93;</span><br />
&nbsp; &nbsp; <span class="kw1">procedure</span> ACallBackMethod<span class="br0">&#40;</span>DataFromServer : &#8230;<span class="br0">&#41;</span>; <span class="kw1">safecall</span>;<br />
&nbsp; <span class="kw1">end</span>;<br />
&nbsp;<span class="co1">//We do not need a CoClass</span></div>
<p><em>IMyCallback </em>interface is known to both the server and the client, because we use the TLB Header in the client and the server. The client will implement and the server will receive a pointer to it and then call the included method <em>ACallBackMethod</em> everytime it wishes to do so.</p>
<p>The server implements a method to allow a callback interface to be passed to it.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">type</span><br />
&nbsp; IServerInt = <span class="kw1">interface</span><span class="br0">&#40;</span>IDispatch<span class="br0">&#41;</span><br />
&nbsp; <span class="br0">&#91;</span>ISERVERINT_GUID<span class="br0">&#93;</span><br />
&nbsp; &nbsp; <span class="kw1">procedure</span> DoStuffThatNeedsCallBack<span class="br0">&#40;</span><span class="kw1">const</span> Callback: IMyCallback;&#8230;<span class="br0">&#41;</span> <span class="kw1">safecall</span>;<br />
&nbsp; <span class="kw1">end</span>;<br />
&nbsp; <span class="co1">//TypeLib editor also declares a CoClass called CoServerInt</span></div>
<p>Of course you have to implement both interfaces: <em>IServerInt</em> and <em>IMyCallback</em>. However <em>IServerInt </em>is implemented on server side and <em>IMyCallback </em>is only implemented on the client side.</p>
<p>On client side (namely your application) write..</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">uses</span> &#8230;, ComSrv,ComObj;<br />
<span class="kw1">type</span><br />
&nbsp; TMyCallback = <span class="kw1">class</span><span class="br0">&#40;</span>TComObject, IMyCallback<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">procedure</span> ACallBackMethod<span class="br0">&#40;</span>DataFromServer : &#8230;<span class="br0">&#41;</span>; <span class="kw1">safecall</span>;<br />
&nbsp; <span class="kw1">end</span>;</p>
<p>&#8230;</p></div>
<p>Install the COM object anywhere before you&#8217;re going to use it.</p>
<div class="dean_ch" style="white-space: wrap;"> &nbsp;TComObjectFactory.<span class="me1">Create</span><span class="br0">&#40;</span>ComServer,<br />
&nbsp; &nbsp; &nbsp;TMyCallback, Class_MyCallback,<br />
&nbsp; &nbsp; &nbsp;<span class="st0">&#8216;MyCallback&#8217;</span>, <span class="co1">//Classname</span><br />
&nbsp; &nbsp; &nbsp;<span class="st0">&#8216;Description here&#8217;</span>,<br />
&nbsp; &nbsp; &nbsp;ciMultiInstance<span class="br0">&#41;</span>;</div>
<p>After all implement the callback method&#8230;</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">procedure</span> TMyCallback.<span class="me1">ACallBackMethod</span><span class="br0">&#40;</span>DataFromServer : &#8230;<span class="br0">&#41;</span>;<br />
<span class="kw1">begin</span><br />
&nbsp; <span class="co1">//do stuff on the non-elevated client side</span><br />
<span class="kw1">end</span>;</div>
<p>&#8230;and anywhere you like, call the method to use our Callback interface.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">var</span> Server : IServerInt;<br />
&nbsp; &nbsp; Callback : IMyCallback;<br />
<span class="kw1">begin</span><br />
&nbsp; Server := CoServerInt.<span class="me1">Create</span>;<br />
&nbsp; Callback := TMyCallback.<span class="me1">Create</span> <span class="kw1">as</span> IMyCallback;</p>
<p>&nbsp; Server.<span class="me1">DoStuffThatNeedsCallBack</span><span class="br0">&#40;</span>Callback, &#8230;<span class="br0">&#41;</span>;<br />
<span class="kw1">end</span>;</div>
<p>I&#8217;m using TComObject and TComObjectFactory on the client side , because this way works for  console applications, too. If you need the possibilities of TAutoIntfObject, you will have to write a standalone COM server with TApplication. However this is not necessary here.  The method ACallBackMethod will be run in the client&#8217;s process space rather than the elevated helper process. You can check whether the callback method runs in the correct process (elevated or not?) with the following code.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">procedure</span> TMyCallback.<span class="me1">ACallBackMethod</span><span class="br0">&#40;</span>DataFromServer : &#8230;<span class="br0">&#41;</span>;<br />
<span class="kw1">var</span> Token : TJwSecurityToken;<br />
<span class="kw1">begin</span><br />
&nbsp; &nbsp;Token := TJwSecurityToken.<span class="me1">CreateTokenEffective</span><span class="br0">&#40;</span>TOKEN_QUERY <span class="kw1">or</span> TOKEN_READ<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="kw1">try</span><br />
&nbsp; &nbsp; &nbsp;<span class="kw1">if</span> Token.<span class="me1">RunElevation</span> = <span class="nu0">0</span> <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;ShowMessage<span class="br0">&#40;</span><span class="st0">&#8216;Process is NOT Elevated: &#8216;</span>+<span class="kw3">IntToStr</span><span class="br0">&#40;</span>GetCurrentProcessId<span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp;<span class="kw1">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;ShowMessage<span class="br0">&#40;</span><span class="st0">&#8216;Process is Elevated: &#8216;</span>+<span class="kw3">IntToStr</span><span class="br0">&#40;</span>GetCurrentProcessId<span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="kw1">finally</span><br />
&nbsp; &nbsp; &nbsp;Token.<span class="me1">Free</span>;<br />
&nbsp; &nbsp;<span class="kw1">end</span>;<br />
<span class="kw1">end</span>;</div>
<p><u>Second way, still on the client side:</u><br />
If you already have a form class, you can add the interface to it.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">type</span><br />
&nbsp; TForm1 = <span class="kw1">class</span><span class="br0">&#40;</span>TForm, IMyCallback<span class="br0">&#41;</span><br />
&nbsp; <span class="kw1">protected</span><br />
&nbsp; &nbsp; <span class="kw1">procedure</span> ACallBackMethod<span class="br0">&#40;</span>DataFromServer : &#8230;<span class="br0">&#41;</span>; <span class="kw1">safecall</span>;<br />
&nbsp; <span class="kw1">end</span>;</div>
<p>Instead of creating the COM object, you pass a self-pointer to the method parameter.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">procedure</span> TForm1.<span class="me1">OnButtonClick</span><span class="br0">&#40;</span>&#8230;<span class="br0">&#41;</span>;<br />
<span class="kw1">var</span> Server : IServerInt;<br />
&nbsp; &nbsp; Callback : IMyCallback;<br />
<span class="kw1">begin</span><br />
&nbsp; Server := CoServerInt.<span class="me1">Create</span>;</p>
<p>&nbsp; Server.<span class="me1">DoStuffThatNeedsCallBack</span><span class="br0">&#40;</span><span class="kw2">Self</span>, &#8230;<span class="br0">&#41;</span>;<br />
<span class="kw1">end</span>;</div>
<p>Be aware that in a multi thread environment, you have to make sure that resources in that specific form are accessed only by one thread at a time.</p>
<p>Eventually the server side calls the methods within the callback interface:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">uses</span> &#8230;, ComSrv,ComObj; </p>
<p><span class="kw1">type</span><br />
&nbsp; TServerIntImpl = <span class="kw1">class</span><span class="br0">&#40;</span>TAutoObject, IServerInt<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">procedure</span> DoStuffThatNeedsCallBack<span class="br0">&#40;</span><span class="kw1">const</span> Callback: IMyCallback;&#8230;<span class="br0">&#41;</span> <span class="kw1">safecall</span>;<br />
&nbsp; <span class="kw1">end</span>;</p>
<p>&#8230;<br />
<span class="kw1">procedure</span> TServerIntImpl.<span class="me1">DoStuffThatNeedsCallBack</span><span class="br0">&#40;</span><span class="kw1">const</span> Callback: IMyCallback;&#8230;<span class="br0">&#41;</span><br />
<span class="kw1">begin</span><br />
&nbsp; &#8230;<br />
&nbsp; <span class="me1">Callback</span>.<span class="me1">ACallBackMethod</span><span class="br0">&#40;</span>&#8230;<span class="br0">&#41;</span>;<br />
<span class="kw1">end</span>;</p>
<p>&#8230;<br />
<span class="kw1">initialization</span><br />
&nbsp; TAutoObjectFactory.<span class="me1">Create</span><span class="br0">&#40;</span>ComServer, TMyCallback,<br />
&nbsp; &nbsp; &nbsp;Class_MyCallback, ciMultiInstance<span class="br0">&#41;</span>;</div>
<p>The callback method will be called in the context of the client. So it will not be elevated. This is because there is no ordinary method call here. COM will pack the function stack and all its parameter into a stream, send it to the client, unpack it and restore a proper function stack to be executed. This happens in the client process of course.<br />
Get more information about COM callbacks <a href="http://www.informit.com/articles/article.aspx?p=130494&amp;seqNum=5" title="Go to external link.">here</a>.</p>
<hr size="2" width="100%" />Aside from the themed dialog problem you never should show window elements in such an elevated method. There is no need to it. All window elements can be displayed by using standard user rights. They do not need Administrator rights; otherwise we had to logon as Administrator.<br />
However you only should do stuff that needs Administrator privileges in these COM methods. The more code you add to the method the more likely a bug may lead to a security risk. So simply call your function that needs Administrator rights, get the results and go back to Standard user rights. There is really no need to display a window with Administrator privilege.<br />
<hr size="2" width="100%" /><strong>Tell me how you liked this blog entry by adding a comment.</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2008/03/14/why-arent-dialogs-themed-in-elevated-com-methods/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

