Как получить сообщение из неуправляемой dll
От: OLLEGator  
Дата: 18.06.09 17:26
Оценка:
Есть dllвидимо на С++.
В ней запускается асинхронный метод чтения, который при появлении данных кидает сообщение в указанный поток.
Есть 2 вопроса.
1. Как бы ему указать поток, если он принимает HENDLE, а едиственное, что мною было найдено подходящего в C# -- IntPtr, который непонятно откуда брать, да и его ли.....
2. Как отловить это сообщение? Как я понял, для использования WaitHandle, его должна использовать и передающая и принимающая сторона. GetMessage, используемый в С++ я в C# не нашёл, как и его аналогов.

Пожалуйста, помогите, уже не первый день бьюсь.
Вскрытие покажет....
(кто знает на латыни, киньте в личку)
Re: Как получить сообщение из неуправляемой dll
От: Аноним  
Дата: 18.06.09 18:32
Оценка:
нормально начальные условия задачи описывай...
Re: Как получить сообщение из неуправляемой dll
От: Camarada Россия  
Дата: 19.06.09 05:08
Оценка:
Здравствуйте, OLLEGator, Вы писали:

OLL>Есть dllвидимо на С++.

OLL>В ней запускается асинхронный метод чтения, который при появлении данных кидает сообщение в указанный поток.
OLL>Есть 2 вопроса.
OLL>1. Как бы ему указать поток, если он принимает HENDLE, а едиственное, что мною было найдено подходящего в C# -- IntPtr, который непонятно откуда брать, да и его ли.....
OLL>2. Как отловить это сообщение? Как я понял, для использования WaitHandle, его должна использовать и передающая и принимающая сторона. GetMessage, используемый в С++ я в C# не нашёл, как и его аналогов.

OLL>Пожалуйста, помогите, уже не первый день бьюсь.


С помощью DllImport импортировать функции WinAPI. Более хорошего решения я не знаю.
Re[2]: Как получить сообщение из неуправляемой dll
От: OLLEGator  
Дата: 19.06.09 05:33
Оценка:
C>С помощью DllImport импортировать функции WinAPI. Более хорошего решения я не знаю.
Да, но это только первый шаг. Потом импортированная функция даже асинхронно запускается и как-то работает (есть функция, которая проверяет состояние).
Но эта функция должна посылать в основной поток сообщения, но непонятно, чем их отлавливать.
Более подробно сейчас опишу проблему в ответе на сабж.
Вскрытие покажет....
(кто знает на латыни, киньте в личку)
Re: Как получить сообщение из неуправляемой dll
От: DuШes  
Дата: 19.06.09 05:59
Оценка:
Здравствуйте, OLLEGator, Вы писали:

OLL>Есть dllвидимо на С++.

OLL>В ней запускается асинхронный метод чтения, который при появлении данных кидает сообщение в указанный поток.
OLL>Есть 2 вопроса.
OLL>1. Как бы ему указать поток, если он принимает HENDLE, а едиственное, что мною было найдено подходящего в C# -- IntPtr, который непонятно откуда брать, да и его ли.....
OLL>2. Как отловить это сообщение? Как я понял, для использования WaitHandle, его должна использовать и передающая и принимающая сторона. GetMessage, используемый в С++ я в C# не нашёл, как и его аналогов.

OLL>Пожалуйста, помогите, уже не первый день бьюсь.



стоит обратить внимание на использование хуков, а также на чтение данных из shared memory
очень будет в тему
http://msdn.microsoft.com/en-us/magazine/cc188966.aspx
удачи
Re: Как получить сообщение из неуправляемой dll
От: OLLEGator  
Дата: 19.06.09 07:21
Оценка:
Я писал:
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
От: OLLEGator  
Дата: 19.06.09 07:25
Оценка:
Здравствуйте, 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  
Дата: 19.06.09 07:30
Оценка:
Здравствуйте, Аноним, Вы писали:

А>нормально начальные условия задачи описывай...


Описал как можно подробнее условия (с кодом) в ответе на САБЖ.
Вскрытие покажет....
(кто знает на латыни, киньте в личку)
Re[2]: Как получить сообщение из неуправляемой dll
От: Pavel Dvorkin Россия  
Дата: 19.06.09 07:53
Оценка: +2
Здравствуйте, 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.
With best regards
Pavel Dvorkin
Re: Как получить сообщение из неуправляемой dll
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 19.06.09 08:37
Оценка:
Может Это поможет http://www.rsdn.ru/forum/dotnet/616700.flat.aspx#616700
Автор: TK
Дата: 22.04.04
и солнце б утром не вставало, когда бы не было меня
Re[3]: Как получить сообщение из неуправляемой dll
От: OLLEGator  
Дата: 19.06.09 11:06
Оценка:
Здравствуйте, 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.


