Как я могу получить указатель на управляемую функцию для предоставления неуправляемому коду в качестве обратного вызова?

Меня интересует отображение диалога открытия файла в старом стиле (то есть такого, который не действует как проводник Windows) в приложении C#. Я нашел этот пример для вызова устаревшей функции GetOpenFileName через [DllImport] и extern. Однако, чтобы на самом деле получить поведение, отличное от Explorer, на странице GOFN указано, что мне также нужно установить перехватчик:

Windows продолжает поддерживать диалоговое окно «Открыть» старого стиля для приложений, которым требуется поддерживать пользовательский интерфейс в соответствии со старым пользовательским интерфейсом. Чтобы отобразить диалоговое окно «Открыть» в старом стиле, включите процедуру-перехватчик OFNHookProcOldStyle и убедитесь, что флаг OFN_EXPLORER не установлен.

Я изменил пример и создал приведенную ниже функцию как обратный вызов OFNHookProcOldStyle, который, если я правильно читаю документацию по таким обратным вызовам, не должен менять никакого поведения, просто всегда возвращая 0 (обрабатывать сообщение). Наличие такого набора перехватчиков должно отключить поведение Explorer при отсутствии флага OFN_EXPLORER для его повторного включения.

public static UIntPtr SimpleOfnHookProcOldStyle(
    [In] IntPtr hdlg, [In] uint uimsg, [In] UIntPtr wParam, [In] IntPtr lParam)
{
    return UIntPtr.Zero;
}

Я установил флаг OFN_ENABLEHOOK следующим образом:

int OFN_ENABLEHOOK = (int)new Int32Converter().ConvertFromString("0x00000020");
ofn.flags = OFN_ENABLEHOOK;

Однако мне также нужно установить фактический обратный вызов перехвата, то есть IntPtr. Как я могу получить IntPtr для моего SimpleOfnHookProcOldStyle метода, чтобы я мог установить его как крючок?

Вы посмотрели новые улучшения взаимодействия в .NET5+, в нем есть примеры, которые могут быть полезны, т. е. базовый сценарий использования управляемого обратного вызова в собственную функцию без UnmanagedCallersOnlyAttribute будет выглядеть так...

Ivan Petrov 21.06.2024 04:11

Почему бы просто не поставить const int OFN_ENABLEHOOK = 0x00000020?

Dai 21.06.2024 07:07

@Дай, я не знал int поддерживает прямое присвоение шестнадцатеричных значений, спасибо!

Oblivious Sage 21.06.2024 16:10
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
79
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вам нужно

  1. Определите статический делегат с той же сигнатурой и назначьте ему свою статическую функцию.
public delegate UIntPtr Delegate_type(IntPtr hdlg, uint uimsg, UIntPtr wParam, IntPtr lParam);
public static Delegate_type native_callback = SimpleOfnHookProcOldStyle;
  1. Используйте GCHandle.Alloc, чтобы сборщик мусора не удалил его.
GCHandle handle = GCHandle.Alloc(native_callback);
  1. Используйте Marshal.GetFunctionPointerForDelegate, чтобы получить IntPtr для этого статического делегата.
IntPtr funcPtr = Marshal.GetFunctionPointerForDelegate(native_callback);
  1. Позвоните handle.Free() после закрытия диалога, чтобы не утечь память.

Приятно знать, что мне не нужны закрепленные. Я не использовал его в своей версии C++/CLI, и этот ответ заставил меня задуматься, не является ли это несчастным случаем, ожидающим своего часа.

Joe 21.06.2024 16:26

информация о том, почему не нужно закреплять делегата stackoverflow.com/a/19866119/15649230

Ahmed AEK 21.06.2024 17:06

Другие вопросы по теме

Почему я не могу получить доступ к местоположению в массиве указателей char с разыменованием указателя int как индекса
Как небезопасно получить конкретную ссылку из Box<dyn Trait>?
Перебирать массив с помощью while
Я хочу изменить значение первой программы с помощью второй программы
Существует ли альтернативный синтаксис для инициализации константного указателя на константные данные?
Ошибка компиляции при использовании функций шаблона C++, которые принимают в качестве аргументов другие функции, которые принимают ссылки на указатели
Segfault с memcpy и массивом
Код выхода 3221225477 и ошибка сегментации после возни с указателями
Я запускаю условный цикл для перебора массива и проверки того, что пользователь ввел только цифры. Ошибка при сравнении с NULL
Можете ли вы передать один и тот же указатель на SystemTimeToTzSpecificLocalTime как для ввода, так и для вывода?