Comments 32
очень познавательно, спасибо.
unmanaged еще позволяет sizeof для reference type обьектов использовать
unmanaged еще позволяет sizeof для reference type обьектов использовать
+3
Любопытно, спасибо.
0
Не совсем по теме, как говорится, навеяло…
Жалко, что SizeParamIndex нельзя использовать в структурах, а то бывают структуры переменной длины. Ну это я уже привередничаю, конечно. :-) А просто SizeParamIndex используют так:
int CeRegQueryValueEx(
IntPtr hKey,
[In, MarshalAs(UnmanagedType.LPWStr)] String lpValueName,
IntPtr lpReserved,
[In, Out, MarshalAs(UnmanagedType.I4)] ref RegType lpType,
[In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)] byte[] lpData,
[In, Out] ref int lpcbData);
Таким образом, после вызова функции среда копирует в наш массив, переданный в lpData, только lpcbData байт.
Жалко, что SizeParamIndex нельзя использовать в структурах, а то бывают структуры переменной длины. Ну это я уже привередничаю, конечно. :-) А просто SizeParamIndex используют так:
int CeRegQueryValueEx(
IntPtr hKey,
[In, MarshalAs(UnmanagedType.LPWStr)] String lpValueName,
IntPtr lpReserved,
[In, Out, MarshalAs(UnmanagedType.I4)] ref RegType lpType,
[In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)] byte[] lpData,
[In, Out] ref int lpcbData);
Таким образом, после вызова функции среда копирует в наш массив, переданный в lpData, только lpcbData байт.
+2
Отличный пост! Достаточно глубоко затронута серьёзная и важная тема. С нетерпением жду следующей статьи. Спасибо.
+1
Серьезный материал…
0
Переносите в .Net блог.
0
Тема очень интересна. Я пишу на .Net с версии 1.1 но только недавно стал обращать внимание на все эти хитрости и вкусности, так как перешел с VB и считал все это ужасно сложным и страшным, но все оказалось гораздо более легким в освоении и что очень важно очень полезным. Например сейчас я разрабатываю shell extension интеграцию в контекстное меню проводника, ожидал как обычно от всех программ на дот нете большую скорость загрузки, но ничего подобного не произошло, так что иногда можно)
Прошу автора подробнее раскрыть тему ;) Спасибо!
Прошу автора подробнее раскрыть тему ;) Спасибо!
+1
При маршалинге сложных гитик всегда можно выполнить упаковку и распаковку обьекта вручную, используя низкоуровневые методы Masrhal.
0
«Передача структур, указателей на функции и прочих нетривиальных вещей.» — вот про это хотелось бы прочитать поподробнее. Ибо в данный момент приходится ускоренными темпами изучать .NET и как раз столкнулся с проблемой вызова unmanaged Delphi функции из dll, которая возвращает результатам структуру (в Delphi это record). При вызове делегата вылетает в exception — Method's type signature is not PInvoke compatible. Надеюсь благодаря вашей следующей статье разберусь с этой проблемой :)
А за статью огромное спасибо.
А за статью огромное спасибо.
0
Многое зависит от того, как делфи возвращает структуру. Попробую угадать и предложить три варианта:
1) by value (если размер её не превышает 8 байт)
И всё равно это не сильно упростит нам жизнь. Но можно попробовать описать возвращаемое значение как Int64 — по крайней мере, мы его получим. Дальше — либо через аналог union-ов, либо через BitConverter.
Случай маловероятный, поэтому код опущу.
2) by reference — возвращается указатель на временную область памяти.
Нам повезло! Описываем функцию как возвращающую IntPtr, а потом этот указатель скармливаем Marshal.PtrToStructure. И всё. :-)
3) в стиле COM — добавляется последний параметр типа T* или T**.
Пробуем описать функцию с дополнительным последним параметром типа ref T retval или ref IntPtr retval.
Гадание на кофейной гуще, конечно же. :-( Да простят меня дельфисты…
1) by value (если размер её не превышает 8 байт)
И всё равно это не сильно упростит нам жизнь. Но можно попробовать описать возвращаемое значение как Int64 — по крайней мере, мы его получим. Дальше — либо через аналог union-ов, либо через BitConverter.
Случай маловероятный, поэтому код опущу.
2) by reference — возвращается указатель на временную область памяти.
Нам повезло! Описываем функцию как возвращающую IntPtr, а потом этот указатель скармливаем Marshal.PtrToStructure. И всё. :-)
3) в стиле COM — добавляется последний параметр типа T* или T**.
Пробуем описать функцию с дополнительным последним параметром типа ref T retval или ref IntPtr retval.
Гадание на кофейной гуще, конечно же. :-( Да простят меня дельфисты…
0
Спасибо. Отлично собрали воедино большой материал по теме.
Интересно почитать про .NET Pipe RPC. Продолжайте, пожалуйста.
Интересно почитать про .NET Pipe RPC. Продолжайте, пожалуйста.
+2
Хорошая статья. Спасибо. Мне, как человеку, съевшему на взаимодействии с unmanaged кодом не одну тонну говна проблем, это всё очень знакомо.
Хотелось бы, чтобы вы получше описали работу с хендлами в P/Invoke. Там всё очень интересно, и чтобы не получить Resource Leak, надо бы использовать всякие обертки над IntPtr. Людям, которые осваивают это, на мой взгляд очень полезно.
Кстати, в Windows Forms есть бага, выражающаяся в Resource Leak при работе с иконками, так что хочешь/не хочешь, а использовать P/Invoke надо :)
Хотелось бы, чтобы вы получше описали работу с хендлами в P/Invoke. Там всё очень интересно, и чтобы не получить Resource Leak, надо бы использовать всякие обертки над IntPtr. Людям, которые осваивают это, на мой взгляд очень полезно.
Кстати, в Windows Forms есть бага, выражающаяся в Resource Leak при работе с иконками, так что хочешь/не хочешь, а использовать P/Invoke надо :)
0
Это случайно не та, которая не релизит иконку в NotificationIcon?
0
Насколько я помню, проблема не напрямую связана с NotifyIcon. Лезет она вроде из Bitmap.GetHIcon() — когда получаем хендл, с которым система уже ничего не может сделать (она не знает когда он освободиться). Но могу ошибаться. Просто помню, что хендлы там улетали только в путь, и все попытки освобождения всё равно заканчивались потерянным хендлом, который приходилось вычищать через P/Invoke.
0
Был бы признателен за примеры кода, поковырять, т.к. в этой сфере я совсем неспециалист :(
0
Еще можно написать обертку на C++/CLI — это специальный язык в который родной двум средам — можно использовать как родные примеры кода C++ по использованию Unmanaged как есть так и реализовывать Managed классы.
0
P/Invoke = Platform Invoke
+1
Хорошая статья, спасибо.
Мне, также как и вам, много приходится работать с Interop, :-) поэтому добавлю свои пять копеек:
1) есть возможность не добавлять сборку в GAC для ComExport. Для этого при регистрации сборки через regasm.exe нужно указать ключи /codebase /tlb — этого будет достаточно.
Для релизов так делать не очень красиво, но для отладки или тестирования RC вполне можно. Ну или в случае, если referenced сборки не являются strong named.
2) однажды столкнулись со случаем, когда в Excel не получалось обратиться из VBA к COM-компоненту, написанному на C# (.NET 2.0). Выяснилось, что Excel использовал среду исполнения .NET 1.1, хотя в системе был весь набор фреймворков — от 1.1 до 3.5. Вылечилось установкой VSTO Runtime (хотя само VSTO не использовали).
Зато (в других наших проектах) без проблем получается использовать в новых фреймворках компоненты, написанные под 1.1. Доходит до курьёза: основное приложение написано на .NET CF 3.5, оно использует компоненту на .NET CF 2.0, а та юзает логгирование через log4net (.NET CF 1.1). И всё работает. :-)
Мне, также как и вам, много приходится работать с Interop, :-) поэтому добавлю свои пять копеек:
1) есть возможность не добавлять сборку в GAC для ComExport. Для этого при регистрации сборки через regasm.exe нужно указать ключи /codebase /tlb — этого будет достаточно.
Для релизов так делать не очень красиво, но для отладки или тестирования RC вполне можно. Ну или в случае, если referenced сборки не являются strong named.
2) однажды столкнулись со случаем, когда в Excel не получалось обратиться из VBA к COM-компоненту, написанному на C# (.NET 2.0). Выяснилось, что Excel использовал среду исполнения .NET 1.1, хотя в системе был весь набор фреймворков — от 1.1 до 3.5. Вылечилось установкой VSTO Runtime (хотя само VSTO не использовали).
Зато (в других наших проектах) без проблем получается использовать в новых фреймворках компоненты, написанные под 1.1. Доходит до курьёза: основное приложение написано на .NET CF 3.5, оно использует компоненту на .NET CF 2.0, а та юзает логгирование через log4net (.NET CF 1.1). И всё работает. :-)
0
Плюсплюсплюсплюс:)
Во-первых, спасибо за статью — еду сегодня на собеседование где будет крутиться затронутая вами тема.
Во-вторых — за нами гоняются клиенты с ссаными тряпками :) Действительно, всто увеличивает время загрузки ворда, но я с вами не согласен, что на такое большое количество времени. Другое дело, что мы это разрабатываем в рамках госпроекта, поэтому тут еще примешивается стыд перед Родиной.
В-третьих, отчего-то имеется острое желание напоить вас пивом в целях потырить знаний и поделиться своими:)
Во-первых, спасибо за статью — еду сегодня на собеседование где будет крутиться затронутая вами тема.
Во-вторых — за нами гоняются клиенты с ссаными тряпками :) Действительно, всто увеличивает время загрузки ворда, но я с вами не согласен, что на такое большое количество времени. Другое дело, что мы это разрабатываем в рамках госпроекта, поэтому тут еще примешивается стыд перед Родиной.
В-третьих, отчего-то имеется острое желание напоить вас пивом в целях потырить знаний и поделиться своими:)
+2
Спасибо, как раз не хватает материала, связанного с реализацией обращений из unmanaged кода к managed-подпрограммам. Обратный механизм достаточно прозрачен, и почитать есть что, а вот это как раз то, что нужно! Присоединяюсь ко всем, кому понравилось. Продолжайте, буду читать с удовольствием.
0
Замечания по переводу терминов. «Managed» и «unmanaged» код можно перевести как «управляемый» и «неуправляемый» код. «Boxing»/«unboxing» — «упаковка»/«распаковка». Такой перевод используется, например, в книге Джеффри Рихтера «Программирование на платформе Microsoft .NET Framework 2.0 на языке C#».
0
> Из этого подхода родилась общая архитектура подобного рода приложений, названная .NET Pipe RPC
хахахаха забавно, как раз реализую то же самое, тока не через pipes, а shared memory. правда при моем подходе, теоретически один внезапно отвалившийся клиент может завалить все оставшееся клиент-серверное взаимодействие (abort) например наложив spin блокировку на shared mem и внезапно умерев )) зато производительность должна быть повыше. ну и еще у меня не жестко rpc, а просто сообщения в свободном формате туда-сюда.
ComExport — не нашел описалова в сети, а вообще net classes экспортят com интерфейсы? ну тот же System.Net.Mail можно загрузить как com в unmanaged c++? увы, не смог найти туториала на это тему… хотя если рантайм при байдинге грузится, то это неприемлемо в любом случае…
спасибо за статью, прочитал с интересом. побольше бы таких адвансед статей и эдвансед пипл на хабре)
хахахаха забавно, как раз реализую то же самое, тока не через pipes, а shared memory. правда при моем подходе, теоретически один внезапно отвалившийся клиент может завалить все оставшееся клиент-серверное взаимодействие (abort) например наложив spin блокировку на shared mem и внезапно умерев )) зато производительность должна быть повыше. ну и еще у меня не жестко rpc, а просто сообщения в свободном формате туда-сюда.
ComExport — не нашел описалова в сети, а вообще net classes экспортят com интерфейсы? ну тот же System.Net.Mail можно загрузить как com в unmanaged c++? увы, не смог найти туториала на это тему… хотя если рантайм при байдинге грузится, то это неприемлемо в любом случае…
спасибо за статью, прочитал с интересом. побольше бы таких адвансед статей и эдвансед пипл на хабре)
0
Если прочитаешь мою следующую статью — поймешь, что это велосипед. Я это уже понял.
Там и про ComExport кстати подробно написано. NET-классы легко и непринужденно экспортирую ком-интерфейсы. И про outproc тоже.
Там и про ComExport кстати подробно написано. NET-классы легко и непринужденно экспортирую ком-интерфейсы. И про outproc тоже.
0
шаринг данных между процессами — это 50-летний велосипед как и их обработка кодом. ну и что :) проще написать, чем мучиться велосипед/не велосипед
фреймворочную часть всегда надо стараться быстрее пройти — работа над ней — это всегда своеобразный time trash, юзер все-таки требует не этого, а собственно, бизнес логику…… программу )
лучше расскажи про Pipe RPC как обещал в конце этой статьи ;-)
фреймворочную часть всегда надо стараться быстрее пройти — работа над ней — это всегда своеобразный time trash, юзер все-таки требует не этого, а собственно, бизнес логику…… программу )
лучше расскажи про Pipe RPC как обещал в конце этой статьи ;-)
0
Штука это сложная, нетривиальная, и не дает никаких преимуществ перед out-process COM. Потому я от нее отказался, когда узнал, что .NET умеет делать outproc.
0
Only those users with full accounts are able to leave comments. Log in, please.
.NET в unmanaged окружении – использование и родовые проблемы