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_  
Дата: 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_  
Дата: 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: код 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[8]: код v1.06
От: _nn_  
Дата: 25.08.04 11:07
Оценка:
Здравствуйте, Andrew S, Вы писали:

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


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

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

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

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

Ну для этого LoadLibraryA есть
Предусмотреть все возможные проблемы заранее надо, или тогда написать чтобы не делать такое
http://rsdn.nemerleweb.com
http://nemerleweb.com
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.