从 C# 调用时,是不是可以获得 Kernel32.dll 函数的最后一个错误代码?

Posted

技术标签:

【中文标题】从 C# 调用时,是不是可以获得 Kernel32.dll 函数的最后一个错误代码?【英文标题】:Is it possible to get last error code for the Kernel32.dll functions when called from C#?从 C# 调用时,是否可以获得 Kernel32.dll 函数的最后一个错误代码? 【发布时间】:2019-11-21 13:21:51 【问题描述】:

我有几个来自Kernel32.dll 的函数,我是从C# 程序调用的。我导入的函数如下:

[System.Runtime.InteropServices.DllImport("Kernel32.dll", EntryPoint = "GetSystemTime", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
private static extern void GetSystemTime(ref SYSTEMTIME lpSystemTime);

[System.Runtime.InteropServices.DllImport("Kernel32.dll", EntryPoint = "SetSystemTime", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
private static extern UInt32 SetSystemTime(ref SYSTEMTIME lpSystemTime);

其中SYSTEMTIME 是这些方法接受的结构。

SetSystemTime 的文档说,如果函数失败,它会返回 0,并调用 GetLastError 以获取有关失败的扩展信息。所以我以与上述函数相同的方式从Kernel32.dll文件中导入GetLastError。现在,当我将失败模拟为:

if (SetSystemTime(ref st) == 0) 
      Console.WriteLine(GetLastError() + " Error occurred: SetSystemTime returned zero.");

GetLastError() 打印出1314 的代码,用于A required privilege not held by the client。我更改了Local security policy 以将用户添加到User rights assignment 中的Replace a process level token,但我仍然得到相同的代码。我在做什么是正确的还是我遗漏了什么?

【问题讨论】:

不要导入GetLastError,直接调用。您必须在 p/invoke 声明中使用SetLastError = true,然后使用Marshal.GetLastWin32Error()。这允许 p/invoke 框架在函数调用返回后立即捕获错误代码。否则 .net 框架可能会调用另一个 API 调用并修改线程的错误代码。 显然documented,调用SetSystemTime需要调用者持有SE_SYSTEMTIME_NAME权限,虽然该函数在没有被持有的时候帮助你获取权限,但它仍然需要你的帐户能够得到它。这意味着以管理员身份运行(提升),或通过本地安全策略明确分配“更改系统时间”权限。一般来说,在让你的程序弄乱系统时钟之前要三思而后行。 ***.com/questions/2818179/… @DavidHeffernan Marshal.GetLastWin32Error() 也返回相同的1314 代码 @NavjotSingh 是的。我给你的建议比这个问题的细节更广泛。不客气。 【参考方案1】:

看起来像是由 UAC 引起的“用户权限分配”。

试试这个:

1] 使用本地安全策略

有时会因为一些管理员帐户冲突而发生。在这种情况下,您需要打开本地安全策略窗口。您可以在任务栏搜索框或 Cortana 中搜索相同的内容,也可以按 Win + R,输入 secpol.msc 并按 Enter 按钮。

导航到Local Policies > Security Options。找到User Account Control: Run all administrators in Admin Approval Mode 并将其设置为Disable

2] 禁用 UAC

UAC 或用户帐户控制可防止程序对系统进行任何更改。但是,有时它也会产生问题。因此,您可以暂时尝试禁用 UAC 并检查它是否有效。要在 Windows 中禁用用户帐户控制,请在任务栏搜索框中搜索用户 Account Control Settings。您应该将 UAC 设置为 Never Notify

希望对你有帮助。

【讨论】:

以上是关于从 C# 调用时,是不是可以获得 Kernel32.dll 函数的最后一个错误代码?的主要内容,如果未能解决你的问题,请参考以下文章

C#调用API函数VirtualProtectEx总是返回0 这是一个植物大战僵尸的游戏修改器..

对于 C#,在调用 Win32 函数(如 GetWindowText)时使用“字符串”而不是“字符串生成器”是不是有不利之处?

用于 kernel32.dll API 的包装器 C#

IAT 钩住但钩住的函数没有被调用

C++ 库问题

c#如何获取串口的句柄?