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: Сам код
От: 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[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[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[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[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[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[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[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
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.