【问题标题】:Marshal.GetLastWin32Error() does not return the errorMarshal.GetLastWin32Error() 不返回错误
【发布时间】:2021-08-09 21:01:31
【问题描述】:

不明白哪里错了。

我正在尝试调用 CreateProcess,但没有成功。

这是调用 CreateProcess winapi 函数的代码:

$param = [CodeDom.Compiler.CompilerParameters]::new()
$param.CompilerOptions = "/unsafe"
Add-Type -CompilerParameters $param -TypeDefinition '
using System.Runtime.InteropServices;
using System;

public class Win32{
    [StructLayout(LayoutKind.Sequential)]
    public struct PROCESS_INFORMATION{
        public IntPtr hProcess;
        public IntPtr hThread;
        public int dwProcessId;
        public int dwThreadId;
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_ATTRIBUTES{
        public int ln;
        public unsafe byte* lpSecurityDescriptor;
        public int bInheritHandle;
    }
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct STARTUPINFO{
        public Int32 cb;
        public string lpReserved;
        public string lpDesktop;
        public string lpTitle;
        public Int32 dwX;
        public Int32 dwY;
        public Int32 dwXSize;
        public Int32 dwYSize;
        public Int32 dwXCountChars;
        public Int32 dwYCountChars;
        public Int32 dwFillAttribute;
        public Int32 dwFlags;
        public Int16 wShowWindow;
        public Int16 cbReserved2;
        public IntPtr lpReserved2;
        public IntPtr hStdInput;
        public IntPtr hStdOutput;
        public IntPtr hStdError;
    }

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    public static extern bool CreateProcess(
        string lpApplicationName,
        string lpCommandLine,
        ref SECURITY_ATTRIBUTES lpProcessAttributes,
        ref SECURITY_ATTRIBUTES lpThreadAttributes,
        bool bInheritHandles,
        uint dwCreationFlags,
        IntPtr lpEnvironment,
        string lpCurrentDirectory,
        ref STARTUPINFO lpStartupInfo,
        ref PROCESS_INFORMATION lpProcessInformation
    );
}'

$path = "C:\Windows\System32\notepad.exe" 
$lpCurrentDirectory = ""
$CommandLine = ""
$lpEnvironment  = [IntPtr]::Zero
$PRIORITY_CLASS = [UInt32]0x0020
$sInfo    = [win32+STARTUPINFO]::new()
$pInfo    = [win32+PROCESS_INFORMATION]::new()
$pSec     = [win32+SECURITY_ATTRIBUTES]::new()
$tSec     = [win32+SECURITY_ATTRIBUTES]::new()
$sInfo.cb = [Runtime.InteropServices.Marshal]::SizeOf($sInfo)
$pSec.ln  = [Runtime.InteropServices.Marshal]::SizeOf($pSec)
$tSec.ln  = [Runtime.InteropServices.Marshal]::SizeOf($tSec)

$result = [Win32]::CreateProcess(
    $path,
    $CommandLine,
    [ref]$pSec,
    [ref]$tSec,
    $false,
    $PRIORITY_CLASS,
    $lpEnvironment,
    $lpCurrentDirectory,
    [ref]$sInfo,
    [ref]$pInfo
)

if(!$result){
    "Error"
}

$errorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error()
if($errorCode -eq 0){
    "The operation completed successfully"
}
else{
    "Error code: $errorCode"
}

输出:

错误

操作成功完成

为什么记事本不启动?

GetLastWin32Error() 返回 0,但我不知道代码中的错误在哪里。

【问题讨论】:

  • $pInfo之后是否包含任何进程信息?
  • hProcess : 0 hThread : 0 dwProcessId : 0 dwThreadId : 0

标签: .net powershell winapi pinvoke


【解决方案1】:

你得到错误的错误是因为这段代码

if(!$result){
    "Error"
}

在调用CreateProcessGetLastWin32Error 之间会覆盖错误。删除此代码,您会得到相关的错误代码 123 (ERROR_INVALID_NAME)

GetLastWin32Error 必须始终在您要为其获取返回错误的调用之后立即使用。

【讨论】:

  • "C:\Windows\System32\notepad.exe" - 此名称无效?
  • @Danny 问题是当前工作目录。指定一个。 IntPtr::Zero 在那里不起作用。见stackoverflow.com/questions/16686122/…
  • 谢谢! $lpCurrentDirectory = split-path $path 修复问题
猜你喜欢
  • 1970-01-01
  • 2013-07-28
  • 2016-05-12
  • 2021-01-04
  • 2014-01-16
  • 1970-01-01
  • 1970-01-01
  • 2011-09-30
  • 2016-05-29
相关资源
最近更新 更多