1,255 views

The JEDI API Library project (JWA) has been successfully revived from a sleep status to an active project with lots of ambitions. Some recent achievements are the new include model of JWA, the release of JWSCL (the Security Library) and of course the “birth” of this blog.

Read the rest of this entry »

Send post as PDF to www.pdf24.org
convert this post to pdf.
376 views

Do you need help? We can support you creating application using JWA and/or JWSCL.

Visit the Get Service site on SourceForge for more information like pricing.

Send post as PDF to www.pdf24.org
convert this post to pdf.
  • Comments Off
275 views

COM Server tells you sth about opened client connections

If you create a COM Server to serve some clients with COM interfaces (or better their functionality), you maybe get sometimes a dialog box that tells you that there are client connections opened. This happens as soon as you try to close your app. If you want to close it though, you have to explicitly click “Yes”.

Read the rest of this entry »

Send post as PDF to www.pdf24.org
convert this post to pdf.
931 views

So you want to write a service…

If you are going to write a service you should consider why you need it to be a service at all. If you can run your application as a standard user, you should do it. A service is a high privileged application that should be created with care and clear thoughts.
So think about your task you want to solve with the application. Read the rest of this entry »

Send post as PDF to www.pdf24.org
convert this post to pdf.
268 views

Technical note

After making some changes to the A-records of the DNS servers responsible for *.delphi-jedi.net, a different host was queried by the clients (e.g. your browsers) for the contents of this blog. Obviously the other host didn’t know how to react and thus gave back a simple “no idea what file that is” (i.e. HTTP error 404) in most cases. The issue has been resolved, but it may take some more time for some people until the DNS changes propagate to their DNS servers.

Mail traffic (the MX-record) was not influenced by this at any time. Jabber communication, however, may have been affected by it.

// Oliver

Send post as PDF to www.pdf24.org
convert this post to pdf.
401 views

Don’t misspell your target desktop…

If you want to use CreateProcess or CreateProcessAsUser and you also want to set the target desktop, you should make sure that the target winstation (usual winsta0) and desktop name (usual default) is spelled correctly.
If you misspell the name (say defaut instead of default - missing l ) the process creation may succeed but your application won’t show but start running.

Send post as PDF to www.pdf24.org
convert this post to pdf.
620 views

Calculating Binary Hashes using TJwFileStreamEx

Why should I use TJwFileStreamEx instead of any other common stream class from the VCL?

Well this question is quite easily answered.

The first thing is that TJwFileStreamEx is based on Memory Mapped Files (MMF). MMF might be the fastest way to access files on your hard disk. Another good reason for using TJwFileStreamEx is its Memory property which is well known from the VCL TMemoryStream class. This property will reduce the effort remarkably.

Getting Started

First you have to include following units to your project:

  1. uses JwsclTypes, JwsclStreams, JwsclCryptProvider;

The signature of our hashing-function looks like this:

  1. function GetFileHash(Algorithm: TJwHashAlgorithm; const Filename: String) : String;

The first parameter is used to specify the Algorithm which is used to hash the file data. The second parameter defines the path to the file which hash you want to compute.

So what do we need to calculate the hash of a file? All we need is an instance of TJwFileStreamEx to open the file and an instance of TJwHash to calculate the hash:

  1. function GetFileHash(Algorithm: TJwHashAlgorithm; const Filename: String) : String;
  2. var
  3.   Stream: TJwFileStreamEx;
  4.   Hash: TJwHash;
  5. begin
  6.   Stream := TJwFileStreamEx.Create(Filename,fmOpenRead);
  7.   try
  8.     Hash := TJwHash.Create(Algorithm);
  9.     // Calculate and return the Hash as a Hex-String
  10.   finally
  11.     Hash.Free;
  12.     Stream.Free;  
  13.   end;
  14. end;

This is the basic framework of our function. To calculate the hash of the file we need 2 methods:

  1. TJwHash.HashData(Data: Pointer; Size: Cardinal);
  2. TJwHash.RetrieveHash(out Len: Cardinal): Pointer;

