Pure C++ delay load
От: Andrew S Россия http://alchemy-lab.com
Дата: 05.08.04 13:16
Оценка: 105 (10)
Приветствую всех.
Немного предыстории. По специфике моей работы мне довольно часто приходится вручную загружать библиотеки, резолвить множество функции. Отчасти потому, что требуется обеспечить совместимость с различными версиями виндовс, отчасти потому, что так бывает удобнее. Конечно, всегда хочется это автоматизировать. С одной стороны, есть поддержка компилятора\линкера в виде Delay Load, с другой стороны, бытует мнение, что использовать этот метод является дурным тоном (и наверное, это так. Несколько раз попав на странное поведение этого механизма, мы от него отказались). Существует достаточно много уже написанных велосипедов, но меня они по ряду причин не устроили. Объяснять все долго, вкратце — некоторые сделаны достаточно "тупо" и неоптимально — т.е. вызывают GetProcAddr и LoadLibrary на каждом шагу, другие не позволяют кастомизировать процесс резолвинга и т.д. и т.п (тот же пример на RSDN, на мой згляд, весьма показателен). Ну да ладно, это все хорошо, а что предлагается.
Предлагается следующее:

    1. Гибкая структура определения функций. Синтаксис достаточно прост и расширяем.
    2. Возможность задания своих policy на ошибки загрузки функции.
    3. Минимальный оверхед — создается _единая_ на все модули таблица указателей на функции, при первом вызове используется прокси с поиском функции, в дальнейшем — прямой вызов. Единая таблица загруженных модулей.
    4. Привычный синтаксис вызова — нет никаких FunResolver<Type>()(params), все внешне выглядит обычным вызовом функции из неймспейса (да так оно на самом деле и есть).

Итак, приступим. Сам код достаточно на мой взгляд понятен и адаптирован под VC6 и будет приведен в слудующем постинге. При желании можно портировать и под другие компиляторы.

А сечас сразу приведу пример использования:

// function table definition && declaration

USE_MODULE_BEGIN(kernel, *"*/ 'kern','el32','.dll' /*"*)
    DECLARE_FUN_P1_THROW(GetModuleHandle, *"*/ 'GetM','odul','eHan','dleA' /*"*, HMODULE, LPCSTR)
    DECLARE_FUN_P1(GetModuleHandleW, *"*/ 'GetM','odul','eHan','dleW' /*"*, HMODULE, LPCWSTR)
USE_MODULE_END

......
//  example

HMODULE hm = kernel::GetModuleHandle("ntdll.dll");
HMODULE hm2 = kernel::GetModuleHandleW(L"user32.dll");


Немного пояснений:
Минимальный размер таблицы указателей и их кросс-модульность обеспечивается синглтоном CDynFunction.
Основная проблема, решаемая в приведенном коде — невозможность в С++ инстанцироваться строковым литералом. Приходится извращаться числовыми литералами.
Многое из кода сделано именно так под VC6. Иначе там либо сложно, либо нельзя (ну или я не знаю как).
Публикуется только код для функций с одним параметром. Думаю, при помощи копи\пасте или макросов не составит труда значительно расширить количество параметров.

На самом деле, конечно, у этого решения тоже есть концептуальные недостатки. Например, если в разных модулях для одной функции задать разные policy, то сформируется несколько указателей (сколько policy) + для каждого будет свой прокси и вызываться GetProcAddr. Был и другой вариант кода, где эта проблема была решена отделением CDynFunction от прокси. Фактически, формировалась единая глобальная таблица указателей, а для каждого модуля была своя локальная копия со своими же прокси. Мне почему то показалось, что такой оверхед это слишком и что обычно в одном приложении следуют одинаковой стратегии на обработку ошибок, поэтому текущий подход в общем случае вызовет меньший оверхед в плане использования памяти.

Все это интересно пообсуждать, если будут дельные предложения — поправить\улучшить, поскольку сейчас реализована только концепция. Если получится хорошо — можно все причесать (например, добавить поддержку многопотоковости) и попробовать выложить в статьи как альтернативу CDynaLinkResolver.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re: Исходники 1.09
От: Andrew S Россия http://alchemy-lab.com
Дата: 08.09.04 13:13
Оценка: 32 (3)
Итак, версия 1.09.

Список изменений:


To do


Исходники доступны по адресу ниже.
http://www.rsdn.ru/File/8583/delayimphlp.zip

P.S. Как уже писалось ранее, есть мысль выложить все это в файлы в качестве отдельной библиотеки или функционала (с соотв. маленьким описанием классов, макросов и примером использования). Если общественность в виде титулованных rsdn'енеров поддержит это (т.е. сочтет данную библиотеку как минимум полезной) — можно будет устроить и это.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[6]: Исходники 1.2.0
От: Andrew S Россия http://alchemy-lab.com
Дата: 19.02.06 15:38
Оценка: 39 (2)
А>>Как выйдти из положения? Dll-ка не моя, поэтому использовать другие соглашения о вызове не могу, в то же время хочу использовать Вашу библиотеку, имхо очень удобная.

A>Ну так просто замени везде в библиотеке WINAPI на на что надо. Правда её тогда нельзя будет использовать с системными функциями.


Ну ладно, ладно, уговорили Не надо так прям вот все менять.
Итак, версия 1.3.0 бета.

Список изменений:

1. Добавлена поддержка конвенций вызова. Непосредственно в библиотеке поддерживаются WINAPI и __cdecl.
Итак, как все это работает. За поддержку встроенных конвенций отвечают макросы
#define DL_NO_STDCALL // не инастанцировать поддержку winapi соглашений о вызовах
#define DL_USE_CDECL  // инстанцировать поддержку __cdecl (по умолчанию отключено)


За поддержку вообще любых конценций отвечают макросы
DL_DECLARE_FUN_PROXY_CC(call_conv) // инстанцировать поддержку конвенций call_conv.

DL_DECLARE_FUN_CC(cc, name_id, r, p)
DL_DECLARE_FUN_THROW_CC(cc, name_id, r, p)
DL_DECLARE_FUN_ERR_CC(cc, name_id, r, p, e)
DL_DECLARE_FUN_ERR_POLICY_CC(cc, name_id, r, p, pl)


Назначение и параметры макросов DL_DECLARE_FUN_xxx_CC аналогичны DL_DECLARE_FUN_xxx, за исключением того, что первым параметром добавляется конвенция о вызове функции. Т.о., на самом деле это generic интерфейс к библиотеке, которым пользуются все остальные макросы.

Ну и примеры использования.

Включение __cdecl:
#define DL_USE_CDECL
#include "delayimphlp.h"

DL_USE_MODULE_BEGIN(mydll, "mydll.dll")
    DL_DECLARE_FUN_CC(__cdecl, MyFun, int, (int))
DL_USE_MODULE_END()


Добавление своих конвенций, например, __fastcall:
#include "delayimphlp.h"

DL_DECLARE_FUN_PROXY_CC(__fastcall)

DL_USE_MODULE_BEGIN(mydll, "mydll.dll")
    DL_DECLARE_FUN_CC(__fastcall, MyFun, int, (int))
DL_USE_MODULE_END()




To do

Багфиксы
Что то еще?


Вообще, у меня возникло устойчивое желание переопределить главные макросы, дабы было
    DL_DECLARE_FUN_CC(ret, call_conv, fun_name, params)
        DL_DECLARE_FUN(ret, fun_name, params)

Так фактически будет повторение синтаксиса определения функции в С... Как вам это, обсудим? Последствия очевидны — обломинго при компиляции старых исходников.

Исходники, !внимание!, не как обычно (поскольку эта бета со значительными изменениями), доступны по адресу ниже.
http://www.rsdn.ru/File/8583/delayimphlp_cc.zip
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[4]: Исходники 1.09
От: _nn_ www.nemerleweb.com
Дата: 13.09.04 11:28
Оценка: +1 -1
Здравствуйте, Andrew S, Вы писали:

__>>DL_USE_MODULE_END стоит изменить на:


AS>А в чем смысл, ну кроме необходимости ставить еще и () для макроса без параметров?


Однообразие.
DL_MODULE_BEGIN(...)

DL_MODULE_END()


Например карты сообщений в MFC и WTL сделанны так и оно смотрится лучше.
Я очень был удивлен что скобок не надо ставить.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: код v1.07
От: Andrew S Россия http://alchemy-lab.com
Дата: 25.08.04 09:48
Оценка: 33 (1)
Список изменений:


To do


По поводу MT — реализация, на мой взгляд, достаточно спорная, можно и нужно обсуждать.
Особенно это касается результирующих размеров прокси — в MT варианте 230-240 байт на функцию,
в ST порядка 80-90 (там все инлайнится буквально в plain code). В MT остается таки один
уровень не инлайновости, но это не спасает — все-таки 240 байт на функцию это прилично.
Конечно, думаю, не больше, чем у других, но все-таки значительно больше ST варианта.
Мысли?


//    delayimphlp.h: Delay import helper
//    Developer:    Andrew Solodovnikov
//    E-mail:        none
//    Date:        03.08.2004

#ifndef    __DELAYIMPHLP_H__
#define __DELAYIMPHLP_H__

#ifndef DL_NO_MT
    #define DL_MT _MT
#endif

#pragma warning (disable: 4786)

#define DL_CAT_(x,y) x##y
#define DL_CAT(x,y) DL_CAT_(x,y)

#define DL_STRINGIZE_(x) #x
#define DL_STRINGIZE(x) DL_STRINGIZE_(x)

#define MAX_DL_REPEAT 16
#define DL_COMMA() ,
#define DL_EMPTY() 

// DL_REPEAT_N
#define DL_REPEAT_IMPL_N_0(x, d) 
#define DL_REPEAT_IMPL_N_1(x, d)    DL_CAT(x,1)
#define DL_REPEAT_IMPL_N_2(x, d)    DL_REPEAT_IMPL_N_1(x, d)d()  DL_CAT(x,2)
#define DL_REPEAT_IMPL_N_3(x, d)    DL_REPEAT_IMPL_N_2(x, d)d()  DL_CAT(x,3)
#define DL_REPEAT_IMPL_N_4(x, d)    DL_REPEAT_IMPL_N_3(x, d)d()  DL_CAT(x,4)
#define DL_REPEAT_IMPL_N_5(x, d)    DL_REPEAT_IMPL_N_4(x, d)d()  DL_CAT(x,5)
#define DL_REPEAT_IMPL_N_6(x, d)    DL_REPEAT_IMPL_N_5(x, d)d()  DL_CAT(x,6)
#define DL_REPEAT_IMPL_N_7(x, d)    DL_REPEAT_IMPL_N_6(x, d)d()  DL_CAT(x,7)
#define DL_REPEAT_IMPL_N_8(x, d)    DL_REPEAT_IMPL_N_7(x, d)d()  DL_CAT(x,8)
#define DL_REPEAT_IMPL_N_9(x, d)    DL_REPEAT_IMPL_N_8(x, d)d()  DL_CAT(x,9)
#define DL_REPEAT_IMPL_N_10(x, d)    DL_REPEAT_IMPL_N_9(x, d)d()  DL_CAT(x,10)
#define DL_REPEAT_IMPL_N_11(x, d)    DL_REPEAT_IMPL_N_10(x, d)d()  DL_CAT(x,11)
#define DL_REPEAT_IMPL_N_12(x, d)    DL_REPEAT_IMPL_N_11(x, d)d()  DL_CAT(x,12)
#define DL_REPEAT_IMPL_N_13(x, d)    DL_REPEAT_IMPL_N_12(x, d)d()  DL_CAT(x,13)
#define DL_REPEAT_IMPL_N_14(x, d)    DL_REPEAT_IMPL_N_13(x, d)d()  DL_CAT(x,14)
#define DL_REPEAT_IMPL_N_15(x, d)    DL_REPEAT_IMPL_N_14(x, d)d()  DL_CAT(x,15)
#define DL_REPEAT_IMPL_N_16(x, d)    DL_REPEAT_IMPL_N_15(x, d)d()  DL_CAT(x,16)

#define DL_REPEAT_IMPL_N(n, x, d) DL_CAT(DL_REPEAT_IMPL_N_,n)(x, d)

#define DL_REPEAT_N(n,x) DL_REPEAT_IMPL_N(n, x, DL_COMMA)

// DL_REPEAT_PARAM_N
#define DL_REPEAT_PARAM_IMPL_N0(n, m, d1, d2)
#define DL_REPEAT_PARAM_IMPL_N1(n, m, d1, d2)    DL_CAT(n,1) DL_CAT(m,1)
#define DL_REPEAT_PARAM_IMPL_N2(n, m, d1, d2)    DL_REPEAT_PARAM_IMPL_N1(n, m, d1, d2)d1() DL_CAT(n,2)d2() DL_CAT(m,2)
#define DL_REPEAT_PARAM_IMPL_N3(n, m, d1, d2)    DL_REPEAT_PARAM_IMPL_N2(n, m, d1, d2)d1() DL_CAT(n,3)d2() DL_CAT(m,3)
#define DL_REPEAT_PARAM_IMPL_N4(n, m, d1, d2)    DL_REPEAT_PARAM_IMPL_N3(n, m, d1, d2)d1() DL_CAT(n,4)d2() DL_CAT(m,4)
#define DL_REPEAT_PARAM_IMPL_N5(n, m, d1, d2)    DL_REPEAT_PARAM_IMPL_N4(n, m, d1, d2)d1() DL_CAT(n,5)d2() DL_CAT(m,5)
#define DL_REPEAT_PARAM_IMPL_N6(n, m, d1, d2)    DL_REPEAT_PARAM_IMPL_N5(n, m, d1, d2)d1() DL_CAT(n,6)d2() DL_CAT(m,6)
#define DL_REPEAT_PARAM_IMPL_N7(n, m, d1, d2)    DL_REPEAT_PARAM_IMPL_N6(n, m, d1, d2)d1() DL_CAT(n,7)d2() DL_CAT(m,7)
#define DL_REPEAT_PARAM_IMPL_N8(n, m, d1, d2)    DL_REPEAT_PARAM_IMPL_N7(n, m, d1, d2)d1() DL_CAT(n,8)d2() DL_CAT(m,8)
#define DL_REPEAT_PARAM_IMPL_N9(n, m, d1, d2)    DL_REPEAT_PARAM_IMPL_N8(n, m, d1, d2)d1() DL_CAT(n,9)d2() DL_CAT(m,9)
#define DL_REPEAT_PARAM_IMPL_N10(n, m, d1, d2)    DL_REPEAT_PARAM_IMPL_N9(n, m, d1, d2)d1() DL_CAT(n,10)d2() DL_CAT(m,10)
#define DL_REPEAT_PARAM_IMPL_N11(n, m, d1, d2)    DL_REPEAT_PARAM_IMPL_N10(n, m, d1, d2)d1() DL_CAT(n,11)d2() DL_CAT(m,11)
#define DL_REPEAT_PARAM_IMPL_N12(n, m, d1, d2)    DL_REPEAT_PARAM_IMPL_N11(n, m, d1, d2)d1() DL_CAT(n,12)d2() DL_CAT(m,12)
#define DL_REPEAT_PARAM_IMPL_N13(n, m, d1, d2)    DL_REPEAT_PARAM_IMPL_N12(n, m, d1, d2)d1() DL_CAT(n,13)d2() DL_CAT(m,13)
#define DL_REPEAT_PARAM_IMPL_N14(n, m, d1, d2)    DL_REPEAT_PARAM_IMPL_N13(n, m, d1, d2)d1() DL_CAT(n,14)d2() DL_CAT(m,14)
#define DL_REPEAT_PARAM_IMPL_N15(n, m, d1, d2)    DL_REPEAT_PARAM_IMPL_N14(n, m, d1, d2)d1() DL_CAT(n,15)d2() DL_CAT(m,15)
#define DL_REPEAT_PARAM_IMPL_N16(n,m, d1, d2)    DL_REPEAT_PARAM_IMPL_N15(n, m, d1, d2)d1() DL_CAT(n,16)d2() DL_CAT(m,16)

#define DL_REPEAT_PARAM_IMPL_N(c, n, m, d1, d2)    DL_CAT(DL_REPEAT_PARAM_IMPL_N,c)(n, m, d1, d2)

#define DL_REPEAT_PARAM_N(c, n, m)    DL_REPEAT_PARAM_IMPL_N(c, n, m, DL_COMMA, DL_EMPTY)

// DL_SEQ_SIZE

#define DL_SEQ_SIZE(seq)    DL_SEQ_SIZE_IMPL(seq)
#define DL_SEQ_SIZE_IMPL(seq)    DL_CAT(DL_N_, DL_SEQ_SIZE_0 seq)

#define DL_SEQ_SIZE_0(_)    DL_SEQ_SIZE_1
#define DL_SEQ_SIZE_1(_)    DL_SEQ_SIZE_2
#define DL_SEQ_SIZE_2(_)    DL_SEQ_SIZE_3
#define DL_SEQ_SIZE_3(_)    DL_SEQ_SIZE_4
#define DL_SEQ_SIZE_4(_)    DL_SEQ_SIZE_5
#define DL_SEQ_SIZE_5(_)    DL_SEQ_SIZE_6
#define DL_SEQ_SIZE_6(_)    DL_SEQ_SIZE_7
#define DL_SEQ_SIZE_7(_)    DL_SEQ_SIZE_8
#define DL_SEQ_SIZE_8(_)    DL_SEQ_SIZE_9
#define DL_SEQ_SIZE_9(_)    DL_SEQ_SIZE_10
#define DL_SEQ_SIZE_10(_)    DL_SEQ_SIZE_11
#define DL_SEQ_SIZE_11(_)    DL_SEQ_SIZE_12
#define DL_SEQ_SIZE_12(_)    DL_SEQ_SIZE_13
#define DL_SEQ_SIZE_13(_)    DL_SEQ_SIZE_14
#define DL_SEQ_SIZE_14(_)    DL_SEQ_SIZE_15
#define DL_SEQ_SIZE_15(_)    DL_SEQ_SIZE_16

#define DL_N_DL_SEQ_SIZE_0    0
#define DL_N_DL_SEQ_SIZE_1    1
#define DL_N_DL_SEQ_SIZE_2    2
#define DL_N_DL_SEQ_SIZE_3    3
#define DL_N_DL_SEQ_SIZE_4    4
#define DL_N_DL_SEQ_SIZE_5    5
#define DL_N_DL_SEQ_SIZE_6    6
#define DL_N_DL_SEQ_SIZE_7    7
#define DL_N_DL_SEQ_SIZE_8    8
#define DL_N_DL_SEQ_SIZE_9    9
#define DL_N_DL_SEQ_SIZE_10    10
#define DL_N_DL_SEQ_SIZE_11    11
#define DL_N_DL_SEQ_SIZE_12    12
#define DL_N_DL_SEQ_SIZE_13    13
#define DL_N_DL_SEQ_SIZE_14    14
#define DL_N_DL_SEQ_SIZE_15    15
#define DL_N_DL_SEQ_SIZE_16    16

// DL_SEQ_ENUM

#define DL_SEQ_ENUM(seq)    DL_SEQ_ENUM_IMPL(seq)
#define DL_SEQ_ENUM_IMPL(seq)    DL_CAT(DL_SEQ_ENUM_, DL_SEQ_SIZE(seq)) seq

#define    DL_SEQ_ENUM_1(x)    x
#define    DL_SEQ_ENUM_2(x)    x, DL_SEQ_ENUM_1
#define    DL_SEQ_ENUM_3(x)    x, DL_SEQ_ENUM_2
#define    DL_SEQ_ENUM_4(x)    x, DL_SEQ_ENUM_3
#define    DL_SEQ_ENUM_5(x)    x, DL_SEQ_ENUM_4
#define    DL_SEQ_ENUM_6(x)    x, DL_SEQ_ENUM_5
#define    DL_SEQ_ENUM_7(x)    x, DL_SEQ_ENUM_6
#define    DL_SEQ_ENUM_8(x)    x, DL_SEQ_ENUM_7
#define    DL_SEQ_ENUM_9(x)    x, DL_SEQ_ENUM_8
#define    DL_SEQ_ENUM_10(x)    x, DL_SEQ_ENUM_9
#define    DL_SEQ_ENUM_11(x)    x, DL_SEQ_ENUM_10
#define    DL_SEQ_ENUM_12(x)    x, DL_SEQ_ENUM_11
#define    DL_SEQ_ENUM_13(x)    x, DL_SEQ_ENUM_12
#define    DL_SEQ_ENUM_14(x)    x, DL_SEQ_ENUM_13
#define    DL_SEQ_ENUM_15(x)    x, DL_SEQ_ENUM_14
#define    DL_SEQ_ENUM_16(x)    x, DL_SEQ_ENUM_15


#define NAME_ID(id)    DL_CAT(CNameId, id)

#define DECLARE_NAME_ID_IMPL(id, name, ret, text)\
struct NAME_ID(id)\
{\
    enum {length = sizeof(name)};\
    static ret GetStr(){return text(name);}\
};


#define DECLARE_NAME_ID_A(id, name)    DECLARE_NAME_ID_IMPL(id, name, LPCSTR, DL_EMPTY())
#define DECLARE_NAME_ID(id, name)    DECLARE_NAME_ID_IMPL(id, name, LPCTSTR,_T)


#ifdef DL_MT
//  MT only
struct CLWMutex
{
    CLWMutex(volatile LONG &pFlag):m_pFlag(pFlag)
    {
    }
    void Lock()
    {
        while(::InterlockedExchange(&m_pFlag, TRUE))
            Sleep(1);
    }
    void Unlock()
    {
        ::InterlockedExchange(&m_pFlag, FALSE);
    }
    volatile LONG &m_pFlag;
};

template<class T>
struct CAutoLock
{
    CAutoLock(T& obj):m_objLock(obj)
    {
        m_objLock.Lock();
    }
    ~CAutoLock()
    {
        m_objLock.Unlock();
    }
    T &m_objLock;
};

#endif //DL_MT


template <class Name>
class CModule
{
public:
    typedef CModule<Name> type;
    typedef Name          name_type;
    static type &GetModule()
    {
#ifdef DL_MT
        static volatile LONG lMutex = FALSE;
        CLWMutex theMutex(lMutex);
        CAutoLock<CLWMutex> autoLock(theMutex);
#endif //DL_MT
        static type Module;
        return Module;
    }
    HMODULE GetModuleHandle() const
    {
        return m_hModule;
    }
    BOOL IsLoaded() const
    {
        return m_hModule != NULL;
    }
//  Caution - use with care. Not thread-safe
    BOOL UnloadModule()
    {
        HMODULE hModule = m_hModule;
        m_hModule = NULL;
        return FreeLibrary(hModule);
    }
    ~CModule()
    {
        if (m_hModule)
            UnloadModule();
    }
private:
    CModule()
    {
        m_hModule = ::LoadLibrary(name_type::GetStr());
    }
    HMODULE m_hModule;
};


template <class Module, class Name, class Proxy>
class CDynFunction
{
public:
    typedef CDynFunction<Module, Name, Proxy> type;
    typedef Proxy                              proxy_type;
    typedef Module                              module_type;
    typedef Name                              name_type;
    
    static typename proxy_type::fun_type &GetProxy()
    {
        static proxy_type::fun_type proxy = proxy_type::template Proxy<type>::ProxyFun;
        return proxy;
    }
    static BOOL InitFunction()
    {
#ifdef DL_MT
        static volatile LONG lMutex = FALSE;
        CLWMutex theMutex(lMutex);
        CAutoLock<CLWMutex> autoLock(theMutex);
    //  test for first entry
        if (GetProxy() != proxy_type::template Proxy<type>::ProxyFun)
            return TRUE;
#endif // DL_MT
        const module_type &theModule = module_type::GetModule();
        if (theModule.IsLoaded())
        {
            FARPROC pFunction = ::GetProcAddress(theModule.GetModuleHandle(), name_type::GetStr());
            if (pFunction)
            {
                GetProxy() = (proxy_type::fun_type)pFunction;
                return TRUE;
            }
        }
        return FALSE;
    }
};



struct CDynFunException
{
    CDynFunException(): m_sMessage(NULL)
    {
    };
    ~CDynFunException()
    {
        free(m_sMessage);
    };
    CDynFunException(LPCTSTR sMessage):m_sMessage(NULL)
    {
        SetMessage(sMessage);
    }
    CDynFunException(const CDynFunException &other):m_sMessage(NULL)
    {
        SetMessage(other.m_sMessage);
    }
    CDynFunException &operator = (const CDynFunException &other)
    {
        SetMessage(other.m_sMessage);
        return *this;
    }
    void SetMessage(LPCTSTR sMessage)
    {
        free(m_sMessage);
        m_sMessage = (LPTSTR)malloc((_tcslen(sMessage) + 1) * sizeof(TCHAR));
        if (m_sMessage)
            _tcscpy(m_sMessage, sMessage);
    }
    LPCTSTR GetMessage() const
    {
        return m_sMessage;
    }
private:
    LPTSTR m_sMessage;
};

template <class R> 
struct FunProxyThrowRetTypeTrait
{
    template <class F>
    struct FunctionTraitImpl
    {
        static R MakeReturn()
        {
            F::MakeReturnImpl();
            return R();
        }
    };
};

template <> 
struct FunProxyThrowRetTypeTrait<void>
{
    template <class F>
    struct FunctionTraitImpl
    {
        static void MakeReturn()
        {
            F::MakeReturnImpl();
        }
    };
};

template<class E = CDynFunException>
struct FunProxyThrowPolicy
{
    template <class DynFunction> 
    struct FunctionTrait:public FunProxyThrowRetTypeTrait<typename DynFunction::proxy_type::ret_type>::template FunctionTraitImpl<FunctionTrait<DynFunction> >
    {
        static void MakeReturnImpl()
        {
            TCHAR szMessage[DynFunction::name_type::length + 64];
            _stprintf(szMessage, _T("Can'n resolve procedure <%s>: %d"), DynFunction::name_type::GetStr(), GetLastError());
            throw E(szMessage);
        }
    };
};


//  we need not implement void return type value policy, 
//  coz void function can only throw on error

template<class R, R value = R()>
struct FunProxyValuePolicy
{
    template <class DynFunction> 
    struct FunctionTrait
    {
        static typename DynFunction::proxy_type::ret_type MakeReturn()
        {
            return value;
        }
    };
};


#define FUN_PROXY(n) DL_CAT(FunProxy,n)
#define FUN_PROXY_IMPL(n) DL_CAT(FUN_PROXY(n),Impl)

#define DECLARE_FUN_PROXY(param_count) \
template <typename R>\
struct FUN_PROXY_IMPL(param_count)\
{\
    template <class DynFunction, DL_REPEAT_N(param_count, typename P), class Policy> struct RetProxy\
    {\
        static R WINAPI ProxyFun(DL_REPEAT_PARAM_N(param_count, P, v))\
        {\
            if (DynFunction::InitFunction())\
                return DynFunction::GetProxy()(DL_REPEAT_N(param_count, v));\
            return Policy::template FunctionTrait<DynFunction>::MakeReturn();\
        }\
    };\
};\
\
template <>\
struct FUN_PROXY_IMPL(param_count) <void>\
{\
    template <class DynFunction, DL_REPEAT_N(param_count, typename P), class Policy> struct RetProxy\
    {\
        static void WINAPI ProxyFun(DL_REPEAT_PARAM_N(param_count, P, v))\
        {\
            if (DynFunction::InitFunction())\
                DynFunction::GetProxy()(DL_REPEAT_N(param_count, v));\
            else\
                Policy::template FunctionTrait<DynFunction>::MakeReturn();\
        }\
    };\
};\
\
template <typename R, DL_REPEAT_N(param_count, typename P), class Policy = FunProxyValuePolicy<R> >\
struct FUN_PROXY(param_count)\
{\
    typedef R (WINAPI *fun_type)(DL_REPEAT_N(param_count, P));\
    typedef R ret_type;\
    template <class DynFunction> struct Proxy:public FUN_PROXY_IMPL(param_count)<R>::template RetProxy<DynFunction, DL_REPEAT_N(param_count, P), Policy>\
    {\
    };\
};

DECLARE_FUN_PROXY(1)
DECLARE_FUN_PROXY(2)
DECLARE_FUN_PROXY(3)
DECLARE_FUN_PROXY(4)
DECLARE_FUN_PROXY(5)
DECLARE_FUN_PROXY(6)
DECLARE_FUN_PROXY(7)
DECLARE_FUN_PROXY(8)
DECLARE_FUN_PROXY(9)
DECLARE_FUN_PROXY(10)
DECLARE_FUN_PROXY(11)
DECLARE_FUN_PROXY(12)
DECLARE_FUN_PROXY(13)
DECLARE_FUN_PROXY(14)
DECLARE_FUN_PROXY(15)
DECLARE_FUN_PROXY(16)

// usefull macro's


#define DL_USE_MODULE_BEGIN(nmspace, name) \
namespace nmspace \
{\
    DECLARE_NAME_ID(DL_CAT(_MODULE_, nmspace), name)\
    typedef CModule<NAME_ID(DL_CAT(_MODULE_, nmspace))> module_type;

#define DL_USE_MODULE_END \
};


#define DL_DECLARE_FUN(NameId, R, P) \
DECLARE_NAME_ID_A(NameId, DL_STRINGIZE(NameId))\
static R (WINAPI *&NameId)(DL_SEQ_ENUM(P)) = CDynFunction<module_type, NAME_ID(NameId), FUN_PROXY(DL_SEQ_SIZE(P))<R, DL_SEQ_ENUM(P)> >::GetProxy();

#define DL_DECLARE_FUN_ERR(Name, NameId, R, P, E)\
DECLARE_NAME_ID_A(NameId, DL_STRINGIZE(NameId))\
static R (WINAPI *&NameId)(DL_SEQ_ENUM(P)) = CDynFunction<module_type, NAME_ID(NameId), FUN_PROXY(DL_SEQ_SIZE(P))<R, DL_SEQ_ENUM(P), FunProxyValuePolicy<R,E> > >::GetProxy();
 
#define DL_DECLARE_FUN_THROW(NameId, R, P)\
DECLARE_NAME_ID_A(NameId, DL_STRINGIZE(NameId))\
static R (WINAPI *&NameId)(DL_SEQ_ENUM(P)) = CDynFunction<module_type, NAME_ID(NameId), FUN_PROXY(DL_SEQ_SIZE(P))<R, DL_SEQ_ENUM(P), FunProxyThrowPolicy<> > >::GetProxy();

#define DL_DECLARE_FUN_POLICY(NameId, R, P, PL) \
DECLARE_NAME_ID_A(NameId, DL_STRINGIZE(NameId))\
static R (WINAPI *&NameId)(DL_SEQ_ENUM(P)) = CDynFunction<module_type, NAME_ID(NameId), FUN_PROXY(DL_SEQ_SIZE(P))<R, DL_SEQ_ENUM(P)>, PL>::GetProxy();

#endif
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[6]: Сам код
От: WolfHound  
Дата: 05.08.04 20:48
Оценка: 21 (1)
Здравствуйте, Andrew S, Вы писали:

AS>Нет, не то. Проинициализируйте буфер статически. Иначе в чем смысл, затраты кода будут больше неиспользуемой части буфера. Я привел вариант, но он ужасен, но там все в компиле-тайм. Другого я придумать не смог .

template<DWORD count>
struct CNameIdBuf;
template<>
struct CNameIdBuf<1>
{
    template <DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
    struct Buf
    {
        static const DWORD* Get()
        {
            static const DWORD a[1]={n0};
            return a;
        }
    };
};
template<>
struct CNameIdBuf<2>
{
    template <DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
    struct Buf
    {
        static const DWORD* Get()
        {
            static const DWORD a[2]={n0, n1};
            return a;
        }
    };
};
.......
template <DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
struct CNameId
{
    CNameId()
    {
        std::cout<<count<<"\n";
    }
    enum
    {
        count   =!n0?0
                :!n1?1
                :!n2?2
                :!n3?3
                :!n4?4
                :!n5?5
                :!n6?6
                :!n7?7
                :8
    };
    static void MakeStr(LPTSTR szBuffer)
    {
        static const DWORD* a=CNameIdBuf<count>::Buf<n0,n1,n2,n3,n4,n5,n6,n7>::Get();
    }
};
int main()
{
//    CNameId<>::MakeStr(0);
    CNameId<1>::MakeStr(0);
    CNameId<1,2>::MakeStr(0);
    //CNameId<1,4,5,6,7>::MakeStr(0);
    //CNameId<1,2,3,4,5,6,7,8>::MakeStr(0);
    return 0;
}

А если не бояться boost'а то специализации можно наплодить так
#define MAKE_BUF_SPEC(z, count, max_count)                                  \
template<>                                                                  \
struct CNameIdBuf<count>                                                    \
{                                                                           \
    template<BOOST_PP_ENUM_PARAMS(max_count, DWORD n)>                      \
    struct Buf                                                              \
    {                                                                       \
        static const DWORD* Get()                                           \
        {                                                                   \
            static const DWORD a[count]={BOOST_PP_ENUM_PARAMS(count, n)};   \
            return a;                                                       \
        }                                                                   \
    };                                                                      \
};                                                                          \
//end macro
BOOST_PP_REPEAT_FROM_TO(1, 9, MAKE_BUF_SPEC, 8)
... << RSDN@Home 1.1.3 beta 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[2]: Код v1.05
От: WolfHound  
Дата: 23.08.04 15:00
Оценка: 21 (1)
Здравствуйте, Andrew S, Вы писали:

У меня тут такая мысль возникла а что если в место
template <DL_REPEAT_DEF_N(MAX_DL_REPEAT, DWORD n, = 0)>
struct CNameId
{
    enum
    {
        DL_REPEAT_PARAM_N(MAX_DL_REPEAT, m_n, =n),
        count   = DL_REPEAT_MACRO_IMPL_N(MAX_DL_REPEAT, NN_REP_COUNT_M, n, DL_EMPTY) MAX_DL_REPEAT,
        length  = count * sizeof(DWORD)
    };
    static LPCTSTR GetStr()
    {
        return CNameIdHolder<count>::template CNameIdHolderImpl<DL_REPEAT_N(MAX_DL_REPEAT, n)>::GetStr();
    }
};


#define DL_USE_MODULE_BEGIN(nmspace, NameId) \
namespace nmspace \
{\
    typedef CModule< CNameId<DL_SEQ_ENUM_CHAR(NameId)> > module_type;

#define DL_USE_MODULE_END \
};


#define DL_DECLARE_FUN(NameId, R, P) \
static R (WINAPI *&DL_SEQ_CAT(NameId))(DL_SEQ_ENUM(P)) = CDynFunction<module_type, CNameId<DL_SEQ_ENUM_CHAR(NameId)>, FUN_PROXY(DL_SEQ_SIZE(P))<R, DL_SEQ_ENUM(P)> >::GetProxy();

#define DL_DECLARE_FUN_ERR(Name, NameId, R, P, E)\
static R (WINAPI *&DL_SEQ_CAT(NameId))(DL_SEQ_ENUM(P)) = CDynFunction<module_type, CNameId<DL_SEQ_ENUM_CHAR(NameId)>, FUN_PROXY(DL_SEQ_SIZE(P))<R, DL_SEQ_ENUM(P), FunProxyValuePolicy<R,E> > >::GetProxy();
 
#define DL_DECLARE_FUN_THROW(NameId, R, P)\
static R (WINAPI *&DL_SEQ_CAT(NameId))(DL_SEQ_ENUM(P)) = CDynFunction<module_type, CNameId<DL_SEQ_ENUM_CHAR(NameId)>, FUN_PROXY(DL_SEQ_SIZE(P))<R, DL_SEQ_ENUM(P), FunProxyThrowPolicy<> > >::GetProxy();



DL_USE_MODULE_BEGIN(kernel, (kern)(el32)(.dll))
    DL_DECLARE_FUN((GetP)(rocA)(ddre)(ss), FARPROC, (HMODULE)(LPCTSTR))
    DL_DECLARE_FUN((GetM)(odul)(eHan)(dleA), HMODULE, (LPCTSTR))
    DL_DECLARE_FUN_THROW((Init)(iali)(zeCr)(itic)(alSe)(ctio)(n), void, (LPCRITICAL_SECTION))
DL_USE_MODULE_END


сделать так
#define DL_USE_MODULE_BEGIN(nmspace, Name) \
namespace nmspace \
{\
    struct CModuleNameId_##nmspace\
    {\
        static LPCSTR GetStr(){return Name;}\
    };\
    typedef CModule< CModuleNameId_##nmspace > module_type;

#define DL_USE_MODULE_END \
};


#define DL_DECLARE_FUN(Name, R, P) \
    struct CFunctionNameId_##Name\
    {\
        static LPCSTR GetStr(){return #Name;}\
    };\
static R (WINAPI *&DL_SEQ_CAT(NameId))(DL_SEQ_ENUM(P)) = CDynFunction<module_type, CFunctionNameId_##Name, FUN_PROXY(DL_SEQ_SIZE(P))<R, DL_SEQ_ENUM(P)> >::GetProxy();

#define DL_DECLARE_FUN_ERR(Name, NameId, R, P, E)\
    struct CFunctionNameId_##Name\
    {\
        static LPCSTR GetStr(){return #Name;}\
    };\
static R (WINAPI *&DL_SEQ_CAT(NameId))(DL_SEQ_ENUM(P)) = CDynFunction<module_type, CFunctionNameId_##Name, FUN_PROXY(DL_SEQ_SIZE(P))<R, DL_SEQ_ENUM(P), FunProxyValuePolicy<R,E> > >::GetProxy();
 
#define DL_DECLARE_FUN_THROW(NameId, R, P)\
    struct CFunctionNameId_##Name\
    {\
        static LPCSTR GetStr(){return #Name;}\
    };\
static R (WINAPI *&DL_SEQ_CAT(NameId))(DL_SEQ_ENUM(P)) = CDynFunction<module_type, CFunctionNameId_##Name, FUN_PROXY(DL_SEQ_SIZE(P))<R, DL_SEQ_ENUM(P), FunProxyThrowPolicy<> > >::GetProxy();



DL_USE_MODULE_BEGIN(kernel, "kernel32.dll")
    DL_DECLARE_FUN(GetProcAddress, FARPROC, (HMODULE)(LPCTSTR))
    DL_DECLARE_FUN(GetModuleHandleA, HMODULE, (LPCTSTR))
    DL_DECLARE_FUN_THROW(InitializeCriticalSection, void, (LPCRITICAL_SECTION))
DL_USE_MODULE_END
... << RSDN@Home 1.1.4 rev. 142 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: Исходники 1.2.0
От: Andrew S Россия http://alchemy-lab.com
Дата: 05.12.05 08:51
Оценка: 20 (1)
Версия 1.2.0

Список изменений:

1. Генерируемые макросами типы, надобные для внутренних нужд библиотеки, находятся теперь в наймспейсе internal_types. Т.о., чтобы добраться до типа модуля, надо теперь писать нечто вроде module_name::internal_types::module_type. Решение, в принципе, спорное — если есть аргументы за\против, можно пообсуждать.
2. Добавлены макросы DL_UNLOAD_MODULE(nmspace) и DL_RESET_FUN(nmspace, name_id). Первый выгружает модуль, а второй приводит функцию в состояние до загрузки (т.е. при следующем ее вызове опять будет вызван прокси-объект). Понадобится это может, например, если необходимо выгрузить и опять загрузить библиотеку, хотя и будет выглядеть довольно муторно. Если есть лучшие предложения — можно обсудить.
3. Багфиксы юникодной конфигурации (за это отдельное спасибо Вечяславу).
4. Новый пример.

To do

Багфиксы
Что то еще?

Исходники, как обычно, доступны по адресу ниже.
http://www.rsdn.ru/File/8583/delayimphlp.zip
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[2]: Сам код
От: _nn_ www.nemerleweb.com
Дата: 05.08.04 14:32
Оценка: 14 (1)
Здравствуйте, Andrew S, Вы писали:

AS>Все в куче, уж не обессудьте.

AS>
AS>#define FLATTEN_STR(buff, name, idx) \
AS>        (buff)[4*(idx)] = (TCHAR)((name##idx & 0xFF000000) >> 24);\
AS>        (buff)[4*(idx) + 1] = (TCHAR)((name##idx & 0xFF0000) >> 16);\
AS>        (buff)[4*(idx) + 2] = (TCHAR)((name##idx & 0xFF00) >> 8);\
AS>        (buff)[4*(idx) + 3] = (TCHAR)(name##idx & 0xFF);

AS>void FlattenStr(LPSTR szBuffer, DWORD n0, DWORD n1, DWORD n2, DWORD n3, DWORD n4, DWORD n5, DWORD n6, DWORD n7)
AS>{
AS>        FLATTEN_STR(szBuffer, n, 0);
AS>        FLATTEN_STR(szBuffer, n, 1);
AS>        FLATTEN_STR(szBuffer, n, 2);
AS>        FLATTEN_STR(szBuffer, n, 3);
AS>        FLATTEN_STR(szBuffer, n, 4);
AS>        FLATTEN_STR(szBuffer, n, 5);
AS>        FLATTEN_STR(szBuffer, n, 6);
AS>        FLATTEN_STR(szBuffer, n, 7);
AS>        szBuffer[64] = _T('\0');
AS>}


AS>template <DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
AS>struct CNameId
AS>{
AS>    enum {name_size = 65, m_n0 = n0, m_n1 = n1, m_n2 = n2, m_n3 = n3, m_n4 = n4, m_n5 = n5, m_n6 = n6, m_n7 = n7};
AS>    static void MakeStr(LPTSTR szBuffer)
AS>    {
AS>        FlattenStr(szBuffer, n0,n1,n2,n3,n4,n5,n6,n7);
AS>    }
AS>};


Это можно переделать так :
void FlattenStr(LPSTR szBuffer, const DWORD* pN, DWORD n)
{
    for(DWORD i=0;i<n;i++)
    {
        szBuffer[i*4+0]=HIBYTE(HIWORD(pN[i]));
        szBuffer[i*4+1]=LOBYTE(HIWORD(pN[i]));
        szBuffer[i*4+2]=HIBYTE(LOWORD(pN[i]));
        szBuffer[i*4+3]=LOBYTE(LOWORD(pN[i]));
    }
    szBuffer[i*4] = 0;
}

template<DWORD n0 = 0,
        DWORD n1 = 0,
        DWORD n2 = 0,
        DWORD n3 = 0,
        DWORD n4 = 0,
        DWORD n5 = 0,
        DWORD n6 = 0,
        DWORD n7 = 0>
struct CNameId
{
    enum
    {
        name_size = 65,
        m_n0 = n0,
        m_n1 = n1,
        m_n2 = n2,
        m_n3 = n3,
        m_n4 = n4,
        m_n5 = n5,
        m_n6 = n6,
        m_n7 = n7
    };

    static void MakeStr(LPTSTR szBuffer)
    {
        static const DWORD a[]={n0,n1,n2,n3,n4,n5,n6,n7};
        FlattenStr(szBuffer, a, 7);
    }
};


Таким образом в случае изменения CNameId функцию FlattenStr не будет необходимости менять.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[8]: CNameID v1.02
От: _nn_ www.nemerleweb.com
Дата: 13.08.04 18:51
Оценка: 14 (1)
Здравствуйте, Andrew S, Вы писали:

AS>>>Ну, и подумайте, что вы предлагаете Хинт — при инстанцировании класса CNameID параметрами должны быть символьные литералы (то бишь константы).

__>>Инстанирование будет литералами, а извне это будет в виде массива.

AS>Не получится. Надо инстанцировать константами, а вы предлагаете инстанцировать фактически содержимым ячеек памяти, что на этапе компиляции компилеру не известно (ведь темплайт в данном случае инстанцируется адресом, к сожалению, а не содержимым).

Вы меня не так поняли
Ну ладно это не важно, я попробую переработать это для совместимости с VC 6 и выложу на форум.
Главное ведь результат

AS>>>>>На самом деле, наверное, лучше подумать над более глобальной проблемой — как удобнее сделать макросы

AS>>>>>USE_MODULE_BEGIN и DECLARE_FUN_P1 в части задания имени. То, что есть сейчас, явно неудобно...
__>>>>Если решить проблемы выше то это отпадет само собой.

AS>>>Да, если решить проблемы Я (и не только я) пробовал, не получилось. Точнее, получилось то, что получилось.

__>>Как только доберусь нормально до компьютера попробую что-нибудь сотворить
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: Попытка компиляции в VC7.1
От: adontz Грузия http://adontz.wordpress.com/
Дата: 23.08.04 16:41
Оценка: 14 (1)
Здравствуйте, Andrew S, Вы писали:

строка 171
static proxy_type::fun_type &GetProxy()
заменить на
static typename proxy_type::fun_type &GetProxy()

строка 260
struct FunctionTrait:public FunProxyThrowRetTypeTrait<DynFunction::proxy_type::ret_type>::template FunctionTraitImpl<FunctionTrait<DynFunction> >
заменить на
struct FunctionTrait:public FunProxyThrowRetTypeTrait<typename DynFunction::proxy_type::ret_type>::template FunctionTraitImpl<FunctionTrait<DynFunction> >

строка 281
static DynFunction::proxy_type::ret_type MakeReturn()
заменить на
static typename DynFunction::proxy_type::ret_type MakeReturn()

строка 310
static R WINAPI ProxyFun(DL_REPEAT_PARAM_N(param_count, P, v))\
заменить на
static void WINAPI ProxyFun(DL_REPEAT_PARAM_N(param_count, P, v))\


После чего всё компилируется и даже работает
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[3]: код v1.08
От: Andrew S Россия http://alchemy-lab.com
Дата: 31.08.04 07:01
Оценка: 14 (1)
БП>Ну, например, вариант с GetModuleHandle вместо LoadLibrary/GetProcAddress.
БП>Во первых работает быстрее.
БП>Во вторых — не нужно делать FreeLibrary.
БП>В третьих, можно вообще не синхронизировать.

Да, я уже про это думал. Вероятно, будет удобным сделать стратегии вида:

struct CModulePolicyLoad
{
static HMODULE Load(LPCTSTR szFileName);
static BOOL Free(HMODULE hModule);
}

и уже их испольовать вместо непосредственных вызовов LoadLibrary и иже с ними.
С одной стороны, это даст возможность не писать большого количества однообразного кода для другого CModule, с другой стороны — даст возможность пользователю управлять процессом загрузки библиотек, например, изменять пути по умолчанию, пути к файлам и т.п.

Как вернусь из отпуска, попробую сделать нечто подобное.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[2]: Исходники 1.09
От: _nn_ www.nemerleweb.com
Дата: 08.09.04 17:56
Оценка: 14 (1)
Здравствуйте, Andrew S, Вы писали:

  • Исправление:
    static typename proxy_type::fun_type &GetProxy()
        {
            static proxy_type::fun_type proxy = proxy_type::template Proxy<type>::ProxyFun;
            return proxy;
        }

    Надо
    typename proxy_type::fun_type proxy = proxy_type::template Proxy<type>::ProxyFun;

    Почему-то это учтено выше, но в функции не учтено.

  • Предложение по обработке DL_MT :

    В кратце : сделать и такую версию и обычную.

    Сделать 2 класса CModule : CModuleMT и CModuleNoMT, CDynFunction и т.п. аналогично.

    А в конце файла такое :
    #ifdef _MT
    
    // #define CModuleMT CModule
    template <class Name, class LoadPolicy = CModuleLoadLibraryPolicy>
    class CModule : CModuleMT<Name,LoadPolicy>
    {...}
    
    //...
    
    #else
    
    // #define CModuleNoMT CModule
    template <class Name, class LoadPolicy = CModuleLoadLibraryPolicy>
    class CModule : CModuleNoMT<Name,LoadPolicy>
    {...}
    
    //...
    
    #endif

    И не надо будет определять макрос DL_MT

    P.S.
    Стиль как-то не очень совпадает, пространство имен называет dl, а имена классов в другом стиле, да еще начинаются на C.

    Есть предложение изменить стиль на стиль STL

    Может пространство имен сменить на delayload, а то dl не очень уникально может быть.
  • http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[10]: Pure C++ delay load
    От: 23W http://kyselgov.pp.ua/
    Дата: 19.07.05 12:33
    Оценка: 12 (1)
    И сново здравствуйте!
    Андрей, Вы будете смеяться, но дождавшись наконец-то полного ребилдинга проекта
    я заметил еще один варнинг (он тоже из области 4-го уровня).Это C4512!
    Проявляется он далеко не всегда, напримерм у меня в проекте есть несеколько модулей оптимизированные под
    высокую производительность, поэтому они не искрользуют никаких библиотек, кроме некоторых шаблонов STL, и
    в настройки этих подпроэктов выкручены "по максимуму".
    Так вот в этих модулях, зачем-то компилятор начинает меня предупреждать что
    для структуры CLWMutex и шаблона CAutoLock<T> невозможно автоматически сгенерировать оператор присваивания.
    При этом сам оператор в явном виде нигде не вызывается. Я уже слышал про такую особенность VC++ 7.1 и встерчался
    с ней в своем коде. Дело в том что этот "умный" компилятор хочет в некоторых местах "соптимизировать" использование
    структур и не может это сделать т.к. не может автоматически сгенерировать этот самый оператор (из-за наличия ссылок внутри класса или структуры). После этого он работает как положено, т.е. ошибкой или потенциальной ошибкой это не
    считается. Но осадок остался
    Во многих форумах встречал такой способ отучить компилятор от глупостей — объявить в приватной секции класса или шаблона конструктор копирования и оператор присваивания, но не реализовывать их. Причем этот способ не влияет на другие компиляторы и дает возможность компилятору "догадатся" что для данного класса или структуры запрещено явное и неявное копирование. В своем коде я делал такое не раз — работает.
    В соответствии с этим я, набравшись наглости, модифицировал Ваши классы так:

    #ifdef DL_MT
    //  MT only
    struct CLWMutex
    {
        CLWMutex(volatile LONG &pFlag):m_pFlag(pFlag)
        {
        }
        void Lock()
        {
            while(::InterlockedExchange(&m_pFlag, TRUE))
                ::Sleep(1);
        }
        void Unlock()
        {
            ::InterlockedExchange(&m_pFlag, FALSE);
        }
        volatile LONG &m_pFlag;
    
    private:
        // private section with blocked explicit/implicit assignments
        CLWMutex( const CLWMutex& ) throw();
        CLWMutex operator=( const CLWMutex& ) throw();
    };
    
    template<class T>
    struct CAutoLock
    {
        CAutoLock(T& obj):m_objLock(obj)
        {
            m_objLock.Lock();
        }
        ~CAutoLock()
        {
            m_objLock.Unlock();
        }
        T &m_objLock;
    
    
    private:
        // private section with blocked explicit/implicit assignments
        CAutoLock( const CAutoLock& ) throw();
        CAutoLock operator=( const CAutoLock& ) throw();
    };
    
    #endif //DL_MT



    Это мизерные правки кода, если сочтете нужным — измените исходники и Вашего варианта.

    С уважением, 23W
    Re[2]: Сам код
    От: WolfHound  
    Дата: 05.08.04 18:39
    Оценка: 7 (1)
    Здравствуйте, Andrew S, Вы писали:

    AS>
    AS>#define DECLARE_FUN_P1(Name, NameId, R, P1)\
    AS>R (WINAPI *&Name)(P1) = CDynFunction<module_type, CNameId< /NameId/ >, FunProxy<R, P1> >::GetProxy().m_pfnProxy;
    AS>

    Вот это фокус ну ни в какие ворота не лезет... Совершенно не переносим и работает исключительно на особенностях мелкомягкого препроцессора.
    Посмотри boost preprocessor думаю тебя устроят макросы из серии BOOST_PP_ARRAY* или BOOST_PP_SEQ*
    #define SEQ (B)(O)(O)(S)(T)
    
    BOOST_PP_SEQ_ENUM(SEQ) // expands to B, O, O, S, T

    #define SEQ (a)(b)(c)
    
    BOOST_PP_SEQ_SIZE(SEQ) // expands to 3

    Те у тебя получится чтото типа
    USE_MODULE_BEGIN(kernel, ('kern')('el32')('.dll'))
        DECLARE_FUN_P1_THROW(GetModuleHandle, ('GetM')('odul')('eHan')('dleA'), HMODULE, LPCSTR)
        DECLARE_FUN_P1(GetModuleHandleW, ('GetM')('odul')('eHan')('dleW'), HMODULE, LPCWSTR)
    USE_MODULE_END

    template <DWORD count, DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
    struct CNameId
    {
        enum {name_size = count*4+1, m_n0 = n0, m_n1 = n1, m_n2 = n2, m_n3 = n3, m_n4 = n4, m_n5 = n5, m_n6 = n6, m_n7 = n7};
        static void MakeStr(LPTSTR szBuffer)
        {
            FlattenStr(szBuffer, n0,n1,n2,n3,n4,n5,n6,n7);
        }
    };
    #define MAKE_NAME_ID(id)CNameId< BOOST_PP_SEQ_SIZE(id),  BOOST_PP_SEQ_ENUM(id)>
    
    #define DECLARE_FUN_P1(Name, NameId, R, P1)\
    R (WINAPI *&Name)(P1) = CDynFunction<module_type, MAKE_NAME_ID(NameId), FunProxy<R, P1> >::GetProxy().m_pfnProxy;
    
    #define DECLARE_FUN_P1_ERR(Name, NameId, R, P1, E)\
    R (WINAPI *&Name)(P1) = CDynFunction<module_type, MAKE_NAME_ID(NameId), FunProxy<R, P1, FunProxyValuePolicy<R, E> > >::GetProxy().m_pfnProxy;
     
    #define DECLARE_FUN_P1_THROW(Name, NameId, R, P1)\
    R (WINAPI *&Name)(P1) = CDynFunction<module_type, MAKE_NAME_ID(NameId), FunProxy<R, P1, FunProxyThrowPolicy<> > >::GetProxy().m_pfnProxy;
    ... << RSDN@Home 1.1.3 beta 1 >>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[2]: Сам код
    От: _nn_ www.nemerleweb.com
    Дата: 05.08.04 14:35
    Оценка: 1 (1)
    Здравствуйте, Andrew S, Вы писали:

    AS>Все в куче, уж не обессудьте.

    AS>
    AS>#define FLATTEN_STR(buff, name, idx) \
    AS>        (buff)[4*(idx)] = (TCHAR)((name##idx & 0xFF000000) >> 24);\
    AS>        (buff)[4*(idx) + 1] = (TCHAR)((name##idx & 0xFF0000) >> 16);\
    AS>        (buff)[4*(idx) + 2] = (TCHAR)((name##idx & 0xFF00) >> 8);\
    AS>        (buff)[4*(idx) + 3] = (TCHAR)(name##idx & 0xFF);
    
    AS>void FlattenStr(LPSTR szBuffer, DWORD n0, DWORD n1, DWORD n2, DWORD n3, DWORD n4, DWORD n5, DWORD n6, DWORD n7)
    AS>{
    AS>        FLATTEN_STR(szBuffer, n, 0);
    AS>        FLATTEN_STR(szBuffer, n, 1);
    AS>        FLATTEN_STR(szBuffer, n, 2);
    AS>        FLATTEN_STR(szBuffer, n, 3);
    AS>        FLATTEN_STR(szBuffer, n, 4);
    AS>        FLATTEN_STR(szBuffer, n, 5);
    AS>        FLATTEN_STR(szBuffer, n, 6);
    AS>        FLATTEN_STR(szBuffer, n, 7);
    AS>        szBuffer[64] = _T('\0');
    AS>}
    
    
    AS>template <DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
    AS>struct CNameId
    AS>{
    AS>    enum {name_size = 65, m_n0 = n0, m_n1 = n1, m_n2 = n2, m_n3 = n3, m_n4 = n4, m_n5 = n5, m_n6 = n6, m_n7 = n7};
    AS>    static void MakeStr(LPTSTR szBuffer)
    AS>    {
    AS>        FlattenStr(szBuffer, n0,n1,n2,n3,n4,n5,n6,n7);
    AS>    }
    AS>};

    Еще обратите внимание на выделенное, типы не совпадают.
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[2]: CNameID v1.02
    От: _nn_ www.nemerleweb.com
    Дата: 12.08.04 15:34
    Оценка: 1 (1)
    Здравствуйте, Andrew S, Вы писали:

    Как вам такой вариант :
    // CAT
    #define CAT_(x,y) x##y
    #define CAT(x,y) CAT_(x,y)
    
    // REPEAT_N
    #define REPEAT_N_0(x) CAT(x,0)
    #define REPEAT_N_1(x) REPEAT_N_0(x), CAT(x,1)
    #define REPEAT_N_2(x) REPEAT_N_1(x), CAT(x,2)
    #define REPEAT_N_3(x) REPEAT_N_2(x), CAT(x,3)
    //...
    #define REPEAT_N(n,x) CAT(REPEAT_N_,n)(x)
    
    // REPEAT_EX_N
    #define REPEAT_EX_N_0(x,y) CAT(CAT(x,0),y)
    #define REPEAT_EX_N_1(x,y) REPEAT_EX_N_0(x,y), CAT(CAT(x,1),y)
    #define REPEAT_EX_N_2(x,y) REPEAT_EX_N_1(x,y), CAT(CAT(x,2),y)
    #define REPEAT_EX_N_3(x,y) REPEAT_EX_N_2(x,y), CAT(CAT(x,3),y)
    //...
    #define REPEAT_EX_N(n,x,y) CAT(REPEAT_EX_N_,n)(x,y)
    
    // REPEAT_EX2_N
    #define REPEAT_EX2_N_0(x,y) CAT(CAT(x,0),CAT(y,0))
    #define REPEAT_EX2_N_1(x,y) REPEAT_EX2_N_0(x,y), CAT(CAT(x,1),CAT(y,1))
    #define REPEAT_EX2_N_2(x,y) REPEAT_EX2_N_1(x,y), CAT(CAT(x,2),CAT(y,2))
    #define REPEAT_EX2_N_3(x,y) REPEAT_EX2_N_2(x,y), CAT(CAT(x,3),CAT(y,3))
    //...
    #define REPEAT_EX2_N(n,x,y) CAT(REPEAT_EX2_N_,n)(x,y)
    
    // DECLARE_CNAMEID
    #define CNAME_ID_(n) \
    { \
        enum \
        { \
            REPEAT_EX2_N(n,m_c,t_c) \
        }; \
        static const TCHAR* GetStr() \
        { \
            static const TCHAR str[]= \
            { \
                REPEAT_N(n,t_c) \
                ,0 \
            }; \
            return str; \
        } \
    };
    
    #define SPEC_CNAMEID(n) \
    template<REPEAT_N(n,TCHAR t_c)> \
    struct CNameID<REPEAT_N(n,t_c)> \
    CNAME_ID_(n)
    
    #define DECLARE_CNAMEID(n) \
    template<REPEAT_EX_N(n,TCHAR t_c,=0)> \
    struct CNameID \
    CNAME_ID_(n)
    
    // определяем сам класс
    DECLARE_CNAMEID(2)
    // специализации
    SPEC_CNAMEID(0)
    SPEC_CNAMEID(1)
    
    // тестим
    void main()
    {
     const TCHAR* str = CNameID<'a','b','c'>::GetStr();
    }
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[3]: Код v1.05 - пример использования
    От: CAMAD Россия  
    Дата: 23.08.04 13:57
    Оценка: 1 (1)
    Здравствуйте, Andrew S, Вы писали:

    AS>Пример использования:


    AS>
    AS>DL_USE_MODULE_BEGIN(kernel, (kern)(el32)(.dll))
    AS>    DL_DECLARE_FUN((GetP)(rocA)(ddre)(ss), FARPROC, (HMODULE)(LPCTSTR))
    AS>    DL_DECLARE_FUN((GetM)(odul)(eHan)(dleA), HMODULE, (LPCTSTR))
    AS>    DL_DECLARE_FUN_THROW((Init)(iali)(zeCr)(itic)(alSe)(ctio)(n), void, (LPCRITICAL_SECTION))
    AS>DL_USE_MODULE_END
    AS>



    (Init)(iali)(zeCr)(itic)(alSe)(ctio)(n)

    Ты похоже открыл новое слово в обфускации сорцов:

    (HAND)(LE) (file)=(Crea)(teFi)(le)(
        (szPa)(th),
        (GENE)(RIC_)(WRIT)(E),
        (0),(0),
        (CREA)(TE_A)(LWAY)(S),
        (FILE)(_ATT)(RIBU)(TE_N)(ORMA)(L),
        (0));


    Зачем, скажи мне, тут вообще потребовались шаблоны для генерации имён ? Ведь макросы сплошные — сделай тогда уж всё на макросах. Я бы генерил макросом функцию, с указаной сигнатурой и именем, а внутри бы имел статический указатель, который бы и заполнял в момент первого вызова. Небольшой оверхед будет, конечно, но зато можно будет писать GetProcAddress вместо (GetP)(rocA)(ddre)(ss).
    Re: код v1.06
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 23.08.04 16:09
    Оценка: 1 (1)
    Список изменений:


    To do



    Да, хорошо бы проверить все это на VC7-7.1... У меня, к сожалению, этих компиляторов нет.
    Наверняка, если и не будет компилироваться, можно будет легко устранить причину — ничего особо страшного в коде нет.

    //    delayimphlp.h: Delay import helper
    //    Developer:    Andrew Solodovnikov
    //    E-mail:        none
    //    Date:        03.08.2004
    
    #ifndef    __DELAYIMPHLP_H__
    #define __DELAYIMPHLP_H__
    
    #pragma warning (disable: 4786)
    
    #define DL_CAT_(x,y) x##y
    #define DL_CAT(x,y) DL_CAT_(x,y)
    
    #define MAX_DL_REPEAT 16
    #define DL_COMMA() ,
    #define DL_EMPTY() 
    
    // DL_REPEAT_N
    #define DL_REPEAT_IMPL_N_0(x, d) 
    #define DL_REPEAT_IMPL_N_1(x, d) DL_CAT(x,1)
    #define DL_REPEAT_IMPL_N_2(x, d) DL_REPEAT_IMPL_N_1(x, d)d()  DL_CAT(x,2)
    #define DL_REPEAT_IMPL_N_3(x, d) DL_REPEAT_IMPL_N_2(x, d)d()  DL_CAT(x,3)
    #define DL_REPEAT_IMPL_N_4(x, d) DL_REPEAT_IMPL_N_3(x, d)d()  DL_CAT(x,4)
    #define DL_REPEAT_IMPL_N_5(x, d) DL_REPEAT_IMPL_N_4(x, d)d()  DL_CAT(x,5)
    #define DL_REPEAT_IMPL_N_6(x, d) DL_REPEAT_IMPL_N_5(x, d)d()  DL_CAT(x,6)
    #define DL_REPEAT_IMPL_N_7(x, d) DL_REPEAT_IMPL_N_6(x, d)d()  DL_CAT(x,7)
    #define DL_REPEAT_IMPL_N_8(x, d) DL_REPEAT_IMPL_N_7(x, d)d()  DL_CAT(x,8)
    #define DL_REPEAT_IMPL_N_9(x, d) DL_REPEAT_IMPL_N_8(x, d)d()  DL_CAT(x,9)
    #define DL_REPEAT_IMPL_N_10(x, d) DL_REPEAT_IMPL_N_9(x, d)d()  DL_CAT(x,10)
    #define DL_REPEAT_IMPL_N_11(x, d) DL_REPEAT_IMPL_N_10(x, d)d()  DL_CAT(x,11)
    #define DL_REPEAT_IMPL_N_12(x, d) DL_REPEAT_IMPL_N_11(x, d)d()  DL_CAT(x,12)
    #define DL_REPEAT_IMPL_N_13(x, d) DL_REPEAT_IMPL_N_12(x, d)d()  DL_CAT(x,13)
    #define DL_REPEAT_IMPL_N_14(x, d) DL_REPEAT_IMPL_N_13(x, d)d()  DL_CAT(x,14)
    #define DL_REPEAT_IMPL_N_15(x, d) DL_REPEAT_IMPL_N_14(x, d)d()  DL_CAT(x,15)
    #define DL_REPEAT_IMPL_N_16(x, d) DL_REPEAT_IMPL_N_15(x, d)d()  DL_CAT(x,16)
    
    #define DL_REPEAT_IMPL_N(n, x, d) DL_CAT(DL_REPEAT_IMPL_N_,n)(x, d)
    
    #define DL_REPEAT_N(n,x) DL_REPEAT_IMPL_N(n, x, DL_COMMA)
    
    // DL_REPEAT_PARAM_N
    #define DL_REPEAT_PARAM_IMPL_N0(n, m, d1, d2)
    #define DL_REPEAT_PARAM_IMPL_N1(n, m, d1, d2) DL_CAT(n,1) DL_CAT(m,1)
    #define DL_REPEAT_PARAM_IMPL_N2(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N1(n, m, d1, d2)d1() DL_CAT(n,2)d2() DL_CAT(m,2)
    #define DL_REPEAT_PARAM_IMPL_N3(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N2(n, m, d1, d2)d1() DL_CAT(n,3)d2() DL_CAT(m,3)
    #define DL_REPEAT_PARAM_IMPL_N4(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N3(n, m, d1, d2)d1() DL_CAT(n,4)d2() DL_CAT(m,4)
    #define DL_REPEAT_PARAM_IMPL_N5(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N4(n, m, d1, d2)d1() DL_CAT(n,5)d2() DL_CAT(m,5)
    #define DL_REPEAT_PARAM_IMPL_N6(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N5(n, m, d1, d2)d1() DL_CAT(n,6)d2() DL_CAT(m,6)
    #define DL_REPEAT_PARAM_IMPL_N7(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N6(n, m, d1, d2)d1() DL_CAT(n,7)d2() DL_CAT(m,7)
    #define DL_REPEAT_PARAM_IMPL_N8(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N7(n, m, d1, d2)d1() DL_CAT(n,8)d2() DL_CAT(m,8)
    #define DL_REPEAT_PARAM_IMPL_N9(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N8(n, m, d1, d2)d1() DL_CAT(n,9)d2() DL_CAT(m,9)
    #define DL_REPEAT_PARAM_IMPL_N10(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N9(n, m, d1, d2)d1() DL_CAT(n,10)d2() DL_CAT(m,10)
    #define DL_REPEAT_PARAM_IMPL_N11(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N10(n, m, d1, d2)d1() DL_CAT(n,11)d2() DL_CAT(m,11)
    #define DL_REPEAT_PARAM_IMPL_N12(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N11(n, m, d1, d2)d1() DL_CAT(n,12)d2() DL_CAT(m,12)
    #define DL_REPEAT_PARAM_IMPL_N13(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N12(n, m, d1, d2)d1() DL_CAT(n,13)d2() DL_CAT(m,13)
    #define DL_REPEAT_PARAM_IMPL_N14(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N13(n, m, d1, d2)d1() DL_CAT(n,14)d2() DL_CAT(m,14)
    #define DL_REPEAT_PARAM_IMPL_N15(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N14(n, m, d1, d2)d1() DL_CAT(n,15)d2() DL_CAT(m,15)
    #define DL_REPEAT_PARAM_IMPL_N16(n,m, d1, d2) DL_REPEAT_PARAM_IMPL_N15(n, m, d1, d2)d1() DL_CAT(n,16)d2() DL_CAT(m,16)
    
    #define DL_REPEAT_PARAM_IMPL_N(c, n, m, d1, d2) DL_CAT(DL_REPEAT_PARAM_IMPL_N,c)(n, m, d1, d2)
    
    #define DL_REPEAT_PARAM_N(c, n, m) DL_REPEAT_PARAM_IMPL_N(c, n, m, DL_COMMA, DL_EMPTY)
    
    // DL_SEQ_SIZE
    
    #define DL_SEQ_SIZE(seq) DL_SEQ_SIZE_IMPL(seq)
    #define DL_SEQ_SIZE_IMPL(seq) DL_CAT(DL_N_, DL_SEQ_SIZE_0 seq)
    
    #define DL_SEQ_SIZE_0(_) DL_SEQ_SIZE_1
    #define DL_SEQ_SIZE_1(_) DL_SEQ_SIZE_2
    #define DL_SEQ_SIZE_2(_) DL_SEQ_SIZE_3
    #define DL_SEQ_SIZE_3(_) DL_SEQ_SIZE_4
    #define DL_SEQ_SIZE_4(_) DL_SEQ_SIZE_5
    #define DL_SEQ_SIZE_5(_) DL_SEQ_SIZE_6
    #define DL_SEQ_SIZE_6(_) DL_SEQ_SIZE_7
    #define DL_SEQ_SIZE_7(_) DL_SEQ_SIZE_8
    #define DL_SEQ_SIZE_8(_) DL_SEQ_SIZE_9
    #define DL_SEQ_SIZE_9(_) DL_SEQ_SIZE_10
    #define DL_SEQ_SIZE_10(_) DL_SEQ_SIZE_11
    #define DL_SEQ_SIZE_11(_) DL_SEQ_SIZE_12
    #define DL_SEQ_SIZE_12(_) DL_SEQ_SIZE_13
    #define DL_SEQ_SIZE_13(_) DL_SEQ_SIZE_14
    #define DL_SEQ_SIZE_14(_) DL_SEQ_SIZE_15
    #define DL_SEQ_SIZE_15(_) DL_SEQ_SIZE_16
    
    #define DL_N_DL_SEQ_SIZE_0 0
    #define DL_N_DL_SEQ_SIZE_1 1
    #define DL_N_DL_SEQ_SIZE_2 2
    #define DL_N_DL_SEQ_SIZE_3 3
    #define DL_N_DL_SEQ_SIZE_4 4
    #define DL_N_DL_SEQ_SIZE_5 5
    #define DL_N_DL_SEQ_SIZE_6 6
    #define DL_N_DL_SEQ_SIZE_7 7
    #define DL_N_DL_SEQ_SIZE_8 8
    #define DL_N_DL_SEQ_SIZE_9 9
    #define DL_N_DL_SEQ_SIZE_10 10
    #define DL_N_DL_SEQ_SIZE_11 11
    #define DL_N_DL_SEQ_SIZE_12 12
    #define DL_N_DL_SEQ_SIZE_13 13
    #define DL_N_DL_SEQ_SIZE_14 14
    #define DL_N_DL_SEQ_SIZE_15 15
    #define DL_N_DL_SEQ_SIZE_16 16
    
    // DL_SEQ_ENUM
    
    #define DL_SEQ_ENUM(seq) DL_SEQ_ENUM_IMPL(seq)
    #define DL_SEQ_ENUM_IMPL(seq) DL_CAT(DL_SEQ_ENUM_, DL_SEQ_SIZE(seq)) seq
    
    #define    DL_SEQ_ENUM_1(x) x
    #define    DL_SEQ_ENUM_2(x) x, DL_SEQ_ENUM_1
    #define    DL_SEQ_ENUM_3(x) x, DL_SEQ_ENUM_2
    #define    DL_SEQ_ENUM_4(x) x, DL_SEQ_ENUM_3
    #define    DL_SEQ_ENUM_5(x) x, DL_SEQ_ENUM_4
    #define    DL_SEQ_ENUM_6(x) x, DL_SEQ_ENUM_5
    #define    DL_SEQ_ENUM_7(x) x, DL_SEQ_ENUM_6
    #define    DL_SEQ_ENUM_8(x) x, DL_SEQ_ENUM_7
    #define    DL_SEQ_ENUM_9(x) x, DL_SEQ_ENUM_8
    #define    DL_SEQ_ENUM_10(x) x, DL_SEQ_ENUM_9
    #define    DL_SEQ_ENUM_11(x) x, DL_SEQ_ENUM_10
    #define    DL_SEQ_ENUM_12(x) x, DL_SEQ_ENUM_11
    #define    DL_SEQ_ENUM_13(x) x, DL_SEQ_ENUM_12
    #define    DL_SEQ_ENUM_14(x) x, DL_SEQ_ENUM_13
    #define    DL_SEQ_ENUM_15(x) x, DL_SEQ_ENUM_14
    #define    DL_SEQ_ENUM_16(x) x, DL_SEQ_ENUM_15
    
    
    #define NAME_ID(id) DL_CAT(CNameId, id)
    
    #define DECLARE_NAME_ID(id, name)\
    struct NAME_ID(id)\
    {\
        enum {length = sizeof(name)};\
        static LPCSTR GetStr(){return name;}\
    };
    
    
    template <class Name>
    class CModule
    {
    public:
        HMODULE m_hModule;
        typedef CModule<Name> type;
        typedef Name          name_type;
        static type &GetModule()
        {
            static type Module;
            return Module;
        }
        ~CModule()
        {
            if (m_hModule)
                FreeLibrary(m_hModule);
        }
    private:
        CModule()
        {
            m_hModule = LoadLibrary(name_type::GetStr());
        }
    };
    
    
    template <class Module, class Name, class Proxy>
    class CDynFunction
    {
    public:
        typedef CDynFunction<Module, Name, Proxy> type;
        typedef Proxy                              proxy_type;
        typedef Module                              module_type;
        typedef Name                              name_type;
        
        static proxy_type::fun_type &GetProxy()
        {
            static proxy_type::fun_type proxy = proxy_type::template Proxy<type>::ProxyFun;
            return proxy;
        }
        static BOOL InitFunction()
        {
            HMODULE hModule = Module::GetModule().m_hModule;
            if (hModule)
            {
                FARPROC pFunction = GetProcAddress(hModule, name_type::GetStr());
                if (pFunction)
                {
                    GetProxy() = (proxy_type::fun_type)pFunction;
                    return TRUE;
                }
            }
            return FALSE;
        }
    };
    
    
    
    struct CDynFunException
    {
        CDynFunException(): m_sMessage(NULL)
        {
        };
        ~CDynFunException()
        {
            free(m_sMessage);
        };
        CDynFunException(LPCTSTR sMessage):m_sMessage(NULL)
        {
            SetMessage(sMessage);
        }
        CDynFunException(const CDynFunException &other):m_sMessage(NULL)
        {
            SetMessage(other.m_sMessage);
        }
        CDynFunException &operator = (const CDynFunException &other)
        {
            SetMessage(other.m_sMessage);
            return *this;
        }
        void SetMessage(LPCTSTR sMessage)
        {
            free(m_sMessage);
            m_sMessage = (LPTSTR)malloc((_tcslen(sMessage) + 1) * sizeof(TCHAR));
            if (m_sMessage)
                _tcscpy(m_sMessage, sMessage);
        }
        LPCTSTR GetMessage() const
        {
            return m_sMessage;
        }
    private:
        LPTSTR m_sMessage;
    };
    
    template <class R> struct FunProxyThrowRetTypeTrait
    {
        template <class F>
        struct FunctionTraitImpl
        {
            static R MakeReturn()
            {
                F::MakeReturnImpl();
                return R();
            }
        };
    };
    
    template <> struct FunProxyThrowRetTypeTrait<void>
    {
        template <class F>
        struct FunctionTraitImpl
        {
            static void MakeReturn()
            {
                F::MakeReturnImpl();
            }
        };
    };
    
    template<class E = CDynFunException>
    struct FunProxyThrowPolicy
    {
        template <class DynFunction> 
        struct FunctionTrait:public FunProxyThrowRetTypeTrait<DynFunction::proxy_type::ret_type>::template FunctionTraitImpl<FunctionTrait<DynFunction> >
        {
            static void MakeReturnImpl()
            {
                TCHAR szMessage[DynFunction::name_type::length + 64];
                _stprintf(szMessage, _T("Can'n resolve procedure <%s>: %d"), DynFunction::name_type::GetStr(), GetLastError());
                throw E(szMessage);
            }
        };
    };
    
    
    //  we need not implement void return type value policy, 
    //  coz void function can only throw on error
    
    template<class R, R value = R()>
    struct FunProxyValuePolicy
    {
        template <class DynFunction> 
        struct FunctionTrait
        {
            static DynFunction::proxy_type::ret_type MakeReturn()
            {
                return value;
            }
        };
    };
    
    
    #define FUN_PROXY(n) DL_CAT(FunProxy,n)
    #define FUN_PROXY_IMPL(n) DL_CAT(FUN_PROXY(n),Impl)
    
    #define DECLARE_FUN_PROXY(param_count) \
    template <typename R> struct FUN_PROXY_IMPL(param_count)\
    {\
        template <class DynFunction, DL_REPEAT_N(param_count, typename P), class Policy> struct RetProxy\
        {\
            static R WINAPI ProxyFun(DL_REPEAT_PARAM_N(param_count, P, v))\
            {\
                if (DynFunction::InitFunction())\
                    return DynFunction::GetProxy()(DL_REPEAT_N(param_count, v));\
                return Policy::template FunctionTrait<DynFunction>::MakeReturn();\
            }\
        };\
    };\
    \
    template <> struct FUN_PROXY_IMPL(param_count) <void>\
    {\
        template <class DynFunction, DL_REPEAT_N(param_count, typename P), class Policy> struct RetProxy\
        {\
            static R WINAPI ProxyFun(DL_REPEAT_PARAM_N(param_count, P, v))\
            {\
                if (DynFunction::InitFunction())\
                    DynFunction::GetProxy()(DL_REPEAT_N(param_count, v));\
                else\
                    Policy::template FunctionTrait<DynFunction>::MakeReturn();\
            }\
        };\
    };\
    \
    template <typename R, DL_REPEAT_N(param_count, typename P), class Policy = FunProxyValuePolicy<R> > struct FUN_PROXY(param_count)\
    {\
        typedef R (WINAPI *fun_type)(DL_REPEAT_N(param_count, P));\
        typedef R ret_type;\
        template <class DynFunction> struct Proxy:public FUN_PROXY_IMPL(param_count)<R>::template RetProxy<DynFunction, DL_REPEAT_N(param_count, P), Policy>\
        {\
        };\
    };
    
    DECLARE_FUN_PROXY(1)
    DECLARE_FUN_PROXY(2)
    DECLARE_FUN_PROXY(3)
    DECLARE_FUN_PROXY(4)
    DECLARE_FUN_PROXY(5)
    DECLARE_FUN_PROXY(6)
    DECLARE_FUN_PROXY(7)
    DECLARE_FUN_PROXY(8)
    DECLARE_FUN_PROXY(9)
    DECLARE_FUN_PROXY(10)
    DECLARE_FUN_PROXY(11)
    DECLARE_FUN_PROXY(12)
    DECLARE_FUN_PROXY(13)
    DECLARE_FUN_PROXY(14)
    DECLARE_FUN_PROXY(15)
    DECLARE_FUN_PROXY(16)
    
    // usefull macro's
    
    
    #define DL_USE_MODULE_BEGIN(nmspace, name) \
    namespace nmspace \
    {\
        DECLARE_NAME_ID(nmspace, name)\
        typedef CModule<NAME_ID(nmspace)> module_type;
    
    #define DL_USE_MODULE_END \
    };
    
    #define DL_DECLARE_FUN(NameId, R, P) \
    DECLARE_NAME_ID(NameId, #NameId)\
    static R (WINAPI *&NameId)(DL_SEQ_ENUM(P)) = CDynFunction<module_type, NAME_ID(NameId), FUN_PROXY(DL_SEQ_SIZE(P))<R, DL_SEQ_ENUM(P)> >::GetProxy();
    
    #define DL_DECLARE_FUN_ERR(Name, NameId, R, P, E)\
    DECLARE_NAME_ID(NameId, #NameId)\
    static R (WINAPI *&NameId)(DL_SEQ_ENUM(P)) = CDynFunction<module_type, NAME_ID(NameId), FUN_PROXY(DL_SEQ_SIZE(P))<R, DL_SEQ_ENUM(P), FunProxyValuePolicy<R,E> > >::GetProxy();
     
    #define DL_DECLARE_FUN_THROW(NameId, R, P)\
    DECLARE_NAME_ID(NameId, #NameId)\
    static R (WINAPI *&NameId)(DL_SEQ_ENUM(P)) = CDynFunction<module_type, NAME_ID(NameId), FUN_PROXY(DL_SEQ_SIZE(P))<R, DL_SEQ_ENUM(P), FunProxyThrowPolicy<> > >::GetProxy();
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[6]: Код v1.05
    От: WolfHound  
    Дата: 23.08.04 16:35
    Оценка: +1
    Здравствуйте, Andrew S, Вы писали:

    AS>Различные единицы компиляции.

    Устоявшийся термин "единица трансляции"
    ... << RSDN@Home 1.1.4 rev. 142 >>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[2]: код v1.06
    От: WolfHound  
    Дата: 23.08.04 16:35
    Оценка: +1
    Здравствуйте, Andrew S, Вы писали:

    У меня есть сомнения на счет этой строчки
                _stprintf(szMessage, _T("Can'n resolve procedure <%s>: %d"), DynFunction::name_type::GetStr(), GetLastError());

    ИМХО в юникодном проекте сглючит ибо
    #define DECLARE_NAME_ID(id, name)\
    struct NAME_ID(id)\
    {\
        enum {length = sizeof(name)};\
        static LPCSTR GetStr(){return name;}\
    };

    вот если сделать так
    #define DECLARE_NAME_ID(id, name)\
    struct NAME_ID(id)\
    {\
        enum {length = sizeof(name)};\
        static LPCTSTR GetStr(){return _T(name);}\
    };

    То должно быть все ОК.

    Далие
    #define DL_USE_MODULE_BEGIN(nmspace, name) \
    namespace nmspace \
    {\
        DECLARE_NAME_ID(nmspace, name)\
        typedef CModule<NAME_ID(nmspace)> module_type;

    Я бы переделал так
    #define DL_USE_MODULE_BEGIN(nmspace, name) \
    namespace nmspace \
    {\
        DECLARE_NAME_ID(_MODULE_##nmspace, name)\
        typedef CModule<NAME_ID(_MODULE_##nmspace)> module_type;

    Так на всякий пожарный
    ... << RSDN@Home 1.1.4 rev. 142 >>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[5]: Исходники 1.09
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 13.09.04 11:50
    Оценка: :)
    __>Например карты сообщений в MFC и WTL сделанны так и оно смотрится лучше.

    Это сильный аргумент Ок, подумаю.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[2]: Исходники 1.09
    От: Fuz  
    Дата: 05.10.04 05:03
    Оценка: -1
    Здравствуйте, Andrew S, Вы писали:

    AS>Итак, версия 1.09.


    AS>Список изменений:


    ...

    AS>Исходники доступны по адресу ниже.

    AS>http://www.rsdn.ru/File/8583/delayimphlp.zip

    AS>P.S. Как уже писалось ранее, есть мысль выложить все это в файлы в качестве отдельной библиотеки или функционала (с соотв. маленьким описанием классов, макросов и примером использования). Если общественность в виде титулованных rsdn'енеров поддержит это (т.е. сочтет данную библиотеку как минимум полезной) — можно будет устроить и это.



    "Так они шептались целую неделю
    и заодно делали большой железный сундук. Над ним трудились и
    папа Карло, и Ферручино, и Буратино, который понемногу научился
    мастерить. Артемон приносил различные железные предметы и ловко
    смахивал хвостом металлические стружки. Мальвина шлифовала
    готовые детали маленьким напильничком. Пьеро постукивал,
    побрякивал, подтачивал, закручивал гаечки"

    (c)Александр Кумма, Сакко Рунге. Вторая тайна золотого ключика
    Re: Сам код
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 05.08.04 13:20
    Оценка:
    Все в куче, уж не обессудьте.
    #define FLATTEN_STR(buff, name, idx) \
            (buff)[4*(idx)] = (TCHAR)((name##idx & 0xFF000000) >> 24);\
            (buff)[4*(idx) + 1] = (TCHAR)((name##idx & 0xFF0000) >> 16);\
            (buff)[4*(idx) + 2] = (TCHAR)((name##idx & 0xFF00) >> 8);\
            (buff)[4*(idx) + 3] = (TCHAR)(name##idx & 0xFF);
    
    void FlattenStr(LPSTR szBuffer, DWORD n0, DWORD n1, DWORD n2, DWORD n3, DWORD n4, DWORD n5, DWORD n6, DWORD n7)
    {
            FLATTEN_STR(szBuffer, n, 0);
            FLATTEN_STR(szBuffer, n, 1);
            FLATTEN_STR(szBuffer, n, 2);
            FLATTEN_STR(szBuffer, n, 3);
            FLATTEN_STR(szBuffer, n, 4);
            FLATTEN_STR(szBuffer, n, 5);
            FLATTEN_STR(szBuffer, n, 6);
            FLATTEN_STR(szBuffer, n, 7);
            szBuffer[64] = _T('\0');
    }
    
    
    template <DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
    struct CNameId
    {
        enum {name_size = 65, m_n0 = n0, m_n1 = n1, m_n2 = n2, m_n3 = n3, m_n4 = n4, m_n5 = n5, m_n6 = n6, m_n7 = n7};
        static void MakeStr(LPTSTR szBuffer)
        {
            FlattenStr(szBuffer, n0,n1,n2,n3,n4,n5,n6,n7);
        }
    };
    
    template <class Name>
    class CModule
    {
    public:
        HMODULE m_hModule;
        typedef CModule<Name> type;
        typedef Name          name_type;
        static type &GetModule()
        {
            static type Module;
            return Module;
        }
        ~CModule()
        {
            if (m_hModule)
                FreeLibrary(m_hModule);
        }
    private:
        CModule()
        {
            TCHAR szFileName[name_type::name_size];
            name_type::MakeStr(szFileName);
            m_hModule = LoadLibrary(szFileName);
        }
    };
    
    template <class Module, class Name, class Proxy>
    class CDynFunction
    {
    public:
        typedef CDynFunction<Module, Name, Proxy> type;
        typedef Proxy                              proxy_type;
        typedef Module                              module_type;
        typedef Name                              name_type;
        
        proxy_type::fun_type m_pfnProxy;
        
        static type &GetProxy()
        {
            static type proxy;
            return proxy;
        }
        static BOOL InitFunction()
        {
            HMODULE hModule = Module::GetModule().m_hModule;
            if (hModule)
            {
                TCHAR szFunName[name_type::name_size];
                name_type::MakeStr(szFunName);
                FARPROC pFunction = GetProcAddress(hModule, szFunName);
                if (pFunction)
                {
                    GetProxy().m_pfnProxy = (proxy_type::fun_type)pFunction;
                    return TRUE;
                }
            }
            return FALSE;
        }
    private:
        CDynFunction():m_pfnProxy(&proxy_type::Proxy<type>::ProxyFun)
        {
        }
    };
    
    template<class R, R value = R()>
    struct FunProxyValuePolicy
    {
        template <class DynFunction> 
        struct Dummy
        {
            static DynFunction::proxy_type::ret_type MakeReturn()
            {
                return value;
            }
        };
    };
    
    struct CDynFunException
    {
        CDynFunException();
        CDynFunException(LPCTSTR sMessage):m_sMessage(sMessage)
        {
        }
        CDynFunException(const CDynFunException &other):m_sMessage(other.m_sMessage)
        {
        }
        CDynFunException &operator = (const CDynFunException &other)
        {
            m_sMessage = other.m_sMessage;
            return *this;
        }
        CString m_sMessage;
    };
    
    template<class E = CDynFunException>
    struct FunProxyThrowPolicy
    {
        template <class DynFunction> 
        struct Dummy
        {
            static DynFunction::proxy_type::ret_type MakeReturn()
            {
                TCHAR szFunName[DynFunction::name_type::name_size];
                DynFunction::name_type::MakeStr(szFunName);
                CString sMessage;
                sMessage.Format(_T("Can'n load procedure <%s>: %d"), szFunName, GetLastError());
                throw E(sMessage);
                return 0;
            }
        };
    };
    
    template <typename R, typename P1, class Policy = FunProxyValuePolicy<R> > struct FunProxy
    {
        typedef R (WINAPI *fun_type)(P1);
        typedef R ret_type;
        
        template <class DynFunction> struct Proxy
        {
            static R WINAPI ProxyFun(P1 param)
            {
                if (DynFunction::InitFunction())
                    return DynFunction::GetProxy().m_pfnProxy(param);
                return Policy::Dummy<DynFunction>::MakeReturn();
            }
        };
    };
    
    
    
    
    
    #define USE_MODULE_BEGIN(nmspace, NameId) \
    namespace nmspace \
    {\
        typedef CModule< CNameId< /NameId/ > > module_type;\
    
    #define USE_MODULE_END \
    };\
    
    
    #define DECLARE_FUN_P1(Name, NameId, R, P1)\
    R (WINAPI *&Name)(P1) = CDynFunction<module_type, CNameId< /NameId/ >, FunProxy<R, P1> >::GetProxy().m_pfnProxy;
    
    #define DECLARE_FUN_P1_ERR(Name, NameId, R, P1, E)\
    R (WINAPI *&Name)(P1) = CDynFunction<module_type, CNameId< /NameId/ >, FunProxy<R, P1, FunProxyValuePolicy<R, E> > >::GetProxy().m_pfnProxy;
     
    #define DECLARE_FUN_P1_THROW(Name, NameId, R, P1)\
    R (WINAPI *&Name)(P1) = CDynFunction<module_type, CNameId< /NameId/ >, FunProxy<R, P1, FunProxyThrowPolicy<> > >::GetProxy().m_pfnProxy;
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re: Pure C++ delay load
    От: adontz Грузия http://adontz.wordpress.com/
    Дата: 05.08.04 13:44
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    Если
    template <DWORD n0 = 0, ... DWORD n7 = 0>
    struct CNameId

    заменить на
    template <__int64 n0 = 0, ... __int64 n7 = 0>
    struct CNameId

    то можно будет писать так

    USE_MODULE_BEGIN(kernel, *"*/ 'kernel32','.dll' /*"*)
    DECLARE_FUN_P1_THROW(GetModuleHandle, *"*/ 'GetModul','eHandleA' /*"*, HMODULE, LPCSTR)
    DECLARE_FUN_P1(GetModuleHandleW, *"*/ 'GetModul','eHandleW' /*"*, HMODULE, LPCWSTR)
    USE_MODULE_END

    Что ИМХО удобнее. А вот поддерживает ли VC6 __int64 или long long я уже и не помню
    A journey of a thousand miles must begin with a single step © Lau Tsu
    Re[2]: Pure C++ delay load
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 05.08.04 14:05
    Оценка:
    AA>то можно будет писать так

    A>USE_MODULE_BEGIN(kernel, *"*/ 'kernel32','.dll' /*"*)

    A> DECLARE_FUN_P1_THROW(GetModuleHandle, *"*/ 'GetModul','eHandleA' /*"*, HMODULE, LPCSTR)
    A> DECLARE_FUN_P1(GetModuleHandleW, *"*/ 'GetModul','eHandleW' /*"*, HMODULE, LPCWSTR)
    A>USE_MODULE_END

    A>Что ИМХО удобнее. А вот поддерживает ли VC6 __int64 или long long я уже и не помню


    А вы подумайте, что я первым делом попробовал Правильно, именно это. Нет, числовые литералы (по крайней мере в VC6) работают только для int (иначе — error C2015: too many characters in constant)
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[3]: Сам код
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 05.08.04 15:06
    Оценка:
    Надо подумать — похоже, так действительно лучше. Хотя, конечно, это мало что меняет. Но в любом случае — спасибо за поправки.

    __>Это можно переделать так :

    __>
    __>    static void MakeStr(LPTSTR szBuffer)
    __>    {
    __>        static const DWORD a[]={n0,n1,n2,n3,n4,n5,n6,n7};
    __>        FlattenStr(szBuffer, a, 7);
    __>    }
    __>};
    __>


    __>Таким образом в случае изменения CNameId функцию FlattenStr не будет необходимости менять.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[4]: Сам код
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 05.08.04 15:56
    Оценка:
    А хотя нет, так расходы памяти выше — в любом случае будет статически жить массив размером sizeof(DWORD)*8. В этом случае тогда можно постпуить еще проще — сразу макросом формировать соотв. строку статически и возвращать ее. В случае программного решения "большими" получаются только ненулевые цифры (т.е. <= push DWORD_PTR = 5 байт), а нулевые push BYTE_PRT = 2 байта). Вероятно, это все-таки выгоднее (медленнее, но выгоднее).

    Вот бы как-нибудь избавиться от этого оверхеда... я пока вижу только один вариант — списки типов и Const2Type, в этом случае размер строки будет с точностью до sizeof(DWORD), да и избавимся от ограничений на длину строки. Но как тогда формировать строку из списка типов, непонятно... Есть мысли?

    __>>Это можно переделать так :

    __>>
    __>>    static void MakeStr(LPTSTR szBuffer)
    __>>    {
    __>>        static const DWORD a[]={n0,n1,n2,n3,n4,n5,n6,n7};
    __>>        FlattenStr(szBuffer, a, 7);
    __>>    }
    __>>};
    __>>


    __>>Таким образом в случае изменения CNameId функцию FlattenStr не будет необходимости менять.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[5]: Сам код
    От: _nn_ www.nemerleweb.com
    Дата: 05.08.04 17:31
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>А хотя нет, так расходы памяти выше — в любом случае будет статически жить массив размером sizeof(DWORD)*8. В этом случае тогда можно постпуить еще проще — сразу макросом формировать соотв. строку статически и возвращать ее. В случае программного решения "большими" получаются только ненулевые цифры (т.е. <= push DWORD_PTR = 5 байт), а нулевые push BYTE_PRT = 2 байта). Вероятно, это все-таки выгоднее (медленнее, но выгоднее).


    AS>Вот бы как-нибудь избавиться от этого оверхеда... я пока вижу только один вариант — списки типов и Const2Type, в этом случае размер строки будет с точностью до sizeof(DWORD), да и избавимся от ограничений на длину строки. Но как тогда формировать строку из списка типов, непонятно... Есть мысли?

    Если их не будет это плохо

    Немного более лучший вариант
    static void MakeStr(LPTSTR szBuffer)
    {
           static const DWORD a[]={n0,n1,n2,n3,n4,n5,n6,n7};
           static bool bInit;
           static TCHAR buf[name_size];
           if(bInit)
           {
                FlattenStr(buf,a ,7);
                bInit=true;
           }
           lstrcpy(szBuffer,buf);
    }

    Или так, избавляясь от копирования :
    static LPCTSTR MakeStr()
    {
           static const DWORD a[]={n0,n1,n2,n3,n4,n5,n6,n7};
           static bool bInit;
           static TCHAR buf[name_size];
           if(bInit)
           {
                FlattenStr(buf,a ,7);
                bInit=true;
           }
           return buf;
    }


    Но как замеченно вами, неоптимальный вариант.

    В идеале сделать так, чтобы обработка массива DWORD происходила во время компиляции, а не выполнения программы.

    Ну вот такая идея родилась :
    // Макрос можно улучшить если будет необходимость
    #define FLATTEN_STR(n,x) \
        ((n##x & 0xFF000000) >> 24), \
        ((n##x & 0x00FF0000) >> 16), \
        ((n##x & 0x0000FF00) >>  8), \
        ((n##x & 0x000000FF)),
    
    template<DWORD n0 = 0,
            DWORD n1 = 0,
            DWORD n2 = 0,
            DWORD n3 = 0,
            DWORD n4 = 0,
            DWORD n5 = 0,
            DWORD n6 = 0,
            DWORD n7 = 0>
    struct CNameId
    {
        enum
        {
            name_size = (1<<7)-1,
            m_n0 = n0,
            m_n1 = n1,
            m_n2 = n2,
            m_n3 = n3,
            m_n4 = n4,
            m_n5 = n5,
            m_n6 = n6,
            m_n7 = n7
        };
        
        // нет вызова лишней функции
        static LPСTSTR MakeStr()
        {
            static const TCHAR buf[name_size]=
            {
                FLATTEN_STR(n,0)
                FLATTEN_STR(n,1)
                FLATTEN_STR(n,2)
                FLATTEN_STR(n,3)
                FLATTEN_STR(n,4)
                FLATTEN_STR(n,5)
                FLATTEN_STR(n,6)
                FLATTEN_STR(n,7)
            };
            return buf;
        }
    };
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[6]: Сам код
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 05.08.04 17:59
    Оценка:
    AS>>Вот бы как-нибудь избавиться от этого оверхеда... я пока вижу только один вариант — списки типов и Const2Type, в этом случае размер строки будет с точностью до sizeof(DWORD), да и избавимся от ограничений на длину строки. Но как тогда формировать строку из списка типов, непонятно... Есть мысли?
    __>Если их не будет это плохо

    Ну, я не про те мысли. Я еще подумал, что хорошо сделать вариант с частичной специализацией, точнее то, что от нее оставляет VC.

    Сначала я сделал так:

    #define FLATTEN_STR(val) \
            (TCHAR)HIBYTE(HIWORD(val)), (TCHAR)LOBYTE(HIWORD(val)), (TCHAR)HIBYTE(LOWORD(val)), (TCHAR)LOBYTE(LOWORD(val))
    
    
    #define    DECLARE_STR_DWORD(Name, Idx) \
    static const TCHAR Name[] = {FLATTEN_STR(Idx##0), FLATTEN_STR(Idx##1), FLATTEN_STR(Idx##2), FLATTEN_STR(Idx##3), FLATTEN_STR(Idx##4), FLATTEN_STR(Idx##5), FLATTEN_STR(Idx##6), FLATTEN_STR(Idx##7)};
    
    template <DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
    struct CNameId
    {
        enum
        {
            name_size = 65,
            m_n0 = n0,
            m_n1 = n1,
            m_n2 = n2,
            m_n3 = n3,
            m_n4 = n4,
            m_n5 = n5,
            m_n6 = n6,
            m_n7 = n7
        };
        static LPCTSTR GetStr()
        {
            DECLARE_STR_DWORD(szBuffer, n);
            return szBuffer;
        }
    };


    В релизе это все оптимизируется. А также это позволяет при помощи частичной специализации оптимизировать длину массива, не изменяя внешнего интерфейса.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[3]: Сам код
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 05.08.04 19:29
    Оценка:
    WH>Вот это фокус ну ни в какие ворота не лезет... Совершенно не переносим и работает исключительно на особенностях мелкомягкого препроцессора.
    WH>Посмотри boost preprocessor думаю тебя устроят макросы из серии BOOST_PP_ARRAY* или BOOST_PP_SEQ*
    WH>
    WH>#define SEQ (B)(O)(O)(S)(T)
    
    WH>BOOST_PP_SEQ_ENUM(SEQ) // expands to B, O, O, S, T
    WH>

    WH>[ccode]
    WH>#define SEQ (a)(b)(c)

    Не хотелось бы тянуть сюда еще буст. Может, есть еще какие варианты?
    А еще хочется немного оптимизировать выделяемую статически память под NameId. Теперь тот кусок кода выглядит так:
    http://www.rsdn.ru/Forum/Message.aspx?mid=751529&amp;only=1
    Автор: Andrew S
    Дата: 05.08.04

    Так получается, что всегда выделяется по 33 байта, что неинтересно. Очевидно, частичной специализацией можно было бы легко это соптимизировать, но под VC6 ее, как известно, нет, а как использовать эмуляцию в этом случае я никак не могу придумать, кроме как наплодить множество вложенных структур, что неинтересно, да и много N=sum(1..8). Есть мысли?
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[7]: Сам код
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 05.08.04 20:12
    Оценка:
    А вот и вариант с частичной специализацией. Просьба увести детей от мониторов, особо впечатлительным лучше не смотреть


    #define FLATTEN_STR(val) \
            (TCHAR)HIBYTE(HIWORD(val)), (TCHAR)LOBYTE(HIWORD(val)), (TCHAR)HIBYTE(LOWORD(val)), (TCHAR)LOBYTE(LOWORD(val))
    
    
    #define    DECLARE_STR_DWORD(Name, Idx) \
    static const TCHAR Name[] = {FLATTEN_STR(Idx##0), FLATTEN_STR(Idx##1), FLATTEN_STR(Idx##2), FLATTEN_STR(Idx##3), FLATTEN_STR(Idx##4), FLATTEN_STR(Idx##5), FLATTEN_STR(Idx##6), FLATTEN_STR(Idx##7)};
    
    
    template <DWORD n0>
    struct CNameIdHolder0
    {
        template <DWORD n1>
        struct CNameIdHolder1
        {
            template <DWORD n2>
            struct CNameIdHolder2
            {
                template <DWORD n3>
                struct CNameIdHolder3
                {
                    template <DWORD n4>
                    struct CNameIdHolder4
                    {
                        template <DWORD n5>
                        struct CNameIdHolder5
                        {
                            template <DWORD n6>
                            struct CNameIdHolder6
                            {
                                template <DWORD n7>
                                struct CNameIdHolder7
                                {
                                    static LPCTSTR GetStr()
                                    {
                                        static const TCHAR szBuffer[] = {
                                                                            FLATTEN_STR(n0),
                                                                            FLATTEN_STR(n1),
                                                                            FLATTEN_STR(n2),
                                                                            FLATTEN_STR(n3),
                                                                            FLATTEN_STR(n4),
                                                                            FLATTEN_STR(n5),
                                                                            FLATTEN_STR(n6),
                                                                            FLATTEN_STR(n7),
                                                                            _T('\0')
                                                                        };
                                        return szBuffer;
                                    }
                                };
                                template <>
                                struct CNameIdHolder7<0>
                                {
                                    static LPCTSTR GetStr()
                                    {
                                        static const TCHAR szBuffer[] = {
                                                                            FLATTEN_STR(n0),
                                                                            FLATTEN_STR(n1),
                                                                            FLATTEN_STR(n2),
                                                                            FLATTEN_STR(n3),
                                                                            FLATTEN_STR(n4),
                                                                            FLATTEN_STR(n5),
                                                                            FLATTEN_STR(n6),
                                                                            _T('\0')
                                                                        };
                                        return szBuffer;
                                    }
                                };
                            };
                            template <>
                            struct CNameIdHolder6<0>
                            {
                                template <DWORD n7>
                                struct CNameIdHolder7
                                {
                                    static LPCTSTR GetStr()
                                    {
                                        static const TCHAR szBuffer[] = {
                                                                            FLATTEN_STR(n0),
                                                                            FLATTEN_STR(n1),
                                                                            FLATTEN_STR(n2),
                                                                            FLATTEN_STR(n3),
                                                                            FLATTEN_STR(n4),
                                                                            FLATTEN_STR(n5),
                                                                            _T('\0')
                                                                        };
                                        return szBuffer;
                                    }
                                };
                            };
                        };
                        template <>
                        struct CNameIdHolder5<0>
                        {
                            template <DWORD n6>
                            struct CNameIdHolder6
                            {
                                template <DWORD n7>
                                struct CNameIdHolder7
                                {
                                    static LPCTSTR GetStr()
                                    {
                                        static const TCHAR szBuffer[] = {
                                                                            FLATTEN_STR(n0),
                                                                            FLATTEN_STR(n1),
                                                                            FLATTEN_STR(n2),
                                                                            FLATTEN_STR(n3),
                                                                            FLATTEN_STR(n4),
                                                                            _T('\0')
                                                                        };
                                        return szBuffer;
                                    }
                                };
                            };
                        };
                    };
                    template <>
                    struct CNameIdHolder4<0>
                    {
                        template <DWORD n5>
                        struct CNameIdHolder5
                        {
                            template <DWORD n6>
                            struct CNameIdHolder6
                            {
                                template <DWORD n7>
                                struct CNameIdHolder7
                                {
                                    static LPCTSTR GetStr()
                                    {
                                        static const TCHAR szBuffer[] = {
                                                                            FLATTEN_STR(n0),
                                                                            FLATTEN_STR(n1),
                                                                            FLATTEN_STR(n2),
                                                                            FLATTEN_STR(n3),
                                                                            _T('\0')
                                                                        };
                                        return szBuffer;
                                    }
                                };
                            };
                        };
                    };
                };
                template <>
                struct CNameIdHolder3<0>
                {
                    template <DWORD n4>
                    struct CNameIdHolder4
                    {
                        template <DWORD n5>
                        struct CNameIdHolder5
                        {
                            template <DWORD n6>
                            struct CNameIdHolder6
                            {
                                template <DWORD n7>
                                struct CNameIdHolder7
                                {
                                    static LPCTSTR GetStr()
                                    {
                                        static const TCHAR szBuffer[] = {
                                                                            FLATTEN_STR(n0),
                                                                            FLATTEN_STR(n1),
                                                                            FLATTEN_STR(n2),
                                                                            _T('\0')
                                                                        };
                                        return szBuffer;
                                    }
                                };
                            };
                        };
                    };
                };
            };
            template <>
            struct CNameIdHolder2<0>
            {
                template <DWORD n3>
                struct CNameIdHolder3
                {
                    template <DWORD n4>
                    struct CNameIdHolder4
                    {
                        template <DWORD n5>
                        struct CNameIdHolder5
                        {
                            template <DWORD n6>
                            struct CNameIdHolder6
                            {
                                template <DWORD n7>
                                struct CNameIdHolder7
                                {
                                    static LPCTSTR GetStr()
                                    {
                                        static const TCHAR szBuffer[] = {
                                                                            FLATTEN_STR(n0),
                                                                            FLATTEN_STR(n1),
                                                                            _T('\0')
                                                                        };
                                        return szBuffer;
                                    }
                                };
                            };
                        };
                    };
                };
            };
        };
        template <>
        struct CNameIdHolder1<0>
        {
            template <DWORD n2>
            struct CNameIdHolder2
            {
                template <DWORD n3>
                struct CNameIdHolder3
                {
                    template <DWORD n4>
                    struct CNameIdHolder4
                    {
                        template <DWORD n5>
                        struct CNameIdHolder5
                        {
                            template <DWORD n6>
                            struct CNameIdHolder6
                            {
                                template <DWORD n7>
                                struct CNameIdHolder7
                                {
                                    static LPCTSTR GetStr()
                                    {
                                        static const TCHAR szBuffer[] = {
                                                                            FLATTEN_STR(n0),
                                                                            _T('\0')
                                                                        };
                                        return szBuffer;
                                    }
                                };
                            };
                        };
                    };
                };
            };
        };
    };
    
    struct CNameIdHolder0<0>
    {
        template <DWORD n1>
        struct CNameIdHolder1
        {
            template <DWORD n2>
            struct CNameIdHolder2
            {
                template <DWORD n3>
                struct CNameIdHolder3
                {
                    template <DWORD n4>
                    struct CNameIdHolder4
                    {
                        template <DWORD n5>
                        struct CNameIdHolder5
                        {
                            template <DWORD n6>
                            struct CNameIdHolder6
                            {
                                template <DWORD n7>
                                struct CNameIdHolder7
                                {
                                    static LPCTSTR GetStr()
                                    {
                                        static const TCHAR szBuffer[] = {
                                                                            _T('\0')
                                                                        };
                                        return szBuffer;
                                    }
                                };
                            };
                        };
                    };
                };
            };
        };
    };
    
    template <DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
    struct CNameId
    {
        enum
        {
            m_n0 = n0,
            m_n1 = n1,
            m_n2 = n2,
            m_n3 = n3,
            m_n4 = n4,
            m_n5 = n5,
            m_n6 = n6,
            m_n7 = n7
        };
        static LPCTSTR GetStr()
        {
            return CNameIdHolder0<n0>::CNameIdHolder1<n1>::CNameIdHolder2<n2>::CNameIdHolder3<n3>::CNameIdHolder4<n4>::CNameIdHolder5<n5>::CNameIdHolder6<n6>::CNameIdHolder7<n7>::GetStr();
        }
    };


    Собственно, теперь максимальные потери — 4 байта. И никакого оверхеда на копирование\преобразование строк
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[4]: Сам код
    От: WolfHound  
    Дата: 05.08.04 20:14
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Так получается, что всегда выделяется по 33 байта, что неинтересно. Очевидно, частичной специализацией можно было бы легко это соптимизировать, но под VC6 ее, как известно, нет, а как использовать эмуляцию в этом случае я никак не могу придумать, кроме как наплодить множество вложенных структур, что неинтересно, да и много N=sum(1..8). Есть мысли?

    template <DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
    struct CNameId
    {
        CNameId()
        {
            std::cout<<count<<"\n";
        }
        enum
        {
            count   =!n0?0
                    :!n1?1
                    :!n2?2
                    :!n3?3
                    :!n4?4
                    :!n5?5
                    :!n6?6
                    :!n7?7
                    :8
        };
    };
    int main()
    {
        CNameId<> id1;
        CNameId<1> id2;
        CNameId<1,2> id3;
        CNameId<1,4,5,6,7> id4;
        CNameId<1,2,3,4,5,6,7,8> id5;
        return 0;
    }
    ... << RSDN@Home 1.1.3 beta 1 >>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[5]: Сам код
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 05.08.04 20:23
    Оценка:
    Нет, не то. Проинициализируйте буфер статически. Иначе в чем смысл, затраты кода будут больше неиспользуемой части буфера. Я привел вариант, но он ужасен, но там все в компиле-тайм. Другого я придумать не смог .

    AS>>Так получается, что всегда выделяется по 33 байта, что неинтересно. Очевидно, частичной специализацией можно было бы легко это соптимизировать, но под VC6 ее, как известно, нет, а как использовать эмуляцию в этом случае я никак не могу придумать, кроме как наплодить множество вложенных структур, что неинтересно, да и много N=sum(1..8). Есть мысли?

    WH>
    WH>template <DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
    WH>struct CNameId
    WH>{
    WH>    CNameId()
    WH>    {
    WH>        std::cout<<count<<"\n";
    WH>    }
    WH>    enum
    WH>    {
    WH>        count   =!n0?0
    WH>                :!n1?1
    WH>                :!n2?2
    WH>                :!n3?3
    WH>                :!n4?4
    WH>                :!n5?5
    WH>                :!n6?6
    WH>                :!n7?7
    WH>                :8
    WH>    };
    WH>};
    WH>int main()
    WH>{
    WH>    CNameId<> id1;
    WH>    CNameId<1> id2;
    WH>    CNameId<1,2> id3;
    WH>    CNameId<1,4,5,6,7> id4;
    WH>    CNameId<1,2,3,4,5,6,7,8> id5;
    WH>    return 0;
    WH>}
    WH>
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[7]: Сам код
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 05.08.04 21:06
    Оценка:
    ]
    WH>А если не бояться boost'а то специализации можно наплодить так
    WH>
    WH>#define MAKE_BUF_SPEC(z, count, max_count)                                  \
    WH>template<>                                                                  \
    WH>struct CNameIdBuf<count>                                                    \
    WH>{                                                                           \
    WH>    template<BOOST_PP_ENUM_PARAMS(max_count, DWORD n)>                      \
    WH>    struct Buf                                                              \
    WH>    {                                                                       \
    WH>        static const DWORD* Get()                                           \
    WH>        {                                                                   \
    WH>            static const DWORD a[count]={BOOST_PP_ENUM_PARAMS(count, n)};   \
    WH>            return a;                                                       \
    WH>        }                                                                   \
    WH>    };                                                                      \
    WH>};                                                                          \
    WH>//end macro
    WH>BOOST_PP_REPEAT_FROM_TO(1, 9, MAKE_BUF_SPEC, 8) 
    WH>


    Красиво, ну буста придется избегать. А за мысль — спасибо.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re: Код V1.01
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 09.08.04 18:15
    Оценка:
    Немного правок из предложенных выше и своих + маленькие багфиксы.
    Определения макросов и прокси для числа параметров > 1 не приведены из принципа
    Как обычно — жду предложений\поправок.

    //    delayimphlp.h: Delay import helper
    //    Developer:    Andrew Solodovnikov
    //    E-mail:        none
    //    Date:        03.08.2004
    
    #ifndef    __DELAYIMPHLP_H__
    #define __DELAYIMPHLP_H__
    
    #define FLATTEN_STR(val) \
            (TCHAR)HIBYTE(HIWORD(val)), (TCHAR)LOBYTE(HIWORD(val)), (TCHAR)HIBYTE(LOWORD(val)), (TCHAR)LOBYTE(LOWORD(val))
    
    
    #define    DECLARE_STR_DWORD(Name, Idx) \
    static const TCHAR Name[] = {FLATTEN_STR(Idx##0), FLATTEN_STR(Idx##1), FLATTEN_STR(Idx##2), FLATTEN_STR(Idx##3), FLATTEN_STR(Idx##4), FLATTEN_STR(Idx##5), FLATTEN_STR(Idx##6), FLATTEN_STR(Idx##7)};
    
    template <int count>
    struct CNameIdHolder
    {
        template <DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
        struct CNameIdHolderImpl
        {
            static LPCTSTR GetStr()
            {
                static const TCHAR szBuffer[] = {
                                                    FLATTEN_STR(n0),
                                                    FLATTEN_STR(n1),
                                                    FLATTEN_STR(n2),
                                                    FLATTEN_STR(n3),
                                                    FLATTEN_STR(n4),
                                                    FLATTEN_STR(n5),
                                                    FLATTEN_STR(n6),
                                                    FLATTEN_STR(n7),
                                                    _T('\0')
                                                };
                return szBuffer;
            }
        };
    };
    
    
    template <>
    struct CNameIdHolder<7>
    {
        template <DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
        struct CNameIdHolderImpl
        {
            static LPCTSTR GetStr()
            {
                static const TCHAR szBuffer[] = {
                                                    FLATTEN_STR(n0),
                                                    FLATTEN_STR(n1),
                                                    FLATTEN_STR(n2),
                                                    FLATTEN_STR(n3),
                                                    FLATTEN_STR(n4),
                                                    FLATTEN_STR(n5),
                                                    FLATTEN_STR(n6),
                                                    _T('\0')
                                                };
                return szBuffer;
            }
        };
    };
    
    
    template <>
    struct CNameIdHolder<6>
    {
        template <DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
        struct CNameIdHolderImpl
        {
            static LPCTSTR GetStr()
            {
                static const TCHAR szBuffer[] = {
                                                    FLATTEN_STR(n0),
                                                    FLATTEN_STR(n1),
                                                    FLATTEN_STR(n2),
                                                    FLATTEN_STR(n3),
                                                    FLATTEN_STR(n4),
                                                    FLATTEN_STR(n5),
                                                    _T('\0')
                                                };
                return szBuffer;
            }
        };
    };
    
    template <>
    struct CNameIdHolder<5>
    {
        template <DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
        struct CNameIdHolderImpl
        {
            static LPCTSTR GetStr()
            {
                static const TCHAR szBuffer[] = {
                                                    FLATTEN_STR(n0),
                                                    FLATTEN_STR(n1),
                                                    FLATTEN_STR(n2),
                                                    FLATTEN_STR(n3),
                                                    FLATTEN_STR(n4),
                                                    _T('\0')
                                                };
                return szBuffer;
            }
        };
    };
    
    template <>
    struct CNameIdHolder<4>
    {
        template <DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
        struct CNameIdHolderImpl
        {
            static LPCTSTR GetStr()
            {
                static const TCHAR szBuffer[] = {
                                                    FLATTEN_STR(n0),
                                                    FLATTEN_STR(n1),
                                                    FLATTEN_STR(n2),
                                                    FLATTEN_STR(n3),
                                                    _T('\0')
                                                };
                return szBuffer;
            }
        };
    };
    
    template <>
    struct CNameIdHolder<3>
    {
        template <DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
        struct CNameIdHolderImpl
        {
            static LPCTSTR GetStr()
            {
                static const TCHAR szBuffer[] = {
                                                    FLATTEN_STR(n0),
                                                    FLATTEN_STR(n1),
                                                    FLATTEN_STR(n2),
                                                    _T('\0')
                                                };
                return szBuffer;
            }
        };
    };
    
    template <>
    struct CNameIdHolder<2>
    {
        template <DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
        struct CNameIdHolderImpl
        {
            static LPCTSTR GetStr()
            {
                static const TCHAR szBuffer[] = {
                                                    FLATTEN_STR(n0),
                                                    FLATTEN_STR(n1),
                                                    _T('\0')
                                                };
                return szBuffer;
            }
        };
    };
    
    template <>
    struct CNameIdHolder<1>
    {
        template <DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
        struct CNameIdHolderImpl
        {
            static LPCTSTR GetStr()
            {
                static const TCHAR szBuffer[] = {
                                                    FLATTEN_STR(n0),
                                                    _T('\0')
                                                };
                return szBuffer;
            }
        };
    };
    
    template <>
    struct CNameIdHolder<0>
    {
        template <DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
        struct CNameIdHolderImpl
        {
            static LPCTSTR GetStr()
            {
                return NULL;
            }
        };
    };
    
    
    template <DWORD n0 = 0, DWORD n1 = 0, DWORD n2 = 0, DWORD n3 = 0, DWORD n4 = 0, DWORD n5 = 0, DWORD n6 = 0, DWORD n7 = 0>
    struct CNameId
    {
        enum
        {
            m_n0 = n0,
            m_n1 = n1,
            m_n2 = n2,
            m_n3 = n3,
            m_n4 = n4,
            m_n5 = n5,
            m_n6 = n6,
            m_n7 = n7,
            count   = (!n0) ? 0: (!n1) ? 1: (!n2) ?2: (!n3) ? 3: (!n4) ? 4: (!n5) ? 5: (!n6) ? 6: 7
        };
        static LPCTSTR GetStr()
        {
            return CNameIdHolder<count>::CNameIdHolderImpl<n0,n1,n2,n3,n4,n5,n6,n7>::GetStr();
        }
    };
    
    template <class Name>
    class CModule
    {
    public:
        HMODULE m_hModule;
        typedef CModule<Name> type;
        typedef Name          name_type;
        static type &GetModule()
        {
            static type Module;
            return Module;
        }
        ~CModule()
        {
            if (m_hModule)
                FreeLibrary(m_hModule);
        }
    private:
        CModule()
        {
            m_hModule = LoadLibrary(name_type::GetStr());
        }
    };
    
    
    template <class Module, class Name, class Proxy>
    class CDynFunction
    {
    public:
        typedef CDynFunction<Module, Name, Proxy> type;
        typedef Proxy                              proxy_type;
        typedef Module                              module_type;
        typedef Name                              name_type;
        
        static proxy_type::fun_type &GetProxy()
        {
            static proxy_type::fun_type proxy = proxy_type::Proxy<type>::ProxyFun;
            return proxy;
        }
        static BOOL InitFunction()
        {
            HMODULE hModule = Module::GetModule().m_hModule;
            if (hModule)
            {
                FARPROC pFunction = GetProcAddress(hModule, name_type::GetStr());
                if (pFunction)
                {
                    GetProxy() = (proxy_type::fun_type)pFunction;
                    return TRUE;
                }
            }
            return FALSE;
        }
    };
    
    template<class R, R value = R()>
    struct FunProxyValuePolicy
    {
        template <class DynFunction> 
        struct Dummy
        {
            static DynFunction::proxy_type::ret_type MakeReturn()
            {
                return value;
            }
        };
    };
    
    struct CDynFunException
    {
        CDynFunException();
        CDynFunException(LPCTSTR sMessage):m_sMessage(sMessage)
        {
        }
        CDynFunException(const CDynFunException &other):m_sMessage(other.m_sMessage)
        {
        }
        CDynFunException &operator = (const CDynFunException &other)
        {
            m_sMessage = other.m_sMessage;
            return *this;
        }
        CString m_sMessage;
    };
    
    template<class E = CDynFunException>
    struct FunProxyThrowPolicy
    {
        template <class DynFunction> 
        struct Dummy
        {
            static DynFunction::proxy_type::ret_type MakeReturn()
            {
                CString sMessage;
                sMessage.Format(_T("Can'n load procedure <%s>: %d"), DynFunction::name_type::GetStr(), GetLastError());
                throw E(sMessage);
                return 0;
            }
        };
    };
    
    template <typename R, typename P1, class Policy = FunProxyValuePolicy<R> > struct FunProxy
    {
        typedef R (WINAPI *fun_type)(P1);
        typedef R ret_type;
        
        template <class DynFunction> struct Proxy
        {
            static R WINAPI ProxyFun(P1 param)
            {
                if (DynFunction::InitFunction())
                    return DynFunction::GetProxy()(param);
                return Policy::Dummy<DynFunction>::MakeReturn();
            }
        };
    };
    
    
    
    #define USE_MODULE_BEGIN(nmspace, NameId) \
    namespace nmspace \
    {\
        typedef CModule< CNameId< /NameId/ > > module_type;\
    
    #define USE_MODULE_END \
    };\
    
    
    #define DECLARE_FUN_P1(Name, NameId, R, P1)\
    static R (WINAPI *&Name)(P1) = CDynFunction<module_type, CNameId< /NameId/ >, FunProxy<R, P1> >::GetProxy();
    
    #define DECLARE_FUN_P1_ERR(Name, NameId, R, P1, E)\
    static R (WINAPI *&Name)(P1) = CDynFunction<module_type, CNameId< /NameId/ >, FunProxy<R, P1, FunProxyValuePolicy<R, E> > >::GetProxy();
     
    #define DECLARE_FUN_P1_THROW(Name, NameId, R, P1)\
    static R (WINAPI *&Name)(P1) = CDynFunction<module_type, CNameId< /NameId/ >, FunProxy<R, P1, FunProxyThrowPolicy<> > >::GetProxy();
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[2]: Код V1.01
    От: _nn_ www.nemerleweb.com
    Дата: 12.08.04 06:35
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Немного правок из предложенных выше и своих + маленькие багфиксы.

    AS>Определения макросов и прокси для числа параметров > 1 не приведены из принципа
    AS>Как обычно — жду предложений\поправок.

    AS>
    <skip>
    AS>


    Пока что придирки к CNameIdHolder.
    Вы действительно считаете что такая специализация выглядит красиво ?
    Лучше уж сделать собственный велосипед на макросах, чем городить это все, вдобавок код у вас не расширяем, т.е. если я захочу, чтобы было не 7, а 8 параметров то мне надо очень много дописывать.

     static const TCHAR szBuffer[] = {
                                                    FLATTEN_STR(n0),
                                                    FLATTEN_STR(n1),
                                                    FLATTEN_STR(n2),
                                                    FLATTEN_STR(n3),
                                                    FLATTEN_STR(n4),
                                                    FLATTEN_STR(n5),
                                                    FLATTEN_STR(n6),
                                                    _T('\0')
                                                };


    Это можно сделать немного красивее :
    template<DWORD n,DWORD nx,DWORD np>
    struct flatten_str
    { enum { value = nx<n?np:0 }; };
    
    static const TCHAR szBuffer[] =
    {
     flatten_str<7,0,n0>::value,
     flatten_str<7,1,n1>::value,
     ...
     flatten_str<7,7,0>::value
    };


    И тогда код получится более приятным :
    template<DWORD n,DWORD nx,DWORD np>
    struct flatten_str
    { enum { value = nx<n?np:0 }; };
    
    template <int count>
    struct CNameIdHolder
    {
        template <DWORD n0 = 0,
                  DWORD n1 = 0,
                  DWORD n2 = 0,
                  DWORD n3 = 0,
                  DWORD n4 = 0,
                  DWORD n5 = 0,
                  DWORD n6 = 0,
                  DWORD n7 = 0>
        struct CNameIdHolderImpl
        {
            static LPCTSTR GetStr()
            {
                static const TCHAR szBuffer[] =
                {
                    (TCHAR)flatten_str<count,0,n0>::value,
                    (TCHAR)flatten_str<count,1,n1>::value,
                    (TCHAR)flatten_str<count,2,n2>::value,
                    (TCHAR)flatten_str<count,3,n3>::value,
                    (TCHAR)flatten_str<count,4,n4>::value,
                    (TCHAR)flatten_str<count,5,n5>::value,
                    (TCHAR)flatten_str<count,6,n6>::value,
                    (TCHAR)flatten_str<count,7,n7>::value,
                    (TCHAR)flatten_str<count,8,0 >::value,
                };
                return szBuffer;
            }
        };
    };


    Что-то вроде того
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[3]: Код V1.01
    От: _nn_ www.nemerleweb.com
    Дата: 12.08.04 07:01
    Оценка:
    Здравствуйте, _nn_, Вы писали:

    Т.е. так :

        static const TCHAR szBuffer[] =
        {
                    (TCHAR)HIBYTE(HIWORD(flatten_str<count,0,n0>::value)),
                    (TCHAR)LOBYTE(HIWORD(flatten_str<count,0,n0>::value)),
                    (TCHAR)HIBYTE(LOWORD(flatten_str<count,0,n0>::value)),
                    (TCHAR)LOBYTE(LOWORD(flatten_str<count,0,n0>::value)),
                    //...
        };
        return szBuffer;
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[3]: Код V1.01
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 12.08.04 08:46
    Оценка:
    __>Пока что придирки к CNameIdHolder.
    __>Вы действительно считаете что такая специализация выглядит красиво ?
    __>Лучше уж сделать собственный велосипед на макросах, чем городить это все, вдобавок код у вас не расширяем, т.е. если я захочу, чтобы было не 7, а 8 параметров то мне надо очень много дописывать.

    Параметров и так 8, а CNameIdHolder и не должен быть расширяем — расширяем CNameId, именно его и надо менять, если надо более длинное имя. Специализация вполне красивая, хотя и не маленькая (впрочем, можно и без нее, но так экономится размер бинарника), и макрос тут тоже лучше, чем набор отдельных классов — "не плодите сущности без необходимости", их уже и так много
    Имхо, главная проблема не в этом, а в том, как удобнее пользовать основные макросы, где требуется переменное число параметров + как красивее определять макросы для различного числа параметров функций.
    А вообще, откровенно говоря, мне не понятна логика комитета, который не предусмотрел специализацию строковыми литералами.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[4]: Код V1.01
    От: _nn_ www.nemerleweb.com
    Дата: 12.08.04 08:59
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    __>>Пока что придирки к CNameIdHolder.

    __>>Вы действительно считаете что такая специализация выглядит красиво ?
    __>>Лучше уж сделать собственный велосипед на макросах, чем городить это все, вдобавок код у вас не расширяем, т.е. если я захочу, чтобы было не 7, а 8 параметров то мне надо очень много дописывать.

    AS>Параметров и так 8, а CNameIdHolder и не должен быть расширяем — расширяем CNameId, именно его и надо менять, если надо более длинное имя. Специализация вполне красивая, хотя и не маленькая (впрочем, можно и без нее, но так экономится размер бинарника), и макрос тут тоже лучше, чем набор отдельных классов — "не плодите сущности без необходимости", их уже и так много

    AS>Имхо, главная проблема не в этом, а в том, как удобнее пользовать основные макросы, где требуется переменное число параметров + как красивее определять макросы для различного числа параметров функций.
    Зато в моем варианте не требуется переписывать для каждой специализации код.

    AS>А вообще, откровенно говоря, мне не понятна логика комитета, который не предусмотрел специализацию строковыми литералами.

    Потому что массивом нельзя специализировать шаблон, а строки это массив символов.
    Видимо реализация этого довольно сложна.

    Мне кажется лучше вместо DWORD делать так :
    template<
            TCHAR c0=0,
            TCHAR c1=0,
            TCHAR c2=0,
            TCHAR c3=0,
                    //...
        >
    class CNameIdHolderImpl
    {
    };


    И не будет проблем с разложением DWORD.
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[5]: Код V1.01
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 12.08.04 09:30
    Оценка:
    __>Зато в моем варианте не требуется переписывать для каждой специализации код.

    Ваш вариант вообще работать не будет, он определяет массив из 8-ми TCHAR Забудьте про эту мысль, она плохая, уверяю вас, вы РОВНЫМ счетом ничего не съэкономите, а наоборот.

    AS>>А вообще, откровенно говоря, мне не понятна логика комитета, который не предусмотрел специализацию строковыми литералами.

    __>Потому что массивом нельзя специализировать шаблон, а строки это массив символов.
    __>Видимо реализация этого довольно сложна.

    Как раз массивом специализировать шаблон можно.


    
    TCHAR sz[] = _T("test");
    
    template <LPCTSTR s>
    struct C
    {
    };
    
    С<sz> c;


    А вот сроковым литералом, который имеет internal linkage и тип const TCHAR[] — нельзя.

    __>Мне кажется лучше вместо DWORD делать так :

    __>
    __>template<
    __>        TCHAR c0=0,
    __>        TCHAR c1=0,
    __>        TCHAR c2=0,
    __>        TCHAR c3=0,
    __>                //...
        >>
    __>class CNameIdHolderImpl
    __>{
    __>};
    __>


    __>И не будет проблем с разложением DWORD.


    Проблем и так нет, это вы их придумали А запись имени получится в 2.5 раза длиннее и еще непонятнее.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[6]: Код V1.01
    От: _nn_ www.nemerleweb.com
    Дата: 12.08.04 09:42
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    __>>Зато в моем варианте не требуется переписывать для каждой специализации код.


    AS>Ваш вариант вообще работать не будет, он определяет массив из 8-ми TCHAR Забудьте про эту мысль, она плохая, уверяю вас, вы РОВНЫМ счетом ничего не съэкономите, а наоборот.


    AS>>>А вообще, откровенно говоря, мне не понятна логика комитета, который не предусмотрел специализацию строковыми литералами.

    __>>Потому что массивом нельзя специализировать шаблон, а строки это массив символов.
    __>>Видимо реализация этого довольно сложна.

    AS>Как раз массивом специализировать шаблон можно.



    AS>
    
    AS>TCHAR sz[] = _T("test");
    
    AS>template <LPCTSTR s>
    AS>struct C
    AS>{
    AS>};
    
    AS>С<sz> c;
    AS>


    AS>А вот сроковым литералом, который имеет internal linkage и тип const TCHAR[] — нельзя.

    Потому что это внешняя линковка, а все что внутреняя нельзя использовать.

    Зато можно сделать такое :
    template<const TCHAR s>
    struct x{};
    
    #define DEF_STR(strname,str) \
     const TCHAR strname##__unique_name[] = str; \
     x<strname##__unique_name> some_type##str_name;


    __>>Мне кажется лучше вместо DWORD делать так :

    __>>
    __>>template<
    __>>        TCHAR c0=0,
    __>>        TCHAR c1=0,
    __>>        TCHAR c2=0,
    __>>        TCHAR c3=0,
    __>>                //...
        >>>
    __>>class CNameIdHolderImpl
    __>>{
    __>>};
    __>>


    __>>И не будет проблем с разложением DWORD.


    AS>Проблем и так нет, это вы их придумали А запись имени получится в 2.5 раза длиннее и еще непонятнее.

    Я люблю придумывать проблемы и героически их решать

    Или может лучше сделать через Traits ?

    template<typename TTraits>
    class x;
    
    struct traits_kernel32_lib
    { static LPCTSTR get_name() { return "kernel32.lib" } };
    
    x<traits_kernel32_lib> lib_kernel;

    Или оформить в виде макроса.
    Тогда нет проблем со строкой и нет проблем с разбором строки и нет проблем с глобальной переменной.

    #define USE_MODULE_BEGIN(nmspace, id, NameId) \
    namespace nmspace \
    {\
        struct nmspace##_traits##id##__unique_name
        { static LPCTSTR get_name() { return NameId; } };
        typedef CModule< CNameId< nmspace##_traits##id##__unique_name > > module_type;\


    Ну или что-то вроде того
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[7]: Код V1.01
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 12.08.04 10:30
    Оценка:
    AS>>А вот сроковым литералом, который имеет internal linkage и тип const TCHAR[] — нельзя.
    __>Потому что это внешняя линковка, а все что внутреняя нельзя использовать.

    Это все понятно.

    __>Зато можно сделать такое :


    В VC6 — нельзя. Можно только без спецификатора const.
    __>
    __>template<const TCHAR s>
    __>struct x{};
    
    __>#define DEF_STR(strname,str) \
    __> const TCHAR strname##__unique_name[] = str; \
    __> x<strname##__unique_name> some_type##str_name;
    __>


    __>>>Мне кажется лучше вместо DWORD делать так :

    __>>>
    __>>>template<
    __>>>        TCHAR c0=0,
    __>>>        TCHAR c1=0,
    __>>>        TCHAR c2=0,
    __>>>        TCHAR c3=0,
    __>>>                //...
        >>>>
    __>>>class CNameIdHolderImpl
    __>>>{
    __>>>};
    __>>>


    __>>>И не будет проблем с разложением DWORD.



    Будут проблемы другого плана — в каждом модуле линковки будет своя таблица (поскольку специализации, в данном случае адреса массивов), будут различаться. А нам то нужно как раз обратно — обеспечить кросс-модульность.

    __>Или может лучше сделать через Traits ?


    __>
    __>template<typename TTraits>
    __>class x;
    
    __>struct traits_kernel32_lib
    __>{ static LPCTSTR get_name() { return "kernel32.lib" } };
    
    __>x<traits_kernel32_lib> lib_kernel;
    __>

    __>Или оформить в виде макроса.
    __>Тогда нет проблем со строкой и нет проблем с разбором строки и нет проблем с глобальной переменной.

    __>
    __>#define USE_MODULE_BEGIN(nmspace, id, NameId) \
    __>namespace nmspace \
    __>{\
    __>    struct nmspace##_traits##id##__unique_name
    __>    { static LPCTSTR get_name() { return NameId; } };
    __>    typedef CModule< CNameId< nmspace##_traits##id##__unique_name > > module_type;\
    __>


    __>Ну или что-то вроде того


    Аналогичная проблема, только, за исключением того, что придется делать трейты для всех функций, библиотеку и т.п. что используются в программе, выносить их в отдельный заголовочный файл, а это убивает изначальную гибкость конструкции.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[8]: Код V1.01
    От: _nn_ www.nemerleweb.com
    Дата: 12.08.04 12:29
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    Проблемы одни

    А теперь сначала все

    Что делает CNameIdHolder ?
    Создает строку из нескольких двойных слов, вместо этого можно использовать обычные символы, и тогда не нужен будет макрос FLATTEN_STR, зато писать надо немного утомительно :
    typedef CModule<
      CNameId<'k','e','r','n','e','l','3','2','.','d','l','l'>
     >kernel_module_type;

    Зато макрос не нужен

    И выйдет что-то такое :
    template<TCHAR c0=0,
             TCHAR c1=0,
             TCHAR c2=0,
             TCHAR c3=0,
             //...
            >
    struct CNameId
    {
      enum
      {
            m_c0 = c0,
            m_c1 = c1,
            m_c2 = c2,
            //...
            count   = (!c0) ? 0: 
                      (!c1) ? 1: 
                      (!c2) ? 2:
                      //...
       };
       static LPCTSTR GetStr()
       {
           static TCHAR strName[] =
           {
             c0,
             c1,
             c2,
             //...
             0
           };
           return strName;  
      }
    };


    Нет лишних классов, лишнего кода, лишних специализаций
    И все красиво и понятно
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[9]: Код V1.01
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 12.08.04 13:27
    Оценка:
    __>Проблемы одни

    А в С++ так всегда — когда кажется, что проблем нет, то это только кажется.

    __>А теперь сначала все


    __>Что делает CNameIdHolder ?

    __>Создает строку из нескольких двойных слов, вместо этого можно использовать обычные символы, и тогда не нужен будет макрос FLATTEN_STR, зато писать надо немного утомительно :

    Нет, он статически инициализирует массив _подходящей_ длины. В вашем случае вам придется делать 32 специализации, иначе получите большой оверхед по длине массива. да и запись каждого символа по-отдельности это совсем некрасиво.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[10]: Код V1.01
    От: _nn_ www.nemerleweb.com
    Дата: 12.08.04 14:20
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    __>>Проблемы одни


    AS>А в С++ так всегда — когда кажется, что проблем нет, то это только кажется.


    __>>А теперь сначала все


    __>>Что делает CNameIdHolder ?

    __>>Создает строку из нескольких двойных слов, вместо этого можно использовать обычные символы, и тогда не нужен будет макрос FLATTEN_STR, зато писать надо немного утомительно :

    AS>Нет, он статически инициализирует массив _подходящей_ длины. В вашем случае вам придется делать 32 специализации, иначе получите большой оверхед по длине массива.

    Оверхед, да будет, но не настолько большой.
    Допустип ограничимся 32 символами, на 100 классов будет максимальный оверхед в 32*100 = 3,2кБ, я не думаю что для программы, размер которой несколько сот кБ это критично.
    AS>да и запись каждого символа по-отдельности это совсем некрасиво.
    А в оригинале разве не так ?

    В крайнем случае сделаем макросы аналоги в boost-е и воспользуемся ими
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[11]: Код V1.01
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 12.08.04 14:28
    Оценка:
    __>Допустип ограничимся 32 символами, на 100 классов будет максимальный оверхед в 32*100 = 3,2кБ, я не думаю что для программы, размер которой несколько сот кБ это критично.

    Может и не критично, но тогда в чем смысл всей этой городни с синглтонами и т.п. Если есть возможность делать оптимальнее при разработке библиотеки — это надо сделать.

    AS>>да и запись каждого символа по-отдельности это совсем некрасиво.

    __>А в оригинале разве не так ?

    Нет, не так Некрасиво — да, но все-таки не по-одному, а пачками по четыре Хотя, конечно, уродство все это

    __>В крайнем случае сделаем макросы аналоги в boost-е и воспользуемся ими


    Ну, ждем предложений Вам и карты в руки.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[12]: Код V1.01
    От: _nn_ www.nemerleweb.com
    Дата: 12.08.04 14:30
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Ну, ждем предложений Вам и карты в руки.


    Сейчас попробую
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[3]: CNameID v1.02
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 12.08.04 18:18
    Оценка:
    __>Как вам такой вариант :

    [skipped]

    Мне — почти никак, он на VC6 компилится не будет, как я понял — там у вас частичная специализация?
    В любом случае, это почти ничего не меняет, ну, кроме конечно размеров исходников, тем более, как я говорил, мне мысль использовать односимвольные числовые литералы почему то не нравится, хотя начиналось все именно так.

    На самом деле, наверное, лучше подумать над более глобальной проблемой — как удобнее сделать макросы
    USE_MODULE_BEGIN и DECLARE_FUN_P1 в части задания имени. То, что есть сейчас, явно неудобно...
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[4]: CNameID v1.02
    От: _nn_ www.nemerleweb.com
    Дата: 13.08.04 06:50
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    __>>Как вам такой вариант :


    AS>[skipped]


    AS>Мне — почти никак, он на VC6 компилится не будет, как я понял — там у вас частичная специализация?

    Забыл про VC6
    А чем вам оверхед мешает ?
    Зато все строки будут одинаковой длинны
    AS>В любом случае, это почти ничего не меняет, ну, кроме конечно размеров исходников, тем более, как я говорил, мне мысль использовать односимвольные числовые литералы почему то не нравится, хотя начиналось все именно так.
    Односимвольные литералы лучше, так как позволяют избежать проблемы вроде этой :
    CModule<'some','tex','t'>


    Мне кажется что стоит сделать какой-нибудь класс для преобразования строки в односимвольные литералы, и тогда проблем не будет.

    template<TCHAR c0,TCHAR c1, ... >
    struct CNameID
    {...};
    
    template<typename T,TCHAR str[]>
    class str_to_char
    {
     typedef T<str[0],str[1],...> type;  // как правильно не знаю :xz: 
    };

    Надеюсь идея ясна.

    AS>На самом деле, наверное, лучше подумать над более глобальной проблемой — как удобнее сделать макросы

    AS>USE_MODULE_BEGIN и DECLARE_FUN_P1 в части задания имени. То, что есть сейчас, явно неудобно...
    Если решить проблемы выше то это отпадет само собой.
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[5]: CNameID v1.02
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 13.08.04 07:24
    Оценка:
    __>Мне кажется что стоит сделать какой-нибудь класс для преобразования строки в односимвольные литералы, и тогда проблем не будет.

    __>
    __>template<TCHAR c0,TCHAR c1, ... >
    __>struct CNameID
    __>{...};
    
    __>template<typename T,TCHAR str[]>
    __>class str_to_char
    __>{
    __> typedef T<str[0],str[1],...> type;  // как правильно не знаю :xz: 
    __>};
    __>

    __>Надеюсь идея ясна.

    Ну, и подумайте, что вы предлагаете Хинт — при инстанцировании класса CNameID параметрами должны быть символьные литералы (то бишь константы).

    AS>>На самом деле, наверное, лучше подумать над более глобальной проблемой — как удобнее сделать макросы

    AS>>USE_MODULE_BEGIN и DECLARE_FUN_P1 в части задания имени. То, что есть сейчас, явно неудобно...
    __>Если решить проблемы выше то это отпадет само собой.

    Да, если решить проблемы Я (и не только я) пробовал, не получилось. Точнее, получилось то, что получилось.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[6]: CNameID v1.02
    От: _nn_ www.nemerleweb.com
    Дата: 13.08.04 07:47
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    __>>Мне кажется что стоит сделать какой-нибудь класс для преобразования строки в односимвольные литералы, и тогда проблем не будет.


    __>>
    __>>template<TCHAR c0,TCHAR c1, ... >
    __>>struct CNameID
    __>>{...};
    
    __>>template<typename T,TCHAR str[]>
    __>>class str_to_char
    __>>{
    __>> typedef T<str[0],str[1],...> type;  // как правильно не знаю :xz: 
    __>>};
    __>>

    __>>Надеюсь идея ясна.

    AS>Ну, и подумайте, что вы предлагаете Хинт — при инстанцировании класса CNameID параметрами должны быть символьные литералы (то бишь константы).

    Инстанирование будет литералами, а извне это будет в виде массива.

    AS>>>На самом деле, наверное, лучше подумать над более глобальной проблемой — как удобнее сделать макросы

    AS>>>USE_MODULE_BEGIN и DECLARE_FUN_P1 в части задания имени. То, что есть сейчас, явно неудобно...
    __>>Если решить проблемы выше то это отпадет само собой.

    AS>Да, если решить проблемы Я (и не только я) пробовал, не получилось. Точнее, получилось то, что получилось.

    Как только доберусь нормально до компьютера попробую что-нибудь сотворить
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[7]: CNameID v1.02
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 13.08.04 12:50
    Оценка:
    AS>>Ну, и подумайте, что вы предлагаете Хинт — при инстанцировании класса CNameID параметрами должны быть символьные литералы (то бишь константы).
    __>Инстанирование будет литералами, а извне это будет в виде массива.

    Не получится. Надо инстанцировать константами, а вы предлагаете инстанцировать фактически содержимым ячеек памяти, что на этапе компиляции компилеру не известно (ведь темплайт в данном случае инстанцируется адресом, к сожалению, а не содержимым).

    AS>>>>На самом деле, наверное, лучше подумать над более глобальной проблемой — как удобнее сделать макросы

    AS>>>>USE_MODULE_BEGIN и DECLARE_FUN_P1 в части задания имени. То, что есть сейчас, явно неудобно...
    __>>>Если решить проблемы выше то это отпадет само собой.

    AS>>Да, если решить проблемы Я (и не только я) пробовал, не получилось. Точнее, получилось то, что получилось.

    __>Как только доберусь нормально до компьютера попробую что-нибудь сотворить
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[2]: CNameID 1.03
    От: _nn_ www.nemerleweb.com
    Дата: 14.08.04 10:20
    Оценка:
    Переработал с целью совместимости с VC 6.0.

    // CAT
    #define CAT_(x,y) x##y
    #define CAT(x,y) CAT_(x,y)
    
    // REPEAT_N
    #define REPEAT_N_0(x) CAT(x,0)
    #define REPEAT_N_1(x) REPEAT_N_0(x), CAT(x,1)
    #define REPEAT_N_2(x) REPEAT_N_1(x), CAT(x,2)
    #define REPEAT_N_3(x) REPEAT_N_2(x), CAT(x,3)
    #define REPEAT_N_4(x) REPEAT_N_3(x), CAT(x,4)
    #define REPEAT_N_5(x) REPEAT_N_4(x), CAT(x,5)
    #define REPEAT_N_6(x) REPEAT_N_5(x), CAT(x,6)
    #define REPEAT_N_7(x) REPEAT_N_6(x), CAT(x,7)
    #define REPEAT_N_8(x) REPEAT_N_7(x), CAT(x,8)
    //...
    #define REPEAT_N(n,x) CAT(REPEAT_N_,n)(x)
    
    // REPEAT2_N
    #define REPEAT2_N_0(x,y) CAT(CAT(x,0),y)
    #define REPEAT2_N_1(x,y) REPEAT2_N_0(x,y), CAT(CAT(x,1),y)
    #define REPEAT2_N_2(x,y) REPEAT2_N_1(x,y), CAT(CAT(x,2),y)
    #define REPEAT2_N_3(x,y) REPEAT2_N_2(x,y), CAT(CAT(x,3),y)
    #define REPEAT2_N_4(x,y) REPEAT2_N_3(x,y), CAT(CAT(x,4),y)
    #define REPEAT2_N_5(x,y) REPEAT2_N_4(x,y), CAT(CAT(x,5),y)
    #define REPEAT2_N_6(x,y) REPEAT2_N_5(x,y), CAT(CAT(x,6),y)
    #define REPEAT2_N_7(x,y) REPEAT2_N_6(x,y), CAT(CAT(x,7),y)
    #define REPEAT2_N_8(x,y) REPEAT2_N_7(x,y), CAT(CAT(x,8),y)
    //...
    #define REPEAT2_N(n,x,y) CAT(REPEAT2_N_,n)(x,y)
    
    // REPEAT2_EX_N
    #define REPEAT2_EX_N_0(x,y) CAT(CAT(x,0),CAT(y,0))
    #define REPEAT2_EX_N_1(x,y) REPEAT2_EX_N_0(x,y), CAT(CAT(x,1),CAT(y,1))
    #define REPEAT2_EX_N_2(x,y) REPEAT2_EX_N_1(x,y), CAT(CAT(x,2),CAT(y,2))
    #define REPEAT2_EX_N_3(x,y) REPEAT2_EX_N_2(x,y), CAT(CAT(x,3),CAT(y,3))
    #define REPEAT2_EX_N_4(x,y) REPEAT2_EX_N_3(x,y), CAT(CAT(x,4),CAT(y,4))
    #define REPEAT2_EX_N_5(x,y) REPEAT2_EX_N_4(x,y), CAT(CAT(x,5),CAT(y,5))
    #define REPEAT2_EX_N_6(x,y) REPEAT2_EX_N_5(x,y), CAT(CAT(x,6),CAT(y,6))
    #define REPEAT2_EX_N_7(x,y) REPEAT2_EX_N_6(x,y), CAT(CAT(x,7),CAT(y,7))
    #define REPEAT2_EX_N_8(x,y) REPEAT2_EX_N_7(x,y), CAT(CAT(x,8),CAT(y,8))
    //...
    #define REPEAT2_EX_N(n,x,y) CAT(REPEAT2_EX_N_,n)(x,y)
    
    // REPEAT3_NC_N
    #define REPEAT3_NC_N_0(x,y,z) CAT(CAT(CAT(x,0),CAT(y,0)),z)
    #define REPEAT3_NC_N_1(x,y,z) REPEAT3_NC_N_0(x,y,z) CAT(CAT(CAT(x,1),CAT(y,1)),z)
    #define REPEAT3_NC_N_2(x,y,z) REPEAT3_NC_N_1(x,y,z) CAT(CAT(CAT(x,2),CAT(y,2)),z)
    #define REPEAT3_NC_N_3(x,y,z) REPEAT3_NC_N_2(x,y,z) CAT(CAT(CAT(x,3),CAT(y,3)),z)
    #define REPEAT3_NC_N_4(x,y,z) REPEAT3_NC_N_3(x,y,z) CAT(CAT(CAT(x,4),CAT(y,4)),z)
    #define REPEAT3_NC_N_5(x,y,z) REPEAT3_NC_N_4(x,y,z) CAT(CAT(CAT(x,5),CAT(y,5)),z)
    #define REPEAT3_NC_N_6(x,y,z) REPEAT3_NC_N_5(x,y,z) CAT(CAT(CAT(x,6),CAT(y,6)),z)
    #define REPEAT3_NC_N_7(x,y,z) REPEAT3_NC_N_6(x,y,z) CAT(CAT(CAT(x,7),CAT(y,7)),z)
    #define REPEAT3_NC_N_8(x,y,z) REPEAT3_NC_N_7(x,y,z) CAT(CAT(CAT(x,8),CAT(y,8)),z)
    //...
    #define REPEAT3_NC_N(n,x,y,z) CAT(REPEAT3_NC_N_,n)(x,y,z)
    
    // CNameID
    #define DECLARE_CNAMEID_IMPL(n) \
        template<unsigned N> \
        struct CNameIDImpl \
        CNAMEID_IMPL_(n,n)
    
    #define SPEC_CNAMEID_IMPL(N,n) \
        template<> \
        struct CNameIDImpl<n> \
        CNAMEID_IMPL_(N,n)
    
    #define CNAMEID_IMPL_(N,n) \
        { \
            template<REPEAT2_EX_N(N,TCHAR t_c,=0)> \
            struct Impl \
            { \
                static const TCHAR* GetStr() \
                { \
                    static const TCHAR str[]= \
                    { \
                        REPEAT_N(n,t_c), \
                        0 \
                    }; \
                    return str; \
                } \
            }; \
        };
    
    #define DECLARE_CNAMEID(n) \
        template<REPEAT2_N(n,TCHAR t_c,=0)> \
        struct CNameID \
        { \
            enum \
            { \
                REPEAT2_EX_N(n,m_c,t_c), \
                count = REPEAT3_NC_N(n,!t_c,?,:) n+1 \
            }; \
            static const TCHAR* GetStr() \
            { return CNameIDImpl<count>::Impl<REPEAT_N(n,t_c)>::GetStr(); } \
        };
    
    DECLARE_CNAMEID_IMPL(7)
    SPEC_CNAMEID_IMPL(7,0)
    SPEC_CNAMEID_IMPL(7,1)
    SPEC_CNAMEID_IMPL(7,2)
    SPEC_CNAMEID_IMPL(7,3)
    SPEC_CNAMEID_IMPL(7,4)
    SPEC_CNAMEID_IMPL(7,5)
    SPEC_CNAMEID_IMPL(7,6)
    
    DECLARE_CNAMEID(7)


    Тестим
    void main()
    {
        int n0 = CNameID<>::count;
        const TCHAR* s0 = CNameID<>::GetStr();
        int n1 = CNameID<'a'>::count;
        const TCHAR* s1 = CNameID<'a'>::GetStr();
        int n2 = CNameID<'a','b'>::count;
        const TCHAR* s2 = CNameID<'a','b'>::GetStr();
        int n3 = CNameID<'a','b','c'>::count;
        const TCHAR* s3 = CNameID<'a','b','c'>::GetStr();
        int n4 = CNameID<'a','b','c','d'>::count;
        const TCHAR* s4 = CNameID<'a','b','c','d'>::GetStr();
        int n5 = CNameID<'a','b','c','d','e'>::count;
        const TCHAR* s5 = CNameID<'a','b','c','d','e'>::GetStr();
    }
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re: Pure C++ delay load
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 16.08.04 15:29
    Оценка:
    Большое спасибо _nn_ за проявленную инициативу, в связи с чем выкладываю обновление до v 1.03
    Специализация выполнена на макросах, максимальная длина строки увеличена до 64 символов, можно без особых изменений в коде и больше.
    На макросы определения функций терпения не хватило, а common вариант не придумался — если есть мысли, будет интересно выслушать.
    И, как обычно — если есть какие предложения (ну, кроме использования буста, тут это как из пушки по воробьям) — u are welcome.

    //    delayimphlp.h: Delay import helper
    //    Developer:    Andrew Solodovnikov
    //    E-mail:        none
    //    Date:        03.08.2004
    
    #ifndef    __DELAYIMPHLP_H__
    #define __DELAYIMPHLP_H__
    
    #define DL_CAT_(x,y) x##y
    #define DL_CAT(x,y) DL_CAT_(x,y)
    
    #define MAX_DL_REPEAT 16
    
    #define DL_REPEAT_EMPTY_PARAM()
    
    // DL_REPEAT_N
    #define DL_REPEAT_N_0(x) 
    #define DL_REPEAT_N_1(x) DL_CAT(x,1)
    #define DL_REPEAT_N_2(x) DL_REPEAT_N_1(x), DL_CAT(x,2)
    #define DL_REPEAT_N_3(x) DL_REPEAT_N_2(x), DL_CAT(x,3)
    #define DL_REPEAT_N_4(x) DL_REPEAT_N_3(x), DL_CAT(x,4)
    #define DL_REPEAT_N_5(x) DL_REPEAT_N_4(x), DL_CAT(x,5)
    #define DL_REPEAT_N_6(x) DL_REPEAT_N_5(x), DL_CAT(x,6)
    #define DL_REPEAT_N_7(x) DL_REPEAT_N_6(x), DL_CAT(x,7)
    #define DL_REPEAT_N_8(x) DL_REPEAT_N_7(x), DL_CAT(x,8)
    #define DL_REPEAT_N_9(x) DL_REPEAT_N_8(x), DL_CAT(x,9)
    #define DL_REPEAT_N_10(x) DL_REPEAT_N_9(x), DL_CAT(x,10)
    #define DL_REPEAT_N_11(x) DL_REPEAT_N_10(x), DL_CAT(x,11)
    #define DL_REPEAT_N_12(x) DL_REPEAT_N_11(x), DL_CAT(x,12)
    #define DL_REPEAT_N_13(x) DL_REPEAT_N_12(x), DL_CAT(x,13)
    #define DL_REPEAT_N_14(x) DL_REPEAT_N_13(x), DL_CAT(x,14)
    #define DL_REPEAT_N_15(x) DL_REPEAT_N_14(x), DL_CAT(x,15)
    #define DL_REPEAT_N_16(x) DL_REPEAT_N_15(x), DL_CAT(x,16)
    
    #define DL_REPEAT_N(n, x) DL_CAT(DL_REPEAT_N_,n)(x)
    
    
    
    // DL_REPEAT_PARAM_N
    #define DL_REPEAT_PARAM_N0(n, m)
    #define DL_REPEAT_PARAM_N1(n, m) DL_CAT(n,1) DL_CAT(m,1)
    #define DL_REPEAT_PARAM_N2(n, m) DL_REPEAT_PARAM_N1(n, m), DL_CAT(n,2) DL_CAT(m,2)
    #define DL_REPEAT_PARAM_N3(n, m) DL_REPEAT_PARAM_N2(n, m), DL_CAT(n,3) DL_CAT(m,3)
    #define DL_REPEAT_PARAM_N4(n, m) DL_REPEAT_PARAM_N3(n, m), DL_CAT(n,4) DL_CAT(m,4)
    #define DL_REPEAT_PARAM_N5(n, m) DL_REPEAT_PARAM_N4(n, m), DL_CAT(n,5) DL_CAT(m,5)
    #define DL_REPEAT_PARAM_N6(n, m) DL_REPEAT_PARAM_N5(n, m), DL_CAT(n,6) DL_CAT(m,6)
    #define DL_REPEAT_PARAM_N7(n, m) DL_REPEAT_PARAM_N6(n, m), DL_CAT(n,7) DL_CAT(m,7)
    #define DL_REPEAT_PARAM_N8(n, m) DL_REPEAT_PARAM_N7(n, m), DL_CAT(n,8) DL_CAT(m,8)
    #define DL_REPEAT_PARAM_N9(n, m) DL_REPEAT_PARAM_N8(n, m), DL_CAT(n,9) DL_CAT(m,9)
    #define DL_REPEAT_PARAM_N10(n, m) DL_REPEAT_PARAM_N9(n, m), DL_CAT(n,10) DL_CAT(m,10)
    #define DL_REPEAT_PARAM_N11(n, m) DL_REPEAT_PARAM_N10(n, m), DL_CAT(n,11) DL_CAT(m,11)
    #define DL_REPEAT_PARAM_N12(n, m) DL_REPEAT_PARAM_N11(n, m), DL_CAT(n,12) DL_CAT(m,12)
    #define DL_REPEAT_PARAM_N13(n, m) DL_REPEAT_PARAM_N12(n, m), DL_CAT(n,13) DL_CAT(m,13)
    #define DL_REPEAT_PARAM_N14(n, m) DL_REPEAT_PARAM_N13(n, m), DL_CAT(n,14) DL_CAT(m,14)
    #define DL_REPEAT_PARAM_N15(n, m) DL_REPEAT_PARAM_N14(n, m), DL_CAT(n,15) DL_CAT(m,15)
    #define DL_REPEAT_PARAM_N16(n,m) DL_REPEAT_PARAM_N15(n, m), DL_CAT(n,16) DL_CAT(m,16)
    
    #define DL_REPEAT_PARAM_N(c, n, m) DL_CAT(DL_REPEAT_PARAM_N,c)(n, m)
    
    // DL_REPEAT_DEF_N
    #define DL_REPEAT_DEF_N0(n, d)
    #define DL_REPEAT_DEF_N1(n, d) DL_CAT(DL_CAT(n,1), d)
    #define DL_REPEAT_DEF_N2(n, d) DL_REPEAT_DEF_N1(n, d), DL_CAT(DL_CAT(n,2), d)
    #define DL_REPEAT_DEF_N3(n, d) DL_REPEAT_DEF_N2(n, d), DL_CAT(DL_CAT(n,3), d)
    #define DL_REPEAT_DEF_N4(n, d) DL_REPEAT_DEF_N3(n, d), DL_CAT(DL_CAT(n,4), d)
    #define DL_REPEAT_DEF_N5(n, d) DL_REPEAT_DEF_N4(n, d), DL_CAT(DL_CAT(n,5), d)
    #define DL_REPEAT_DEF_N6(n, d) DL_REPEAT_DEF_N5(n, d), DL_CAT(DL_CAT(n,6), d)
    #define DL_REPEAT_DEF_N7(n, d) DL_REPEAT_DEF_N6(n, d), DL_CAT(DL_CAT(n,7), d)
    #define DL_REPEAT_DEF_N8(n, d) DL_REPEAT_DEF_N7(n, d), DL_CAT(DL_CAT(n,8), d)
    #define DL_REPEAT_DEF_N9(n, d) DL_REPEAT_DEF_N8(n, d), DL_CAT(DL_CAT(n,9), d)
    #define DL_REPEAT_DEF_N10(n, d) DL_REPEAT_DEF_N9(n, d), DL_CAT(DL_CAT(n,10), d)
    #define DL_REPEAT_DEF_N11(n, d) DL_REPEAT_DEF_N10(n, d), DL_CAT(DL_CAT(n,11), d)
    #define DL_REPEAT_DEF_N12(n, d) DL_REPEAT_DEF_N11(n, d), DL_CAT(DL_CAT(n,12), d)
    #define DL_REPEAT_DEF_N13(n, d) DL_REPEAT_DEF_N12(n, d), DL_CAT(DL_CAT(n,13), d)
    #define DL_REPEAT_DEF_N14(n, d) DL_REPEAT_DEF_N13(n, d), DL_CAT(DL_CAT(n,14), d)
    #define DL_REPEAT_DEF_N15(n, d) DL_REPEAT_DEF_N14(n, d), DL_CAT(DL_CAT(n,15), d)
    #define DL_REPEAT_DEF_N16(n,d) DL_REPEAT_DEF_N15(n, d), DL_CAT(DL_CAT(n,16), d)
    
    #define DL_REPEAT_DEF_N(c, n, d) DL_CAT(DL_REPEAT_DEF_N,c)(n, d)
    
    
    // DL_REPEAT_MACRO_N
    
    #define DL_REPEAT_MACRO_N0(m, p)
    #define DL_REPEAT_MACRO_N1(m, p) m(DL_CAT(p,1))
    #define DL_REPEAT_MACRO_N2(m, p) DL_REPEAT_MACRO_N1(m, p), m(DL_CAT(p,2))
    #define DL_REPEAT_MACRO_N3(m, p) DL_REPEAT_MACRO_N2(m, p), m(DL_CAT(p,3))
    #define DL_REPEAT_MACRO_N4(m, p) DL_REPEAT_MACRO_N3(m, p), m(DL_CAT(p,4))
    #define DL_REPEAT_MACRO_N5(m, p) DL_REPEAT_MACRO_N4(m, p), m(DL_CAT(p,5))
    #define DL_REPEAT_MACRO_N6(m, p) DL_REPEAT_MACRO_N5(m, p), m(DL_CAT(p,6))
    #define DL_REPEAT_MACRO_N7(m, p) DL_REPEAT_MACRO_N6(m, p), m(DL_CAT(p,7))
    #define DL_REPEAT_MACRO_N8(m, p) DL_REPEAT_MACRO_N7(m, p), m(DL_CAT(p,8))
    #define DL_REPEAT_MACRO_N9(m, p) DL_REPEAT_MACRO_N8(m, p), m(DL_CAT(p,9))
    #define DL_REPEAT_MACRO_N10(m, p) DL_REPEAT_MACRO_N9(m, p), m(DL_CAT(p,10))
    #define DL_REPEAT_MACRO_N11(m, p) DL_REPEAT_MACRO_N10(m, p), m(DL_CAT(p,11))
    #define DL_REPEAT_MACRO_N12(m, p) DL_REPEAT_MACRO_N11(m, p), m(DL_CAT(p,12))
    #define DL_REPEAT_MACRO_N13(m, p) DL_REPEAT_MACRO_N12(m, p), m(DL_CAT(p,13))
    #define DL_REPEAT_MACRO_N14(m, p) DL_REPEAT_MACRO_N13(m, p), m(DL_CAT(p,14))
    #define DL_REPEAT_MACRO_N15(m, p) DL_REPEAT_MACRO_N14(m, p), m(DL_CAT(p,15))
    #define DL_REPEAT_MACRO_N16(m, p) DL_REPEAT_MACRO_N15(m, p), m(DL_CAT(p,16))
    
    #define DL_REPEAT_MACRO_N(c, m, p) DL_CAT(DL_REPEAT_MACRO_N,c)(m,p)
    
    #define FLATTEN_STR(val) \
            (TCHAR)HIBYTE(HIWORD(val)), (TCHAR)LOBYTE(HIWORD(val)), (TCHAR)HIBYTE(LOWORD(val)), (TCHAR)LOBYTE(LOWORD(val))
    
    
    #define    DECLARE_STR_DWORD(Name, Idx) \
    static const TCHAR Name[] = {FLATTEN_STR(Idx##0), FLATTEN_STR(Idx##1), FLATTEN_STR(Idx##2), FLATTEN_STR(Idx##3), FLATTEN_STR(Idx##4), FLATTEN_STR(Idx##5), FLATTEN_STR(Idx##6), FLATTEN_STR(Idx##7)};
    
    
    template <int count>
    struct CNameIdHolder
    {
        template <DL_REPEAT_N(MAX_DL_REPEAT, DWORD n)>
        struct CNameIdHolderImpl
        {
            static LPCTSTR GetStr()
            {
                static const TCHAR szBuffer[] = {
                                                    DL_REPEAT_MACRO_N(MAX_DL_REPEAT, FLATTEN_STR, n),
                                                    _T('\0')
                                                };
                return szBuffer;
            }
        };
    };
    
    #define NAME_ID_HOLDER_SPEC(num)\
    template <>\
    struct CNameIdHolder<num>\
    {\
        template <DL_REPEAT_N(MAX_DL_REPEAT, DWORD n)>\
        struct CNameIdHolderImpl\
        {\
            static LPCTSTR GetStr()\
            {\
                static const TCHAR szBuffer[] = {\
                                                    DL_REPEAT_MACRO_N(num, FLATTEN_STR, n),\
                                                    _T('\0')\
                                                };\
                return szBuffer;\
            }\
        };\
    };
    
    NAME_ID_HOLDER_SPEC(15)
    NAME_ID_HOLDER_SPEC(14)
    NAME_ID_HOLDER_SPEC(13)
    NAME_ID_HOLDER_SPEC(12)
    NAME_ID_HOLDER_SPEC(11)
    NAME_ID_HOLDER_SPEC(10)
    NAME_ID_HOLDER_SPEC(9)
    NAME_ID_HOLDER_SPEC(8)
    NAME_ID_HOLDER_SPEC(7)
    NAME_ID_HOLDER_SPEC(6)
    NAME_ID_HOLDER_SPEC(5)
    NAME_ID_HOLDER_SPEC(4)
    NAME_ID_HOLDER_SPEC(3)
    NAME_ID_HOLDER_SPEC(2)
    NAME_ID_HOLDER_SPEC(1)
    
    template <>
    struct CNameIdHolder<0>
    {
        template <DL_REPEAT_N(MAX_DL_REPEAT, DWORD n)>
        struct CNameIdHolderImpl
        {
            static LPCTSTR GetStr()
            {
                return NULL;
            }
        };
    };
    
    
    template <DL_REPEAT_DEF_N(MAX_DL_REPEAT, DWORD n, = 0)>
    struct CNameId
    {
        enum
        {
            DL_REPEAT_PARAM_N(MAX_DL_REPEAT, m_n, =n),
            count   = (!n1) ? 0: (!n2) ? 1: (!n3) ?2: (!n4) ? 3: (!n5) ? 4: (!n6) ? 5: (!n7) ? 6: (!n8) ? 7: 
                      (!n9) ? 8: (!n10) ? 9: (!n11) ?10: (!n12) ? 11: (!n13) ? 12: (!n14) ? 13: (!n15) ? 14: (!n16) ? 15: 16
        };
        static LPCTSTR GetStr()
        {
            return CNameIdHolder<count>::CNameIdHolderImpl<DL_REPEAT_N(MAX_DL_REPEAT, n)>::GetStr();
        }
    };
    
    template <class Name>
    class CModule
    {
    public:
        HMODULE m_hModule;
        typedef CModule<Name> type;
        typedef Name          name_type;
        static type &GetModule()
        {
            static type Module;
            return Module;
        }
        ~CModule()
        {
            if (m_hModule)
                FreeLibrary(m_hModule);
        }
    private:
        CModule()
        {
            m_hModule = LoadLibrary(name_type::GetStr());
        }
    };
    
    
    template <class Module, class Name, class Proxy>
    class CDynFunction
    {
    public:
        typedef CDynFunction<Module, Name, Proxy> type;
        typedef Proxy                              proxy_type;
        typedef Module                              module_type;
        typedef Name                              name_type;
        
        static proxy_type::fun_type &GetProxy()
        {
            static proxy_type::fun_type proxy = proxy_type::Proxy<type>::ProxyFun;
            return proxy;
        }
        static BOOL InitFunction()
        {
            HMODULE hModule = Module::GetModule().m_hModule;
            if (hModule)
            {
                FARPROC pFunction = GetProcAddress(hModule, name_type::GetStr());
                if (pFunction)
                {
                    GetProxy() = (proxy_type::fun_type)pFunction;
                    return TRUE;
                }
            }
            return FALSE;
        }
    };
    
    template<class R, R value = R()>
    struct FunProxyValuePolicy
    {
        template <class DynFunction> 
        struct Dummy
        {
            static DynFunction::proxy_type::ret_type MakeReturn()
            {
                return value;
            }
        };
    };
    
    struct CDynFunException
    {
        CDynFunException();
        CDynFunException(LPCTSTR sMessage):m_sMessage(sMessage)
        {
        }
        CDynFunException(const CDynFunException &other):m_sMessage(other.m_sMessage)
        {
        }
        CDynFunException &operator = (const CDynFunException &other)
        {
            m_sMessage = other.m_sMessage;
            return *this;
        }
        CString m_sMessage;
    };
    
    template<class E = CDynFunException>
    struct FunProxyThrowPolicy
    {
        template <class DynFunction> 
        struct Dummy
        {
            static DynFunction::proxy_type::ret_type MakeReturn()
            {
                CString sMessage;
                sMessage.Format(_T("Can'n load procedure <%s>: %d"), DynFunction::name_type::GetStr(), GetLastError());
                throw E(sMessage);
                return 0;
            }
        };
    };
    
    
    
    #define FUN_PROXY(n) DL_CAT(FunProxy,n)
    
    #define DECLARE_FUN_PROXY(param_count) \
    template <typename R, DL_REPEAT_N(param_count, typename P), class Policy = FunProxyValuePolicy<R> > struct FUN_PROXY(param_count)\
    {\
        typedef R (WINAPI *fun_type)(DL_REPEAT_N(param_count, P));\
        typedef R ret_type;\
        template <class DynFunction> struct Proxy\
        {\
            static R WINAPI ProxyFun(DL_REPEAT_PARAM_N(param_count, P, v))\
            {\
                if (DynFunction::InitFunction())\
                    return DynFunction::GetProxy()(DL_REPEAT_N(param_count, v));\
                return Policy::Dummy<DynFunction>::MakeReturn();\
            }\
        };\
    };
    
    
    DECLARE_FUN_PROXY(1)
    DECLARE_FUN_PROXY(2)
    DECLARE_FUN_PROXY(3)
    DECLARE_FUN_PROXY(4)
    DECLARE_FUN_PROXY(5)
    DECLARE_FUN_PROXY(6)
    DECLARE_FUN_PROXY(7)
    DECLARE_FUN_PROXY(8)
    DECLARE_FUN_PROXY(9)
    DECLARE_FUN_PROXY(10)
    DECLARE_FUN_PROXY(11)
    DECLARE_FUN_PROXY(12)
    DECLARE_FUN_PROXY(13)
    DECLARE_FUN_PROXY(14)
    DECLARE_FUN_PROXY(15)
    DECLARE_FUN_PROXY(16)
    
    // usefull macro's
    
    #define USE_MODULE_BEGIN(nmspace, NameId) \
    namespace nmspace \
    {\
        typedef CModule< CNameId< /NameId/ > > module_type;
    
    #define USE_MODULE_END \
    };
    
    
    
    #define DECLARE_FUN_P1(Name, NameId, R, P1) \
    static R (WINAPI *&Name)(P1) = CDynFunction<module_type, CNameId< /NameId/ >, FUN_PROXY(1)<R, P1> >::GetProxy();
    
    
    #define DECLARE_FUN_P1_ERR(Name, NameId, R, P1, E)\
    static R (WINAPI *&Name)(P1) = CDynFunction<module_type, CNameId< /NameId/ >, FUN_PROXY(1)<R, P1, FunProxyValuePolicy<R, E> > >::GetProxy();
     
    #define DECLARE_FUN_P1_THROW(Name, NameId, R, P1)\
    static R (WINAPI *&Name)(P1) = CDynFunction<module_type, CNameId< /NameId/ >, FUN_PROXY(1)<R, P1, FunProxyThrowPolicy<> > >::GetProxy();
    
    #endif
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[2]: Pure C++ delay load
    От: _nn_ www.nemerleweb.com
    Дата: 17.08.04 07:24
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Большое спасибо _nn_ за проявленную инициативу, в связи с чем выкладываю обновление до v 1.03

    AS>Специализация выполнена на макросах, максимальная длина строки увеличена до 64 символов, можно без особых изменений в коде и больше.
    AS>На макросы определения функций терпения не хватило, а common вариант не придумался — если есть мысли, будет интересно выслушать.

    Есть идея, но она мне кажется неосуществима.
    Что-то такое :
    #define CAT_0(x) CAT(x,0)
    //...
    #define CAT_n(x) CAT(x,n)
    
    #define REPEAT_N(nfrom,nto,x) CAT(CAT_,nfrom)(x) /* как-нибудь перебор */ CAT(CAT_(nto))(x)


    Вместо _T('\0') лучше писать просто 0, меньше проблем, вдобавок макрос _T определяется в commctrl.h, а если он не будет подключен то будут проблемы.

    Есть еще предложение убрать CString из CDynFunException, таким образом сделать так чтобы можно было использовать код в программах WinAPI.
    struct CDynFunException
    {
        CDynFunException() : m_sMessage(0) {}
        CDynFunException(LPCTSTR sMessage) : m_sMessage(0)
        { SetMessage(sMessage); }
        CDynFunException(const CDynFunException &other) : m_sMessage(0)
        { SetMessage(other.sMessage); }
        CDynFunException &operator = (const CDynFunException &other)
        {
            SetMessage(other.sMessage);
            return *this;
        }
        ~CDynFunExecption()
        { delete[] m_sMessage; }
    
        const TCHAR* GetMessage() { return m_sMessage; }
    private:
        void SetMessage(LPCTSTR sMessage)
        {
           delete[] m_sMessage;
           m_sMessage = new TCHAR[lstrlen(other.m_sMessage)+1];
           lstrcpy(m_sMessage,other.m_sMessage);
        }
        TCHAR* m_sMessage;
    };


    FunProxyThrowPolicy использует тоже CString, однако он выкидывает это как исключение.
    Поэтому пользователю придется заботиться об уничтожении выделенной памяти или же сделать обертку для этого.
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[3]: Pure C++ delay load
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 18.08.04 13:22
    Оценка:
    __>Есть идея, но она мне кажется неосуществима.
    __>Что-то такое :
    __>
    __>#define CAT_0(x) CAT(x,0)
    __>//...
    __>#define CAT_n(x) CAT(x,n)
    
    __>#define REPEAT_N(nfrom,nto,x) CAT(CAT_,nfrom)(x) /* как-нибудь перебор */ CAT(CAT_(nto))(x)
    __>


    А зачем это предлагается, я что то не понял.

    __>Вместо _T('\0') лучше писать просто 0, меньше проблем, вдобавок макрос _T определяется в commctrl.h, а если он не будет подключен то будут проблемы.


    Нет, это в tchar.h, и проблем не будет

    __>Есть еще предложение убрать CString из CDynFunException, таким образом сделать так чтобы можно было использовать код в программах WinAPI.

    __>
    __>struct CDynFunException
    __>{
    __>    CDynFunException() : m_sMessage(0) {}
    __>    CDynFunException(LPCTSTR sMessage) : m_sMessage(0)
    __>    { SetMessage(sMessage); }
    __>    CDynFunException(const CDynFunException &other) : m_sMessage(0)
    __>    { SetMessage(other.sMessage); }
    __>    CDynFunException &operator = (const CDynFunException &other)
    __>    {
    __>        SetMessage(other.sMessage);
    __>        return *this;
    __>    }
    __>    ~CDynFunExecption()
    __>    { delete[] m_sMessage; }
    
    __>    const TCHAR* GetMessage() { return m_sMessage; }
    __>private:
    __>    void SetMessage(LPCTSTR sMessage)
    __>    {
    __>       delete[] m_sMessage;
    __>       m_sMessage = new TCHAR[lstrlen(other.m_sMessage)+1];
    __>       lstrcpy(m_sMessage,other.m_sMessage);
    __>    }
    __>    TCHAR* m_sMessage;
    __>};
    __>


    new может сам вызывать эксепшен — начинаем тихо форматировать диск Конечно, лучше использовать malloc\free.

    __>FunProxyThrowPolicy использует тоже CString, однако он выкидывает это как исключение.

    __>Поэтому пользователю придется заботиться об уничтожении выделенной памяти или же сделать обертку для этого.

    Там можно вообще выделять буфер не динамически, а на стеке — максимальный размер строки с именем функции известен в FunProxyThrowPolicy::Dummy::MakeReturn через DynFunction::name_type во время компиляции, размер буфера под целое тоже. Просто лень было (да и важнее проблемы были и есть) — я политики для исключений сделал больше просто для того, дабы показать, что очень просто расширить предлагаемый функционал.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[4]: Pure C++ delay load
    От: _nn_ www.nemerleweb.com
    Дата: 18.08.04 15:41
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>А зачем это предлагается, я что то не понял.

    Да так тупая затея

    __>>Вместо _T('\0') лучше писать просто 0, меньше проблем, вдобавок макрос _T определяется в commctrl.h, а если он не будет подключен то будут проблемы.


    AS>Нет, это в tchar.h, и проблем не будет

    Да, там тоже есть, а если он не подключен что делать ?
    Так что 0, а не _T('\0').

    __>>Есть еще предложение убрать CString из CDynFunException, таким образом сделать так чтобы можно было использовать код в программах WinAPI.

    __>>
    <skip>
    __>>


    AS>new может сам вызывать эксепшен — начинаем тихо форматировать диск Конечно, лучше использовать malloc\free.

    Проверку исключения я убрал, так как суть не в нем.
    А вообще malloc подойдет конечно
    Будет такое :
    struct CDynFunException
    {
        CDynFunException() : m_sMessage(0) {}
        CDynFunException(LPCTSTR sMessage) : m_sMessage(0)
        { SetMessage(sMessage); }
        CDynFunException(const CDynFunException& other) : m_sMessage(0)
        { SetMessage(other.sMessage); }
        CDynFunException &operator=(const CDynFunException &other)
        {
            SetMessage(other.sMessage);
            return *this;
        }
        ~CDynFunExecption()
        { free(m_sMessage); }
    
        const TCHAR* GetMessage() { return m_sMessage; }
    private:
        void SetMessage(LPCTSTR sMessage)
        {
           free(m_sMessage);
           m_sMessage = malloc(lstrlen(other.m_sMessage)+1);
           lstrcpy(m_sMessage,other.m_sMessage);
        }
        TCHAR* m_sMessage;
    };


    __>>FunProxyThrowPolicy использует тоже CString, однако он выкидывает это как исключение.

    __>>Поэтому пользователю придется заботиться об уничтожении выделенной памяти или же сделать обертку для этого.

    AS>Там можно вообще выделять буфер не динамически, а на стеке — максимальный размер строки с именем функции известен в FunProxyThrowPolicy::Dummy::MakeReturn через DynFunction::name_type во время компиляции, размер буфера под целое тоже. Просто лень было (да и важнее проблемы были и есть) — я политики для исключений сделал больше просто для того, дабы показать, что очень просто расширить предлагаемый функционал.

    Ясно.
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re: Код v1.04
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 20.08.04 11:00
    Оценка:
    Собственно, версия 1.04

    Список изменений:


    To do


    Как обычно — ждем сообщений о багах, предложений по фичам и прочее-прочее.


    //    delayimphlp.h: Delay import helper
    //    Developer:    Andrew Solodovnikov
    //    E-mail:        none
    //    Date:        03.08.2004
    
    #ifndef    __DELAYIMPHLP_H__
    #define __DELAYIMPHLP_H__
    
    #define DL_CAT_(x,y) x##y
    #define DL_CAT(x,y) DL_CAT_(x,y)
    
    #define MAX_DL_REPEAT 16
    #define DL_COMMA() ,
    #define DL_EMPTY() 
    
    // DL_REPEAT_N
    #define DL_REPEAT_IMPL_N_0(x, d) 
    #define DL_REPEAT_IMPL_N_1(x, d) DL_CAT(x,1)
    #define DL_REPEAT_IMPL_N_2(x, d) DL_REPEAT_IMPL_N_1(x, d)d()  DL_CAT(x,2)
    #define DL_REPEAT_IMPL_N_3(x, d) DL_REPEAT_IMPL_N_2(x, d)d()  DL_CAT(x,3)
    #define DL_REPEAT_IMPL_N_4(x, d) DL_REPEAT_IMPL_N_3(x, d)d()  DL_CAT(x,4)
    #define DL_REPEAT_IMPL_N_5(x, d) DL_REPEAT_IMPL_N_4(x, d)d()  DL_CAT(x,5)
    #define DL_REPEAT_IMPL_N_6(x, d) DL_REPEAT_IMPL_N_5(x, d)d()  DL_CAT(x,6)
    #define DL_REPEAT_IMPL_N_7(x, d) DL_REPEAT_IMPL_N_6(x, d)d()  DL_CAT(x,7)
    #define DL_REPEAT_IMPL_N_8(x, d) DL_REPEAT_IMPL_N_7(x, d)d()  DL_CAT(x,8)
    #define DL_REPEAT_IMPL_N_9(x, d) DL_REPEAT_IMPL_N_8(x, d)d()  DL_CAT(x,9)
    #define DL_REPEAT_IMPL_N_10(x, d) DL_REPEAT_IMPL_N_9(x, d)d()  DL_CAT(x,10)
    #define DL_REPEAT_IMPL_N_11(x, d) DL_REPEAT_IMPL_N_10(x, d)d()  DL_CAT(x,11)
    #define DL_REPEAT_IMPL_N_12(x, d) DL_REPEAT_IMPL_N_11(x, d)d()  DL_CAT(x,12)
    #define DL_REPEAT_IMPL_N_13(x, d) DL_REPEAT_IMPL_N_12(x, d)d()  DL_CAT(x,13)
    #define DL_REPEAT_IMPL_N_14(x, d) DL_REPEAT_IMPL_N_13(x, d)d()  DL_CAT(x,14)
    #define DL_REPEAT_IMPL_N_15(x, d) DL_REPEAT_IMPL_N_14(x, d)d()  DL_CAT(x,15)
    #define DL_REPEAT_IMPL_N_16(x, d) DL_REPEAT_IMPL_N_15(x, d)d()  DL_CAT(x,16)
    
    #define DL_REPEAT_IMPL_N(n, x, d) DL_CAT(DL_REPEAT_IMPL_N_,n)(x, d)
    
    #define DL_REPEAT_N(n,x) DL_REPEAT_IMPL_N(n, x, DL_COMMA)
    
    // DL_REPEAT_PARAM_N
    #define DL_REPEAT_PARAM_IMPL_N0(n, m, d1, d2)
    #define DL_REPEAT_PARAM_IMPL_N1(n, m, d1, d2) DL_CAT(n,1) DL_CAT(m,1)
    #define DL_REPEAT_PARAM_IMPL_N2(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N1(n, m, d1, d2)d1() DL_CAT(n,2)d2() DL_CAT(m,2)
    #define DL_REPEAT_PARAM_IMPL_N3(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N2(n, m, d1, d2)d1() DL_CAT(n,3)d2() DL_CAT(m,3)
    #define DL_REPEAT_PARAM_IMPL_N4(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N3(n, m, d1, d2)d1() DL_CAT(n,4)d2() DL_CAT(m,4)
    #define DL_REPEAT_PARAM_IMPL_N5(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N4(n, m, d1, d2)d1() DL_CAT(n,5)d2() DL_CAT(m,5)
    #define DL_REPEAT_PARAM_IMPL_N6(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N5(n, m, d1, d2)d1() DL_CAT(n,6)d2() DL_CAT(m,6)
    #define DL_REPEAT_PARAM_IMPL_N7(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N6(n, m, d1, d2)d1() DL_CAT(n,7)d2() DL_CAT(m,7)
    #define DL_REPEAT_PARAM_IMPL_N8(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N7(n, m, d1, d2)d1() DL_CAT(n,8)d2() DL_CAT(m,8)
    #define DL_REPEAT_PARAM_IMPL_N9(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N8(n, m, d1, d2)d1() DL_CAT(n,9)d2() DL_CAT(m,9)
    #define DL_REPEAT_PARAM_IMPL_N10(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N9(n, m, d1, d2)d1() DL_CAT(n,10)d2() DL_CAT(m,10)
    #define DL_REPEAT_PARAM_IMPL_N11(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N10(n, m, d1, d2)d1() DL_CAT(n,11)d2() DL_CAT(m,11)
    #define DL_REPEAT_PARAM_IMPL_N12(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N11(n, m, d1, d2)d1() DL_CAT(n,12)d2() DL_CAT(m,12)
    #define DL_REPEAT_PARAM_IMPL_N13(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N12(n, m, d1, d2)d1() DL_CAT(n,13)d2() DL_CAT(m,13)
    #define DL_REPEAT_PARAM_IMPL_N14(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N13(n, m, d1, d2)d1() DL_CAT(n,14)d2() DL_CAT(m,14)
    #define DL_REPEAT_PARAM_IMPL_N15(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N14(n, m, d1, d2)d1() DL_CAT(n,15)d2() DL_CAT(m,15)
    #define DL_REPEAT_PARAM_IMPL_N16(n,m, d1, d2) DL_REPEAT_PARAM_IMPL_N15(n, m, d1, d2)d1() DL_CAT(n,16)d2() DL_CAT(m,16)
    
    #define DL_REPEAT_PARAM_IMPL_N(c, n, m, d1, d2) DL_CAT(DL_REPEAT_PARAM_IMPL_N,c)(n, m, d1, d2)
    
    #define DL_REPEAT_PARAM_N(c, n, m) DL_REPEAT_PARAM_IMPL_N(c, n, m, DL_COMMA, DL_EMPTY)
    
    // DL_REPEAT_DEF_IMPL_N
    #define DL_REPEAT_DEF_IMPL_N0(n, def, d)
    #define DL_REPEAT_DEF_IMPL_N1(n, def, d) DL_CAT(DL_CAT(n,1), def)
    #define DL_REPEAT_DEF_IMPL_N2(n, def, d) DL_REPEAT_DEF_IMPL_N1(n, def, d)d() DL_CAT(DL_CAT(n,2), def)
    #define DL_REPEAT_DEF_IMPL_N3(n, def, d) DL_REPEAT_DEF_IMPL_N2(n, def, d)d() DL_CAT(DL_CAT(n,3), def)
    #define DL_REPEAT_DEF_IMPL_N4(n, def, d) DL_REPEAT_DEF_IMPL_N3(n, def, d)d() DL_CAT(DL_CAT(n,4), def)
    #define DL_REPEAT_DEF_IMPL_N5(n, def, d) DL_REPEAT_DEF_IMPL_N4(n, def, d)d() DL_CAT(DL_CAT(n,5), def)
    #define DL_REPEAT_DEF_IMPL_N6(n, def, d) DL_REPEAT_DEF_IMPL_N5(n, def, d)d() DL_CAT(DL_CAT(n,6), def)
    #define DL_REPEAT_DEF_IMPL_N7(n, def, d) DL_REPEAT_DEF_IMPL_N6(n, def, d)d() DL_CAT(DL_CAT(n,7), def)
    #define DL_REPEAT_DEF_IMPL_N8(n, def, d) DL_REPEAT_DEF_IMPL_N7(n, def, d)d() DL_CAT(DL_CAT(n,8), def)
    #define DL_REPEAT_DEF_IMPL_N9(n, def, d) DL_REPEAT_DEF_IMPL_N8(n, def, d)d() DL_CAT(DL_CAT(n,9), def)
    #define DL_REPEAT_DEF_IMPL_N10(n, def, d) DL_REPEAT_DEF_IMPL_N9(n, def, d)d() DL_CAT(DL_CAT(n,10), def)
    #define DL_REPEAT_DEF_IMPL_N11(n, def, d) DL_REPEAT_DEF_IMPL_N10(n, def, d)d() DL_CAT(DL_CAT(n,11), def)
    #define DL_REPEAT_DEF_IMPL_N12(n, def, d) DL_REPEAT_DEF_IMPL_N11(n, def, d)d() DL_CAT(DL_CAT(n,12), def)
    #define DL_REPEAT_DEF_IMPL_N13(n, def, d) DL_REPEAT_DEF_IMPL_N12(n, def, d)d() DL_CAT(DL_CAT(n,13), def)
    #define DL_REPEAT_DEF_IMPL_N14(n, def, d) DL_REPEAT_DEF_IMPL_N13(n, def, d)d() DL_CAT(DL_CAT(n,14), def)
    #define DL_REPEAT_DEF_IMPL_N15(n, def, d) DL_REPEAT_DEF_IMPL_N14(n, def, d)d() DL_CAT(DL_CAT(n,15), def)
    #define DL_REPEAT_DEF_IMPL_N16(n, def, d) DL_REPEAT_DEF_IMPL_N15(n, def, d)d() DL_CAT(DL_CAT(n,16), def)
    
    #define DL_REPEAT_DEF_IMPL_N(c, n, def, d) DL_CAT(DL_REPEAT_DEF_IMPL_N,c)(n, def, d)
    
    #define DL_REPEAT_DEF_N(c, n, def) DL_REPEAT_DEF_IMPL_N(c, n, def, DL_COMMA)
    
    // DL_REPEAT_MACRO_N
    
    #define DL_REPEAT_MACRO_IMPL_N0(m, p, d)
    #define DL_REPEAT_MACRO_IMPL_N1(m, p, d) m(p,1)
    #define DL_REPEAT_MACRO_IMPL_N2(m, p, d) DL_REPEAT_MACRO_IMPL_N1(m, p, d)d() m(p,2)
    #define DL_REPEAT_MACRO_IMPL_N3(m, p, d) DL_REPEAT_MACRO_IMPL_N2(m, p, d)d() m(p,3)
    #define DL_REPEAT_MACRO_IMPL_N4(m, p, d) DL_REPEAT_MACRO_IMPL_N3(m, p, d)d() m(p,4)
    #define DL_REPEAT_MACRO_IMPL_N5(m, p, d) DL_REPEAT_MACRO_IMPL_N4(m, p, d)d() m(p,5)
    #define DL_REPEAT_MACRO_IMPL_N6(m, p, d) DL_REPEAT_MACRO_IMPL_N5(m, p, d)d() m(p,6)
    #define DL_REPEAT_MACRO_IMPL_N7(m, p, d) DL_REPEAT_MACRO_IMPL_N6(m, p, d)d() m(p,7)
    #define DL_REPEAT_MACRO_IMPL_N8(m, p, d) DL_REPEAT_MACRO_IMPL_N7(m, p, d)d() m(p,8)
    #define DL_REPEAT_MACRO_IMPL_N9(m, p, d) DL_REPEAT_MACRO_IMPL_N8(m, p, d)d() m(p,9)
    #define DL_REPEAT_MACRO_IMPL_N10(m, p, d) DL_REPEAT_MACRO_IMPL_N9(m, p, d)d() m(p,10)
    #define DL_REPEAT_MACRO_IMPL_N11(m, p, d) DL_REPEAT_MACRO_IMPL_N10(m, p, d)d() m(p,11)
    #define DL_REPEAT_MACRO_IMPL_N12(m, p, d) DL_REPEAT_MACRO_IMPL_N11(m, p, d)d() m(p,12)
    #define DL_REPEAT_MACRO_IMPL_N13(m, p, d) DL_REPEAT_MACRO_IMPL_N12(m, p, d)d() m(p,13)
    #define DL_REPEAT_MACRO_IMPL_N14(m, p, d) DL_REPEAT_MACRO_IMPL_N13(m, p, d)d() m(p,14)
    #define DL_REPEAT_MACRO_IMPL_N15(m, p, d) DL_REPEAT_MACRO_IMPL_N14(m, p, d)d() m(p,15)
    #define DL_REPEAT_MACRO_IMPL_N16(m, p, d) DL_REPEAT_MACRO_IMPL_N15(m, p, d)d() m(p,16)
    
    #define DL_REPEAT_MACRO_IMPL_N(c, m, p, d) DL_CAT(DL_REPEAT_MACRO_IMPL_N,c)(m,p, d)
    #define DL_REPEAT_MACRO_N(c, m, p) DL_REPEAT_MACRO_IMPL_N(c, m, p, DL_COMMA)
    
    #define FLATTEN_STR3(val) (((val) > 0xFFFFFF) ? (val) : 0)
    #define FLATTEN_STR2(val) (((val) > 0xFFFFFF) ? (val) : FLATTEN_STR3(val << 8))
    #define FLATTEN_STR1(val) (((val) > 0xFFFFFF) ? (val) : FLATTEN_STR2(val << 8))
    #define FLATTEN_STR0(val) (((val) > 0xFFFFFF) ? (val) : FLATTEN_STR1(val << 8))
    
    #define FLATTEN_STR_(val) \
            (TCHAR)HIBYTE(HIWORD(val)), (TCHAR)LOBYTE(HIWORD(val)), (TCHAR)HIBYTE(LOWORD(val)), (TCHAR)LOBYTE(LOWORD(val))
    
    #define FLATTEN_STR(val, num) FLATTEN_STR_(FLATTEN_STR0(DL_CAT(val, num)))
    
    #pragma warning (disable: 4786)
    
    template <int count>
    struct CNameIdHolder
    {
        template <DL_REPEAT_N(MAX_DL_REPEAT, DWORD n)>
        struct CNameIdHolderImpl
        {
            static LPCTSTR GetStr()
            {
                static const TCHAR szBuffer[] = {
                                                    DL_REPEAT_MACRO_N(MAX_DL_REPEAT, FLATTEN_STR, n),
                                                    _T('\0')
                                                };
                return szBuffer;
            }
        };
    };
    
    #define NAME_ID_HOLDER_SPEC(num)\
    template <>\
    struct CNameIdHolder<num>\
    {\
        template <DL_REPEAT_N(MAX_DL_REPEAT, DWORD n)>\
        struct CNameIdHolderImpl\
        {\
            static LPCTSTR GetStr()\
            {\
                static const TCHAR szBuffer[] = {\
                                                    DL_REPEAT_MACRO_N(num, FLATTEN_STR, n),\
                                                    _T('\0')\
                                                };\
                return szBuffer;\
            }\
        };\
    };
    
    NAME_ID_HOLDER_SPEC(15)
    NAME_ID_HOLDER_SPEC(14)
    NAME_ID_HOLDER_SPEC(13)
    NAME_ID_HOLDER_SPEC(12)
    NAME_ID_HOLDER_SPEC(11)
    NAME_ID_HOLDER_SPEC(10)
    NAME_ID_HOLDER_SPEC(9)
    NAME_ID_HOLDER_SPEC(8)
    NAME_ID_HOLDER_SPEC(7)
    NAME_ID_HOLDER_SPEC(6)
    NAME_ID_HOLDER_SPEC(5)
    NAME_ID_HOLDER_SPEC(4)
    NAME_ID_HOLDER_SPEC(3)
    NAME_ID_HOLDER_SPEC(2)
    NAME_ID_HOLDER_SPEC(1)
    
    template <>
    struct CNameIdHolder<0>
    {
        template <DL_REPEAT_N(MAX_DL_REPEAT, DWORD n)>
        struct CNameIdHolderImpl
        {
            static LPCTSTR GetStr()
            {
                return NULL;
            }
        };
    };
    
    #define NN_REP_COUNT_M(p, n) (!DL_CAT(p,n)) ? (n-1):
    
    template <DL_REPEAT_DEF_N(MAX_DL_REPEAT, DWORD n, = 0)>
    struct CNameId
    {
        enum
        {
            DL_REPEAT_PARAM_N(MAX_DL_REPEAT, m_n, =n),
            count   = DL_REPEAT_MACRO_IMPL_N(MAX_DL_REPEAT, NN_REP_COUNT_M, n, DL_EMPTY) MAX_DL_REPEAT,
            length  = count * sizeof(DWORD)
        };
        static LPCTSTR GetStr()
        {
            return CNameIdHolder<count>::template CNameIdHolderImpl<DL_REPEAT_N(MAX_DL_REPEAT, n)>::GetStr();
        }
    };
    
    template <class Name>
    class CModule
    {
    public:
        HMODULE m_hModule;
        typedef CModule<Name> type;
        typedef Name          name_type;
        static type &GetModule()
        {
            static type Module;
            return Module;
        }
        ~CModule()
        {
            if (m_hModule)
                FreeLibrary(m_hModule);
        }
    private:
        CModule()
        {
            m_hModule = LoadLibrary(name_type::GetStr());
        }
    };
    
    
    template <class Module, class Name, class Proxy>
    class CDynFunction
    {
    public:
        typedef CDynFunction<Module, Name, Proxy> type;
        typedef Proxy                              proxy_type;
        typedef Module                              module_type;
        typedef Name                              name_type;
        
        static proxy_type::fun_type &GetProxy()
        {
            static proxy_type::fun_type proxy = proxy_type::template Proxy<type>::ProxyFun;
            return proxy;
        }
        static BOOL InitFunction()
        {
            HMODULE hModule = Module::GetModule().m_hModule;
            if (hModule)
            {
                FARPROC pFunction = GetProcAddress(hModule, name_type::GetStr());
                if (pFunction)
                {
                    GetProxy() = (proxy_type::fun_type)pFunction;
                    return TRUE;
                }
            }
            return FALSE;
        }
    };
    
    
    
    struct CDynFunException
    {
        CDynFunException(): m_sMessage(NULL)
        {
        };
        ~CDynFunException()
        {
            free(m_sMessage);
        };
        CDynFunException(LPCTSTR sMessage):m_sMessage(NULL)
        {
            SetMessage(sMessage);
        }
        CDynFunException(const CDynFunException &other):m_sMessage(NULL)
        {
            SetMessage(other.m_sMessage);
        }
        CDynFunException &operator = (const CDynFunException &other)
        {
            SetMessage(other.m_sMessage);
            return *this;
        }
        void SetMessage(LPCTSTR sMessage)
        {
            free(m_sMessage);
            m_sMessage = (LPTSTR)malloc((_tcslen(sMessage) + 1) * sizeof(TCHAR));
            if (m_sMessage)
                _tcscpy(m_sMessage, sMessage);
        }
        LPTSTR m_sMessage;
    };
    
    template <class R> struct FunProxyThrowRetTypeTrait
    {
        template <class F>
        struct FunctionTraitImpl
        {
            static R MakeReturn()
            {
                F::MakeReturnImpl();
                return R();
            }
        };
    };
    
    template <> struct FunProxyThrowRetTypeTrait<void>
    {
        template <class F>
        struct FunctionTraitImpl
        {
            static void MakeReturn()
            {
                F::MakeReturnImpl();
            }
        };
    };
    
    template<class E = CDynFunException>
    struct FunProxyThrowPolicy
    {
        template <class DynFunction> 
        struct FunctionTrait:public FunProxyThrowRetTypeTrait<DynFunction::proxy_type::ret_type>::template FunctionTraitImpl<FunctionTrait<DynFunction> >
        {
            static void MakeReturnImpl()
            {
                TCHAR szMessage[DynFunction::name_type::length + 64];
                _stprintf(szMessage, _T("Can'n resolve procedure <%s>: %d"), DynFunction::name_type::GetStr(), GetLastError());
                throw E(szMessage);
            }
        };
    };
    
    
    //  we need not implement void return type value policy, 
    //  coz void function can only throw on error
    
    template<class R, R value = R()>
    struct FunProxyValuePolicy
    {
        template <class DynFunction> 
        struct FunctionTrait
        {
            static DynFunction::proxy_type::ret_type MakeReturn()
            {
                return value;
            }
        };
    };
    
    
    #define FUN_PROXY(n) DL_CAT(FunProxy,n)
    #define FUN_PROXY_IMPL(n) DL_CAT(FUN_PROXY(n),Impl)
    
    #define DECLARE_FUN_PROXY(param_count) \
    template <typename R> struct FUN_PROXY_IMPL(param_count)\
    {\
        template <class DynFunction, DL_REPEAT_N(param_count, typename P), class Policy> struct RetProxy\
        {\
            static R WINAPI ProxyFun(DL_REPEAT_PARAM_N(param_count, P, v))\
            {\
                if (DynFunction::InitFunction())\
                    return DynFunction::GetProxy()(DL_REPEAT_N(param_count, v));\
                return Policy::template FunctionTrait<DynFunction>::MakeReturn();\
            }\
        };\
    };\
    \
    template <> struct FUN_PROXY_IMPL(param_count) <void>\
    {\
        template <class DynFunction, DL_REPEAT_N(param_count, typename P), class Policy> struct RetProxy\
        {\
            static R WINAPI ProxyFun(DL_REPEAT_PARAM_N(param_count, P, v))\
            {\
                if (DynFunction::InitFunction())\
                    DynFunction::GetProxy()(DL_REPEAT_N(param_count, v));\
                else\
                    Policy::template FunctionTrait<DynFunction>::MakeReturn();\
            }\
        };\
    };\
    \
    template <typename R, DL_REPEAT_N(param_count, typename P), class Policy = FunProxyValuePolicy<R> > struct FUN_PROXY(param_count)\
    {\
        typedef R (WINAPI *fun_type)(DL_REPEAT_N(param_count, P));\
        typedef R ret_type;\
        template <class DynFunction> struct Proxy:public FUN_PROXY_IMPL(param_count)<R>::template RetProxy<DynFunction, DL_REPEAT_N(param_count, P), Policy>\
        {\
        };\
    };
    
    DECLARE_FUN_PROXY(1)
    DECLARE_FUN_PROXY(2)
    DECLARE_FUN_PROXY(3)
    DECLARE_FUN_PROXY(4)
    DECLARE_FUN_PROXY(5)
    DECLARE_FUN_PROXY(6)
    DECLARE_FUN_PROXY(7)
    DECLARE_FUN_PROXY(8)
    DECLARE_FUN_PROXY(9)
    DECLARE_FUN_PROXY(10)
    DECLARE_FUN_PROXY(11)
    DECLARE_FUN_PROXY(12)
    DECLARE_FUN_PROXY(13)
    DECLARE_FUN_PROXY(14)
    DECLARE_FUN_PROXY(15)
    DECLARE_FUN_PROXY(16)
    
    // usefull macro's
    
    #define USE_MODULE_BEGIN(nmspace, NameId) \
    namespace nmspace \
    {\
        typedef CModule< CNameId< /NameId/ > > module_type;
    
    #define USE_MODULE_END \
    };
    
    
    
    #define DECLARE_FUN_P1(Name, NameId, R, P1) \
    static R (WINAPI *&Name)(P1) = CDynFunction<module_type, CNameId< /NameId/ >, FUN_PROXY(1)<R, P1> >::GetProxy();
    
    
    #define DECLARE_FUN_P1_ERR(Name, NameId, R, P1, E)\
    static R (WINAPI *&Name)(P1) = CDynFunction<module_type, CNameId< /NameId/ >, FUN_PROXY(1)<R, P1, FunProxyValuePolicy<R,E> > >::GetProxy();
     
    #define DECLARE_FUN_P1_THROW(Name, NameId, R, P1)\
    static R (WINAPI *&Name)(P1) = CDynFunction<module_type, CNameId< /NameId/ >, FUN_PROXY(1)<R, P1, FunProxyThrowPolicy<> > >::GetProxy();
    
    #endif
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[2]: Код v1.04
    От: _nn_ www.nemerleweb.com
    Дата: 20.08.04 13:20
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Собственно, версия 1.04


    AS>Список изменений:


    AS>

    Наверное все же стоит в структуре CDynFunException член m_sMessage сделать приватным, мало ли что будет
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[3]: Код v1.04
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 20.08.04 13:31
    Оценка:
    __>Наверное все же стоит в структуре CDynFunException член m_sMessage сделать приватным, мало ли что будет

    Done. Впрочем, когда выбрасывается исключение, то мало уже не будет
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[2]: Код v1.04
    От: _nn_ www.nemerleweb.com
    Дата: 20.08.04 18:40
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>

    Компиляторонезависимый будет так : (при потере функциональности )
    #define DECLARE_FUN1_P1(Name, NameId0, R, P1) \
     static R (WINAPI *&Name)(P1) = CDynFunction<module_type, CNameId<NameId0>, FUN_PROXY(1)<R, P1> >::GetProxy();
    
    #define DECLARE_FUN2_P1(Name, NameId0, NameId1, R, P1) \
     static R (WINAPI *&Name)(P1) = CDynFunction<module_type, CNameId<NameId0,NameId1>, FUN_PROXY(1)<R, P1> >::GetProxy();
    
    //...


    Или же так:
    #define DECLARE_FUN1_P1(Name, NameId0, R, P1) \
     static R (WINAPI *&Name)(REPEAT_N(1,P)) = CDynFunction<module_type, CNameId<REPEAT_N(0,NameId)>, FUN_PROXY(1)<R, REPEAT_N(1,P)> >::GetProxy();
    
    #define DECLARE_FUN2_P1(Name, NameId0, NameId1, R, P1) \
     static R (WINAPI *&Name)(REPEAT_N(1,P)) = CDynFunction<module_type, CNameId<REPEAT_N(1,NameId)>, FUN_PROXY(1)<R, REPEAT_N(1,P)> >::GetProxy();
    //...


    Идея думаю ясна.

    Есть идея, только не знаю если она переносима :
    Если написать #define X(a0,a1,a2....an), по при использовании X(a) в a1, a2 будет пусто.
    Это на VC++, если на других компиляторах также то проблем нет.
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re: Код v1.05a
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 21.08.04 18:34
    Оценка:
    >>Компилеро-независимый способ задания строк, сейчас работает только на линейке VC
    По следам буста изменил способ задания строк. Теперь декларации выглядят так:

    USE_MODULE_BEGIN(kernel, (kern)(el32)(.dll))
        DECLARE_FUN_P1(GetModuleHandle, (GetM)(odul)(eHan)(dleA), HMODULE, LPCTSTR)
        DECLARE_FUN_P1(GetModuleHandleW, (GetM)(odul)(eHan)(dleW), HMODULE, LPCWSTR)
        DECLARE_FUN_P1_THROW(InitializeCriticalSection, (Init)(iali)(zeCr)(itic)(alSe)(ctio)(n),VOID, LPCRITICAL_SECTION)
    USE_MODULE_END


    Уже лучше, конечно, но и не идеально, конечно.
    Собственно, можно вообще сделать декларации в виде
    USE_MODULE_BEGIN(kernel, (kern)(el32)(.dll))
        DECLARE_FUN_P1((GetM)(odul)(eHan)(dleA), HMODULE, LPCTSTR)
        DECLARE_FUN_P1((GetM)(odul)(eHan)(dleW), HMODULE, LPCWSTR)
        DECLARE_FUN_P1_THROW(InitializeCriticalSection, (Init)(iali)(zeCr)(itic)(alSe)(ctio)(n),VOID, LPCRITICAL_SECTION)
    USE_MODULE_END


    Но в этом случае непонятно, как быть с юникодом... А хотя, есть мысль — ведь если в этом случае писать kernel::GetModuleHandle, то препроцессор это на основе стандартных хидеров фактически сам преобразует в нужный вариант — либо kernel::GetModuleHandleA, либо kernel::GetModuleHandleW. Фактически бесплатная поддержка юникода. Как господам такая мысль? Если понравится, сделаем так. В результате плюсы — сокращенная запись + полуавтоматический юникод.


    Да, из todo остается:
    >>Автоматический генератор макросов DECLARE_FUN_XXX

    Есть мысли?

    //    delayimphlp.h: Delay import helper
    //    Developer:    Andrew Solodovnikov
    //    E-mail:        none
    //    Date:        03.08.2004
    
    #ifndef    __DELAYIMPHLP_H__
    #define __DELAYIMPHLP_H__
    
    #define DL_CAT_(x,y) x##y
    #define DL_CAT(x,y) DL_CAT_(x,y)
    
    #define MAX_DL_REPEAT 16
    #define DL_COMMA() ,
    #define DL_EMPTY() 
    
    // DL_REPEAT_N
    #define DL_REPEAT_IMPL_N_0(x, d) 
    #define DL_REPEAT_IMPL_N_1(x, d) DL_CAT(x,1)
    #define DL_REPEAT_IMPL_N_2(x, d) DL_REPEAT_IMPL_N_1(x, d)d()  DL_CAT(x,2)
    #define DL_REPEAT_IMPL_N_3(x, d) DL_REPEAT_IMPL_N_2(x, d)d()  DL_CAT(x,3)
    #define DL_REPEAT_IMPL_N_4(x, d) DL_REPEAT_IMPL_N_3(x, d)d()  DL_CAT(x,4)
    #define DL_REPEAT_IMPL_N_5(x, d) DL_REPEAT_IMPL_N_4(x, d)d()  DL_CAT(x,5)
    #define DL_REPEAT_IMPL_N_6(x, d) DL_REPEAT_IMPL_N_5(x, d)d()  DL_CAT(x,6)
    #define DL_REPEAT_IMPL_N_7(x, d) DL_REPEAT_IMPL_N_6(x, d)d()  DL_CAT(x,7)
    #define DL_REPEAT_IMPL_N_8(x, d) DL_REPEAT_IMPL_N_7(x, d)d()  DL_CAT(x,8)
    #define DL_REPEAT_IMPL_N_9(x, d) DL_REPEAT_IMPL_N_8(x, d)d()  DL_CAT(x,9)
    #define DL_REPEAT_IMPL_N_10(x, d) DL_REPEAT_IMPL_N_9(x, d)d()  DL_CAT(x,10)
    #define DL_REPEAT_IMPL_N_11(x, d) DL_REPEAT_IMPL_N_10(x, d)d()  DL_CAT(x,11)
    #define DL_REPEAT_IMPL_N_12(x, d) DL_REPEAT_IMPL_N_11(x, d)d()  DL_CAT(x,12)
    #define DL_REPEAT_IMPL_N_13(x, d) DL_REPEAT_IMPL_N_12(x, d)d()  DL_CAT(x,13)
    #define DL_REPEAT_IMPL_N_14(x, d) DL_REPEAT_IMPL_N_13(x, d)d()  DL_CAT(x,14)
    #define DL_REPEAT_IMPL_N_15(x, d) DL_REPEAT_IMPL_N_14(x, d)d()  DL_CAT(x,15)
    #define DL_REPEAT_IMPL_N_16(x, d) DL_REPEAT_IMPL_N_15(x, d)d()  DL_CAT(x,16)
    
    #define DL_REPEAT_IMPL_N(n, x, d) DL_CAT(DL_REPEAT_IMPL_N_,n)(x, d)
    
    #define DL_REPEAT_N(n,x) DL_REPEAT_IMPL_N(n, x, DL_COMMA)
    
    // DL_REPEAT_PARAM_N
    #define DL_REPEAT_PARAM_IMPL_N0(n, m, d1, d2)
    #define DL_REPEAT_PARAM_IMPL_N1(n, m, d1, d2) DL_CAT(n,1) DL_CAT(m,1)
    #define DL_REPEAT_PARAM_IMPL_N2(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N1(n, m, d1, d2)d1() DL_CAT(n,2)d2() DL_CAT(m,2)
    #define DL_REPEAT_PARAM_IMPL_N3(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N2(n, m, d1, d2)d1() DL_CAT(n,3)d2() DL_CAT(m,3)
    #define DL_REPEAT_PARAM_IMPL_N4(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N3(n, m, d1, d2)d1() DL_CAT(n,4)d2() DL_CAT(m,4)
    #define DL_REPEAT_PARAM_IMPL_N5(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N4(n, m, d1, d2)d1() DL_CAT(n,5)d2() DL_CAT(m,5)
    #define DL_REPEAT_PARAM_IMPL_N6(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N5(n, m, d1, d2)d1() DL_CAT(n,6)d2() DL_CAT(m,6)
    #define DL_REPEAT_PARAM_IMPL_N7(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N6(n, m, d1, d2)d1() DL_CAT(n,7)d2() DL_CAT(m,7)
    #define DL_REPEAT_PARAM_IMPL_N8(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N7(n, m, d1, d2)d1() DL_CAT(n,8)d2() DL_CAT(m,8)
    #define DL_REPEAT_PARAM_IMPL_N9(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N8(n, m, d1, d2)d1() DL_CAT(n,9)d2() DL_CAT(m,9)
    #define DL_REPEAT_PARAM_IMPL_N10(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N9(n, m, d1, d2)d1() DL_CAT(n,10)d2() DL_CAT(m,10)
    #define DL_REPEAT_PARAM_IMPL_N11(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N10(n, m, d1, d2)d1() DL_CAT(n,11)d2() DL_CAT(m,11)
    #define DL_REPEAT_PARAM_IMPL_N12(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N11(n, m, d1, d2)d1() DL_CAT(n,12)d2() DL_CAT(m,12)
    #define DL_REPEAT_PARAM_IMPL_N13(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N12(n, m, d1, d2)d1() DL_CAT(n,13)d2() DL_CAT(m,13)
    #define DL_REPEAT_PARAM_IMPL_N14(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N13(n, m, d1, d2)d1() DL_CAT(n,14)d2() DL_CAT(m,14)
    #define DL_REPEAT_PARAM_IMPL_N15(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N14(n, m, d1, d2)d1() DL_CAT(n,15)d2() DL_CAT(m,15)
    #define DL_REPEAT_PARAM_IMPL_N16(n,m, d1, d2) DL_REPEAT_PARAM_IMPL_N15(n, m, d1, d2)d1() DL_CAT(n,16)d2() DL_CAT(m,16)
    
    #define DL_REPEAT_PARAM_IMPL_N(c, n, m, d1, d2) DL_CAT(DL_REPEAT_PARAM_IMPL_N,c)(n, m, d1, d2)
    
    #define DL_REPEAT_PARAM_N(c, n, m) DL_REPEAT_PARAM_IMPL_N(c, n, m, DL_COMMA, DL_EMPTY)
    
    // DL_REPEAT_DEF_IMPL_N
    #define DL_REPEAT_DEF_IMPL_N0(n, def, d)
    #define DL_REPEAT_DEF_IMPL_N1(n, def, d) DL_CAT(DL_CAT(n,1), def)
    #define DL_REPEAT_DEF_IMPL_N2(n, def, d) DL_REPEAT_DEF_IMPL_N1(n, def, d)d() DL_CAT(DL_CAT(n,2), def)
    #define DL_REPEAT_DEF_IMPL_N3(n, def, d) DL_REPEAT_DEF_IMPL_N2(n, def, d)d() DL_CAT(DL_CAT(n,3), def)
    #define DL_REPEAT_DEF_IMPL_N4(n, def, d) DL_REPEAT_DEF_IMPL_N3(n, def, d)d() DL_CAT(DL_CAT(n,4), def)
    #define DL_REPEAT_DEF_IMPL_N5(n, def, d) DL_REPEAT_DEF_IMPL_N4(n, def, d)d() DL_CAT(DL_CAT(n,5), def)
    #define DL_REPEAT_DEF_IMPL_N6(n, def, d) DL_REPEAT_DEF_IMPL_N5(n, def, d)d() DL_CAT(DL_CAT(n,6), def)
    #define DL_REPEAT_DEF_IMPL_N7(n, def, d) DL_REPEAT_DEF_IMPL_N6(n, def, d)d() DL_CAT(DL_CAT(n,7), def)
    #define DL_REPEAT_DEF_IMPL_N8(n, def, d) DL_REPEAT_DEF_IMPL_N7(n, def, d)d() DL_CAT(DL_CAT(n,8), def)
    #define DL_REPEAT_DEF_IMPL_N9(n, def, d) DL_REPEAT_DEF_IMPL_N8(n, def, d)d() DL_CAT(DL_CAT(n,9), def)
    #define DL_REPEAT_DEF_IMPL_N10(n, def, d) DL_REPEAT_DEF_IMPL_N9(n, def, d)d() DL_CAT(DL_CAT(n,10), def)
    #define DL_REPEAT_DEF_IMPL_N11(n, def, d) DL_REPEAT_DEF_IMPL_N10(n, def, d)d() DL_CAT(DL_CAT(n,11), def)
    #define DL_REPEAT_DEF_IMPL_N12(n, def, d) DL_REPEAT_DEF_IMPL_N11(n, def, d)d() DL_CAT(DL_CAT(n,12), def)
    #define DL_REPEAT_DEF_IMPL_N13(n, def, d) DL_REPEAT_DEF_IMPL_N12(n, def, d)d() DL_CAT(DL_CAT(n,13), def)
    #define DL_REPEAT_DEF_IMPL_N14(n, def, d) DL_REPEAT_DEF_IMPL_N13(n, def, d)d() DL_CAT(DL_CAT(n,14), def)
    #define DL_REPEAT_DEF_IMPL_N15(n, def, d) DL_REPEAT_DEF_IMPL_N14(n, def, d)d() DL_CAT(DL_CAT(n,15), def)
    #define DL_REPEAT_DEF_IMPL_N16(n, def, d) DL_REPEAT_DEF_IMPL_N15(n, def, d)d() DL_CAT(DL_CAT(n,16), def)
    
    #define DL_REPEAT_DEF_IMPL_N(c, n, def, d) DL_CAT(DL_REPEAT_DEF_IMPL_N,c)(n, def, d)
    
    #define DL_REPEAT_DEF_N(c, n, def) DL_REPEAT_DEF_IMPL_N(c, n, def, DL_COMMA)
    
    // DL_REPEAT_MACRO_N
    
    #define DL_REPEAT_MACRO_IMPL_N0(m, p, d)
    #define DL_REPEAT_MACRO_IMPL_N1(m, p, d) m(p,1)
    #define DL_REPEAT_MACRO_IMPL_N2(m, p, d) DL_REPEAT_MACRO_IMPL_N1(m, p, d)d() m(p,2)
    #define DL_REPEAT_MACRO_IMPL_N3(m, p, d) DL_REPEAT_MACRO_IMPL_N2(m, p, d)d() m(p,3)
    #define DL_REPEAT_MACRO_IMPL_N4(m, p, d) DL_REPEAT_MACRO_IMPL_N3(m, p, d)d() m(p,4)
    #define DL_REPEAT_MACRO_IMPL_N5(m, p, d) DL_REPEAT_MACRO_IMPL_N4(m, p, d)d() m(p,5)
    #define DL_REPEAT_MACRO_IMPL_N6(m, p, d) DL_REPEAT_MACRO_IMPL_N5(m, p, d)d() m(p,6)
    #define DL_REPEAT_MACRO_IMPL_N7(m, p, d) DL_REPEAT_MACRO_IMPL_N6(m, p, d)d() m(p,7)
    #define DL_REPEAT_MACRO_IMPL_N8(m, p, d) DL_REPEAT_MACRO_IMPL_N7(m, p, d)d() m(p,8)
    #define DL_REPEAT_MACRO_IMPL_N9(m, p, d) DL_REPEAT_MACRO_IMPL_N8(m, p, d)d() m(p,9)
    #define DL_REPEAT_MACRO_IMPL_N10(m, p, d) DL_REPEAT_MACRO_IMPL_N9(m, p, d)d() m(p,10)
    #define DL_REPEAT_MACRO_IMPL_N11(m, p, d) DL_REPEAT_MACRO_IMPL_N10(m, p, d)d() m(p,11)
    #define DL_REPEAT_MACRO_IMPL_N12(m, p, d) DL_REPEAT_MACRO_IMPL_N11(m, p, d)d() m(p,12)
    #define DL_REPEAT_MACRO_IMPL_N13(m, p, d) DL_REPEAT_MACRO_IMPL_N12(m, p, d)d() m(p,13)
    #define DL_REPEAT_MACRO_IMPL_N14(m, p, d) DL_REPEAT_MACRO_IMPL_N13(m, p, d)d() m(p,14)
    #define DL_REPEAT_MACRO_IMPL_N15(m, p, d) DL_REPEAT_MACRO_IMPL_N14(m, p, d)d() m(p,15)
    #define DL_REPEAT_MACRO_IMPL_N16(m, p, d) DL_REPEAT_MACRO_IMPL_N15(m, p, d)d() m(p,16)
    
    #define DL_REPEAT_MACRO_IMPL_N(c, m, p, d) DL_CAT(DL_REPEAT_MACRO_IMPL_N,c)(m,p, d)
    #define DL_REPEAT_MACRO_N(c, m, p) DL_REPEAT_MACRO_IMPL_N(c, m, p, DL_COMMA)
    
    #define DL_SEQ_SIZE(seq) DL_SEQ_SIZE_IMPL(seq)
    #define DL_SEQ_SIZE_IMPL(seq) DL_CAT(DL_N_, DL_SEQ_SIZE_0 seq)
    
    #define DL_SEQ_SIZE_0(_) DL_SEQ_SIZE_1
    #define DL_SEQ_SIZE_1(_) DL_SEQ_SIZE_2
    #define DL_SEQ_SIZE_2(_) DL_SEQ_SIZE_3
    #define DL_SEQ_SIZE_3(_) DL_SEQ_SIZE_4
    #define DL_SEQ_SIZE_4(_) DL_SEQ_SIZE_5
    #define DL_SEQ_SIZE_5(_) DL_SEQ_SIZE_6
    #define DL_SEQ_SIZE_6(_) DL_SEQ_SIZE_7
    #define DL_SEQ_SIZE_7(_) DL_SEQ_SIZE_8
    #define DL_SEQ_SIZE_8(_) DL_SEQ_SIZE_9
    #define DL_SEQ_SIZE_9(_) DL_SEQ_SIZE_10
    #define DL_SEQ_SIZE_10(_) DL_SEQ_SIZE_11
    #define DL_SEQ_SIZE_11(_) DL_SEQ_SIZE_12
    #define DL_SEQ_SIZE_12(_) DL_SEQ_SIZE_13
    #define DL_SEQ_SIZE_13(_) DL_SEQ_SIZE_14
    #define DL_SEQ_SIZE_14(_) DL_SEQ_SIZE_15
    #define DL_SEQ_SIZE_15(_) DL_SEQ_SIZE_16
    
    #define DL_N_DL_SEQ_SIZE_0 0
    #define DL_N_DL_SEQ_SIZE_1 1
    #define DL_N_DL_SEQ_SIZE_2 2
    #define DL_N_DL_SEQ_SIZE_3 3
    #define DL_N_DL_SEQ_SIZE_4 4
    #define DL_N_DL_SEQ_SIZE_5 5
    #define DL_N_DL_SEQ_SIZE_6 6
    #define DL_N_DL_SEQ_SIZE_7 7
    #define DL_N_DL_SEQ_SIZE_8 8
    #define DL_N_DL_SEQ_SIZE_9 9
    #define DL_N_DL_SEQ_SIZE_10 10
    #define DL_N_DL_SEQ_SIZE_11 11
    #define DL_N_DL_SEQ_SIZE_12 12
    #define DL_N_DL_SEQ_SIZE_13 13
    #define DL_N_DL_SEQ_SIZE_14 14
    #define DL_N_DL_SEQ_SIZE_15 15
    #define DL_N_DL_SEQ_SIZE_16 16
    
    
    #define DL_SEQ_ENUM(seq) DL_SEQ_ENUM_IMPL(seq)
    #define DL_SEQ_ENUM_IMPL(seq) DL_CAT(DL_SEQ_ENUM_, DL_SEQ_SIZE(seq)) seq
    
    #define DL_MAKE_CHAR_(x) #@x
    #define DL_MAKE_CHAR(x) DL_MAKE_CHAR_(x)
    
    #define    DL_SEQ_ENUM_1(x) DL_MAKE_CHAR(x)
    #define    DL_SEQ_ENUM_2(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_1
    #define    DL_SEQ_ENUM_3(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_2
    #define    DL_SEQ_ENUM_4(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_3
    #define    DL_SEQ_ENUM_5(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_4
    #define    DL_SEQ_ENUM_6(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_5
    #define    DL_SEQ_ENUM_7(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_6
    #define    DL_SEQ_ENUM_8(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_7
    #define    DL_SEQ_ENUM_9(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_8
    #define    DL_SEQ_ENUM_10(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_9
    #define    DL_SEQ_ENUM_11(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_10
    #define    DL_SEQ_ENUM_12(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_11
    #define    DL_SEQ_ENUM_13(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_12
    #define    DL_SEQ_ENUM_14(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_13
    #define    DL_SEQ_ENUM_15(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_14
    #define    DL_SEQ_ENUM_16(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_15
    
    
    #define FLATTEN_STR3(val) (((val) > 0xFFFFFF) ? (val) : 0)
    #define FLATTEN_STR2(val) (((val) > 0xFFFFFF) ? (val) : FLATTEN_STR3(val << 8))
    #define FLATTEN_STR1(val) (((val) > 0xFFFFFF) ? (val) : FLATTEN_STR2(val << 8))
    #define FLATTEN_STR0(val) (((val) > 0xFFFFFF) ? (val) : FLATTEN_STR1(val << 8))
    
    #define FLATTEN_STR_(val) \
            (TCHAR)HIBYTE(HIWORD(val)), (TCHAR)LOBYTE(HIWORD(val)), (TCHAR)HIBYTE(LOWORD(val)), (TCHAR)LOBYTE(LOWORD(val))
    
    #define FLATTEN_STR(val, num) FLATTEN_STR_(FLATTEN_STR0(DL_CAT(val, num)))
    
    #pragma warning (disable: 4786)
    
    template <int count>
    struct CNameIdHolder
    {
        template <DL_REPEAT_N(MAX_DL_REPEAT, DWORD n)>
        struct CNameIdHolderImpl
        {
            static LPCTSTR GetStr()
            {
                static const TCHAR szBuffer[] = {
                                                    DL_REPEAT_MACRO_N(MAX_DL_REPEAT, FLATTEN_STR, n),
                                                    _T('\0')
                                                };
                return szBuffer;
            }
        };
    };
    
    #define NAME_ID_HOLDER_SPEC(num)\
    template <>\
    struct CNameIdHolder<num>\
    {\
        template <DL_REPEAT_N(MAX_DL_REPEAT, DWORD n)>\
        struct CNameIdHolderImpl\
        {\
            static LPCTSTR GetStr()\
            {\
                static const TCHAR szBuffer[] = {\
                                                    DL_REPEAT_MACRO_N(num, FLATTEN_STR, n),\
                                                    _T('\0')\
                                                };\
                return szBuffer;\
            }\
        };\
    };
    
    NAME_ID_HOLDER_SPEC(15)
    NAME_ID_HOLDER_SPEC(14)
    NAME_ID_HOLDER_SPEC(13)
    NAME_ID_HOLDER_SPEC(12)
    NAME_ID_HOLDER_SPEC(11)
    NAME_ID_HOLDER_SPEC(10)
    NAME_ID_HOLDER_SPEC(9)
    NAME_ID_HOLDER_SPEC(8)
    NAME_ID_HOLDER_SPEC(7)
    NAME_ID_HOLDER_SPEC(6)
    NAME_ID_HOLDER_SPEC(5)
    NAME_ID_HOLDER_SPEC(4)
    NAME_ID_HOLDER_SPEC(3)
    NAME_ID_HOLDER_SPEC(2)
    NAME_ID_HOLDER_SPEC(1)
    
    template <>
    struct CNameIdHolder<0>
    {
        template <DL_REPEAT_N(MAX_DL_REPEAT, DWORD n)>
        struct CNameIdHolderImpl
        {
            static LPCTSTR GetStr()
            {
                return NULL;
            }
        };
    };
    
    #define NN_REP_COUNT_M(p, n) (!DL_CAT(p,n)) ? (n-1):
    
    template <DL_REPEAT_DEF_N(MAX_DL_REPEAT, DWORD n, = 0)>
    struct CNameId
    {
        enum
        {
            DL_REPEAT_PARAM_N(MAX_DL_REPEAT, m_n, =n),
            count   = DL_REPEAT_MACRO_IMPL_N(MAX_DL_REPEAT, NN_REP_COUNT_M, n, DL_EMPTY) MAX_DL_REPEAT,
            length  = count * sizeof(DWORD)
        };
        static LPCTSTR GetStr()
        {
            return CNameIdHolder<count>::template CNameIdHolderImpl<DL_REPEAT_N(MAX_DL_REPEAT, n)>::GetStr();
        }
    };
    
    template <class Name>
    class CModule
    {
    public:
        HMODULE m_hModule;
        typedef CModule<Name> type;
        typedef Name          name_type;
        static type &GetModule()
        {
            static type Module;
            return Module;
        }
        ~CModule()
        {
            if (m_hModule)
                FreeLibrary(m_hModule);
        }
    private:
        CModule()
        {
            m_hModule = LoadLibrary(name_type::GetStr());
        }
    };
    
    
    template <class Module, class Name, class Proxy>
    class CDynFunction
    {
    public:
        typedef CDynFunction<Module, Name, Proxy> type;
        typedef Proxy                              proxy_type;
        typedef Module                              module_type;
        typedef Name                              name_type;
        
        static proxy_type::fun_type &GetProxy()
        {
            static proxy_type::fun_type proxy = proxy_type::template Proxy<type>::ProxyFun;
            return proxy;
        }
        static BOOL InitFunction()
        {
            HMODULE hModule = Module::GetModule().m_hModule;
            if (hModule)
            {
                FARPROC pFunction = GetProcAddress(hModule, name_type::GetStr());
                if (pFunction)
                {
                    GetProxy() = (proxy_type::fun_type)pFunction;
                    return TRUE;
                }
            }
            return FALSE;
        }
    };
    
    
    
    struct CDynFunException
    {
        CDynFunException(): m_sMessage(NULL)
        {
        };
        ~CDynFunException()
        {
            free(m_sMessage);
        };
        CDynFunException(LPCTSTR sMessage):m_sMessage(NULL)
        {
            SetMessage(sMessage);
        }
        CDynFunException(const CDynFunException &other):m_sMessage(NULL)
        {
            SetMessage(other.m_sMessage);
        }
        CDynFunException &operator = (const CDynFunException &other)
        {
            SetMessage(other.m_sMessage);
            return *this;
        }
        void SetMessage(LPCTSTR sMessage)
        {
            free(m_sMessage);
            m_sMessage = (LPTSTR)malloc((_tcslen(sMessage) + 1) * sizeof(TCHAR));
            if (m_sMessage)
                _tcscpy(m_sMessage, sMessage);
        }
        LPCTSTR GetMessage() const
        {
            return m_sMessage;
        }
    private:
        LPTSTR m_sMessage;
    };
    
    template <class R> struct FunProxyThrowRetTypeTrait
    {
        template <class F>
        struct FunctionTraitImpl
        {
            static R MakeReturn()
            {
                F::MakeReturnImpl();
                return R();
            }
        };
    };
    
    template <> struct FunProxyThrowRetTypeTrait<void>
    {
        template <class F>
        struct FunctionTraitImpl
        {
            static void MakeReturn()
            {
                F::MakeReturnImpl();
            }
        };
    };
    
    template<class E = CDynFunException>
    struct FunProxyThrowPolicy
    {
        template <class DynFunction> 
        struct FunctionTrait:public FunProxyThrowRetTypeTrait<DynFunction::proxy_type::ret_type>::template FunctionTraitImpl<FunctionTrait<DynFunction> >
        {
            static void MakeReturnImpl()
            {
                TCHAR szMessage[DynFunction::name_type::length + 64];
                _stprintf(szMessage, _T("Can'n resolve procedure <%s>: %d"), DynFunction::name_type::GetStr(), GetLastError());
                throw E(szMessage);
            }
        };
    };
    
    
    //  we need not implement void return type value policy, 
    //  coz void function can only throw on error
    
    template<class R, R value = R()>
    struct FunProxyValuePolicy
    {
        template <class DynFunction> 
        struct FunctionTrait
        {
            static DynFunction::proxy_type::ret_type MakeReturn()
            {
                return value;
            }
        };
    };
    
    
    #define FUN_PROXY(n) DL_CAT(FunProxy,n)
    #define FUN_PROXY_IMPL(n) DL_CAT(FUN_PROXY(n),Impl)
    
    #define DECLARE_FUN_PROXY(param_count) \
    template <typename R> struct FUN_PROXY_IMPL(param_count)\
    {\
        template <class DynFunction, DL_REPEAT_N(param_count, typename P), class Policy> struct RetProxy\
        {\
            static R WINAPI ProxyFun(DL_REPEAT_PARAM_N(param_count, P, v))\
            {\
                if (DynFunction::InitFunction())\
                    return DynFunction::GetProxy()(DL_REPEAT_N(param_count, v));\
                return Policy::template FunctionTrait<DynFunction>::MakeReturn();\
            }\
        };\
    };\
    \
    template <> struct FUN_PROXY_IMPL(param_count) <void>\
    {\
        template <class DynFunction, DL_REPEAT_N(param_count, typename P), class Policy> struct RetProxy\
        {\
            static R WINAPI ProxyFun(DL_REPEAT_PARAM_N(param_count, P, v))\
            {\
                if (DynFunction::InitFunction())\
                    DynFunction::GetProxy()(DL_REPEAT_N(param_count, v));\
                else\
                    Policy::template FunctionTrait<DynFunction>::MakeReturn();\
            }\
        };\
    };\
    \
    template <typename R, DL_REPEAT_N(param_count, typename P), class Policy = FunProxyValuePolicy<R> > struct FUN_PROXY(param_count)\
    {\
        typedef R (WINAPI *fun_type)(DL_REPEAT_N(param_count, P));\
        typedef R ret_type;\
        template <class DynFunction> struct Proxy:public FUN_PROXY_IMPL(param_count)<R>::template RetProxy<DynFunction, DL_REPEAT_N(param_count, P), Policy>\
        {\
        };\
    };
    
    DECLARE_FUN_PROXY(1)
    DECLARE_FUN_PROXY(2)
    DECLARE_FUN_PROXY(3)
    DECLARE_FUN_PROXY(4)
    DECLARE_FUN_PROXY(5)
    DECLARE_FUN_PROXY(6)
    DECLARE_FUN_PROXY(7)
    DECLARE_FUN_PROXY(8)
    DECLARE_FUN_PROXY(9)
    DECLARE_FUN_PROXY(10)
    DECLARE_FUN_PROXY(11)
    DECLARE_FUN_PROXY(12)
    DECLARE_FUN_PROXY(13)
    DECLARE_FUN_PROXY(14)
    DECLARE_FUN_PROXY(15)
    DECLARE_FUN_PROXY(16)
    
    // usefull macro's
    
    #define USE_MODULE_BEGIN(nmspace, NameId) \
    namespace nmspace \
    {\
        typedef CModule< CNameId<DL_SEQ_ENUM(NameId)> > module_type;
    
    #define USE_MODULE_END \
    };
    
    
    
    #define DECLARE_FUN_P1(Name, NameId, R, P1) \
    static R (WINAPI *&Name)(P1) = CDynFunction<module_type, CNameId<DL_SEQ_ENUM(NameId)>, FUN_PROXY(1)<R, P1> >::GetProxy();
    
    
    #define DECLARE_FUN_P1_ERR(Name, NameId, R, P1, E)\
    static R (WINAPI *&Name)(P1) = CDynFunction<module_type, CNameId<DL_SEQ_ENUM(NameId)>, FUN_PROXY(1)<R, P1, FunProxyValuePolicy<R,E> > >::GetProxy();
     
    #define DECLARE_FUN_P1_THROW(Name, NameId, R, P1)\
    static R (WINAPI *&Name)(P1) = CDynFunction<module_type, CNameId<DL_SEQ_ENUM(NameId)>, FUN_PROXY(1)<R, P1, FunProxyThrowPolicy<> > >::GetProxy();
    
    #endif
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[2]: Код v1.05a
    От: _nn_ www.nemerleweb.com
    Дата: 22.08.04 05:53
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    Как можно заметить код разделяется на два куска — это макросы для повоторения и сам код для загрузки библиотек.
    Может стоит выделить для макросов отдельную ветку ?

    Все же стоит заменить DWORD, на TCHAR, так нельзя будет ошибиться в написани, вдобавок читать приятней
    // DWORD
    USE_MODULE_BEGIN(kernel, (kern)(el3)(3.dl)(l)) -> kernel3
    // TCHAR
    USE_MODULE_BEGIN(kernel, (k)(e)(r)(n)(e)(l)(3)(2)(.)(d)(l)(l) ) -> kernel32.dll
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[3]: Код v1.05a
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 22.08.04 10:26
    Оценка:
    __>Как можно заметить код разделяется на два куска — это макросы для повоторения и сам код для загрузки библиотек.
    __>Может стоит выделить для макросов отдельную ветку ?

    Может и стоит. У вас есть предложения по макросам? У меня — есть. Например, было бы интересно придумать макрос для разбиения идентификатора на квартеты (или отдельные символы). Тогда можно было бы вообще в нативном синтаксисе писать декларации функций. Конечно, это невозможно скорее всего, но тем не менее. Ну, и конечно, хорошо бы автоматизировать процесс задания макросов декларации функций. Я не смог придумать, как это сделать.

    __>Все же стоит заменить DWORD, на TCHAR, так нельзя будет ошибиться в написани, вдобавок читать приятней


    Мы уже это обсуждали, мое мнение, что не стоит — слишком длинная запись. Впрочем, это не суть важно.
    Меня вот что инетерсует — ваше мнение по поводу деклараций функций в сокращенном виде — делать или нет? Мне думается, что в сокращенном виде особой функциональности не теряется, писать текста меньше почти в 2 раза.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[4]: Код v1.05a
    От: _nn_ www.nemerleweb.com
    Дата: 22.08.04 10:49
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    __>>Как можно заметить код разделяется на два куска — это макросы для повоторения и сам код для загрузки библиотек.

    __>>Может стоит выделить для макросов отдельную ветку ?

    AS>Может и стоит. У вас есть предложения по макросам? У меня — есть. Например, было бы интересно придумать макрос для разбиения идентификатора на квартеты (или отдельные символы). Тогда можно было бы вообще в нативном синтаксисе писать декларации функций. Конечно, это невозможно скорее всего, но тем не менее. Ну, и конечно, хорошо бы автоматизировать процесс задания макросов декларации функций. Я не смог придумать, как это сделать.


    Идея :
    #define DECLARE_FUN(Name, NameId, R, P1, COMMA1, P2, COMMA2, P3, COMMA3, ...) \
    static R (WINAPI *&Name)(P1) = CDynFunction<module_type, CNameId<DL_SEQ_ENUM(NameId)>, FUN_PROXY(1)<R, P1 COMMA1 P2 COMMA2 ...> >::GetProxy(); // повторение здесь можно через макрос оформить.


    использование :
    // до
    DECLARE_FUN_P1(GetModuleHandle, (GetM)(odul)(eHan)(dleA), HMODULE, LPCTSTR)
    
    // после
    DECLARE_FUN(GetModuleHandle, (GetM)(odul)(eHan)(dleA), HMODULE, LPCTSTR, EMPTY, EMPTY ... )
    // EMPTY.. можно тоже через макрос оформить - REPEAT_N((сколько надо),EMPTY)

    Не очень переносимый вариант :
    DECLARE_FUN(GetModuleHandle, (GetM)(odul)(eHan)(dleA), HMODULE, LPCTSTR)
    // будет много предупреждений, однако код сработает нормально


    __>>Все же стоит заменить DWORD, на TCHAR, так нельзя будет ошибиться в написани, вдобавок читать приятней


    AS>Мы уже это обсуждали, мое мнение, что не стоит — слишком длинная запись. Впрочем, это не суть важно.

    А что насчет проблемы упомянутой выше ?
    AS>Меня вот что инетерсует — ваше мнение по поводу деклараций функций в сокращенном виде — делать или нет? Мне думается, что в сокращенном виде особой функциональности не теряется, писать текста меньше почти в 2 раза.
    Не понял про что вы.

    А почему бы не сделать так:
    #define DECLARE_FUN(name1,name2,name3....) \
     CAT(name1,CAT(name2,CAT(name3... ))) // ну или через макрос как-то

    DECLARE_FUN(G,e,t,M,o,d,u,l,e,H,a,n,d,l,e, REPEAT_N((сколько надо),EMPTY)

    Индефикатор уже разбит, а сложить проще чем разбить
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[4]: Код v1.05a
    От: _nn_ www.nemerleweb.com
    Дата: 22.08.04 10:56
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    Есть предложение обсудить финальную версию этой вещи по ICQ, а то тема зашла уже довольно далеко.
    Мой номер внизу.

    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[5]: Код v1.05a
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 22.08.04 11:50
    Оценка:
    __>Идея :
    __>
    __>#define DECLARE_FUN(Name, NameId, R, P1, COMMA1, P2, COMMA2, P3, COMMA3, ...) \
    __>static R (WINAPI *&Name)(P1) = CDynFunction<module_type, CNameId<DL_SEQ_ENUM(NameId)>, FUN_PROXY(1)<R, P1 COMMA1 P2 COMMA2 ...> >::GetProxy(); // повторение здесь можно через макрос оформить.
    __>


    Я сделал проще (и вероятно, удобнее) — собственно, решение лежало на поверхности:

    #define DECLARE_FUN(Name, NameId, R, P) \
    static R (WINAPI *&Name)(DL_SEQ_ENUM(P)) = CDynFunction<module_type, CNameId<DL_SEQ_ENUM_CHAR(NameId)>, FUN_PROXY(DL_SEQ_SIZE(P))<R, DL_SEQ_ENUM(P)> >::GetProxy();


    И функции декларируются единообразно для любого числа параметров (до DL_MAX_REPEAT):

    USE_MODULE_BEGIN(kernel, (kern)(el32)(.dll))
        DECLARE_FUN(GetProcAddress, (GetP)(rocA)(ddre)(ss), FARPROC, (HMODULE)(LPCTSTR))
    USE_MODULE_END


    А вот слить (GetP)(rocA)(ddre)(ss) в GetProcAddress у меня не получилось. Есть мысли?
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[5]: Код v1.05a
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 22.08.04 11:51
    Оценка:
    __>Есть предложение обсудить финальную версию этой вещи по ICQ, а то тема зашла уже довольно далеко.
    __>Мой номер внизу.

    __>


    Мысль интересная, но если только детали. Обсуждание тут интереснее тем, что другие форумчане могут предложить решения, которых мы просто не видим.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re: Код v1.05
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 23.08.04 12:40
    Оценка:
    Собственно, версия 1.04

    Список изменений:


    To do


    Как обычно — ждем сообщений о багах, предложений по фичам и прочее-прочее.



    //    delayimphlp.h: Delay import helper
    //    Developer:    Andrew Solodovnikov
    //    E-mail:        none
    //    Date:        03.08.2004
    
    #ifndef    __DELAYIMPHLP_H__
    #define __DELAYIMPHLP_H__
    
    #define DL_CAT_(x,y) x##y
    #define DL_CAT(x,y) DL_CAT_(x,y)
    
    #define MAX_DL_REPEAT 16
    #define DL_COMMA() ,
    #define DL_EMPTY() 
    
    // DL_REPEAT_N
    #define DL_REPEAT_IMPL_N_0(x, d) 
    #define DL_REPEAT_IMPL_N_1(x, d) DL_CAT(x,1)
    #define DL_REPEAT_IMPL_N_2(x, d) DL_REPEAT_IMPL_N_1(x, d)d()  DL_CAT(x,2)
    #define DL_REPEAT_IMPL_N_3(x, d) DL_REPEAT_IMPL_N_2(x, d)d()  DL_CAT(x,3)
    #define DL_REPEAT_IMPL_N_4(x, d) DL_REPEAT_IMPL_N_3(x, d)d()  DL_CAT(x,4)
    #define DL_REPEAT_IMPL_N_5(x, d) DL_REPEAT_IMPL_N_4(x, d)d()  DL_CAT(x,5)
    #define DL_REPEAT_IMPL_N_6(x, d) DL_REPEAT_IMPL_N_5(x, d)d()  DL_CAT(x,6)
    #define DL_REPEAT_IMPL_N_7(x, d) DL_REPEAT_IMPL_N_6(x, d)d()  DL_CAT(x,7)
    #define DL_REPEAT_IMPL_N_8(x, d) DL_REPEAT_IMPL_N_7(x, d)d()  DL_CAT(x,8)
    #define DL_REPEAT_IMPL_N_9(x, d) DL_REPEAT_IMPL_N_8(x, d)d()  DL_CAT(x,9)
    #define DL_REPEAT_IMPL_N_10(x, d) DL_REPEAT_IMPL_N_9(x, d)d()  DL_CAT(x,10)
    #define DL_REPEAT_IMPL_N_11(x, d) DL_REPEAT_IMPL_N_10(x, d)d()  DL_CAT(x,11)
    #define DL_REPEAT_IMPL_N_12(x, d) DL_REPEAT_IMPL_N_11(x, d)d()  DL_CAT(x,12)
    #define DL_REPEAT_IMPL_N_13(x, d) DL_REPEAT_IMPL_N_12(x, d)d()  DL_CAT(x,13)
    #define DL_REPEAT_IMPL_N_14(x, d) DL_REPEAT_IMPL_N_13(x, d)d()  DL_CAT(x,14)
    #define DL_REPEAT_IMPL_N_15(x, d) DL_REPEAT_IMPL_N_14(x, d)d()  DL_CAT(x,15)
    #define DL_REPEAT_IMPL_N_16(x, d) DL_REPEAT_IMPL_N_15(x, d)d()  DL_CAT(x,16)
    
    #define DL_REPEAT_IMPL_N(n, x, d) DL_CAT(DL_REPEAT_IMPL_N_,n)(x, d)
    
    #define DL_REPEAT_N(n,x) DL_REPEAT_IMPL_N(n, x, DL_COMMA)
    
    // DL_REPEAT_PARAM_N
    #define DL_REPEAT_PARAM_IMPL_N0(n, m, d1, d2)
    #define DL_REPEAT_PARAM_IMPL_N1(n, m, d1, d2) DL_CAT(n,1) DL_CAT(m,1)
    #define DL_REPEAT_PARAM_IMPL_N2(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N1(n, m, d1, d2)d1() DL_CAT(n,2)d2() DL_CAT(m,2)
    #define DL_REPEAT_PARAM_IMPL_N3(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N2(n, m, d1, d2)d1() DL_CAT(n,3)d2() DL_CAT(m,3)
    #define DL_REPEAT_PARAM_IMPL_N4(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N3(n, m, d1, d2)d1() DL_CAT(n,4)d2() DL_CAT(m,4)
    #define DL_REPEAT_PARAM_IMPL_N5(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N4(n, m, d1, d2)d1() DL_CAT(n,5)d2() DL_CAT(m,5)
    #define DL_REPEAT_PARAM_IMPL_N6(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N5(n, m, d1, d2)d1() DL_CAT(n,6)d2() DL_CAT(m,6)
    #define DL_REPEAT_PARAM_IMPL_N7(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N6(n, m, d1, d2)d1() DL_CAT(n,7)d2() DL_CAT(m,7)
    #define DL_REPEAT_PARAM_IMPL_N8(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N7(n, m, d1, d2)d1() DL_CAT(n,8)d2() DL_CAT(m,8)
    #define DL_REPEAT_PARAM_IMPL_N9(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N8(n, m, d1, d2)d1() DL_CAT(n,9)d2() DL_CAT(m,9)
    #define DL_REPEAT_PARAM_IMPL_N10(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N9(n, m, d1, d2)d1() DL_CAT(n,10)d2() DL_CAT(m,10)
    #define DL_REPEAT_PARAM_IMPL_N11(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N10(n, m, d1, d2)d1() DL_CAT(n,11)d2() DL_CAT(m,11)
    #define DL_REPEAT_PARAM_IMPL_N12(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N11(n, m, d1, d2)d1() DL_CAT(n,12)d2() DL_CAT(m,12)
    #define DL_REPEAT_PARAM_IMPL_N13(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N12(n, m, d1, d2)d1() DL_CAT(n,13)d2() DL_CAT(m,13)
    #define DL_REPEAT_PARAM_IMPL_N14(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N13(n, m, d1, d2)d1() DL_CAT(n,14)d2() DL_CAT(m,14)
    #define DL_REPEAT_PARAM_IMPL_N15(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N14(n, m, d1, d2)d1() DL_CAT(n,15)d2() DL_CAT(m,15)
    #define DL_REPEAT_PARAM_IMPL_N16(n,m, d1, d2) DL_REPEAT_PARAM_IMPL_N15(n, m, d1, d2)d1() DL_CAT(n,16)d2() DL_CAT(m,16)
    
    #define DL_REPEAT_PARAM_IMPL_N(c, n, m, d1, d2) DL_CAT(DL_REPEAT_PARAM_IMPL_N,c)(n, m, d1, d2)
    
    #define DL_REPEAT_PARAM_N(c, n, m) DL_REPEAT_PARAM_IMPL_N(c, n, m, DL_COMMA, DL_EMPTY)
    
    // DL_REPEAT_DEF_IMPL_N
    #define DL_REPEAT_DEF_IMPL_N0(n, def, d)
    #define DL_REPEAT_DEF_IMPL_N1(n, def, d) DL_CAT(DL_CAT(n,1), def)
    #define DL_REPEAT_DEF_IMPL_N2(n, def, d) DL_REPEAT_DEF_IMPL_N1(n, def, d)d() DL_CAT(DL_CAT(n,2), def)
    #define DL_REPEAT_DEF_IMPL_N3(n, def, d) DL_REPEAT_DEF_IMPL_N2(n, def, d)d() DL_CAT(DL_CAT(n,3), def)
    #define DL_REPEAT_DEF_IMPL_N4(n, def, d) DL_REPEAT_DEF_IMPL_N3(n, def, d)d() DL_CAT(DL_CAT(n,4), def)
    #define DL_REPEAT_DEF_IMPL_N5(n, def, d) DL_REPEAT_DEF_IMPL_N4(n, def, d)d() DL_CAT(DL_CAT(n,5), def)
    #define DL_REPEAT_DEF_IMPL_N6(n, def, d) DL_REPEAT_DEF_IMPL_N5(n, def, d)d() DL_CAT(DL_CAT(n,6), def)
    #define DL_REPEAT_DEF_IMPL_N7(n, def, d) DL_REPEAT_DEF_IMPL_N6(n, def, d)d() DL_CAT(DL_CAT(n,7), def)
    #define DL_REPEAT_DEF_IMPL_N8(n, def, d) DL_REPEAT_DEF_IMPL_N7(n, def, d)d() DL_CAT(DL_CAT(n,8), def)
    #define DL_REPEAT_DEF_IMPL_N9(n, def, d) DL_REPEAT_DEF_IMPL_N8(n, def, d)d() DL_CAT(DL_CAT(n,9), def)
    #define DL_REPEAT_DEF_IMPL_N10(n, def, d) DL_REPEAT_DEF_IMPL_N9(n, def, d)d() DL_CAT(DL_CAT(n,10), def)
    #define DL_REPEAT_DEF_IMPL_N11(n, def, d) DL_REPEAT_DEF_IMPL_N10(n, def, d)d() DL_CAT(DL_CAT(n,11), def)
    #define DL_REPEAT_DEF_IMPL_N12(n, def, d) DL_REPEAT_DEF_IMPL_N11(n, def, d)d() DL_CAT(DL_CAT(n,12), def)
    #define DL_REPEAT_DEF_IMPL_N13(n, def, d) DL_REPEAT_DEF_IMPL_N12(n, def, d)d() DL_CAT(DL_CAT(n,13), def)
    #define DL_REPEAT_DEF_IMPL_N14(n, def, d) DL_REPEAT_DEF_IMPL_N13(n, def, d)d() DL_CAT(DL_CAT(n,14), def)
    #define DL_REPEAT_DEF_IMPL_N15(n, def, d) DL_REPEAT_DEF_IMPL_N14(n, def, d)d() DL_CAT(DL_CAT(n,15), def)
    #define DL_REPEAT_DEF_IMPL_N16(n, def, d) DL_REPEAT_DEF_IMPL_N15(n, def, d)d() DL_CAT(DL_CAT(n,16), def)
    
    #define DL_REPEAT_DEF_IMPL_N(c, n, def, d) DL_CAT(DL_REPEAT_DEF_IMPL_N,c)(n, def, d)
    
    #define DL_REPEAT_DEF_N(c, n, def) DL_REPEAT_DEF_IMPL_N(c, n, def, DL_COMMA)
    
    // DL_REPEAT_MACRO_N
    
    #define DL_REPEAT_MACRO_IMPL_N0(m, p, d)
    #define DL_REPEAT_MACRO_IMPL_N1(m, p, d) m(p,1)
    #define DL_REPEAT_MACRO_IMPL_N2(m, p, d) DL_REPEAT_MACRO_IMPL_N1(m, p, d)d() m(p,2)
    #define DL_REPEAT_MACRO_IMPL_N3(m, p, d) DL_REPEAT_MACRO_IMPL_N2(m, p, d)d() m(p,3)
    #define DL_REPEAT_MACRO_IMPL_N4(m, p, d) DL_REPEAT_MACRO_IMPL_N3(m, p, d)d() m(p,4)
    #define DL_REPEAT_MACRO_IMPL_N5(m, p, d) DL_REPEAT_MACRO_IMPL_N4(m, p, d)d() m(p,5)
    #define DL_REPEAT_MACRO_IMPL_N6(m, p, d) DL_REPEAT_MACRO_IMPL_N5(m, p, d)d() m(p,6)
    #define DL_REPEAT_MACRO_IMPL_N7(m, p, d) DL_REPEAT_MACRO_IMPL_N6(m, p, d)d() m(p,7)
    #define DL_REPEAT_MACRO_IMPL_N8(m, p, d) DL_REPEAT_MACRO_IMPL_N7(m, p, d)d() m(p,8)
    #define DL_REPEAT_MACRO_IMPL_N9(m, p, d) DL_REPEAT_MACRO_IMPL_N8(m, p, d)d() m(p,9)
    #define DL_REPEAT_MACRO_IMPL_N10(m, p, d) DL_REPEAT_MACRO_IMPL_N9(m, p, d)d() m(p,10)
    #define DL_REPEAT_MACRO_IMPL_N11(m, p, d) DL_REPEAT_MACRO_IMPL_N10(m, p, d)d() m(p,11)
    #define DL_REPEAT_MACRO_IMPL_N12(m, p, d) DL_REPEAT_MACRO_IMPL_N11(m, p, d)d() m(p,12)
    #define DL_REPEAT_MACRO_IMPL_N13(m, p, d) DL_REPEAT_MACRO_IMPL_N12(m, p, d)d() m(p,13)
    #define DL_REPEAT_MACRO_IMPL_N14(m, p, d) DL_REPEAT_MACRO_IMPL_N13(m, p, d)d() m(p,14)
    #define DL_REPEAT_MACRO_IMPL_N15(m, p, d) DL_REPEAT_MACRO_IMPL_N14(m, p, d)d() m(p,15)
    #define DL_REPEAT_MACRO_IMPL_N16(m, p, d) DL_REPEAT_MACRO_IMPL_N15(m, p, d)d() m(p,16)
    
    #define DL_REPEAT_MACRO_IMPL_N(c, m, p, d) DL_CAT(DL_REPEAT_MACRO_IMPL_N,c)(m,p, d)
    #define DL_REPEAT_MACRO_N(c, m, p) DL_REPEAT_MACRO_IMPL_N(c, m, p, DL_COMMA)
    
    // DL_SEQ_SIZE
    
    #define DL_SEQ_SIZE(seq) DL_SEQ_SIZE_IMPL(seq)
    #define DL_SEQ_SIZE_IMPL(seq) DL_CAT(DL_N_, DL_SEQ_SIZE_0 seq)
    
    #define DL_SEQ_SIZE_0(_) DL_SEQ_SIZE_1
    #define DL_SEQ_SIZE_1(_) DL_SEQ_SIZE_2
    #define DL_SEQ_SIZE_2(_) DL_SEQ_SIZE_3
    #define DL_SEQ_SIZE_3(_) DL_SEQ_SIZE_4
    #define DL_SEQ_SIZE_4(_) DL_SEQ_SIZE_5
    #define DL_SEQ_SIZE_5(_) DL_SEQ_SIZE_6
    #define DL_SEQ_SIZE_6(_) DL_SEQ_SIZE_7
    #define DL_SEQ_SIZE_7(_) DL_SEQ_SIZE_8
    #define DL_SEQ_SIZE_8(_) DL_SEQ_SIZE_9
    #define DL_SEQ_SIZE_9(_) DL_SEQ_SIZE_10
    #define DL_SEQ_SIZE_10(_) DL_SEQ_SIZE_11
    #define DL_SEQ_SIZE_11(_) DL_SEQ_SIZE_12
    #define DL_SEQ_SIZE_12(_) DL_SEQ_SIZE_13
    #define DL_SEQ_SIZE_13(_) DL_SEQ_SIZE_14
    #define DL_SEQ_SIZE_14(_) DL_SEQ_SIZE_15
    #define DL_SEQ_SIZE_15(_) DL_SEQ_SIZE_16
    
    #define DL_N_DL_SEQ_SIZE_0 0
    #define DL_N_DL_SEQ_SIZE_1 1
    #define DL_N_DL_SEQ_SIZE_2 2
    #define DL_N_DL_SEQ_SIZE_3 3
    #define DL_N_DL_SEQ_SIZE_4 4
    #define DL_N_DL_SEQ_SIZE_5 5
    #define DL_N_DL_SEQ_SIZE_6 6
    #define DL_N_DL_SEQ_SIZE_7 7
    #define DL_N_DL_SEQ_SIZE_8 8
    #define DL_N_DL_SEQ_SIZE_9 9
    #define DL_N_DL_SEQ_SIZE_10 10
    #define DL_N_DL_SEQ_SIZE_11 11
    #define DL_N_DL_SEQ_SIZE_12 12
    #define DL_N_DL_SEQ_SIZE_13 13
    #define DL_N_DL_SEQ_SIZE_14 14
    #define DL_N_DL_SEQ_SIZE_15 15
    #define DL_N_DL_SEQ_SIZE_16 16
    
    // DL_SEQ_ENUM
    
    #define DL_SEQ_ENUM(seq) DL_SEQ_ENUM_IMPL(seq)
    #define DL_SEQ_ENUM_IMPL(seq) DL_CAT(DL_SEQ_ENUM_, DL_SEQ_SIZE(seq)) seq
    
    #define    DL_SEQ_ENUM_1(x) x
    #define    DL_SEQ_ENUM_2(x) x, DL_SEQ_ENUM_1
    #define    DL_SEQ_ENUM_3(x) x, DL_SEQ_ENUM_2
    #define    DL_SEQ_ENUM_4(x) x, DL_SEQ_ENUM_3
    #define    DL_SEQ_ENUM_5(x) x, DL_SEQ_ENUM_4
    #define    DL_SEQ_ENUM_6(x) x, DL_SEQ_ENUM_5
    #define    DL_SEQ_ENUM_7(x) x, DL_SEQ_ENUM_6
    #define    DL_SEQ_ENUM_8(x) x, DL_SEQ_ENUM_7
    #define    DL_SEQ_ENUM_9(x) x, DL_SEQ_ENUM_8
    #define    DL_SEQ_ENUM_10(x) x, DL_SEQ_ENUM_9
    #define    DL_SEQ_ENUM_11(x) x, DL_SEQ_ENUM_10
    #define    DL_SEQ_ENUM_12(x) x, DL_SEQ_ENUM_11
    #define    DL_SEQ_ENUM_13(x) x, DL_SEQ_ENUM_12
    #define    DL_SEQ_ENUM_14(x) x, DL_SEQ_ENUM_13
    #define    DL_SEQ_ENUM_15(x) x, DL_SEQ_ENUM_14
    #define    DL_SEQ_ENUM_16(x) x, DL_SEQ_ENUM_15
    
    // DL_SEQ_ENUM_CHAR
    
    #define DL_SEQ_ENUM_CHAR(seq) DL_SEQ_ENUM_CHAR_IMPL(seq)
    #define DL_SEQ_ENUM_CHAR_IMPL(seq) DL_CAT(DL_SEQ_ENUM_CHAR_, DL_SEQ_SIZE(seq)) seq
    
    #define DL_MAKE_CHAR_(x) #@x
    #define DL_MAKE_CHAR(x) DL_MAKE_CHAR_(x)
    
    #define    DL_SEQ_ENUM_CHAR_1(x) DL_MAKE_CHAR(x)
    #define    DL_SEQ_ENUM_CHAR_2(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_CHAR_1
    #define    DL_SEQ_ENUM_CHAR_3(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_CHAR_2
    #define    DL_SEQ_ENUM_CHAR_4(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_CHAR_3
    #define    DL_SEQ_ENUM_CHAR_5(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_CHAR_4
    #define    DL_SEQ_ENUM_CHAR_6(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_CHAR_5
    #define    DL_SEQ_ENUM_CHAR_7(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_CHAR_6
    #define    DL_SEQ_ENUM_CHAR_8(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_CHAR_7
    #define    DL_SEQ_ENUM_CHAR_9(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_CHAR_8
    #define    DL_SEQ_ENUM_CHAR_10(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_CHAR_9
    #define    DL_SEQ_ENUM_CHAR_11(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_CHAR_10
    #define    DL_SEQ_ENUM_CHAR_12(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_CHAR_11
    #define    DL_SEQ_ENUM_CHAR_13(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_CHAR_12
    #define    DL_SEQ_ENUM_CHAR_14(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_CHAR_13
    #define    DL_SEQ_ENUM_CHAR_15(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_CHAR_14
    #define    DL_SEQ_ENUM_CHAR_16(x) DL_MAKE_CHAR(x), DL_SEQ_ENUM_CHAR_15
    
    // DL_SEQ_ELEM
    
    #define DL_SEQ_ELEM(i, seq) DL_SEQ_ELEM_IMPL(i, seq)
    #define DL_SEQ_ELEM_IMPL(i, seq) DL_SEQ_ELEM_IMPL2((DL_CAT(DL_SEQ_ELEM_, i) seq))
    #define DL_SEQ_ELEM_IMPL2(par) DL_SEQ_ELEM_IMPL3(DL_SEQ_ELEM_IMPL1 par)
    #define DL_SEQ_ELEM_IMPL3(par) par
    #define DL_SEQ_ELEM_IMPL1(x, _) x
    
    #define    DL_SEQ_ELEM_0(x) x, DL_ELEM_NIL
    #define    DL_SEQ_ELEM_1(_)  DL_SEQ_ELEM_0
    #define    DL_SEQ_ELEM_2(_)  DL_SEQ_ELEM_1
    #define    DL_SEQ_ELEM_3(_)  DL_SEQ_ELEM_2
    #define    DL_SEQ_ELEM_4(_)  DL_SEQ_ELEM_3
    #define    DL_SEQ_ELEM_5(_)  DL_SEQ_ELEM_4
    #define    DL_SEQ_ELEM_6(_)  DL_SEQ_ELEM_5
    #define    DL_SEQ_ELEM_7(_)  DL_SEQ_ELEM_6
    #define    DL_SEQ_ELEM_8(_)  DL_SEQ_ELEM_7
    #define    DL_SEQ_ELEM_9(_)  DL_SEQ_ELEM_8
    #define    DL_SEQ_ELEM_10(_)  DL_SEQ_ELEM_9
    #define    DL_SEQ_ELEM_11(_)  DL_SEQ_ELEM_10
    #define    DL_SEQ_ELEM_12(_)  DL_SEQ_ELEM_11
    #define    DL_SEQ_ELEM_13(_)  DL_SEQ_ELEM_12
    #define    DL_SEQ_ELEM_14(_)  DL_SEQ_ELEM_13
    #define    DL_SEQ_ELEM_15(_)  DL_SEQ_ELEM_14
    #define    DL_SEQ_ELEM_16(_)  DL_SEQ_ELEM_15
    
    #define DL_SEQ_HEAD(seq) DL_SEQ_HEAD_IMPL(seq)
    #define DL_SEQ_HEAD_IMPL(seq) DL_SEQ_ELEM(0, seq)
    
    #define DL_SEQ_TAIL(seq) DL_SEQ_TAIL_IMPL(DL_SEQ_TAIL_IMPL1 seq)
    #define DL_SEQ_TAIL_IMPL(seq) seq
    #define DL_SEQ_TAIL_IMPL1(x)
    
    // DL_SEQ_FOLD_LEFT
    
    #define DL_SEQ_FOLD_LEFT(macro, state, seq) DL_SEQ_FOLD_LEFT_IMPL(macro, state, seq) 
    #define DL_SEQ_FOLD_LEFT_IMPL(macro, state, seq) DL_CAT(DL_SEQ_FOLD_LEFT_, DL_SEQ_SIZE(seq))(macro, state, seq)
    
    #define DL_SEQ_FOLD_LEFT_0(macro, state, seq) DL_EMPTY()
    #define DL_SEQ_FOLD_LEFT_1(macro, state, seq) macro(state, DL_SEQ_ELEM(0, seq))
    #define DL_SEQ_FOLD_LEFT_2(macro, state, seq) macro(DL_CAT(DL_SEQ_FOLD_LEFT_,1)(macro, state, seq), DL_SEQ_ELEM(1, seq))
    #define DL_SEQ_FOLD_LEFT_3(macro, state, seq) macro(DL_CAT(DL_SEQ_FOLD_LEFT_,2)(macro, state, seq), DL_SEQ_ELEM(2, seq))
    #define DL_SEQ_FOLD_LEFT_4(macro, state, seq) macro(DL_CAT(DL_SEQ_FOLD_LEFT_,3)(macro, state, seq), DL_SEQ_ELEM(3, seq))
    #define DL_SEQ_FOLD_LEFT_5(macro, state, seq) macro(DL_CAT(DL_SEQ_FOLD_LEFT_,4)(macro, state, seq), DL_SEQ_ELEM(4, seq))
    #define DL_SEQ_FOLD_LEFT_6(macro, state, seq) macro(DL_CAT(DL_SEQ_FOLD_LEFT_,5)(macro, state, seq), DL_SEQ_ELEM(5, seq))
    #define DL_SEQ_FOLD_LEFT_7(macro, state, seq) macro(DL_CAT(DL_SEQ_FOLD_LEFT_,6)(macro, state, seq), DL_SEQ_ELEM(6, seq))
    #define DL_SEQ_FOLD_LEFT_8(macro, state, seq) macro(DL_CAT(DL_SEQ_FOLD_LEFT_,7)(macro, state, seq), DL_SEQ_ELEM(7, seq))
    #define DL_SEQ_FOLD_LEFT_9(macro, state, seq) macro(DL_CAT(DL_SEQ_FOLD_LEFT_,8)(macro, state, seq), DL_SEQ_ELEM(8, seq))
    #define DL_SEQ_FOLD_LEFT_10(macro, state, seq) macro(DL_CAT(DL_SEQ_FOLD_LEFT_,9)(macro, state, seq), DL_SEQ_ELEM(9, seq))
    #define DL_SEQ_FOLD_LEFT_11(macro, state, seq) macro(DL_CAT(DL_SEQ_FOLD_LEFT_,10)(macro, state, seq), DL_SEQ_ELEM(10, seq))
    #define DL_SEQ_FOLD_LEFT_12(macro, state, seq) macro(DL_CAT(DL_SEQ_FOLD_LEFT_,11)(macro, state, seq), DL_SEQ_ELEM(11, seq))
    #define DL_SEQ_FOLD_LEFT_13(macro, state, seq) macro(DL_CAT(DL_SEQ_FOLD_LEFT_,12)(macro, state, seq), DL_SEQ_ELEM(12, seq))
    #define DL_SEQ_FOLD_LEFT_14(macro, state, seq) macro(DL_CAT(DL_SEQ_FOLD_LEFT_,13)(macro, state, seq), DL_SEQ_ELEM(13, seq))
    #define DL_SEQ_FOLD_LEFT_15(macro, state, seq) macro(DL_CAT(DL_SEQ_FOLD_LEFT_,14)(macro, state, seq), DL_SEQ_ELEM(14, seq))
    #define DL_SEQ_FOLD_LEFT_16(macro, state, seq) macro(DL_CAT(DL_SEQ_FOLD_LEFT_,15)(macro, state, seq), DL_SEQ_ELEM(15, seq))
    
    // DL_SEQ_CAT
    
    #define DL_SEQ_CAT(seq) DL_SEQ_CAT_IMPL(seq)
    #define DL_SEQ_CAT_IMPL(seq) DL_SEQ_FOLD_LEFT(DL_CAT, DL_SEQ_HEAD(seq), DL_SEQ_TAIL(seq))
    
    // DL_FLATTEN_STR
    
    #define DL_FLATTEN_STR3(val) (((val) > 0xFFFFFF) ? (val) : 0)
    #define DL_FLATTEN_STR2(val) (((val) > 0xFFFFFF) ? (val) : DL_FLATTEN_STR3(val << 8))
    #define DL_FLATTEN_STR1(val) (((val) > 0xFFFFFF) ? (val) : DL_FLATTEN_STR2(val << 8))
    #define DL_FLATTEN_STR0(val) (((val) > 0xFFFFFF) ? (val) : DL_FLATTEN_STR1(val << 8))
    
    #define DL_FLATTEN_STR_(val) \
            (TCHAR)HIBYTE(HIWORD(val)), (TCHAR)LOBYTE(HIWORD(val)), (TCHAR)HIBYTE(LOWORD(val)), (TCHAR)LOBYTE(LOWORD(val))
    
    #define DL_FLATTEN_STR(val, num) DL_FLATTEN_STR_(DL_FLATTEN_STR0(DL_CAT(val, num)))
    
    #pragma warning (disable: 4786)
    
    template <int count>
    struct CNameIdHolder
    {
        template <DL_REPEAT_N(MAX_DL_REPEAT, DWORD n)>
        struct CNameIdHolderImpl
        {
            static LPCTSTR GetStr()
            {
                static const TCHAR szBuffer[] = {
                                                    DL_REPEAT_MACRO_N(MAX_DL_REPEAT, DL_FLATTEN_STR, n),
                                                    _T('\0')
                                                };
                return szBuffer;
            }
        };
    };
    
    #define NAME_ID_HOLDER_SPEC(num)\
    template <>\
    struct CNameIdHolder<num>\
    {\
        template <DL_REPEAT_N(MAX_DL_REPEAT, DWORD n)>\
        struct CNameIdHolderImpl\
        {\
            static LPCTSTR GetStr()\
            {\
                static const TCHAR szBuffer[] = {\
                                                    DL_REPEAT_MACRO_N(num, DL_FLATTEN_STR, n),\
                                                    _T('\0')\
                                                };\
                return szBuffer;\
            }\
        };\
    };
    
    NAME_ID_HOLDER_SPEC(15)
    NAME_ID_HOLDER_SPEC(14)
    NAME_ID_HOLDER_SPEC(13)
    NAME_ID_HOLDER_SPEC(12)
    NAME_ID_HOLDER_SPEC(11)
    NAME_ID_HOLDER_SPEC(10)
    NAME_ID_HOLDER_SPEC(9)
    NAME_ID_HOLDER_SPEC(8)
    NAME_ID_HOLDER_SPEC(7)
    NAME_ID_HOLDER_SPEC(6)
    NAME_ID_HOLDER_SPEC(5)
    NAME_ID_HOLDER_SPEC(4)
    NAME_ID_HOLDER_SPEC(3)
    NAME_ID_HOLDER_SPEC(2)
    NAME_ID_HOLDER_SPEC(1)
    
    template <>
    struct CNameIdHolder<0>
    {
        template <DL_REPEAT_N(MAX_DL_REPEAT, DWORD n)>
        struct CNameIdHolderImpl
        {
            static LPCTSTR GetStr()
            {
                return NULL;
            }
        };
    };
    
    #define NN_REP_COUNT_M(p, n) (!DL_CAT(p,n)) ? (n-1):
    
    template <DL_REPEAT_DEF_N(MAX_DL_REPEAT, DWORD n, = 0)>
    struct CNameId
    {
        enum
        {
            DL_REPEAT_PARAM_N(MAX_DL_REPEAT, m_n, =n),
            count   = DL_REPEAT_MACRO_IMPL_N(MAX_DL_REPEAT, NN_REP_COUNT_M, n, DL_EMPTY) MAX_DL_REPEAT,
            length  = count * sizeof(DWORD)
        };
        static LPCTSTR GetStr()
        {
            return CNameIdHolder<count>::template CNameIdHolderImpl<DL_REPEAT_N(MAX_DL_REPEAT, n)>::GetStr();
        }
    };
    
    template <class Name>
    class CModule
    {
    public:
        HMODULE m_hModule;
        typedef CModule<Name> type;
        typedef Name          name_type;
        static type &GetModule()
        {
            static type Module;
            return Module;
        }
        ~CModule()
        {
            if (m_hModule)
                FreeLibrary(m_hModule);
        }
    private:
        CModule()
        {
            m_hModule = LoadLibrary(name_type::GetStr());
        }
    };
    
    
    template <class Module, class Name, class Proxy>
    class CDynFunction
    {
    public:
        typedef CDynFunction<Module, Name, Proxy> type;
        typedef Proxy                              proxy_type;
        typedef Module                              module_type;
        typedef Name                              name_type;
        
        static proxy_type::fun_type &GetProxy()
        {
            static proxy_type::fun_type proxy = proxy_type::template Proxy<type>::ProxyFun;
            return proxy;
        }
        static BOOL InitFunction()
        {
            HMODULE hModule = Module::GetModule().m_hModule;
            if (hModule)
            {
                FARPROC pFunction = GetProcAddress(hModule, name_type::GetStr());
                if (pFunction)
                {
                    GetProxy() = (proxy_type::fun_type)pFunction;
                    return TRUE;
                }
            }
            return FALSE;
        }
    };
    
    
    
    struct CDynFunException
    {
        CDynFunException(): m_sMessage(NULL)
        {
        };
        ~CDynFunException()
        {
            free(m_sMessage);
        };
        CDynFunException(LPCTSTR sMessage):m_sMessage(NULL)
        {
            SetMessage(sMessage);
        }
        CDynFunException(const CDynFunException &other):m_sMessage(NULL)
        {
            SetMessage(other.m_sMessage);
        }
        CDynFunException &operator = (const CDynFunException &other)
        {
            SetMessage(other.m_sMessage);
            return *this;
        }
        void SetMessage(LPCTSTR sMessage)
        {
            free(m_sMessage);
            m_sMessage = (LPTSTR)malloc((_tcslen(sMessage) + 1) * sizeof(TCHAR));
            if (m_sMessage)
                _tcscpy(m_sMessage, sMessage);
        }
        LPCTSTR GetMessage() const
        {
            return m_sMessage;
        }
    private:
        LPTSTR m_sMessage;
    };
    
    template <class R> struct FunProxyThrowRetTypeTrait
    {
        template <class F>
        struct FunctionTraitImpl
        {
            static R MakeReturn()
            {
                F::MakeReturnImpl();
                return R();
            }
        };
    };
    
    template <> struct FunProxyThrowRetTypeTrait<void>
    {
        template <class F>
        struct FunctionTraitImpl
        {
            static void MakeReturn()
            {
                F::MakeReturnImpl();
            }
        };
    };
    
    template<class E = CDynFunException>
    struct FunProxyThrowPolicy
    {
        template <class DynFunction> 
        struct FunctionTrait:public FunProxyThrowRetTypeTrait<DynFunction::proxy_type::ret_type>::template FunctionTraitImpl<FunctionTrait<DynFunction> >
        {
            static void MakeReturnImpl()
            {
                TCHAR szMessage[DynFunction::name_type::length + 64];
                _stprintf(szMessage, _T("Can'n resolve procedure <%s>: %d"), DynFunction::name_type::GetStr(), GetLastError());
                throw E(szMessage);
            }
        };
    };
    
    
    //  we need not implement void return type value policy, 
    //  coz void function can only throw on error
    
    template<class R, R value = R()>
    struct FunProxyValuePolicy
    {
        template <class DynFunction> 
        struct FunctionTrait
        {
            static DynFunction::proxy_type::ret_type MakeReturn()
            {
                return value;
            }
        };
    };
    
    
    #define FUN_PROXY(n) DL_CAT(FunProxy,n)
    #define FUN_PROXY_IMPL(n) DL_CAT(FUN_PROXY(n),Impl)
    
    #define DECLARE_FUN_PROXY(param_count) \
    template <typename R> struct FUN_PROXY_IMPL(param_count)\
    {\
        template <class DynFunction, DL_REPEAT_N(param_count, typename P), class Policy> struct RetProxy\
        {\
            static R WINAPI ProxyFun(DL_REPEAT_PARAM_N(param_count, P, v))\
            {\
                if (DynFunction::InitFunction())\
                    return DynFunction::GetProxy()(DL_REPEAT_N(param_count, v));\
                return Policy::template FunctionTrait<DynFunction>::MakeReturn();\
            }\
        };\
    };\
    \
    template <> struct FUN_PROXY_IMPL(param_count) <void>\
    {\
        template <class DynFunction, DL_REPEAT_N(param_count, typename P), class Policy> struct RetProxy\
        {\
            static R WINAPI ProxyFun(DL_REPEAT_PARAM_N(param_count, P, v))\
            {\
                if (DynFunction::InitFunction())\
                    DynFunction::GetProxy()(DL_REPEAT_N(param_count, v));\
                else\
                    Policy::template FunctionTrait<DynFunction>::MakeReturn();\
            }\
        };\
    };\
    \
    template <typename R, DL_REPEAT_N(param_count, typename P), class Policy = FunProxyValuePolicy<R> > struct FUN_PROXY(param_count)\
    {\
        typedef R (WINAPI *fun_type)(DL_REPEAT_N(param_count, P));\
        typedef R ret_type;\
        template <class DynFunction> struct Proxy:public FUN_PROXY_IMPL(param_count)<R>::template RetProxy<DynFunction, DL_REPEAT_N(param_count, P), Policy>\
        {\
        };\
    };
    
    DECLARE_FUN_PROXY(1)
    DECLARE_FUN_PROXY(2)
    DECLARE_FUN_PROXY(3)
    DECLARE_FUN_PROXY(4)
    DECLARE_FUN_PROXY(5)
    DECLARE_FUN_PROXY(6)
    DECLARE_FUN_PROXY(7)
    DECLARE_FUN_PROXY(8)
    DECLARE_FUN_PROXY(9)
    DECLARE_FUN_PROXY(10)
    DECLARE_FUN_PROXY(11)
    DECLARE_FUN_PROXY(12)
    DECLARE_FUN_PROXY(13)
    DECLARE_FUN_PROXY(14)
    DECLARE_FUN_PROXY(15)
    DECLARE_FUN_PROXY(16)
    
    // usefull macro's
    
    #define DL_USE_MODULE_BEGIN(nmspace, NameId) \
    namespace nmspace \
    {\
        typedef CModule< CNameId<DL_SEQ_ENUM_CHAR(NameId)> > module_type;
    
    #define DL_USE_MODULE_END \
    };
    
    
    
    #define DL_DECLARE_FUN(NameId, R, P) \
    static R (WINAPI *&DL_SEQ_CAT(NameId))(DL_SEQ_ENUM(P)) = CDynFunction<module_type, CNameId<DL_SEQ_ENUM_CHAR(NameId)>, FUN_PROXY(DL_SEQ_SIZE(P))<R, DL_SEQ_ENUM(P)> >::GetProxy();
    
    #define DL_DECLARE_FUN_ERR(Name, NameId, R, P, E)\
    static R (WINAPI *&DL_SEQ_CAT(NameId))(DL_SEQ_ENUM(P)) = CDynFunction<module_type, CNameId<DL_SEQ_ENUM_CHAR(NameId)>, FUN_PROXY(DL_SEQ_SIZE(P))<R, DL_SEQ_ENUM(P), FunProxyValuePolicy<R,E> > >::GetProxy();
     
    #define DL_DECLARE_FUN_THROW(NameId, R, P)\
    static R (WINAPI *&DL_SEQ_CAT(NameId))(DL_SEQ_ENUM(P)) = CDynFunction<module_type, CNameId<DL_SEQ_ENUM_CHAR(NameId)>, FUN_PROXY(DL_SEQ_SIZE(P))<R, DL_SEQ_ENUM(P), FunProxyThrowPolicy<> > >::GetProxy();
    
    #endif
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[2]: Код v1.05 - пример использования
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 23.08.04 12:45
    Оценка:
    Пример использования:

    DL_USE_MODULE_BEGIN(kernel, (kern)(el32)(.dll))
        DL_DECLARE_FUN((GetP)(rocA)(ddre)(ss), FARPROC, (HMODULE)(LPCTSTR))
        DL_DECLARE_FUN((GetM)(odul)(eHan)(dleA), HMODULE, (LPCTSTR))
        DL_DECLARE_FUN_THROW((Init)(iali)(zeCr)(itic)(alSe)(ctio)(n), void, (LPCRITICAL_SECTION))
    DL_USE_MODULE_END
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[4]: Код v1.05 - пример использования
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 23.08.04 15:05
    Оценка:
    CAM>Зачем, скажи мне, тут вообще потребовались шаблоны для генерации имён ? Ведь макросы сплошные — сделай тогда уж всё на макросах. Я бы генерил макросом функцию, с указаной сигнатурой и именем, а внутри бы имел статический указатель, который бы и заполнял в момент первого вызова. Небольшой оверхед будет, конечно, но зато можно будет писать GetProcAddress вместо (GetP)(rocA)(ddre)(ss).

    Наверное, вам надо посмотреть хотя бы немного первый вариант кода (который практически без макросов) . Там ясно видно — почему и как. Макросы в дальнейшем появились _только_ для удобства записи.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[5]: Код v1.05 - пример использования
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 23.08.04 15:18
    Оценка:
    CAM>>Зачем, скажи мне, тут вообще потребовались шаблоны для генерации имён ? Ведь макросы сплошные — сделай тогда уж всё на макросах. Я бы генерил макросом функцию, с указаной сигнатурой и именем, а внутри бы имел статический указатель, который бы и заполнял в момент первого вызова. Небольшой оверхед будет, конечно, но зато можно будет писать GetProcAddress вместо (GetP)(rocA)(ddre)(ss).

    AS>Наверное, вам надо посмотреть хотя бы немного первый вариант кода (который практически без макросов) . Там ясно видно — почему и как. Макросы в дальнейшем появились _только_ для удобства записи.


    А хотя, вкупе с предложение WolfHound можно попробовать и так... и оверхеда не будет. Вот только кросс-модульность. Сейчас попробуем.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[3]: Код v1.05
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 23.08.04 15:25
    Оценка:
    WH>У меня тут такая мысль возникла а что если в место
    [skipped]

    Super! А кросс-модульность будет работать? Т.е. будем ли мы получать один прокси в результате специализаций одинаковыми NameId из разных модулей в этом случае?

    (P.S. только что попробовал — все работает, как и следовало ожидать).
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[4]: Код v1.05
    От: WolfHound  
    Дата: 23.08.04 15:53
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Super! А кросс-модульность будет работать? Т.е. будем ли мы получать один прокси в результате специализаций одинаковыми NameId из разных модулей в этом случае?

    1)Что ты понимаешь под модулем?
    2)По идеи этот вариант должен работать также как и твой.
    ... << RSDN@Home 1.1.4 rev. 142 >>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[5]: Код v1.05
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 23.08.04 15:56
    Оценка:
    AS>>Super! А кросс-модульность будет работать? Т.е. будем ли мы получать один прокси в результате специализаций одинаковыми NameId из разных модулей в этом случае?
    WH>1)Что ты понимаешь под модулем?
    Различные единицы компиляции. Уже проверил — все нормально, одинаковые прокси из разных единиц компиляции находятся после линка по одним адресам.

    WH>2)По идеи этот вариант должен работать также как и твой.


    Так и работает. Еще раз спасибо — самое очевидно решение я и не заметил. А ведь в первоначальном виде (без темплайтов) у нас идентификатор имени именно так и определялся — при помощит подобных макросов
    В общем, похоже мы нашли вариант специализировать шаблоны константной строкой, правда, при маленькой помощи препроцессора
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[7]: Код v1.05
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 23.08.04 16:57
    Оценка:
    AS>>Различные единицы компиляции.
    WH>Устоявшийся термин "единица трансляции"

    Ок, можно и так. Как барин скажет, так и будем
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[2]: код v1.06
    От: adontz Грузия http://adontz.wordpress.com/
    Дата: 23.08.04 17:36
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

  • Поддержка MT.

    В принципе вся "опасная" часть находится внутри InitFunction (я ничего не пропустил?). Самое простое это обернуть её в CriticalSection. Это тормознёт все потоки — что плохо. С другой стороны такой казалось бы легковесный объект как event отожрал у меня около 16 тыс тиков.
    for (int index = 0; index < 100000; index++)
     {
      CloseHandle(CreateEvent(NULL, FALSE, FALSE, _T("EVENT")));
     }

    Mutex отнял приблизительно столько же времени. На этом фоне очень привлекательны критические секции. Они судя по всему раза в 4 быстрее.
    Хотя вобщем-то не известно какие потоки запускает DllMain и как отразиться на программе то, что LoadLibrary вызван из критической секции.

  • Поддержка соглашений о вызовах кроме __stdcall.
  • Поддержка функций с переменным числом параметров.

    ИМХО только с привлечением ассемблера. Надо будет ProxyFun переписать.
    Собственно релиз в VC7.1 как раз и представляет собой то, что надо (параметры шаблонов опущены)
    call        CDynFunction<>::InitFunction (401730h) 
    test        eax,eax 
    je          error: 
    jmp         dword ptr [`CDynFunction<>::GetProxy'::`2'::proxy] 
    error:
    call        FunProxyThrowPolicy<>::MakeReturnImpl

    Как видишь этот код не завязан ни на количество параметров ни на конвенцию вызова.


    P.S. Вызов через такую обёртку даже быстрее вызова через таблицу импорта. Вот я и думаю, а не создать ли продвинутый файл windows (как string.h -> string) в котором все функции будут раскиданы по пространствам имён? Как побочный эффект своего рода антиотладка (передаю привер шароварщикам ) Эдакая МЕГАИДЕЯ
  • A journey of a thousand miles must begin with a single step © Lau Tsu
    Re[3]: код v1.06
    От: WolfHound  
    Дата: 23.08.04 18:19
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

    Придется делать так
    #define DECLARE_NAME_ID(id, name)\
    struct NAME_ID(id)\
    {\
        enum {length = sizeof(name)};\
        static LPCSTR GetStr(){return name;}\
        static LPCTSTR GetTStr(){return _T(name);}\
    };

    Ибо
    FARPROC GetProcAddress(
      HMODULE hModule,    // handle to DLL module
      LPCSTR lpProcName   // function name
    );
    
    HMODULE LoadLibrary(
      LPCTSTR lpFileName   // file name of module
    );

    (C)MSDN
    ... << RSDN@Home 1.1.4 rev. 142 >>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[3]: код v1.06
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 23.08.04 18:25
    Оценка:
    A>
  • Поддержка MT.

    A>В принципе вся "опасная" часть находится внутри InitFunction (я ничего не пропустил?). Самое простое это обернуть её в CriticalSection. Это тормознёт все потоки — что плохо. С другой стороны такой казалось бы легковесный объект как event отожрал у меня около 16 тыс тиков.


    Верно, но не совсем. На самом деле там 2 места в одной функции — собственно, сама функция и синглтон модуля. Т.е. надо будет по одному объекту синхронизации на модуль + по одному на каждую функцию. На первый взгляд, печально — но на самом деле, все несколько лучше — можно это все обернуть в lightweight mutex'ы — пример приводил WolfHound. Это обеспечит помимо простоты синхронизации еще и всего 4 байта оверхеда на функцию и модуль в MT версии, что имхо немного. Можно вообще LW мутекс привязать только к модулю или же к классу функций (например, сделать его параметр статическим синглтоном без конструктора, как и прокси, по параметру CDynFunction::Name или еще как — надо подумать. В общем, варианты есть, и не такие уж сложные\медленные, тем более, что все это только один раз вызываться будет).
    Вообще, на крайний случай — можно засинхронизировать только синглтон модулей, а сама функция на самом деле вполне реенернабельна.

    A>
  • Поддержка соглашений о вызовах кроме __stdcall.
    A>
  • Поддержка функций с переменным числом параметров.

    Тут придется поправить макросы. Но я подумал — что то расхотелось мне это делать. Не так и много целевых функций имеет отличные от STDCALL конвенции, к тому же в основном это _cdecl с переменным числом параметров, а их все равно легально кроме как через V версии не передать — а они все WINAPI. Т.е. практическая необходимость сомнительна. Поэтому я (пока?) решил на это забить.
  • http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[4]: код v1.06
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 23.08.04 18:56
    Оценка:
    WH>Придется делать так
    WH>
    WH>#define DECLARE_NAME_ID(id, name)\
    WH>struct NAME_ID(id)\
    WH>{\
    WH>    enum {length = sizeof(name)};\
    WH>    static LPCSTR GetStr(){return name;}\
    WH>    static LPCTSTR GetTStr(){return _T(name);}\
    WH>};
    WH>


    Ага. Я решил во избежание дублирования анси и не анси строк в юникодной версии (наверное, компиляторы выкинут ненужный код, но лучше не рисковать) сделать так:

    #define DECLARE_NAME_ID_IMPL(id, name, text)\
    struct NAME_ID(id)\
    {\
        enum {length = sizeof(name)};\
        static LPCSTR GetStr(){return text(name);}\
    };
    
    
    #define DECLARE_NAME_ID_A(id, name) DECLARE_NAME_ID_IMPL(id, name, DL_NONE)
    #define DECLARE_NAME_ID(id, name) DECLARE_NAME_ID_IMPL(id, name, _T)
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[5]: код v1.06б
    От: adontz Грузия http://adontz.wordpress.com/
    Дата: 23.08.04 19:57
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    Я тут взял на себя наглость прошёлся по коду regex'пами и проч. Изменения под Unicode и под VC7.1 внесены.


    // DelayLoad.h: Delay import helper
    // Developer: Andrew Solodovnikov
    // E-mail: none
    // Date: 23.08.2004
    //
    #pragma once
    //
    #define DL_MERGE_(x,y) x##y
    #define DL_MERGE(x,y) DL_MERGE_(x,y)
    //
    #define DL_COMMA() ,
    #define DL_EMPTY()
    //
    #define DL_REPEAT_IMPL_N_0(x, d)
    #define DL_REPEAT_IMPL_N_1(x, d) DL_MERGE(x,1)
    #define DL_REPEAT_IMPL_N_2(x, d) DL_REPEAT_IMPL_N_1(x, d)d() DL_MERGE(x,2)
    #define DL_REPEAT_IMPL_N_3(x, d) DL_REPEAT_IMPL_N_2(x, d)d() DL_MERGE(x,3)
    #define DL_REPEAT_IMPL_N_4(x, d) DL_REPEAT_IMPL_N_3(x, d)d() DL_MERGE(x,4)
    #define DL_REPEAT_IMPL_N_5(x, d) DL_REPEAT_IMPL_N_4(x, d)d() DL_MERGE(x,5)
    #define DL_REPEAT_IMPL_N_6(x, d) DL_REPEAT_IMPL_N_5(x, d)d() DL_MERGE(x,6)
    #define DL_REPEAT_IMPL_N_7(x, d) DL_REPEAT_IMPL_N_6(x, d)d() DL_MERGE(x,7)
    #define DL_REPEAT_IMPL_N_8(x, d) DL_REPEAT_IMPL_N_7(x, d)d() DL_MERGE(x,8)
    #define DL_REPEAT_IMPL_N_9(x, d) DL_REPEAT_IMPL_N_8(x, d)d() DL_MERGE(x,9)
    #define DL_REPEAT_IMPL_N_10(x, d) DL_REPEAT_IMPL_N_9(x, d)d() DL_MERGE(x,10)
    #define DL_REPEAT_IMPL_N_11(x, d) DL_REPEAT_IMPL_N_10(x, d)d() DL_MERGE(x,11)
    #define DL_REPEAT_IMPL_N_12(x, d) DL_REPEAT_IMPL_N_11(x, d)d() DL_MERGE(x,12)
    #define DL_REPEAT_IMPL_N_13(x, d) DL_REPEAT_IMPL_N_12(x, d)d() DL_MERGE(x,13)
    #define DL_REPEAT_IMPL_N_14(x, d) DL_REPEAT_IMPL_N_13(x, d)d() DL_MERGE(x,14)
    #define DL_REPEAT_IMPL_N_15(x, d) DL_REPEAT_IMPL_N_14(x, d)d() DL_MERGE(x,15)
    #define DL_REPEAT_IMPL_N_16(x, d) DL_REPEAT_IMPL_N_15(x, d)d() DL_MERGE(x,16)
    //
    #define DL_REPEAT_IMPL_N(n, x, d) DL_MERGE(DL_REPEAT_IMPL_N_,n)(x, d)
    //
    #define DL_REPEAT_N(n,x) DL_REPEAT_IMPL_N(n, x, DL_COMMA)
    //
    #define DL_REPEAT_PARAM_IMPL_N0(n, m, d1, d2)
    #define DL_REPEAT_PARAM_IMPL_N1(n, m, d1, d2) DL_MERGE(n,1) DL_MERGE(m,1)
    #define DL_REPEAT_PARAM_IMPL_N2(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N1(n, m, d1, d2)d1() DL_MERGE(n,2)d2() DL_MERGE(m,2)
    #define DL_REPEAT_PARAM_IMPL_N3(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N2(n, m, d1, d2)d1() DL_MERGE(n,3)d2() DL_MERGE(m,3)
    #define DL_REPEAT_PARAM_IMPL_N4(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N3(n, m, d1, d2)d1() DL_MERGE(n,4)d2() DL_MERGE(m,4)
    #define DL_REPEAT_PARAM_IMPL_N5(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N4(n, m, d1, d2)d1() DL_MERGE(n,5)d2() DL_MERGE(m,5)
    #define DL_REPEAT_PARAM_IMPL_N6(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N5(n, m, d1, d2)d1() DL_MERGE(n,6)d2() DL_MERGE(m,6)
    #define DL_REPEAT_PARAM_IMPL_N7(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N6(n, m, d1, d2)d1() DL_MERGE(n,7)d2() DL_MERGE(m,7)
    #define DL_REPEAT_PARAM_IMPL_N8(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N7(n, m, d1, d2)d1() DL_MERGE(n,8)d2() DL_MERGE(m,8)
    #define DL_REPEAT_PARAM_IMPL_N9(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N8(n, m, d1, d2)d1() DL_MERGE(n,9)d2() DL_MERGE(m,9)
    #define DL_REPEAT_PARAM_IMPL_N10(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N9(n, m, d1, d2)d1() DL_MERGE(n,10)d2() DL_MERGE(m,10)
    #define DL_REPEAT_PARAM_IMPL_N11(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N10(n, m, d1, d2)d1() DL_MERGE(n,11)d2() DL_MERGE(m,11)
    #define DL_REPEAT_PARAM_IMPL_N12(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N11(n, m, d1, d2)d1() DL_MERGE(n,12)d2() DL_MERGE(m,12)
    #define DL_REPEAT_PARAM_IMPL_N13(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N12(n, m, d1, d2)d1() DL_MERGE(n,13)d2() DL_MERGE(m,13)
    #define DL_REPEAT_PARAM_IMPL_N14(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N13(n, m, d1, d2)d1() DL_MERGE(n,14)d2() DL_MERGE(m,14)
    #define DL_REPEAT_PARAM_IMPL_N15(n, m, d1, d2) DL_REPEAT_PARAM_IMPL_N14(n, m, d1, d2)d1() DL_MERGE(n,15)d2() DL_MERGE(m,15)
    #define DL_REPEAT_PARAM_IMPL_N16(n,m, d1, d2) DL_REPEAT_PARAM_IMPL_N15(n, m, d1, d2)d1() DL_MERGE(n,16)d2() DL_MERGE(m,16)
    //
    #define DL_REPEAT_PARAM_IMPL_N(c, n, m, d1, d2) DL_MERGE(DL_REPEAT_PARAM_IMPL_N,c)(n, m, d1, d2)
    //
    #define DL_REPEAT_PARAM_N(c, n, m) DL_REPEAT_PARAM_IMPL_N(c, n, m, DL_COMMA, DL_EMPTY)
    //
    #define DL_SEQ_SIZE(seq) DL_SEQ_SIZE_IMPL(seq)
    #define DL_SEQ_SIZE_IMPL(seq) DL_MERGE(DL_N_, DL_SEQ_SIZE_0 seq)
    //
    #define DL_SEQ_SIZE_0(_) DL_SEQ_SIZE_1
    #define DL_SEQ_SIZE_1(_) DL_SEQ_SIZE_2
    #define DL_SEQ_SIZE_2(_) DL_SEQ_SIZE_3
    #define DL_SEQ_SIZE_3(_) DL_SEQ_SIZE_4
    #define DL_SEQ_SIZE_4(_) DL_SEQ_SIZE_5
    #define DL_SEQ_SIZE_5(_) DL_SEQ_SIZE_6
    #define DL_SEQ_SIZE_6(_) DL_SEQ_SIZE_7
    #define DL_SEQ_SIZE_7(_) DL_SEQ_SIZE_8
    #define DL_SEQ_SIZE_8(_) DL_SEQ_SIZE_9
    #define DL_SEQ_SIZE_9(_) DL_SEQ_SIZE_10
    #define DL_SEQ_SIZE_10(_) DL_SEQ_SIZE_11
    #define DL_SEQ_SIZE_11(_) DL_SEQ_SIZE_12
    #define DL_SEQ_SIZE_12(_) DL_SEQ_SIZE_13
    #define DL_SEQ_SIZE_13(_) DL_SEQ_SIZE_14
    #define DL_SEQ_SIZE_14(_) DL_SEQ_SIZE_15
    #define DL_SEQ_SIZE_15(_) DL_SEQ_SIZE_16
    //
    #define DL_N_DL_SEQ_SIZE_0 0
    #define DL_N_DL_SEQ_SIZE_1 1
    #define DL_N_DL_SEQ_SIZE_2 2
    #define DL_N_DL_SEQ_SIZE_3 3
    #define DL_N_DL_SEQ_SIZE_4 4
    #define DL_N_DL_SEQ_SIZE_5 5
    #define DL_N_DL_SEQ_SIZE_6 6
    #define DL_N_DL_SEQ_SIZE_7 7
    #define DL_N_DL_SEQ_SIZE_8 8
    #define DL_N_DL_SEQ_SIZE_9 9
    #define DL_N_DL_SEQ_SIZE_10 10
    #define DL_N_DL_SEQ_SIZE_11 11
    #define DL_N_DL_SEQ_SIZE_12 12
    #define DL_N_DL_SEQ_SIZE_13 13
    #define DL_N_DL_SEQ_SIZE_14 14
    #define DL_N_DL_SEQ_SIZE_15 15
    #define DL_N_DL_SEQ_SIZE_16 16
    //
    #define DL_SEQ_ENUM(seq) DL_SEQ_ENUM_IMPL(seq)
    #define DL_SEQ_ENUM_IMPL(seq) DL_MERGE(DL_SEQ_ENUM_, DL_SEQ_SIZE(seq)) seq
    //
    #define DL_SEQ_ENUM_1(x) x
    #define DL_SEQ_ENUM_2(x) x, DL_SEQ_ENUM_1
    #define DL_SEQ_ENUM_3(x) x, DL_SEQ_ENUM_2
    #define DL_SEQ_ENUM_4(x) x, DL_SEQ_ENUM_3
    #define DL_SEQ_ENUM_5(x) x, DL_SEQ_ENUM_4
    #define DL_SEQ_ENUM_6(x) x, DL_SEQ_ENUM_5
    #define DL_SEQ_ENUM_7(x) x, DL_SEQ_ENUM_6
    #define DL_SEQ_ENUM_8(x) x, DL_SEQ_ENUM_7
    #define DL_SEQ_ENUM_9(x) x, DL_SEQ_ENUM_8
    #define DL_SEQ_ENUM_10(x) x, DL_SEQ_ENUM_9
    #define DL_SEQ_ENUM_11(x) x, DL_SEQ_ENUM_10
    #define DL_SEQ_ENUM_12(x) x, DL_SEQ_ENUM_11
    #define DL_SEQ_ENUM_13(x) x, DL_SEQ_ENUM_12
    #define DL_SEQ_ENUM_14(x) x, DL_SEQ_ENUM_13
    #define DL_SEQ_ENUM_15(x) x, DL_SEQ_ENUM_14
    #define DL_SEQ_ENUM_16(x) x, DL_SEQ_ENUM_15
    //
    #define NAME_ID(id) DL_MERGE(CNameId, id)
    //
    #define DECLARE_NAME_ID(id, name, TYPE, modifier)\
    struct NAME_ID(id)\
        {\
            enum {length = sizeof(name)};\
            static TYPE GetStr() { return modifier(name); }\
        };
    //
    #define DECLARE_NAME_ID_A(id, name) DECLARE_NAME_ID(id, name, LPCSTR, DL_EMPTY() )
    #define DECLARE_NAME_ID_T(id, name) DECLARE_NAME_ID(id, name, LPCTSTR, TEXT)
    //
    template <class Name>
    class CModule
        {
            public:
                HMODULE m_hModule;
            public:
                typedef CModule<Name> type;
                typedef Name name_type;
            public:
                static type &GetModule()
                    {
                        static type Module;
                        return Module;
                    }
                ~CModule()
                    {
                        if (m_hModule)
                            {
                                FreeLibrary(m_hModule);
                            }
                    }
                private:
                    CModule()
                        {
                            m_hModule = LoadLibrary(name_type::GetStr());
                        }
        };
    //
    template <class Module, class Name, class Proxy>
    class CDynFunction
        {
            public:
                typedef CDynFunction<Module, Name, Proxy> type;
                typedef Proxy proxy_type;
                typedef Module module_type;
                typedef Name name_type;
            public:
                static typename proxy_type::fun_type &GetProxy()
                    {
                        static proxy_type::fun_type proxy = proxy_type::template Proxy<type>::ProxyFun;
                        return proxy;
                    }
                static BOOL InitFunction()
                    {
                        if (Module::GetModule().m_hModule)
                            {
                                FARPROC lpFunction = GetProcAddress(Module::GetModule().m_hModule, name_type::GetStr());
                                if (lpFunction)
                                    {
                                        GetProxy() = (proxy_type::fun_type)lpFunction;
                                        return TRUE;
                                    }
                            }
                        return FALSE;
                    }
        };
    //
    class CDynFunException
        {
            public:
                CDynFunException(): m_sMessage(NULL)
                    {
                    };
                ~CDynFunException()
                    {
                        free(m_sMessage);
                    };
                CDynFunException(LPCTSTR sMessage):m_sMessage(NULL)
                    {
                        SetMessage(sMessage);
                    }
                CDynFunException(const CDynFunException &other):m_sMessage(NULL)
                    {
                        SetMessage(other.m_sMessage);
                    }
                CDynFunException &operator = (const CDynFunException &other)
                    {
                        SetMessage(other.m_sMessage);
                        return *this;
                    }
                void SetMessage(LPCTSTR sMessage)
                    {
                        free(m_sMessage);
                        m_sMessage = (LPTSTR)malloc((_tcslen(sMessage) + 1) * sizeof(TCHAR));
                        if (m_sMessage)
                            {
                                _tcscpy(m_sMessage, sMessage);
                            }
                    }
                LPCTSTR GetMessage() const
                    {
                        return m_sMessage;
                    }
            private:
                LPTSTR m_sMessage;
        };
    //
    template <class R> struct FunProxyThrowRetTypeTrait
        {
            template <class F>
            struct FunctionTraitImpl
                {
                    static R MakeReturn()
                        {
                            F::MakeReturnImpl();
                            return R();
                        }
                };
        };
    //
    template <> struct FunProxyThrowRetTypeTrait<void>
        {
            template <class F>
            struct FunctionTraitImpl
                {
                    static void MakeReturn()
                        {
                            F::MakeReturnImpl();
                        }
                };
        };
    //
    template<class E = CDynFunException>
    struct FunProxyThrowPolicy
        {
            template <class DynFunction>
            struct FunctionTrait:public FunProxyThrowRetTypeTrait<typename DynFunction::proxy_type::ret_type>::template FunctionTraitImpl<FunctionTrait<DynFunction> >
                {
                    static void MakeReturnImpl()
                        {
                            TCHAR szMessage[DynFunction::name_type::length + 64];
                            _stprintf(szMessage, _T("Can'n resolve procedure <%s>: %d"), DynFunction::name_type::GetStr(), GetLastError());
                            throw E(szMessage);
                            }
                };
        };
    //
    template<class R, R value = R()>
    struct FunProxyValuePolicy
        {
            template <class DynFunction>
            struct FunctionTrait
                {
                    static typename DynFunction::proxy_type::ret_type MakeReturn()
                        {
                            return value;
                        }
                };
        };
    //
    #define DL_FUN_PROXY(n) DL_MERGE(FunProxy,n)
    #define DL_FUN_PROXY_IMPL(n) DL_MERGE(DL_FUN_PROXY(n),Impl)
    //
    #define DECLARE_FUN_PROXY(param_count) \
    template <typename R> \
    struct DL_FUN_PROXY_IMPL(param_count) \
        { \
            template <class DynFunction, DL_REPEAT_N(param_count, typename P), class Policy> \
            struct RetProxy \
                { \
                    static R WINAPI ProxyFun(DL_REPEAT_PARAM_N(param_count, P, v)) \
                        { \
                            if (DynFunction::InitFunction()) \
                                { \
                                    return DynFunction::GetProxy()(DL_REPEAT_N(param_count, v)); \
                                } \
                            else \
                                { \
                                    return Policy::template FunctionTrait<DynFunction>::MakeReturn(); \
                                } \
                        }\
                };\
        };\
    \
    template <> \
    struct DL_FUN_PROXY_IMPL(param_count) <void> \
        { \
            template <class DynFunction, DL_REPEAT_N(param_count, typename P), class Policy> \
            struct RetProxy \
                { \
                    static void WINAPI ProxyFun(DL_REPEAT_PARAM_N(param_count, P, v)) \
                        { \
                            if (DynFunction::InitFunction()) \
                                DynFunction::GetProxy()(DL_REPEAT_N(param_count, v)); \
                            else \
                                Policy::template FunctionTrait<DynFunction>::MakeReturn(); \
                        } \
                }; \
        }; \
    \
    template <typename R, DL_REPEAT_N(param_count, typename P), class Policy = FunProxyValuePolicy<R> > \
    struct DL_FUN_PROXY(param_count) \
        { \
            typedef R (WINAPI *fun_type)(DL_REPEAT_N(param_count, P)); \
            typedef R ret_type; \
            template <class DynFunction> \
            struct Proxy: public DL_FUN_PROXY_IMPL(param_count)<R>::template RetProxy<DynFunction, DL_REPEAT_N(param_count, P), Policy> \
                    { \
                    }; \
    };
    //
    DECLARE_FUN_PROXY(1)
    DECLARE_FUN_PROXY(2)
    DECLARE_FUN_PROXY(3)
    DECLARE_FUN_PROXY(4)
    DECLARE_FUN_PROXY(5)
    DECLARE_FUN_PROXY(6)
    DECLARE_FUN_PROXY(7)
    DECLARE_FUN_PROXY(8)
    DECLARE_FUN_PROXY(9)
    DECLARE_FUN_PROXY(10)
    DECLARE_FUN_PROXY(11)
    DECLARE_FUN_PROXY(12)
    DECLARE_FUN_PROXY(13)
    DECLARE_FUN_PROXY(14)
    DECLARE_FUN_PROXY(15)
    DECLARE_FUN_PROXY(16)
    //
    #define DL_USE_MODULE_BEGIN(nmspace, name) \
    namespace nmspace \
        { \
            DECLARE_NAME_ID_T(_MODULE_##nmspace, name) \
            typedef CModule<NAME_ID(_MODULE_##nmspace)> module_type;
    //
    #define DL_USE_MODULE_END \
        };
    //
    #define DL_DECLARE_FUN(NameId, R, P) \
    DECLARE_NAME_ID_A(NameId, #NameId) \
    static R (WINAPI *&NameId)(DL_SEQ_ENUM(P)) = CDynFunction<module_type, NAME_ID(NameId), DL_FUN_PROXY(DL_SEQ_SIZE(P))<R, DL_SEQ_ENUM(P)> >::GetProxy();
    //
    #define DL_DECLARE_FUN_ERR(Name, NameId, R, P, E) \
    DECLARE_NAME_ID_A(NameId, #NameId) \
    static R (WINAPI *&NameId)(DL_SEQ_ENUM(P)) = CDynFunction<module_type, NAME_ID(NameId), DL_FUN_PROXY(DL_SEQ_SIZE(P))<R, DL_SEQ_ENUM(P), FunProxyValuePolicy<R,E> > >::GetProxy();
    //
    #define DL_DECLARE_FUN_THROW(NameId, R, P) \
    DECLARE_NAME_ID_A(NameId, #NameId) \
    static R (WINAPI *&NameId)(DL_SEQ_ENUM(P)) = CDynFunction<module_type, NAME_ID(NameId), DL_FUN_PROXY(DL_SEQ_SIZE(P))<R, DL_SEQ_ENUM(P), FunProxyThrowPolicy<> > >::GetProxy();
    //
    // End of file
    //
    A journey of a thousand miles must begin with a single step © Lau Tsu
    Re[6]: код v1.06б
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 23.08.04 20:31
    Оценка:
    A>Я тут взял на себя наглость прошёлся по коду regex'пами и проч. Изменения под Unicode и под VC7.1 внесены.

    Не, мне такое форматирование не нравится Не по стандарту (нашему, по крайней мере). Одни отсупы {} чего стоят. Да и переименование макроса CAT в MERGE тоже не по стандарту — в бусте именно CAT и хочется этому хоть как то соответствовать. Опять же, у меня еще несколько изменений касательно авто-поддержки юникода (да, да, именно авто поддержки, на основе заголовков от обычных, статически линкуемых бибилотек), которые я тут еще не отражал. В общем, думаю, пока что не стоит форматировать сурсы (по крайней мере публично — локально можно конечно делать что угодно ) — бесполезный труд, у меня еще слишком много чего есть, и конкатенировать после таких изменений сложно Но в любом случае — спасибо за попытку!
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[7]: код v1.06б
    От: adontz Грузия http://adontz.wordpress.com/
    Дата: 23.08.04 21:55
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Да и переименование макроса CAT в MERGE тоже не по стандарту — в бусте именно CAT и хочется этому хоть как-то соответствовать.


    Это совершенно не соответствует англо-русскому словарю В доке к ## preprocessor operator так и написано

    The double-number-sign or "token-pasting" operator (##), which is sometimes called the "merging" operator, is used in both object-like and function-like macros.

    А о чём думали в бусте я не знаю Cat это кошка Я кошек люблю, но здесь они не к месту.

    AS>Опять же, у меня еще несколько изменений касательно авто-поддержки юникода (да, да, именно авто поддержки, на основе заголовков от обычных, статически линкуемых бибилотек), которые я тут еще не отражал.


    А что ещё? Там же макросы типа
    #ifdef _UNICODE
    #define Func FuncW
    #else
    #define Func FuncA
    #endif

    Что ещё туда добавлять? Func на FuncA или FuncW будет заменятся вне зависимости он нашего желания. Со структурами тоже самое. В unicode я это дело уже компилировал (1.06б) всё ОК.
    Я что-то упустил?

    AS>В общем, думаю, пока что не стоит форматировать сурсы (по крайней мере публично — локально можно конечно делать что угодно ) — бесполезный труд, у меня еще слишком много чего есть, и конкатенировать после таких изменений сложно Но в любом случае — спасибо за попытку!


    Отступы только делай табуляцией.
    A journey of a thousand miles must begin with a single step © Lau Tsu
    Re[8]: код v1.06б
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 23.08.04 22:03
    Оценка:
    AS>>Да и переименование макроса CAT в MERGE тоже не по стандарту — в бусте именно CAT и хочется этому хоть как-то соответствовать.

    A>Это совершенно не соответствует англо-русскому словарю В доке к ## preprocessor operator так и написано


    Соответствует.
    A>А о чём думали в бусте я не знаю Cat это кошка Я кошек люблю, но здесь они не к месту.

    Это сокращение от concatenate и достаточно точно отражает смысл, как мне кажется В отличие от MERGE — которое значит совмещать, но не соединять. Вообше, merge на мой взгляд больше применим к множествам, а конкатинация — к последовательностям.

    AS>>Опять же, у меня еще несколько изменений касательно авто-поддержки юникода (да, да, именно авто поддержки, на основе заголовков от обычных, статически линкуемых бибилотек), которые я тут еще не отражал.


    A>А что ещё? Там же макросы типа

    A>
    A>#ifdef _UNICODE
    A>#define Func FuncW
    A>#else
    A>#define Func FuncA
    A>#endif
    A>

    A>Что ещё туда добавлять? Func на FuncA или FuncW будет заменятся вне зависимости он нашего желания. Со структурами тоже самое. В unicode я это дело уже компилировал (1.06б) всё ОК.
    A>Я что-то упустил?

    Конечно. В текущей версии DECLARE_NAME_ID(NameId, #NameId) раскроет LoadLibrary именно в "LoadLibrary" вне зависимости от нашего (не)желания.
    AS>>В общем, думаю, пока что не стоит форматировать сурсы (по крайней мере публично — локально можно конечно делать что угодно ) — бесполезный труд, у меня еще слишком много чего есть, и конкатенировать после таких изменений сложно Но в любом случае — спасибо за попытку!

    A>Отступы только делай табуляцией.


    Дык я вроде ей и делаю (точнее, VAssist делает). Если где что и упустил — или по своему недосмотру, или спостил изменения с форума. Или ты имеешь ввиду отсуп между типом и именем определения (ну или директивой\именем)? Там да, я по-привычке ставлю пробелы. Попробую поправить.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[9]: код v1.06б
    От: adontz Грузия http://adontz.wordpress.com/
    Дата: 23.08.04 22:25
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Это сокращение от concatenate и достаточно точно отражает смысл, как мне кажется В отличие от MERGE — которое значит совмещать, но не соединять.

    Скорее объединять.

    AS>Вообше, merge на мой взгляд больше применим к множествам, а конкатинация — к последовательностям.

    Ну я за имя не дерусь, используется этот макрос всё равно только в служебных целях. Просто для меня оно показалось непонятным.

    AS>Конечно. В текущей версии DECLARE_NAME_ID(NameId, #NameId) раскроет LoadLibrary именно в "LoadLibrary" вне зависимости от нашего (не)желания.


    Ну и? У одних функций есть A/W версии у других нету. ИМХО лучше сделать
    DL_USE_MODULE_BEGIN(kernel, "kernel32.dll")
        DL_DECLARE_FUN(GetModuleHandleA, HMODULE, (LPCSTR))
        DL_DECLARE_FUN(GetModuleHandleW, HMODULE, (LPCWSTR))
    DL_USE_MODULE_END
    чем
    DL_USE_MODULE_BEGIN(kernel, "kernel32.dll")
        DL_DECLARE_FUN_DUAL(GetModuleHandle, HMODULE, (LPC??что здесь писать??STR))
    DL_USE_MODULE_END

    A>>Отступы только делай табуляцией.
    AS>Дык я вроде ей и делаю (точнее, VAssist делает).

    Нет, это я зря ругаюсь. Если копировать с сайта, то по любому пробелы, даже если в исходном сообщении табуляция.
    Единственный шанс получить текст с табуляцией это копировать из цитирования в форме ответа
    Зато если в студии выделить всё и нажать Tab, Shift+Tab то всё будет как надо но это в 7.1, а в 6ке не знаю как.
    A journey of a thousand miles must begin with a single step © Lau Tsu
    Re[10]: код v1.06б
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 24.08.04 07:39
    Оценка:
    A>Ну и? У одних функций есть A/W версии у других нету. ИМХО лучше сделать
    A>
    A>DL_USE_MODULE_BEGIN(kernel, "kernel32.dll")
    A>    DL_DECLARE_FUN(GetModuleHandleA, HMODULE, (LPCSTR))
    A>    DL_DECLARE_FUN(GetModuleHandleW, HMODULE, (LPCWSTR))
    A>DL_USE_MODULE_END
    A>
    чем

    A>
    A>DL_USE_MODULE_BEGIN(kernel, "kernel32.dll")
    A>    DL_DECLARE_FUN_DUAL(GetModuleHandle, HMODULE, (LPC??что здесь писать??STR))
    A>DL_USE_MODULE_END
    A>


    А здесь писать
    DL_USE_MODULE_BEGIN(kernel, "kernel32.dll")
    DL_DECLARE_FUN_DUAL(GetModuleHandle, HMODULE, (LPCTSTR))
    DL_USE_MODULE_END

    В этом то и фишка. На самом деле, за нас все сделает препроцессор, маленький трюк, как и с CAT, на самом деле — заставить его вывести макрос до дальнейшего препроцессирования.

    A>>>Отступы только делай табуляцией.

    AS>>Дык я вроде ей и делаю (точнее, VAssist делает).

    A>Нет, это я зря ругаюсь. Если копировать с сайта, то по любому пробелы, даже если в исходном сообщении табуляция.

    A>Единственный шанс получить текст с табуляцией это копировать из цитирования в форме ответа
    A>Зато если в студии выделить всё и нажать Tab, Shift+Tab то всё будет как надо но это в 7.1, а в 6ке не знаю как.

    У меня вроде как с табами копируется, а если целевой редактор понимает — то даже и RTF. VAssist — великая штука.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[2]: код v1.06
    От: _nn_ www.nemerleweb.com
    Дата: 24.08.04 08:07
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Список изменений:


    AS>[list]

    AS>Изменены порождающие макросы (спасибо WolfHound). Теперь синтаксис стал гораздо более очевидным и нативным:
    AS>
    AS>DL_USE_MODULE_BEGIN(kernel, "kernel32.dll")
    AS>    DL_DECLARE_FUN(GetProcAddress, FARPROC, (HMODULE)(LPCTSTR))
    AS>    DL_DECLARE_FUN(GetModuleHandleA, HMODULE, (LPCTSTR))
    AS>    DL_DECLARE_FUN_THROW(InitializeCriticalSection, void, (LPCRITICAL_SECTION))
    AS>DL_USE_MODULE_END
    AS>


    Маленкое замечание :

    Что будет если написать так :
    DL_USE_MODULE_BEGIN(kernel, L"kernel32.dll")


    Мне кажется в CNameId будет немного неправильные значения.

    Решение 1 :
    передавать тип в макрос :
    DL_USE_MODULE_BEGIN(kernel, WCHAR, L"kernel32.dll")


    Решение 2 :
    Сделать два набора классов :
    template<typename T>
    CNameIdT {...}
    
    typedef CNameIdT<CHAR> CNameIdA;
    typedef CNameIdT<WCHAR> CNameIdW;
    
    #ifdef UNICODE
    typedef CNameIdW CNameId;
    #define DL_USE_MODULE_BEGIN DL_USE_MODULE_BEGIN_W
    #else
    typedef CNameIdA CNameId;
    #define DL_USE_MODULE_BEGIN DL_USE_MODULE_BEGIN_A
    #endif
    
    // явно
    DL_USE_MODULE_BEGIN_A(kernel, "kernel32.dll")
    DL_USE_MODULE_BEGIN_W(kernel, L"kernel32.dll")
    
    // неявно
    DL_USE_MODULE_BEGIN(kernel, "kernel32.dll")
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[2]: код v1.06
    От: CAMAD Россия  
    Дата: 24.08.04 10:59
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    ...

    AS>To do


    AS>Поддержка MT.


    Я не вижу проблемы с MT. Запись/чтение выравненного двойного слова атомарна, поэтому худшее, что может быть — лишний вызов GetProcAddress.

    Ещё у меня предложение — вместо разных макросов, для разных способов обработки ошибок позволить в макросе указывать функцию-обработчик, с таким же возвращаемым значенем, как и генерируемая функция. Таким образом будет выбор, или возвратить что-то инвалидное, или сделать throw / RaiseException. Кроме того, исчезнет зависимость от sprintf'а. Конечно, указывать в каждой функции обработчик ошибок — накладно, пока могу предложить только "глобальный" обработчик, который будет указываться в DL_USE_MODULE_BEGIN.

    Кстати, я вижу, что ошибки с LoadModule никак не обрабатываются, и единственный способ узнать, что dll'ки нет — это самостоятельно проверить CModule::GetModule на 0.
    Re[3]: код v1.06
    От: CAMAD Россия  
    Дата: 24.08.04 11:02
    Оценка:
    Здравствуйте, CAMAD, Вы писали:

    ...

    CAM>Кстати, я вижу, что ошибки с LoadModule никак не обрабатываются, и единственный способ узнать, что dll'ки нет — это самостоятельно проверить CModule::GetModule на 0.


    Имелось в виду LoadLibrary.
    Re[3]: код v1.06
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 24.08.04 11:23
    Оценка:
    AS>>To do

    AS>>Поддержка MT.


    CAM>Я не вижу проблемы с MT. Запись/чтение выравненного двойного слова атомарна, поэтому худшее, что может быть — лишний вызов GetProcAddress.


    А я вижу. Читайте соотв. пост

    CAM>Ещё у меня предложение — вместо разных макросов, для разных способов обработки ошибок позволить в макросе указывать функцию-обработчик, с таким же возвращаемым значенем, как и генерируемая функция. Таким образом будет выбор, или возвратить что-то инвалидное, или сделать throw / RaiseException. Кроме того, исчезнет зависимость от sprintf'а. Конечно, указывать в каждой функции обработчик ошибок — накладно, пока могу предложить только "глобальный" обработчик, который будет указываться в DL_USE_MODULE_BEGIN.


    Политики удобнее. Это не только мое менение.

    CAM>Кстати, я вижу, что ошибки с LoadModule никак не обрабатываются, и единственный способ узнать, что dll'ки нет — это самостоятельно проверить CModule::GetModule на 0.


    Обрабатываются — вызывается соотв. политика ошибки. В ней есть доступ как к типу модуля, так и к типу функции, чего вполне досточно для формирования _любого_ сообщения об ошибке.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[4]: код v1.06
    От: CAMAD Россия  
    Дата: 24.08.04 12:09
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>>>To do


    AS>>>Поддержка MT.


    CAM>>Я не вижу проблемы с MT. Запись/чтение выравненного двойного слова атомарна, поэтому худшее, что может быть — лишний вызов GetProcAddress.


    AS>А я вижу. Читайте соотв. пост


    Пожалуйста объясни, какие ты видишь проблемы с MT в функции InitFunction.

    CAM>>Ещё у меня предложение — вместо разных макросов, для разных способов обработки ошибок позволить в макросе указывать функцию-обработчик, с таким же возвращаемым значенем, как и генерируемая функция. Таким образом будет выбор, или возвратить что-то инвалидное, или сделать throw / RaiseException. Кроме того, исчезнет зависимость от sprintf'а. Конечно, указывать в каждой функции обработчик ошибок — накладно, пока могу предложить только "глобальный" обработчик, который будет указываться в DL_USE_MODULE_BEGIN.


    AS>Политики удобнее. Это не только мое менение.


    Во-первых, они у тебя "зашиты", поэтому толку от них — 0. Я как раз и предлагаю позволить их указывать в макросе. Потому-что я, например, не хочу ловить твой CDynFunException, или вообще, у меня EH отключен, и я хочу кинуть виндовое исключение.
    Во-вторых, даже если ты их позволишь указывать, то функции будут удобнее, потому-что "объектность" политики, наличие у неё состояния, как у объекта — не нужно. Функции тут самое то. Кроме того, меньше писать.

    Насчёт полезности политик — я согласен, но в данном случае они лишние.

    CAM>>Кстати, я вижу, что ошибки с LoadModule никак не обрабатываются, и единственный способ узнать, что dll'ки нет — это самостоятельно проверить CModule::GetModule на 0.


    AS>Обрабатываются — вызывается соотв. политика ошибки. В ней есть доступ как к типу модуля, так и к типу функции, чего вполне досточно для формирования _любого_ сообщения об ошибке.


    Даа, _любое_ сообщение можно сформировать. Вот только в MakeReturn непонятно, _что_ не так — то ли LoadLibrary не удался, и GetModule().m_hModule вернула 0, то ли функция не найдена и GetProcAddress вернула 0.
    Re[5]: код v1.06
    От: CAMAD Россия  
    Дата: 24.08.04 12:16
    Оценка:
    Здравствуйте, CAMAD, Вы писали:

    ...

    CAM>>Кстати, я вижу, что ошибки с LoadModule никак не обрабатываются, и единственный способ узнать, что dll'ки нет — это самостоятельно проверить CModule::GetModule на 0.


    AS>>Обрабатываются — вызывается соотв. политика ошибки. В ней есть доступ как к типу модуля, так и к типу функции, чего вполне досточно для формирования _любого_ сообщения об ошибке.


    Блин, опять что-то забыл.
    Я имел в виду, что, например, если dllка не найдена (т.е. CModule::m_hModule==0), то может потребоваться вообще показать мессадж бокс и завершиться.

    Кстати, как насчёт переименовать CModule::GetModule() в CModule::GetInstance(), и добавить

    HMODULE CModule::GetHandle() {
     return GetInstance().m_hModule;
    }

    ?

    Мне кажется kernel::CModule::GetHandle() выглядит красивее, чем kernel::CModule().GetModule().m_hModule.
    Re[5]: код v1.06
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 24.08.04 12:28
    Оценка:
    CAM>Пожалуйста объясни, какие ты видишь проблемы с MT в функции InitFunction.

    Синглтон майерса не потокобезопасен. В данном случае он используется в CModule. Там можно немного и по-другому, но проблему это не снимет.

    CAM>>>Ещё у меня предложение — вместо разных макросов, для разных способов обработки ошибок позволить в макросе CAM>Во-первых, они у тебя "зашиты", поэтому толку от них — 0. Я как раз и предлагаю позволить их указывать в макросе. Потому-что я, например, не хочу ловить твой CDynFunException, или вообще, у меня EH отключен, и я хочу кинуть виндовое исключение.

    CAM>Во-вторых, даже если ты их позволишь указывать, то функции будут удобнее, потому-что "объектность" политики, наличие у неё состояния, как у объекта — не нужно. Функции тут самое то. Кроме того, меньше писать.

    CAM>Насчёт полезности политик — я согласен, но в данном случае они лишние.


    Верно, насчет макроса, который позволит задавать политики, я как то забыл. Будет просто еще один макрос.

    CAM>>>Кстати, я вижу, что ошибки с LoadModule никак не обрабатываются, и единственный способ узнать, что dll'ки нет — это самостоятельно проверить CModule::GetModule на 0.


    AS>>Обрабатываются — вызывается соотв. политика ошибки. В ней есть доступ как к типу модуля, так и к типу функции, чего вполне досточно для формирования _любого_ сообщения об ошибке.


    CAM>Даа, _любое_ сообщение можно сформировать. Вот только в MakeReturn непонятно, _что_ не так — то ли LoadLibrary не удался, и GetModule().m_hModule вернула 0, то ли функция не найдена и GetProcAddress вернула 0.


    Анализируйте GetLastError(). Но я не думаю, что есть большая разница между ненахождение функции и незагрузкой модуля — технически это _одно_ неверное действие — невозможность отрезолвить функцию. Впрочем, вероятно, мысль сделать политики ошибки загрузки модуля тоже неплохая — если общественность поддержит, сделаю. Хотя, в этом случае будет возникать ситуация вызова аж 2-х политик в случае ошибки загрузки модуля, что на мой взгляд, неправильно. (технически это исправить несложно, но это возникает именно _логически_)
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[6]: код v1.06
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 24.08.04 12:31
    Оценка:
    CAM>Кстати, как насчёт переименовать CModule::GetModule() в CModule::GetInstance(), и добавить

    CAM>
    CAM>HMODULE CModule::GetHandle() {
    CAM> return GetInstance().m_hModule;
    CAM>}
    CAM>

    CAM>?

    CAM>Мне кажется kernel::CModule::GetHandle() выглядит красивее, чем kernel::CModule().GetModule().m_hModule.


    Думаю, не стоит. Зачем посторонним доступ к хандлу модуля А вот сделать метод GetProcAddress и вызывать именно его — это то, что надо, на мой взгляд.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[7]: код v1.06
    От: CAMAD Россия  
    Дата: 24.08.04 13:23
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    CAM>>Кстати, как насчёт переименовать CModule::GetModule() в CModule::GetInstance(), и добавить


    CAM>>
    CAM>>HMODULE CModule::GetHandle() {
    CAM>> return GetInstance().m_hModule;
    CAM>>}
    CAM>>

    CAM>>?

    CAM>>Мне кажется kernel::CModule::GetHandle() выглядит красивее, чем kernel::CModule().GetModule().m_hModule.


    AS>Думаю, не стоит. Зачем посторонним доступ к хандлу модуля А вот сделать метод GetProcAddress и вызывать именно его — это то, что надо, на мой взгляд.


    Я всё пытаюсь тебе сказать, что нужен способ узнать, что DLL не загрузилась. Если ты не хочешь сделать policy на этот случай — остаётся только проверка хэндла ручками. И по-моему, kernel::CModule::GetHandle() будет нагляднее.
    Хотя даже сделай ты policy — всё равно нужно дать возможность проверять ручками, потому-что обрабатывать ошибку отсутствия DLLки скорее всего придётся штатно, в какой-нибудь InitInstance.
    Re[6]: код v1.06
    От: CAMAD Россия  
    Дата: 24.08.04 13:39
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    CAM>>Пожалуйста объясни, какие ты видишь проблемы с MT в функции InitFunction.


    AS>Синглтон майерса не потокобезопасен. В данном случае он используется в CModule. Там можно немного и по-другому, но проблему это не снимет.


    Синглтон майерса — умное слово. У тебя есть HMODULE, который суть void*, и есть функции его проверки и установки. Они атомарны. Худшее, что может быть, опять — последовательный вызов LoadLibrary.

    Код может выглядеть так :

    class CModule {
    public:
      static HMODULE GetHandle() {
        if (!GetHandleRef()) {
          GetHandleRef()=LoadLibrary();
        }
        return GetHandleRef();
      }
    private:
      static HMODULE & GetHandleRef() {
        static HMODULE handle=0;
        return &handle;
      }
    };


    Или так :


    class CModule {
    public:
      static HMODULE GetHandle() {
        if (m_handle) {
          m_handle=LoadLibrary();
        }
        return m_handle;
      }
    private:
      static HMODULE m_handle;
    };
    
    __declspec(selectany) CModule::m_handle=0;


    ...

    AS>Анализируйте GetLastError(). Но я не думаю, что есть большая разница между ненахождение функции и незагрузкой модуля — технически это _одно_ неверное действие — невозможность отрезолвить функцию. Впрочем, вероятно, мысль сделать политики ошибки загрузки модуля тоже неплохая — если общественность поддержит, сделаю. Хотя, в этом случае будет возникать ситуация вызова аж 2-х политик в случае ошибки загрузки модуля, что на мой взгляд, неправильно. (технически это исправить несложно, но это возникает именно _логически_)


    Возможно, ты прав, на счёт небольшой разницы этих двух ситуаций, однако по-моему предпочтительнее дать пользователям возможность решать, что для них важно и нужно. Когда есть возможность, ей можно и не пользоваться, а вот когда её нет, и она нужна, то возникают проблемы.
    Re[7]: код v1.06
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 24.08.04 13:54
    Оценка:
    CAM>>>Пожалуйста объясни, какие ты видишь проблемы с MT в функции InitFunction.

    AS>>Синглтон майерса не потокобезопасен. В данном случае он используется в CModule. Там можно немного и по-другому, но проблему это не снимет.


    CAM>Синглтон майерса — умное слово. У тебя есть HMODULE, который суть void*, и есть функции его проверки и установки. Они атомарны. Худшее, что может быть, опять — последовательный вызов LoadLibrary.


    Ага, а регистрировать функцию для выполнения FreeLibrary (AtExit) вы будете ручками.
    В общем, нет, все не то. Почитайте топик про синглтон майерса в форуме cpp и проникнитесь. До этого обсуждать что-либо про MT нет смысла.

    AS>>Анализируйте GetLastError(). Но я не думаю, что есть большая разница между ненахождение функции и незагрузкой модуля — технически это _одно_ неверное действие — невозможность отрезолвить функцию. Впрочем, вероятно, мысль сделать политики ошибки загрузки модуля тоже неплохая — если общественность поддержит, сделаю. Хотя, в этом случае будет возникать ситуация вызова аж 2-х политик в случае ошибки загрузки модуля, что на мой взгляд, неправильно. (технически это исправить несложно, но это возникает именно _логически_)


    CAM>Возможно, ты прав, на счёт небольшой разницы этих двух ситуаций, однако по-моему предпочтительнее дать пользователям возможность решать, что для них важно и нужно. Когда есть возможность, ей можно и не пользоваться, а вот когда её нет, и она нужна, то возникают проблемы.


    НИКАКОЙ проблемы нет. Если m_hModule == 0 — значит, ошибка относится к загрузке модуля, иначе — к функции. Ну где здесь проблемы, не понимаю? Макрос, позволяющий задавать свою policy, я уже сделал.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[3]: код v1.06
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 24.08.04 13:58
    Оценка:
    __>Маленкое замечание :

    __>Что будет если написать так :

    __>
    __>DL_USE_MODULE_BEGIN(kernel, L"kernel32.dll")
    __>


    __>Мне кажется в CNameId будет немного неправильные значения.


    __>Решение 1 :


    Если так написать, код просто не откомпилируется
    error C2440: 'return' : cannot convert from 'unsigned short [13]' to 'const char *'
            Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[8]: код v1.06
    От: CAMAD Россия  
    Дата: 24.08.04 14:13
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    CAM>>>>Пожалуйста объясни, какие ты видишь проблемы с MT в функции InitFunction.


    AS>>>Синглтон майерса не потокобезопасен. В данном случае он используется в CModule. Там можно немного и по-другому, но проблему это не снимет.


    CAM>>Синглтон майерса — умное слово. У тебя есть HMODULE, который суть void*, и есть функции его проверки и установки. Они атомарны. Худшее, что может быть, опять — последовательный вызов LoadLibrary.


    AS>Ага, а регистрировать функцию для выполнения FreeLibrary (AtExit) вы будете ручками.

    AS>В общем, нет, все не то. Почитайте топик про синглтон майерса в форуме cpp и проникнитесь. До этого обсуждать что-либо про MT нет смысла.

    Фу, как позорно облажался !
    Хотя, зная, что такое синглтон майерса, я бы сделал так :

    class CModule {
      class Destroyer {
      public:
        ~Destroyer() {
          if (CModule::GetHandleRef()) {
            FreeLibrary(CModule::GetHandleRef());
          }
        }
      };
      friend Destroyer;
    public:
      static HMODULE GetHandle() {
        static Destroyer destroyer;
        if (!GetHandleRef()) {
          GetHandleRef()=LoadLibrary();
        }
        return GetHandleRef();
      }
    private:
      static HMODULE & GetHandleRef() {
        static HMODULE handle=0;
        return &handle;
      }
    };


    И по прежнему этот вариант лучше, чем любой с CriticalSection/Mutex'ами.

    ....

    CAM>>Возможно, ты прав, на счёт небольшой разницы этих двух ситуаций, однако по-моему предпочтительнее дать пользователям возможность решать, что для них важно и нужно. Когда есть возможность, ей можно и не пользоваться, а вот когда её нет, и она нужна, то возникают проблемы.


    AS>НИКАКОЙ проблемы нет. Если m_hModule == 0 — значит, ошибка относится к загрузке модуля, иначе — к функции. Ну где здесь проблемы, не понимаю? Макрос, позволяющий задавать свою policy, я уже сделал.


    См. здесь
    Автор: CAMAD
    Дата: 24.08.04
    .
    Re[4]: код v1.06
    От: _nn_ www.nemerleweb.com
    Дата: 24.08.04 14:18
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    __>>Маленкое замечание :


    __>>Что будет если написать так :

    __>>
    __>>DL_USE_MODULE_BEGIN(kernel, L"kernel32.dll")
    __>>


    __>>Мне кажется в CNameId будет немного неправильные значения.


    __>>Решение 1 :


    AS>Если так написать, код просто не откомпилируется

    AS>
    AS>error C2440: 'return' : cannot convert from 'unsigned short [13]' to 'const char *'
    AS>        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
    AS>


    Стоит доработать это.
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[5]: код v1.06
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 24.08.04 15:46
    Оценка:
    __>Стоит доработать это.

    Зачем? Все правильно. В юникодном проекте строка с L откомпилится вполне нормально.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[9]: код v1.06
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 24.08.04 15:56
    Оценка:
    CAM>Хотя, зная, что такое синглтон майерса, я бы сделал так :

    CAM>
    CAM>class CModule {
    CAM>  class Destroyer {
    CAM>  public:
    CAM>    ~Destroyer() {
    CAM>      if (CModule::GetHandleRef()) {
    CAM>        FreeLibrary(CModule::GetHandleRef());
    CAM>      }
    CAM>    }
    CAM>  };
    CAM>  friend Destroyer;
    CAM>public:
    CAM>  static HMODULE GetHandle() {
    CAM>    static Destroyer destroyer;
    CAM>    if (!GetHandleRef()) {
    CAM>      GetHandleRef()=LoadLibrary();
    CAM>    }
    CAM>    return GetHandleRef();
    CAM>  }
    CAM>private:
    CAM>  static HMODULE & GetHandleRef() {
    CAM>    static HMODULE handle=0;
    CAM>    return &handle;
    CAM>  }
    CAM>};
    CAM>


    CAM>И по прежнему этот вариант лучше, чем любой с CriticalSection/Mutex'ами.


    И опять мимо.
    Вот в этом месте
    static Destroyer destroyer;

    будет вызван конструктор Destroyer, но не только — еще и будет зарегистрирован деструктор дестроера. Причем вызывать или нет саму процедуру регистрации деструктора определяется состоянием флага.
    Проще показать нап примере. На самом деле, этот код эквивалентен примерно такому:
       static char destroyer[sizeof(destroyer)];
       if (!instance_flag)
       {
            new (&destroyer[0])Destroyer();
            atexit(destroyer_instance_deleter);
       }

    Думаю, дальше объяснять не надо. В общем — читайте Александреску, там про эти проблемы подробно.Ну и + форум, конечно.
    PS MT я уже сделал, немного потестирую и выложу
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[7]: код v1.06
    От: Блудов Павел Россия  
    Дата: 25.08.04 02:16
    Оценка:
    Здравствуйте, CAMAD, Вы писали:

    CAM>Худшее, что может быть, опять — последовательный вызов LoadLibrary.


    Тогда нужен будет и лишний вызов FreeLibrary. Иначе — утечка.

    Можно сделать тупо на атомарных функциях:

        if (!m_hModule)
        {
            HMODULE hModule = ::LoadLibrary(...);
            if (::InterlockedCompareExchangePointer(&m_hModule, hModule, NULL))
            {
                    // Somebody did it already
                    ::FreeLibrary(hModule);
            }
        }
    ... << RSDN@Home 1.1.4 @@subversion >>
    Re[6]: код v1.06
    От: _nn_ www.nemerleweb.com
    Дата: 25.08.04 05:23
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    __>>Стоит доработать это.


    AS>Зачем? Все правильно. В юникодном проекте строка с L откомпилится вполне нормально.


    Вы меня не поняли.

    Есть 4 ситуации —
    не юникод проект . не юникодная строка — будет работать нормально
    не юникод проект . юникодная строка — не будет работать
    юникод проект . не юникодная строка — не будет работать
    юникод проект . юникодная строка — будет работать нормально

    Я говорю про случаи где не будет работать.
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[7]: код v1.06
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 25.08.04 07:06
    Оценка:
    Не, я понял.

    __>не юникод проект . юникодная строка — не будет работать

    __>юникод проект . не юникодная строка — не будет работать

    Вот эти 2 ситуации на мой взгляд могут присутствовать в 0.0001% случае и должны быть отправлены в dev\null
    Это примерно как вызвать LoadLibrary в неюникодном проекте с юникодной строкой и возмущаться — почему это не компилируется
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[10]: код v1.06
    От: CAMAD Россия  
    Дата: 25.08.04 08:08
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    ....

    AS>И опять мимо.

    AS>Вот в этом месте
    AS>
    AS>static Destroyer destroyer;
    AS>

    AS>будет вызван конструктор Destroyer, но не только — еще и будет зарегистрирован деструктор дестроера. Причем вызывать или нет саму процедуру регистрации деструктора определяется состоянием флага.

    Мда, лучше бы мне подумать, прежде чем писать half-baked решение.
    Мало того, что два раза может быть вызван ~Destroyer (это ты имел в виду ?), так ещё и FreeLibrary нужно вызывать для каждого LoadLibrary... Кстати, там Павел Блудов предложил решение второй проблемы, на Interlocked функциях — если и в деструкторе Destroyer сделать то же, т.е. менять хенлд с 0, и потом его грохать, то вроде всё должно быть ок (наконец-то !).
    Re[11]: код v1.06
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 25.08.04 08:36
    Оценка:
    CAM>Мда, лучше бы мне подумать, прежде чем писать half-baked решение.
    CAM>Мало того, что два раза может быть вызван ~Destroyer (это ты имел в виду ?), так ещё и FreeLibrary нужно вызывать для каждого LoadLibrary... Кстати, там Павел Блудов предложил решение второй проблемы, на Interlocked функциях — если и в деструкторе Destroyer сделать то же, т.е. менять хенлд с 0, и потом его грохать, то вроде всё должно быть ок (наконец-то !).

    Я видел, это все очевидно. Но зачем — когда на тех же Interlocked легко делается LW mutex и все проблемы идут лесом буквально 3-мя строчками кода
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[8]: код v1.06
    От: _nn_ www.nemerleweb.com
    Дата: 25.08.04 11:07
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Не, я понял.


    __>>не юникод проект . юникодная строка — не будет работать

    __>>юникод проект . не юникодная строка — не будет работать

    AS>Вот эти 2 ситуации на мой взгляд могут присутствовать в 0.0001% случае и должны быть отправлены в dev\null

    AS>Это примерно как вызвать LoadLibrary в неюникодном проекте с юникодной строкой и возмущаться — почему это не компилируется

    Ну для этого LoadLibraryA есть
    Предусмотреть все возможные проблемы заранее надо, или тогда написать чтобы не делать такое
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[9]: код v1.06
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 25.08.04 11:14
    Оценка:
    __>Ну для этого LoadLibraryA есть
    __>Предусмотреть все возможные проблемы заранее надо, или тогда написать чтобы не делать такое

    А что — кто то уже кроме нас пробовал?
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[10]: код v1.06
    От: _nn_ www.nemerleweb.com
    Дата: 25.08.04 11:23
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    __>>Ну для этого LoadLibraryA есть

    __>>Предусмотреть все возможные проблемы заранее надо, или тогда написать чтобы не делать такое

    AS>А что — кто то уже кроме нас пробовал?

    Еще видимо нет, а то так бы написали =)
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[2]: код v1.07
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 25.08.04 12:49
    Оценка:
    btw — может, лучше выкладывать новые версии отдельным архивом в файловую область? А то не всем, наверное, интересно получать довольно приличные по размеру постинги
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re: код v1.08
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 25.08.04 13:23
    Оценка:
    Список изменений:


    To do


    По поводу размеров прокси — думается, оптимизировать больше некуда, получаемый код выглядит оптимальным как в случае VC6, так и в случае VC7. Ждем новых предложений.

    Исходники доступны по адресу ниже.
    http://www.rsdn.ru/File/8583/delayimphlp.zip
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[3]: код v1.07
    От: adontz Грузия http://adontz.wordpress.com/
    Дата: 25.08.04 13:24
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>btw — может, лучше выкладывать новые версии отдельным архивом в файловую область? А то не всем, наверное, интересно получать довольно приличные по размеру постинги


    Такие люди жмут сюда
    A journey of a thousand miles must begin with a single step © Lau Tsu
    Re[2]: код v1.08
    От: Блудов Павел Россия  
    Дата: 26.08.04 01:44
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>To do


    AS>

    Ну, например, вариант с GetModuleHandle вместо LoadLibrary/GetProcAddress.
    Во первых работает быстрее.
    Во вторых — не нужно делать FreeLibrary.
    В третьих, можно вообще не синхронизировать.

    Для заведомо загруженных библиотек типа NTDLL, Kernel32, USER и GDI будет лучше.
    ... << RSDN@Home 1.1.4 @@subversion >>
    Re[2]: Сам код
    От: MShura  
    Дата: 27.08.04 10:30
    Оценка:
    AS>
    AS>            TCHAR szFunName[name_type::name_size];
    AS>            name_type::MakeStr(szFunName);
    AS>            FARPROC pFunction = GetProcAddress(hModule, szFunName);
    AS>


    Я не знаю указывали на это или нет, но GetProcAddress принимает только ASCII строку!
    Re[3]: код v1.06
    От: MShura  
    Дата: 01.09.04 10:04
    Оценка:
    A>P.S. Вызов через такую обёртку даже быстрее вызова через таблицу импорта. Вот я и думаю, а не создать ли продвинутый файл windows (как string.h -> string) в котором все функции будут раскиданы по пространствам имён? Как побочный эффект своего рода антиотладка (передаю привер шароварщикам ) Эдакая МЕГАИДЕЯ

    Очень слабая защита, поскольку в первую очередь break ставится на первую инструкцию функции.
    Защиту получше описал Крис Касперски:
    Управление передается не на первую инструкцию импортируемой функции, а на 3-й или 4-й байт, при этом недостающие байты (обычно стандартный пролог) выполняются клиентом.
    Re[3]: Исходники 1.09
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 09.09.04 08:37
    Оценка:
    __>
  • Исправление:
    __>
    __>static typename proxy_type::fun_type &GetProxy()
    __>    {
    __>        static proxy_type::fun_type proxy = proxy_type::template Proxy<type>::ProxyFun;
    __>        return proxy;
    __>    }
    __>

    __>Надо
    __>
    __>typename proxy_type::fun_type proxy = proxy_type::template Proxy<type>::ProxyFun;
    __>

    __>Почему-то это учтено выше, но в функции не учтено.

    Нет, это почему то в функции не учтено, а что учтено выше — вполне очевидно. Спасибо. Fixed.

    __>
  • Предложение по обработке DL_MT :

    Мне текущий вариант нравится, он весьма лаконичен.
    __>И не надо будет определять макрос DL_MT

    Макрос DL_MT определяется просто для красоты — на самом деле, хватило бы и DL_NO_MT

    __>P.S.

    __>Стиль как-то не очень совпадает, пространство имен называет dl, а имена классов в другом стиле, да еще начинаются на C.
    __>Есть предложение изменить стиль на стиль STL

    Ну, у нас тоже есть некоторые свои требования на оформление кода, данный вариант является компромисным ( в данном случае я стремился к тому, чтобы типы назывались в стиле stl, а классы — в стиле MFC, что на мой взгляд более читабельно). Тем не менее внес несколько изменений, дабы было более однозначно.
    __>Может пространство имен сменить на delayload, а то dl не очень уникально может быть.

    Да, dl не слишком уникально (учитывая встроенный ассемблер). delayload тоже, я полагаю. Есть еще мысли по названию неймспейса?
  • http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[4]: Исходники 1.09
    От: _nn_ www.nemerleweb.com
    Дата: 09.09.04 09:00
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    __>>
  • Предложение по обработке DL_MT :

    AS>Мне текущий вариант нравится, он весьма лаконичен.

    __>>И не надо будет определять макрос DL_MT

    AS>Макрос DL_MT определяется просто для красоты — на самом деле, хватило бы и DL_NO_MT


    Я имел ввиду немного другое.
    В данной реализации невозможно использовать в проекте многопоточном немногопоточный класс и наоборот.
    А таким образом можно использовать класс, который в зависимости от настроек будет другои, а можно и явно задать что использовать.

    __>>P.S.

    __>>Стиль как-то не очень совпадает, пространство имен называет dl, а имена классов в другом стиле, да еще начинаются на C.
    __>>Есть предложение изменить стиль на стиль STL

    AS>Ну, у нас тоже есть некоторые свои требования на оформление кода, данный вариант является компромисным ( в данном случае я стремился к тому, чтобы типы назывались в стиле stl, а классы — в стиле MFC, что на мой взгляд более читабельно). Тем не менее внес несколько изменений, дабы было более однозначно.


    Мне кажется что классы в стиле MFC это самое хучшее что может быть,IMHO
    Зачем надо это "C" вначале, можно без него обойтись.

    __>>Может пространство имен сменить на delayload, а то dl не очень уникально может быть.


    AS>Да, dl не слишком уникально (учитывая встроенный ассемблер). delayload тоже, я полагаю. Есть еще мысли по названию неймспейса?


    delayload довольно уникально по сравнению с dl.
    Вообще надо определиться со стилем и тогда название может быть delayload, DelayLoad. delay_load.

    P.S.
    Стиль STL мне кажется лучше всего подходит здесь.

    P.P.S.
    Небольшое добавление :
    struct CLWMutex
    {
        void Lock()
        {
            while(::InterlockedExchange(&m_pFlag, TRUE))
                ::Sleep(1); // почему здесь не было оператора видимости ?
        }
    };
  • http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[5]: Исходники 1.09
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 09.09.04 09:16
    Оценка:
    __>Я имел ввиду немного другое.
    __>В данной реализации невозможно использовать в проекте многопоточном немногопоточный класс и наоборот.

    Отнюдь. Как раз первое — задается макросом DL_NO_MT. А второе просто не нужно — подумайте сами, зачем в немногопоточном приложении использовать явно лишний многопоточный вариант.

    AS>>Ну, у нас тоже есть некоторые свои требования на оформление кода, данный вариант является компромисным ( в данном случае я стремился к тому, чтобы типы назывались в стиле stl, а классы — в стиле MFC, что на мой взгляд более читабельно). Тем не менее внес несколько изменений, дабы было более однозначно.


    __>Мне кажется что классы в стиле MFC это самое хучшее что может быть,IMHO

    __>Зачем надо это "C" вначале, можно без него обойтись.

    Для понятности, что это класс имплементации. Класс интерфейса начинается на I. Мне наоборот нравится, хотя, может, просто привычка.

    __>>>Может пространство имен сменить на delayload, а то dl не очень уникально может быть.


    AS>>Да, dl не слишком уникально (учитывая встроенный ассемблер). delayload тоже, я полагаю. Есть еще мысли по названию неймспейса?


    __>delayload довольно уникально по сравнению с dl.

    __>Вообще надо определиться со стилем и тогда название может быть delayload, DelayLoad. delay_load.

    Ок, тогда пусть будет delayload. Сейчас поправим...

    __>P.P.S.

    __>Небольшое добавление :
    __>
    __>struct CLWMutex
    __>{
    __>    void Lock()
    __>    {
    __>        while(::InterlockedExchange(&m_pFlag, TRUE))
    __>            ::Sleep(1); // почему здесь не было оператора видимости ?
    __>    }
    __>};
    __>


    Ага, это тоже поправим Спасибо.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[6]: Исходники 1.09
    От: _nn_ www.nemerleweb.com
    Дата: 09.09.04 09:43
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    __>>Я имел ввиду немного другое.

    __>>В данной реализации невозможно использовать в проекте многопоточном немногопоточный класс и наоборот.

    AS>Отнюдь. Как раз первое — задается макросом DL_NO_MT. А второе просто не нужно — подумайте сами, зачем в немногопоточном приложении использовать явно лишний многопоточный вариант.


    Давайте тогда к первому :
    // многопоточная программа
    #define DL_NO_MT
    #include <delayload.h>

    А если я хочу использовать многопоточный класс тоже.
    Получается что я не могу это сделать.

    А было бы так:
    #include <delayload.h>
    
    // CModule - зависит от настройки
    // CModuleMT - многопоточный
    // CModuleNoMT - не многопоточный
    
    //  DL_USE_MODULE_LOAD_POLICY_BEGIN
    typedef delayload::CModule<NAME_ID(DL_CAT(_MODULE_, nmspace)), load_policy> module_type;
    
    // задаем явно
    // DL_USE_MODULE_NOMT_LOAD_POLICY_BEGIN
    typedef delayload::CModuleNoMT<NAME_ID(DL_CAT(_MODULE_, nmspace)), load_policy> module_type;


    AS>>>Ну, у нас тоже есть некоторые свои требования на оформление кода, данный вариант является компромисным ( в данном случае я стремился к тому, чтобы типы назывались в стиле stl, а классы — в стиле MFC, что на мой взгляд более читабельно). Тем не менее внес несколько изменений, дабы было более однозначно.


    __>>Мне кажется что классы в стиле MFC это самое хучшее что может быть,IMHO

    __>>Зачем надо это "C" вначале, можно без него обойтись.

    AS>Для понятности, что это класс имплементации. Класс интерфейса начинается на I. Мне наоборот нравится, хотя, может, просто привычка.

    Насчет интерфейса это согласен.
    Я делаю так :
    Классы которые относятся к программе делаю в стиле MFC это если программа на MFC или WTL , а классы моей библиотеки делаю не в стиле MFC, так отличить легко что куда =)

    Еще опечаточка:
    static void MakeReturnImpl()
            {
                TCHAR szMessage[DynFunction::name_type::length + 64];
                _stprintf(szMessage, _T("Can'n resolve procedure <%s>: %d"), DynFunction::name_type::GetStr(), GetLastError());
                throw E(szMessage);
            }


    Надо can't или cannot.

    P.S.
    Что-то у вас нет единого стиля в коде.
    return Policy::template FunctionTrait<DynFunction>::MakeReturn(); // есть template
    //...
    delayload::FUN_PROXY(DL_SEQ_SIZE(p))<r, DL_SEQ_ENUM(p), pl > >::GetProxy() // нет template


    Может стоить добавить template где надо, хотя и без него компилируется
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[7]: Исходники 1.09
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 09.09.04 10:00
    Оценка:
    __>P.S.
    __>Что-то у вас нет единого стиля в коде.
    __>
    __>return Policy::template FunctionTrait<DynFunction>::MakeReturn(); // есть template
    __>//...
    __>delayload::FUN_PROXY(DL_SEQ_SIZE(p))<r, DL_SEQ_ENUM(p), pl > >::GetProxy() // нет template
    __>


    __>Может стоить добавить template где надо, хотя и без него компилируется


    Разве это относится к стилю? Если вы про спецификатор template после наймспейса — то в данном случае он не нужен. И комеау со мной тут согласен.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[8]: Исходники 1.09
    От: _nn_ www.nemerleweb.com
    Дата: 09.09.04 10:03
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    __>>P.S.

    __>>Что-то у вас нет единого стиля в коде.
    __>>
    __>>return Policy::template FunctionTrait<DynFunction>::MakeReturn(); // есть template
    __>>//...
    __>>delayload::FUN_PROXY(DL_SEQ_SIZE(p))<r, DL_SEQ_ENUM(p), pl > >::GetProxy() // нет template
    __>>


    __>>Может стоить добавить template где надо, хотя и без него компилируется


    AS>Разве это относится к стилю? Если вы про спецификатор template после наймспейса — то в данном случае он не нужен. И комеау со мной тут согласен.


    Ой, delayload это пространство имен
    Я забыл что вы переименовали его, прощу прощения
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[9]: Исходники 1.09
    От: _nn_ www.nemerleweb.com
    Дата: 09.09.04 10:20
    Оценка:
    Здравствуйте, _nn_, Вы писали:

    А что насчет многопоточных и немногопоточных классов в одной программе сразу ?
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[10]: Исходники 1.09
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 09.09.04 10:27
    Оценка:
    __>А что насчет многопоточных и немногопоточных классов в одной программе сразу ?

    Многопоточность в данном случае не сильно влияет и на размер кода, и на производительность (на размер почти не влияет, а на производительность во временнОм понятии — вообще). Макрос DL_NO_MT в свое время появился из-за того, что размер кода сильно возрос после реализации MT. Однако после выноса части прокси в отдельную функцию оказалось, что размер кода MT ~~== размеру кода ST. Так что это не принципиально. Я сначала думал сделать стратегии для поддержки многопоточности, но потом решил, что это уже слишком, да и не нужно никому.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[11]: Исходники 1.09
    От: _nn_ www.nemerleweb.com
    Дата: 09.09.04 10:51
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    __>>А что насчет многопоточных и немногопоточных классов в одной программе сразу ?


    AS>Многопоточность в данном случае не сильно влияет и на размер кода, и на производительность (на размер почти не влияет, а на производительность во временнОм понятии — вообще). Макрос DL_NO_MT в свое время появился из-за того, что размер кода сильно возрос после реализации MT. Однако после выноса части прокси в отдельную функцию оказалось, что размер кода MT ~~== размеру кода ST. Так что это не принципиально. Я сначала думал сделать стратегии для поддержки многопоточности, но потом решил, что это уже слишком, да и не нужно никому.


    Я не про размер говорю.
    Я имею ввиду что стоит сделать 2 версии классов CModule и CDynFunction.

    P.S.
    Поговорим насчет стиля ?
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[12]: Исходники 1.09
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 09.09.04 12:56
    Оценка:
    __>Я не про размер говорю.
    __>Я имею ввиду что стоит сделать 2 версии классов CModule и CDynFunction.

    Нет, по приведенным ранее причинам.

    __>P.S.

    __>Поговорим насчет стиля ?

    Да ну, у каждого свои понятия красоты кода
    Вот если таки хватит сил или общественность поддержит инициативу официального выкладывания этой поделки на RSDN — тогда уже будем все там править, что соответствовало тому, что принято на RSDN.
    Впрочем, в любом случае — использоваться в 99% случаях будут только макросы, так что стиль оформления кода внутри наймспейса не так и важен, только из эстетических соображений. А мне текущий вариант более (или менее) нравится

    Лучше еще что-нибудь по улучшению функционала придумать... Да вот не думается ничего
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[13]: Исходники 1.09
    От: _nn_ www.nemerleweb.com
    Дата: 09.09.04 17:42
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    __>>Я не про размер говорю.

    __>>Я имею ввиду что стоит сделать 2 версии классов CModule и CDynFunction.

    AS>Нет, по приведенным ранее причинам.


    __>>P.S.

    __>>Поговорим насчет стиля ?

    AS>Да ну, у каждого свои понятия красоты кода

    Само собой.
    AS>Вот если таки хватит сил или общественность поддержит инициативу официального выкладывания этой поделки на RSDN — тогда уже будем все там править, что соответствовало тому, что принято на RSDN.
    AS>Впрочем, в любом случае — использоваться в 99% случаях будут только макросы, так что стиль оформления кода внутри наймспейса не так и важен, только из эстетических соображений. А мне текущий вариант более (или менее) нравится
    Если макросы будут, то это конечно не важно
    Задача чтобы от них избавиться.

    AS>Лучше еще что-нибудь по улучшению функционала придумать... Да вот не думается ничего

    Уменьшит количество макросов.
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[14]: Исходники 1.09
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 13.09.04 07:28
    Оценка:
    __>Если макросы будут, то это конечно не важно
    __>Задача чтобы от них избавиться.

    Боюсь, что не получится. Во-первых, не поддерживается специализация строковым литералом. Приходится с макросами извращаться — никак иначе. Во-вторых — макросы заворачивают ненужные и нудные телодвижения (например, декларация глобального для объявления модуля в единице трансляции типа модуля). В данном случае без них было бы кисло.

    AS>>Лучше еще что-нибудь по улучшению функционала придумать... Да вот не думается ничего

    __>Уменьшит количество макросов.

    Вариантов не вижу. Их вроде и так минимально возможное количество
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[15]: Исходники 1.09
    От: _nn_ www.nemerleweb.com
    Дата: 13.09.04 08:29
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    __>>Если макросы будут, то это конечно не важно

    __>>Задача чтобы от них избавиться.

    AS>Боюсь, что не получится. Во-первых, не поддерживается специализация строковым литералом. Приходится с макросами извращаться — никак иначе. Во-вторых — макросы заворачивают ненужные и нудные телодвижения (например, декларация глобального для объявления модуля в единице трансляции типа модуля). В данном случае без них было бы кисло.


    Согласен они упрощают код, скрывая лишнее.
    Однако если есть возможность(надеюсь что есть) без них то лучше без них.
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[2]: Исходники 1.09
    От: _nn_ www.nemerleweb.com
    Дата: 13.09.04 09:02
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    DL_USE_MODULE_END стоит изменить на:
    #define DL_USE_MODULE_END() \
     };
    http://rsdn.nemerleweb.com
    http://nemerleweb.com
    Re[3]: Исходники 1.09
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 13.09.04 11:12
    Оценка:
    __>DL_USE_MODULE_END стоит изменить на:

    А в чем смысл, ну кроме необходимости ставить еще и () для макроса без параметров?
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[6]: Исходники 1.09
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 01.10.04 15:13
    Оценка:
    __>>Например карты сообщений в MFC и WTL сделанны так и оно смотрится лучше.

    AS>Это сильный аргумент Ок, подумаю.


    Кстати, тут поступило предложение изменить макросы DL_DECLARE_FUN_xxx(name, ret, ...) на DL_DECLARE_FUN_xxx(ret, name, ...). Как общественность смотрит на это? С одной стороны, это вроде как больше походит на обычное С определение функции, с другой стороны, мне почему то более логичным кажется сначала указание имени импортируемой функции, а потом уже типов (может, просто привычка, конечно). Какие будут мнения? Если положительные, то последствия для тех мест, где используется старый вариант, я надеюсь, вы представляете
    В общем, высказывайтесь. Я в сомнениях.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[3]: Исходники 1.09
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 05.10.04 06:57
    Оценка:
    Милейший, если у вас есть какие то конкретные предложения по библиотеке, либо по функционалу — вперед. Если же нет — просьба не засорять подобными сообщениями эту ветку, для них есть специальные форумы. Заранее спасибо.

    Fuz>

    Fuz>"Так они шептались целую неделю
    Fuz>и заодно делали большой железный сундук. Над ним трудились и
    Fuz>папа Карло, и Ферручино, и Буратино, который понемногу научился
    Fuz>мастерить. Артемон приносил различные железные предметы и ловко
    Fuz>смахивал хвостом металлические стружки. Мальвина шлифовала
    Fuz>готовые детали маленьким напильничком. Пьеро постукивал,
    Fuz>побрякивал, подтачивал, закручивал гаечки"

    Fuz>(c)Александр Кумма, Сакко Рунге. Вторая тайна золотого ключика
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[4]: Исходники 1.09
    От: Fuz  
    Дата: 05.10.04 07:30
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Милейший, если у вас есть какие то конкретные предложения по библиотеке, либо по функционалу — вперед. Если же нет — просьба не засорять подобными сообщениями эту ветку, для них есть специальные форумы. Заранее спасибо.


    Не хотите, не буду... да и правила вроде не разрешают... просто расслабляться иногда тоже нужно.
    Извините, если задел.
    Re[5]: Исходники 1.09
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 05.10.04 07:43
    Оценка:
    Fuz>Не хотите, не буду... да и правила вроде не разрешают... просто расслабляться иногда тоже нужно.

    Не хочу. А вообще-то, до этого момента тут никто и не напрягался
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re: Исходники 1.1.0
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 09.02.05 14:28
    Оценка:
    Гм. Неожиданное обновление.

    Выяснился один небольшой недостаток — отсутствие поддержки функций без параметров.
    Как реализовать это в рамках текущих макросов, я придумать не смог, в связи с чем пришлось добавить макросы с индексом 0... Если есть какие предложения по другой реализации всего этого — с интересом обсудим.

    Итак, версия 1.1.0.

    Список изменений:

    Добавлены макросы для поддержки функций без параметров:
    DL_DECLARE_FUN_0_ERR_POLICY
    DL_DECLARE_FUN_0
    DL_DECLARE_FUN_0_THROW
    DL_DECLARE_FUN_0_ERR

    Синтаксис и назначение аналогичны таковым для остальных функций, за исключением, ессно, отсутствия списка параметров.

    To do

    Багфиксы
    Что то еще?

    Исходники доступны по адресу ниже.
    http://www.rsdn.ru/File/8583/delayimphlp.zip
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[2]: Исходники 1.1.0
    От: MShura  
    Дата: 10.02.05 13:12
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Гм. Неожиданное обновление.


    AS>Выяснился один небольшой недостаток — отсутствие поддержки функций без параметров.


    Есть еще как минимум один...
    Поддержка UNICODE.

    Я уже давно писал в этой теме, что GetProcAddress не принимает UNICODE строк.
    Попробуйте в тестовом проекте поставить UNICODE вместо _MBCS.
    Re[3]: Исходники 1.1.0
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 10.02.05 18:21
    Оценка:
    AS>>Гм. Неожиданное обновление.

    AS>>Выяснился один небольшой недостаток — отсутствие поддержки функций без параметров.


    MS>Есть еще как минимум один...

    MS>Поддержка UNICODE.

    MS>Я уже давно писал в этой теме, что GetProcAddress не принимает UNICODE строк.

    MS>Попробуйте в тестовом проекте поставить UNICODE вместо _MBCS.

    Так никто туда его и не передает. По крайней мере, не думал передавать — обратите внимание на макрос DECLARE_NAME_ID_A. Другое дело, что DL_GetProcAddressImpl пользовала LPCTSTR — это уже по недосмотру при оптимизации. Это я поправил, спасибо, а вот остальное вроде все работает. Так что ваше давнишнее замечание к этому багу никакого отношения не имеет.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re: Pure C++ delay load
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 16.05.05 11:07
    Оценка:
    Хм. Еще одно неожиданное обновление предыдущего обновления.

    >>Выяснился один небольшой недостаток — отсутствие поддержки функций без параметров.

    >>Как реализовать это в рамках текущих макросов, я придумать не смог, в связи с чем пришлось добавить макросы с индексом 0... Если есть какие >>предложения по другой реализации всего этого — с интересом обсудим.

    Немного подумав, как обойтись, придумать смог
    В процессе придумывания было найдено несколько новых багов 6-ки, так что если непонятно, почему сделано именно, так, а не проще — см. комменты.

    Итак, версия 1.1.1.

    Список изменений:

    1. Функции без параметров представлены в виде функций с одим параметром типа void. То бишь объявлять их надо примерно так DL_DECLARE_FUN(имя, ret_type, (void))

    2. Убраны макросы для поддержки функций без параметров за ненадобностью:
    DL_DECLARE_FUN_0_ERR_POLICY
    DL_DECLARE_FUN_0
    DL_DECLARE_FUN_0_THROW
    DL_DECLARE_FUN_0_ERR

    To do

    Багфиксы
    Что то еще?

    Исходники доступны по адресу ниже.
    http://www.rsdn.ru/File/8583/delayimphlp.zip
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[2]: Pure C++ delay load
    От: 23W http://kyselgov.pp.ua/
    Дата: 19.07.05 10:11
    Оценка:
    Здравствуйте, Andrew S!
    Есть вопрос по новой версии вашей библиотеки.
    При компиляции в VC++ 7.1 на 4 уровне предупреждений мне постоянно генерируются
    варнинги C4702 и C4100. Причем первый по нескольку раз, он сильно забивает трей, что немного раздражает.
    Единственный способ который я нашол, это "закрыть" подключение библиотеки в прагмы:

    #pragma warning(disable: 4702)
    #pragma warning(disable: 4100)
    #include <delayimphlp.h>
    #pragma warning(default: 4100)
    #pragma warning(default: 4702)


    Для меня это не выход, т.к. библиотека используюется в очень многих файлах. Можете что-то подсказать как избавиться от этих предупреждени ? Возможно, я неправильно формирую описание функций ?
    Re[3]: Pure C++ delay load
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 19.07.05 10:27
    Оценка:
    23W>
    23W>#pragma warning(disable: 4702)
    23W>#pragma warning(disable: 4100)
    23W>#include <delayimphlp.h>
    23W>#pragma warning(default: 4100)
    23W>#pragma warning(default: 4702)
    23W>


    23W>Для меня это не выход, т.к. библиотека используюется в очень многих файлах. Можете что-то подсказать как избавиться от этих предупреждени ? Возможно, я неправильно формирую описание функций ?


    Я в другой ветке ответил. У меня в 2003-м генерится только один варнинг (4702) на код

            static  ret_type MakeReturn()
            {
                TCHAR szMessage[DynFunction::name_type::length + 64];
                _stprintf(szMessage, _T("Can'n resolve procedure <%s>: %d"), DynFunction::name_type::GetStr(), GetLastError());
                throw E(szMessage);
                return ret_type();
            }


    Очевидно, нормального способа запретить его, кроме как прагмой (что вы и делаете), нет. Можете поместить ее непосредственно в заголовок библиотеки.

    Если у вас генерится 4100, то наверняка это в line 303
        static BOOL Free(HMODULE hModule)


    Исправляется это просто:

        static BOOL Free(HMODULE /*hModule*/)


    B повторюсь. На мой взгляд, 4-й уровень предупреждений ничего полезного не несет, самый удобный вариант — 3-й.
    Удачи.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[4]: Pure C++ delay load
    От: 23W http://kyselgov.pp.ua/
    Дата: 19.07.05 10:40
    Оценка:
    Здравствуйте, Andrew S.

    Спасибо за ответ.
    Что же будут блокировать предупреждения через прагмы, вносить имземения в Ваш код не буду (я не сторонник таких действий).

    P.S.:
    В другой ветке я просто не смог удалить свои старые вопросы, после того как нашел эту. Извините — ламер
    Re[5]: Pure C++ delay load
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 19.07.05 10:49
    Оценка:
    23W>Спасибо за ответ.
    23W>Что же будут блокировать предупреждения через прагмы, вносить имземения в Ваш код не буду (я не сторонник таких действий).

    В данном случае это вполне правильный подход. То, что возможно ведет к 4100, я поправил и выложил на сайт — http://gzip.rsdn.ru/File/8583/delayimphlp.zip
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[6]: Pure C++ delay load
    От: 23W http://kyselgov.pp.ua/
    Дата: 19.07.05 11:11
    Оценка:
    Андрей, может Вы тогда и исправите предупреждение С4702 ?
    Генерируется оно тут CFunProxyThrowPolicy::FunctionTrait метод MakeReturn строка 467


    static  ret_type MakeReturn()
    {
        TCHAR szMessage[DynFunction::name_type::length + 64];
        _stprintf(szMessage, _T("Can'n resolve procedure <%s>: %d"), DynFunction::name_type::GetStr(), GetLastError());
        throw E(szMessage);
        return ret_type();  // ТУТ генерируется С4702
    }


    Судя потому, что там написано, return действительно лишний. Без него VC++ 7.1 компилирует это код без ошибок и предупреждений. Я понимаю что библиотека универсальная. Но может следует внести некоторые изменения, например так:

    static  ret_type MakeReturn()
    {
        TCHAR szMessage[DynFunction::name_type::length + 64];
        _stprintf(szMessage, _T("Can'n resolve procedure <%s>: %d"), DynFunction::name_type::GetStr(), GetLastError());
        throw E(szMessage);
    #if (_MSC_VER<1300) || !defined(_MSC_VER)
        return ret_type();
    #endif
    }

    Такой код вроде бы не разрушает логики библиотеки и не приводит к неприятностям с варнингами.
    Re[6]: Pure C++ delay load
    От: 23W http://kyselgov.pp.ua/
    Дата: 19.07.05 11:15
    Оценка:
    P.S.:
    Ну и не забудьте поднять верисю до 1.1.2
    Re[7]: Pure C++ delay load
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 19.07.05 11:43
    Оценка:
    23W>Такой код вроде бы не разрушает логики библиотеки и не приводит к неприятностям с варнингами.

    Я попробовал на VC6, там тоже без это строчки компилится. Думаю, можно просто ее закомментить.
    Выложил в файлы.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[8]: Pure C++ delay load
    От: 23W http://kyselgov.pp.ua/
    Дата: 19.07.05 11:58
    Оценка:
    Андрей, огромное СПАСИБО.
    У меня все компилируется, ошибок и предупреждений нет.
    Теперь легко перешел на новую версию.
    Библиотека просто класс!
    Re[9]: Pure C++ delay load
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 19.07.05 12:08
    Оценка:
    23W>Андрей, огромное СПАСИБО.
    23W>У меня все компилируется, ошибок и предупреждений нет.
    23W>Теперь легко перешел на новую версию.

    Вам тоже спасибо — несколькими недочетами, хоть и мелкими, но стало меньше.

    Успехов.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[11]: Pure C++ delay load
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 19.07.05 13:12
    Оценка:
    23W>И сново здравствуйте!
    23W>Андрей, Вы будете смеяться, но дождавшись наконец-то полного ребилдинга проекта
    23W>я заметил еще один варнинг (он тоже из области 4-го уровня).Это C4512!

    Ок, спасибо за поправки, я их интегрировал (в слегка изменнном виде) и выложил результат в файлы по старой ссылке.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re: Pure C++ delay load
    От: avbochagov Россия  
    Дата: 19.07.05 16:33
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    Библиотека классная.

    Есть одно очень МАЛЕНЬКОЕ замечание

    в строке 478 формируется сообщение "Can'n resolve procedure <%s>: %d".

    Мне кажется что должно быть так "Can't resolve procedure <%s>: %d".
    ... << RSDN@Home 1.2.0 alpha rev. 580>>
    Re[2]: Pure C++ delay load
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 19.07.05 17:12
    Оценка:
    A>Библиотека классная.
    A>Есть одно очень МАЛЕНЬКОЕ замечание
    A>в строке 478 формируется сообщение "Can'n resolve procedure <%s>: %d".
    A>Мне кажется что должно быть так "Can't resolve procedure <%s>: %d".

    Ага, точно. Этот баг фиксился несколько раз, но, как феникс, он постоянно возрождался от версии к версии Вот и сейчас.
    Выложил в файлы исправленный вариант. http://gzip.rsdn.ru/File/8583/delayimphlp.zip
    Спасибо за замечание.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[3]: Pure C++ delay load
    От: avbochagov Россия  
    Дата: 20.07.05 08:07
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Ага, точно. Этот баг фиксился несколько раз, но, как феникс, он постоянно возрождался от версии к версии Вот и сейчас.




    Еще вопросик в тему: в вашей статье нигде не упоминается про лицензию? есть какие-нибудь ограничения на использования вашей библиотеки в коммерческих проектах?
    ... << RSDN@Home 1.2.0 alpha rev. 581>>
    Re[4]: Pure C++ delay load
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 20.07.05 08:58
    Оценка:
    AS>>Ага, точно. Этот баг фиксился несколько раз, но, как феникс, он постоянно возрождался от версии к версии Вот и сейчас.

    A>


    A>Еще вопросик в тему: в вашей статье нигде не упоминается про лицензию? есть какие-нибудь ограничения на использования вашей библиотеки в коммерческих проектах?

    Иначе был бы смысл выкладывать ее в общий доступ... Конечно, нет ограничений, по крайней мере, с моей стороны — пользуйте, изменяйте и улучшайте на здоровье. Если какие баги\улучшательства найдете — пишите, поправим\добавим в новые версии.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[5]: Pure C++ delay load
    От: avbochagov Россия  
    Дата: 20.07.05 09:56
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    A>>Еще вопросик в тему: в вашей статье нигде не упоминается про лицензию? есть какие-нибудь ограничения на использования вашей библиотеки в коммерческих проектах?

    AS>Иначе был бы смысл выкладывать ее в общий доступ... Конечно, нет ограничений, по крайней мере, с моей стороны — пользуйте, изменяйте и улучшайте на здоровье. Если какие баги\улучшательства найдете — пишите, поправим\добавим в новые версии.

    Ок. Спасибо.
    ... << RSDN@Home 1.2.0 alpha rev. 581>>
    Re: Pure C++ delay load
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 25.09.05 22:21
    Оценка:
    Итак, версия 1.1.3.

    Список изменений:

    1. Немного изменены макросы DL_REPEAT_XXXX Теперь нумерация параметров начинается с 0, а не с 1. Для совместимости с бустом. На внешнем интерфейсе библиотеки это никак не отразилось.
    2. Расширен список поддерживаемых компиляторов: добавлена возможность вместо предлагаемой библиотекой реализации использовать порождающие макросы от boost::preprocessor. Для этого надо в свойствах проекта или же перед включением заголовка библиотеки определить макрос
    #define DL_USE_BOOST_PP

    По крайней мере, теперь макросы не будут проблемой в случае, если нативная реализация не устраивает целевой препроцессор.

    To do

    Багфиксы
    Что то еще?

    Исходники, как обычно, доступны по адресу ниже.
    http://www.rsdn.ru/File/8583/delayimphlp.zip
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[2]: Реализация отложенной загрузки библиотек на С++
    От: 23W http://kyselgov.pp.ua/
    Дата: 05.12.05 09:03
    Оценка:
    Спасибо за новую версию.
    Re[2]: Исходники 1.2.0
    От: ssi Россия  
    Дата: 18.02.06 20:14
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Версия 1.2.0


    Скачал новую версию. Компилирую. Запускаю прогу. При загрузке функции получаю Debug Error:

    ...
    File: delayimphlp.h
    Line: 611

    Run-Time Check Failure #0 — The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling conversion with a function pointer declared with a different calling conversion.

    Abort Ignore Retry


    Вашу библиотеку использую так:

    DL_USE_MODULE_BEGIN(foo, _T("foo.dll"))
    
        DL_DECLARE_FUN_THROW(
              Bar
            , result
            , (char const*)(short)(char const*)(char const*)(char const*)(HWND)(char const*)
            )
    
    DL_USE_MODULE_END()


    где то в коде...
    result bar_result = foo::Bar( // на этой строчке вываливается message box Debug Error'а
          str1_.c_str()
        , short1_
        , str2_.c_str()
        , str3_.c_str()
        , str4_.c_str()
        , m_hWnd
        , str5_.c_str()
        );



    Где грабли?

    P.S. Если делаю по простому LoadLibrary, GetProcAddress — все ОК.
    Знающие не говорят, говорящие не знают. Лао Цзы
    Re[3]: Исходники 1.2.0
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 19.02.06 02:02
    Оценка:
    ssi>Где грабли?

    Грабли в соглашениях о вызове. У вас, скорее всего, используется __сcall. В библиотеке — __stdcall, и добавлять поддержку других конвенций не планируется.

    ssi>P.S. Если делаю по простому LoadLibrary, GetProcAddress — все ОК.


    А кто бы сомневался. Там-то вы функцию определяете как __ccall.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[4]: Исходники 1.2.0
    От: Аноним  
    Дата: 19.02.06 06:31
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    ssi>>Где грабли?


    AS>Грабли в соглашениях о вызове. У вас, скорее всего, используется __сcall. В библиотеке — __stdcall, и добавлять поддержку других конвенций не планируется.


    ssi>>P.S. Если делаю по простому LoadLibrary, GetProcAddress — все ОК.


    AS>А кто бы сомневался. Там-то вы функцию определяете как __ccall.


    Как выйдти из положения? Dll-ка не моя, поэтому использовать другие соглашения о вызове не могу, в то же время хочу использовать Вашу библиотеку, имхо очень удобная.
    Re[5]: Исходники 1.2.0
    От: adontz Грузия http://adontz.wordpress.com/
    Дата: 19.02.06 08:27
    Оценка:
    Здравствуйте, Аноним, Вы писали:

    А>Как выйдти из положения? Dll-ка не моя, поэтому использовать другие соглашения о вызове не могу, в то же время хочу использовать Вашу библиотеку, имхо очень удобная.


    Ну так просто замени везде в библиотеке WINAPI на на что надо. Правда её тогда нельзя будет использовать с системными функциями.
    A journey of a thousand miles must begin with a single step © Lau Tsu
    Re[6]: Исходники 1.2.0
    От: ssi Россия  
    Дата: 19.02.06 08:42
    Оценка:
    Здравствуйте, adontz, Вы писали:

    A>Здравствуйте, Аноним, Вы писали:


    А>>Как выйдти из положения? Dll-ка не моя, поэтому использовать другие соглашения о вызове не могу, в то же время хочу использовать Вашу библиотеку, имхо очень удобная.


    A>Ну так просто замени везде в библиотеке WINAPI на на что надо. Правда её тогда нельзя будет использовать с системными функциями.


    Библиотека (.dll) не моя, менять ничего не могу. Даже хедера нет, есть только дока с описанием контекста функций.
    Знающие не говорят, говорящие не знают. Лао Цзы
    Re[7]: Исходники 1.2.0
    От: adontz Грузия http://adontz.wordpress.com/
    Дата: 19.02.06 08:53
    Оценка:
    Здравствуйте, ssi, Вы писали:

    ssi>Библиотека (.dll) не моя, менять ничего не могу. Даже хедера нет, есть только дока с описанием контекста функций.


    В библиотеке которой посвящён этот топик, а не в той которую ты хочешь подключить
    A journey of a thousand miles must begin with a single step © Lau Tsu
    Re[8]: Исходники 1.2.0
    От: ssi Россия  
    Дата: 19.02.06 10:56
    Оценка:
    Здравствуйте, adontz, Вы писали:

    A>Здравствуйте, ssi, Вы писали:


    ssi>>Библиотека (.dll) не моя, менять ничего не могу. Даже хедера нет, есть только дока с описанием контекста функций.


    A>В библиотеке которой посвящён этот топик, а не в той которую ты хочешь подключить


    Работает. Спасибо.
    Знающие не говорят, говорящие не знают. Лао Цзы
    Re[7]: Исходники 1.2.0
    От: Аноним  
    Дата: 19.02.06 18:33
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Включение __cdecl:

    AS>
    AS>#define DL_USE_CDECL
    AS>#include "delayimphlp.h"
    
    AS>DL_USE_MODULE_BEGIN(mydll, "mydll.dll")
    AS>    DL_DECLARE_FUN_CC(__cdecl, MyFun, int, (int))
    AS>DL_USE_MODULE_END()
    AS>


    Раз уж мы определили дефайном DL_USE_CDECL, зачем использовать DL_DECLARE_FUN_CC(__cdecl, ...) вместо обычного DL_DECLARE_FUN()?

    или так нельзя:
    DL_USE_MODULE_BEGIN(mydll, "mydll.dll")
        DL_DECLARE_FUN_CC(__cdecl, MyFun1, int, (int))
        DL_DECLARE_FUN_CC(__fastcall, MyFun2, int, (int))
        DL_DECLARE_FUN_CC(__my_call, MyFun3, int, (int))
    DL_USE_MODULE_END()


    ?

    И еще вопрос: если функция возвращает сишную структуру, то почему я не могу использовать макросы DL_DECLARE_FUN и DL_DECLARE_FUN_ERR? Компилятор выдает ошибки С2993 и С2975 на класс CFunProxyValuePolicy?
    Получается, что в этом случае единственный способ узнать об ошибке это использовать DL_DECLARE_FUN_THROW, что ИМХО не очень удобно — ставить вокруг каждого вызова функции из dll-ки блок try-catch.
    Re[8]: Исходники 1.2.0
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 19.02.06 21:34
    Оценка:
    А>Раз уж мы определили дефайном DL_USE_CDECL, зачем использовать DL_DECLARE_FUN_CC(__cdecl, ...) вместо обычного DL_DECLARE_FUN()?

    DL_DECLARE_FUN подразумевает использование соглашений WINAPI. DL_DECLARE_FUN_CC позволяет явно указать соглашения. Често говоря, не понимаю недоразумения.

    А>или так нельзя:

    А>
    А>DL_USE_MODULE_BEGIN(mydll, "mydll.dll")
    А>    DL_DECLARE_FUN_CC(__cdecl, MyFun1, int, (int))
    А>    DL_DECLARE_FUN_CC(__fastcall, MyFun2, int, (int))
    А>    DL_DECLARE_FUN_CC(__my_call, MyFun3, int, (int))
    А>DL_USE_MODULE_END()
    А>


    А>?


    Можно, для этого DL_DECLARE_FUN_CC и нужно. дефайн DL_USE_CDECL не изменяет конвенций по умолчанию, он лишь добавляет поддержку __cdecl в DL_DECLARE_FUN_CC. Думаю, этот код говорит сам за себя:

    #ifdef DL_USE_CDECL
        DL_DECLARE_FUN_PROXY_CC(__cdecl)
    #endif /*DL_USE_CDECL*/


    А>И еще вопрос: если функция возвращает сишную структуру, то почему я не могу использовать макросы DL_DECLARE_FUN и DL_DECLARE_FUN_ERR? Компилятор выдает ошибки С2993 и С2975 на класс CFunProxyValuePolicy?


    В параметры шаблона стратегии эта штука передается как template<class R, R value = R()>. Т.е., допустимы только интегральные типы и указатели — все то, что принимает значения константы. Единственная проблема со стратегией CFunProxyValuePolicy — это то, что для, например, HANDLE, нельзя передать -1 как значение ошибки. В случае HANDLE это решается тем, что оно в вин32 не может также принимать и значение 0, хотя это, конечно, и не очень красиво получается. Если кто-нибудь предложит красивое решение проблемы — я буду только рад...

    А вообще, если често.. Возвращать из экспортируемой функции структуру по значению... ну, я бы за это кастрировал, если только этому нет _очень_ веских оснований. И это меньшее, что можно сделать, нельзя допускать, чтобы такие люди размножались

    А>Получается, что в этом случае единственный способ узнать об ошибке это использовать DL_DECLARE_FUN_THROW, что ИМХО не очень удобно — ставить вокруг каждого вызова функции из dll-ки блок try-catch.


    Ровно так же это единственный способ узнать об ошибке в случае void функций — так что других вариантов тут нет. Инстанцировать шаблон с типизированым параметром можно только интегральным литералом, указателем на объект с external linkage (например, функцию), либо NULL для указателя. Если у вас есть какие-то лучшие предложения (с реализацией, конечно, напредлагать просто так и я сам могу) — u are welcome.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[8]: Вдогонку...
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 20.02.06 01:01
    Оценка:
    А>Получается, что в этом случае единственный способ узнать об ошибке это использовать DL_DECLARE_FUN_THROW, что ИМХО не очень удобно — ставить вокруг каждого вызова функции из dll-ки блок try-catch.

    Совсем забыл сказать — у вас еще есть вариант использовать DL_DECLARE_FUN_ERR_POLICY(name_id, r, p, pl), где задать свою политику, допускающую возвращение структур. Например, такую:

    struct CFunProxyDefPolicy
    {
        template <class DynFunction> 
        struct FunctionTrait
        {
            static typename DynFunction::proxy_type::ret_type MakeReturn()
            {
                return typename DynFunction::proxy_type::ret_type();
            }
        };
    };
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re: Pure C++ delay load
    От: Plague Россия 177230800
    Дата: 26.02.06 12:15
    Оценка:
    Штука понравилась, но не смог сослаться на функцию с переменным количеством параметров, в следствие чего не стал использовать для решения одной задачи. Обыдна... Может я чего не досмотрел???
    Re[2]: Pure C++ delay load
    От: adontz Грузия http://adontz.wordpress.com/
    Дата: 26.02.06 13:55
    Оценка:
    Здравствуйте, Plague, Вы писали:

    P>Штука понравилась, но не смог сослаться на функцию с переменным количеством параметров, в следствие чего не стал использовать для решения одной задачи. Обыдна... Может я чего не досмотрел???


    STDCALL использовавшийся до последнего времени в библиотеке не поддерживает переменное число аргументов. Сейчас есть поддержка нескольких конвенций. Переменное число аргументов поддерживает CDECL
    A journey of a thousand miles must begin with a single step © Lau Tsu
    Re[3]: Pure C++ delay load
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 26.02.06 15:48
    Оценка:
    P>>Штука понравилась, но не смог сослаться на функцию с переменным количеством параметров, в следствие чего не стал использовать для решения одной задачи. Обыдна... Может я чего не досмотрел???

    Нет, все верно. stdcall традиционно не поддерживает переменное число агрументов, поскольку стек очищает сама функция. cdecl может поддерживать переменное число агрументов, однако в библиотеке переменное число агрументов не поддерживается вообще. Используйте va функции для передачи переменного числа агрументов, если оные, конечно, имеются. Еще где-то в исходниках были еще варианты динамической загрузки — может там что поможет.

    A>STDCALL использовавшийся до последнего времени в библиотеке не поддерживает переменное число аргументов. Сейчас есть поддержка нескольких конвенций. Переменное число аргументов поддерживает CDECL


    См. выше, это не так. Переменное число агрументов не может быть поддержано библиотекой архитектурно — для этого простыми методами не обойтись — надо подменять стек.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[4]: Pure C++ delay load
    От: Plague Россия 177230800
    Дата: 27.02.06 09:08
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Нет, все верно. stdcall традиционно не поддерживает переменное число агрументов, поскольку стек очищает сама функция. cdecl может поддерживать переменное число агрументов, однако в библиотеке переменное число агрументов не поддерживается вообще. Используйте va функции для передачи переменного числа агрументов, если оные, конечно, имеются. Еще где-то в исходниках были еще варианты динамической загрузки — может там что поможет.


    Просто есть DLL одной малоизвесной SQL базы данных, и было желание написать "враппер", т.к. вся работа шла через одну DLL. Так там экспортировались функции с переменным количеством аргументов , было б неплохо хотябы "подпорку" написать, что для всех как обычно функций, а для таких "с извратами". Чтоб для можно было использовать для _любых_ С-функций.
    Re[5]: Pure C++ delay load
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 28.02.06 12:42
    Оценка:
    AS>>Нет, все верно. stdcall традиционно не поддерживает переменное число агрументов, поскольку стек очищает сама функция. cdecl может поддерживать переменное число агрументов, однако в библиотеке переменное число агрументов не поддерживается вообще. Используйте va функции для передачи переменного числа агрументов, если оные, конечно, имеются. Еще где-то в исходниках были еще варианты динамической загрузки — может там что поможет.

    P>Просто есть DLL одной малоизвесной SQL базы данных, и было желание написать "враппер", т.к. вся работа шла через одну DLL. Так там экспортировались функции с переменным количеством аргументов , было б неплохо хотябы "подпорку" написать, что для всех как обычно функций, а для таких "с извратами". Чтоб для можно было использовать для _любых_ С-функций.


    Не получится. Проблема в прокси — там требуется знать количество параметров при определении. Ну и сама идеология "ленивой" загрузки не позволяет это делать. Впрочем, все ясно из кода...
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[6]: Pure C++ delay load
    От: adontz Грузия http://adontz.wordpress.com/
    Дата: 28.02.06 12:58
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Не получится. Проблема в прокси — там требуется знать количество параметров при определении. Ну и сама идеология "ленивой" загрузки не позволяет это делать. Впрочем, все ясно из кода...


    В принципе некоторое количество ассемблера решило бы проблему
    A journey of a thousand miles must begin with a single step © Lau Tsu
    Re[7]: Pure C++ delay load
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 28.02.06 22:56
    Оценка:
    AS>>Не получится. Проблема в прокси — там требуется знать количество параметров при определении. Ну и сама идеология "ленивой" загрузки не позволяет это делать. Впрочем, все ясно из кода...

    A>В принципе некоторое количество ассемблера решило бы проблему


    Некоторое количество машинных команд может решить любую программистскую проблему. Вот только вопрос в том, как правильно собрать эти команды. В рамках библиотеки использовать ассемблерные вставки, очевидно, смысла нет — 99% задач решается и без них, для остального есть поддерживаемый компилятором делейлоад, либо резолвинг ручками. Смысла терять в переносимости библиотеки из-за сомнительной поддержки переменного числа параметров я не вижу Написать ручками обертку на загружаемую библиотеку один раз — имхо не проблема.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re: Pure C++ delay load
    От: Tanker  
    Дата: 01.03.06 13:30
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    Объясни в кратце, для чего нужно городить этот огрод — 'GetM','odul','eHan','dleA'
    The animals went in two by two, hurrah, hurrah...
    Re[2]: Pure C++ delay load
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 01.03.06 13:44
    Оценка:
    T>Объясни в кратце, для чего нужно городить этот огрод — 'GetM','odul','eHan','dleA'

    Вкртц. — См. посл. верс.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re: Исходники 1.4.0
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 11.07.06 14:42
    Оценка:
    Поскольку сразу через 2 версии, то в порядке очереди.

    Итак, версия 1.3.0. (предыдущая)

    Список изменений:

    1. Добавлена поддержка конвенций вызова. Непосредственно в библиотеке поддерживаются WINAPI и __cdecl.
    Итак, как все это работает. За поддержку встроенных конвенций отвечают макросы
    #define DL_NO_STDCALL // не инстанцировать поддержку winapi соглашений о вызовах
    #define DL_USE_CDECL  // инстанцировать поддержку __cdecl (по умолчанию отключено)

    За поддержку вообще любых конценций отвечают макросы
    DL_DECLARE_FUN_PROXY_CC(call_conv) // инстанцировать поддержку конвенций call_conv.
    
    DL_DECLARE_FUN_CC(cc, name_id, r, p)
    DL_DECLARE_FUN_THROW_CC(cc, name_id, r, p)
    DL_DECLARE_FUN_ERR_CC(cc, name_id, r, p, e)
    DL_DECLARE_FUN_ERR_POLICY_CC(cc, name_id, r, p, pl)

    Назначение и параметры макросов DL_DECLARE_FUN_xxx_CC аналогичны DL_DECLARE_FUN_xxx, за исключением того, что первым параметром добавляется конвенция о вызове функции. Т.о., на самом деле это generic интерфейс к библиотеке, которым пользуются все остальные макросы.

    Ну и примеры использования.

    Включение __cdecl:
    #define DL_USE_CDECL
    #include "delayimphlp.h"
    
    DL_USE_MODULE_BEGIN(mydll, "mydll.dll")
        DL_DECLARE_FUN_CC(__cdecl, MyFun, int, (int))
    DL_USE_MODULE_END()

    Добавление своих конвенций, например, __fastcall:
    #include "delayimphlp.h"
    
    DL_DECLARE_FUN_PROXY_CC(__fastcall)
    
    DL_USE_MODULE_BEGIN(mydll, "mydll.dll")
        DL_DECLARE_FUN_CC(__fastcall, MyFun, int, (int))
    DL_USE_MODULE_END()


    Версия 1.4.0. (текущая)

    Список изменений:

    1. Добавлена поддержка числовых идентификаторов функций (by ord), а также возможность переименования (алиаса) для функций. Для этого определен расширенный набор макросов DL_DECLARE_FUN_...._EX. Список параметров аналогичен обычному набору, за исключением необходимости задавать и имя , и идентификатор функции (ижентификатор это то, что получает GetProcAddr).
    Например,
    DL_DECLARE_FUN_EX(Fun123, 123, DWORD, (VOID))
    DL_DECLARE_FUN_EX(fun_124, "Fun124", DWORD, (VOID)).

    2. Добавлена политика ошибок CFunProxyDefPolicy — в отличие от CFunProxyValuePolicy, позволяет работать не только со встроенными типами. Данная политика используется в макросах DL_DECLARE_FUN(_EX) вместо CFunProxyValuePolicy<ret_type>.

    To do

    Багфиксы
    Что то еще?

    Исходники, как обычно, брать по адресу http://www.rsdn.ru/File/8583/delayimphlp.zip
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.