我正在处理使用来自sourceforge.net的FastMM4
的应用程序。
所以我在开头就将FastMM4.pas
添加到uses子句中。在应用程序中,我需要在batch
FinalizeMemoryManager;
之后finalization
之后运行unit FastMM4;
个文件
initialization
RunInitializationCode;
finalization
{$ifndef PatchBCBTerminate}
FinalizeMemoryManager;
RunTheBatFileAtTheEnd; //my code here..calling a procedure
{$endif}
end.
然后我的 RunTheBatFileAtTheEnd 的代码是:
procedure RunTheBatFileAtTheEnd;
begin
//some code here....
sFilePaTh:=SysUtils.ExtractFilePath(applicaTname)+sFileNameNoextension+'_log.nam';
ShellExecute(applcatiOnHAndle,'open', pchar(sExeName),pchar(sFilePaTh), nil, SW_SHOWNORMAL) ;
end;
为此我需要在fastmm4单位的uses子句中使用SysUtils,shellapi
。 但使用它们
这条消息来了
但是,如果我从其使用中移除SysUtils,shellapi
它。
我仍然需要安装fastmm4的所有功能,但使用SysUtils,shellapi
,未安装fastmm4
我有自己的单位,但最终确定是在fastmm4终结之前执行的。
任何人都可以告诉我如何解决这个问题?
EDIT-1
unit FastMM4;
//...
...
implementation
uses
{$ifndef Linux}Windows,{$ifdef FullDebugMode}{$ifdef Delphi4or5}ShlObj,{$else}
SHFolder,{$endif}{$endif}{$else}Libc,{$endif}FastMM4Messages,SysUtils,shellapi;
我的申请
program memCheckTest;
uses
FastMM4,
EDIT-2:
(在@SertacAkyuz回答之后),我删除了SysUtils
并且它有效,但我仍然需要运行批处理文件以通过RunTheBatFileAtTheEnd
打开外部应用程序。原因是..我想要一个外部应用程序只在FastMM4之后才能运行finalization
。 sExeName
是运行文件sFilePaTh
(.nam)的应用程序。任何人都可以告诉你怎么做?没有uninstalling FastMM4
。
答案 0 :(得分:5)
FastMM检查默认内存管理器是否已设置,然后通过调用'system.pas'中的IsMemoryManagerSet
函数安装自己的内存管理器。如果设置了默认内存管理器,它将拒绝设置自己的内存管理器并显示问题中显示的消息。
关于'fastmm4.pas'的消息中的指令应该是项目的.dpr文件中的第一个单元假设'fastmm4.pas'本身没有被修改。
当您修改'fastmm4.pas'的uses子句时,如果uses子句中包含的任何单元都有initialization
部分,那么该部分代码必须在'的初始化部分之前运行' fastmm4.pas'。如果该代码需要通过RTL分配/收费内存,则设置默认内存管理器。
因此,你必须小心改变'fastmm4.pas',不要在uses子句中包含任何这样的单位,比如'sysutils.pas'。
下面的示例代码(没有错误检查,文件检查等..)显示如何使用记事本启动FastMM的日志文件(如果存在日志文件),而不分配任何内存:
var
CmdLine: array [0..300] of Char; // increase as needed
Len: Integer;
SInfo: TStartupInfo;
PInfo: TProcessInformation;
initialization
... // fastmm code
finalization
{$ifndef PatchBCBTerminate}
FinalizeMemoryManager; // belongs to fastmm
// Our application is named 'Notepad' and the path is defined in AppPaths
CmdLine := 'Notepad "'; // 9 Chars (note the opening quote)
Len := windows.GetModuleFileName(0, PChar(@CmdLine[9]), 260) + 8;
// assumes the executable has an extension.
while CmdLine[Len] <> '.' do
Dec(Len);
CmdLine[Len] := #0;
lstrcat(CmdLine, '_MemoryManager_EventLog.txt"'#0); // note the closing quote
ZeroMemory(@SInfo, SizeOf(SInfo));
SInfo.cb := SizeOf(SInfo);
CreateProcess(nil, CmdLine, nil, nil, False,
NORMAL_PRIORITY_CLASS, nil, nil, sInfo, pInfo);
{$endif}
end.
答案 1 :(得分:1)
我同意Sertac的回答,但如果你坚持使用SysUtils.pas
,我也想提出建议。答案是不要使用它,并从中提取所需的内容并将其放入您自己的副本中。以下是您需要的内容 - ExtractFilePath
使用LastDeliminator
,使用StrScan
,还有2个常量,因此我将它们复制到这个新单元并命名为MySysUtils.pas
。< / p>
这也广泛用于那些不想编写一堆他们永远不会使用的额外代码的人(你必须绝对确定它不会在任何单位的任何地方使用)。
unit MySysUtils;
interface
const
PathDelim = '\';
DriveDelim = ':';
implementation
function StrScan(const Str: PWideChar; Chr: WideChar): PWideChar;
begin
Result := Str;
while Result^ <> #0 do begin
if Result^ = Chr then
Exit;
Inc(Result);
end;
if Chr <> #0 then
Result := nil;
end;
function LastDelimiter(const Delimiters, S: string): Integer;
var
P: PChar;
begin
Result := Length(S);
P := PChar(Delimiters);
while Result > 0 do begin
if (S[Result] <> #0) and (StrScan(P, S[Result]) <> nil) then
Exit;
Dec(Result);
end;
end;
function ExtractFilePath(const FileName: string): string;
var
I: Integer;
begin
I := LastDelimiter(PathDelim + DriveDelim, FileName);
Result := Copy(FileName, 1, I);
end;
end.