DllImport 编码错误

DllImport wrong encoding

我无法正常使用 Dll 导入的 win api 函数,这可能与字符串的编码方式有关。

实际上我正在尝试使用来自 kernel32.dll 的 CreateProcess。
它是通过以下方式导入的:

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
      public static extern bool CreateProcess(
         [MarshalAs(UnmanagedType.LPStr)] string ApplicationName,
         [MarshalAs(UnmanagedType.LPStr)] ref string CommandLine,
         ref SECURITY_ATTRIBUTES ProcessAttributes,
         ref SECURITY_ATTRIBUTES ThreadAttributes,
         bool InheritHandles,
         uint CreationFlags,
         IntPtr Environment,
         [MarshalAs(UnmanagedType.LPStr)] string CurrentDirectory,
         [In] ref StartupInfo StartupInfo,
         out PROCESS_INFORMATION ProcessInformation);

代码中调用如下:

var fileName = PInvokeEncode(FileName);
var arguments =  PInvokeEncode(Arguments);
workingDirectory = PInvokeEncode(workingDirectory);
//var arguments = Arguments.ToString(pinvokeEncoding);
if (!ProcessUtility.CreateProcess(
        fileName,
        ref arguments,
        ref processAttributes,
        ref threadAttributes,
        true, //inherit handles
        (uint)(CreationFlags.CREATE_NEW_CONSOLE | CreationFlags.CREATE_UNICODE_ENVIRONMENT),
        IntPtr.Zero, //inherits current environement
        workingDirectory,
        ref startupInfo,
        out processInformation))
{
    throw new Win32Exception("CreateProcessAsUser");
}

...
...
...

private static readonly Encoding PInvokeEncoding = Encoding.ASCII;

private static string PInvokeEncode(string value)
{
    var bytes = Encoding.Default.GetBytes(value);
    var encodedString = PInvokeEncoding.GetString(bytes);
    return encodedString;
}

然后在固定装置中,我启动了一个调用 CreateProcess 的测试 文件名 = @"c:\Windows\System32\cmd.exe" 和参数 = @"/C ""c:\Windows\System32\ping.exe /?"""

如您所见,在任务管理器中,当我启动一个新的 cmd.exe 时,命令行列中显示的值无效:

应该显示c:\Windows\System32\cmd.exe /C "c:\Windows\System32\ping.exe /?"

知道如何更正任务管理器的编码以显示正确的字符串吗?

是的,你的p/invoke是错误的。您要求提供该函数的 Unicode 版本,但还要求传递 ANSI 字符串。您的屏幕截图与问题中的代码不对应。如果您真的使用问题中的代码,系统将无法解码任何一个字符串。

另一个错误是在第二个参数上使用 ref。你必须删除它。

pinvoke.net 的版本不错:

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

您可能更喜欢使用 IntPtr SECURITY_ATTRIBUTES 代替 ref SECURITY_ATTRIBUTES,这样您就可以为这些参数传递 IntPtr.Zero