Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Proper way to initialize DLL for calling WinAPI functions via handles?

Status
Not open for further replies.

djjd47130

Programmer
Nov 1, 2010
480
US
I'm building a DLL which contains whatever might be needed to prepare a delphi 7 app for Windows 7's special effects, such as drawing glass, minimizing forms properly to the taskbar, bringing modal forms to front (as they tend to get hidden quite often), and placing a green progress indicator in the form's taskbar icon. I'm putting this into a DLL to keep for future redistributable support to keep delphi 7 applications compatible with windows 7 (and vista for that matter). I want other coders to be able to use it without seeing how everything works, as well as keep the host app's file size to a minimal, because all this functionality can be shared.

The problem is I haven't touched a DLL in forever, and I'm still not that comfortable with them. I need to make sure I'm doing this right...

Now the first issue I have is whether I will need the ShareMem. I want to avoid it as much as possible, but I need to make sure my exported functions are compatible. Obviously I can't pass objects if I'm not using ShareMem, so I pass handles (HWND) instead. But should I publish it as HWND or another type? And should it be a const, var, or neither, or does that matter?

Another problem is that it's using ComObj, which requires me to use CoInitialize. But, no matter where I put CoInitialize, it keeps giving me an error that CoInitialize hasn't been called (which I clearly do call it). I wound up moving it to the initialization and finalization sections. Still doesn't work there either, but in a DLL, is this a safe place to put any code?

Next, I have a clash between two functionalities here: The swapping of the application's 'hidden' form messes up the progress indicator in the taskbar icon. Both of them relate to the taskbar icon, but if the app's secret form gets swapped, then the progress indicator doesn't work.

Another thing, there was no help at the source where I got the taskbar/progressbar code. This code won't allow using it on multiple forms - it presumes it's always going to be Application.Handle. I tried to convert it, but got lost. It works only when you don't swap out the app's secret form with the main form.

And finally, I'd like to be able to change a form's color from within the DLL - using only the form's handle (or the form's canvas handle?). I presume I will need to create a TCanvas within the DLL and fill it with the desired color (for glass transparency). I need to make sure this is safe.

(Will be posting the code in next couple posts)


JD Solutions
 
