Contributor: A.A. OLOWOFOYEKU { I have just extended some PD sources (in this month's SWAG - HOOKCRT.PAS) to convert it to a unit, with supporting Pascal Object and Delphi Class. This hooks into the WinCRT unit (BPW and Delphi 1.x) to add menus, etc. A sample program is included. You might wish to add this to the SWAG archives. Thanks. ------------------------------ cut ------------------------------ } Unit HookCrt2; { ----- ORIGINAL MESSAGE --- The intent of this program is to provide the ability to add additional functionality to WinCRT. Like the ablity to add and use a menubar and to be able to respond to mouse clicks. WinCRT does NOT need to be modified to run this app. This program is Public Domain by Cedar Island Software. Use it as you see fit. All the usual disclaimers apply. Thanks to Neil Rubenking and his book 'Turbo Pascal for Windows Techniques and Utilities'. Thanks to Kurt Barthlemess of BPASCAL (TeamB). Thanks also to Paul A. LeBlanc of BCPPWIN (TeamB). Good Luck and Have Fun. Mike Caughran Cedar Island Software [71034,2371] ---- ADDED MESSAGE by Dr A Olowofoyeku ------ September 1996 Amended and Extended by Dr A Olowofoyeku (The African Chief); [a] converted to a unit [b] a Pascal object (and Delphi Class) to encapsulate the unit's functionality. [c] some default procedural types and functions [d] MyInitWinCRT changed to: HookedInitWinCRT - and now takes some parameters [e] MyDoneWinCRT changed to: HookedDoneWinCrt; [f] supports Delphi 1.x Enjoy! THIS UNIT IS PUBLIC DOMAIN - NOTHING IS WARRANTEED. USE AT YOUR OWN RISK! Dr A. Olowofoyeku (The African Chief) Email: laa12@cc.keele.ac.uk http://ourworld.compuserve.com/homepages/African_Chief/ } Interface {$ifdef Ver80} {Delphi 1.x} {$Define Delphi} {$endif Ver80} uses {$ifndef Delphi}Objects {$else}Messages{$endif},WinCRT, WinTypes, WinProcs; {/////////////////////////////////////////////////////////////} {////////////// exported data and functions //////////////////} {/////////////////////////////////////////////////////////////} {custom icon for CRT window} Var CrtappIcon : hIcon; { User menu command tags (identifiers) start from 1 to 64 for CRT menu tags } Const cm_User1 = 1; cm_UserMax = 64; {Crt Window function type} Type aWindowFunc = Function(Window : HWnd; Message : Word; wParam : Word; lParam : LongInt) : LongInt; {menu command procedural type} aMenuFunc = Procedure(Const aTag:integer); {create a CRT window} Function HookedInitWinCRT( Const Left, {left side of the window} Top, {top of the window} width, {width of the window} height:integer; {height of the window} Title :pChar ; {window title} aWinProc:aWindowFunc; {new window function, or Nil for default} MenuFunc:aMenuFunc {new window procedure, or Nil for default} ):HWnd; {returns the handle to the CRT window} {destroy a CRT window} Function HookedDoneWinCRT : Boolean; {/////////////////////////////////////////////////////////////} {///////////////////// CRT object ////////////////////////////} {// This object encapsulates the functionality of this unit //} {/////////////////////////////////////////////////////////////} {/////////////////////////////////////////////////////////////} Type TNewCrtClass = {$ifdef Delphi}Class{$else}Object(TObject){$endif} HWindow : HWnd; {handle of the CRT window} Constructor {$ifdef Delphi}Create{$else}Init{$endif} {init constructor - calls HookedInitWinCRT with all these parameters, to create the CRT window} (Const Left, {left side of the window} Top, {top of the window} width, {width of the window} height:integer; {height of the window} Title :pChar ; {window title} aWinProc:aWindowFunc; {new window function, or Nil for default} MenuFunc:aMenuFunc {new window procedure, or Nil for default} ); Destructor {$ifDef Delphi}Destroy;override{$else}Done; virtual{$endif}; Procedure MakeMainMenu(Caption:pChar;Tag:integer);virtual; {create a main menu item = e.g., File Menu, Edit, etc. Caption = the title of the menu Tag = the command tag } Procedure MakeSubMenu(ParentNum:Byte;Caption:pChar;Tag:integer);virtual; {create a submenu under the main menu "parentnum" ParentNum = the numeric ID of the parent main menu Caption = the title of the menu Tag = the command tag } Procedure MakeSeparator(ParentNum:Byte);virtual; {create a menu separator under the main menu "parentnum" ParentNum = the numeric ID of the parent main menu } Procedure AssignCRTMenu;virtual; {assign the menu to the CRT window and repaint the menu; MUST be called at some stage - normall AFTER all the menu items have been create.} Private MainMenus : Array[0..32] of HMenu; {max 32 main MainMenus} MenuCount : Word; {number of main MainMenus created} end;{end of CRT object} {////////////////////////////////////////////////} Var OldCRTProc : TFarProc;{pointer to old window function} NewCRTHandle : HWND; {handle to CRT window} implementation var NewCRTProc : TFarProc; {pointer to new window function} Var DefMenuFunc:aMenuFunc;{menu command function} {////////////////////////////////////////////////} function NewDefaultMsgHandler(Window : HWnd; Message : Word; {default message handler - if none is specified in call to HookedInitWinCRT} wParam : Word; lParam : LongInt) : LongInt; export; begin case Message of wm_Command : begin case WParam of cm_User1 .. cm_UserMax: If @DefMenuFunc<> Nil then DefMenuFunc(WParam); end; end; end; NewDefaultMsgHandler := CallWindowProc(OldCRTProc, Window, Message, wParam, lParam); end; {////////////////////////////////////////////////} {////////////////////////////////////////////////} {////////////////////////////////////////////////} {////////////////////////////////////////////////} Constructor TNewCrtClass.{$ifdef Delphi}Create{$else}Init{$endif}; Begin Inherited {$ifdef Delphi}Create;{$else}Init;{$endif} HWindow := HookedInitWinCrt (Left,Top,width,height,Title,aWinProc,MenuFunc); FillChar(MainMenus, Sizeof(MainMenus), #0); MainMenus[0] := CreateMenu; MenuCount := 0; End; {////////////////////////////////////////////////} Destructor TNewCrtClass.{$ifDef Delphi}Destroy{$else}Done{$endif}; Begin FillChar(MainMenus, Sizeof(MainMenus), #0); MenuCount := 0; HWindow := 0; HookedDoneWinCRT; {$ifdef Delphi} Inherited Destroy; {$else} Inherited Done; {$endif} End; {////////////////////////////////////////////////} Procedure TNewCrtClass.MakeMainMenu; Begin If MenuCount>=32 then Exit; If Tag > 0 then AppendMenu(MainMenus[0], mf_Enabled, Tag, Caption) else begin Inc(MenuCount); MainMenus[MenuCount] := CreateMenu; AppendMenu(MainMenus[0], mf_PopUp or mf_Enabled, MainMenus[MenuCount], Caption); end; End; {////////////////////////////////////////////////} Procedure TNewCrtClass.MakeSubMenu; Begin If (ParentNum<1) or (ParentNum>32) then exit; AppendMenu(MainMenus[ParentNum], mf_Enabled, Tag, Caption); End; {////////////////////////////////////////////////} Procedure TNewCrtClass.MakeSeparator; Begin If (ParentNum<1) or (ParentNum>32) then exit; AppendMenu(MainMenus[ParentNum], mf_Separator,0, ''); End; {////////////////////////////////////////////////} Procedure TNewCrtClass.AssignCRTMenu; Begin SetMenu(HWindow,MainMenus[0]); End; {////////////////////////////////////////////////} {////////////////////////////////////////////////} function GetCRTWindowHandle: HWnd; {return handle to the CRT window} begin ClrScr; {force active window} GetCRTWindowHandle := GetActiveWindow; end; {////////////////////////////////////////////////} Procedure GetScreenResolution(Var aTPoint : TPoint); {get the current screen resolution and return it in "T"} Var HD : HDC; Wn : HWnd; Begin Wn := GetDesktopWindow; Hd := GetDC(Wn); With aTPoint do begin X := GetDeviceCaps(Hd, HorzRes); Y := GetDeviceCaps(Hd, VertRes); End; ReleaseDC(Wn, Hd); End; {////////////////////////////////////////////////} Procedure SetWindowCoordinates; {set up CRT window for possible scrolling} Var aPoint : tpoint; aReal : real; anInt : integer; Begin GetScreenResolution(aPoint); With aPoint do begin aReal := Y /25; If y > 768 then aReal := (aReal*13.2) else If Y >= 600 then aReal := (aReal*15.8) else aReal := (aReal*18.4); anInt := round(aReal + 25); WindowSize.Y := anInt; If X > 800 then anInt := 11 else anInt := 10; WindowSize.X := (ScreenSize.X * anInt); end; End; {////////////////////////////////////////////////} {////////////////////////////////////////////////} Function HookedInitWinCRT; {initialise the new crt stuff} Begin {window location coordinates} With WindowOrg do begin x := Left; y := Top; end; {the size of the CRT window buffer} With ScreenSize do begin x := Width; y := Height; end; {setup the window properly} SetWindowCoordinates; {set window title} lStrCpy(WindowTitle, Title); {call WinCRT.InitWinCRT} InitWinCrt; {get the CRT window handle} NewCRTHandle := GetCRTWindowHandle; {SetWindowText(NewCRTHandle, Title);} {save old window proc} OldCRTProc := TFarProc(GetWindowLong(NewCRTHandle, gwl_WndProc)); {assign new window proc} If @aWinProc<>Nil then NewCrtProc := MakeProcInstance(@aWinProc, hInstance) else NewCrtProc := MakeProcInstance(@NewDefaultMsgHandler, hInstance); {make it happen!} SetWindowLong(NewCRTHandle, gwl_WndProc, LongInt(NewCrtProc)); {assign CRT menu proc} If @MenuFunc <> Nil then DefMenuFunc := MenuFunc; {if custom icon used, assign it} If CrtappIcon<>0 then SetClassWord(NewCRTHandle, gcw_hIcon, CrtappIcon); {return handle of CRT window} HookedInitWinCRT := NewCRTHandle; End; {////////////////////////////////////////////////} Function HookedDoneWinCRT; {dispose of the new crt window} begin DoneWinCrt; {call WinCRT.DoneWinCrt} HookedDoneWinCRT:=True; {do other stuff} CrtappIcon := 0; NewCRTHandle:=0; FreeProcInstance(NewCrtProc); DefMenuFunc := Nil; end; {////////////////////////////////////////////////} {////////////////////////////////////////////////} {////////////////////////////////////////////////} {///////// initialisation block /////////////////} {////////////////////////////////////////////////} begin CrtappIcon := 0; NewCRTHandle := 0; DefMenuFunc := Nil; end. {////////////////////////////////////////////////} {////////////////////////////////////////////////} {// TEST PROGRAM: shows usage of HOOKCRT2.PAS ///} {////////////////////////////////////////////////} {////////////////////////////////////////////////} Program TestCRT; {$ifdef Ver80} {$Define Delphi} {$endif Ver80} uses {$ifdef Delphi}Messages,{$endif}WinTypes, WinProcs, HookCrt2, WinCrt; {menu constants: start from 1 - to infinity} Const cm_Exit = 1; cm_About = 2; cm_Clear = 3; Var TestCrtObj : TNewCrtClass; {////////////////////////////////////////////////} {////////////////////////////////////////////////} Procedure ExecMenus(Const Tag:Integer);forward; {a sample procedure to process menu choices} function ShellAbout(hwnd:HWND; Title,Text:PChar; icon:HICON):integer; external 'SHELL' index 22; {an "About" function} {////////////////////////////////////////////////} {////////////////////////////////////////////////} function TestProc(Window : HWnd; Message : Word; wParam : Word; lParam : LongInt) : LongInt; export; {sample new menu handler} begin case Message of wm_char : begin {MessageBeep(0);} end; wm_LButtonDown : MessageBox(NewCrtHandle,'Left button','Mouse',MB_OK); wm_Command : begin case WParam of cm_User1 .. cm_UserMax: ExecMenus(WParam); end; end; end; {call the old window proc = essential!} TestProc := CallWindowProc(OldCRTProc, Window, Message, wParam, lParam); end; {////////////////////////////////////////////////} Procedure ExecMenus(Const Tag:Integer); Begin Case Tag of cm_About: ShellAbout(NewCrtHandle,'Hooked CRT#Cedar Island Software & The Chief','Hello World, from the Chief!', CrtappIcon); cm_Exit: TestCrtObj.{$ifDef Delphi}Free{$else}Done{$endif}; {HookedDoneWinCRT;} cm_Clear: begin clrscr; gotoxy(1,1); end; End; End; {////////////////////////////////////////////////} procedure DoTest; var Name : String; begin LoadString(GetModuleHandle('USER'),514,@Name[1],79); Name[0]:=Char(LStrLen(@Name[1])); Writeln('Hello ',Name); Writeln('Welcome to a Subclassed WinCRT World!'); readln; end; {////////////////////////////////////////////////} {////////////////////////////////////////////////} {//////////// program block ////////////////////} begin TestCrtObj{$ifdef Delphi}:= TNewCrtClass.Create{$else}.Init{$endif} (1,1,80,25,'Chief''s Hooked CRT Window',TestProc,ExecMenus); With TestCrtObj do begin MakeMainMenu('&File ', 0); MakeSubMenu(1, '&New', 0); MakeSubMenu(1, '&Open...', 0); MakeSubMenu(1, '&Save', 0); MakeSubMenu(1, 'Save &As ...', 0); MakeSeparator(1); MakeSubMenu(1,'E&xit', cm_Exit); MakeMainMenu('&Edit ', 0); MakeSubMenu(2,'Cu&t Shift+Del', 0); MakeSubMenu(2,'&Copy Ctrl+Ins', 0); MakeSubMenu(2, '&Paste Shift+Ins', 0); MakeSubMenu(2, 'C&lear Ctrl+Del', cm_Clear); MakeSeparator(2); MakeSubMenu(2,'E&xit', cm_Exit); MakeMainMenu('&Help ', 0); MakeSubMenu(3,'&Contents Shift+F1', 0); MakeSubMenu(3,'&Topic Search', 0); MakeSubMenu(3,'&Using Help', 0); MakeSeparator(3); MakeSubMenu(3,'&About ...', cm_About); MakeSeparator(3); MakeSubMenu(3,'E&xit', cm_Exit); AssignCrtMenu; {this MUST be called after creating all menus!!} DoTest; {call a test procedure} {dispose of object and CRT window} {$ifDef Delphi}Free{$else}Done{$endif}; end; end. [----------------------- end cut ------------------------] Warmest regards, The Chief --------- Dr. Abimbola A. Olowofoyeku (The African Chief) Keele University, England (and, The Great Elephant) Email: laa12@keele.ac.uk or, chief@mep.com http://ourworld.compuserve.com/homepages/African_Chief/chief.htm