<?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; Registry</title>
	<atom:link href="http://blog.delphi-jedi.net/tag/registry/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>TRegistry.DeleteKey and 64bit</title>
		<link>http://blog.delphi-jedi.net/2010/08/17/tregistry-deletekey-and-64bit/</link>
		<comments>http://blog.delphi-jedi.net/2010/08/17/tregistry-deletekey-and-64bit/#comments</comments>
		<pubDate>Tue, 17 Aug 2010 12:51:19 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[Common]]></category>
		<category><![CDATA[64bit]]></category>
		<category><![CDATA[Registry]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=784</guid>
		<description><![CDATA[I got a bug from someone who told me that he had problems with the TRegistry method DeleteKey on his 64bit Windows. It just didn&#8217;t delete a 64bit key* from the registry although he used the KEY_WOW64_64KEY flag in desired access parameter of  TRegistry.Create. At first I thought that it was a problem with the [...]]]></description>
			<content:encoded><![CDATA[<p>I got a bug from someone who told me that he had problems with the TRegistry method <a href="http://docwiki.embarcadero.com/VCL/en/Registry.TRegistry.DeleteKey" target="_blank"><em>DeleteKey</em></a> on his 64bit Windows. It just didn&#8217;t delete a 64bit key* from the registry although he used the KEY_WOW64_64KEY flag in desired access parameter of  TRegistry.Create.</p>
<p><span id="more-784"></span></p>
<p>At first I thought that it was a problem with the OpenKey function of TRegistry. However, this was already confirmed and fixed as a bug in <a href="http://qc.embarcadero.com/wc/qcmain.aspx?d=23429" target="_blank">QC# 23429</a>.</p>
<p>Then I wanted to check the real error value of DeleteKey. Of course, it just returns true or false, so I added a call to GetLastError. And it returned 87 (Invalid Parameter). It must be said that using GetLastError in a framework like VCL is always a problem because you don&#8217;t really know how many winapi functions are called subsequent to the actual winapi function. So you may get an error value from another random function. This is one reason I&#8217;m using exceptions in JWSCL, btw.<br />
 A quick step through debugging session (you have to enable debug dcu in project options and rebuild the project) confirmed that the invalid parameter error (87) came from RegDeleteKey. But why 87? The next step was obvious because I had a windows function and thus I would have to read its <a href="http://msdn.microsoft.com/en-us/library/ms724845%28VS.85%29.aspx" target="_blank">MSDN documentation</a>.</p>
<p>It reads:</p>
<div>
<blockquote><p><cite><strong>RegDeleteKey </strong>Function<br />
 Deletes a subkey and its values. Note that key names are not case sensitive. <strong> </strong></cite></p>
<p><strong>64-bit Windows: </strong>On WOW64, 32-bit  applications view a registry tree that is separate from the registry  tree that 64-bit applications view. To enable an application to delete  an entry in the alternate registry view, use the <a id="ctl00_MTCS_main_ctl01" onclick="javascript:Track('ctl00_MTCS_main_ctl00|ctl00_MTCS_main_ctl01',this);" href="http://msdn.microsoft.com/en-us/library/ms724847%28VS.85%29.aspx"><strong>RegDeleteKeyEx</strong></a> function.</p>
</blockquote>
<p><br class="spacer_" /></p>
<p>So the RegDeleteKey<strong>Ex</strong> function must be used. But don&#8217;t stop reading here and implement it. We can&#8217;t just use this function because MSDN states that this function is only available in XP 64bit or Vista (32 and 64bit). So this gets more complicated and I suggest this way :</p>
<table border="1">
<tbody>
<tr>
<td></td>
<td>XP 32bit</td>
<td>XP 64bit</td>
<td>Vista and newer (32+64)</td>
</tr>
<tr style="text-align: center;">
<td style="text-align: left;">RegDeleteKey</td>
<td>√</td>
<td>only 32bit keys</td>
<td>only 32bit keys</td>
</tr>
<tr>
<td>RegDeleteKeyEx</td>
<td>unsupported</td>
<td style="text-align: center;">√</td>
<td style="text-align: center;">√</td>
</tr>
</tbody>
</table>
<p>√ &#8211; will run fine as it is intended.</p>
<ul>
<li>On a 64bit Windows, always call RegDeleteKeyEx. It supports both 32bit and 64bit registry keys.</li>
<li>Otherwise, if you don&#8217;t want to delete 64bit keys:
<ul>
<li>Call RegDeleteKeyEx on Vista or newer, though.</li>
<li>Call RegDeleteKey on XP 32bit. </li>
</ul>
</li>
</ul>
<p>As a conclusion, you cannot use the TRegistry method DeleteKey with 64bit registry keys. Either you have to use your own RegDeleteKeyEx call or just use a derived class of TRegistry. Of course this is only necessary it you want to access 64bit keys&#8230;this article is FYI.</p>
<p>In the end, the question arises to me why RegDeleteKey does not support 64bit registry keys. I couldn&#8217;t find any evidences, so I can only use my brain to think of one:<br />
 Well, the RegDeleteKey function can be really dangerous if a 32bit application, that is not aware of 64bit, erases 64bit keys. This is especially true for &#8220;HKEY_LOCAL_MACHINE\SOFTWARE&#8221; because you may have installed two versions of an application with same name. First you installed a 32bit only application (name it X) you bought several years ago for your 32bit Windows. One day the vendor sends you a 64bit only update that you install (*so happy*). You decide to abandon the 32bit version and call its custom made uninstaller which deletes all of its known keys. Of course, it will also delete the 64bit version. This may be fictional but possible without the breakup of 32bit and 64bit keys in heavily used parts of the registry. So RegDeleteKey will not delete the 64bit keys because that would break 64bit applications. It seems to me that Microsoft experienced it already, before they decided to add 32-64bit registry separation.  Maybe Raymond Chen would say something like this: <em>Believe us, we tried the other way around:  it&#8217;s worse</em>.</p>
<p><br class="spacer_" /></p>
<p>If you are interested in more information, I suggest you to read <a href="http://msdn.microsoft.com/en-us/library/aa384129%28VS.85%29.aspx" target="_blank">Accessing an Alternate Registry View</a>.</p>
<p>* The key was a subkey from &#8220;HKEY_LOCAL_MACHINE\SOFTWARE&#8221;. In 64bit Windows, a 32bit application (not aware of 64bit) will only see the contents of &#8220;HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node&#8221;.</p>
<h3>Update</h3>
<p>I submitted a bug report to QC: <a href="http://qc.embarcadero.com/wc/qcmain.aspx?d=87323" target="_blank">#87323</a></p>
<h3>Links</h3>
<ul>
<li><a href="http://www.delphipraxis.net/127364-registry-deletekey-problem-unter-xp64.html" target="_blank">DelphiPraxis</a></li>
</ul>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2010/08/17/tregistry-deletekey-and-64bit/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>The Case of The Failed Loading of The User Profile</title>
		<link>http://blog.delphi-jedi.net/2009/07/20/the-case-of-the-failed-loading-of-the-user-profile/</link>
		<comments>http://blog.delphi-jedi.net/2009/07/20/the-case-of-the-failed-loading-of-the-user-profile/#comments</comments>
		<pubDate>Mon, 20 Jul 2009 20:52:45 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[Common]]></category>
		<category><![CDATA[JEDI Windows Security Code Lib]]></category>
		<category><![CDATA[Administrator]]></category>
		<category><![CDATA[JWSCL]]></category>
		<category><![CDATA[profile]]></category>
		<category><![CDATA[Registry]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=370</guid>
		<description><![CDATA[Some time ago, I was in the situation to set up a new computer with a Windows XP 64 CD. Well it doesn&#8217;t matter that it was 64bit.  However, I always create a separate partitions for Windows XP. And because user profiles tend to get big, I moved a new user to a second partition. [...]]]></description>
			<content:encoded><![CDATA[<p>Some time ago, I was in the situation to set up a new computer with a Windows XP 64 CD. Well it doesn&#8217;t matter that it was 64bit.  However, I always create a separate partitions for Windows XP. And because user profiles tend to get big, I moved a new user to a second partition. (See the Internet how it is done) But as if it wasn&#8217;t enough I thought that I also could move the Administrator profile that easy. Way wrong!</p>
<p><span id="more-370"></span>First of all, copying a loaded user profile isn&#8217;t possible without the BACKUP privilege. You can&#8217;t open already opened files a second time (share deny). The solution is: Either you can use a backup application that runs with the special privilege or you can just use another administrative user (which I did).</p>
<p>There are some keys which have absolute path variables that must be changed, too. But that is a minor problem. The big problem was that Windows could not load the profile of the Administrator. Windows tried to start up the users desktop but then failed with the dialog:  &#8220;Windows failed to load user profile.&#8221;</p>
<p>It got more confusing because every other user in the system didn&#8217;t suffer from this problem. And to top it,  sometimes I could successfully login to the Administrator account.</p>
<h3>Solution</h3>
<p>In such cases the event manager is a good way to find the error source. In my case, it told me that &#8220;NTUSER.DAT&#8221; (this is where Windows stores the current user keys called a <a href="http://msdn.microsoft.com/en-us/library/ms724877%28VS.85%29.aspx">registry hive</a>) was already opened by another process. I really can&#8217;t say why this was the case because it shouldn&#8217;t be the case shortly after a fresh boot up. (Of course, the file was correct, it had no write protection, and security was set accordingly)</p>
<p>In such a case you usually have some ways to fix the problem:</p>
<p>1. Reinstall Windows<br />
Good choice. But too much work &#8212; and who will promise me that it won&#8217;t happen again?</p>
<p>2. Leave Administrator where it was<br />
Also good choice. And I tried it. However my Windows could not handle two profile places somehow and the very same error occured with the old profile location.</p>
<p>3. Live with the situation<br />
Some people do it. I thought about it, too, I have to admit. That&#8217;s because there is a user called root in the system now.</p>
<p>4. Find the bug and ignore how much time it will cost.<br />
Ouch. I don&#8217;t have time, so not a good option.</p>
<p>5.Create a workaround.<br />
YES! That&#8217;s what I did.</p>
<p>So I came up with a practical and fast solution. As I&#8217;ve already written, the user&#8217;s registry hive could not be loaded.<br />
Why? I don&#8217;t know much about it but the registry file was blocked.<br />
Well, I&#8217;ve found out that if the Administrator registry hive was already loaded (HKEY_USERS\S-1-5-21-xxx-500 is visible) the Windows could successfully logon the Administrator. I simulated this situation by manually loading the user&#8217;s profile using the <a href="http://msdn.microsoft.com/en-us/library/bb762281%28VS.85%29.aspx" target="_blank">LoadUserProfile</a> function from Windows API. Well, it always worked!</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">uses</span><br />
&nbsp; JwaWindows,<br />
&nbsp; JwsclToken,<br />
&nbsp; jwscltypes;</p>
<p><span class="kw1">var</span><br />
&nbsp; &nbsp;T : TJwSecurityToken;<br />
&nbsp; &nbsp;ProfileInfo : TJwProfileInfo;<br />
<span class="kw1">begin</span><br />
&nbsp; T := TJwSecurityToken.<span class="me1">CreateTokenByProcess</span><span class="br0">&#40;</span><span class="nu0">0</span>, TOKEN_ALL_ACCESS<span class="br0">&#41;</span>;<br />
&nbsp; <span class="kw1">try</span><br />
&nbsp; &nbsp; T.<span class="me1">LoadUserProfile</span><span class="br0">&#40;</span>ProfileInfo, <span class="br0">&#91;</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;<br />
&nbsp; <span class="kw1">finally</span><br />
&nbsp; &nbsp; T.<span class="me1">Free</span>;<br />
&nbsp; <span class="kw1">end</span>;</div>
<p>The next step was to do it automatically before an Administrator could logon. Of course, I could have created a service which loads the user profile at startup but I wanted to be fast so there is another option called Task Scheduler.<br />
Every Windows startup I let run the code above as a simple task with Administrator credentials (needs password).</p>
<p>I don&#8217;t know whether the Task Scheduler loads the profile (I would guess so). However the problem is that the profile could be unloaded after the process has ended. So the hive would be removed and logon would no more be possible.</p>
<p>Thus the code above just loads the profile but does not unload it. Since profiles are not watched by Windows (at least in XP) the registry hive  stays loaded and a logon attempt will work (T.Free won&#8217;t unload it!).</p>
<h3>JEDI Windows Security Code Library used features</h3>
<ul>
<li><a href="http://jwscldoc.delphi-jedi.net/TJwSecurityToken.html">TJwSecurityToken</a> (class)<a href="http://jwscldoc.delphi-jedi.net/TJwSecurityToken.html"><br />
</a></li>
<li>TJwSecurityToken.<a href="http://jwscldoc.delphi-jedi.net/TJwSecurityToken_LoadUserProfile@TJwProfileInfo@TJwProfileMembers.html" target="_blank">LoadUserProfile</a> (method)</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2009/07/20/the-case-of-the-failed-loading-of-the-user-profile/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Using Windows Contacts</title>
		<link>http://blog.delphi-jedi.net/2008/04/08/using-windows-contacts/</link>
		<comments>http://blog.delphi-jedi.net/2008/04/08/using-windows-contacts/#comments</comments>
		<pubDate>Tue, 08 Apr 2008 22:17:13 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[JEDI Windows API Headers]]></category>
		<category><![CDATA[COM]]></category>
		<category><![CDATA[JWA]]></category>
		<category><![CDATA[Registry]]></category>
		<category><![CDATA[WAB]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=103</guid>
		<description><![CDATA[Since Windows Vista, a new API called Windows Contacts (WC) was born. It replaces the Windows Address BookAPI. You can get your personal properties by using the Windows Address Book Editor. It can be opened using &#8220;wab&#8221; in command line. At first you see your personal &#8220;Contacts&#8221; folder. This folder contains your personal contact file. [...]]]></description>
			<content:encoded><![CDATA[<p>Since Windows Vista, a new API called <a href="http://msdn2.microsoft.com/en-us/library/ms735779%28VS.85%29.aspx">Windows Contacts</a> (WC) was born. It replaces the <a href="http://msdn2.microsoft.com/en-us/library/ms629361(VS.85).aspx">Windows Address Book</a>API.</p>
<p>You can get your personal properties by using the Windows Address Book Editor. It can be opened using &#8220;wab&#8221; in command line.<span id="more-103"></span></p>
<p><a href="http://blog.delphi-jedi.net/wp-content/uploads/2008/03/bild-21.jpg"><img src="http://blog.delphi-jedi.net/wp-content/uploads/2008/03/bild-21-small.jpg" alt="Bild" width="450" height="336" /></a></p>
<p>At first you see your personal &#8220;Contacts&#8221; folder. This folder contains your personal contact file. Its extension is &#8220;.contact&#8221;. A double click on it opens the Address editor as seen below:</p>
<p><a href="http://blog.delphi-jedi.net/wp-content/uploads/2008/03/bild-20.jpg"><img src="http://blog.delphi-jedi.net/wp-content/uploads/2008/03/bild-20-small.jpg" alt="Bild" width="450" height="366" /></a></p>
<p>&#8220;Web.exe&#8221; can also receive any personal contact file to import it to your personal contacts.</p>
<p>The contact file contains a formatted text in xml syntax. Data is arranged in a tree that is used to retrieve values. When I am writing of a path, I iterate through the tree. Some of the elements contains a collection of the same element type. The reason comes from the fact, that several other contacts can be added to the personal contact. The WC API uses the array brackets to access different contact values.</p>
<p>The following sample path shows you how to obtain the first user&#8217;s name.(Notice that the array starts with one not zero.)</p>
<blockquote><p>NameCollection/Name[1]/GivenName</p></blockquote>
<p>XML (manually formatted):</p>
<div class="dean_ch" style="white-space: wrap;"><span class="sc3"><span class="re1">&lt;c:NameCollection<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;c:Name</span> <span class="re0">c:ElementID</span>=<span class="st0">&quot;cf809c84-6692-404e-9f57-6f81e130ee11&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;c:GivenName</span> <span class="re0">c:Version</span>=<span class="st0">&quot;1&quot;</span> <span class="re0">c:ModificationDate</span>=<span class="st0">&quot;2008-03-27T20:29:18Z&quot;</span><span class="re2">&gt;</span></span>TestUser<span class="sc3"><span class="re1">&lt;/c:GivenName<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;c:FormattedName<span class="re2">&gt;</span></span></span>TestUser<span class="sc3"><span class="re1">&lt;/c:FormattedName<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/c:Name<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/c:NameCollection<span class="re2">&gt;</span></span></span></div>
<p>This parts can be cut into three parts:</p>
<ol>
<li>NameCollection defines a container for the array</li>
<li>/Name defines an array which contains all contacts</li>
<li>GivenName defines a name property of exact one contact.</li>
</ol>
<p>There are also Value tags:</p>
<blockquote><p>ContactIDCollection/ContactID[1]/Value</p></blockquote>
<p>XML (manually formatted):</p>
<div class="dean_ch" style="white-space: wrap;"><span class="sc3"><span class="re1">&lt;c:ContactIDCollection<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;c:ContactID</span> <span class="re0">c:ElementID</span>=<span class="st0">&quot;aa8014fe-423c-4e8e-ad9f-4d750a6ba8bb&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;c:Value<span class="re2">&gt;</span></span></span>5634564e-72356-339-8220-12342f4a4106<span class="sc3"><span class="re1">&lt;/c:Value<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/c:ContactID<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/c:ContactIDCollection<span class="re2">&gt;</span></span></span></div>
<p>This path returns the GUID of contact number one.</p>
<p>Many parts of a path are already defined as constants. Have a look at them in <a href="http://msdn2.microsoft.com/en-us/library/ms735869(VS.85).aspx">MSDN</a>.</p>
<p>So how can we read from the personal contact file? Since new API uses COM, we will use the following interfaces</p>
<ul>
<li>IContact</li>
<li>IContactCollection</li>
<li>IContactManager</li>
<li>IContactProperties</li>
<li>IContactPropertyCollection</li>
</ul>
<p>Actually there is no implementation of these interfaces for Delphi. To create your own type library (TLB) do the following steps (in Vista of course):</p>
<ol>
<li>Get Visual Studio 200x</li>
<li>Download and install the latest version <a href="http://www.microsoft.com/downloads/details.aspx?familyid=ff6467e6-5bba-4bf5-b562-9199be864d29&amp;displaylang=en">Windows SDK</a> for Vista for MIDL and IContact.IDL.</li>
<li>Open the Visual Studio Command Prompt (in VS open menu Tools). We need the predefined include path settings.</li>
<li>Add path of midl.exe from the Windows SDK to your path environment. Use this command:
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">set</span> path=%path%;&lt;your path here&gt;\Microsoft SDKs\Windows\v6<span class="nu0">.0</span>\Bin</div>
</li>
<li>Change folder to ;&lt;your path here&gt;\Microsoft SDKs\Windows\v6.0\Include</li>
<li>Backup and open IContact.idl in your favorite text editor.<br />
Find these lines&#8230;</p>
<div class="dean_ch" style="white-space: wrap;">interface IContactPropertyCollection;<br />
interface IContactCollection;</div>
<p>&#8230;and add :</p>
<div class="dean_ch" style="white-space: wrap;">interface IContactProperties;<br />
interface IContactPropertyCollection;</div>
<p>Additionally find this method&#8230;</p>
<div class="dean_ch" style="white-space: wrap;">HRESULT CommitChanges<span class="br0">&#40;</span><span class="br0">&#91;</span>in<span class="br0">&#93;</span> DWORD dwCommitFlags<span class="br0">&#41;</span>;</div>
<p>&#8230;and also add :</p>
<div class="dean_ch" style="white-space: wrap;">HRESULT _DO_NOT_USE1<span class="br0">&#40;</span><span class="br0">&#91;</span>in<span class="br0">&#93;</span> IContactProperties* pC<span class="br0">&#41;</span>;<br />
HRESULT _DO_NOT_USE2<span class="br0">&#40;</span><span class="br0">&#91;</span>in<span class="br0">&#93;</span> IContactPropertyCollection* pC<span class="br0">&#41;</span>;</div>
<p>In this way <em>midl.exe</em> will also create interfaces in the typelibrary for <em>IContactProperties</em> and <em>IContactPropertyCollection</em>.<br />
I could not figure out how to do it in another way. Comments are apreciated.</li>
<li>You should also find all appearances of&#8230;
<div class="dean_ch" style="white-space: wrap;">procedure Next; safecall;</div>
<p>&#8230;and replace them by:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw2">function</span> Next : HRESULT; stdcall;</div>
<p>It is necessary because we need to check for a positive return value (S_FALSE). Delphi does not raise an EOleSysError exception for positive values.</li>
<li>Save your work and start the conversion:<br />
<strong> midl icontact.idl /tlb icontact.tlb</strong></li>
<li>The new tlb file can now be imported using Delphi. To do so, start Delphi as Administrator, open menu &#8220;Components&#8221; and select &#8220;Install components&#8221; and hit the next button until all the components are listed. Click button &#8220;add&#8221; and choose the newly created <em>IContact.tlb</em>. Delphi imports the library and also generates the Delphi type library source code.</li>
</ol>
<p>Did you know?</p>
<blockquote><p>You can also (un)register a TLB file using regtlib.exe from C:\Windows\System32\URTTEMP<br />
Type &#8220;regtlib Icontact.tlb&#8221; to register the library and &#8220;regtlib /u IContact.tlb&#8221; to unregister it.</p></blockquote>
<p><strong>You can find an already generated type library and and Delphi source code at the end of this article.</strong></p>
<p>Using the Windows Contact API is really easy as soon as the Delphi type library unit exists. It implements class factories for IContact and IContactManager. Use the IContact class factory if you want to add your own contacts to the user&#8217;s personal database. If you just want to read data you have to use IContactManager.<br />
Retrieving the current user&#8217;s profile is simple:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">var</span><br />
&nbsp; ContactManager : IContactManager;<br />
&nbsp; Contact : IContact;<br />
<span class="kw1">begin</span><br />
&nbsp; CoInitialize<span class="br0">&#40;</span><span class="kw2">nil</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; ContactManager := CoContactManager.<span class="me1">Create</span>;<br />
&nbsp; ContactManager.<span class="kw3">Initialize</span><span class="br0">&#40;</span><span class="st0">&#8216;Your AppName&#8217;</span>,<span class="st0">&#8216;AppVersion&#8217;</span><span class="br0">&#41;</span>;</div>
<p>These lines creates an empty contact manager. Notice that the method Initialize is necessary for further calls.<br />
Now we have to actually open the current user&#8217;s contact database.</p>
<div class="dean_ch" style="white-space: wrap;">ContactManager.<span class="me1">GetMeContact</span><span class="br0">&#40;</span>Contact<span class="br0">&#41;</span>;</div>
<p>The new interface Contact contains all the user&#8217;s personal data. We can obtain it through a path value as shown in the beginning of this article.<br />
Let us obtain the user&#8217;s name. This task is done by retrieving the property interface IContactProperties using the Contact instance.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">var</span><br />
&nbsp; ContactProp : IContactProperties;<br />
&nbsp; Path,<br />
&nbsp; Name : <span class="kw4">WideString</span>;<br />
&nbsp; wName : <span class="kw4">PWideChar</span>;<br />
&nbsp; Size : <span class="kw4">Cardinal</span>;<br />
<span class="kw1">begin</span><br />
&nbsp; OleCheck<span class="br0">&#40;</span>Contact.<span class="me1">QueryInterface</span><span class="br0">&#40;</span>IID_IContactProperties, ContactProp<span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
<p>The new instance ContactProp allows us to access a property through a path.</p>
<div class="dean_ch" style="white-space: wrap;"> &nbsp;&#8230;<br />
&nbsp; <span class="me1">Path</span> := <span class="st0">&#8216;NameCollection/Name[1]/GivenName&#8217;</span>;<br />
&nbsp; Size := <span class="nu0">0</span>;</p>
<p>&nbsp; <span class="kw1">try</span><br />
&nbsp; &nbsp; ContactProp.<span class="me1">GetString</span><span class="br0">&#40;</span><span class="kw4">PWideChar</span><span class="br0">&#40;</span>Path<span class="br0">&#41;</span>, <span class="nu0">0</span>, <span class="kw2">nil</span>, <span class="nu0">0</span>, Size<span class="br0">&#41;</span>;<br />
&nbsp; <span class="kw1">except</span><br />
&nbsp; &nbsp; <span class="kw3">GetMem</span><span class="br0">&#40;</span>Name, Size*<span class="kw3">sizeof</span><span class="br0">&#40;</span><span class="kw4">WideChar</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; ContactProp.<span class="me1">GetString</span><span class="br0">&#40;</span><span class="kw4">PWideChar</span><span class="br0">&#40;</span>Path<span class="br0">&#41;</span>, <span class="nu0">0</span>, wName, Size, Size<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; Name := <span class="kw4">WideString</span><span class="br0">&#40;</span>wName<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="kw3">FreeMem</span><span class="br0">&#40;</span>wName<span class="br0">&#41;</span>;<br />
&nbsp; <span class="kw1">end</span>;</div>
<p>The variable <strong>Name</strong> will contain the user&#8217;s name.  In this way we make sure that the right amount of memory is allocated. Notice that the <strong>GetString</strong> actually returns the count of chars and not the count of bytes, so we have to double the size. We always get an exception in <strong>GetString </strong> because Delphi wraps (safecall convetion) the method and automatically raises an exception if the function returns a negative value (E_XXX code). We don&#8217;t distinguish between a memory error which we need to check for the correct size and a real error. So let us implement it in the right way:</p>
<div class="dean_ch" style="white-space: wrap;"> &nbsp;&#8230;<br />
&nbsp; <span class="kw1">try</span><br />
&nbsp; &nbsp; ContactProp.<span class="me1">GetString</span><span class="br0">&#40;</span><span class="kw4">PWideChar</span><span class="br0">&#40;</span>Path<span class="br0">&#41;</span>, <span class="nu0">0</span>, <span class="kw2">nil</span>, <span class="nu0">0</span>, Size<span class="br0">&#41;</span>;<br />
&nbsp; <span class="kw1">except</span><br />
&nbsp; &nbsp; <span class="kw1">on</span> E : EOleSysError <span class="kw1">do</span><br />
&nbsp; &nbsp; <span class="kw1">begin</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>ResultCode<span class="br0">&#40;</span>E.<span class="me1">ErrorCode</span><span class="br0">&#41;</span> &lt;&gt; ERROR_INSUFFICIENT_BUFFER<span class="br0">&#41;</span> <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">raise</span>;<br />
&nbsp; &nbsp; &nbsp; &#8230;.<br />
&nbsp; &nbsp; <span class="kw1">end</span>;<br />
&nbsp; <span class="kw1">end</span>;</div>
<p>In this way all &#8220;real&#8221; errors are catched and reraised.</p>
<p>All the other properties can be obtained in similar ways. However what properties are available at all? The interface IContactPropertyCollection allows us to obtain all available property names and types. IContactProperties implements a method GetPropertyCollection which returns a pointer to a IContactPropertyCollection that contains the requested properties. It is also possible to filter some of them.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">function</span> GetCollection<span class="br0">&#40;</span><span class="kw1">const</span> ContactProp: IContactProperties<span class="br0">&#41;</span> &#8230;<br />
<span class="kw1">var</span><br />
&nbsp; Dummy : <span class="kw4">PWideChar</span>;<br />
&nbsp; Props : IContactPropertyCollection;<br />
&nbsp; H : HRESULT;</p>
<p><span class="kw1">begin</span><br />
&nbsp; Dummy := <span class="kw2">nil</span>;</p>
<p>&nbsp; ContactProp.<span class="me1">GetPropertyCollection</span><span class="br0">&#40;</span>Props, <span class="nu0">0</span>, <span class="kw2">nil</span>, <span class="nu0">0</span>, Dummy, <span class="kw4">Integer</span><span class="br0">&#40;</span><span class="kw2">true</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
<p>The new property collection contains an enumeration method to iterating all available properties. Be aware that you must call Next before you start getting data.</p>
<div class="dean_ch" style="white-space: wrap;">Dummy<br />
ContactProp.<span class="me1">GetPropertyCollection</span><span class="br0">&#40;</span>Props, <span class="nu0">0</span>, <span class="kw2">nil</span>, <span class="nu0">0</span>, Dummy, <span class="kw4">Integer</span><span class="br0">&#40;</span><span class="kw2">true</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
H := Props.<span class="me1">Next</span>;</p>
<p><span class="kw1">while</span> H &lt;&gt; S_FALSE <span class="kw1">do</span><br />
<span class="kw1">begin</span><br />
&nbsp; &#8230;<br />
&nbsp; <span class="me1">H</span> := Props.<span class="me1">Next</span>;<br />
<span class="kw1">end</span>;</div>
<p>In this way we can obtain name, type , version, modification time and ID of a property.  Just use the available methods of IContactPropertyCollection.</p>
<ul>
<li>GetPropertyName</li>
<li>GetPropertyType</li>
<li>GetPropertyVersion</li>
<li>GetPropertyModificationDate</li>
<li>GetPropertyArrayElementID</li>
</ul>
<p>We already coded how to get a string using COM methods. So this code isn&#8217;t new to you. It retrieves the name of the property.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">var</span><br />
&nbsp; PW : <span class="kw4">PWideChar</span>;<br />
&nbsp; Name : <span class="kw4">WideString</span>;<br />
&nbsp; Size : <span class="kw4">Cardinal</span>;<br />
<span class="kw1">begin</span><br />
&nbsp; Size := <span class="nu0">0</span>;<br />
&nbsp; <span class="kw1">try</span><br />
&nbsp; &nbsp; Props.<span class="me1">GetPropertyName</span><span class="br0">&#40;</span><span class="kw2">nil</span>,<span class="nu0">0</span>, Size<span class="br0">&#41;</span>;<br />
&nbsp; <span class="kw1">except</span><br />
&nbsp; &nbsp; <span class="kw1">on</span> E : EOleSysError <span class="kw1">do</span><br />
&nbsp; &nbsp; <span class="kw1">begin</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>ResultCode<span class="br0">&#40;</span>E.<span class="me1">ErrorCode</span><span class="br0">&#41;</span> &lt;&gt; ERROR_INSUFFICIENT_BUFFER<span class="br0">&#41;</span> <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">raise</span>;</p>
<p>&nbsp; &nbsp; &nbsp; <span class="kw3">GetMem</span><span class="br0">&#40;</span>PW, <span class="br0">&#40;</span>Size<span class="nu0">+1</span><span class="br0">&#41;</span>*<span class="kw3">sizeof</span><span class="br0">&#40;</span><span class="kw4">WideChar</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; Props.<span class="me1">GetPropertyName</span><span class="br0">&#40;</span>PW, Size, Size<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; Name := <span class="kw4">WideString</span><span class="br0">&#40;</span>PW<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="kw1">end</span>;<br />
&nbsp; <span class="kw1">end</span>;<br />
<span class="kw1">end</span>;</div>
<p>To make life easier I created a unit that implements the shown code. You can download ContactMisc.pas in the download section of this article. The unit implements the following functions:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">const</span><br />
&nbsp; CGD_DEFAULT = <span class="re0">$<span class="nu0">00000000</span></span>;</p>
<p>&nbsp; CGD_UNKNOWN_PROPERTY = <span class="re0">$<span class="nu0">00000000</span></span>;<br />
&nbsp; CGD_STRING_PROPERTY = <span class="re0">$<span class="nu0">00000001</span></span>;<br />
&nbsp; CGD_DATE_PROPERTY = <span class="re0">$<span class="nu0">00000002</span></span>;<br />
&nbsp; CGD_BINARY_PROPERTY = <span class="re0">$<span class="nu0">00000004</span></span>;<br />
&nbsp; CGD_ARRAY_NODE = <span class="re0">$<span class="nu0">00000008</span></span>;</p>
<p><span class="kw1">type</span> TWideStringArray = <span class="kw1">array</span> <span class="kw1">of</span> <span class="kw4">WideString</span>;</p>
<p><span class="coMULTI">{@Name contains contact information}</span><br />
TContactProperty = <span class="kw1">record</span><br />
&nbsp; <span class="co1">//ID contains the contact&#8217;s guid as a string</span><br />
&nbsp; ID,<br />
&nbsp; <span class="co1">//Name contains the contanct&#8217;s name</span><br />
&nbsp; Name : <span class="kw4">WideString</span>;<br />
&nbsp; <span class="co1">//Type contains contact type</span><br />
&nbsp; Typ,<br />
&nbsp; Version : <span class="kw4">Cardinal</span>;<br />
&nbsp; <span class="kw3">Time</span> : TFileTime;<br />
<span class="kw1">end</span>;</p>
<p>TContactPropertyArray = <span class="kw1">array</span> <span class="kw1">of</span> TContactProperty;</p>
<p><span class="coMULTI">{@Name returns a contact value in binary form.<br />
@param(Contact defines an interface to a contact which is used to retrieve data)<br />
@param(Path defines a path to the value to be retrieved.<br />
Most calls to @Name needs the string &quot;/Value&quot; at the end for success.<br />
For more about possible path values visit:<br />
http://msdn2.microsoft.com/en-us/library/ms735869(VS.85).aspx<br />
)<br />
@param(Mime returns the mime type of binary data)<br />
@return(Returns a memory stream containing the data)<br />
@raises(EPathNotFound will be raised if parameter Path could not be found.)<br />
}</span><br />
<span class="kw1">function</span> GetContactBinaryValue<span class="br0">&#40;</span><span class="kw1">const</span> Contact : IContact;const Path : <span class="kw4">WideString</span>;<br />
out Mime : <span class="kw4">WideString</span><span class="br0">&#41;</span> : TMemoryStream;</p>
<p><span class="coMULTI">{@Name returns an array of available contact properties.<br />
@param(Contact defines an interface to a contact which is used to retrieve data)<br />
}</span><br />
<span class="kw1">function</span> GetUserContactProperties<span class="br0">&#40;</span><span class="kw1">const</span> Contact : IContact<span class="br0">&#41;</span> : TContactPropertyArray;</p>
<p><span class="coMULTI">{@Name returns all available contacts from a contact manager.<br />
@param(Manager defines an interface to a contact manager interface)<br />
@return(Returns a list of IContact interfaces)<br />
}</span><br />
<span class="kw1">function</span> GetContactList<span class="br0">&#40;</span><span class="kw1">const</span> Manager : IContactManager<span class="br0">&#41;</span> : TInterfaceList;</p>
<p><span class="coMULTI">{@Name returns the value of a contact&#8217;s property<br />
@param(Path defines a path to the value to be retrieved.<br />
Most calls to @Name needs the string &quot;/Value&quot; at the end for success.<br />
For more about possible path values visit:<br />
http://msdn2.microsoft.com/en-us/library/ms735869(VS.85).aspx<br />
)<br />
@param(Contact defines an interface to a contact which is used to retrieve data.)<br />
@raises(EPathNotFound will be raised if parameter Path could not be found.)<br />
}</span><br />
<span class="kw1">function</span> GetContactValue<span class="br0">&#40;</span><span class="kw1">const</span> Contact : IContact;const Path : <span class="kw4">WideString</span><span class="br0">&#41;</span> : <span class="kw4">WideString</span>;</div>
<p>Some hints in the end</p>
<ul>
<li> The Windows Contacts API does not allow to open foreign contact profiles. Although IContactManager implements the method Load, it is useless.  Every contact file may contain several contacts. However only one contact belongs to the user. The method Loads expects a contact file name and the user&#8217;s ID (GUID) .    <strong>/GUID:&#8221;xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx&#8221; /PATH:&#8221;&#8230;&#8230;..\xy.contact&#8221;</strong><br />
You cannot retrieve the GUID of a foreign user with the WC API. To do so, you had to parse the contact file manually.</li>
<li>So how does
<div class="dean_ch" style="white-space: wrap;">ContactManager.<span class="me1">GetMeContact</span><span class="br0">&#40;</span>Contact<span class="br0">&#41;</span>;</div>
<p>retrieve the user&#8217;s ID?<br />
The ID is stored in the registry. Look at &#8230;<br />
<strong> HKEY_CURRENT_USER\Software\Microsoft\WAB\Me</strong><br />
&#8230;and you&#8217;ll find the a string that is necessary for the <strong>Load </strong>method of  <em>IContactManager</em>.</li>
<li>The WC API is sensible to the current token. A service may use an impersonated thread to get a foreign user contact.</li>
</ul>
<p>Download:</p>
<p>Download the package <a title="Demonstration of Windows Contacts API and headers" href="http://blog.delphi-jedi.net/wp-content/uploads/2008/03/windowscontacts.zip">here</a>. It contains:</p>
<ul>
<li>IContact.tlb &#8211; type library</li>
<li>Contact_tlb.pas &#8211; delphi type library header</li>
<li>ContactMisc.pas &#8211; IContact tools</li>
<li>Contacts.dpr &#8211; small demonstration</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2008/04/08/using-windows-contacts/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

