首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >德尔福屏幕键盘(osk.exe)在Win32上工作,但在Win64上失败。

德尔福屏幕键盘(osk.exe)在Win32上工作,但在Win64上失败。
EN

Stack Overflow用户
提问于 2014-04-16 17:23:45
回答 3查看 6.9K关注 0票数 4

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

代码语言:javascript
运行
复制
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函数失败”错误。

在windows目录上搜索显示存在osk.exe。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-04-17 08:27:47

在UAC下,osk有一些特别之处。此代码与错误代码740,ERROR_ELEVATION_REQUIRED失败,请求的操作需要提升。

代码语言:javascript
运行
复制
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/

因此,您的问题与32位或64位无关,而是因为您的XP系统没有UAC。

更广泛地说,我认为这应该足以说服你不要再打电话给ShellExecute了。它只存在于16位兼容性,在报告错误时是非常无用的。如果需要错误,请打电话给ShellExecuteEx。然而,由于我们正在开始一个新的过程,CreateProcess通常是正确的调用API。

也就是说,在这种特殊情况下,osk的设计不能由CreateProcess以编程方式启动。它确实需要由ShellExecuteShellExecuteEx调用。这允许shell执行其UAC魔术。现在,事实证明,魔术不可能发生在32位WOW64进程。然后,解决方案是通过调用ShellExecuteEx从64位进程启动osk。

这是你的解决办法:

  1. 在32位系统上,只需调用ShellExecuteEx来打开osk
  2. 在64位系统上,如果您的进程是64位,您可以再次调用ShellExecuteEx来打开osk
  3. 在64位系统上,如果您的进程是32位WOW64进程,则需要启动单独的64位进程,然后调用ShellExecuteEx打开osk

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

代码语言:javascript
运行
复制
#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进程调用它。我知道,它确实有实际工作的优点!

票数 4
EN

Stack Overflow用户

发布于 2019-01-14 11:28:23

代码语言:javascript
运行
复制
Function Wow64DisableWow64FsRedirection(Var Wow64FsEnableRedirection: LongBool): LongBool; StdCall;
  External 'Kernel32.dll' Name 'Wow64DisableWow64FsRedirection';

Var
  Wow64FsEnableRedirection: LongBool;
begin
  if Wow64DisableWow64FsRedirection(Wow64FsEnableRedirection) then ShellExecute(0,nil, 'osk.exe', nil, nil, SW_show);
end;
票数 1
EN

Stack Overflow用户

发布于 2018-11-04 12:48:25

另一个简单得多的选项是在ShellExecute中使用ShellExecute,如下所示:

代码语言:javascript
运行
复制
{  
If UTExistFile(GetWindowsSystemDir() + '\OSK.exe') then  
// we can "see" OSK.exe in the System32 folder, so we are running on 
// 32-bit Windows, so no problem accessing OSK.EXE in System32.
ShellExecute(Application.Handle,       // HWND hwnd
       'open',                   // LPCTSTR lpOperation
        LPCTSTR(GetWindowsSystemDir() + '\OSK.exe'), // LPCTSTR lpFile
        '',                        // LPCTSTR lpParameters
        '',                        // LPCTSTR lpDirectory,
        SW_Show)                   // INT nShowCmd
else     
// Use SysNative to get at OSK.EXE. This will not work for 64-bit OS 
// before Vista (e.g. XP), but it won't lock or crash your system and at
// least you can compile and run the application on all versions of Windows;
// both 32 and 64 bit.
ShellExecute(Application.Handle,    // HWND hwnd
    'open',                         // LPCTSTR lpOperation
    LPCTSTR(GetWindowsDir() + '\SysNative\OSK.EXE'),  // LPCTSTR lpFile
    '',                            // LPCTSTR lpParameters
    '',                            // LPCTSTR lpDirectory,
    SW_Show) ;                     // INT nShowCmd
}

它在64位Windows 10上运行得很好。理论上,我还没有尝试过其他版本的操作系统,这应该适用于所有版本的操作系统,除了64位的前Vista版本,在这种情况下OSK不会显示,但是32位编译的应用程序将在所有版本的Windows 32位和64位上运行。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23116149

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档