<?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; JWA</title>
	<atom:link href="http://blog.delphi-jedi.net/tag/jwa/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>How to Run the OnScreenKeyboard</title>
		<link>http://blog.delphi-jedi.net/2010/11/29/how-to-run-the-onscreenkeyboard/</link>
		<comments>http://blog.delphi-jedi.net/2010/11/29/how-to-run-the-onscreenkeyboard/#comments</comments>
		<pubDate>Mon, 29 Nov 2010 14:30:48 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[JEDI Windows API Headers]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[DLL]]></category>
		<category><![CDATA[HowTo]]></category>
		<category><![CDATA[JWA]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=899</guid>
		<description><![CDATA[There are lots of questions on the Internt how to run the OnScreen Keyboard on a Windows 64 System from a 32bit Process. Some time ago, I investigated it but due to a lack of time I didn&#8217;t finish it. Today, I want to you show the solution of this problem. From a 32Bit application, [...]]]></description>
			<content:encoded><![CDATA[<p>There are lots of questions on the Internt how to run the OnScreen Keyboard on a Windows 64 System from a 32bit Process. Some time ago, I investigated it but due to a lack of time I didn&#8217;t finish it. Today, I want to you show the solution of this problem.</p>
<p><span id="more-899"></span>From a 32Bit application, Windows makes sure that you cannot access the Windows\System32 folder because this is the place where Windows has all its 64bit DLLs and other files. Since a 32Bit app cannot load 64Bit DLLs, Windows redirects the access to Windows\SysWOW64 folder which is (nearly) a 32Bit copy of the System32 folder. Therefore if you call ShellExecute on the e.g. Windows\System32\osk.exe you actually run Windows\SysWOW64\osk.exe. However the 32Bit version of  OnScreenKeyboard refuses to run on a 64Bit system.</p>
<p>Fortunately, we can disable the redirrection with Wow64DisableWow64FsRedirection.</p>
<p>That leads us to a problem with ShellExecute. It uses internal functions that are located in DLLs. And there is the problem. If a winapi function wasn&#8217;t called before, it will be setup by calling LoadLibrary and GetProcAddress. However, since redirection is offline, LoadLibrary will load a 64Bit DLL which, of course, fails. In such a case ShellExecuteEx returns GetLastError  $7E (127) which defines the error  &#8220;The module specified could not be found &#8220;. I wondered what module was not found and used ProcessExplorer to compare pre- and post situation of ShellExecute. There were many, but only one made ShellExecuteEx work with disabled redirection: MPR.dll (multi protocol router). Step by step disasm returned the that WNetGetConnectionW was loaded from the DLL. So the fix is to load this library before ShellExecuteEx (also ShellExecute) is called.</p>
<pre class="brush:delphi">uses
  JwaWinType,
  JwaWinBase,
  JwaShellAPI,
  JwaSHFolder,
  JwaShlObj;

function Wow64DisableWow64FsRedirection(out OldValue: PVOID): BOOL; stdcall; external 'Kernel32.dll'; //only for JWA &lt; 2.4
function Wow64RevertWow64FsRedirection(const OldValue: PVOID): BOOL; stdcall; external 'Kernel32.dll'; //only for JWA &lt; 2.4

procedure RunOnScreenKeyBoard;
  function GetNativeWindowsDirectory : String;
  var
    P : array[0..MAX_PATH] of Char;
  begin
    SHGetFolderPath(0, CSIDL_SYSTEM, 0, SHGFP_TYPE_DEFAULT, @P);

    result := P;
  end;
var
  oldValue : Pointer;
  Path : String;
  hMpr_DLL : HMODULE;
  ShInfo : SHELLEXECUTEINFO;
begin
  //CoInitializeEx(nil, COINIT_MULTITHREADED or COINIT_DISABLE_OLE1DDE); //*1

  hMpr_DLL := LoadLibrary('mpr.dll'); //*2
  try
    if not Wow64DisableWow64FsRedirection(oldValue) then
      RaiseLastOSError;
    try
      Path := GetNativeWindowsDirectory + '\osk.exe';

      ZeroMemory(@ShInfo, sizeof(ShInfo));
      ShInfo.cbSize := sizeof(ShInfo);
      ShInfo.lpVerb := 'open';
      ShInfo.fMask := SEE_MASK_FLAG_NO_UI or SEE_MASK_NOASYNC;
      ShInfo.lpFile := PChar(Path);

      if not ShellExecuteEx(ShInfo) then
        RaiseLastOSError;
    finally
       Wow64RevertWow64FsRedirection(oldValue);
    end;
  finally
    FreeLibrary(hMpr_DLL);
  end;
end;
</pre>
<p>*1 Has no use here if it was already called. But it is a reminder that it should be called for ShellExecute due to MSDN docs.<br />
 *2 Make sure you don&#8217;t call LoadLibrary when redirection is offline.</p>
<h3>Delphi (addition)</h3>
<p>I forgot to mention that in my experiences, a simple call to ShellExecute works if you run your app in Delphi. You&#8217;ll see that the app already has mpr.dll loaded if you check with Process Explorer. However, running the same app in Windows Explorer it will fail. <br />
 You see that Delphi can have an effect on your application. Therefore, always test your app separately.</p>
<h3>Download</h3>
<p>You can download this file from <a href="https://jedi-apilib.svn.sourceforge.net/svnroot/jedi-apilib/jwapi/trunk/Examples/OSK/64bit OSK/OSK 64 Example.dpr">here</a>.</p>
<h3>Remarks</h3>
<p>I tested this code on my Win7 64bit System only.</p>
<p>The string &#8220;%windir%\sysnative\osk.exe&#8221; was a first guess. However, ShellExecute fails with Error 2 (File Not Found).</p>
<p>Because this is a 64Bit Problem only, I did <strong>not </strong>make extra effort to check for a 64Bit Windows. The function Wow64DisableWow64FsRedirection is not available on a 32Bit platform, so using static linking is a bad idea if you want to use your app on 32Bit.</p>
<p><span style="font-size: large;">If you find this code useful, you may consider a donation? As usual, a donation can be also a WinAPI conversion, examples, bug fixes etc.</span></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2010/11/29/how-to-run-the-onscreenkeyboard/feed/</wfw:commentRss>
		<slash:comments>3</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>Using Windows 7 Taskbar-features via components</title>
		<link>http://blog.delphi-jedi.net/2010/08/18/using-windows-7-taskbar-features-via-components/</link>
		<comments>http://blog.delphi-jedi.net/2010/08/18/using-windows-7-taskbar-features-via-components/#comments</comments>
		<pubDate>Wed, 18 Aug 2010 04:39:49 +0000</pubDate>
		<dc:creator>chaosben</dc:creator>
				<category><![CDATA[JEDI Windows API Headers]]></category>
		<category><![CDATA[GUI]]></category>
		<category><![CDATA[HowTo]]></category>
		<category><![CDATA[JWA]]></category>
		<category><![CDATA[Window]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Windows 7]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=770</guid>
		<description><![CDATA[Windows 7 gave us some nice and useful little eye-catchers in the taskbar. Those are available using the Windows shell interfaces ITaskbarList3 and ITaskbarList4. But alas, how can a Delphi developer incorporate these in his applications? You may read on if you ever wanted to&#8230; have this cool progress bar feature in the taskbar. have [...]]]></description>
			<content:encoded><![CDATA[<p>Windows 7 gave us some nice and useful little eye-catchers in the taskbar. Those are available using the Windows shell interfaces <a href="http://msdn.microsoft.com/en-us/library/dd391692%28v=VS.85%29.aspx" target="_blank">ITaskbarList3</a> and <a href="http://msdn.microsoft.com/en-us/library/dd562040%28VS.85%29.aspx">ITaskbarList4</a>. <br />
 But alas, how can a Delphi developer incorporate these in his applications?</p>
<p><span id="more-770"></span>You may read on if you ever wanted to&#8230;</p>
<ol>
<li>have this cool progress bar feature in the taskbar.</li>
<li>have an overlay icon onto your application&#8217;s icon in the taskbar.</li>
<li>multiple tabs for each window or control of your application in the taskbar.</li>
<li>have thumb buttons inside the preview of your form (like the Windows MediaPlayer).</li>
</ol>
<p>You want your application to look like that?</p>
<p><a href="http://blog.delphi-jedi.net/wp-content/uploads/2010/08/Screen1.png"><img class="aligncenter size-full wp-image-804" src="http://blog.delphi-jedi.net/wp-content/uploads/2010/08/Screen1.png" alt="" width="421" height="203" /></a></p>
<p>Are you using Windows 7? What a lucky (wo)man you are.</p>
<p>The guys from <a href="http://code.google.com/p/theunknownones/" target="_blank">TheUnknownOnes</a> just released some components to use the new features introduced in Windows 7.  <br />
 Of course, these components are based on the JEDI Windows API. At the moment (until the next release of JWAPI), you&#8217;ll have to checkout the trunk of the JWAPI in order to get the code compiled. <br />
 To get these components, checkout <a href="http://theunknownones.googlecode.com/svn/trunk/Components/TaskBarList/" target="_blank">the source</a> out of their svn repository.</p>
<p>And if you want to discuss something about them in German: use <a href="http://www.delphipraxis.net/153782-taskbarlistcomponents-fuer-windows-7-a.html" target="_blank">this thread</a>.</p>
<p>A first short demo was published <a href="http://vimeo.com/14291783" target="_blank">here</a>. Stay tuned for some more.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2010/08/18/using-windows-7-taskbar-features-via-components/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Retrieving File Owner</title>
		<link>http://blog.delphi-jedi.net/2010/03/11/retrieving-file-owner/</link>
		<comments>http://blog.delphi-jedi.net/2010/03/11/retrieving-file-owner/#comments</comments>
		<pubDate>Thu, 11 Mar 2010 13:52:11 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[JEDI Windows API Headers]]></category>
		<category><![CDATA[JEDI Windows Security Code Lib]]></category>
		<category><![CDATA[file]]></category>
		<category><![CDATA[JWA]]></category>
		<category><![CDATA[JWSCL]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=676</guid>
		<description><![CDATA[This article is about how to retrieve the owner of a file. If you are experienced with some of the WinAPI security function this can be pretty easy. There are some problems that needs to be addressed though. The first one is the size of the security items like the SID name of the owner. [...]]]></description>
			<content:encoded><![CDATA[<p>This article is about how to retrieve the owner of a file. If you are experienced with some of the WinAPI security function this can be pretty easy. There are some problems that needs to be addressed though. The first one is the size of the security items like the SID name of the owner. Secondly, there is the possibility that a SID cannot be resolved to a human readable name at all. And thirdly, we need to check all the result values.</p>
<p><span id="more-676"></span></p>
<h2>WinAPI</h2>
<pre class="brush:delphi">
uses
  SysUtils,
  //JwaWindows, //Use either JwaWindows or these JEDI headers:
  JwaWinBase,
  JwaWinType,
  JwaWinNT,
  JwaAclApi,
  JwaAccCtrl,
  JwaWinError,
  JwaSddl;

type
  TOwnerResult = (orNone, orName, orSID);

function GetFileOwner(const FileName: string;
  out Domain, Username: String): TOwnerResult;
var
  pSD: PSecurityDescriptor;
  dwOwnerNameSize, dwDomainNameSize: DWORD;
  pOwnerSID: PSID;
  pszOwnerName, pszDomainName: PChar;
  OwnerType: SID_NAME_USE;
  dwError : DWORD;
begin
  result := orNone;

  pSD := nil;
  dwError := GetNamedSecurityInfo(
     PChar(FileName),//__in       LPTSTR pObjectName,
     SE_FILE_OBJECT,//__in       SE_OBJECT_TYPE ObjectType,
     OWNER_SECURITY_INFORMATION,//__in       SECURITY_INFORMATION SecurityInfo,
     @pOwnerSID,//__out_opt  PSID *ppsidOwner,
     nil,//__out_opt  PSID *ppsidGroup,
     nil,//__out_opt  PACL *ppDacl,
     nil,//__out_opt  PACL *ppSacl,
     pSD//__out_opt  PSECURITY_DESCRIPTOR *ppSecurityDescriptor
   );
  if (dwError <> NOERROR) then
  begin
    SetLastError(dwError);
    RaiseLastOSError;
  end;

  //First get necessary memory size for Owner and Domain
  dwOwnerNameSize  := 0;
  dwDomainNameSize := 0;
  if not LookupAccountSID(nil, pOwnerSID, nil,
    dwOwnerNameSize, nil, dwDomainNameSize, OwnerType) then
  begin
    //Check for SIDs that are unknown on this local system
    if (GetLastError() = ERROR_NONE_MAPPED) then
    begin
      Win32Check(ConvertSidToStringSid(pOwnerSID, pszOwnerName));
      Domain := '';
      Username := pszOwnerName;
      LocalFree(HLOCAL(pszOwnerName));
      result := orSID;
      exit;
    end
    else
    //Any other error exits the function
    if (GetLastError() <> ERROR_INSUFFICIENT_BUFFER) then
      RaiseLastOsError;
  end;

  //Allocate memory for owner and domain
  //Take into account the size of a char type (like WideCHAR)
  GetMem(pszOwnerName, dwOwnerNameSize*sizeof(CHAR));
  try
    GetMem(pszDomainName, dwDomainNameSize*sizeof(CHAR));
    try
      //Retrieve name and domain
      Win32Check(LookupAccountSID(nil, pOwnerSID, pszOwnerName,
        dwOwnerNameSize, pszDomainName, dwDomainNameSize, OwnerType));

      result := orName;

      Domain   := pszDomainName;
      Username := pszOwnerName;
    finally
      FreeMem(pszDomainName);
    end;
  finally
    FreeMem(pszOwnerName);
  end;
end;
</pre>
<p>The function behaves the following:</p>
<ul>
<li>If an WinAPI error occurs the exception EOSError is thrown. You can retrieve the error value from its property Errorcode.</li>
<li>If the user name could be retrieved the result value is <em>orName</em> and both parameter <em>Domain </em>and <em>UserName</em> contain a value. Otherwise the result is orSID and only UserName contains the User Security Identifier (e.g. S-1-5-21-564352346-2735467565-567745764-1001).</li>
</ul>
<h2>JWSCL</h2>
<p>Of course, JWSCL wraps these function calls already. Thus the source size decreases rapidly. See another <a href="http://blog.delphi-jedi.net/2007/10/21/why-jwscl">example here</a>.<br />
In JWSCL it is quite different to implement the function. However the behaviour is equal:</p>
<pre class="brush:delphi">function JwsclGetFileOwner(const FileName: string;
  out Domain, Username: String): TOwnerResult;
var
  F : TJwSecureFileObject;
  Owner : TJwSecurityId;
begin
  F := TJwSecureFileObject.Create(FileName);
  try
    Owner := F.Owner; //Owner is cached/freed by TJwSecureFileObject
    try
      Domain := Owner.GetAccountDomainName();
      Username := Owner.GetAccountName();
      Result := orName;
    except
      on E : EJwsclWinCallFailedException do
      begin
        if E.LastError = ERROR_NONE_MAPPED then
        begin
          Domain := '';
          Username := Owner.StringSID;
          Result := orSID;
        end
        else
          raise;
      end;
    end;
  finally
    F.Free;
  end;
end;
</pre>
<p>In a next version of JWSCL (currently trunk) the exception handling will be a little bit different:</p>
<pre class="brush:delphi">function JwsclGetFileOwner2(const FileName: string;
  out Domain, Username: String): TOwnerResult;
var
  F : TJwSecureFileObject;
  Owner : TJwSecurityId;
begin
  F := TJwSecureFileObject.Create(FileName);
  try
    Owner := F.Owner; //Owner is cached/freed by TJwSecureFileObject
    try
      Domain := Owner.GetAccountDomainName();
      Username := Owner.GetAccountName();
      Result := orName;
    except
      on E : EJwsclSidNotMappedException do //not mapped error is handled differently
      begin
        Domain := '';
        Username := Owner.StringSID;
        Result := orSID;
      end;
    end;
  finally
    F.Free;
  end;
end;
</pre>
<p>If you use JWSCL (Version >= 0.9.2a) and enable the compiler switch <strong>JWSCL_SIDCACHE</strong> in file Include\Jwscl.inc, JWSCL will add a SID cache (for all TJwSecurityID instances globally). In this way LookupAccountSid will be called only once for every unknown SID and thus SIDs that were already translated are retrieved from cache instead.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2010/03/11/retrieving-file-owner/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JWSCL and FreeAndNil Second Attempt</title>
		<link>http://blog.delphi-jedi.net/2010/02/25/jwscl-and-freeandnil-second-attempt/</link>
		<comments>http://blog.delphi-jedi.net/2010/02/25/jwscl-and-freeandnil-second-attempt/#comments</comments>
		<pubDate>Thu, 25 Feb 2010 19:48:08 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[JEDI Windows API Headers]]></category>
		<category><![CDATA[JWA]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=665</guid>
		<description><![CDATA[In my last article &#8220;Jwscl and FreeAndNil&#8221; there were some great comments on the source design. Oliver told me to use a guarded memory page so the memory is always invalid. With his information I wrote a source code that creates a pointer which always triggers an access violation. Unfortunately, Access Violations are rather common [...]]]></description>
			<content:encoded><![CDATA[<p>In my last article &#8220;<a href="http://blog.delphi-jedi.net/2010/02/25/jwscl-and-freeandnil/" target="_blank">Jwscl and FreeAndNil</a>&#8221; there were some great comments on the source design. Oliver told me to use a guarded memory page so the memory is always invalid. With his information I wrote a source code that creates a pointer which always triggers an access violation.</p>
<p><span id="more-665"></span>Unfortunately, Access Violations are rather common and thus nobody can tell why it happens at a first glance. So I added an exception handler that maps this special access violation to a separate exception class (I called it EJwsclAccessedGuardPointerException).</p>
<pre class="brush:delphi">uses
  ExceptionLog,
  //JwaWindows, //or
  JwaWinBase, JwaWinNT, JwaNtStatus,
  SysUtils;

type
  EJwsclAccessedGuardPointerException = class(Exception)
  public
    ExceptionRecord: PExceptionRecord;
  end;

resourcestring
  SGuardPageException = 'It was tried to access a guarded pointer. This '+
   'pointer was freed previously and is now accessed without initialization. '+
   'JWSCL may guard its class members in this way. You should check for '+
   ' accesses to e.g. class members which instance was freed.'#13#10+
   'Exception was raised at this address: $%p';

var
  GuardPtr : Pointer;
  OldExcpObj : function (P: PExceptionRecord): Exception;
  OldExitProc : procedure;

procedure MyExitProcessProc;
begin
  VirtualFree(GuardPtr, 0, MEM_RELEASE);

  if @OldExitProc &lt;&gt; nil then
    OldExitProc;
end;

function MyGetExceptionObject(P: PExceptionRecord): Exception;
var ErrorCode : Integer;
begin
  if (P.ExceptionCode = STATUS_ACCESS_VIOLATION) and
    (P.ExceptObject = GuardPtr) then
  begin
    result := EJwsclAccessedGuardPointerException.CreateFmt(SGuardPageException,
        [P.ExceptionAddress]);
    EJwsclAccessedGuardPointerException(Result).ExceptionRecord := P;
  end
  else
  begin
    result := OldExcpObj(P);
  end;
end;

var
  T : TObject;
  SysInfo : TSystemInfo;
begin
  OldExcpObj := ExceptObjProc;
  ExceptObjProc := @MyGetExceptionObject;

  OldExitProc := ExitProcessProc;
  ExitProcessProc := MyExitProcessProc;

  //On 32Bit OS call
  //GetSystemInfo(@SysInfo);
  //On WOW64Bit OS call (use IsWow64Process)
  GetNativeSystemInfo(@SysInfo);

  GuardPtr := VirtualAlloc(
    Pointer($BADC0DE),//  __in_opt  LPVOID lpAddress,
    SysInfo.dwPageSize,//  __in      SIZE_T dwSize,
    MEM_RESERVE,//  __in      DWORD flAllocationType,
    PAGE_NOACCESS//  __in      DWORD flProtect
  );
  if GuardPtr = nil then
    RaiseLastOSError;

  T := TObject(Pointer(GuardPtr));
  T.Free;
end.
</pre>
<p>Since the object has this guard pointer value (which may be dynamic) a call to Free (or Destroy) will fail with the exception EJwsclAccessedGuardPointerException. Be aware that there is no actual memory allocated. It is all about virtual memory.</p>
<p>The MyExitProcessProc is called right before the process exits. There is another exit handler called ExitProc that is called before the units are finalized. So I&#8217;m stuck with ExitProcessProc which is fine though.</p>
<p>I must say that I like this approach since it seems to be safer than just using a nearly arbitrary magic value. The value is still there so you can see it as an invalid memory address in a debugger. However, Assigned or similar workarounds will not work because the memory location can vary.<br />
 And of course the exception message clearly states what happened here.  There could added more information like stack trace but that I leave to you (or the JCL).</p>
<p>Be aware that there still might be errors. This code is hot.  <img src='http://blog.delphi-jedi.net/wp-includes/images/smilies/icon_cool.gif' alt='8-)' class='wp-smiley' /> </p>
<p>What is your opinion?<br class="spacer_" /></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2010/02/25/jwscl-and-freeandnil-second-attempt/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Version Checking for Delphi (2nd Update)</title>
		<link>http://blog.delphi-jedi.net/2009/08/29/version-checking-for-delphi/</link>
		<comments>http://blog.delphi-jedi.net/2009/08/29/version-checking-for-delphi/#comments</comments>
		<pubDate>Sat, 29 Aug 2009 14:07:23 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[Common]]></category>
		<category><![CDATA[JEDI Windows API Headers]]></category>
		<category><![CDATA[JWA]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=392</guid>
		<description><![CDATA[There is an interesting article about checking the version of the operating system. If you are too lazy to read it then just remember this: Do not check it at all! Well, I changed my mind. You should read it! So go to Yochay Kiriaty&#8217;s Article, read it and then get back her for the [...]]]></description>
			<content:encoded><![CDATA[<p>There is an interesting article about checking the version of the operating system. If you are too lazy to read it then just remember this: Do not check it at all!<br />
 Well, I changed my mind. You should read it! So go to <a href="http://windowsteamblog.com/blogs/developers/archive/2009/08/05/version-checking-just-don-t-do-it.aspx" target="_blank">Yochay Kiriaty&#8217;s</a> Article, read it and then get back her for the Delphi part.</p>
<p><span id="more-392"></span>What have we learned from the article?</p>
<ol>
<li>Avoid version checks at all</li>
<li>Check for functionality</li>
<li>Use the right functions</li>
<li>Learn logic</li>
</ol>
<h3>1. It is always frustrating if an application doesn&#8217;t start because of version checking.</h3>
<p>If you have a Win32API function that is not available on older OS, do not use a version check. If you don&#8217;t dive the internal structures of Window it is very likely that your application will work.</p>
<h3>2. Instead: try to load the function with GetProcAddress. If it fails, well then use something else.</h3>
<p>That is the reason why I tell people to set the DYNAMIC_LINK compiler switch when using any of the JEDI functions. In this case the JEDI API libraries loads a function using <em>GetProcedureAddress </em>(located in JwaWinTypes &#8211; don&#8217;t ask me why it is located there).<br />
 GetProcedureAddress can raise two types of Exception.</p>
<ul>
<li>EJwaLoadLibraryError : If a necessary library could not be found.</li>
<li>EJwaGetProcAddressError : If the function could not be located in the library.</li>
</ul>
<p>So now it is easy to write an exception handler:</p>
<pre class="brush:delphi">try
  API_Call(...);
except
  on E1 : EJwaLoadLibraryError do
    //fail safe library not found
  on E2 : EJwaGetProcAddressError do
   //fail safe function not found
end;</pre>
<p>Well, this code only works if you define DYNAMIC_LINK in your project options. Don&#8217;t forget it! If it is not defined, and you try to run your application on an older Windows, it just won&#8217;t start. Instead you get a nasty error message.</p>
<p>Delphi 2010 comes with a new feature that MS Visual C++ people know as <a href="http://msdn.microsoft.com/en-us/library/151kt790.aspx" target="_blank">Linker support for Delay-loaded DLLs</a>.<br />
 Allen Bauer posted an article about this new feature for Delphi under the strange headline <a href="http://blogs.embarcadero.com/abauer/2009/08/25/38894" target="_blank">Procrastinators Unite… Eventually!</a> You can also think of it as &#8220;Delay loaded functions for Delphi&#8221;.</p>
<pre class="brush:delphi">function NewAPIFunction(Parameter : TParameter): BOOL; stdcall;
  external 'user32.dll' name 'NewAPIFunction' delayed;
...

begin
  NewAPIFunction(Parameter);
end;</pre>
<p>Do you recognize the new word &#8220;delayed&#8221; ? If you try to access the function for the first time, it will be loaded automatically from the library &#8220;user32.dll&#8221;. So we don&#8217;t have to be afraid of running the application on an older Windows version. Unfortunately, we also have to add code that checks for the Windows version.</p>
<pre class="brush:delphi">begin
  if OSVersion > 5.1 then
    NewAPIFunction(Parameter);
end;</pre>
<p><span style="font-size: x-small;">(Don&#8217;t be confused about <em>GreaterThan</em>. There is a </span><span style="font-size: x-small;">bug in the code </span><span style="font-size: x-small;">plugin that prevents the greater sign to be shown correctly.)</span></p>
<p>Haven&#8217;t we learned that it is not good to check for the OS version? Shouldn&#8217;t we check for functionality? Apparently, delay loading in Delphi 2010 wasn&#8217;t created with this idea in mind.<br />
 If we change the library name or the function name to something incorrect, like:</p>
<pre class="brush:delphi">function NewAPIFunction(Parameter : TParameter): BOOL; stdcall;
  external 'user32Bla.dll' name 'NewAPIFunction' delayed;
...

begin
  NewAPIFunction(Parameter);
end;</pre>
<p>&#8230;and call this function, at least, I get a nasty <em>EExternalException </em>with the message &#8220;External Exception C0FB007<strong>E</strong>&#8220;.<br />
 Even using the correct library but an incorrect function name doesn&#8217;t change the exception type, but the message :<br />
 &#8220;External Exception C0FB007<strong>F</strong>&#8220;.</p>
<p>Well, It could have been so nice! And in Update 2 we&#8217;re going to see how&#8230;</p>
<pre class="brush:delphi">function NewAPIFunction(Parameter : TParameter): BOOL; stdcall;
  external 'user32.dll' name 'NewAPIFunction' delayed;
...

begin
  try
    NewAPIFunction(Parameter);
  on E1 : ELoadLibraryError do
    //fail safe library not found
  on E2 : EGetProcAddressError do
   //fail safe function not found
end;</pre>
<p>Instead we need to check:</p>
<pre class="brush:delphi">function NewAPIFunction(Parameter : TParameter): BOOL; stdcall;
  external 'user32.dll' name 'NewAPIFunction' delayed;
...

begin
  try
    NewAPIFunction(Parameter);
  on E : EExternalException do
    //failsafe
end;</pre>
<p>However, I wouldn&#8217;t even be sure that this exception type is always the same. <em>EExternalException </em>is always suspect to me, isn&#8217;t it? So in the end it is all about <em>Exception</em>.</p>
<h2>UPDATE</h2>
<p>I was so short sighted! To the COM people  <em>C0FB007E</em> should look quite familiar. Yeah, it is a <a href="http://en.wikipedia.org/wiki/HRESULT" target="_blank">HRESULT</a> code. It maps to</p>
<p>Severity (ERROR_SEVERITY_ERROR = $C) + Facility Code ($FB) + Code (7E and 7F)</p>
<p>Well $7E is 126 in decimal and can be found in JwaWinError.pas as ERROR_MOD_NOT_FOUND. Same goes for $7F =127 which is ERROR_PROC_NOT_FOUND.</p>
<p>Knowing this we can use:</p>
<pre class="brush:delphi">begin
  try
    NewAPIFunction(Parameter);
  on E : EExternalException do
     RaiseLastOSError(Windows.HResultCode(E.ExceptionRecord.ExceptionCode));
  end;
end;</pre>
<p>This exception should be known to Delphi programmers. And you can add another try except block around to catch the Win32 exception.</p>
<p>The exception EExternalException comes from an internal call to <a href="http://msdn.microsoft.com/en-us/library/ms680552%28VS.85%29.aspx" target="_blank">RaiseException</a>.</p>
<h2>UPDATE2:</h2>
<p>If you read the system.pas file from Delphi 2010 you&#8217;ll find the function SetDliFailureHook. It allows us to get notified when an delayed loading error occured.  So how does it look?</p>
<pre class="brush:delphi">uses
  Windows,
  SysUtils;

type
  ELoadLibraryError = class(EWin32Error);
  EGetProcAddressError = class(EWin32Error);

function DelayedFailureHook(dliNotify: dliNotification; pdli: PDelayLoadInfo): Pointer; stdcall;
begin
  case dliNotify of
    dliNoteStartProcessing: ;
    dliNotePreLoadLibrary: ;
    dliNotePreGetProcAddress: ;
    dliFailLoadLibrary   :
      raise ELoadLibraryError.CreateFmt(
        'Failed to load library "%0:s".'#13#10' Error (%1:d) %2:s',[AnsiString(pdli.szDll),
          pdli.dwLastError, SysErrorMessage(pdli.dwLastError)]);
    dliFailGetProcAddress:
      if pdli.dlp.fImportByName then
        raise EGetProcAddressError.CreateFmt(
            'Failed to load function "%0:s" from "%1:s"'#13#10' Error (%2:d) %3:s',[
           AnsiString(pdli.dlp.szProcName), AnsiString(pdli.szDll),
          pdli.dwLastError, SysErrorMessage(pdli.dwLastError)])
      else
        raise EGetProcAddressError.CreateFmt(
            'Failed to load function #%0:d from "%1:s"'#13#10' Error (%2:d) %3:s',[
           pdli.dlp.dwOrdinal, AnsiString(pdli.szDll),
          pdli.dwLastError, SysErrorMessage(pdli.dwLastError)]);

    dliNoteEndProcessing: ;
  end;
end;

...
begin
  SetDliFailureHook(DelayedFailureHook);

  try
    NewAPIFunction(Parameter);
  on E1 : ELoadLibraryError do
    //fail safe library not found
  on E2 : EGetProcAddressError do
   //fail safe function not found
  end;
end.</pre>
<p>All the other errors we don&#8217;t process are converted to an EExternalException error automatically. You can try it out by removing the case dliFailLoadLibrary or dliFailGetProcAddress.</p>
<p>By the way:</p>
<ol>
<li> The function pointer of NewAPIFunction is not nil. It points to an address that does the magic behind the curtain.</li>
<li>If you wonder why the JEDI Windows API hasn&#8217;t implemented this feature: We are still in pre alpha stage.<br />
 You could help by telling us your experience with this feature.</li>
</ol>
<h3>3. Using the right functions can be a bit problematic. There are a lot of possible functions you can use:</h3>
<ol>
<li>JwaWinBase/Windows contains GetVersion and GetVersionEx</li>
<li>There is also a more complex function called VerifyVersionInfo(Ex)</li>
<li>And Delphi comes with a function of its own in SysUtils :  CheckWin32Version</li>
</ol>
<p>CheckWin32Version is little known to Delphi programmers. Instead they create their own complicated classes and tool functions. But if you just want to check for the major and minor version of the OS, try this:</p>
<pre class="brush:delphi">if CheckWin32Version(5, 1) then</pre>
<p>It checks for Windows XP regardless of a service pack. It is the easiest and safest way to check the OS version. But sometimes you need also to know the service pack or even more.</p>
<p>GetVersion and GetVersionEx can be hard to be used. So Microsoft added support for a more flexible and safe way to check the OS version. VerifyVersionInfo was born.</p>
<p>I have translated Yochay Kiriaty&#8217;s example of VerifyVersionInfo for you.</p>
<pre class="brush:delphi">uses
  JwaWinNT,
  JwaNative,
  JwaWinBase;

function IsWindowsXPorLater : Boolean;
const
  Condition = VER_GREATER_EQUAL;
var
  OSInfo : TOSVersionInfoEx;
  ConditionMask : Int64;
begin
  ZeroMemory(@OsInfo, sizeof(OSInfo));
  OSInfo.dwOSVersionInfoSize := SizeOf(OSInfo);
  OSInfo.dwMajorVersion := 5;
  OSInfo.dwMinorVersion := 1;
  OSInfo.wServicePackMajor := 1;
  OSInfo.wServicePackMinor := 0;

  ConditionMask := 0;
  ConditionMask := VerSetConditionMask(ConditionMask, VER_MAJORVERSION, Condition);
  ConditionMask := VerSetConditionMask(ConditionMask, VER_MINORVERSION, Condition);
  ConditionMask := VerSetConditionMask(ConditionMask, VER_SERVICEPACKMAJOR, Condition);
  ConditionMask := VerSetConditionMask(ConditionMask, VER_SERVICEPACKMINOR, Condition);

  result := VerifyVersionInfo(OSInfo, VER_MAJORVERSION or VER_MINORVERSION or
     VER_SERVICEPACKMAJOR or VER_SERVICEPACKMINOR,
     ConditionMask);
end;</pre>
<p>I hope more people are going to use this function.</p>
<h3>4. In the end I also want to write something about logic.</h3>
<p>If you wonder why so many applications ceased to work when Windows Vista came out. Well, if you look at this code you should know why (Windows XP: 5.1 -&gt; Vista: 6.0)</p>
<pre class="brush:delphi"> if (MajorVersion >= 5) and (MinorVersion >= 1) then
 begin 'OK'
 end
 else
 begin
 'Sorry. Old Windows version detected'
 end;</pre>
<p>Well, such a (similar) code is (still) used a lot of times. And it seems to work for Windows 2000 and XP. But in Vista MajorVersion was changed to 6 and, because it was the very first release of version 6, MinorVersion was set to zero. So the if condition stopped working on the second condition check. (BTW: This is a reason why Windows 7 is using version 6.1 instead of version 7.0 .)<br />
 Sometimes we need to apply the <a href="http://en.wikipedia.org/wiki/Mathematical_logic">basic rules of logic</a> (read a good book from <a href="http://www.amazon.co.uk/s/ref=nb_ss?url=search-alias%3Dstripbooks&amp;field-keywords=logic&amp;x=19&amp;y=16">Amazon</a>) or check (nearly) all possible values in a table:</p>
<table style="text-align: center;" border="0">
<thead>
<tr class="wp-caption">
<td>MajorVersion</td>
<td>MinorVersion</td>
<td>Condition Result</td>
</tr>
</thead>
<tbody>
<tr>
<td>&#8230;</td>
<td>&#8230;</td>
<td>&#8230;</td>
</tr>
<tr>
<td>4</td>
<td>1</td>
<td>False</td>
</tr>
<tr>
<td>4</td>
<td>2</td>
<td>False</td>
</tr>
<tr>
<td>4</td>
<td>3</td>
<td>False</td>
</tr>
<tr>
<td>5</td>
<td>0</td>
<td>False</td>
</tr>
<tr>
<td>5</td>
<td>1</td>
<td>True</td>
</tr>
<tr>
<td>5</td>
<td>2</td>
<td>True</td>
</tr>
<tr>
<td>5</td>
<td>3</td>
<td>True</td>
</tr>
<tr>
<td>6</td>
<td>0</td>
<td>False</td>
</tr>
<tr>
<td>6</td>
<td>1</td>
<td>True</td>
</tr>
<tr>
<td>7</td>
<td>0</td>
<td>False</td>
</tr>
<tr>
<td>7</td>
<td>1</td>
<td>True</td>
</tr>
</tbody>
</table>
<p>Not all Windows versions in this table really exists. But how could you know that at that time? So make the table as complete as possible. Then you can change the variables <em>Win32MajorVersion </em>and <em>Win32MinorVersion </em>to the test your if condition and run your application. Software engineers also use unit tests to check the <span style="text-decoration: line-through;">correctness</span> efficiency of their functions.</p>
<p>All in all, if the people of the bad applications had used a function like CheckWin32Version, we hadn&#8217;t this article now:</p>
<pre class="brush:delphi">function CheckWin32Version(AMajor: Integer; AMinor: Integer = 0): Boolean;
 begin
 Result := (Win32MajorVersion >AMajor) or
 ((Win32MajorVersion = AMajor) and
 (Win32MinorVersion >= AMinor));
 end;</pre>
<p>But then we couldn&#8217;t blame Microsoft for their bad compatibility. *g*</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2009/08/29/version-checking-for-delphi/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Winlogon Notification Package</title>
		<link>http://blog.delphi-jedi.net/2008/05/27/winlogon-notification-package/</link>
		<comments>http://blog.delphi-jedi.net/2008/05/27/winlogon-notification-package/#comments</comments>
		<pubDate>Tue, 27 May 2008 18:07:05 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[JEDI Windows API Headers]]></category>
		<category><![CDATA[JWA Downloads]]></category>
		<category><![CDATA[JWA]]></category>
		<category><![CDATA[winlogon]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=234</guid>
		<description><![CDATA[What is that? MSDN say&#8217;s: A Winlogon Notification Package is a DLL that exports functions that handle Winlogon events. For example, when a user logs onto the system, Winlogon calls each notification package&#8217;s logon event handler function to provide information about the event. So you might know, the mechanism of Winlogon Notification Package is available [...]]]></description>
			<content:encoded><![CDATA[<p><strong>What is that? MSDN say&#8217;s: </strong><em>A Winlogon Notification Package is a DLL that exports functions that handle Winlogon events. For example, when a user logs onto the system, Winlogon calls each notification package&#8217;s logon event handler function to provide information about the event.</em></p>
<p><span id="more-234"></span></p>
<p>So you might know, the mechanism of Winlogon Notification Package is available in Windows 2000, Windows XP and Windows 2003 Server. In contrast to Windows Vista, it is completely different, maybe I’ll come back with separate tutorial describing how to build a notification package for Windows Vista.</p>
<p>I&#8217;m going to demonstrate here, how to create such a notification package and as a special gift, we will learn how to create a PNG image with drop shadow effect, which we will use later to draw a transparent window inside the Winlogon Desktop.</p>
<p><a href="http://blog.delphi-jedi.net/wp-content/uploads/2008/05/capture.jpg"><img class="alignnone size-thumbnail wp-image-230" title="capture" src="http://blog.delphi-jedi.net/wp-content/uploads/2008/05/capture.jpg" alt="Winlogon" width="301" height="221" /></a></p>
<p>It&#8217;s time for our <strong>Winlogon Notification Package</strong>. Start Delphi and create a new DLL project.</p>
<p>What we need to do next is to define the Message Callback and the WLXNotificationInfo, as described in <a href="http://msdn.microsoft.com/en-us/library/aa381183(VS.85).aspx">MSDN</a></p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">Type</span><br />
<span class="co1">// this callback function does not return a value as described on mdsn.</span></p>
<p>&nbsp; TFnMsgeCallback = <span class="kw1">function</span> <span class="br0">&#40;</span>bVerbose: <span class="kw4">Boolean</span>; lpMessage: <span class="kw4">PWideChar</span><span class="br0">&#41;</span>: <span class="kw4">Cardinal</span>; <span class="kw1">stdcall</span>;</p>
<p><span class="co1">// this structure stores information about a Winlogon event.</span></p>
<p>TWlxNotificationInfo = <span class="kw1">record</span><br />
&nbsp; &nbsp; Size: <span class="kw4">Cardinal</span>;<br />
&nbsp; &nbsp; Flags: <span class="kw4">Cardinal</span>;<br />
&nbsp; &nbsp; UserName: <span class="kw4">PWideChar</span>;<br />
&nbsp; &nbsp; Domain: <span class="kw4">PWideChar</span>;<br />
&nbsp; &nbsp; WindowStation: <span class="kw4">PWideChar</span>;<br />
&nbsp; &nbsp; Token: <span class="kw4">Cardinal</span>;<br />
&nbsp; &nbsp; Desktop: <span class="kw4">Cardinal</span>;<br />
&nbsp; &nbsp; StatusCallback: TFnMsgeCallback;<br />
&nbsp; <span class="kw1">end</span>;<br />
&nbsp; PWlxNotificationInfo = ^TWlxNotificationInfo;</p>
<p><span class="coMULTI">{ &nbsp;winlogon can inform about the following events:<br />
Lock,<br />
Lockoff,<br />
Logon,<br />
Shutdown,<br />
StartScreensave,<br />
StartShell,<br />
StartUp,<br />
StopScreenSaver,<br />
Unlock</p>
<p>For a complete describtion of those events look at: </p>
<p>http://msdn.microsoft.com/en-us/library/aa380544(VS.85).aspx<br />
}</span></p>
<p><span class="co1">// example of handling the Logon Message</span></p>
<p><span class="kw1">procedure</span> LogonHandler<span class="br0">&#40;</span>Info: PWlxNotificationInfo<span class="br0">&#41;</span>; <span class="kw1">stdcall</span>;<br />
<span class="kw1">begin</span></p>
<p><span class="kw1">end</span>;</p>
<p><span class="co1">// the entrance function for DLL</span></p>
<p><span class="kw1">procedure</span> EntryPointProc<span class="br0">&#40;</span>reason: <span class="kw4">integer</span><span class="br0">&#41;</span>;<br />
<span class="kw1">begin</span><br />
&nbsp; <span class="kw1">case</span> reason <span class="kw1">of</span><br />
&nbsp; &nbsp; DLL_PROCESS_ATTACH: &nbsp;<span class="co1">//1</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">Begin</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">// Disable DLL_THREAD_ATTACH &amp;amp; DLL_THREAD_DETACH</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">// notification calls. This is a performance optimization</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">// for multithreaded applications that do not need</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">// thread-level notifications of attachment or</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">// detachment.</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; DisableThreadLibraryCalls<span class="br0">&#40;</span>hInstance<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; <span class="kw1">end</span>;<br />
&nbsp; &nbsp; DLL_THREAD_ATTACH: &nbsp; <span class="co1">//2</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">begin</span></p>
<p>&nbsp; &nbsp; &nbsp; <span class="kw1">end</span>;<br />
&nbsp; &nbsp; DLL_PROCESS_DETACH: &nbsp;<span class="co1">//3</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">begin</span></p>
<p>&nbsp; &nbsp; &nbsp; <span class="kw1">end</span>;<br />
&nbsp; &nbsp; DLL_THREAD_DETACH: &nbsp; <span class="co1">//0</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">begin</span></p>
<p>&nbsp; &nbsp; &nbsp; <span class="kw1">end</span>;<br />
&nbsp; <span class="kw1">end</span>;</p>
<p><span class="kw1">end</span>;</p>
<p><span class="co1">// define the exports for the DLL</span></p>
<p>exports<br />
&nbsp; LogonHandler;</p>
<p><span class="kw1">begin</span><br />
&nbsp; DllProc := @EntryPointProc;<br />
&nbsp; DllProc<span class="br0">&#40;</span>DLL_PROCESS_ATTACH<span class="br0">&#41;</span>;<br />
<span class="kw1">end</span>.</div>
<p>Our Prototype, is ready to use. The compiled DLL has to be in the following folder:</p>
<p style="padding-left: 30px;"><strong> C:\Windows\System32 </strong>(adapt it to your environment)<strong><br />
</strong></p>
<p>Now we can inform the operating system that we created a <strong>Winlogon Notification Package. </strong>This step will be done in the registry under the following key:</p>
<p style="padding-left: 30px;"><strong>HKey_Local_Machine\Software\Microsoft\WindowsNT\<br />
CurrentVersion\Winlogon\Notify\YourNotification </strong></p>
<table class="MsoTableMediumList2Accent1" style="border: medium none; width: 73.16%; border-collapse: collapse;" border="1" cellspacing="0" cellpadding="0" width="73%">
<tbody>
<tr>
<td style="padding: 0cm 5.4pt; background: white none repeat scroll 0%; width: 21.78%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; border: medium medium 3pt none none solid -moz-use-text-color -moz-use-text-color #4f81bd;" width="21%" valign="top">
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"><span lang="EN-US">Name</span></p>
</td>
<td style="padding: 0cm 5.4pt; background: white none repeat scroll 0%; width: 20.94%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; border: medium medium 3pt none none solid -moz-use-text-color -moz-use-text-color #4f81bd;" width="20%" valign="top">
<p class="MsoNormal" style="margin-bottom: 0.0001pt; text-align: center; line-height: normal;" align="center"><span lang="EN-US">Type</span></p>
</td>
<td style="padding: 0cm 5.4pt; background: white none repeat scroll 0%; width: 57.28%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; border: medium medium 3pt none none solid -moz-use-text-color -moz-use-text-color #4f81bd;" width="57%" valign="top">
<p class="MsoNormal" style="margin-bottom: 0.0001pt; text-align: center; line-height: normal;" align="center"><span lang="EN-US">Value</span></p>
</td>
</tr>
<tr>
<td style="padding: 0cm 5.4pt; background: white none repeat scroll 0%; width: 21.78%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; border: medium 1pt medium medium none solid none none -moz-use-text-color #4f81bd -moz-use-text-color -moz-use-text-color;" width="21%" valign="top">
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"><span lang="EN-US">DLLName</span></p>
</td>
<td style="border: medium none; padding: 0cm 5.4pt; background: #d3dfee none repeat scroll 0%; width: 20.94%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" width="20%" valign="top">
<p class="MsoNormal" style="margin-bottom: 0.0001pt; text-align: center; line-height: normal;" align="center"><span lang="EN-US">REG_SZ</span></p>
</td>
<td style="padding: 0cm 5.4pt; background: #d3dfee none repeat scroll 0%; width: 57.28%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; border: medium 1pt medium medium none solid none none -moz-use-text-color #4f81bd -moz-use-text-color -moz-use-text-color;" width="57%" valign="top">
<p class="MsoNormal" style="margin-bottom: 0.0001pt; text-align: center; line-height: normal;" align="center"><span lang="EN-US">C:\Windows\System32\YourDLLName.dll</span></p>
</td>
</tr>
<tr>
<td style="padding: 0cm 5.4pt; background: white none repeat scroll 0%; width: 21.78%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; border: medium 1pt medium medium none solid none none -moz-use-text-color #4f81bd -moz-use-text-color -moz-use-text-color;" width="21%" valign="top">
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"><span lang="EN-US">Asynchronous</span></p>
</td>
<td style="border: medium none; padding: 0cm 5.4pt; width: 20.94%;" width="20%" valign="top">
<p class="MsoNormal" style="margin-bottom: 0.0001pt; text-align: center; line-height: normal;" align="center"><span lang="EN-US">REG_DWORD</span></p>
</td>
<td style="padding: 0cm 5.4pt; width: 57.28%; border: medium 1pt medium medium none solid none none -moz-use-text-color #4f81bd -moz-use-text-color -moz-use-text-color;" width="57%" valign="top">
<p class="MsoNormal" style="margin-bottom: 0.0001pt; text-align: center; line-height: normal;" align="center"><span lang="EN-US">0</span></p>
</td>
</tr>
<tr>
<td style="padding: 0cm 5.4pt; background: white none repeat scroll 0%; width: 21.78%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; border: medium 1pt medium medium none solid none none -moz-use-text-color #4f81bd -moz-use-text-color -moz-use-text-color;" width="21%" valign="top">
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"><span lang="EN-US">Impersonate</span></p>
</td>
<td style="border: medium none; padding: 0cm 5.4pt; background: #d3dfee none repeat scroll 0%; width: 20.94%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" width="20%" valign="top">
<p class="MsoNormal" style="margin-bottom: 0.0001pt; text-align: center; line-height: normal;" align="center"><span lang="EN-US">REG_DWORD</span></p>
</td>
<td style="padding: 0cm 5.4pt; background: #d3dfee none repeat scroll 0%; width: 57.28%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; border: medium 1pt medium medium none solid none none -moz-use-text-color #4f81bd -moz-use-text-color -moz-use-text-color;" width="57%" valign="top">
<p class="MsoNormal" style="margin-bottom: 0.0001pt; text-align: center; line-height: normal;" align="center"><span lang="EN-US">0</span></p>
</td>
</tr>
<tr>
<td style="padding: 0cm 5.4pt; background: white none repeat scroll 0%; width: 21.78%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; border: medium 1pt medium medium none solid none none -moz-use-text-color #4f81bd -moz-use-text-color -moz-use-text-color;" width="21%" valign="top">
<p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"><span style="color: black;">Logon</span></p>
</td>
<td style="padding: 0cm 5.4pt; width: 20.94%; border: medium medium 1pt none none solid -moz-use-text-color -moz-use-text-color #4f81bd;" width="20%" valign="top">
<p class="MsoNormal" style="margin-bottom: 0.0001pt; text-align: center; line-height: normal;" align="center"><span lang="EN-US">REG_SZ</span></p>
</td>
<td style="padding: 0cm 5.4pt; width: 57.28%; border: medium 1pt 1pt medium none solid solid none -moz-use-text-color #4f81bd #4f81bd -moz-use-text-color;" width="57%" valign="top">
<p class="MsoNormal" style="margin-bottom: 0.0001pt; text-align: center; line-height: normal;" align="center"><span style="color: black;">LogonHandler</span></p>
</td>
</tr>
</tbody>
</table>
<p>The valid values are described in this <a href="http://msdn.microsoft.com/en-us/library/aa379402(VS.85).aspx">MSDN article.</a></p>
<p><strong>Creating the PNG Image</strong></p>
<p>For completing this Project you will need to download the following:</p>
<p><strong>Graphics32 Library</strong><br />
<em>Graphics32 is a graphics library for Delphi and Kylix/CLX. Optimized for 32-bit pixel formats, it provides fast operations with pixels and graphic primitives. In most cases Graphics32 considerably outperforms the standard TBitmap/TCanvas methods.</em></p>
<p><strong>PNG Components<br />
</strong><em>Delphi VCL Components with PNG Image support.</em></p>
<p>What you&#8217;ll need is an already exisiting PNG or a new one. I&#8217;ll use with the <a href="http://blog.delphi-jedi.net/home/">Jedi Api WSCL Logo</a>.<br />
Open the Logo in Photoshop but remember this can be done in almost any other Graphic Application which supports PNG and layer based drawing.</p>
<p>The Logo from this site is already a PNG, so you will see a transparent background when it is opened in Photoshop. If you like to add a drop shadow style to it, you won&#8217;t see it,because of the mentioned transparent background. It is also a problem on a black background, btw. So first thing to do is to add a temporary background layer into the Logo. To do so, click on the &#8220;<strong>Create New Layer Symbol</strong>&#8221; in the layer palette (indicated as a small notepad icon).</p>
<p>Now select the new created layer by clicking on it and drag it behind the Logo layer. With the new layer still selected, switch to the &#8220;Tools Window&#8221; and select the &#8220;<strong>Paint Bucket Tool</strong>&#8220;. Select white as your foreground color. If you have another color as foreground color, <strong>simply press d and then x</strong>. In this way it will reset the foreground and backgound colors. Now click inside your image on the transparent part and you&#8217;ll see the Logo with a white background applied.</p>
<p>Switch to your layers palette and double click on the Logo layer. The &#8220;Layers Styles Dialog&#8221; should be visible now. Select &#8220;Drop Shadow&#8221; and you can adjust the angle of the drop shadow and its size. While you adjust it, also watch the Logo. Photoshop shows you a preview of the changes. If you&#8217;re satisfied with your settings hit ok.</p>
<p>At this time, we don&#8217;t need our white background layer anymore, so select it and drag it to the trash can symbol in the layer palette. It will be deleted then. Afterwards save the Logo, select PNG as the file format and a new window will appear (PNG Options). Select none and hit ok.</p>
<p>There also exists a small <a href="#Downloads">video presentation</a> which will help you<strong>.</strong></p>
<p><strong>Drawing the PNG onto the Form Canvas</strong></p>
<p>The following source is kindly provided by <strong>Coder90</strong>. He wrote a nice example in a german delphi <a href="http://www.delphipraxis.net/post606056.html#606056">forum<br />
</a></p>
<p><strong>The Sources<br />
</strong>I won&#8217;t go into any details here, basically the procedure will load the PNG into a Bitmap32 Object and blends it to the forms canvas.</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">Type</span><br />
<span class="kw1">interface</span></p>
<p><span class="kw1">uses</span><br />
&nbsp; Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,<br />
&nbsp; Dialogs, ExtCtrls, StdCtrls, GR32;</p>
<p>&nbsp; <span class="kw1">public</span><br />
&nbsp; &nbsp; <span class="coMULTI">{ Public declarations }</span><br />
&nbsp; &nbsp; BMP32 : TBitmap32;<br />
&nbsp; &nbsp; BlendF: TBlendFunction;<br />
&nbsp; &nbsp; P: TPoint;<br />
&nbsp; &nbsp; Size: TSize;<br />
&nbsp; &nbsp; <span class="kw1">procedure</span> BlendIt;<br />
&nbsp; <span class="kw1">end</span>;</p>
<p>&nbsp; <span class="kw1">procedure</span> LoadPNGintoBitmap32<span class="br0">&#40;</span>DstBitmap: TBitmap32;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Filename: <span class="kw4">String</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out AlphaChannelUsed: <span class="kw4">Boolean</span><span class="br0">&#41;</span>; <span class="kw1">overload</span>;</p>
<p>&nbsp; <span class="kw1">procedure</span> LoadPNGintoBitmap32<span class="br0">&#40;</span>DstBitmap: TBitmap32;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SrcStream: TStream;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out AlphaChannelUsed: <span class="kw4">Boolean</span><span class="br0">&#41;</span>; <span class="kw1">overload</span>;</p>
<p>&nbsp; <span class="kw1">procedure</span> LoadPNGintoBitmap32<span class="br0">&#40;</span>DstBitmap: TBitmap32;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; szSection : <span class="kw4">PChar</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; szName &nbsp; &nbsp;: <span class="kw4">String</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out AlphaChannelUsed: <span class="kw4">Boolean</span><span class="br0">&#41;</span>; <span class="kw1">overload</span>;</p>
<p><span class="kw1">uses</span> PNGImage;</p>
<p><span class="kw1">procedure</span> LoadPNGintoBitmap32<span class="br0">&#40;</span>DstBitmap: TBitmap32;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SrcStream: TStream;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out AlphaChannelUsed: <span class="kw4">Boolean</span><span class="br0">&#41;</span>;<br />
<span class="kw1">var</span><br />
&nbsp; PNGObject: TPNGObject;<br />
&nbsp; TransparentColor: TColor32;<br />
&nbsp; PixelPtr: PColor32;<br />
&nbsp; AlphaPtr: <span class="kw4">PByte</span>;<br />
&nbsp; X, Y: <span class="kw4">Integer</span>;<br />
<span class="kw1">begin</span><br />
&nbsp; PNGObject := <span class="kw2">nil</span>;<br />
&nbsp; <span class="kw1">try</span><br />
&nbsp; &nbsp; PNGObject := TPngObject.<span class="me1">Create</span>;<br />
&nbsp; &nbsp; PNGObject.<span class="me1">LoadFromStream</span><span class="br0">&#40;</span>SrcStream<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; DstBitmap.<span class="me1">Assign</span><span class="br0">&#40;</span>PNGObject<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; DstBitmap.<span class="me1">ResetAlpha</span>;</p>
<p>&nbsp; &nbsp; <span class="kw1">case</span> PNGObject.<span class="me1">TransparencyMode</span> <span class="kw1">of</span><br />
&nbsp; &nbsp; &nbsp; ptmPartial:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">begin</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>PNGObject.<span class="me1">Header</span>.<span class="me1">ColorType</span> = COLOR_GRAYSCALEALPHA<span class="br0">&#41;</span> <span class="kw1">or</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span>PNGObject.<span class="me1">Header</span>.<span class="me1">ColorType</span> = COLOR_RGBALPHA<span class="br0">&#41;</span> <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">begin</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PixelPtr := PColor32<span class="br0">&#40;</span>@DstBitmap.<span class="me1">Bits</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> Y := <span class="nu0">0</span> <span class="kw1">to</span> DstBitmap.<span class="me1">Height</span> &#8211; <span class="nu0">1</span> <span class="kw1">do</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">begin</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; AlphaPtr := <span class="kw4">PByte</span><span class="br0">&#40;</span>PNGObject.<span class="me1">AlphaScanline</span><span class="br0">&#91;</span>Y<span class="br0">&#93;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> X := <span class="nu0">0</span> <span class="kw1">to</span> DstBitmap.<span class="me1">Width</span> &#8211; <span class="nu0">1</span> <span class="kw1">do</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">begin</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PixelPtr^ := <span class="br0">&#40;</span>PixelPtr^ <span class="kw1">and</span> <span class="re0">$00FFFFFF</span><span class="br0">&#41;</span> <span class="kw1">or</span> <span class="br0">&#40;</span>TColor32<span class="br0">&#40;</span>AlphaPtr^<span class="br0">&#41;</span> <span class="kw1">shl</span> <span class="nu0">24</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">Inc</span><span class="br0">&#40;</span>PixelPtr<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">Inc</span><span class="br0">&#40;</span>AlphaPtr<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">end</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">end</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; AlphaChannelUsed := <span class="kw2">True</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">end</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">end</span>;<br />
&nbsp; &nbsp; &nbsp; ptmBit:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">begin</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TransparentColor := Color32<span class="br0">&#40;</span>PNGObject.<span class="me1">TransparentColor</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PixelPtr := PColor32<span class="br0">&#40;</span>@DstBitmap.<span class="me1">Bits</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> X := <span class="nu0">0</span> <span class="kw1">to</span> <span class="br0">&#40;</span>DstBitmap.<span class="me1">Height</span> &#8211; <span class="nu0">1</span><span class="br0">&#41;</span> * <span class="br0">&#40;</span>DstBitmap.<span class="me1">Width</span> &#8211; <span class="nu0">1</span><span class="br0">&#41;</span> <span class="kw1">do</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">begin</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> PixelPtr^ = TransparentColor <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PixelPtr^ := PixelPtr^ <span class="kw1">and</span> <span class="re0">$00FFFFFF</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">Inc</span><span class="br0">&#40;</span>PixelPtr<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">end</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; AlphaChannelUsed := <span class="kw2">True</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">end</span>;<br />
&nbsp; &nbsp; &nbsp; ptmNone:<br />
&nbsp; &nbsp; &nbsp; &nbsp; AlphaChannelUsed := <span class="kw2">False</span>;<br />
&nbsp; &nbsp; <span class="kw1">end</span>;<br />
&nbsp; <span class="kw1">finally</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="kw3">Assigned</span><span class="br0">&#40;</span>PNGObject<span class="br0">&#41;</span> <span class="kw1">then</span> PNGObject.<span class="me1">Free</span>;<br />
&nbsp; <span class="kw1">end</span>;<br />
<span class="kw1">end</span>;</p>
<p><span class="kw1">procedure</span> LoadPNGintoBitmap32<span class="br0">&#40;</span>DstBitmap: TBitmap32;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Filename: <span class="kw4">String</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out AlphaChannelUsed: <span class="kw4">Boolean</span><span class="br0">&#41;</span>;<br />
<span class="kw1">var</span><br />
&nbsp; FileStream: TFileStream;<br />
<span class="kw1">begin</span><br />
&nbsp; FileStream := TFileStream.<span class="me1">Create</span><span class="br0">&#40;</span>Filename, fmOpenRead<span class="br0">&#41;</span>;<br />
&nbsp; <span class="kw1">try</span><br />
&nbsp; &nbsp; LoadPNGintoBitmap32<span class="br0">&#40;</span>DstBitmap, FileStream, AlphaChannelUsed<span class="br0">&#41;</span>;<br />
&nbsp; <span class="kw1">finally</span><br />
&nbsp; &nbsp; FileStream.<span class="me1">Free</span>;<br />
&nbsp; <span class="kw1">end</span>;<br />
<span class="kw1">end</span>;</p>
<p><span class="kw1">procedure</span> LoadPNGintoBitmap32<span class="br0">&#40;</span>DstBitmap: TBitmap32;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; szSection : <span class="kw4">PChar</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; szName &nbsp; &nbsp;: <span class="kw4">String</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out AlphaChannelUsed: <span class="kw4">Boolean</span><span class="br0">&#41;</span>;<br />
<span class="kw1">var</span><br />
&nbsp; Stream: TResourceStream;<br />
<span class="kw1">begin</span><br />
&nbsp; Stream := TResourceStream.<span class="me1">Create</span><span class="br0">&#40;</span>hInstance, szName, <span class="kw4">PChar</span><span class="br0">&#40;</span>szSection<span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; <span class="kw1">try</span><br />
&nbsp; &nbsp; LoadPNGintoBitmap32<span class="br0">&#40;</span>DstBitmap, Stream, AlphaChannelUsed<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="kw1">finally</span><br />
&nbsp; &nbsp; &nbsp;Stream.<span class="me1">Free</span>;<br />
&nbsp; &nbsp;<span class="kw1">end</span>;<br />
<span class="kw1">end</span>;</p>
<p><span class="coMULTI">{ Works only Win2000_Up }</span></p>
<p><span class="kw1">procedure</span> TForm1.<span class="me1">BlendIt</span>;<br />
&nbsp; <span class="kw1">var</span><br />
&nbsp; &nbsp; Alpha: <span class="kw4">Boolean</span>;<br />
<span class="kw1">begin</span><br />
&nbsp; BMP32 := TBitmap32.<span class="me1">Create</span>;<br />
&nbsp;<span class="coMULTI">{Load PNG from File<br />
&nbsp; LoadPNGintoBitmap32(BMP32, ExtractFilePath(ParamStr(0)) + &#8216;WSCL.png&#8217;, Alpha);<br />
&nbsp;}</span><br />
&nbsp; <span class="co1">// Load PNG From Resource</span><br />
&nbsp; LoadPNGintoBitmap32<span class="br0">&#40;</span>BMP32, <span class="kw4">PChar</span><span class="br0">&#40;</span><span class="st0">&#8216;PNG&#8217;</span><span class="br0">&#41;</span>, <span class="st0">&#8216;WSCL&#8217;</span>, Alpha<span class="br0">&#41;</span>;</p>
<p>&nbsp; setWindowLong<span class="br0">&#40;</span>Handle, GWL_EXSTYLE,<br />
&nbsp; getWindowLong<span class="br0">&#40;</span>Handle, GWL_EXSTYLE<span class="br0">&#41;</span> <span class="kw1">or</span> WS_EX_LAYERED <span class="coMULTI">{or WS_EX_TRANSPARENT}</span><span class="br0">&#41;</span>;<br />
&nbsp; <span class="co1">// WS_EX_TRANSPARENT makes the Window for MouseClicks transparent&#8230;</span></p>
<p>&nbsp; BlendF.<span class="me1">BlendOp</span> := AC_SRC_OVER;<br />
&nbsp; BlendF.<span class="me1">BlendFlags</span> := <span class="nu0">0</span>;<br />
&nbsp; BlendF.<span class="me1">SourceConstantAlpha</span> := <span class="nu0">255</span>;<br />
&nbsp; BlendF.<span class="me1">AlphaFormat</span> := AC_SRC_ALPHA;<br />
&nbsp; P := Point<span class="br0">&#40;</span><span class="nu0">0</span>, <span class="nu0">0</span><span class="br0">&#41;</span>;<br />
&nbsp; Size.<span class="me1">cx</span> := BMP32.<span class="me1">Width</span>;<br />
&nbsp; Size.<span class="me1">cy</span> := BMP32.<span class="me1">Height</span>;</p>
<p>&nbsp; UpdateLayeredWindow<span class="br0">&#40;</span>Handle, <span class="nu0">0</span>, <span class="kw2">nil</span>, @Size, BMP32.<span class="me1">Handle</span>, @P, <span class="nu0">0</span>, @BlendF, ULW_ALPHA<span class="br0">&#41;</span>;</p>
<p>&nbsp; <span class="co1">// Set Window on Top</span><br />
&nbsp; SetWindowPos<span class="br0">&#40;</span>Handle, HWND_TOPMOST, Left, Top, Width, Height,<br />
&nbsp; SWP_NOACTIVATE <span class="kw1">or</span> SWP_NOMOVE <span class="kw1">or</span> SWP_NOSIZE<span class="br0">&#41;</span>;</p>
<p>&nbsp; <span class="co1">// Set Parent to Desktop</span><br />
&nbsp; SetWindowLong<span class="br0">&#40;</span>Handle, GWL_HWNDPARENT, <span class="nu0">0</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; <span class="co1">// Hide Window from Taskbar</span><br />
&nbsp; SetWindowLong<span class="br0">&#40;</span>Handle, GWL_EXSTYLE,<br />
&nbsp; GetWindowLong<span class="br0">&#40;</span>Handle, GWL_EXSTYLE<span class="br0">&#41;</span> <span class="kw1">or</span><br />
&nbsp; WS_EX_TOOLWINDOW <span class="kw1">and</span> <span class="kw1">not</span> WS_EX_APPWINDOW<span class="br0">&#41;</span>;<br />
<span class="kw1">end</span>;</div>
<p>Call it in the FormOnCreate handler and don&#8217;t forget to free the Bitmap32 Object, a good place e.g. would be on the FormOnDestroy Handler.</p>
<p><strong>Additional informations for you</strong></p>
<p>I have to tell you that the first version of this package was slightly different than the one I’ll post here.<br />
Well I used an external executeable which was called from my DLL when the LogonEvent was called.</p>
<p>But I encountered a big problem with that technique. One of the biggest problems were that my external application was executed more then once. Additionally I wasn’t able to close it. Neither Application.Terminate nor Application.Mainform.Close worked here. I did some experiments with a mutex which worked in some cases, but then, Christian Wimmer gave me many good ideas and suggestions.</p>
<p>So the improvements were:</p>
<ol>
<li>The transparent Window is now directly created inside of the Winlogon Process by creating a new thread object.</li>
<li>Christian implemented an TApplication.OnIdle handler inside the thread object which will safely close the transparent window when it isn&#8217;t needed anymore.</li>
</ol>
<h3>Prerequisites:</h3>
<p>The following Delphi packages are necessary. They are not included and must therfore downloaded and installed (if necessary) separately. Please, also recognize the license of these packages. The winlogon examples does only have a Copyright and no Warranty license.</p>
<h3>Download:<a name="Downloads"></a></h3>
<p>3rd Party Components and Library&#8217;s you need to download:<br />
<a href="https://sourceforge.net/projects/graphics32/">Graphics32</a><br />
<a href="http://www.thany.org/article/18/Delphi_components">PNG Components</a></p>
<p>Jedi Tutorial Files:<a href="http://www.thany.org/article/18/Delphi_components"><br />
</a><a href="http://blog.delphi-jedi.net/wp-content/uploads/2008/05/vid.avi">Photoshop Tutorial<br />
</a>(dowload size: 2.12 MB Format: AVI)<a href="http://blog.delphi-jedi.net/wp-content/uploads/2008/05/vid.avi"><br />
</a><a href="http://blog.delphi-jedi.net/wp-content/uploads/2008/05/winlogon.zip">winlogon<br />
</a>(dowload size: 82.2 KB Format: ZIP)</p>
<h2>Warning:</h2>
<p>If you want to use such a Winlogon Notification DLL in a productive system you have to make sure that the wrong person can&#8217;t manipulate the DLL file. This can be done by setting the file&#8217;s access control list to allow only write access to SYSTEM and Administrators. There is no need for other users to have even read access, since the DLL is only used by winlogon. Furthermore you should save this file in a save place like the System32 folder.</p>
<p><strong>Conclusion:</strong></p>
<p>I hope you learned something new and had as much fun as I had writing this little tutorial for you!<br />
My biggest thanks fly out to Christian Wimmer for all his support and help for making me finish this project.</p>
<p>Kindest regards<br />
stOrM!</p>
<p>(contact by comments or <a href="http://blog.delphi-jedi.net/about/">mail @ JEDI</a>)</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2008/05/27/winlogon-notification-package/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
<enclosure url="http://blog.delphi-jedi.net/wp-content/uploads/2008/05/vid.avi" length="2232108" type="video/x-msvideo" />
		</item>
		<item>
		<title>Did you know? #7</title>
		<link>http://blog.delphi-jedi.net/2008/05/16/did-you-know-6/</link>
		<comments>http://blog.delphi-jedi.net/2008/05/16/did-you-know-6/#comments</comments>
		<pubDate>Fri, 16 May 2008 09:42:00 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[Common]]></category>
		<category><![CDATA[JWA]]></category>
		<category><![CDATA[JWSCL]]></category>
		<category><![CDATA[Pipe]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=202</guid>
		<description><![CDATA[You cannot impersonate a pipe until you have read from it. Even a write call doesn&#8217;t work. So a service has to wait for a dummy client write call until it can check the client&#8217;s token. The following codes shows how multi instance pipe server could look like. Be aware that I wrote this to [...]]]></description>
			<content:encoded><![CDATA[<p>You cannot impersonate a pipe until you have read from it. Even a write call doesn&#8217;t work. So a service has to wait for a dummy client write call until it can check the client&#8217;s token.</p>
<p>The following codes shows how multi instance pipe server could look like. Be aware that I wrote this to show how it can be done and not for a simple copy&amp;paste.</p>
<p><span id="more-202"></span></p>
<div class="dean_ch" style="white-space: wrap;"><span class="co1">//necessary units</span><br />
<span class="kw1">uses</span> JwaWindows, &#8230;, JwsclToken, JwsclUtils, JwsclComUtils, JwsclLogging, SvcMgr;<br />
&#8230;<br />
<span class="coMULTI">{checks ReadFile and WriteFile result but ignores overlapped error result}</span><br />
<span class="kw1">function</span> CheckPipe<span class="br0">&#40;</span><span class="kw1">const</span> Value : <span class="kw4">Boolean</span><span class="br0">&#41;</span> : <span class="kw4">Boolean</span>;<br />
<span class="kw1">begin</span><br />
&nbsp; result := <span class="br0">&#40;</span>Value <span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">or</span> <span class="br0">&#40;</span><span class="kw1">not</span> Value <span class="kw1">and</span> <span class="br0">&#40;</span><span class="kw3">GetLastError</span><span class="br0">&#40;</span><span class="br0">&#41;</span> = ERROR_IO_PENDING<span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
<span class="kw1">end</span>;</p>
<p><span class="kw1">var</span><br />
&nbsp; ServiceStopEvent : <span class="kw4">THandle</span>; <span class="co1">//define a stop event for the service</span><br />
&nbsp; Stopped : <span class="kw4">Boolean</span> = <span class="kw2">false</span>;</p>
<p><span class="kw1">procedure</span> &#8230;<span class="me1">ServiceExecute</span><br />
<span class="kw1">var</span><br />
&nbsp; Log : IJwLogClient;</p>
<p>&nbsp; ProtocolVersion,<br />
&nbsp; WaitResult : <span class="kw4">DWORD</span>;<br />
&nbsp; Msg : TMsg;<br />
&nbsp; OvLapped : OVERLAPPED;<br />
&nbsp; PipeToken : TJwSecurityToken;<br />
<span class="kw1">begin</span><br />
&nbsp; <span class="co1">//JWSCL logging</span><br />
&nbsp; Log := uLogging.<span class="me1">LogServer</span>.<span class="me1">Connect</span><span class="br0">&#40;</span>etMethod,ClassName,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;ServiceExecute&#8217;</span>,<span class="st0">&#8216;MainUnit.pas&#8217;</span>,<span class="st0">&#8221;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; hPipe := CreateNamedPipe<span class="br0">&#40;</span><span class="st0">&#8216;\\.\pipe\PipeName&#8217;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; PIPE_ACCESS_DUPLEX <span class="kw1">or</span> FILE_FLAG_OVERLAPPED,<br />
&nbsp; &nbsp; &nbsp; &nbsp; PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, <span class="nu0">0</span>, <span class="nu0">0</span>, <span class="nu0">0</span>, <span class="kw2">nil</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; <span class="co1">//check hPipe here&#8230;TODO for the reader</span></p>
<p>&nbsp; ZeroMemory<span class="br0">&#40;</span>@OvLapped, <span class="kw3">sizeof</span><span class="br0">&#40;</span>OvLapped<span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; OvLapped.<span class="me1">hEvent</span> := CreateEvent<span class="br0">&#40;</span><span class="kw2">nil</span>, <span class="kw2">false</span>, <span class="kw2">false</span>, <span class="kw2">nil</span><span class="br0">&#41;</span>;<br />
&nbsp; <span class="co1">//auto CloseHandle</span><br />
&nbsp; TJwAutoPointer.<span class="me1">Wrap</span><span class="br0">&#40;</span>OvLapped.<span class="me1">hEvent</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; Stopped := <span class="kw2">false</span>;<br />
&nbsp; <span class="co1">//for services we use this msg friendly approach</span><br />
&nbsp; <span class="kw1">repeat</span> <span class="co1">//1.</span><br />
&nbsp; &nbsp; &nbsp;ConnectNamedPipe<span class="br0">&#40;</span>Pipe, @OvLapped<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp;<span class="kw1">repeat</span> <span class="co1">//2.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;ServiceThread.<span class="me1">ProcessRequests</span><span class="br0">&#40;</span><span class="kw2">False</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp;WaitResult := JwMsgWaitForMultipleObjects<span class="br0">&#40;</span><span class="br0">&#91;</span>ServiceStopEvent, OvLapped.<span class="me1">hEvent</span><span class="br0">&#93;</span>, <span class="kw2">false</span>, INFINITE, QS_ALLINPUT<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">case</span> WaitResult <span class="kw1">of</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WAIT_OBJECT_0 + <span class="nu0">1</span> : &nbsp;ResetEvent<span class="br0">&#40;</span>OvLapped.<span class="me1">hEvent</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WAIT_OBJECT_0 + <span class="nu0">2</span> : &nbsp;PeekMessage<span class="br0">&#40;</span>Msg, <span class="nu0">0</span>, <span class="nu0">0</span>, <span class="nu0">0</span>, PM_NOREMOVE<span class="br0">&#41;</span>; <span class="co1">//tag message as read, so waitfor does not return next time</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//another problem</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">end</span>;<br />
&nbsp; &nbsp; &nbsp;<span class="kw1">until</span> WaitResult &lt;&gt; WAIT_OBJECT_0 + <span class="nu0">2</span>; <span class="co1">//2.</span></p>
<p>&nbsp; &nbsp; &nbsp;<span class="kw1">if</span> WaitResult = WAIT_OBJECT_0 <span class="nu0">+1</span> <span class="kw1">then</span> <span class="co1">//connected</span><br />
&nbsp; &nbsp; &nbsp;<span class="kw1">begin</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">//read dummy data or e.g. Protocol version of client</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">if</span> <span class="kw1">not</span> CheckPipe<span class="br0">&#40;</span>ReadFile<span class="br0">&#40;</span>Pipe, @ProtocolVersion, <span class="kw3">sizeof</span><span class="br0">&#40;</span>ProtocolVersion<span class="br0">&#41;</span> ,<span class="kw2">nil</span>, @OvLapped<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">//uhh error</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">begin</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">//JWSCL JwsclUtils.pas implements this more convenient wait function</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">if</span> JwWaitForMultipleObjects<span class="br0">&#40;</span><span class="br0">&#91;</span>ServiceStopEvent, OvLapped.<span class="me1">hEvent</span><span class="br0">&#93;</span>, <span class="kw2">false</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TIMEOUT<span class="br0">&#41;</span> = WAIT_OBJECT_0 <span class="nu0">+1</span> <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">begin</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">try</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//now we can get the client&#8217;s token &#8211; may throw exception if it fails!</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TJwSecurityToken.<span class="me1">ImpersonateNamedPipeClient</span><span class="br0">&#40;</span>Pipe<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">try</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PipeToken := TJwSecurityToken.<span class="me1">CreateTokenByThread</span><span class="br0">&#40;</span><span class="nu0">0</span>, MAXIMUM_ALLOWED, <span class="kw2">true</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">finally</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TJwSecurityToken.<span class="me1">RevertToSelf</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">end</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//&#8230;&#8230;. go on with what you want</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">on</span> E : Exception <span class="kw1">do</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">begin</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Log.<span class="me1">Exception</span><span class="br0">&#40;</span>E<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">end</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">end</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Log.<span class="me1">Log</span><span class="br0">&#40;</span><span class="st0">&#8216;Read for protocol version failed.&#8217;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">end</span>;<br />
&nbsp; &nbsp; &nbsp;<span class="kw1">end</span>;</p>
<p>&nbsp; &nbsp; &nbsp;DisconnectNamedPipe<span class="br0">&#40;</span>Pipe<span class="br0">&#41;</span>;<br />
&nbsp; <span class="kw1">until</span> Stopped; <span class="co1">//1. &#8211; the one who signales ServiceStopEvent, must also set this boolean value to true</span></p>
<p>&nbsp; CloseHandle<span class="br0">&#40;</span>Pipe<span class="br0">&#41;</span>;<br />
<span class="kw1">end</span>;</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2008/05/16/did-you-know-6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Did you know? #1</title>
		<link>http://blog.delphi-jedi.net/2008/05/08/did-you-know-1/</link>
		<comments>http://blog.delphi-jedi.net/2008/05/08/did-you-know-1/#comments</comments>
		<pubDate>Thu, 08 May 2008 20:05:00 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[Common]]></category>
		<category><![CDATA[JEDI Windows API Headers]]></category>
		<category><![CDATA[CreateProcessAsUser]]></category>
		<category><![CDATA[DidYouKnow]]></category>
		<category><![CDATA[JWA]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=193</guid>
		<description><![CDATA[A call to CreateProcessAsUser will fail with ERROR_INVALID_PARAMETER if your new process belongs to another session and you allowed inheritance of handles. In this case you have to set parameter bInheritHandles to FALSE.]]></description>
			<content:encoded><![CDATA[<p>A call to <a href="http://msdn.microsoft.com/en-us/library/ms682429.aspx">CreateProcessAsUser</a> will fail with <strong>ERROR_INVALID_PARAMETER</strong> if your new process belongs to another session and you allowed inheritance of handles. In this case you have to set parameter <em>bInheritHandles</em> to <strong>FALSE</strong>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2008/05/08/did-you-know-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Wishlist</title>
		<link>http://blog.delphi-jedi.net/2008/05/02/wishlist/</link>
		<comments>http://blog.delphi-jedi.net/2008/05/02/wishlist/#comments</comments>
		<pubDate>Fri, 02 May 2008 12:31:44 +0000</pubDate>
		<dc:creator>Christian Wimmer</dc:creator>
				<category><![CDATA[Common]]></category>
		<category><![CDATA[JEDI Windows API Headers]]></category>
		<category><![CDATA[JEDI Windows Security Code Lib]]></category>
		<category><![CDATA[JWA]]></category>
		<category><![CDATA[JWSCL]]></category>

		<guid isPermaLink="false">http://blog.delphi-jedi.net/?p=182</guid>
		<description><![CDATA[The following topics you can choose to research. Each topic has several possible options you can work on. The options are Library: Creating Windows headers for JEDI Windows API or (wrapper) classes for JEDI Windows Security Blogpost: Writing a blog post about the topic. Example: Writing an example about the topic that demonstrates using the [...]]]></description>
			<content:encoded><![CDATA[<p>The following topics you can choose to research. Each topic has several possible options you can work on. The options are</p>
<ul>
<li><strong>Library</strong>: Creating Windows headers for JEDI Windows API or (wrapper) classes for JEDI Windows Security</li>
<li><strong>Blogpost</strong>: Writing a blog post about the topic.</li>
<li><strong>Example</strong>: Writing an example about the topic that demonstrates using the JEDI API, JWSCL or parts of it.</li>
</ul>
<p>Of course it is possible to handle one or more of these options.</p>
<table border="1">
<tbody>
<tr>
<td><span style="font-size: small;"><strong>Topic</strong></span></td>
<td><span style="font-size: small;"><strong>Library</strong></span></td>
<td><span style="font-size: small;"><strong>Blogpost</strong></span></td>
<td><span style="font-size: small;"><strong>Example</strong></span></td>
<td><span style="font-size: small;"><strong>Belonging</strong></span></td>
<td><span style="font-size: small;"><strong>Status</strong></span></td>
</tr>
<tr>
<td>AuthZ</td>
<td>√</td>
<td>Δ</td>
<td>Δ</td>
<td><strong>JWSCL</strong></td>
<td><a href="http://mailhide.recaptcha.net/d?k=01MeKrDPlF4UMY4OOGe4JcPA==&amp;c=qu6RnFAF5jjxh0bbfE7ymCJCa5TFUIfZS6RdKFzWmME=">available</a></td>
</tr>
<tr>
<td>JwShellExecute</td>
<td>√</td>
<td>Δ</td>
<td>Δ</td>
<td><strong>JWSCL</strong></td>
<td><a href="http://mailhide.recaptcha.net/d?k=01MeKrDPlF4UMY4OOGe4JcPA==&amp;c=qu6RnFAF5jjxh0bbfE7ymCJCa5TFUIfZS6RdKFzWmME=">available</a></td>
</tr>
<tr>
<td>Private security descriptor</td>
<td>partly √</td>
<td>Δ</td>
<td>Δ</td>
<td><strong>JWSCL</strong></td>
<td><a href="http://mailhide.recaptcha.net/d?k=01MeKrDPlF4UMY4OOGe4JcPA==&amp;c=qu6RnFAF5jjxh0bbfE7ymCJCa5TFUIfZS6RdKFzWmME=">available</a></td>
</tr>
<tr>
<td>Task Scheduler</td>
<td>X</td>
<td>Δ</td>
<td>Δ</td>
<td><strong>JWA</strong></td>
<td><a href="http://mailhide.recaptcha.net/d?k=01MeKrDPlF4UMY4OOGe4JcPA==&amp;c=qu6RnFAF5jjxh0bbfE7ymCJCa5TFUIfZS6RdKFzWmME=">available</a></td>
</tr>
<tr>
<td>Shutdown</td>
<td>-</td>
<td>Δ</td>
<td>(example only)</td>
<td><strong>JWSCL</strong></td>
<td><a href="http://mailhide.recaptcha.net/d?k=01MeKrDPlF4UMY4OOGe4JcPA==&amp;c=qu6RnFAF5jjxh0bbfE7ymCJCa5TFUIfZS6RdKFzWmME=">available</a></td>
</tr>
<tr>
<td>Whoami</td>
<td>-</td>
<td>Δ</td>
<td>(example only)</td>
<td><strong>JWSCL</strong></td>
<td><a href="http://mailhide.recaptcha.net/d?k=01MeKrDPlF4UMY4OOGe4JcPA==&amp;c=qu6RnFAF5jjxh0bbfE7ymCJCa5TFUIfZS6RdKFzWmME=">available</a></td>
</tr>
<tr>
<td>Thread safe password list</td>
<td>partly √</td>
<td>Δ</td>
<td>Δ</td>
<td><strong>JWSCL</strong></td>
<td><a href="http://mailhide.recaptcha.net/d?k=01MeKrDPlF4UMY4OOGe4JcPA==&amp;c=qu6RnFAF5jjxh0bbfE7ymCJCa5TFUIfZS6RdKFzWmME=">available</a></td>
</tr>
<tr>
<td>Remote Desktop</td>
<td>X</td>
<td>Δ</td>
<td>Δ</td>
<td><strong>JWA</strong></td>
<td><a href="http://mailhide.recaptcha.net/d?k=01MeKrDPlF4UMY4OOGe4JcPA==&amp;c=qu6RnFAF5jjxh0bbfE7ymCJCa5TFUIfZS6RdKFzWmME=">available</a></td>
</tr>
<tr>
<td>System Event Notification Service</td>
<td>X</td>
<td>Δ</td>
<td>Δ</td>
<td><strong>JWA</strong></td>
<td><a href="http://mailhide.recaptcha.net/d?k=01MeKrDPlF4UMY4OOGe4JcPA==&amp;c=qu6RnFAF5jjxh0bbfE7ymCJCa5TFUIfZS6RdKFzWmME=">available</a></td>
</tr>
<tr>
<td>Conditional Variables</td>
<td>X</td>
<td>Δ</td>
<td>Δ</td>
<td><strong>JWA</strong><strong>/JWSCL</strong></td>
<td><a href="http://mailhide.recaptcha.net/d?k=01MeKrDPlF4UMY4OOGe4JcPA==&amp;c=qu6RnFAF5jjxh0bbfE7ymCJCa5TFUIfZS6RdKFzWmME=">available</a></td>
</tr>
<tr>
<td>Logging Administration</td>
<td>-</td>
<td>Δ</td>
<td>Δ</td>
<td><strong>JWSCL</strong></td>
<td><a href="http://mailhide.recaptcha.net/d?k=01MeKrDPlF4UMY4OOGe4JcPA==&amp;c=qu6RnFAF5jjxh0bbfE7ymCJCa5TFUIfZS6RdKFzWmME=">available</a></td>
</tr>
<tr>
<td>Application UpToDate Service</td>
<td>-</td>
<td>Δ</td>
<td>Δ</td>
<td><strong>JWA</strong><strong>/JWSCL</strong></td>
<td><a href="http://mailhide.recaptcha.net/d?k=01MeKrDPlF4UMY4OOGe4JcPA==&amp;c=qu6RnFAF5jjxh0bbfE7ymCJCa5TFUIfZS6RdKFzWmME=">available</a></td>
</tr>
<tr>
<td>JEDI API&amp;WSCL Installation</td>
<td>-</td>
<td>Δ</td>
<td>Δ</td>
<td><strong>JWA</strong><strong>/JWSCL</strong></td>
<td></td>
</tr>
<tr>
<td>??</td>
<td>??</td>
<td>??</td>
<td>??</td>
<td><strong>JWA/JWSCL</strong></td>
<td><a href="http://mailhide.recaptcha.net/d?k=01MeKrDPlF4UMY4OOGe4JcPA==&amp;c=qu6RnFAF5jjxh0bbfE7ymCJCa5TFUIfZS6RdKFzWmME=">available</a></td>
</tr>
</tbody>
</table>
<p>Legend:</p>
<table border="1">
<tbody>
<tr>
<td>√</td>
<td>The task is already completed.</td>
</tr>
<tr>
<td>X</td>
<td>The code must be implemented.</td>
</tr>
<tr>
<td>-</td>
<td>No activity necessary/possible.</td>
</tr>
<tr>
<td>Δ</td>
<td>The task is available.</td>
</tr>
<tr>
<td>??</td>
<td>Missing projects? Make suggestions&#8230;</td>
</tr>
</tbody>
</table>
<h2>Topic abstracts:</h2>
<p><strong>AuthZ</strong><br />
AuthZ is implemented by JWSCL and provides authentication access classes to do access checks without needing a logged on user. The acceptor can create examples and blog posts about its usage.</p>
<p><strong>JwShellExecute</strong><br />
JwShellExecute is a wrapper for ShellExecuteEx and enhances it with elevation for XP and Vista. The acceptor can create examples and blog posts about its usage.</p>
<p><strong>PrivateSecurityDescriptor</strong><br />
PrivateSecurityDescriptor is partly implemented and provides mechanics to maintain security descriptors on user defined objects (classes). The acceptor can use existing implementation and also create examples and blog posts about its usage.</p>
<p><strong>Task Scheduler</strong><br />
Task Scheduler is an API which exists since Windows 95 Plus. In Windows Vista there is a new (but incompatible) version 2.0 of  Task Scheduler. The acceptor implements the Windows headers (COM) and one or more examples. A blog post is also possible.</p>
<p><strong>Shutdown</strong><br />
Shutdown is a project for JWSCL which implements a service that shuts down the computer. The big difference is that users are informed and are able to abort the shutdown sequence. The acceptor will create a project and maybe write an article about its usage.</p>
<p><strong>Whoami</strong><br />
Whoami is a project for JWSCL which shows security related information about the user. The acceptor will create a project and maybe write an article about its usage.</p>
<p><strong>ThreadedPasswordList</strong><br />
ThreadedPasswordList is a JWSCL class that maintains a list of encrypted login credentials (username, domain, password) along with user data (also encrypted). The acceptor will adapt an existing class to JWSCL standards and maybe write an article about its usage.</p>
<p><strong>Remote Desktop</strong><br />
Remote Desktop API is introduced in Windows Vista and provides access to remote processes. The API is available in COM in JWA and needs a demonstration project.  The acceptor implements the Windows headers and one or more examples. A blog post is also possible.</p>
<p><strong>System Event Notification Service (SENS)</strong><br />
Please read <a href="http://msdn.microsoft.com/en-us/library/cc185680%28VS.85%29.aspx">MSDN article</a> about SENS.</p>
<p><strong>Conditional Variables</strong><br />
The acceptor creates a header file and a library class that offers and implements the new Vista feature Conditional Variables.<br />
Please read <a href="http://msdn.microsoft.com/en-us/library/ms683476(VS.85).aspx">MSDN article</a> about CV.</p>
<p><strong>Logging Administration</strong><br />
JWSCL implements a threadsafe log mechanism and saves the logs into a xml file. However there is actually no way to read and filter these xml files. Thus the acceptor will create a client that allows to open several log xml files as well as maintain, read them. Filtering of the log messages will also be a part of the new application</p>
<p><strong>Application UpToDate Service</strong><br />
Application UptoDate Service is a mechanism that helps the user to let her JEDI applications stay up to date. The acceptor adds this functionality to all JEDI API&amp;WSCL applications and to the server.</p>
<p><strong>JEDI API&amp;WSCL Installation Application</strong> (in process)<br />
The projects needs an installation and update program that can download the sources from the latest subversion branch, install the source path to all Delphi installations and also compile the source for all Delphi versions. Futhermore it can be used to update the source codes to the latest version. Eventually it is used to remove the whole project if no more necessary.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delphi-jedi.net/2008/05/02/wishlist/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