HashData tells our instance of TJwHash which data is to be hashed and which size this data has. RetrieveHash calculates the Hash and retrieves a pointer to the hash data.

Finally we have to free the Buffer using the class method

  1. TJwHash.FreeBuffer(Buffer: Pointer);

Now our function looks like this:

  1. function GetFileHash(Algorithm: TJwHashAlgorithm; const Filename: String) : String;
  2. var
  3.   Stream: TJwFileStreamEx;
  4.   Hash: TJwHash;
  5.   HashSize: Cardinal;
  6.   HashData: Pointer;
  7. begin
  8.   Stream := TJwFileStreamEx.Create(Filename,fmOpenRead);
  9.   Hash := TJwHash.Create(Algorithm);
  10.   try
  11.     Hash.HashData(Stream.Memory,Stream.Size);
  12.     HashData := Hash.RetrieveHash(HashSize);
  13.     TJwHash.FreeBuffer(HashData);
  14.   finally
  15.     Hash.Free;
  16.     Stream.Free;
  17.   end;
  18. end;

At last we need to convert the binary hash into a hex-string:

  1. for i:= 1 to HashSize do
  2. begin
  3.   Result := Result + IntToHex(PByte(HashData)^,2);
  4.   inc(PByte(HashData));
  5. end;
  6. dec(PByte(HashData),HashSize); //neccessary to free HashData

Now we’re done and finally our function looks like this:

  1. function GetFileHash(Algorithm: TJwHashAlgorithm; const Filename: String) : String;
  2. var
  3.   Stream: TJwFileStreamEx;
  4.   Hash: TJwHash;
  5.   HashSize: Cardinal;
  6.   HashData: Pointer;
  7.   i: Integer;
  8. begin
  9.   Stream := TJwFileStreamEx.Create(Filename,fmOpenRead);
  10.   Hash := TJwHash.Create(Algorithm);
  11.   try
  12.     Hash.HashData(Stream.Memory,Stream.Size);
  13.     HashData := Hash.RetrieveHash(HashSize);
  14.  
  15.     for i:= 1 to HashSize do
  16.     begin
  17.       Result := Result + IntToHex(PByte(HashData)^,2);
  18.       inc(PByte(HashData));
  19.     end;
  20.     dec(PByte(HashData),HashSize);
  21.  
  22.     TJwHash.FreeBuffer(HashData);
  23.   finally
  24.     Hash.Free;
  25.     Stream.Free;
  26.   end;
  27. end;

How do I use this function?

  1. // first param can be one of these values:
  2. // haMD2, haMD4, haMD5, haSHA
  3. Label1.Caption := GetFileHash(haSHA,‘C:\Progam Files\Program\AFile.ext’);

OK, but what is the advantage of TJwFileStreamEx over other Streams?

Well, you don’t have to load the file into a TMemoryStream and thus the file will not be loaded completely into memory. Furthermore this solution is much faster than a solution using TMemoryStream and similar…

Download

Download the source and binaries of this example (260kiB). This includes the new and necessary JWSCL source files. However you need to download the whole package separately.

Send post as PDF to www.pdf24.org
convert this post to pdf.
434 views

Issuetracker

The JEDI Community has an issue tracker where you can submit bugs, features and fixes. Please use this tracker for both JEDI projects API and WSCL.

http://homepages.borland.com/jedi/issuetracker

Switch to project “JEDI API” in the drop down field in the top right corner of the page.

Send post as PDF to www.pdf24.org
convert this post to pdf.
1,388 views

Winlogon Notification Package

What is that? MSDN say’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’s logon event handler function to provide information about the event.

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.

I’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.

Winlogon

It’s time for our Winlogon Notification Package. Start Delphi and create a new DLL project.

