【问题标题】:delphi 7, FastMM4 cannot install work arounddelphi 7,FastMM4 无法安装解决方法
【发布时间】:2012-05-28 12:33:20
【问题描述】:

我正在开发一个使用来自sourceforge.netFastMM4 的应用程序。 所以我在开头就将FastMM4.pas 添加到了uses 子句中。在应用程序中,我需要像这样在finalizationfinalization 中的FinalizeMemoryManager; 之后运行batch 文件

  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 最终化之前执行的。

谁能告诉我如何解决这个问题?

编辑- 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

【问题讨论】:

  • 哪个使用子句?如果在界面中,您使 FastMM4 依赖于它们,它们将首先被初始化,包括它们所依赖的任何单元。在那里完成的任何内存分配都会导致这种情况。您是否尝试过将这两个单元移至实施条款?这应该会改变依赖顺序。
  • @MarjanVenema :我为使用条款添加了新代码,SysUtils,shellapi;implementation
  • 你必须不用'sysutils'。 'sysutils' 的初始化部分的代码需要分配内存,因此必须设置内存管理器。
  • @SertacAkyuz 好的,所以sysutils 是问题所在,我会尝试一下

标签: delphi delphi-7 fastmm


【解决方案1】:

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.

【讨论】:

  • 我需要sFilePaTh:=SysUtils.ExtractFilePath(applicaTname),如果没有SysUtils,我将无法获得,那么有什么方法可以获取应用程序文件路径吗? (甚至是`application.exe')。
  • ok..问题:Notepad "我的应用程序名称是tracker.exe我如何写它来代替Notepad "
  • @Presley - 更好地使用完整路径。计算字符,就像在答案中一样。 CmdLine:='C:\somefolder\tracker.exe ",使用 27 个字符,然后是 Len:=GetModuleFileName(0,PChar(@CmdLine[27]),..)。增加 CmdLine 的大小以增加使用空间:var CmdLine:array[0..350] of Char 等。使用调试器跟踪 CmdLine 的构建方式。
  • 我刚刚尝试了它与硬编码路径一起工作,但是我如何获取我的应用程序的路径(安装路径),因为我无法使用注册表..如何???
  • @Presley - 一种选择是在“应用程序路径”键或环境路径 (link) 中注册您的应用程序,这样您就不必找到它。另一种可以尝试直接使用apiregistry functions,但我认为无法在cmets中锻炼更多细节。
【解决方案2】:

我同意 Sertac 的回答,但如果您坚持使用SysUtils.pas,也想给个建议。答案是不要使用它,并从中提取您需要的内容并将其放入您自己的副本中。下面是您需要的 - ExtractFilePath 使用了 LastDeliminator,它使用了 StrScan,还有 2 个常量,所以我将它们复制到这个新单元中并命名为 MySysUtils.pas

这也被广泛用于那些不想编译一堆他们永远不会使用的额外代码的人(你必须绝对确定它不会在任何单元的任何地方使用)。

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.

【讨论】:

  • +1,嘿,绝招。!!但是Application.ExeName 使用forms.pas 怎么办,我仍然会遇到同样的问题,即无法安装 Fastmm4,那么在这种情况下该怎么办?获取Application.ExeName
  • @Presley - 您可以使用“GetModuleFileName”,因为这就是 VCL 用于 ParamStr(0) 的方式。示例实现请参见this answer(您可以使用函数的 ansi 版本)。
  • @SertacAkyuz 好的,但我想你错过了链接
  • 我只是看不到在 FastMM 初始化之前进行这种需要使用内存的调用的可能性。我正在挠头,试图理解为什么需要将这种类型的代码放在 FastMM4.pas 中。
  • @JerryDodge :我正在尝试创建一个应用程序,它将打开我由fastmm4 创建的log 文件,该文件恰好是在FinalizeMemoryManager 之后创建的(最终确定)..i现在希望我的应用程序弹出并显示log 文件,我猜这只有在FinalizeMemoryManager 完成执行之后才有可能......你能帮我在FinalizeMemoryManager 之后运行我的应用程序吗?
猜你喜欢
  • 2013-11-24
  • 2014-05-09
  • 1970-01-01
  • 2021-09-04
  • 1970-01-01
  • 1970-01-01
  • 2014-11-19
  • 2014-03-25
  • 1970-01-01
相关资源
最近更新 更多