Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Указатель на делегат


Автор: Red Wind 9.5.2007, 13:26
С праздником!
У меня есть определённый делегат. Нужно получить указатель на на этот делегат, что бы использовать в unmenaged коде. Вообще в framework 2.0 есть специальный метод Marshal.GetFunctionPointerForDelegate. Но мне нужно обойдтись возможностями первого фрэймворка. Скажите, как это мождно сделать?

Автор: marcusmae 9.5.2007, 14:01
И Вас с праздником!

http://www.atalasoft.com/cs/blogs/stevehawley/archive/2006/07/28/10560.aspx

Цитата

Basically, you have to create a singleton struct to hold your delegate:
Код

typedef bool (*fMyCallback)(unsigned long uUserData);

__delegate bool MyCallback(__int32 uUserData);

__gc struct MyCallbackWrapper {
    [MarshalAsAttribute(UnmanagedType::FunctionPtr)]
    MyCallback *m_call;
};

__nogc struct MyCallbackWrapperUnmanaged {
    fMyCallBack m_callUnmanged;
};

fMyCallBack MakeUnmanagedCallback(MyCallback call)
{
    __gc struct MyCallbackWrapper *wrapper = new MyCallbackWrapper();
    wrapper->m_call = call;
    MyCallbackWrapperUnmanaged wrapperUnmanaged;
    Marshal::StructureToPtr(wrapper, &wrapperUnmanaged, false);
    return wrapperUnmanaged.m_callUnmanaged;
}



Подойдёт?

Автор: Red Wind 9.5.2007, 15:31
Боюсь, что не пойдёт. С++ я не знаю, и разобраться с этим для меня проблема.

Автор: marcusmae 9.5.2007, 17:30
Цитата(Red Wind @  9.5.2007,  15:31 Найти цитируемый пост)
С++ я не знаю, и разобраться с этим для меня проблема.


Наверно, так или иначе Вам придётся написать managed/unmanaged мост. Из всего семейства языков .NET сочетать managed и unmanaged можно только в плюсах...

Вдруг помогут мои комментарии к коду?

Код

// объявили тип указателя на функцию (действует как алиас)
typedef bool (*fMyCallback)(unsigned long uUserData);

// это, собственно, делегат; всё так же как на C#. Напишите свой.
__delegate bool MyCallback(__int32 uUserData);

// __gc (Garbage Collector) в старом синтаксисе (в .NET1.1) указывает на то, это - managed-структура
__gc struct MyCallbackWrapper {
    [MarshalAsAttribute(UnmanagedType::FunctionPtr)]
    // здесь держим экземпляр делегата
    MyCallback *m_call;
};

// __nogc (Garbage Collector) в старом синтаксисе (в .NET1.1) указывает на то, это - unmanaged-структура
__nogc struct MyCallbackWrapperUnmanaged {
    // здесь держим указатель на функцию
    fMyCallBack m_callUnmanged;
};

// эта функция берёт на вход экземпляр делегата, а возвращает указатель на функцию
fMyCallBack MakeUnmanagedCallback(MyCallback call)
{
    // создали экземпляр managed-структуры. Структура нужна как обёртка, чтобы затем Marshal-ить
    __gc struct MyCallbackWrapper *wrapper = new MyCallbackWrapper();

    // положили в неё наш экземпляр делегата
    wrapper->m_call = call;

    // создали экземпляр unmanaged-структуры
    MyCallbackWrapperUnmanaged wrapperUnmanaged;

    // промаршалим managed-структуру в unmanaged-структуру
    Marshal::StructureToPtr(wrapper, &wrapperUnmanaged, false);

    // вернули указатель, который получился в unmanaged-структуре
    return wrapperUnmanaged.m_callUnmanaged;
}


Всё это можно было бы положить в dllку на плюсах (CLR Class Libary) и, подключив к вашему C#-ому проекту, использовать с включёнными указателями (unsafe)...

Автор: Red Wind 9.5.2007, 20:29
Спасибо за столь подробное объяснение! Но скорее всего я немного запутался с постановкой задачи:(. Нужно полчить не указатель на делегат, а просто указатель на нейкий метод и положить этот указатель в класс IntPtr. Вот. Просто во втором фрэймворке имея возможность воспользоваться Marshal.GetFunctionPointerForDelegate это делается через делегаты.

Автор: MFSham 10.5.2007, 00:32
Может чего полезного найдешь по этой ссылке: http://www.intuit.ru/department/pl/csharp20/14/csharp20_14.html

Автор: Red Wind 10.5.2007, 22:19
MFSham,  спасибо за ссылку. Глянул. Может почерпну что-нибудь полезное. Но вот наткнулся на такаие методы как
System.Runtime.InteropServices.Marshal.GetManagedThunkForUnmanagedMethodPtr
System.Runtime.InteropServices.Marshal.GetUnmanagedThunkForManagedMethodPtr

Вот что написано в MSDN:

[ObsoleteAttribute("The GetManagedThunkForUnmanagedMethodPtr method has been deprecated and will be removed in a future release.", false)] 
public static IntPtr GetManagedThunkForUnmanagedMethodPtr (
    IntPtr pfnMethodToWrap,
    IntPtr pbSignature,
    int cbSignature
)

Parameters
pfnMethodToWrap
A pointer to the method to marshal. 

pbSignature
A pointer to the method signature. 

cbSignature
The number of bytes in pbSignature. 

Return Value
A pointer to the thunk that will marshal a call from the pfnMethodToWrap parameter. 

Вроде по описанию похоже на то что нужно. Но проблема в том, что нет никакой документации по ним. Пока у меня не получилось разобраться с тем как их применять. Например, как получить указатель на метод и его сигнатуру?

Автор: mr.DUDA 10.5.2007, 23:43
А как вы сочетаете unmanaged код с managed ? Если речь о простом вызове функции из unmanaged DLL через [DllImport], то можно объявить указатель как обычный делегат и передавать его соответственно:
Код
public class Some
{
    public delegate bool CallBackPtr(int hwnd, int lParam);

    [DllImport("user32.dll")]
    public static extern int EnumWindows(CallBackPtr callPtr, int lPar); 

    void Main()
    {
        EnumWindows(new CallBackPtr(МойМетод), 0);
    }

    public static bool МойМетод(int hwnd, int lParam) 
    { 
        Console.WriteLine("Window handle is "+hwnd);
        return true;
    }
}

Автор: marcusmae 11.5.2007, 21:35
Цитата(Red Wind @  10.5.2007,  22:19 Найти цитируемый пост)
 Но проблема в том, что нет никакой документации по ним.


Обычно документация отсутствует, если метод (класс) помечен deprecated (устаревший).

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)