首页 > 解决方案 > PowerShell 和 WinApi

问题描述

我正在尝试这个:

$signature = @'
[DllImport("shell32.dll")]
public static extern int ShellExecuteW(
  int    hwnd,
  string lpOperation,
  string lpFile,
  string lpParameters,
  string lpDirectory,
  int     nShowCmd
);
'@

$exec = Add-Type -memberDefinition $signature -name "win" -namespace Win32Functions -passThru

$exec::ShellExecuteW(0, "open", "notepad.exe", 0, 0, 1)

但记事本没有启动。我如何正确地写下来?

标签: powershellwinapi

解决方案


立即修复是双重的:

  • [DllImport("shell32.dll")]->
    [DllImport("Shell32.dll", CharSet = CharSet.Unicode)]

    • 由于您明确定位ShellExecuteW- API 函数的UnicodeCharSet版本 - 您必须通过属性中的字段声明该事实。[1]

    • 虽然不是绝对必要的,int hwnd但应该是IntPtr hwnd.

  • $exec::ShellExecuteW(0, "open", "notepad.exe", 0, 0, 1)->
    $exec::ShellExecute(0, "open", "notepad.exe", [NullString]::Value, [NullString]::Value, 1)

    • 注意[NullString]::Value传递nullstring-typed 参数的使用;默认情况下,PowerShell$null在字符串上下文中将其视为空字符串,而不是null; 但是,在这种特殊情况下,空字符串(因此$null)也可以工作。

把它们放在一起:

$exec = Add-Type -name "win" -namespace Win32Functions -passThru -memberDefinition @'
[DllImport("shell32.dll", CharSet=CharSet.Unicode)]
public static extern int ShellExecuteW(
  IntPtr hwnd,
  string lpOperation,
  string lpFile,
  string lpParameters,
  string lpDirectory,
  int    nShowCmd
);
'@

$exec::ShellExecuteW(
  0, 
  'open', 
  'notepad.exe', 
  [NullString]::Value, 
  [NullString]::Value, 
  1
)

退后一步:Start-Processcmdlet 允许您执行相同的操作,而无需按需编译的 P/Invoke 声明:

# Use -WorkingDirectory, if  needed.
Start-Process Notepad.Exe -Verb Open -WindowStyle Normal

[1]在指定值的情况下省略W后缀( ShellExecute)在实践中也很有效,尽管文档暗示随后会调用ANSI版本。但是,我在实践中看不到这一点:即使将带有 ANSI 范围之外的字符(例如,)的参数显式传递给函数的 ANSI 版本,它们似乎也正确地传递给了记事本。然而,相反地,将这样的字符串传递给控制台应用程序似乎永远不会正确地传递它们,即使明确针对 Unicode 版本也是如此。CharSet'file€§ü.txt'


推荐阅读