Windows 7登录Delphi中的屏幕保护程序

时间:2011-04-06 14:12:56

标签: delphi windows-7 screensaver authentication

使用Delphi应用程序作为Windows 7登录屏幕保护程序(对于32位和64位Windows)时遇到问题。即使是空白应用程序(没有任何额外代码的新项目)也会引发错误。

Delphi 7应用程序抛出“内存无法读取”错误,Delphi 2010应用程序抛出“应用程序中发生异常未知软件异常”,然后“运行时错误217”。在任何表单初始化之前和异常处理程序的任何初始化之前都会发生此错误。

将notepad.exe设置为登录屏幕保护程序正常。

这里有什么想法?

2 个答案:

答案 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)

经过一番玩耍后。这必须连接到Delphi隐藏的主(实际主窗口)窗口,您需要认真看看Application.initialise或Application.HookMainWindow()。

因为令人惊讶的是这段代码不会引起问题:

program w7logonsaver;
{$APPTYPE CONSOLE}

var
  i: Integer;
begin
  for i := 1 to 20 do
    writeln;
  write('K ');
  ReadLn;
end.

点击Enter即可退出。