从 C# 调用 Advapi32.dll 本机 EventWrite 函数?
Posted
技术标签:
【中文标题】从 C# 调用 Advapi32.dll 本机 EventWrite 函数?【英文标题】:Call Advapi32.dll native EventWrite function from C#? 【发布时间】:2015-04-06 15:13:33 【问题描述】:我正在尝试使用 C# .Net 来触发 Window 的 Service Trigger Events。
具体来说,我正在尝试触发此事件,以便从非特权帐户启动 WebClient 服务。
C:\>sc qtriggerinfo WebClient
[SC] QueryServiceConfig2 SUCCESS
SERVICE_NAME: WebClient
START SERVICE
CUSTOM : 22b6d684-fa63-4578-87c9-effcbe6643c7 [ETW PROVIDER UUID]
我能够在 C++ 中启动服务时找到 this reference,但不确定如何在 C# 中实现相同的功能:
bool StartWebClientService()
const GUID _MS_Windows_WebClntLookupServiceTrigger_Provider =
0x22B6D684, 0xFA63, 0x4578,
0x87, 0xC9, 0xEF, 0xFC, 0xBE, 0x66, 0x43, 0xC7 ;
REGHANDLE Handle;
bool success = false;
if (EventRegister(&_MS_Windows_WebClntLookupServiceTrigger_Provider,
nullptr, nullptr, &Handle) == ERROR_SUCCESS)
EVENT_DESCRIPTOR desc;
EventDescCreate(&desc, 1, 0, 0, 4, 0, 0, 0);
success = EventWrite(Handle, &desc, 0, nullptr) == ERROR_SUCCESS;
EventUnregister(Handle);
return success;
这是我正在使用的代码:
[StructLayout(LayoutKind.Explicit, Size=12)]
public class EVENT_DESCRIPTOR
[FieldOffset(0)]ushort Id = 1;
[FieldOffset(2)]byte Version = 0;
[FieldOffset(3)]byte Channel = 0;
[FieldOffset(4)]byte Level = 4;
[FieldOffset(5)]byte Opcode = 0;
[FieldOffset(6)]ushort Task = 0;
[FieldOffset(8)]ulong Keyword = 0;
//...
void startService()
Guid webCleintTrigger = new Guid(0x22B6D684, 0xFA63, 0x4578, 0x87, 0xC9, 0xEF, 0xFC, 0xBE, 0x66, 0x43, 0xC7);
IntPtr handle;
uint output = EventRegister(ref webCleintTrigger, IntPtr.Zero, IntPtr.Zero, out handle);
//This is what is returned:
//output = 0 <- Good
//handle = 65537 <- Good handle?
bool success = false;
if (output == 0)
//Create event descriptor
EVENT_DESCRIPTOR desc = new EVENT_DESCRIPTOR();
//Write the event
uint writeOutput = EventWrite(handle, ref desc, 0, IntPtr.Zero); //Throws PInvokeStackImbalance
success = writeOutput == 0;
EventUnregister(handle);
[DllImport("Advapi32.dll", SetLastError = true)]
public static extern uint EventRegister(ref Guid guid, [Optional] IntPtr EnableCallback, [Optional] IntPtr CallbackContext, out IntPtr RegHandle);
[DllImport("Advapi32.dll", SetLastError = true)]
public static extern uint EventWrite(IntPtr RegHandle, ref EVENT_DESCRIPTOR EventDescriptor, uint UserDataCount, [Optional] IntPtr UserData);
[DllImport("Advapi32.dll", SetLastError = true)]
public static extern uint EventUnregister(IntPtr RegHandle);
对EventWrite
的调用会引发PInvokeStackImbalance
异常。这可能是我的 EVENT_DESCRIPTOR
结构的错误吗?
这是原生Event_Descriptor的结构:
typedef struct _EVENT_DESCRIPTOR
USHORT Id;
UCHAR Version;
UCHAR Channel;
UCHAR Level;
UCHAR Opcode;
USHORT Task;
ULONGLONG Keyword;
EVENT_DESCRIPTOR, *PEVENT_DESCRIPTOR;typedef const EVENT_DESCRIPTOR *PCEVENT_DESCRIPTOR;
这是我的 C# 结构:
[StructLayout(LayoutKind.Explicit, Size=16)]
public class EVENT_DESCRIPTOR
[FieldOffset(0)]ushort Id = 1;
[FieldOffset(2)]byte Version = 0;
[FieldOffset(3)]byte Channel = 0;
[FieldOffset(4)]byte Level = 4;
[FieldOffset(5)]byte Opcode = 0;
[FieldOffset(6)]ushort Task = 0;
[FieldOffset(8)]ulong Keyword = 0;
这是原生EventWrite函数的结构:
ULONG EventWrite(
_In_ REGHANDLE RegHandle,
_In_ PCEVENT_DESCRIPTOR EventDescriptor,
_In_ ULONG UserDataCount,
_In_opt_ PEVENT_DATA_DESCRIPTOR UserData
);
这是我对 Event Write 的 PInvoke 调用:
[DllImport("Advapi32.dll", SetLastError = true)]
public static extern uint EventWrite(IntPtr RegHandle, ref EVENT_DESCRIPTOR EventDescriptor, uint UserDataCount, [Optional] IntPtr UserData);
这是我正在抛出 PInvokeStackImbalance 异常的调用:
EVENT_DESCRIPTOR desc = new EVENT_DESCRIPTOR();
uint writeOutput = EventWrite(handle, ref desc, 0, IntPtr.Zero); //Throws PInvokeStackImbalance
【问题讨论】:
第一个参数必须是ref Guid
。
@HansPassant,允许函数调用通过,但仍然失败(返回最大值),知道为什么吗?
返回值类型是uint,不是ulong。本机代码中的 ULONG 是 32 位类型。
句柄包含一些数据结构的偏移量。在某些情况下,数据结构都是虚拟内存,句柄值是指针。在其他情况下,它是一个数组索引,在这种情况下,您的进程中的第一次调用总是返回 1
一点也不奇怪。句柄的某些位也可用于标志......这使得始终看到0x10001
完全可行且不足为奇。
REGHANDLE
应该是 Int64
,而不是 IntPtr
。实际上,你可以在referencesource.microsoft.com/#System.ServiceModel.Internals/…看到微软自己的p/invoke声明这些函数
【参考方案1】:
感谢 BenVoigt 将我指向他们已经实现 PInvoke 调用的 Microsoft source reference。
这是解决方案:
[StructLayout(LayoutKind.Explicit, Size=16)]
public class EVENT_DESCRIPTOR
[FieldOffset(0)]ushort Id = 1;
[FieldOffset(2)]byte Version = 0;
[FieldOffset(3)]byte Channel = 0;
[FieldOffset(4)]byte Level = 4;
[FieldOffset(5)]byte Opcode = 0;
[FieldOffset(6)]ushort Task = 0;
[FieldOffset(8)]long Keyword = 0;
[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct EventData
[FieldOffset(0)]
internal UInt64 DataPointer;
[FieldOffset(8)]
internal uint Size;
[FieldOffset(12)]
internal int Reserved;
//...
void startService()
Guid webCleintTrigger = new Guid(0x22B6D684, 0xFA63, 0x4578, 0x87, 0xC9, 0xEF, 0xFC, 0xBE, 0x66, 0x43, 0xC7);
long handle = 0;
uint output = EventRegister(ref webCleintTrigger, IntPtr.Zero, IntPtr.Zero, ref handle);
//This is what is returned:
//output = 0 <- Good
//handle = 65537 <- Good handle?
bool success = false;
if (output == 0)
//Create event descriptor
EVENT_DESCRIPTOR desc = new EVENT_DESCRIPTOR();
//Write the event
unsafe
uint writeOutput = EventWrite(handle, ref desc, 0, null);
success = writeOutput == 0;
EventUnregister(handle);
[DllImport("Advapi32.dll", SetLastError = true)]
public static extern uint EventRegister(ref Guid guid, [Optional] IntPtr EnableCallback, [Optional] IntPtr CallbackContext, [In][Out] ref long RegHandle);
[DllImport("Advapi32.dll", SetLastError = true)]
public static extern unsafe uint EventWrite(long RegHandle, ref EVENT_DESCRIPTOR EventDescriptor, uint UserDataCount, EventData* UserData);
[DllImport("Advapi32.dll", SetLastError = true)]
public static extern uint EventUnregister(long RegHandle);
【讨论】:
以上是关于从 C# 调用 Advapi32.dll 本机 EventWrite 函数?的主要内容,如果未能解决你的问题,请参考以下文章
environ("username") 与 advapi32.dll
在 Windows XP 上安装 JDK8 - advapi32.dll 错误