What we need to do next is to define the Message Callback and the WLXNotificationInfo, as described in MSDN

  1. Type
  2. // this callback function does not return a value as described on mdsn.
  3.  
  4.   TFnMsgeCallback = function (bVerbose: Boolean; lpMessage: PWideChar): Cardinal; stdcall;
  5.  
  6. // this structure stores information about a Winlogon event.
  7.  
  8. TWlxNotificationInfo = record
  9.     Size: Cardinal;
  10.     Flags: Cardinal;
  11.     UserName: PWideChar;
  12.     Domain: PWideChar;
  13.     WindowStation: PWideChar;
  14.     Token: Cardinal;
  15.     Desktop: Cardinal;
  16.     StatusCallback: TFnMsgeCallback;
  17.   end;
  18.   PWlxNotificationInfo = ^TWlxNotificationInfo;
  19.  
  20. {  winlogon can inform about the following events:
  21. Lock,
  22. Lockoff,
  23. Logon,
  24. Shutdown,
  25. StartScreensave,
  26. StartShell,
  27. StartUp,
  28. StopScreenSaver,
  29. Unlock
  30.  
  31. For a complete describtion of those events look at:
  32.  
  33. http://msdn.microsoft.com/en-us/library/aa380544(VS.85).aspx
  34. }
  35.  
  36. // example of handling the Logon Message
  37.  
  38. procedure LogonHandler(Info: PWlxNotificationInfo); stdcall;
  39. begin
  40.  
  41. end;
  42.  
  43. // the entrance function for DLL
  44.  
  45. procedure EntryPointProc(reason: integer);
  46. begin
  47.   case reason of
  48.     DLL_PROCESS_ATTACH:  //1
  49.       Begin
  50.              // Disable DLL_THREAD_ATTACH & DLL_THREAD_DETACH
  51.              // notification calls. This is a performance optimization
  52.              // for multithreaded applications that do not need
  53.              // thread-level notifications of attachment or
  54.              // detachment.
  55.  
  56.         DisableThreadLibraryCalls(hInstance);
  57.  
  58.       end;
  59.     DLL_THREAD_ATTACH:   //2
  60.       begin
  61.  
  62.       end;
  63.     DLL_PROCESS_DETACH:  //3
  64.       begin
  65.  
  66.       end;
  67.     DLL_THREAD_DETACH:   //0
  68.       begin
  69.  
  70.       end;
  71.   end;
  72.  
  73. end;
  74.  
  75. // define the exports for the DLL
  76.  
  77. exports
  78.   LogonHandler;
  79.  
  80. begin
  81.   DllProc := @EntryPointProc;
  82.   DllProc(DLL_PROCESS_ATTACH);
  83. end.

Our Prototype, is ready to use. The compiled DLL has to be in the following folder:

C:\Windows\System32 (adapt it to your environment)

Now we can inform the operating system that we created a Winlogon Notification Package. This step will be done in the registry under the following key:

HKey_Local_Machine\Software\Microsoft\WindowsNT\
CurrentVersion\Winlogon\Notify\YourNotification

Name

Type

Value

DLLName

REG_SZ

C:\Windows\System32\YourDLLName.dll

Asynchronous

REG_DWORD

0

Impersonate

REG_DWORD

0

Logon

REG_SZ

LogonHandler

The valid values are described in this MSDN article.

Creating the PNG Image

For completing this Project you will need to download the following:

Graphics32 Library
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.

PNG Components
Delphi VCL Components with PNG Image support.

What you’ll need is an already exisiting PNG or a new one. I’ll use with the Jedi Api WSCL Logo.
Open the Logo in Photoshop but remember this can be done in almost any other Graphic Application which supports PNG and layer based drawing.

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’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 “Create New Layer Symbol” in the layer palette (indicated as a small notepad icon).

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 “Tools Window” and select the “Paint Bucket Tool“. Select white as your foreground color. If you have another color as foreground color, simply press d and then x. In this way it will reset the foreground and backgound colors. Now click inside your image on the transparent part and you’ll see the Logo with a white background applied.

Switch to your layers palette and double click on the Logo layer. The “Layers Styles Dialog” should be visible now. Select “Drop Shadow” 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’re satisfied with your settings hit ok.

At this time, we don’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.

There also exists a small video presentation which will help you.

Drawing the PNG onto the Form Canvas

The following source is kindly provided by Coder90. He wrote a nice example in a german delphi forum

