Delphi中的Windows7登录屏幕保护程序
我在使用Delphi应用程序作为Windows 7登录屏幕保护程序(适用于32位和64位Windows)时遇到问题。即使是空白的应用程序(没有任何额外代码的新项目)也会抛出错误 Delphi 7应用程序抛出“内存无法读取”错误,Delphi 2010应用程序抛出“应用程序中发生的异常未知软件异常”,然后抛出“运行时错误217”。此错误发生在任何窗体初始化之前以及任何异常处理程序初始化之前 将notepad.exe设置为登录屏幕保护程序可以正常工作Delphi中的Windows7登录屏幕保护程序,delphi,windows-7,screensaver,authentication,Delphi,Windows 7,Screensaver,Authentication,我在使用Delphi应用程序作为Windows 7登录屏幕保护程序(适用于32位和64位Windows)时遇到问题。即使是空白的应用程序(没有任何额外代码的新项目)也会抛出错误 Delphi 7应用程序抛出“内存无法读取”错误,Delphi 2010应用程序抛出“应用程序中发生的异常未知软件异常”,然后抛出“运行时错误217”。此错误发生在任何窗体初始化之前以及任何异常处理程序初始化之前 将notepad.exe设置为登录屏幕保护程序可以正常工作 你知道这里发生了什么吗?玩了一会儿。这必须连接到
你知道这里发生了什么吗?玩了一会儿。这必须连接到Delphi的隐藏主窗口(real main),您需要认真查看Application.initialise或Application.HookMainWindow() 因为令人惊讶的是,这段代码没有引起问题:
program w7logonsaver;
{$APPTYPE CONSOLE}
var
i: Integer;
begin
for i := 1 to 20 do
writeln;
write('K ');
ReadLn;
end.
只需按enter键即可退出。正如我在评论中所说,这不是“看不见的代码”,而是导致问题的某个单元的初始化部分的代码。我已经设法找到了罪犯(至少有一个——可能还有其他人) 使用
表单
单元时,它依赖于类
单元
初始化部分调用InitThreadSynchronization
,其中包括以下调用:
SyncEvent := CreateEvent(nil, True, False, '');
if SyncEvent = 0 then
RaiseLastOSError;
当从登录屏幕中调用API时,似乎API调用CreateEvent
失败。不幸的是,我不确定登录屏幕:(a)完全禁止CreateEvent
(b)需要CreateEventEx
,或者(c)是否可以使用适当的lpEventAttributes
参数。我发布了一个更具体的问题,希望能找到答案:
您可以使用以下控制台应用程序验证问题:
program TestLoginScreensaver;
{$APPTYPE CONSOLE}
uses
Windows,
SysUtils;
var
SyncEvent: THandle;
begin
try
SyncEvent := CreateEvent(nil, True, False, '');
if SyncEvent = 0 then
RaiseLastOSError;
CloseHandle(SyncEvent); //So handle is closed if it was created (e.g. while logged in)
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
Readln;
end.
SyncEvent
的目的是启用TThread
实例同步回主线程。因此,如果您编写一个单线程应用程序,或者使用TThread
以外的其他方法创建线程,您实际上根本不需要/使用SyncEvent
侧向RANT:这是使用初始化部分时出现问题的一个主要示例。仅仅包括一个单位就有可能带来不必要的副作用。它们基本上是无害的,但在这种情况下不是。现在你可能会争辩说Classes.pas
太臃肿了,我不会争辩。但关键是,如果从DPR显式地调用类初始化,那么这个问题将更容易识别并找到解决方法
编辑:新解决方案 正如Remy Lebeau在我发布的另一个问题中指出的那样。
该行:
SyncEvent := CreateEvent(nil, True, False, '');
必须更改为:
SyncEvent := CreateEvent(nil, True, False, nil);
由于此解决方案涉及到重新编译VCL单元,因此您可能需要在这个主题上进行一些讨论
由于这是唯一的更改(在D2009中编译),我能够成功地在登录屏幕上显示一个空白表单。但是,请记住,由于登录屏幕上的安全限制,您通常希望能够执行的某些操作将是禁止的。(而且我刚刚尝试了NOTEPAD.EXE作为登录屏幕保护程序!真是一团糟!我还必须尝试File/Open来查看我可以访问和不能访问的内容!)Andreas:LOL;)现在我想将spectrum 3加载程序屏幕设置为登录屏幕保护程序。因此,我们需要找出如何做到这一点@AndreasRejbrand从File/Open,您可以按住Shift键并右键单击文件夹以打开命令提示符。我可以运行regedit,但无法更改任何内容。似乎安全限制确实限制了您可以做的一些事情。然而,更可怕的是,这样做不是为了.DEFAULT,而是为了你自己的用户帐户。“屏幕保护程序”(即记事本)在您自己帐户的上下文中运行。你仍然拥有完全的访问权限。换句话说,即使我在没有点击切换用户进入主登录屏幕的情况下锁定桌面,我也不会被锁定!它发生在Application.Initialize之前。我想在一些不可见的代码中。@Kaitnieks不是“不可见的”,只是在某个单元的初始化部分编写代码。您可以通过在程序中包含/排除某些单元来缩小VCL单元的范围。这听起来非常复杂,所以我现在不能去测试解决方案,但我没有理由怀疑这是否有效,所以我接受您的答案。您不需要重新编译RTL/VCL。由于有问题的代码仅出现在
实现
部分,而不是接口
部分,因此您可以复制Classes.pas
并对其进行相应修改,然后将修改后的文件直接添加到项目中。修改后的代码将覆盖从RTL导入的本机代码。只需确保运行时包已禁用,否则将无法工作。@RemyLebeau Correct;正如你所说@Kaitnieks,澄清一下。。。解决方案只是对Classes.pas
做了一点小小的更改。当我说“包括重新编译VCL单元”:我不是说你必须重新编译“整个RTL/VCL”Controls.pas
。我有点惊讶,因为我的改变只是执行;为什么像Forms.pas这样的其他单位不行?但我没有进一步调查。重新编译VCL单元的问题链接在您遇到问题时会有所帮助。Classes.pas
错误现已报告给QC: