home *** CD-ROM | disk | FTP | other *** search
- {$define RETAIL_VERSION}
- {!$define WIN32}
- {***************************************************************************
- Source File Name : ALCHECK.PAS
- Autor : Mario M. Westphal
- Erstellt am : 10.07.1992
-
- Compiler : Turbo Pascal for Windows 1.5
- Betriebssystem : DOS 5.0, Windows 3.x
- Compiler-Schalter : -
-
- Bemerkungen : -
-
- Beschreibung : AlCheck dient zum ▄berprⁿfen von Programmen auf
- den Verbrauch folgender Ressourcen:
- -Globaler Heap
- -USER Heap
- -GDI Heap
- -Filehandles
-
- Revisionen : 1.00 10.07.1992 created (MW)
- 1.10 07.04.1993 revisited (MW)
- ****************************************************************************}
- {$M 8192,8192}
- {$A+,B-,D+,F-,G+,I-,L+,N-,R+,S+,V+,W-,X+,Q+}
-
- {$ifdef RETAIL_VERSION}
- {$D-,L-,S-,R-,Q-}
- {$endif}
-
- program AllocationChecker;
- {$R ALCHECK.RES}
-
- uses
- WinTypes,
- WinProcs,
- Objects,
- OMemory,
- OWindows,
- ODialogs,
- Win31,
- Strings,
- MMSystem,
- BWCC,
- WinDos,
- ToolHelp,
- Stress,
- Validate,
- SysTools,
- ExDlg;
-
-
- {$I ALCHECK.IDS : Stringtabellen-IDs }
-
- const
- APPNAME = 'Allocation Checker';
- INIFILENAME = 'ALCHECK.INI';
-
- { Schalter }
- iddlg_BtnFix = 200;
- iddlg_BtnCheck = 201;
- iddlg_BtnStart = 202;
-
- { Fixiert }
- iddlg_GlobalF = 101;
- iddlg_UserF = 102;
- iddlg_GDIF = 103;
- iddlg_HandlesF = 104;
-
- { Aktuell }
- iddlg_GlobalA = 110;
- iddlg_UserA = 111;
- iddlg_GDIA = 112;
- iddlg_HandlesA = 113;
-
- { Steuerelemente }
- iddlg_Interval = 121; { Interval Edit }
- iddlg_HandleUpd = 122; { Handles aktualisieren }
- iddlg_OnTop = 123; { Immer Oben }
- iddlg_Logging = 124; { Logfile mitfⁿhren }
- iddlg_Message = 130; { Messagefeld }
-
- { Sytemmenⁿ }
- idmsys_About = 999; { "About"-Kommando im Systemmenⁿ }
-
-
- type
- { Struktur fⁿr die ⁿberwachten Ressourcen }
- TCheckRec = record
- lGlobalMem : LongInt;
- lUserMem : LongInt;
- lGDIMem : LongInt;
- iHandles : Integer;
- end;
-
- type
- { Spalte Fixiert und Aktuell }
- TDlgRec = record
- FixRec : TCheckRec;
- CurRec : TCheckRec;
- end;
-
- type
- { Ableitung mit neuen Eigenschaften. Die Methode Error gibt einen aus der Stringtabelle }
- { geladenen Text aus. Im Feld Parent wird das Elternfenster gespeichert. Dieses wird }
- { fⁿr die MessageBox ben÷tigt, da der Hauptfenster-Dialog durch den Stil HWND_TOPMOST }
- { die MessageBox sonst ⁿberdecken wⁿrde. ▄ber dieses Handle kann bei einem Fehler der }
- { Fokus wieder auf das Eltern (Edit) - Fenster gesetzt werden. }
- PRangeVal = ^TRangeVal;
- TRangeVal = object(TRangeValidator)
- Parent : PEdit;
- constructor Init(AParent: PEdit; AMin, AMax: Longint);
- procedure Error; virtual;
- end;
-
- {-------------------------------------------------------------------------------
- Setzt das Feld Parent auf AParent und ruft den Konstruktor des Vorfahren auf.
- }
- constructor TRangeVal.Init(AParent: PEdit; AMin, AMax: Longint);
- begin
- Inherited Init(AMin,AMax);
- Parent := AParent;
- end;
-
- {-------------------------------------------------------------------------------
- Gibt eine Meldung aus und setzt anschlie▀end den Fokus auf das zugeordnete
- Edit-Feld.
- }
- procedure TRangeVal.Error;
- var
- s : array[0..255] of Char;
- a : array[0..3] of Word;
- begin
- { Bastle einen String mit Bereichsangaben }
- a[0] := LoWord(Min);
- a[1] := HiWord(Min);
- a[2] := LoWord(Max);
- a[3] := HiWord(Max);
- wvsprintf(s,LoadStr(ids_InvalidInterval),a);
- MessageBox(Parent^.HWindow,s,APPNAME,mb_Ok or mb_IconExclamation);
- SetFocus(Parent^.HWindow);
- Parent^.SetSelection(0,Parent^.GetTextLen);
- end;
-
-
- type
- PMWindow = ^TMWindow;
- TMWindow = object(TDlgWindow)
- lpDlgRec : TDlgRec; { Struktur: Informationen im Dialog }
- lInterval : LongInt; { Intervall-Zeit in ms }
- bIntervalOn : Boolean; { Intervall Ein/Aus }
- wRegMsg : Word; { Systemweiter Nachrichtencode }
- tfLogFile : Text; { Logdatei }
- peInterval : PEdit; { ▄berprⁿfung des Intervals }
-
- { Inheritance }
- constructor Init (AParent: PWindowsObject; ATitle: PChar);
- procedure SetupWindow; virtual;
- destructor Done; virtual;
- function GetClassName: PChar; virtual;
- procedure GetWindowClass(var AWndClass: TWndClass); virtual;
-
- { Special message handling }
- procedure WMSysCommand (var Msg: TMessage);
- virtual wm_First or wm_SysCommand;
- procedure DefWndProc (var Msg: TMessage); virtual;
-
- { Ressource checking and message logging }
- procedure UpdateLogFile (Notification: PChar);
- procedure GetActualValues (var DR: TCheckRec; CheckHandles: Boolean);
- procedure UpdateFixValues;
- procedure UpdateActualValues;
-
- { Message handling }
- procedure WMDLGFix (var Msg: TMessage);
- virtual id_First or iddlg_BtnFix;
- procedure WMDLGCheck (var Msg: TMessage);
- virtual id_First or iddlg_BtnCheck;
- procedure IntervalBtn (var Msg: TMessage);
- virtual id_First or iddlg_BtnStart;
- procedure OnTopBtn (var Msg: TMessage);
- virtual id_First or iddlg_OnTop;
- procedure WMTimer (var Msg: TMessage);
- virtual wm_First or wm_Timer;
-
- { INI-files }
- procedure ReadINIData;
- procedure WriteINIData;
- end;
-
- {*******************************************************************************}
- { TMWindow }
- {*******************************************************************************}
- constructor TMWindow.Init (AParent : PWindowsObject; ATitle: PChar);
- begin
- Inherited Init(AParent, 'DLG_MAINWINDOW');
- { Erzeuge eine systemweit eindeutige Nachricht }
- wRegMsg := RegisterWindowMessage('ALCHECK_NOTIFY');
- { Editfeld fⁿr den Intervall... }
- New(peInterval,InitResource(@Self,iddlg_Interval,6));
- { ...und ein Validierungsobjekt }
- peInterval^.SetValidator(New(PRangeVal,Init(peInterval,250,65000)));
- end;
-
- {-------------------------------------------------------------------------------
- ╓ffnet das Logfile und lie▀t die Daten aus der INI-Datei ein. Fⁿgt dem
- Systemmenⁿ eine "About"-Option hinzu.
- }
- procedure TMWindow.SetupWindow;
- var
- hmnuSys : HMenu;
-
- { Existiert die Logdatei, wird sie im Modus }
- { Append ge÷ffnet, ansonsten neu angelegt. }
- procedure OpenLogFile;
- var
- sz : array[0..255] of Char;
- szT : array[0..20] of Char;
- y,m,d,dow : Word;
- begin
- {$ifopt I+}
- {$define I_ON}
- {$I-}
- {$endif}
- { Die Logdatei wird in selben Verzeichnis wie ALCHECK }
- { angelegt und erhΣlt den Namen ALCHECK.LOG. }
- GetModuleFileName(HInstance,sz,SizeOf(sz));
- FileSplit(sz,sz,szT,szT);
- if sz[StrLen(sz)-1] <> '\' then StrCat(sz,'\');
- Assign(tfLogFile,StrCat(sz,'ALCHECK.LOG'));
- { Immer zuerst im Modus "Append" }
- Append(tfLogFile);
- if IOResult <> 0 then Rewrite(tfLogFile);
-
- FillChar(sz,80,'-');
- sz[80] := #0;
- WriteLn(tfLogFile,sz);
-
- { Datum und Uhrzeit eintragen }
- GetDate(y,m,d,dow);
- wvsprintf(szT,'%02u',m);
- Write(tfLogFile,d:2,'.',szT,'.',y,' - ');
- GetTime(d,m,dow,dow);
- wvsprintf(szT,'%02u',m);
- WriteLn(tfLogFile,d,':',szT);
- WriteLn(tfLogFile,sz);
- {$ifdef I_ON}
- {$undef I_ON}
- {$I+}
- {$endif}
- end;
-
-
- begin
- Inherited SetupWindow;
- SetWindowText(HWindow,APPNAME);
-
- bIntervalOn := false;
-
- { Initialisierungsdatei auslesen }
- ReadINIData;
-
- { Logdatei anlegen }
- OpenLogFile;
-
- { "About"-Eintrag in das Systemmenⁿ einhΣngen }
- hmnuSys := GetSystemMenu(HWindow,false);
- AppendMenu(hmnuSys,mf_SEPARATOR,$FFFF,nil);
- AppendMenu(hmnuSys,mf_STRING,idmsys_About,LoadStr(ids_About));
-
- { Wird als Flag fⁿr UpdateActualValues verwendet: -1 => Keine Filehandles anzeigen }
- lpDlgRec.CurRec.iHandles := -1;
- lpDlgRec.FixRec.iHandles := -1;
- end;
-
- {-------------------------------------------------------------------------------
- Timer freigeben, Logdatei schlie▀en und die INI-Daten wegschreiben.
- }
- destructor TMWindow.Done;
- begin
- KillTimer(HWindow,1);
- Close(tfLogFile);
- WriteINIData;
- Inherited Done;
- end;
-
- {-------------------------------------------------------------------------------
- Der Klassenname wird fⁿr FindWindow ben÷tigt.
- }
- function TMWindow.GetClassName: PChar;
- begin
- GetClassName := 'BorDlgWin-ALCHECK';
- end;
-
- {-------------------------------------------------------------------------------
- }
- procedure TMWindow.GetWindowClass(var AWndClass: TWndClass);
- begin
- Inherited GetWindowClass(AWndClass);
- AWndClass.hIcon := LoadIcon(HInstance,'APP_ICON');
- end;
-
- {-------------------------------------------------------------------------------
- Bearbeitet die "About"-Option im Systemmenⁿ.
- }
- procedure TMWindow.WMSysCommand (var Msg: TMessage);
- begin
- if LoWord(Msg.wParam) = idmsys_About then
- begin
- Application^.ExecDialog(New(PCtrDialog,Init(@Self,'DLG_ABOUT',CTRDLG_PARENT)));
- end
- else
- DefWndProc(Msg);
- end;
-
- {-------------------------------------------------------------------------------
- ▄berschrieben, um die Kommunikationsnachrichten von AlCheckNotify abzufangen.
- }
- procedure TMWindow.DefWndProc (var Msg: TMessage);
- begin
- if Msg.Message = wRegMsg then
- begin
- { Eine Anwendung hat eine Nachricht fⁿr ALCHECK }
- SetDlgItemText(HWindow,iddlg_Message,PChar(Msg.lParam));
- GetActualValues(lpDlgRec.CurRec,IsDlgButtonChecked(HWindow,iddlg_HandleUpd) > 0);
- UpdateActualValues;
- if Msg.wParam <> 0 then
- begin
- { Neu fixieren }
- GetActualValues(lpDlgRec.FixRec,IsDlgButtonChecked(HWindow,iddlg_HandleUpd) > 0);
- UpdateFixValues;
- end;
- UpdateLogFile(PChar(Msg.lParam));
- end
- else
- Inherited DefWndProc(Msg);
- end;
-
- {-------------------------------------------------------------------------------
- TrΣgt die aktuellen Werte in das Logfile ein.
- }
- procedure TMWindow.UpdateLogFile (Notification: PChar);
- begin
- if IsDlgButtonChecked(HWindow,iddlg_Logging) > 0 then
- begin
- WriteLn(tfLogFile,'[',Notification,']');
- WriteLn(tfLogFile,LoadStr(ids_LogFileHeader));
- WriteLn(tfLogFile,' ',lpDlgRec.CurRec.lGlobalMem:10,' ',lpDlgRec.FixRec.lGlobalMem);
- WriteLn(tfLogFile,' ',lpDlgRec.CurRec.lUserMem:10 ,' ',lpDlgRec.FixRec.lUserMem);
- WriteLn(tfLogFile,' ',lpDlgRec.CurRec.lGDIMem:10 ,' ',lpDlgRec.FixRec.lGDIMem);
- if IsDlgButtonChecked(HWindow,iddlg_HandleUpd) > 0 then
- WriteLn(tfLogFile,' ',lpDlgRec.CurRec.iHandles:10 ,' ',lpDlgRec.FixRec.iHandles)
- else
- WriteLn(tfLogFile,LoadStr(ids_LogFileNoHandles));
- WriteLn(tfLogFile);
- end;
- end;
-
- {-------------------------------------------------------------------------------
- Ermitteln der aktuellen Systemressourcen. Wird "CheckHandles" als true
- ⁿbergeben, wird zusΣtzlich die Anzahl der freien File-Handles ermittelt.
- }
- procedure TMWindow.GetActualValues (var DR: TCheckRec; CheckHandles: Boolean);
- var
- lpSysHeap : TSysHeapInfo;
- begin
- lpSysHeap.dwSize := SizeOf(lpSysHeap);
- SystemHeapInfo(@lpSysHeap);
- with DR do
- begin
- GlobalCompact(0); { Bei Bedarf! }
- lGlobalMem := GetFreeSpace(0) div 1024;
- lUserMem := lpSysHeap.wUserFreePercent;
- lGDIMem := lpSysHeap.wGDIFreePercent;;
- if CheckHandles then iHandles := GetFreeFileHandles
- end;
- end;
-
- {-------------------------------------------------------------------------------
- Die fixierten Werte aktualisieren
- }
- procedure TMWindow.UpdateFixValues;
- var sz : array[0..100] of Char;
- begin
- with lpDlgRec.FixRec do
- begin
- Str(lGlobalMem,sz);
- StrCat(sz,' KB');
- SetDlgItemText(HWindow,iddlg_GlobalF,sz);
-
- Str(lUserMem,sz);
- StrCat(sz,'%');
- SetDlgItemText(HWindow,iddlg_UserF,sz);
-
- Str(lGDIMem,sz);
- StrCat(sz,'%');
- SetDlgItemText(HWindow,iddlg_GDIF,sz);
-
- if iHandles < 0 then
- StrCopy(sz,'?')
- else
- Str(iHandles,sz);
- SetDlgItemText(HWindow,iddlg_HandlesF,sz);
- end;
- end;
-
- {-------------------------------------------------------------------------------
- Die aktuellen Werte neu eintragen.
- }
- procedure TMWindow.UpdateActualValues;
- var sz : array[0..100] of Char;
- begin
- with lpDlgRec.CurRec do
- begin
- Str(lGlobalMem,sz);
- StrCat(sz,' KB');
- SetDlgItemText(HWindow,iddlg_GlobalA,sz);
-
- Str(lUserMem,sz);
- StrCat(sz,'%');
- SetDlgItemText(HWindow,iddlg_UserA,sz);
-
- Str(lGDIMem,sz);
- StrCat(sz,'%');
- SetDlgItemText(HWindow,iddlg_GDIA,sz);
-
- if iHandles < 0 then
- StrCopy(sz,'?')
- else
- Str(iHandles,sz);
- SetDlgItemText(HWindow,iddlg_HandlesA,sz);
- end;
- end;
-
- {-------------------------------------------------------------------------------
- Btn-Response: Aktuelle Ressourcen neu fixieren.
- }
- procedure TMWindow.WMDLGFix (var Msg: TMessage);
- begin
- GetActualValues(lpDlgRec.FixRec,IsDlgButtonChecked(HWindow,iddlg_HandleUpd) > 0);
- UpdateFixValues;
- UpdateLogFile(LoadStr(ids_Manual));
- end;
-
- {-------------------------------------------------------------------------------
- Btn-Response: Aktuelle Werte neu eintragen.
- }
- procedure TMWindow.WMDLGCheck (var Msg: TMessage);
- begin
- GetActualValues(lpDlgRec.CurRec,IsDlgButtonChecked(HWindow,iddlg_HandleUpd) > 0);
- UpdateActualValues;
- UpdateLogFile(LoadStr(ids_Manual));
- end;
-
- {-------------------------------------------------------------------------------
- Btn-Response: Intervall ein- oder ausschalten
- }
- procedure TMWindow.IntervalBtn (var Msg: TMessage);
- var
- sz : array[0..5] of Char;
- szCaption : array[0..100] of Char;
- nCode : Integer;
- begin
- if not bIntervalOn then
- begin
- { ▄berprⁿfe den Wert im Intervall-Editfeld. Wird ein ungⁿltiger Wert gefunden, }
- { wird dieser gemeldet und der Timer wird nicht gestartet. }
- if not peInterval^.IsValid(true) then exit;
-
- if SetTimer(HWindow,1,lInterval,nil) <> 0 then
- begin
- bIntervalOn := true;
- peInterval^.GetText(sz,SizeOf(sz));
- Val(sz,lInterval,nCode);
- SetDlgItemText(HWindow,iddlg_BtnStart,LoadStr(ids_Stop));
- GetActualValues(lpDlgRec.CurRec,IsDlgButtonChecked(HWindow,iddlg_HandleUpd) > 0);
- UpdateActualValues;
- { ─ndere die Caption, um den aktiven Status des Timers anzuzeigen }
- StrCopy(szCaption,APPNAME);
- StrCat(szCaption,LoadStr(ids_Running));
- SetWindowText(HWindow,szCaption);
- end
- else
- begin
- MessageBox(HWindow,LoadStr(ids_NoSystemTimer),APPNAME,mb_Ok or mb_IconStop);
- end;
- end
- else
- begin
- { Interval ausschalten }
- bIntervalOn := false;
- StrCopy(szCaption,APPNAME);
- SetWindowText(HWindow,szCaption);
- FlashWindow(HWindow,false);
- KillTimer(HWindow,1);
- SetDlgItemText(HWindow,iddlg_BtnStart,LoadStr(ids_Start));
- end;
- end;
-
- {-------------------------------------------------------------------------------
- Btn-Response: Das Fenster zwischen 'Immer Oben' und normaler Z-Ordnung
- umschalten.
- }
- procedure TMWindow.OnTopBtn (var Msg: TMessage);
- begin
- if IsDlgButtonChecked(HWindow,iddlg_OnTop) > 0 then
- SetWindowPos(HWindow,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE or SWP_NOMOVE)
- else
- SetWindowPos(HWindow,HWND_NOTOPMOST,0,0,0,0,SWP_NOSIZE or SWP_NOMOVE);
- end;
-
- {-------------------------------------------------------------------------------
- Realisiert alle Aktionen, die beim Auftreten eines Timer-Ereignisses
- ausgefⁿhrt werden mⁿssen.
- }
- procedure TMWindow.WMTimer (var Msg: TMessage);
- begin
- FlashWindow(HWindow,true);
- GetActualValues(lpDlgRec.CurRec,IsDlgButtonChecked(HWindow,iddlg_HandleUpd) > 0);
- UpdateActualValues;
- UpdateLogFile(LoadStr(ids_Interval));
- end;
-
- {-------------------------------------------------------------------------------
- Lie▀t die EintrΣge aus der INI-Datei und setzt die entsprechenden Optionen.
- }
- procedure TMWindow.ReadINIData;
- var
- x, y : Integer;
- u : Word;
- sz : array[0..20] of Char;
- begin
- { Position }
- x := GetPrivateProfileInt(APPNAME,'XPos',100,INIFILENAME);
- y := GetPrivateProfileInt(APPNAME,'YPos',100,INIFILENAME);
-
- { Update Filehandles }
- u := GetPrivateProfileInt(APPNAME,'UpdateHandles',0,INIFILENAME);
- if u <> 0 then CheckDlgButton(HWindow,iddlg_HandleUpd,1);
-
- { Always on top }
- u := GetPrivateProfileInt(APPNAME,'OnTop',0,INIFILENAME);
- if u <> 0 then
- begin
- CheckDlgButton(HWindow,iddlg_OnTop,1);
- SetWindowPos(HWindow,HWND_TOPMOST,x,y,0,0,SWP_NOSIZE)
- end
- else
- SetWindowPos(HWindow,0,x,y,0,0,SWP_NOZORDER or SWP_NOSIZE);
-
- { Logdatei }
- u := GetPrivateProfileInt(APPNAME,'Logging',0,INIFILENAME);
- if u <> 0 then CheckDlgButton(HWindow,iddlg_Logging,1);
-
- { Interval }
- lInterval := GetPrivateProfileInt(APPNAME,'Interval',1000,INIFILENAME);
- Str(lInterval,sz);
- peInterval^.SetText(sz);
- end;
-
- {-------------------------------------------------------------------------------
- Schreibt die aktuellen Einstellungen in die INI-Datei.
- }
- procedure TMWindow.WriteINIData;
- var
- rc : TRect;
- s : array[0..20] of Char;
- begin
- { Position }
- GetWindowRect(HWindow,rc);
- Str(rc.Left,s);
- WritePrivateProfileString(APPNAME,'XPos',s,INIFILENAME);
- Str(rc.Top,s);
- WritePrivateProfileString(APPNAME,'YPos',s,INIFILENAME);
-
- { Update Filehandles }
- if IsDlgButtonChecked(HWindow,iddlg_HandleUpd) > 0 then
- WritePrivateProfileString(APPNAME,'UpdateHandles','1',INIFILENAME)
- else
- WritePrivateProfileString(APPNAME,'UpdateHandles','0',INIFILENAME);
-
- { Always on top }
- if IsDlgButtonChecked(HWindow,iddlg_OnTop) > 0 then
- WritePrivateProfileString(APPNAME,'OnTop','1',INIFILENAME)
- else
- WritePrivateProfileString(APPNAME,'OnTop','0',INIFILENAME);
-
- { Logdatei }
- if IsDlgButtonChecked(HWindow,iddlg_Logging) > 0 then
- WritePrivateProfileString(APPNAME,'Logging','1',INIFILENAME)
- else
- WritePrivateProfileString(APPNAME,'Logging','0',INIFILENAME);
-
- { Interval }
- peInterval^.GetText(s,SizeOf(s));
- WritePrivateProfileString(APPNAME,'Interval',s,INIFILENAME);
- end;
-
- {*******************************************************************************}
- { M A I N }
- {*******************************************************************************}
- type
- TACApplication = object(TApplication)
- procedure InitMainWindow; virtual;
- end;
-
- procedure TACApplication.InitMainWindow;
- begin
- MainWindow := New(PMWindow, Init(nil, APPNAME));
- end;
-
- var
- ThisApp : TACApplication;
- hwndOld : HWnd;
- hwndDlg : HWnd;
-
- begin
- { Wegen der Logdatei kann ALCHECK nur einmal gestartet werden. }
- { ▄berprⁿfe, ob schon eine Instanz lΣuft. Wenn ja, bringe sie }
- { in den Vordergrund, ansonsten erzeuge eine neue Instanz. }
- hwndOld := FindWindow('BorDlgWin-ALCHECK',nil);
- if hwndOld = 0 then
- begin
- ThisApp.Init(APPNAME);
- ThisApp.Run;
- ThisApp.Done;
- end
- else
- begin
- { Ist ein Popup-Window offen? Wenn ja, mu▀ dieses auch nach oben gebracht werden! }
- hwndDlg := GetLastActivePopup(hwndOld);
- BringWindowToTop(hwndOld);
- if hwndDlg <> hwndOld then BringWindowToTop(hwndDlg);
- end;
- end.
-