Есть dllвидимо на С++.
В ней запускается асинхронный метод чтения, который при появлении данных кидает сообщение в указанный поток.
Есть 2 вопроса.
1. Как бы ему указать поток, если он принимает HENDLE, а едиственное, что мною было найдено подходящего в C# -- IntPtr, который непонятно откуда брать, да и его ли.....
2. Как отловить это сообщение? Как я понял, для использования WaitHandle, его должна использовать и передающая и принимающая сторона. GetMessage, используемый в С++ я в C# не нашёл, как и его аналогов.
Пожалуйста, помогите, уже не первый день бьюсь.
Вскрытие покажет....
(кто знает на латыни, киньте в личку)
Здравствуйте, OLLEGator, Вы писали:
OLL>Есть dllвидимо на С++. OLL>В ней запускается асинхронный метод чтения, который при появлении данных кидает сообщение в указанный поток. OLL>Есть 2 вопроса. OLL>1. Как бы ему указать поток, если он принимает HENDLE, а едиственное, что мною было найдено подходящего в C# -- IntPtr, который непонятно откуда брать, да и его ли..... OLL>2. Как отловить это сообщение? Как я понял, для использования WaitHandle, его должна использовать и передающая и принимающая сторона. GetMessage, используемый в С++ я в C# не нашёл, как и его аналогов.
OLL>Пожалуйста, помогите, уже не первый день бьюсь.
С помощью DllImport импортировать функции WinAPI. Более хорошего решения я не знаю.
Re[2]: Как получить сообщение из неуправляемой dll
C>С помощью DllImport импортировать функции WinAPI. Более хорошего решения я не знаю.
Да, но это только первый шаг. Потом импортированная функция даже асинхронно запускается и как-то работает (есть функция, которая проверяет состояние).
Но эта функция должна посылать в основной поток сообщения, но непонятно, чем их отлавливать.
Более подробно сейчас опишу проблему в ответе на сабж.
Вскрытие покажет....
(кто знает на латыни, киньте в личку)
Здравствуйте, OLLEGator, Вы писали:
OLL>Есть dllвидимо на С++. OLL>В ней запускается асинхронный метод чтения, который при появлении данных кидает сообщение в указанный поток. OLL>Есть 2 вопроса. OLL>1. Как бы ему указать поток, если он принимает HENDLE, а едиственное, что мною было найдено подходящего в C# -- IntPtr, который непонятно откуда брать, да и его ли..... OLL>2. Как отловить это сообщение? Как я понял, для использования WaitHandle, его должна использовать и передающая и принимающая сторона. GetMessage, используемый в С++ я в C# не нашёл, как и его аналогов.
OLL>Пожалуйста, помогите, уже не первый день бьюсь.
Я писал: OLL>Есть dllвидимо на С++. OLL>В ней запускается асинхронный метод чтения, который при появлении данных кидает сообщение в указанный поток. OLL>Есть 2 вопроса. OLL>1. Как бы ему указать поток, если он принимает HENDLE, а едиственное, что мною было найдено подходящего в C# -- IntPtr, который непонятно откуда брать, да и его ли..... OLL>2. Как отловить это сообщение? Как я понял, для использования WaitHandle, его должна использовать и передающая и принимающая сторона. GetMessage, используемый в С++ я в C# не нашёл, как и его аналогов.
OLL>Пожалуйста, помогите, уже не первый день бьюсь.
БОЛЕЕ ПОДРОБНОЕ ОПИСАНИЕ ПРОБЛЕМЫ.
1. Есть функция, которая описанна следующим образом: uint32 WINAPI QueryAsync( AsyncQuery* query ) ; Асинхронная функция посылки запроса в БД. (База специальная, можно работать только через эту dll)
Возвращает управление сразу после проведения необходимых операций, до того как начнется процесс передачи запроса. Возвращаемое значение — идентификатор этого запроса в Библиотеке.
Библиотека сообщает клиенту о состоянии запроса и поступлении данных посылкой сообщения, указанного клиентом.
Соответственно есть описание структуры, передающейся на вход: struct AsyncQuery
{
<...> параметры запроса, не омеющие отношения к теме HANDLE handle ; — дескриптор окна или потока — получателя информации BOOL is_thread ; — true — если получатель информации — поток; если получатель — окно — false uint32 msg ; — номер уведомляющего сообщения uint32 answer_size ; — размер в байтах буфера под получаемые данные void* answer_buf ; — указатель на буфер под получаемые данные } ;
2. Вот как это было мною реализованно:
[StructLayout(LayoutKind.Sequential)]
unsafe public struct AsyncQuery
{
public/*??*/IntPtr/*??*/ handle;
[MarshalAs(UnmanagedType.Bool)]
public bool is_thread;
public UInt32 msg;
public UInt32 answer_size;
public void* answer_buf;
}
[DllImport("rtdbconm.dll", EntryPoint = "_QueryAsync@4")]
public static extern UInt32 RTDBQueryAsync(ref AsyncQuery query);
public unsafe void TestRunAsync()
{
//coздание буфера для получения данныхuint* pIDAnswerMemo = stackalloc uint[IDArr.Length*3];
//Сборка запроса
AsyncQuery AQ = new AsyncQuery();
AQ.type = 31;
AQ.oicat = oi;
AQ.TStart = t;
AQ.TStop = 0;
AQ.step = 0;
AQ.mask = 0;
AQ.mask_on = 0;
AQ.mask_send = 0;
AQ.query_size = (uint)(sizeof(uint) * IDArr.Length);
AQ.query_buf = pIDArrMemo;
AQ.handle = new IntPtr(Thread.CurrentThread.ManagedThreadId);
AQ.is_thread = true;
AQ.msg = MMI_Message;
AQ.answer_size = (uint)(sizeof(OI_Temp) * IDArr.Length);
AQ.answer_buf = pIDAnswerMemo;
//Запуск запросаuint AQ_id = OIKdllConnect.RTDBQueryAsync(ref AQ);
Console.WriteLine("ID запроса -- " + AQ_id.ToString());
// Проверка состояния запросаif (OIKdllConnect.RTDBAsyncIsConnect(AQ_id)) <...> // Тут видно, что запрос запущен и активен.
//!!!!! Вот тут как-то надо ловить сообщения, которые посылает этот запрос :maniac:
//Следующая конструкция не работает, только проверяет работу запроса:
EventWaitHandle wait = new AutoResetEvent(false);
for (byte i = 1; i <= 100; i++) // Во время этого цикла запрос падает. Всё время через разное количество итераций (от 50 до 70)
{
bool rezult = wait.WaitOne(1);
if (!rezult) Console.WriteLine("не попали....");
if (OIKdllConnect.RTDBAsyncIsConnect(AQ_id))
Console.WriteLine("И всё-таки он крутится!!...");
else
{
Console.WriteLine("Сдулся.... ((((( i=" + i.ToString());
break;
}
}
}
Вывод: (некоторые текстовые выводы не показанны в тексте,частично они замененны на комментарии)
Сборка запроса
Запуск запроса
ID запроса -- 1
И всё-таки он крутится!!...
не попали....
И всё-таки он крутится!!...
не попали....
И всё-таки он крутится!!...
не попали....
И всё-таки он крутится!!...
не попали....
И всё-таки он крутится!!...
не попали....
Сдулся.... ((((( i=61
ВОПРОСЫ:
1. Как правильно передать ссылку на запускающий поток?
2. Как бы мне отловть сообщения (если они, конечно, дойдут)?....
Некоторые комментарии.
1. При обявлении AsyncQuery.handle как Int32 и передачи в него Thread.CurrentThread.ManagedThreadId, поток не падает, а работает, пока его не закроешь (закрывается штатно, с задерхкой не более секунды). При существующем объявлении поток падает в интервале 50-70 итераций, или ровно между 200 и 250 мс, если выставить ожидание на 50.
Возможно это происходит из-за приходящих в разное время событий, либо из-за длительности работы параллельных потоков системы.
2. Как я понял, EventWaitHandle надо использовать на обоих концах, а не только на приёме, как получилось у меня. Видимо по-этому и не работает.
3. Вот тут описанна функция, которой можно поймать сообщение. При чём, эта же функция показанна в примере для С++. Но как это реализовать на C#, уме не приложу.
З.Ы. Если нужны уточнение, скажите, а то мне не очень видно, как это со стороны видно. Да и не очень понятно, как тут можно редактировать.
Вскрытие покажет....
(кто знает на латыни, киньте в личку)
Re[2]: Как получить сообщение из неуправляемой dll
Здравствуйте, DuШes, Вы писали:
DШ>Здравствуйте, OLLEGator, Вы писали:
OLL>>Есть dllвидимо на С++. OLL>>В ней запускается асинхронный метод чтения, который при появлении данных кидает сообщение в указанный поток. OLL>>Есть 2 вопроса. OLL>>1. Как бы ему указать поток, если он принимает HENDLE, а едиственное, что мною было найдено подходящего в C# -- IntPtr, который непонятно откуда брать, да и его ли..... OLL>>2. Как отловить это сообщение? Как я понял, для использования WaitHandle, его должна использовать и передающая и принимающая сторона. GetMessage, используемый в С++ я в C# не нашёл, как и его аналогов.
OLL>>Пожалуйста, помогите, уже не первый день бьюсь.
DШ>стоит обратить внимание на использование хуков, а также на чтение данных из shared memory DШ>очень будет в тему DШ>http://msdn.microsoft.com/en-us/magazine/cc188966.aspx DШ>удачи
Спасибо. Уже появились мысли.
Более полное описание проблемы с кодом и замечаниями в моём ответе на САБЖ.
Вскрытие покажет....
(кто знает на латыни, киньте в личку)
Re[2]: Как получить сообщение из неуправляемой dll
Здравствуйте, OLLEGator, Вы писали:
OLL>Соответственно есть описание структуры, передающейся на вход: OLL>struct AsyncQuery OLL>{ OLL><...> параметры запроса, не омеющие отношения к теме OLL>HANDLE handle ; — дескриптор окна или потока — получателя информации
Если можно окна , то все просто. Создай невидимое окно(форму) и передай его дескриптор. Это окно и получит сообщение, лови его потом в Control.WndProc .
Меня , правда, одно настораживает. Как это "окна или потока" ? Они там внутри определят, что именно передали ? Вообще-то это возможно (дескрипторы потоков суть малые числа, про дескрипторы окон такое не скажешь), но не очень уж надежно.
OLL>BOOL is_thread ; — true — если получатель информации — поток; если получатель — окно — false OLL>uint32 msg ; — номер уведомляющего сообщения OLL>uint32 answer_size ; — размер в байтах буфера под получаемые данные OLL>void* answer_buf ; — указатель на буфер под получаемые данные OLL>} ;
OLL>2. Вот как это было мною реализованно: OLL> AQ.handle = new IntPtr(Thread.CurrentThread.ManagedThreadId);
ManagedThreadId — вовсе не хендл.
Gets a unique identifier for the current managed thread.
Если нужен хендл текущего потока — придется ИМХО использовать Win API. См. в сторону GetCurrentThread, она вернет псевдохендл. Его можно и передать, но только если уверен, что посылка пойдет в том же потоке. Если не уверен — нужно из него сделать настоящий хендл — DuplicateHandle. Не забудь потом CloseHandle.
Здравствуйте, Pavel Dvorkin, Вы писали:
OLL>>2. Вот как это было мною реализованно: OLL>> AQ.handle = new IntPtr(Thread.CurrentThread.ManagedThreadId);
PD>ManagedThreadId — вовсе не хендл.
PD>Gets a unique identifier for the current managed thread.
PD>Если нужен хендл текущего потока — придется ИМХО использовать Win API. См. в сторону GetCurrentThread, она вернет псевдохендл. Его можно и передать, но только если уверен, что посылка пойдет в том же потоке. Если не уверен — нужно из него сделать настоящий хендл — DuplicateHandle. Не забудь потом CloseHandle.
using System.Diagnostics;
//----------------------------------------------------
AQ.handle = Process.GetCurrentProcess().Handle;
Это может заработать? А то я уже запутался... Хендл... Псевдохендл... Поток.... Процесс.... Бррр!!....
Едиственное, что может быть на руку, то что события должен получать единственный основной поток этого процесса.
Вскрытие покажет....
(кто знает на латыни, киньте в личку)
PD>Если нужен хендл текущего потока — придется ИМХО использовать Win API. См. в сторону GetCurrentThread, она вернет псевдохендл. Его можно и передать, но только если уверен, что посылка пойдет в том же потоке. Если не уверен — нужно из него сделать настоящий хендл — DuplicateHandle. Не забудь потом CloseHandle.
БЛИН!!... я этот GetCurrentThread даже подключить не могу. Не могу найти.
Вскрытие покажет....
(кто знает на латыни, киньте в личку)
Re[4]: SOS!!!
От:
Аноним
Дата:
20.06.09 07:43
Оценка:
Здравствуйте, OLLEGator, Вы писали:
PD>>Если нужен хендл текущего потока — придется ИМХО использовать Win API. См. в сторону GetCurrentThread, она вернет псевдохендл. Его можно и передать, но только если уверен, что посылка пойдет в том же потоке. Если не уверен — нужно из него сделать настоящий хендл — DuplicateHandle. Не забудь потом CloseHandle.
OLL>БЛИН!!... я этот GetCurrentThread даже подключить не могу. Не могу найти.
Оно Вам не нужно. Эта DLL для отправки сообщения потоку использует PostThreadMessage — иного просто нет — а эта функция принимает именно Thread ID, не Handle.
Сразу предупрежу — я не спец в NET, я его попросту не знаю. Просто сейчас ради любопытства полистал MSDN, и вроде как получается, что без импорта GetMessage или PeekMessage путь у Вас только один — подключить System.Windows.Forms. Далее либо создаёте потомка класса NativeWindow, либо реализатора интерфейса IMessageFilter, которого нужно зарегистрировать вызовом Application.AddMessageFilter. В обоих случаях сам Message Loop запускается вызовом Application.Run, а прерывать его видимо нужно вызовом Application.ExitThread
PS Я бы лучше GetMessage или PeekMessage импортировал
Re[2]: Как получить сообщение из неуправляемой dll
using System.Diagnostics;
OLL>//----------------------------------------------------
OLL>AQ.handle = Process.GetCurrentProcess().Handle;
Это хендл процесса, а не потока.
OLL>Это может заработать? А то я уже запутался... Хендл... Псевдохендл... Поток.... Процесс.... Бррр!!....
Не обижайся, но с этого и надо бы начинать. Ты взялся за программирование не в рамках чистой .Net, а с выходом на неуправлеямый код. Чтобы что-то сделать в этой области. надо понимать Win API, иначе ты ничего путного не сделаешь. Почитай книгу Рихтера по Win32 приложениям (не по .Net!), там все это подробно рассматривается.
P.S. Псевдохендл — это просто величина, которую можно использовать вместо настоящего хендла для вызова функций, требующих этот хендл, но только в рамках своего потока или процесса. Иными словами, в потоке A псевдохендл текущего потока может быть использован для ссылки на поток A, а в потоке B он же окажется ссылкой на поток B. В то время как настоящий хендл потока A можно использовать для ссылки на поток A где угодно в пределах данного процесса.
With best regards
Pavel Dvorkin
Re[5]: Как получить сообщение из неуправляемой dll
PD>Это хендл процесса, а не потока.
PD>Не обижайся, но с этого и надо бы начинать. Ты взялся за программирование не в рамках чистой .Net, а с выходом на неуправлеямый код. Чтобы что-то сделать в этой области. надо понимать Win API, иначе ты ничего путного не сделаешь. Почитай книгу Рихтера по Win32 приложениям (не по .Net!), там все это подробно рассматривается.
Спасибо за совет. Найду и почитаю.
То, что указание на процесс врят ли поможет попасть в поток, я догадывался. Просто это быдо пятничное безумие.
Да и не то что бы я сам очень хотел выходить из ДотНет на неуправляемый код, но пришлось. Там ещё предстоит отдельно разобраться с той самой асинхронной функцией. Ведь эта dll для доступа к комплексу, который для меня -- чёрный ящик.
Ещё раз спасибо за хорошие советы.
ЗЫ. Все нужные функции, вроде бы, нашёл и подключил. А не ловится и запрос в том комплексе отваливается. ((((
Вскрытие покажет....
(кто знает на латыни, киньте в личку)
Re[6]: Как получить сообщение из неуправляемой dll
Здравствуйте, OLLEGator, Вы писали:
OLL>Да и не то что бы я сам очень хотел выходить из ДотНет на неуправляемый код, но пришлось. Там ещё предстоит отдельно разобраться с той самой асинхронной функцией. Ведь эта dll для доступа к комплексу, который для меня -- чёрный ящик.
Я так понимаю, что ты должен вызвать что то из этой DLL, она должна положить что то в буфер который передается в answer_buf
а сообщение ловится через посылку его в окно?
Через создание наследника NativeWindow создаешь окно, у которого получаешь дескриптор окнапредварительно создав его в конструкторе
через
this.CreateHandle(new CreateParams());
Создаешь массив и пинишь его и получаешь его адрес
byte [] buffer = new byte[100*100];
GCHandle gch = GCHandle.Alloc( buffer,GCHandleType.Pinned );
var data = gch.AddrOfPinnedObject(); // получаешь ссылку на массив
Получи номер сообщения через RegisterWindowMessage и передай его своей длл,
и его же отлавливай в WndProc наследника NativeWindow
и солнце б утром не вставало, когда бы не было меня
Re[3]: Как получить сообщение из неуправляемой dll
PD>Меня , правда, одно настораживает. Как это "окна или потока" ? Они там внутри определят, что именно передали ? Вообще-то это возможно (дескрипторы потоков суть малые числа, про дескрипторы окон такое не скажешь), но не очень уж надежно.
Для этого есть [b]BOOL is_thread ; — true — если получатель информации — поток; если получатель — окно — false[/b]
и солнце б утром не вставало, когда бы не было меня
Re[4]: Как получить сообщение из неуправляемой dll
Здравствуйте, Serginio1, Вы писали:
S>Для этого есть S>[b]BOOL is_thread ; — true — если получатель информации — поток; если получатель — окно — false[/b]
Верно. Я не заметил
Но все же, для потока нужен не дескриптор, а ID. И тут два варианта возможны. Либо надо передавать именно дескриптор, а они из него ID получат, либо все же надо подсунуть ID вместо дескриптора. На Win API такие шутки не в диковинку. ИМХО надо оба варианта пробовать.
Но твой вариант с окном лучше.
With best regards
Pavel Dvorkin
Re[5]: Как получить сообщение из неуправляемой dll