从 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)时使用“字符串”而不是“字符串生成器”是不是有不利之处?