Delphi-屏幕键盘(osk.exe)在Win32上有效,但在Win64上失败 [英] Delphi - On Screen Keyboard (osk.exe) works on Win32 but fails on 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
.
这是您的解决方法:
- 在32位系统上,只需调用
ShellExecuteEx
打开osk
。 - 在64位系统上,如果您的进程是64位,则可以再次调用
ShellExecuteEx
打开osk
。 - 在64位系统上,如果您的进程是32位WOW64进程,则您需要启动一个单独的64位进程,该进程依次调用
ShellExecuteEx
打开osk
。
- On a 32 bit system, you can simply call
ShellExecuteEx
to openosk
. - On a 64 bit system, if your process is 64 bit, you can again call
ShellExecuteEx
to openosk
. - 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 openosk
.
由于您似乎没有使用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屋!