The Sources
I won’t go into any details here, basically the procedure will load the PNG into a Bitmap32 Object and blends it to the forms canvas.

  1. Type
  2. interface
  3.  
  4. uses
  5.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  6.   Dialogs, ExtCtrls, StdCtrls, GR32;
  7.  
  8.   public
  9.     { Public declarations }
  10.     BMP32 : TBitmap32;
  11.     BlendF: TBlendFunction;
  12.     P: TPoint;
  13.     Size: TSize;
  14.     procedure BlendIt;
  15.   end;
  16.  
  17.   procedure LoadPNGintoBitmap32(DstBitmap: TBitmap32;
  18.                                 Filename: String;
  19.                                 out AlphaChannelUsed: Boolean); overload;
  20.  
  21.   procedure LoadPNGintoBitmap32(DstBitmap: TBitmap32;
  22.                                 SrcStream: TStream;
  23.                                 out AlphaChannelUsed: Boolean); overload;
  24.  
  25.   procedure LoadPNGintoBitmap32(DstBitmap: TBitmap32;
  26.                                 szSection : PChar;
  27.                                 szName    : String;
  28.                                 out AlphaChannelUsed: Boolean); overload;
  29.  
  30. uses PNGImage;
  31.  
  32. procedure LoadPNGintoBitmap32(DstBitmap: TBitmap32;
  33.                               SrcStream: TStream;
  34.                               out AlphaChannelUsed: Boolean);
  35. var
  36.   PNGObject: TPNGObject;
  37.   TransparentColor: TColor32;
  38.   PixelPtr: PColor32;
  39.   AlphaPtr: PByte;
  40.   X, Y: Integer;
  41. begin
  42.   PNGObject := nil;
  43.   try
  44.     PNGObject := TPngObject.Create;
  45.     PNGObject.LoadFromStream(SrcStream);
  46.  
  47.     DstBitmap.Assign(PNGObject);
  48.     DstBitmap.ResetAlpha;
  49.  
  50.     case PNGObject.TransparencyMode of
  51.       ptmPartial:
  52.         begin
  53.           if (PNGObject.Header.ColorType = COLOR_GRAYSCALEALPHA) or
  54.              (PNGObject.Header.ColorType = COLOR_RGBALPHA) then
  55.           begin
  56.             PixelPtr := PColor32(@DstBitmap.Bits[0]);
  57.             for Y := 0 to DstBitmap.Height - 1 do
  58.             begin
  59.               AlphaPtr := PByte(PNGObject.AlphaScanline[Y]);
  60.               for X := 0 to DstBitmap.Width - 1 do
  61.               begin
  62.                 PixelPtr^ := (PixelPtr^ and $00FFFFFF) or (TColor32(AlphaPtr^) shl 24);
  63.                 Inc(PixelPtr);
  64.                 Inc(AlphaPtr);
  65.               end;
  66.             end;
  67.  
  68.             AlphaChannelUsed := True;
  69.           end;
  70.         end;
  71.       ptmBit:
  72.         begin
  73.           TransparentColor := Color32(PNGObject.TransparentColor);
  74.           PixelPtr := PColor32(@DstBitmap.Bits[0]);
  75.           for X := 0 to (DstBitmap.Height - 1) * (DstBitmap.Width - 1) do
  76.           begin
  77.             if PixelPtr^ = TransparentColor then
  78.               PixelPtr^ := PixelPtr^ and $00FFFFFF;
  79.             Inc(PixelPtr);
  80.           end;
  81.  
  82.           AlphaChannelUsed := True;
  83.         end;
  84.       ptmNone:
  85.         AlphaChannelUsed := False;
  86.     end;
  87.   finally
  88.     if Assigned(PNGObject) then PNGObject.Free;
  89.   end;
  90. end;
  91.  
  92. procedure LoadPNGintoBitmap32(DstBitmap: TBitmap32;
  93.                               Filename: String;
  94.                               out AlphaChannelUsed: Boolean);
  95. var
  96.   FileStream: TFileStream;
  97. begin
  98.   FileStream := TFileStream.Create(Filename, fmOpenRead);
  99.   try
  100.     LoadPNGintoBitmap32(DstBitmap, FileStream, AlphaChannelUsed);
  101.   finally
  102.     FileStream.Free;
  103.   end;
  104. end;
  105.  
  106. procedure LoadPNGintoBitmap32(DstBitmap: TBitmap32;
  107.                               szSection : PChar;
  108.                               szName    : String;
  109.                               out AlphaChannelUsed: Boolean);
  110. var
  111.   Stream: TResourceStream;
  112. begin
  113.   Stream := TResourceStream.Create(hInstance, szName, PChar(szSection));
  114.   try
  115.     LoadPNGintoBitmap32(DstBitmap, Stream, AlphaChannelUsed);
  116.     finally
  117.      Stream.Free;
  118.    end;
  119. end;
  120.  
  121. { Works only Win2000_Up }
  122.  
  123. procedure TForm1.BlendIt;
  124.   var
  125.     Alpha: Boolean;
  126. begin
  127.   BMP32 := TBitmap32.Create;
  128.  {Load PNG from File
  129.   LoadPNGintoBitmap32(BMP32, ExtractFilePath(ParamStr(0)) + ‘WSCL.png’, Alpha);
  130.  }
  131.   // Load PNG From Resource
  132.   LoadPNGintoBitmap32(BMP32, PChar(‘PNG’), ‘WSCL’, Alpha);
  133.  
  134.   setWindowLong(Handle, GWL_EXSTYLE,
  135.   getWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED {or WS_EX_TRANSPARENT});
  136.   // WS_EX_TRANSPARENT makes the Window for MouseClicks transparent…
  137.  
  138.   BlendF.BlendOp := AC_SRC_OVER;
  139.   BlendF.BlendFlags := 0;
  140.   BlendF.SourceConstantAlpha := 255;
  141.   BlendF.AlphaFormat := AC_SRC_ALPHA;
  142.   P := Point(0, 0);
  143.   Size.cx := BMP32.Width;
  144.   Size.cy := BMP32.Height;
  145.  
  146.   UpdateLayeredWindow(Handle, 0, nil, @Size, BMP32.Handle, @P, 0, @BlendF, ULW_ALPHA);
  147.  
  148.   // Set Window on Top
  149.   SetWindowPos(Handle, HWND_TOPMOST, Left, Top, Width, Height,
  150.   SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);
  151.  
  152.   // Set Parent to Desktop
  153.   SetWindowLong(Handle, GWL_HWNDPARENT, 0);
  154.  
  155.   // Hide Window from Taskbar
  156.   SetWindowLong(Handle, GWL_EXSTYLE,
  157.   GetWindowLong(Handle, GWL_EXSTYLE) or
  158.   WS_EX_TOOLWINDOW and not WS_EX_APPWINDOW);
  159. end;

Call it in the FormOnCreate handler and don’t forget to free the Bitmap32 Object, a good place e.g. would be on the FormOnDestroy Handler.

Additional informations for you

I have to tell you that the first version of this package was slightly different than the one I’ll post here.
Well I used an external executeable which was called from my DLL when the LogonEvent was called.

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.

So the improvements were:

  1. The transparent Window is now directly created inside of the Winlogon Process by creating a new thread object.
  2. Christian implemented an TApplication.OnIdle handler inside the thread object which will safely close the transparent window when it isn’t needed anymore.

Prerequisites:

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.

Download:

3rd Party Components and Library’s you need to download:
Graphics32
PNG Components

Jedi Tutorial Files:
Photoshop Tutorial
(dowload size: 2.12 MB Format: AVI)
winlogon
(dowload size: 82.2 KB Format: ZIP)

Warning:

If you want to use such a Winlogon Notification DLL in a productive system you have to make sure that the wrong person can’t manipulate the DLL file. This can be done by setting the file’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.

Conclusion:

I hope you learned something new and had as much fun as I had writing this little tutorial for you!
My biggest thanks fly out to Christian Wimmer for all his support and help for making me finish this project.

Kindest regards
stOrM!

(contact by comments or mail @ JEDI)