Delphi-屏幕键盘(osk.exe)在Win32上有效,但在Win64上失败 [英] Delphi - On Screen Keyboard (osk.exe) works on Win32 but fails on Win64

查看:506
本文介绍了Delphi-屏幕键盘(osk.exe)在Win32上有效,但在Win64上失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从我的应用程序中运行屏幕键盘。它在Windows XP 32位下可以正常工作,但在Win 7 64位下不能正常工作。

I'm trying to run the on screen keyboard from my application. It works correctly under Windows XP 32 bits, but incorrect under Win 7 64 bits.

unit Unit5;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ShellAPI;

type
  TForm5 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
   class function IsWOW64: Boolean;
    { Public declarations }
  end;

var
  Form5: TForm5;

implementation

{$R *.dfm}


procedure TForm5.FormCreate(Sender: TObject);
var path:String;
    res : Integer;

function GetSysDir: string;
var
  Buf: array[0..MAX_PATH] of Char;
  Len: UINT;
  S: String;
begin
  {$IFNDEF WIN64}
  if TForm5.IsWOW64 then
  begin
    Len := GetWindowsDirectory(Buf, MAX_PATH);
    if Len = 0 then RaiseLastOSError;
    SetString(S, Buf, Len);
    Result := IncludeTrailingPathDelimiter(S) + 'Sysnative\';
    Exit;
  end;
  {$ENDIF}
  Len := GetSystemDirectory(Buf, MAX_PATH);
  if Len = 0 then RaiseLastOSError;
  SetString(S, Buf, Len);
  Result := IncludeTrailingPathDelimiter(S);
end;

begin
 path := GetSysDir;

 path := path + 'osk.exe';

  res := ShellExecute(self.Handle,'open',Pchar(path),nil,nil,SW_NORMAL);

 if res <> 42 then
  begin
   ShowMessage(path);
   RaiseLastOSError;
  end;
end;

class function TForm5.IsWOW64: Boolean;
type
  TIsWow64Process = function( // Type of IsWow64Process API fn
    Handle: THandle;
    var Res: BOOL
  ): BOOL; stdcall;
var
  IsWow64Result: BOOL;              // result from IsWow64Process
  IsWow64Process: TIsWow64Process;  // IsWow64Process fn reference
begin
  // Try to load required function from kernel32
  IsWow64Process := GetProcAddress(
    GetModuleHandle('kernel32'), 'IsWow64Process'
  );
  if Assigned(IsWow64Process) then
  begin
    // Function is implemented: call it
    if not IsWow64Process(GetCurrentProcess, IsWow64Result) then
     RaiseLastOSError;
    // Return result of function
    Result := IsWow64Result;
  end
  else
    // Function not implemented: can't be running on Wow64
    Result := False;
end;


end.

在x64下运行应用程序会显示路径C:\Windows\Sysnative\osk.exe ,并引发调用OS功能失败错误。

Running the application under x64 reveals the path C:\Windows\Sysnative\osk.exe , and raise a 'call to an OS function failed' error.

搜索Windows目录显示osk.exe存在

Searching on windows directories reveals that osk.exe exists

推荐答案

在UAC下的osk。此代码失败,错误代码为740, ERROR_ELEVATION_REQUIRED 请求的操作需要提升

There is something special about osk under UAC. This code fails with error code 740, ERROR_ELEVATION_REQUIRED, The requested operation requires elevation.

var
  si: TStartupInfo;
  pi: TProcessInformation;
....
si.cb := SizeOf(si);
GetStartupInfo(si);
Win32Check(CreateProcess('C:\Windows\system32\osk.exe', nil, nil, nil, 
  False, 0, nil, nil, si, pi));

在具有UAC的计算机上,这在32位和64位进程下均失败。您可以在此处找到有关此问题的一些讨论:> https://web.archive.org/web/20170311141004/http://blog.delphi-jedi.net/2008/05 / 17 / the-case-of-shellexecute-shellexecuteex-createprocess-and-oskexe /

This fails under both 32 and 64 bit processes on machines with UAC. You can find some discussion of the issue here: https://web.archive.org/web/20170311141004/http://blog.delphi-jedi.net/2008/05/17/the-case-of-shellexecute-shellexecuteex-createprocess-and-oskexe/

所以您的问题与32位或64位无关,

So your problem is not related to 32 or 64 bit, rather it is down to your XP system not having UAC.

更广泛地说,我认为这应该足以说服您不要调用 ShellExecute 。它仅存在16位兼容性,并且在报告错误时毫无用处。如果您想出错,请调用 ShellExecuteEx 。但是,由于我们正在开始一个新过程,因此 CreateProcess 通常是调用的正确API。

More broadly I think this should be enough to convince you never to call ShellExecute again. It only exists for 16 bit compatibility and is singularly useless at reporting errors. If you want errors call ShellExecuteEx. However, since we are starting a new process, CreateProcess would normally be the right API to call.

,在这种特定情况下,osk的设计无法通过 CreateProcess 以编程方式启动。它确实需要由 ShellExecute ShellExecuteEx 调用。这允许外壳执行其UAC魔术。现在,事实证明魔术无法从32位WOW64进程中发生。然后,解决方案是从64位进程开始osk,并调用 ShellExecuteEx

That said, in this specific case the design of osk is such that it cannot be started programmatically by CreateProcess. It does need to be invoked by ShellExecute, or ShellExecuteEx. This allows the shell to perform its UAC magic. Now, it turns out that magic cannot happen from a 32 bit WOW64 process. The solution then is to start osk from a 64 bit process with a call to ShellExecuteEx.

这是您的解决方法:


  1. 在32位系统上,只需调用 ShellExecuteEx 打开 osk

  2. 在64位系统上,如果您的进程是64位,则可以再次调用 ShellExecuteEx 打开 osk

  3. 在64位系统上,如果您的进程是32位WOW64进程,则您需要启动一个单独的64位进程,该进程依次调用 ShellExecuteEx 打开 osk

  1. On a 32 bit system, you can simply call ShellExecuteEx to open osk.
  2. On a 64 bit system, if your process is 64 bit, you can again call ShellExecuteEx to open osk.
  3. On a 64 bit system, if your process is 32 bit WOW64 process, you need to start a separate 64 bit process which in turn calls ShellExecuteEx to open osk.

由于您似乎没有使用64位版本的Delphi,因此需要找到64位编译器。您可以使用64位fpc或64位C ++编译器。以下C ++程序就足够了:

Since you don't appear to be using a 64 bit version of Delp you'll need to find a 64 bit compiler. You could use the 64 bit fpc, or a 64 bit C++ compiler. The following C++ program is enough:

#include <Windows.h>
#include <Shellapi.h>

int CALLBACK WinMain(
  HINSTANCE hInstance,
  HINSTANCE hPrevInstance,
  LPSTR lpCmdLine,
  int nCmdShow
)
{
    SHELLEXECUTEINFOW sei = { sizeof(sei) };
    sei.lpVerb = L"open";
    sei.lpFile = L"osk.exe";
    sei.nShow = SW_SHOW;
    ShellExecuteExW(&sei);
}

您可以使用64位C ++编译器进行编译,然后从您的计算机上调用32位WOW64进程。我知道之以鼻,但这确实具有实际工作的优点!

You can compile that with a 64 bit C++ compiler and then call it from your 32 bit WOW64 process. Long winded I know, but it does have the merit of actually working!

这篇关于Delphi-屏幕键盘(osk.exe)在Win32上有效,但在Win64上失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