Вот, нашёл в самом ДотНет System.Diagnostics.Process:

using System.Diagnostics;
//----------------------------------------------------
AQ.handle = Process.GetCurrentProcess().Handle;

Это может заработать? А то я уже запутался... Хендл... Псевдохендл... Поток.... Процесс.... Бррр!!....
Едиственное, что может быть на руку, то что события должен получать единственный основной поток этого процесса.
Вскрытие покажет....
(кто знает на латыни, киньте в личку)
Re[3]: SOS!!!
От: OLLEGator  
Дата: 19.06.09 16:28
Оценка:
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
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 20.06.09 13:18
Оценка: +2
Здравствуйте, OLLEGator, Вы писали:

Наверное проще сделать наследника от NativeWindow и переопределить в нем WndProc для отлова нужного события( которое наверное нужно зарегестрировать уже не помню)
В WndProc получении нужного Msg получить данные.
http://msdn.microsoft.com/ru-ru/library/system.windows.forms.nativewindow.wndproc.aspx
и солнце б утром не вставало, когда бы не было меня
Re[4]: Как получить сообщение из неуправляемой dll
От: Pavel Dvorkin Россия  
Дата: 22.06.09 05:51
Оценка: +1
Здравствуйте, OLLEGator, Вы писали:


OLL>Вот, нашёл в самом ДотНет System.Diagnostics.Process:


OLL>
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
От: OLLEGator  
Дата: 22.06.09 10:06
Оценка:
PD>Это хендл процесса, а не потока.

PD>Не обижайся, но с этого и надо бы начинать. Ты взялся за программирование не в рамках чистой .Net, а с выходом на неуправлеямый код. Чтобы что-то сделать в этой области. надо понимать Win API, иначе ты ничего путного не сделаешь. Почитай книгу Рихтера по Win32 приложениям (не по .Net!), там все это подробно рассматривается.


Спасибо за совет. Найду и почитаю.
То, что указание на процесс врят ли поможет попасть в поток, я догадывался. Просто это быдо пятничное безумие.
Да и не то что бы я сам очень хотел выходить из ДотНет на неуправляемый код, но пришлось. Там ещё предстоит отдельно разобраться с той самой асинхронной функцией. Ведь эта dll для доступа к комплексу, который для меня -- чёрный ящик.

Ещё раз спасибо за хорошие советы.

ЗЫ. Все нужные функции, вроде бы, нашёл и подключил. А не ловится и запрос в том комплексе отваливается. ((((
Вскрытие покажет....
(кто знает на латыни, киньте в личку)
Re[6]: Как получить сообщение из неуправляемой dll
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 22.06.09 11:32
Оценка: +1
Здравствуйте, 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
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 22.06.09 11:39
Оценка: +1
Здравствуйте, Pavel Dvorkin, Вы писали:


PD>Меня , правда, одно настораживает. Как это "окна или потока" ? Они там внутри определят, что именно передали ? Вообще-то это возможно (дескрипторы потоков суть малые числа, про дескрипторы окон такое не скажешь), но не очень уж надежно.



Для этого есть
[b]BOOL is_thread ; — true — если получатель информации — поток; если получатель — окно — false[/b]
и солнце б утром не вставало, когда бы не было меня
Re[4]: Как получить сообщение из неуправляемой dll
От: Pavel Dvorkin Россия  
Дата: 22.06.09 12:30
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>Для этого есть

S>[b]BOOL is_thread ; — true — если получатель информации — поток; если получатель — окно — false[/b]

Верно. Я не заметил

Но все же, для потока нужен не дескриптор, а ID. И тут два варианта возможны. Либо надо передавать именно дескриптор, а они из него ID получат, либо все же надо подсунуть ID вместо дескриптора. На Win API такие шутки не в диковинку. ИМХО надо оба варианта пробовать.

Но твой вариант с окном лучше.
With best regards
Pavel Dvorkin
Re[5]: Как получить сообщение из неуправляемой dll
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 22.06.09 13:05
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:
Поздно нашел, оказывается уже все что нужно ему здесь описано http://rsdn.ru/forum/dotnet/3435889.flat.aspx#3435889
Автор:
Дата: 20.06.09
как с NativeWindow так и через IMessageFilter.
и солнце б утром не вставало, когда бы не было меня
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.