Как обнаружить объект события, созданный в .NET из Win32 - PullRequest
2 голосов
/ 12 декабря 2010

Я создаю именованный объект события в .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);

, оно отлично работает и возвращает правильный дескриптор события.1012 *

Почему он не работает с собственным приложением C ++?Что-то мне не хватает?

Ответы [ 2 ]

1 голос
/ 12 декабря 2010

Win32 API-вызовы бывают двух версий - ANSI и Unicode. Согласно документам для DllImport, вы должны указать это как атрибут CharSet, в противном случае по умолчанию используется версия ANSI. Даже если вы маршалируете строку как LPWStr, вы фактически вызываете версию ANSI, и она, скорее всего, видит только первый символ имени G. Но ваше приложение Win32 использует полное имя Unicode (как вы и предполагали), но не может найти такое именованное событие.

Попробуйте явно импортировать Unicode-версию функции:

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

Если вы укажете CharSet, вам также не нужно указывать маршалинг самостоятельно.

0 голосов
/ 12 декабря 2010

Хотя проблема может заключаться в ANSI / Unicode, API-интерфейсы ANSI работают путем сопоставления строк с Unicode и последующего вызова пути к коду Unicode.Так что это не должно быть проблемой.

При ошибке File Not Found существует несоответствие имени.Попробуйте изменить нативное приложение на использование CreateEvent (если имя существует, вы получите дескриптор, а GetLastError() вернет ERROR_ALREADY_EXISTS - таким образом, шаблон CreateEvent и всегда проверяет последнюю ошибку, чтобы избежать синхронизациизависимости или условия гонки вокруг создания объекта.

Если вы не столкнулись с именем, используйте handle или Process Explorer (оба SysInternals), чтобы посмотреть на событиеобъект, чтобы увидеть, как на самом деле его имя.


ОБНОВЛЕНИЕ

Что произошло (TL: DR: версия):

Сообщая P /Вызовите, что это API-интерфейс ANSI (по умолчанию, если вы не указали Unicode) и скажите, что строка Unicode дает неправильные результаты. Исправление любого из них решило бы проблему.

Полная версия:

Исходное объявление P / Inovoke:

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

имеет метод API по умолчанию (ANSI) (поскольку для свойства DllImport CharSet по умолчанию установлено значение CharSet.Ansi) но строка имеет UnmanagedType.LPWStr: передать ширину (т.е. Unicode) string.

Если вы посмотрите на имя объекта, когда он запущен, вы увидите:

\Sessions\1\BaseNamedObjects\G

, где API только что увидел G от имени, идобавьте префикс имени сеанса.

Изменение объявления: [DllImport ("kernel32.dll")] static extern IntPtr CreateEvent (IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, [MarshalAs (UnmanagedType.LPSt))] string lpName);

передача строки ANSI в API ANSI или

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

передача строки Unicode в API Unicode, обе работают с созданным именем объекта:

\BaseNamedObjects\unique_id_string

(Global - псевдоним в дереве объектов ядра для BaseNamedObjects.)

Сводка:

Объявления P / Invoke должны быть на 100% правильными.... даже один символ имеет значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...