使用Delphi应用程序作为Windows 7登录屏幕保护程序(对于32位和64位Windows)时遇到问题。即使是空白应用程序(没有任何额外代码的新项目)也会引发错误。
Delphi 7应用程序抛出“内存无法读取”错误,Delphi 2010应用程序抛出“应用程序中发生异常未知软件异常”,然后“运行时错误217”。在任何表单初始化之前和异常处理程序的任何初始化之前都会发生此错误。
将notepad.exe设置为登录屏幕保护程序正常。
这里有什么想法?
答案 0 :(得分:5)
正如我在评论中所说,它不是"隐形代码",只是某些单元的初始化部分中的代码导致了问题。我设法追查罪魁祸首(至少其中一个 - 可能还有其他人)。
使用Forms
单位时,它依赖于Classes
单位。
初始化部分调用InitThreadSynchronization
,其中包括以下内容:
SyncEvent := CreateEvent(nil, True, False, '');
if SyncEvent = 0 then
RaiseLastOSError;
从登录屏幕调用时,似乎API调用CreateEvent
失败。不幸的是,我不确定登录屏幕:(a)完全禁止CreateEvent
(b)需要CreateEventEx
或(c)使用适当的lpEventAttributes
参数。我发布了一个更具体的问题,希望能找到:CreateEvent from Windows-7 Logon Screen
您可以使用以下控制台应用验证问题:
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
。
SIDE-RANT :这是使用初始化部分的问题的主要示例。仅仅包括一个单元可能会引入不必要的副作用。他们主要是无害的,但在这种情况下不是。现在你可能会说
Classes.pas
臃肿,我不会争辩。但重点是,如果从DPR中将类初始化称为显式,则此问题将更容易识别并找到解决方法。
正如Remy Lebeau在我发布的另一个问题中指出的那样 这一行:
SyncEvent := CreateEvent(nil, True, False, '');
必须更改为:
SyncEvent := CreateEvent(nil, True, False, nil);
由于此解决方案涉及重新编译VCL单元,您可能需要查看有关此主题的previous questions中的一些
将此作为唯一的更改(在D2009中编译),我能够在登录屏幕上成功显示空白表单。但是,请记住,由于Logon屏幕的安全限制,您通常可以预期能够做的一些事情将会被禁止。
答案 1 :(得分:1)
因为令人惊讶的是这段代码不会引起问题:
program w7logonsaver;
{$APPTYPE CONSOLE}
var
i: Integer;
begin
for i := 1 to 20 do
writeln;
write('K ');
ReadLn;
end.
点击Enter即可退出。