在 Windows 和 Delphi 中实现应用程序的可移植性?
我们的这个应用程序不会写入 Windows 注册表或将其配置文件(例如 INI 文件)存储在用户的配置文件中;相反,它将其配置文件存储在程序的目录中。维基百科有这样的说法
便携式应用程序(便携式应用程序)是一种设计为独立于操作系统运行的计算机软件程序。此类应用程序存储在可移动存储设备上,例如 CD、USB 闪存驱动器、闪存卡 - 将其程序文件、配置信息和数据单独存储在存储介质上。
所以我们的问题是,这是否使我们的应用程序成为真正的便携式应用程序(portable app)?
我应该指出,如果应用程序位于写保护介质上,我们将使用下面的函数,因此它不会尝试写入该介质。
function GetTempFile(): string;
var
Buffer: array[0..MAX_PATH] of Char;
begin
Windows.ZeroMemory(@Buffer, System.SizeOf(Buffer));
SysUtils.StrPCopy(Buffer, SysUtils.ExcludeTrailingBackslash(SysUtils.ExtractFilePath(System.ParamStr(0))));
Windows.GetTempFileName(Buffer, '~', 0, Buffer);
Result := string(Buffer);
end;
function IsMediumWriteProtected(): Boolean;
var
ErrorMode: Word;
hHandle: THandle;
begin
ErrorMode := Windows.SetErrorMode(SEM_FAILCRITICALERRORS);
try
hHandle := Windows.CreateFile(PChar(GetTempFile()), GENERIC_WRITE, 0, nil,
CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY or FILE_FLAG_DELETE_ON_CLOSE, 0);
try
Result := (hHandle = INVALID_HANDLE_VALUE);
finally
Windows.CloseHandle(hHandle);
end;
finally
Windows.SetErrorMode(ErrorMode);
end;
end;
We have this application that does not write to the Windows registry or store its configuration files (such as an INI file) in the user's profile; instead, it stores its configuration files in the program's directory. Wikipedia has this statement
A portable application (portable app) is a computer software program designed to run independently from an operating system. This type of application is stored on a removable storage device such as a CD, USB flash drive, flash card - storing its program files, configuration information and data on the storage medium alone.
so our question is, does this make our application a true portable application (portable app)?
I should point out that if the application is on a write protected medium we use the function below, so it doesn't try to write to that medium.
function GetTempFile(): string;
var
Buffer: array[0..MAX_PATH] of Char;
begin
Windows.ZeroMemory(@Buffer, System.SizeOf(Buffer));
SysUtils.StrPCopy(Buffer, SysUtils.ExcludeTrailingBackslash(SysUtils.ExtractFilePath(System.ParamStr(0))));
Windows.GetTempFileName(Buffer, '~', 0, Buffer);
Result := string(Buffer);
end;
function IsMediumWriteProtected(): Boolean;
var
ErrorMode: Word;
hHandle: THandle;
begin
ErrorMode := Windows.SetErrorMode(SEM_FAILCRITICALERRORS);
try
hHandle := Windows.CreateFile(PChar(GetTempFile()), GENERIC_WRITE, 0, nil,
CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY or FILE_FLAG_DELETE_ON_CLOSE, 0);
try
Result := (hHandle = INVALID_HANDLE_VALUE);
finally
Windows.CloseHandle(hHandle);
end;
finally
Windows.SetErrorMode(ErrorMode);
end;
end;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果这确实是您的问题,那么一个真正的便携式应用程序应该:
我自己对便携式应用程序的格式塔定义并不总是要求应用程序位于只读位置时可以工作,除了这个维基百科参考之外,我不确定它是否是标准的荒野。很高兴您尝试遵循维基百科文章中阐明的法律条文。令我恼火的是,您从维基百科文章中引用的内容包含一些内部矛盾;如果定义既期望必须支持 CDROM(或者您的应用程序不可移植),又指定数据应单独存储在该介质上。你遇到了这种矛盾,现在违反了法律条文的一部分,以避免违反法律的第一部分。因此,该定义要么阻止您在这种情况下保存任何内容,要么该定义实际上本身并不是一条法律,并且只要遵循我上面提到的两点,您就可以自由地做您想做的事。
我上面给出的便携式应用程序的极简定义是,除了这两点之外,您所做的事情应该是适合您的用户的。
我真的不明白 SO 上的任何人怎么能为你的可移植性开绿灯。您只能通过测试来真正验证可移植性,最好是由一群人(例如 Beta 测试或现场测试用户)进行测试。我也不认为 StackOverflow 是请求帮助测试二进制文件的好地方。这是一个用于提出编程问题的网站,而不是用于形成 Beta 测试、现场测试等或用于推广您的应用程序。事实上,我不明白我们如何安全地从您那里下载二进制文件,而不会让我们的系统冒运行我们从此处链接下载的二进制代码的风险。我建议您删除二进制文件的链接。
我要做的测试:
将其放在 USB 密钥上,并在多个不同的干净 Windows 系统上的几台不同 PC 上运行它,包括 XP、Vista、Win 7、多个服务包级别的 Windows Server 2008(无 SP、Sp1) 、XP 上的 Sp2、Sp3 等),以及几个不同的脏系统(安装了 Visual Studio、安装了 Delphi、安装了 Office 和各种防病毒系统的系统)。
确保您不需要外部运行时 BPL/DLL 或其他运行时内容,除了与可执行文件位于同一文件夹中的内容(并排配置)。这样,您的应用程序无需修改用户的路径即可运行,并且您不必担心 DLL 地狱混乱。
检查您的应用程序中是否没有在应用程序文件夹之外发生注册表写入或文件系统写入。 SysInternals Process Monitor 非常适合此操作。
A truly portable application, if that is truly your question, should:
My own gestalt definition of a portable app does not always require that the app work when it is located on a read-only place, and other than this wikipedia reference, I am not sure that it's standard in the wild. It's great that you're trying to follow the letter of the law as spelled out in Wikipedia articles. It irks me that the quote you have given from the Wikipedia article contains a bit of an internal contradiction; if the definition both expects that a CDROM must be supported (or your app is not portable) and also specifies that the data should be stored on that media alone. You have run into that contradiction, and are now violating one part of the letter of the law, to avoid violating the first part of it. So the definition either prevents you from saving anything at all in that case, or that definition isn't in fact, a law unto itself, and you're free to do as you like, provided the two points I mention above are followed.
A minimalist definition of portable app is the one I gave above, and what you do beyond those two points, should be whatever is right for your users.
I really don't see how anyone on SO can give you a green light on portability. You can only truly verify portability by testing, and ideally testing by a group of people, such as beta test or fieldtest users. I also don't see StackOverflow as a good place for requests for help testing binaries. This is a site for asking programming questions, not for forming beta tests, field-tests etc, or for promoting your app. In fact I don't see how we could safely download a binary from you and not be risking our systems running binary code we downloaded from links here. I recommend you remove the link to the binaries.
Tests I would do:
Put it on a usb key, and run it on several different PCs on several different clean windows systems, including XP, Vista, Win 7, Windows Server 2008 at several service pack levels (no SP, Sp1, Sp2, Sp3 on XP etc), and on several different dirty systems (systems with visual studio installed, delphi installed, office installed, and various anti-virus systems).
Be sure you require no external runtime BPLs/DLLs or other runtime stuff, except those located in the same folder as your executable (side by side configuration). That way the user's path does not have to be modified for your app to work, and you don't have to worry about DLL hell confusion.
Check that no registry writes or filesystem writes outside the app folder occur in your app. SysInternals Process Monitor is great for this.
不要使用
Windows.GetCurrentDirectory()
检索可执行文件的目录。它返回进程的当前工作目录,该目录可以在进程的生命周期内动态更改,因此不能保证您每次都能获得正确的目录。要可靠地获取应用的目录,请改用Sysutils.ExtractFilePath(Sysutils.ParamStr(0))
。在内部,这使用 Windows.GetModuleFileName(nil) 来获取应用程序的完整路径,然后截断可执行文件名称,留下所需的目录路径。Do not use
Windows.GetCurrentDirectory()
to retrieve the executable file's directory. It returns the process's current working directory, which can change dynamically during the process's lifetime, so you are not guaranteed to get the correct directory every time. To get the app's directory reliably, useSysutils.ExtractFilePath(Sysutils.ParamStr(0))
instead. Internally, this usesWindows.GetModuleFileName(nil)
to get the full path of your app and then truncates off the executable name, leaving the desired directory path.