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
。
我无法正常使用 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
。