(Putting //<--- after everything that needs attention

This is my common Windows 7 library unit

JDWin7.pas
Code:
unit JDWin7;

interface

uses
  Forms
  , Types
  , Windows
  , SysUtils
  , ComObj         //<---
  , Controls
  , Graphics
  , Themes;

const
  TASKBAR_CID: TGUID = '{56FDF344-FD6D-11d0-958A-006097C9A090}';
  TBPF_NOPROGRESS = 0;
  TBPF_INDETERMINATE = 1;
  TBPF_NORMAL = 2;
  TBPF_ERROR = 4;
  TBPF_PAUSED = 8;

type   
  TTaskBarProgressState = (tbpsNone, tbpsIndeterminate, tbpsNormal, tbpsError, tbpsPaused);

  ITaskBarList3 = interface(IUnknown)
  ['{EA1AFB91-9E28-4B86-90E9-9E9F8A5EEFAF}']
    function HrInit(): HRESULT; stdcall;
    function AddTab(hwnd: THandle): HRESULT; stdcall;
    function DeleteTab(hwnd: THandle): HRESULT; stdcall;
    function ActivateTab(hwnd: THandle): HRESULT; stdcall;
    function SetActiveAlt(hwnd: THandle): HRESULT; stdcall;
    function MarkFullscreenWindow(hwnd: THandle; fFullscreen: Boolean): HRESULT; stdcall;
    function SetProgressValue(hwnd: THandle; ullCompleted: UInt64; ullTotal: UInt64): HRESULT; stdcall;
    function SetProgressState(hwnd: THandle; tbpFlags: Cardinal): HRESULT; stdcall;
    function RegisterTab(hwnd: THandle; hwndMDI: THandle): HRESULT; stdcall;
    function UnregisterTab(hwndTab: THandle): HRESULT; stdcall;
    function SetTabOrder(hwndTab: THandle; hwndInsertBefore: THandle): HRESULT; stdcall;
    function SetTabActive(hwndTab: THandle; hwndMDI: THandle; tbatFlags: Cardinal): HRESULT; stdcall;
    function ThumbBarAddButtons(hwnd: THandle; cButtons: Cardinal; pButtons: Pointer): HRESULT; stdcall;
    function ThumbBarUpdateButtons(hwnd: THandle; cButtons: Cardinal; pButtons: Pointer): HRESULT; stdcall;
    function ThumbBarSetImageList(hwnd: THandle; himl: THandle): HRESULT; stdcall;
    function SetOverlayIcon(hwnd: THandle; hIcon: THandle; pszDescription: PChar): HRESULT; stdcall;
    function SetThumbnailTooltip(hwnd: THandle; pszDescription: PChar): HRESULT; stdcall;
    function SetThumbnailClip(hwnd: THandle; var prcClip: TRect): HRESULT; stdcall;
  end;

var    
  GlobalTaskBarInterface: ITaskBarList3;
  HasGlobalTaskBarForm: Bool;        //<---
  GlobalTaskBarForm: HWND;        //<---

function InitializeTaskbarAPI(FormHandle: HWND): Boolean; overload;        //<---
function InitializeTaskbarAPI: Boolean; overload;        //<---
function SetTaskbarProgressState(const AState: Cardinal): Boolean; overload;
function SetTaskbarProgressState(const AState: TTaskBarProgressState): Boolean; overload;
function SetTaskbarProgressValue(const ACurrent:UInt64; const AMax: UInt64): Boolean;
function SetTaskbarOverlayIcon(const AIcon: THandle; const ADescription: String): Boolean; overload;
function SetTaskbarOverlayIcon(const AIcon: TIcon; const ADescription: String): Boolean; overload;
function SetTaskbarOverlayIcon(const AList: TImageList; const IconIndex: Integer; const ADescription: String): Boolean; overload;
           
function InitWin7Form(FormHandle: HWND; const Color: TColor): Bool;        //<---
function InitWin7App(AppHandle: HWND): Bool;        //<---

procedure GlassForm(FormHandle: HWND; cBlurColorKey: TColor = clFuchsia);

implementation

procedure SetFormColor(FormHandle: HWND; Color: TColor);          //<---
var
  C: TCanvas;
begin
  //Make C the canvas of the form from FormHandle
  
  //Fill the canvas with the specified Color
  
end;

procedure GlassForm(FormHandle: HWND; cBlurColorKey: TColor = clFuchsia);
const
  WS_EX_LAYERED = $80000;
  LWA_COLORKEY = 1;
type
  _MARGINS = packed record
    cxLeftWidth: Integer;
    cxRightWidth: Integer;
    cyTopHeight: Integer;
    cyBottomHeight: Integer;
  end;
  PMargins = ^_MARGINS;
  TMargins = _MARGINS;
  DwmIsCompositionEnabledFunc = function(pfEnabled: PBoolean): HRESULT; stdcall;
  DwmExtendFrameIntoClientAreaFunc = function(
    destWnd: HWND; const pMarInset: PMargins): HRESULT; stdcall;
  SetLayeredWindowAttributesFunc = function(
    destWnd: HWND; cKey: TColor; bAlpha: Byte; dwFlags: DWord): BOOL; stdcall;
var
  hDWMDLL: Cardinal;
  osVinfo: TOSVERSIONINFO;
  fDwmIsCompositionEnabled: DwmIsCompositionEnabledFunc;
  fDwmExtendFrameIntoClientArea: DwmExtendFrameIntoClientAreaFunc;
  fSetLayeredWindowAttributesFunc: SetLayeredWindowAttributesFunc;
  bCmpEnable: Boolean;
  mgn: TMargins;
begin
  ZeroMemory(@osVinfo, SizeOf(osVinfo));
  OsVinfo.dwOSVersionInfoSize := SizeOf(TOSVERSIONINFO);
  if ((GetVersionEx(osVInfo) = True) and
    (osVinfo.dwPlatformId = VER_PLATFORM_WIN32_NT) and
    (osVinfo.dwMajorVersion >= 6)) then
  begin
    hDWMDLL := LoadLibrary('dwmapi.dll');
    if hDWMDLL <> 0 then
    begin
      @fDwmIsCompositionEnabled :=
        GetProcAddress(hDWMDLL, 'DwmIsCompositionEnabled');
      @fDwmExtendFrameIntoClientArea :=
        GetProcAddress(hDWMDLL, 'DwmExtendFrameIntoClientArea');
      @fSetLayeredWindowAttributesFunc :=
        GetProcAddress(GetModulehandle(user32), 'SetLayeredWindowAttributes');
      if ((@fDwmIsCompositionEnabled <> nil) and
        (@fDwmExtendFrameIntoClientArea <> nil) and
        (@fSetLayeredWindowAttributesFunc <> nil)) then
      begin
        fDwmIsCompositionEnabled(@bCmpEnable);
        if bCmpEnable = True then begin
          SetFormColor(FormHandle, cBlurColorKey); //Not done yet          //<---
          SetWindowLong(FormHandle, GWL_EXSTYLE,
            GetWindowLong(FormHandle, GWL_EXSTYLE) or WS_EX_LAYERED);
          fSetLayeredWindowAttributesFunc(FormHandle, cBlurColorKey, 0, LWA_COLORKEY);
          ZeroMemory(@mgn, SizeOf(mgn));
          mgn.cxLeftWidth := -1;
          mgn.cxRightWidth := -1;
          mgn.cyTopHeight := -1;
          mgn.cyBottomHeight := -1;
          fDwmExtendFrameIntoClientArea(FormHandle, @mgn);
        end;
      end;
      FreeLibrary(hDWMDLL);
    end;
  end;
end;

//Used explicitly for a particular form 
//  in attempt to overcome problem with swapping app's secret form
function InitializeTaskbarAPI(FormHandle: HWND): Boolean;        //<---
begin
  HasGlobalTaskBarForm:= True;
  GlobalTaskBarForm:= FormHandle;
  Result:= InitializeTaskbarAPI;
end;

//Used for the application's secret form
function InitializeTaskbarAPI: Boolean;
var
  Unknown: IInterface;
  Temp: ITaskBarList3;
begin
  //What if I wanted 3 forms to each have 
  //  their own progress indicator in the taskbar?        //<---
  if GlobalTaskBarForm = 0 then
    GlobalTaskBarForm:= Application.Handle;
  if Assigned(GlobalTaskBarInterface) then begin
    Result := True;
    Exit;
  end;
  try
    //Creates COM object - FAILS saying CoInitialize hasn't been called
    Unknown := CreateComObject(TASKBAR_CID);        //<---
    if Assigned(Unknown) then begin
      Temp := Unknown as ITaskBarList3;
      if Temp.HrInit() = S_OK then begin
        GlobalTaskBarInterface := Temp;
      end;
    end;
  except
    GlobalTaskBarInterface := nil;
  end;
  Result:= Assigned(GlobalTaskBarInterface);
end;

function CheckAPI: Boolean;
begin
  Result:= Assigned(GlobalTaskBarInterface);
end;
                          
function SetTaskbarProgressState(const AState: Cardinal): Boolean;
begin
  Result:= False;
  if CheckApi then begin
    Result:= GlobalTaskBarInterface.SetProgressState(GlobalTaskBarForm, AState) = S_OK;
  end;
end;

//Sets the state of the progress indicator in the taskbar icon
function SetTaskbarProgressState(const AState: TTaskBarProgressState): Boolean;
var
  Flag: Cardinal;
begin
  Result := False;
  if CheckAPI then begin
    case AState of
      tbpsIndeterminate: Flag := TBPF_INDETERMINATE;
      tbpsNormal: Flag := TBPF_NORMAL;
      tbpsError: Flag := TBPF_ERROR;
      tbpsPaused: Flag := TBPF_PAUSED;
    else
      Flag:= TBPF_NOPROGRESS;
    end;
    Result:= GlobalTaskBarInterface.SetProgressState(GlobalTaskBarForm, Flag) = S_OK;
  end;
end;

//Sets the position of the taskbar icon's progress indicator
function SetTaskbarProgressValue(const ACurrent: UInt64; const AMax: UInt64): Boolean;
begin                                            //Is UInt64 DLL safe?
  Result:= False;
  if CheckAPI then begin
    Result := GlobalTaskBarInterface.SetProgressValue(
      GlobalTaskBarForm, ACurrent, AMax) = S_OK;
  end;
end;

function SetTaskbarOverlayIcon(const AIcon: THandle; const ADescription: String): Boolean;
begin                                                      //Replace with PChar
  Result := False;
  if CheckAPI then begin
    Result := GlobalTaskBarInterface.SetOverlayIcon(
      GlobalTaskBarForm, AIcon, PAnsiChar(ADescription)) = S_OK;
  end;
end;

//I would need to use ShareMem to export these ones        //<---
function SetTaskbarOverlayIcon(const AIcon: TIcon;
  const ADescription: String): Boolean;
begin
  Result := False;
  if CheckAPI then begin
    if Assigned(AIcon) then
    begin
      Result := SetTaskbarOverlayIcon(AIcon.Handle, ADescription);
    end else begin
      Result := SetTaskbarOverlayIcon(THandle(nil), ADescription);
    end;
  end;
end;

function SetTaskbarOverlayIcon(const AList: TImageList;
  const IconIndex: Integer; const ADescription: String): Boolean;
var
  Temp: TIcon;
begin
  Result := False;
  if CheckAPI then begin
    if (IconIndex >= 0) and (IconIndex < AList.Count) then begin
      Temp := TIcon.Create;
      try
        AList.GetIcon(IconIndex, Temp);
        Result := SetTaskbarOverlayIcon(Temp, ADescription);
      finally
        Temp.Free;
      end;
    end else begin
      Result := SetTaskbarOverlayIcon(nil, ADescription);
    end;
  end;
end;


//Master initialization of a single form
function InitWin7Form(FormHandle: HWND; const Color: TColor): Bool;
begin
  //How should I do this if I want the progress indicator to work in multiple forms?
  ShowWindow(FormHandle, SW_HIDE);         //<---
  SetWindowLong(FormHandle, GWL_EXSTYLE, GetWindowLong(FormHandle, GWL_EXSTYLE)
    and not WS_EX_APPWINDOW or WS_EX_TOOLWINDOW);
  ShowWindow(FormHandle, SW_SHOW);
end;

//Master initialization of an application
function InitWin7App(AppHandle: HWND): Bool;
begin
  Result:= InitializeTaskbarAPI;         //<---
  Sleep(500);
end;

initialization        //<---
  CoInitialize(nil); //Isn't working???         //<---
  GlobalTaskBarInterface:= nil;
  HasGlobalTaskBarForm:= False;
  GlobalTaskBarForm:= 0;

finalization        //<---
  GlobalTaskBarInterface:= nil;
  HasGlobalTaskBarForm:= False;
  GlobalTaskBarForm:= 0;
  CoUninitialize;

end.

JD Solutions
 
Here is[ the DLL that wraps JDWin7.pas/b]

Code:
library Win7;

uses
  //Do I need ShareMem?
  //ShareMem,      //<---
  Windows,
  Forms,
  JDWin7,
  SysUtils,
  Classes;

{$R *.res}
     
function Win7InitTaskbar(const FormHandle: HWND): Bool; stdcall;
begin
  Result:= InitializeTaskbarAPI(FormHandle);
end;
       
function Win7InitForm(const FormHandle: HWND): Bool; stdcall;
begin

end;

function Win7SetTaskbarState(const AState: Cardinal): Bool; stdcall;
begin
  Result:= SetTaskbarProgressState(AState);
end;

function Win7SetTaskbarValue(const ACurrent: UInt64; const AMax: UInt64): Bool; stdcall;
begin                                        //is UInt64 Safe for DLL?
  Result:= SetTaskbarProgressValue(ACurrent, AMax);
end;
     

exports
  Win7InitTaskbar,
  Win7InitForm,
  Win7SetTaskbarState,
  Win7SetTaskbarValue;

begin

end.


JD Solutions
 
And finally the unit to wrap the DLL.
I'm copying the TForm from Forms.pas and making my own, automating the Windows7 functionality. The final step will be figuring out how to replace the default VCL form with my custom form in the Delphi 7 IDE...

Code:
unit Win7;

interface

uses
  //ShareMem, //Do I need?                 //<---
  Classes, Windows, SysUtils, Forms, Messages;

function Win7InitTaskbar(const FormHandle: HWND): Bool;
  external 'Win7.dll';
function Win7SetTaskbarState(const AState: Cardinal): Bool;
  external 'Win7.dll';
function Win7SetTaskbarValue(const ACurrent: UInt64; const AMax: UInt64): Bool;
  external 'Win7.dll';                       //UInt64?              //<---

type
  //Will be adding more functionality to automate Win7 effects
  //      [Copy of TForm]     //<---
  TWin7Form = class(TCustomForm)
  public
    procedure ArrangeIcons;
    procedure Cascade;
    procedure Next;
    procedure Previous;
    procedure Tile;
    property ActiveMDIChild;
    property ClientHandle;
    property DockManager;
    property MDIChildCount;
    property MDIChildren;
    property TileMode;
  published
    property Action;
    property ActiveControl;
    property Align;
    property AlphaBlend default False;
    property AlphaBlendValue default 255;
    property Anchors;
    property AutoScroll;
    property AutoSize;
    property BiDiMode;
    property BorderIcons;
    property BorderStyle;
    property BorderWidth;
    property Caption;
    property ClientHeight;
    property ClientWidth;
    property Color;
    property TransparentColor default False;
    property TransparentColorValue default 0;
    property Constraints;
    property Ctl3D;
    property UseDockManager;
    property DefaultMonitor;
    property DockSite;
    property DragKind;
    property DragMode;
    property Enabled;
    property ParentFont default False;
    property Font;
    property FormStyle;
    property Height;
    property HelpFile;
    property HorzScrollBar;
    property Icon;
    property KeyPreview;
    property Menu;
    property OldCreateOrder;
    property ObjectMenuItem;
    property ParentBiDiMode;
    property PixelsPerInch;
    property PopupMenu;
    property Position;
    property PrintScale;
    property Scaled;
    property ScreenSnap default False;
    property ShowHint;
    property SnapBuffer default 10;
    property VertScrollBar;
    property Visible;
    property Width;
    property WindowState;
    property WindowMenu;
    property OnActivate;
    property OnCanResize;
    property OnClick;
    property OnClose;
    property OnCloseQuery;
    property OnConstrainedResize;
    property OnContextPopup;
    property OnCreate;
    property OnDblClick;
    property OnDestroy;
    property OnDeactivate;
    property OnDockDrop;
    property OnDockOver;
    property OnDragDrop;
    property OnDragOver;
    property OnEndDock;
    property OnGetSiteInfo;
    property OnHide;
    property OnHelp;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property OnMouseDown;
    property OnMouseMove;
    property OnMouseUp;
    property OnMouseWheel;
    property OnMouseWheelDown;
    property OnMouseWheelUp;
    property OnPaint;
    property OnResize;
    property OnShortCut;
    property OnShow;
    property OnStartDock;
    property OnUnDock;
  end;

implementation

{ TWin7Form }

procedure TWin7Form.Tile;
const
  TileParams: array[TTileMode] of Word = (MDITILE_HORIZONTAL, MDITILE_VERTICAL);
begin
  if (FormStyle = fsMDIForm) and (ClientHandle <> 0) then
    SendMessage(ClientHandle, WM_MDITILE, TileParams[TileMode], 0);
end;

procedure TWin7Form.Cascade;
begin
  if (FormStyle = fsMDIForm) and (ClientHandle <> 0) then
    SendMessage(ClientHandle, WM_MDICASCADE, 0, 0);
end;

procedure TWin7Form.ArrangeIcons;
begin
  if (FormStyle = fsMDIForm) and (ClientHandle <> 0) then
    SendMessage(ClientHandle, WM_MDIICONARRANGE, 0, 0);
end;

procedure TWin7Form.Next;
begin
  if (FormStyle = fsMDIForm) and (ClientHandle <> 0) then
    SendMessage(ClientHandle, WM_MDINEXT, 0, 0);
end;

procedure TWin7Form.Previous;
begin
  if (FormStyle = fsMDIForm) and (ClientHandle <> 0) then
    SendMessage(ClientHandle, WM_MDINEXT, 0, 1);
end;

end.


JD Solutions
 
(And yes, I did see my typo in the header of one of the units :p )

JD Solutions
 
I'm not asking anyone to answer everything I'm asking, just whatever help you can give would be great. No one's going to sit down and write this thing for me, I know.

JD Solutions
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top