Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何从Win32检测在.NET中创建的事件对象_.net_Winapi_Events - Fatal编程技术网

如何从Win32检测在.NET中创建的事件对象

如何从Win32检测在.NET中创建的事件对象,.net,winapi,events,.net,Winapi,Events,我正在.NET中使用以下互操作调用创建命名事件对象: [DllImport("kernel32.dll")] static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, [MarshalAs(UnmanagedType.LPWStr)] string lpName); const string EVENT_NAME = "Global\\unique_

我正在.NET中使用以下互操作调用创建命名事件对象:

[DllImport("kernel32.dll")]
static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset,
    bool bInitialState, [MarshalAs(UnmanagedType.LPWStr)] string lpName);

const string EVENT_NAME = "Global\\unique_id_string";
const uint SYNCHRONIZE = 0x00100000;
const uint EVENT_MODIFY_STATE = 0x0002;
hEvent = CreateEvent(IntPtr.Zero, true, false, EVENT_NAME);
然后我尝试从Win32程序中打开此事件,如下所示

WCHAR evntName[MAX_PATH] = {0};
wcscpy(evntName, L"Global\\unique_id_string");
HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, evntName);
但返回的句柄始终为0

当我从另一个.NET应用程序中尝试类似的操作时

[DllImport("kernel32.dll")]
static extern IntPtr OpenEvent(UInt32 dwDesiredAccess, bool bInheritable,
    [MarshalAs(UnmanagedType.LPWStr)] string lpName);

const string EVENT_NAME = "Global\\unique_id_string";
const uint SYNCHRONIZE = 0x00100000;
const uint EVENT_MODIFY_STATE = 0x0002;

IntPtr hEvent = OpenEvent(EVENT_MODIFY_STATE | SYNCHRONIZE, false, EVENT_NAME);
它工作正常,并返回事件的正确句柄


为什么不使用本地C++应用程序?我缺少什么吗?

Win32 API调用有两个版本——ANSI和Unicode。根据的文档,必须将其指定为
CharSet
属性,否则默认为ANSI版本。即使您将字符串封送为
LPWStr
,但实际上您正在调用ANSI版本,它很可能只看到名称
G
的第一个字符。但是您的Win32应用程序正在使用完整的Unicode名称(如您所希望的),但找不到这样一个命名事件

尝试显式导入函数的Unicode版本:

[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]

如果指定
字符集
,也不需要自己指定封送。

虽然ANSI/Unicode可能是问题所在,但ANSI API通过将字符串映射到Unicode,然后调用Unicode代码路径来工作。所以这不应该是个问题

“未找到文件”错误导致名称不匹配。尝试将本机应用程序也更改为使用(如果名称存在,您将获得一个句柄,
GetLastError()
返回已经存在的错误-
CreateEvent
的模式,并始终检查最后一个错误,以避免对象创建的时间依赖性或争用条件

如果没有名称冲突,请使用或(两个系统内部)查看事件对象,以了解其真正名称


更新 发生了什么(TL:DR:version): 告诉p/Invoke它是一个ANSI API(默认值,如果您不指定Unicode),并说字符串是Unicode会产生错误的结果。解决这两个问题都可以解决问题

更完整的版本: 原始p/Inovoke声明:

[DllImport("kernel32.dll")]
static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset,
        bool bInitialState, [MarshalAs(UnmanagedType.LPWStr)] string lpName);
具有默认的(ANSI)API方法(因为
DllImport
CharSet
属性默认为
CharSet.ANSI
但该字符串具有
UnmanagedType.LPWStr
:传递宽(即Unicode)字符串

如果在运行时查看对象的名称,您会看到:

\Sessions\1\BaseNamedObjects\G 将Unicode字符串传递给Unicode API都可以工作,并创建一个对象名:

\BaseNamedObjects\unique_id_string \BaseNamedObjects\unique\u id\u字符串 (
Global
BaseNamedObjects
的内核对象树中的别名)

总结:
p/Invoke声明必须100%正确…即使只有一个字符是有效的。

在本机应用程序中,
GetLastError()
返回什么?(0,或者更确切地说是NULL,表示失败,但您需要找出失败的原因。)另外,您是否让创建事件的应用程序继续运行?如果没有对内核对象的引用,它将被销毁。很抱歉,我忘了提到这一点。GetLastError()返回2,这是错误文件未找到的系统错误代码。这让我完全困惑。是的,事件创建应用程序正在后台运行。它在系统托盘中运行。未找到文件对于命名对象意味着“没有具有该名称的对象”。即使它们可能在内部映射到Unicode,但输入字符串被视为ANSI字符串,它最终只会看到Unicode字符串的第一个字符。不知何故,它只有在显式指定Unicode时才起作用。此解决方案与Charset方法相结合,对我来说效果非常好。@casablanca,我不理解:从正确的ANSI代码页到Unicode执行正确的转码。因此,ANSI文本输出函数会写入多个字符。我怀疑更多的情况是P/Invoke和编组混淆。由于Unicode字符串编码为UTF-16,
L“hello”
在内存中看起来像
h\0e\0l\0l\0o\0\0\0
。ANSI
“hello”
就是
hello\0
。ANSI函数将在第一个空字符处停止,因此Unicode字符串看起来像
“h”
。您可以通过将Unicode字符串传递给ANSI函数来测试这一点,例如
MessageBoxA(NULL,(LPCSTR)L“hello”,NULL,0)
将只显示
h
@casablanca:我正在更新这里的根本原因(P/invoke不一致)。调用ANSI版本的
CreateEvent
也可以。 \BaseNamedObjects\unique_id_string