<?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; Common</title>
	<atom:link href="http://blog.delphi-jedi.net/category/common/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>Say NO to Secure Boot for Windows Only</title>
		<link>http://blog.delphi-jedi.net/2011/10/19/say-no-to-secure-boot-for-windows-only/</link>
		<comments>http://blog.delphi-jedi.net/2011/10/19/say-no-to-secure-boot-for-windows-only/#comments</comments>
		<pubDate>Wed, 19 Oct 2011 18:52:10 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[Common]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=978</guid>
		<description><![CDATA[The next generations of computers implement a mechanism called &#8220;Secure Boot&#8221; to disallow malicious applications to boot themselves. However, it seems that Microsoft may use this mechanism and its market power to disable dual boot of Windows 8 with other free operating systems. More than 6000 people signed already, including me. Please sign and spread [...]]]></description>
			<content:encoded><![CDATA[<p>The next generations of computers implement a mechanism called &#8220;Secure Boot&#8221; to disallow malicious applications to boot themselves. However, it seems that Microsoft may use this mechanism and its market power to disable dual boot of Windows 8 with other free operating systems.</p>
<p>More than 6000 people signed already, including me. Please sign and spread the word :</p>
<p>Read more about the issue and how to sign here:</p>
<p><a href="http://www.fsf.org/campaigns/secure-boot-vs-restricted-boot/statement">http://www.fsf.org/campaigns/secure-boot-vs-restricted-boot/statement</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2011/10/19/say-no-to-secure-boot-for-windows-only/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>If You Don&#8217;t See It</title>
		<link>http://blog.delphi-jedi.net/2010/12/01/if-you-dont-see-it/</link>
		<comments>http://blog.delphi-jedi.net/2010/12/01/if-you-dont-see-it/#comments</comments>
		<pubDate>Wed, 01 Dec 2010 20:22:08 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[Common]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=922</guid>
		<description><![CDATA[If you don&#8217;t see it. The blog has a full size layout now. To use it, click the link Large on the top-right corner of the blog. Thanks Storm!. I had a wow effect, do you?]]></description>
			<content:encoded><![CDATA[<p>If you don&#8217;t see it. The blog has a full size layout now. To use it, click the link <strong>Large</strong> on the top-right corner of the blog. Thanks <a href="http://www.private-storm.de" target="_blank">Storm!</a>.</p>
<p><a href="http://blog.delphi-jedi.net/wp-content/uploads/2010/12/Large.png"><img class="alignnone size-full wp-image-923" title="Large" src="http://blog.delphi-jedi.net/wp-content/uploads/2010/12/Large.png" alt="" width="212" height="62" /></a></p>
<p>I had a wow effect, do you?</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2010/12/01/if-you-dont-see-it/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Is File In Use</title>
		<link>http://blog.delphi-jedi.net/2010/11/14/is-file-in-use/</link>
		<comments>http://blog.delphi-jedi.net/2010/11/14/is-file-in-use/#comments</comments>
		<pubDate>Sun, 14 Nov 2010 19:57:43 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[Common]]></category>
		<category><![CDATA[JEDI Windows API Headers]]></category>
		<category><![CDATA[COM]]></category>
		<category><![CDATA[Conversion]]></category>
		<category><![CDATA[file]]></category>
		<category><![CDATA[HowTo]]></category>
		<category><![CDATA[JWA]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=861</guid>
		<description><![CDATA[In a thread on DelphiPraxis there was a question that comes up several times a year. However, this time I could remember that there is actually an COM API that can solve the problem. The question was about how to find out which process has a lock on a file. The main problem was, in [...]]]></description>
			<content:encoded><![CDATA[<p>In a thread on DelphiPraxis there was a question that comes up several times a year. However, this time I could remember that there is actually an COM API that can solve the problem. The question was about how to find out which process has a lock on a file. The main problem was, in deed, that I could not remember the API&#8217;s name so Assarbad put some effort in retrieving it. Thanks.<span id="more-861"></span></p>
<p>The name of the API is <a href="http://msdn.microsoft.com/en-us/library/bb775874%28VS.85%29.aspx" target="_blank">IFileIsInUse</a>, an interface. It resides in Shobjidl.h, Shobjidl.idl and newly in JwaShlObj.pas. This is the translation:</p>
<pre class="brush:delphi">{$IFDEF WINVISTA_UP}
const
  IID_IFileIsInUse: TGUID = (
    D1:$64a1cbf0; D2:$3a1a; D3:$4461; D4:($91,$58,$37,$69,$69,$69,$39,$50));

type
  {$ALIGN 4}
  tagFILE_USAGE_TYPE = (
    FUT_PLAYING = 0,
    FUT_EDITING = 1,
    FUT_GENERIC = 2
  );
  FILE_USAGE_TYPE = tagFILE_USAGE_TYPE;
  TFileUsageType = FILE_USAGE_TYPE;

const
  OF_CAP_CANSWITCHTO     = $0001;
  OF_CAP_CANCLOSE        = $0002;

type
  IFileIsInUse = interface(IUnknown)
    ['{64a1cbf0-3a1a-4461-9158-376969693950}']
    function GetAppName(out ppszName: LPWSTR) : HRESULT; stdcall;
    function GetUsage(out pfut : FILE_USAGE_TYPE) : HRESULT; stdcall;
    function GetCapabilities(out pdwCapFlags : DWORD) : HRESULT; stdcall;
    function GetSwitchToHWND(out phwnd : HWND) : HRESULT; stdcall;
    function CloseFile() : HRESULT; stdcall;
  end;

{$ENDIF WINVISTA_UP}
</pre>
<p>The interface can be used as a client and also can be implemented by a server. A client usually checks if a file has a lock and retrieves a pointer to this interface to access the methods. A server usually holds a lock on a given file and implements the interface to provide the methods to the client. This article will discuss only the client side.<br />
 You see that this API only works if both sides do their jobs. A process that locks a file must also implement this interface and register it, so a client can receive a status information. There is no direct link between a file lock and the process name. If a process holds a lock on a file but does not implement the interface you are on your own again. <br />
 Eventually, this is only a shell helper for the nice Windows Explorer deletion dialog.</p>
<p><a href="http://blog.delphi-jedi.net/wp-content/uploads/2010/11/FileInUse-2.png"><img class="alignnone size-full wp-image-869" title="FileInUse Windows Explorer Dialog" src="http://blog.delphi-jedi.net/wp-content/uploads/2010/11/FileInUse-2.png" alt="" width="496" height="293" /></a></p>
<pre class="brush:delphi">  IFileIsInUse = interface(IUnknown)
    function GetAppName(out ppszName: LPWSTR) : HRESULT; stdcall;
    function GetUsage(out pfut : FILE_USAGE_TYPE) : HRESULT; stdcall;
    function GetCapabilities(out pdwCapFlags : DWORD) : HRESULT; stdcall;
    function GetSwitchToHWND(out phwnd : HWND) : HRESULT; stdcall;
    function CloseFile() : HRESULT; stdcall;
  end;
</pre>
<p>The methods of the interface are really easy to understand.</p>
<ul>
<li><em>GetAppName </em>retrieves the name of the process that holds the file. It can be any chosen name by the application designer. To get the name use always a PWideChar and don&#8217;t forget to free it with CoTaskMemFree (it uses the interface IMalloc). Don&#8217;t forget to check for the result. If you like exception you can also rewrite the code using <strong>safecall</strong> (convert the function to a procedure then).</li>
<li><em>GetUsage </em>returns the reason why the file is locked. It can be one of the enumeration constant of  TFileUsage. Either it can be playing a video or music or editing a file. If these are not sufficient the value FUT_GENERIC must be used. Maybe there will be more values in future.</li>
<li> <em>GetCapabilities </em>returns a set of flags in a DWORD. They define whether the file can be closed (OF_CAP_CANCLOSE) by calling <em>CloseFile</em> or the we can put the application into foreground (OF_CAP_CANSWITCHTO). Be aware that you should inform the user that you are about to switch the window. Otherwise she could get nervous about her missing application window. Switching the window can be done by <a href="http://msdn.microsoft.com/en-us/library/ms633539%28VS.85%29.aspx" target="_blank"><em>SetForegroundWindow</em></a>. But your application must have a focus (and some other rules, see MSDN SetForegroundWindow) to switch the window; otherwise nothing happens.</li>
<li><em>GetSwitchToHWND</em> returns a window handle of the other process. Only use this handle to switch to the window. You don&#8217;t really know what window is returned here. Don&#8217;t try to close it or anything else because this is just bad behaviour. At all costs, check the return value. Otherwise you don&#8217;t know whether the returned window handle is valid or just an random number. In worst case it is an existing window from your process. Well, COM rules tell us to nullify the out parameters but usually it is better to check.<br />
 Of course, the call is only valid if GetCapabilities returns the bit OF_CAP_CANSWITCHTO.</li>
<li><em>CloseFile</em> implements the server side of closing the file. The call is only valid if <em>GetCapabilities </em>returns the bit OF_CAP_CANCLOSE. Well, this is really nice. However, don&#8217;t trust it! Always recheck the lock on the file instead of continuing blindly.</li>
</ul>
<p>To retrieve an interface on the file you have to lock it first. Either you download and compile the MSDN example <a href="http://msdn.microsoft.com/en-us/library/ee330722(v=VS.85).aspx" target="_blank">IsFileInUse</a> or you open up an application that implements the interface (e.g. a PDF Reader, MS Office).</p>
<p>The next step is to know where the locked files are placed. The location is the running object table, short ROT (ActiveX.GetRunningObjectTable() retrieves it). It is a global* (on machine) table that holds running COM objects. You can implement your own interfaces and put it in this table. Because interfaces can be arbitrary in its structure and reason to be,  they are attached to monikers (<a href="http://msdn.microsoft.com/en-us/library/ms679705%28VS.85%29.aspx" target="_blank">IMoniker</a>) which describe them uniquely. There are several types of monikers like class, item and file moniker (more information provides IMoniker in MSDN). We are interested in the latter only. <br />
 So the whole work is an enumeration over all monikers in the ROT.  Usually there are not that much in there (I got 5 here). Each moniker is checked for its type (IsSystemMoniker) and if it is a file moniker (MKSYS_FILEMONIKER) the path is compared to the input parameter FileName. Honestly, I cannot tell why there is a comparison of the prefix at first followed by a comparison of the moniker itself, sorry. <br />
 The object itself is retrieved from the moniker by GetObject. It may fail with E_ACCESS_DENIED so a check is done using <em>Succeeded</em>. In the end, we can try to retrieve the IFileIsInUse interface. There may be such a file registered but without the implementation of the interface, thus an additional check.</p>
<p>I didn&#8217;t create this whole source by myself. In fact, there is a <a href="http://msdn.microsoft.com/en-us/library/ee330722(v=VS.85).aspx" target="_blank">FileIsInUse example </a>in MSDN that is the base of this article. The original source is located in the docx file in the download. The example FileIsInUse will create a server.</p>
<p><br class="spacer_" /></p>
<pre class="brush:delphi">function GetFileInUseInfo(const FileName : WideString) : IFileIsInUse;
var
  ROT : IRunningObjectTable;
  mFile, enumIndex, Prefix : IMoniker;
  enumMoniker : IEnumMoniker;
  MonikerType : LongInt;
  unkInt  : IInterface;
begin
  result := nil;

  OleCheck(GetRunningObjectTable(0, ROT));
  OleCheck(CreateFileMoniker(PWideChar(FileName), mFile));

  OleCheck(ROT.EnumRunning(enumMoniker));

  while (enumMoniker.Next(1, enumIndex, nil) = S_OK) do
  begin
    OleCheck(enumIndex.IsSystemMoniker(MonikerType));
    if MonikerType = MKSYS_FILEMONIKER then
    begin
      if Succeeded(mFile.CommonPrefixWith(enumIndex, Prefix)) and
         (mFile.IsEqual(Prefix) = S_OK) then
      begin
       if Succeeded(ROT.GetObject(enumIndex, unkInt)) then
        begin
          if Succeeded(unkInt.QueryInterface(IID_IFileIsInUse, result)) then
          begin
            result := unkInt as IFileIsInUse;
            exit;
          end;
        end;
      end;
    end;
  end;
end;
</pre>
<p><br class="spacer_" /></p>
<h3>Conclusion<br class="spacer_" /></h3>
<p>This whole API has some caveats</p>
<ul>
<li>This API relies on a server that registers an interface in the ROT honestly. If an application doesn&#8217;t do the effort, you will be unable to aquire the name of it.</li>
<li>If you lock a file on a shared folder and you want to access the very same file on the local file system, you cannot determine the process if you access the shared folder from localhost. The reason is Windows itself. Windows is the provider of the file to the outer world (even if it is a loopback) so Windows Explorer shows &#8220;System&#8221; as origin. In the ROT you will see the the UNC path instead of the local file system path. Thus the comparison and our function will fail.</li>
<li>*Security: A ROT is not really global. In fact, there are several ROTs in the system. ROTs are divided by a user and then the mandatory integrity control (MIC) or integrity levels (IL) high, medium and propably low (didn&#8217;t check). If you run as a user, your processes get an medium level and as an Administrator you&#8217;ll get an high integrity level. A server that runs with an medium integrity level will only be allowed to register itself into the medium ROT. So it must be started at least once as Administrator to be allowed to create some Registry keys for COM (LOCAL_MACHINE\Classes\AppID\<em>guid</em>). In this way it will be available in all ROTs if it wants. Unfortunately, this is not the end. On a multi user system, every object in a moniker has a security descriptor that tells COM who is allowed to access it. If Alice wants to access an object in the ROT that was created by Bob, Bob has to explicitily grant Alice access to it. By default the security, which allow access to SYSTEM, Administrators and the creator, is copied from the global COM security settings and can be changed either in the registry for an AppID, at process startup or for each registered object by the server. JWSCL provides all of them in JwsclComSecurity.pas (only Subversion trunk and &gt;= 0.9.4). In this way a server can change the settings to, say, allow all authenticated users access to the object. </li>
</ul>
<h3>Downloads</h3>
<p>You can download the example file from the Subversion directly.</p>
<table border="0">
<tbody>
<tr>
<td><a href="tsvn:https://jedi-apilib.svn.sourceforge.net/svnroot/jedi-apilib/jwapi/trunk/Examples/FileIsInUse/Client/FileIsInUseClientExample.dpr"><img class="size-full wp-image-387 alignnone" title="tortoisecheckout" src="http://blog.delphi-jedi.net/wp-content/uploads/2007/12/tortoisecheckout.png" alt="Checkout with TortoiseSVN" width="48" height="48" /></a></td>
<td><a href="https://jedi-apilib.svn.sourceforge.net/svnroot/jedi-apilib/jwapi/trunk/Examples/FileIsInUse/Client/FileIsInUseClientExample.dpr" target="_blank">https://jedi-apilib.svn.sourceforge.net/svnroot/jedi-apilib/jwapi/trunk/Examples/FileIsInUse/Client/FileIsInUseClientExample.dpr</a></td>
</tr>
</tbody>
</table>
<p><br class="spacer_" /></p>
<h3>Sequel</h3>
<p>The next article discusses the the implementation if the interface IFileIsInUse.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2010/11/14/is-file-in-use/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>The JEDI Wiki</title>
		<link>http://blog.delphi-jedi.net/2010/11/12/the-jedi-wiki/</link>
		<comments>http://blog.delphi-jedi.net/2010/11/12/the-jedi-wiki/#comments</comments>
		<pubDate>Fri, 12 Nov 2010 18:26:12 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[Common]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=880</guid>
		<description><![CDATA[Many people are not aware of the JEDI Wiki. This wiki is/should be a central information point around all JEDI projects. Unfortunately, this is a lot of work. Therfore, we depend on the community helping us out here. If you want to write a documentation, consider first to create an account. This will help immensely [...]]]></description>
			<content:encoded><![CDATA[<p>Many people are not aware of the<a href="http://wiki.delphi-jedi.org" target="_blank"> JEDI Wiki</a>. This wiki is/should be a central information point around all JEDI projects. Unfortunately, this is a lot of work. Therfore, we depend on the community helping us out here.</p>
<p><span id="more-880"></span>If you want to write a documentation, consider first to create an account. This will help immensely if there is a need to contact you on the subject. Of course, it is not mandatory and you don&#8217;t contact any JEDI member.</p>
<p>I have written a page about <a href="http://wiki.delphi-jedi.org/index.php?title=JEDI_Windows_Security_Code_Library" target="_blank">JWSCL</a>. It can be improved though.</p>
<p>Also JCL news can be found <a href="http://wiki.delphi-jedi.org/index.php?title=JCL_News" target="_blank">here</a> (although they look outdated)</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2010/11/12/the-jedi-wiki/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The Way WinAPI Shows Errors</title>
		<link>http://blog.delphi-jedi.net/2010/10/29/the-way-winapi-shows-errors/</link>
		<comments>http://blog.delphi-jedi.net/2010/10/29/the-way-winapi-shows-errors/#comments</comments>
		<pubDate>Thu, 28 Oct 2010 22:17:44 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[Common]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=834</guid>
		<description><![CDATA[I got an interested answer in a forum question which I participated in. The question was not about the subject of this article but instead an answer contained code that was interesting enough to write this article. The code was Delphi but it was clearly inspired by plain C code (even using goto). However, here, [...]]]></description>
			<content:encoded><![CDATA[<p>I got an interested answer in a forum question which I participated in. The question was not about the subject of this article but instead an answer contained code that was interesting enough to write this article. The code was Delphi but it was clearly inspired by plain C code (even using goto). However, here, I want to talk about how errors are returned in most of the WinAPI functions and why the given code in the answer is not the correct way to do  so.<span id="more-834"></span></p>
<p>The code was not posted in this exact way. I just extracted the necessary parts for your comprehension (The original source was even more a duplicate of real plain C code.):</p>
<pre class="brush:delphi">function IsUserMemberOf(const Group : PSID) : BOOL;
 var
   hToken : HANDLE;
 begin
   result := false;
   //retrieve Token here and store in hToken ... (short version)
   if not OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY or TOKEN_DUPLICATE, hToken) then
     goto Exit;

   //additional stuff for Vista and house keeping for Windows in general and a lot of gotos   

   if not CheckTokenMembership(hToken, Group, @result) then
   begin
     goto Exit_1;
   end;

:Exit_1
  CloseHandle(hToken);
  goto Exit;
:Exit
end; </pre>
<p>What is the problem here with the return value of the function? First of all, every WinAPI function is checked against its return value and the function exits if the function call fails. This is good, because I still see a lot of codes where no checks are made. But we have another problem here. There are two possible results (sets of possible return values) we actually want to tell the caller of this function:</p>
<ul>
<li>The set of possible results whether the user is member of a given group. This is clearly a binary (say: two elements: TRUE/FALSE) set here.</li>
<li>The set of whether an error occured. This is also a binary set (TRUE/FALSE).</li>
</ul>
<p>The codomain of your function is a binary set which means the range of the return value is FALSE (0) to TRUE (1). However, the function above maps two sets with different meanings into one set: the codomain or function result. If one of the WinAPI calls fails, the function immediately exits and returns FALSE. So the element FALSE is obviously used for two computation results. On that tells the caller that the user is NOT a member of the given group and the other one tells her that the function failed for whatever reason. So we have a mapping of two values to one value. We lost information! Without an additional (meta) information we are unable to distinguish them again. Always think of it when you want to specifiy/write a function. But of course we have this information somewhere else. The WinAPI itself has it. GetLastError provides the error value which (hopefully) helps us to solve the problem. So everything is fine now? I wish! Check this out:</p>
<pre class="brush:delphi">function GetMyUserName : String;
var
 nSize : Cardinal;
 p : PChar;
begin
 nSize := 0;
 if not GetUserName(nil, nSize) and (GetLastError() = ERROR_INSUFFICIENT_BUFFER) then
 begin  
   GetMem(p, nSize * sizeof(WCHAR));
   try
     if not GetUserName(p, nSize) then
       RaiseLastOSError;
     result := p;
   finally
     FreeMem(p);
   end;
 end
 else
   RaiseLastOSError;
end; 

begin
  ...
  xy := GetMyUserName();
  bIsMember := IsUserMemberOf(aGroup);

  if not bIsMember and (GetLastError() _unequal_ 0) then
    ERROR //...handling;
end;</pre>
<p>The function IsUserMemberOf is called in succession of GetMyUserName which asks the WinAPI function GetUserName to return the size of the username string. The GetLastError code is set to ERROR_INSUFFICIENT_BUFFER (122<sub>dec</sub>) which tells us to use create a memory block of valid size.<br />
 Now GetMyUserName returns correctly our username and let&#8217;s say that IsUserMemberOf does not fail either. But it wants to tell us that the user (or better process) is not the member of our given group. So the return value is FALSE and it is a fact that most of the WinAPI functions won&#8217;t change the LastError value if they succeed. So GetLastError will still be ERROR_INSUFFICIENT_BUFFER (122<sub>dec</sub>) when the variable bIsMember is tested for validity and the result is an ERROR handling which, in fact, should not be done here.<br />
 As you see, although we got additional information from GetLastError, the implementation of our function does not allow a caller to find out whether the return value is the value of a computation or an error status.</p>
<p>If you intend to write such a function. I urge you not to use plain C techniques. Why? Let us check how WinAPI functions could look like in Delphi with plain C techniques:</p>
<pre class="brush:delphi">function GetUserNameW(lpBuffer: LPWSTR; nSize: PDWORD): BOOL;
var
   pUserName : PWideChar;
   res: NTSTATUS;
   bRes : Boolean;
begin
   bRes := FALSE;

   if (nSize = nil) then
   begin
     SetLastError(ERROR_INVALID_PARAMETER);
     goto Exit;
   end;

   if (lpBuffer = NIL) or (nSize^ _smallerthan_ InternalGetMinUserNameLength()) then
   begin
      nSize^ := InternalGetMinUserNameLength();

      SetLastError(ERROR_INSUFFICIENT_BUFFER);
      goto Exit;
   end;

   //This is not quite necessary but adds more complexion to the example
   pUserName := HLOCAL(LocalAlloc(LPTR, InternalGetMinUserNameLength() * sizeof(WIDECHAR));
   //TODO: also check pUserName for nil, if nil goto Exit

   res := NtGetUserName(pUserName, InternalGetMinUserNameLength() * sizeof(WIDECHAR));
   if NT_FAILED(res) then
   begin
      SetLastError(NtStatusToDosError(res));
      goto Exit_1;
   end;   

   if not StrCopyMemory(lpBuffer, pUserName) then //fake call but already uses SetLastError
      goto Exit_1;

   bRes := TRUE;
:Exit_1
   FreeMem(pUserName);
   goto Exit;
:Exit
   result := bRes; //in C actually: return bRes;
end;
</pre>
<p>Looks complicated, doesn&#8217;t it? I didn&#8217;t intend to write the real implemention of GetUserName (I don&#8217;t know it by heart) but instead just show a fictive implementation.  So WinAPI uses solely the function result as an error indication. FALSE means an error occured and the out parameter values and GetLastError must be checked according to documentation. TRUE means, everything is fine.</p>
<p>Do we need this in Delphi? Not really. If you intend to write a library, a DLL file, that needs to be called by other languages, well, than you could use SetLastError as an error reporting facility. But then you still have to return all your computations in an out/var parameter (by reference). Of course, you can also use the type HRESULT as error indicator in the return value.</p>
<pre class="brush:delphi">function GetUserNameW(lpBuffer: LPWSTR; nSize: PDWORD): HRESULT; </pre>
<p>If you want a plain Delphi function, you can make life easier by using exceptions.</p>
<pre class="brush:delphi">procedure GetUserNameW(Name: PWideChar; var nSize: DWORD); </pre>
<p>In addition, this makes it possible to return a computation in the function return value.</p>
<pre class="brush:delphi">function GetUserNameW(Name: PWideChar; var nSize: DWORD) : PWideChar;
begin
  if (nSize = nil) then
  begin
    SetLastError(ERROR_INVALID_PARAMETER);
    RaiseLastOsError;
  end;
  ... //to make it short one example here is sufficient
end;
</pre>
<p>As you can see, RaiseLastOsError is called which raises an EOsError. It contains the GetLastError return code in its property ErrorCode automatically. We can even create our own exception class (JWSCL does with EJwsclWinCallFailedException) and get rid of SetLastError at all!  And, of course you can use the native string type feature of Delphi which makes the function really easy to use.</p>
<pre class="brush:delphi">function GetUserName() : String;</pre>
<p>The function returns a string. It does not return an empty string in a case of failure as other implementations we can find on the internet. Otherwise, we would have the same problem as in the beginning of this article: One return value that can be a valid computation result or an error status. What&#8217;s your guess in this situation?</p>
<pre class="brush:delphi">function IsUserMemberOf(const Group : PSID) : Boolean;
 var
   hToken : HANDLE;
 begin
   result := false;
   //retrieve Token here and store in hToken ... (short version)
   if not OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY or TOKEN_DUPLICATE, hToken) then
     RaiseLastOsError;

   //additional stuff for Vista and house keeping for Windows in general and a lot of RaiseLastOsError;

   if not CheckTokenMembership(hToken, Group, @result) then
   begin
      RaiseLastOsError;
   end;
end; </pre>
<p>A good implementation comes from JEDI Component Library (JCL) in file <a href="http://jcl.svn.sourceforge.net/viewvc/jcl/trunk/jcl/source/windows/JclSecurity.pas?revision=3097&amp;content-type=text%2Fplain" target="_blank">JclSecurity.pas</a> Forget about all the other implementations!! Use this one:</p>
<pre class="brush:delphi">function IsGroupMember(RelativeGroupID: DWORD): Boolean;
var
  psidAdmin: Pointer;
  Token: THandle;
  Count: DWORD;
  TokenInfo: PTokenGroups;
  HaveToken: Boolean;
  I: Integer;
const
  SE_GROUP_USE_FOR_DENY_ONLY = $00000010;
begin
  Result := not IsWinNT;
  if Result then // Win9x and ME don't have user groups
    Exit;
  psidAdmin := nil;
  TokenInfo := nil;
  HaveToken := False;
  try
    Token := 0;
    HaveToken := OpenThreadToken(GetCurrentThread, TOKEN_QUERY, True, Token);
    if (not HaveToken) and (GetLastError = ERROR_NO_TOKEN) then
      HaveToken := OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, Token);
    if HaveToken then
    begin
      {$IFDEF FPC}
      Win32Check(AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2,
        SECURITY_BUILTIN_DOMAIN_RID, RelativeGroupID, 0, 0, 0, 0, 0, 0,
        psidAdmin));
      if GetTokenInformation(Token, TokenGroups, nil, 0, @Count) or
       (GetLastError <> ERROR_INSUFFICIENT_BUFFER) then
         RaiseLastOSError;
      TokenInfo := PTokenGroups(AllocMem(Count));
      Win32Check(GetTokenInformation(Token, TokenGroups, TokenInfo, Count, @Count));
      {$ELSE FPC}
      Win32Check(AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2,
        SECURITY_BUILTIN_DOMAIN_RID, RelativeGroupID, 0, 0, 0, 0, 0, 0,
        psidAdmin));
      if GetTokenInformation(Token, TokenGroups, nil, 0, Count) or
       (GetLastError <> ERROR_INSUFFICIENT_BUFFER) then
         RaiseLastOSError;
      TokenInfo := PTokenGroups(AllocMem(Count));
      Win32Check(GetTokenInformation(Token, TokenGroups, TokenInfo, Count, Count));
      {$ENDIF FPC}
      for I := 0 to TokenInfo^.GroupCount - 1 do
      begin
        {$RANGECHECKS OFF} // Groups is an array [0..0] of TSIDAndAttributes, ignore ERangeError
        Result := EqualSid(psidAdmin, TokenInfo^.Groups[I].Sid);
        if Result then
        begin
          //consider denied ACE with Administrator SID
          Result := TokenInfo^.Groups[I].Attributes and SE_GROUP_USE_FOR_DENY_ONLY
              <> SE_GROUP_USE_FOR_DENY_ONLY;
          Break;
        end;
        {$IFDEF RANGECHECKS_ON}
        {$RANGECHECKS ON}
        {$ENDIF RANGECHECKS_ON}
      end;
    end;
  finally
    if TokenInfo <> nil then
      FreeMem(TokenInfo);
    if HaveToken then
      CloseHandle(Token);
    if psidAdmin <> nil then
      FreeSid(psidAdmin);
  end;
end;

function IsAdministrator: Boolean;
begin
  Result := IsGroupMember(DOMAIN_ALIAS_RID_ADMINS);
end;
</pre>
<p>The same can be done using JWSCL.</p>
<pre class="brush:delphi">uses
  JwaWindows,
  JwsclToken,
  JwsclKnownSid,
  JwsclUtils;

var
  Token : TJwSecurityToken;
begin
  JwInitWellKnownSIDs;

  Token := TJwSecurityToken.CreateTokenEffective(TOKEN_READ or TOKEN_QUERY or TOKEN_DUPLICATE);
  try
    Token.ConvertToImpersonatedToken(DEFAULT_IMPERSONATION_LEVEL, MAXIMUM_ALLOWED);
    if Token.CheckTokenMembership(JwAdministratorsSID) then
      //active member of Administrators
  finally
    Token.Free;
  end;
end;</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2010/10/29/the-way-winapi-shows-errors/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<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>Windows LNK Exploit</title>
		<link>http://blog.delphi-jedi.net/2010/07/19/windows-lnk-exploit/</link>
		<comments>http://blog.delphi-jedi.net/2010/07/19/windows-lnk-exploit/#comments</comments>
		<pubDate>Mon, 19 Jul 2010 10:37:18 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[Common]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=751</guid>
		<description><![CDATA[As you maybe have heard already. There is a shell exploit that is executed when Windows shows just the icon from a link file. MS works on it but currently you can only remove the icon handler key from the registry to be &#8220;safe&#8221;. See this link. It also tells us the impact of the [...]]]></description>
			<content:encoded><![CDATA[<p>As you maybe have heard already. There is a shell exploit that is executed when Windows shows just the icon from a link file. MS works on it but currently you can only remove the icon handler key from the registry to be &#8220;safe&#8221;. See this <a href="http://www.microsoft.com/technet/security/advisory/2286198.mspx" target="_blank">link</a>. It also tells us the impact of the action. However, on Windows 7, I think this prevents me from working efficiently with the Windows Explorer.<span id="more-751"></span><a href="http://www.microsoft.com/technet/security/advisory/2286198.mspx" target="_blank"> Technet reads:</a></p>
<p><cite><strong>Impact of workaround.</strong>Disabling icons from being displayed for  shortcuts prevents the issue from being exploited on affected systems.  When this workaround is implemented, shortcut files and Internet  Explorer shortcuts will no longer have an icon displayed.</cite></p>
<p>Let me show you, why I can&#8217;t work anymore efficiently.</p>
<div id="attachment_752" class="wp-caption alignnone" style="width: 471px"><a href="http://blog.delphi-jedi.net/wp-content/uploads/2010/07/StartMenuWin7Clear.png"><img class="size-full wp-image-752 " title="StartMenuWin7Clear" src="http://blog.delphi-jedi.net/wp-content/uploads/2010/07/StartMenuWin7Clear.png" alt="Windows 7 Taskbar with plain Icons" width="461" height="30" /></a><p class="wp-caption-text">Windows 7 Taskbar with plain Icons</p></div>
<p>As you can see, some of the applications are already started and they don&#8217;t have their icon but some of them have. I don&#8217;t see the reason though. Do you?</p>
<p>BTW: This goes on in the start menu, on the desktop, and the favorite list in Windows Explorer.</p>
<p>Happy working&#8230;.  <img src='http://blog.delphi-jedi.net/wp-includes/images/smilies/icon_twisted.gif' alt=':twisted:' class='wp-smiley' /> </p>
<p>EDIT:</p>
<p>A <a href="http://code.google.com/p/linkiconshim/" target="_blank">possible fix</a> was supplied by external programmers. Maybe this will be the only option for the last few people who are using Windows 2000 still.</p>
<p><br class="spacer_" /></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2010/07/19/windows-lnk-exploit/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Useful scripts for MSVC and C++ Builder users …</title>
		<link>http://blog.delphi-jedi.net/2010/06/24/useful-scripts-for-msvc-and-c-builder-users-%e2%80%a6/</link>
		<comments>http://blog.delphi-jedi.net/2010/06/24/useful-scripts-for-msvc-and-c-builder-users-%e2%80%a6/#comments</comments>
		<pubDate>Thu, 24 Jun 2010 12:10:57 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[Common]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=742</guid>
		<description><![CDATA[Assarbad wrote this script some time ago to compile and link C++ projects on the command line easier. I adapted the cmd script for VC++2010 and also for C++ Builder 2009/2010 and now I have been using it for quite some time. So I wanted to give it back to the community. Feel free to [...]]]></description>
			<content:encoded><![CDATA[<p>Assarbad wrote this <a href="http://blog.assarbad.net/20090116/useful-script-for-msvc-users/" target="_blank">script</a> some time ago to compile and link C++ projects on the command line easier. I adapted the cmd script for VC++2010 and also for C++ Builder 2009/2010 and now I have been using it for quite some time. So I wanted to give it back to the community.</p>
<p><span id="more-742"></span>Feel free to use it since it is public domain.</p>
<p><a href="http://blog.delphi-jedi.net/wp-content/uploads/2010/06/scripts.zip">Download C++ Environment Scripts</a></p>
<p>By default the scripts setup the environment to the newest compiler found on your system. In this way you can just call msbuild and build your projects.</p>
<p><br class="spacer_" /></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2010/06/24/useful-scripts-for-msvc-and-c-builder-users-%e2%80%a6/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>New JEDI News Server</title>
		<link>http://blog.delphi-jedi.net/2010/03/22/new-jedi-news-server/</link>
		<comments>http://blog.delphi-jedi.net/2010/03/22/new-jedi-news-server/#comments</comments>
		<pubDate>Mon, 22 Mar 2010 15:24:27 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[Common]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=719</guid>
		<description><![CDATA[As you maybe already know, the old news server for JEDI related questions crashed some time ago. Unfortunately, the old host could not undo the crash and thus some JEDI members created a new server (Thanks you!). The new server location is: news.delphi-jedi.org Please adapt your news reader accordingly. However, it is a pity that [...]]]></description>
			<content:encoded><![CDATA[<p>As you maybe already know, the old news server for JEDI related questions crashed some time ago. Unfortunately, the old host could not undo the crash and thus some JEDI members created a new server (Thanks you!). The new server location is: <span style="font-size: medium;"><strong>news.delphi-jedi.org </strong></span></p>
<p><span id="more-719"></span>Please adapt your news reader accordingly. However, it is a pity that the old messages cannot be restored and maybe never will without an backup.</p>
<p>Furthermore, the server itself may still be changed but the address will stay the same.</p>
<p><br class="spacer_" /></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2010/03/22/new-jedi-news-server/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Embarcadero Forum Access</title>
		<link>http://blog.delphi-jedi.net/2010/03/22/embarcadero-forum-access/</link>
		<comments>http://blog.delphi-jedi.net/2010/03/22/embarcadero-forum-access/#comments</comments>
		<pubDate>Mon, 22 Mar 2010 09:50:57 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[Common]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=715</guid>
		<description><![CDATA[If you are accessing the Embarcadero Forums and such through an Offline Reader like Mozilla Thunderbird, you probably have had a connection problem for some time now. I don&#8217;t know what the reason is. However, as a solution instead, use the address forums.embarcadero.com and don&#8217;t forget to activate SSL. I couldn&#8217;t make a connection without [...]]]></description>
			<content:encoded><![CDATA[<p>If you are accessing the Embarcadero Forums and such through an Offline Reader like Mozilla Thunderbird, you probably have had a connection problem for some time now. I don&#8217;t know what the reason is. However, as a solution instead, use the address <strong>forums.embarcadero.com</strong> and don&#8217;t forget to activate SSL. I couldn&#8217;t make a connection without it.</p>
<p><span id="more-715"></span>UPDATE:</p>
<p>It looks to me as if only the unsecured access is not accepted. Instead only SSL is available regardless of the address (so both works).<br />
I got some mails from people who couldn&#8217;t answer the threads I participate. So they sent me mails directly. </p>
<p>A shame that Kaster&#8217;s thread wasn&#8217;t replicated by e.g. Nick. His blog is far more often read by people than this Announce forum (which was afterwards effectively unavailable to me and others).<br />
Furthermore some forums look to me a little bit more abandoned than usual. So the activity seems to be lower.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2010/03/22/embarcadero-forum-access/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

