Здравствуйте, Andrew S, Вы писали:
AS>Super! А кросс-модульность будет работать? Т.е. будем ли мы получать один прокси в результате специализаций одинаковыми NameId из разных модулей в этом случае?
1)Что ты понимаешь под модулем?
2)По идеи этот вариант должен работать также как и твой.
... << RSDN@Home 1.1.4 rev. 142 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
AS>>Super! А кросс-модульность будет работать? Т.е. будем ли мы получать один прокси в результате специализаций одинаковыми NameId из разных модулей в этом случае? WH>1)Что ты понимаешь под модулем?
Различные единицы компиляции. Уже проверил — все нормально, одинаковые прокси из разных единиц компиляции находятся после линка по одним адресам.
WH>2)По идеи этот вариант должен работать также как и твой.
Так и работает. Еще раз спасибо — самое очевидно решение я и не заметил. А ведь в первоначальном виде (без темплайтов) у нас идентификатор имени именно так и определялся — при помощит подобных макросов
В общем, похоже мы нашли вариант специализировать шаблоны константной строкой, правда, при маленькой помощи препроцессора
Убраны ненужные теперь макросы DL_SEQ_ELEM и многие другие — макромагии стало меньше, совместимость с препроцессорами выше.
To do
Поддержка MT.
Поддержка соглашений о вызовах кроме __stdcall.
Поддержка функций с переменным числом параметров.
Что то еще?
Да, хорошо бы проверить все это на VC7-7.1... У меня, к сожалению, этих компиляторов нет.
Наверняка, если и не будет компилироваться, можно будет легко устранить причину — ничего особо страшного в коде нет.
В принципе вся "опасная" часть находится внутри InitFunction (я ничего не пропустил?). Самое простое это обернуть её в CriticalSection. Это тормознёт все потоки — что плохо. С другой стороны такой казалось бы легковесный объект как event отожрал у меня около 16 тыс тиков.
for (int index = 0; index < 100000; index++)
{
CloseHandle(CreateEvent(NULL, FALSE, FALSE, _T("EVENT")));
}
Mutex отнял приблизительно столько же времени. На этом фоне очень привлекательны критические секции. Они судя по всему раза в 4 быстрее.
Хотя вобщем-то не известно какие потоки запускает DllMain и как отразиться на программе то, что LoadLibrary вызван из критической секции.
Поддержка соглашений о вызовах кроме __stdcall.
Поддержка функций с переменным числом параметров.
ИМХО только с привлечением ассемблера. Надо будет ProxyFun переписать.
Собственно релиз в VC7.1 как раз и представляет собой то, что надо (параметры шаблонов опущены)
call CDynFunction<>::InitFunction (401730h)
test eax,eax
je error:
jmp dword ptr [`CDynFunction<>::GetProxy'::`2'::proxy]
error:
call FunProxyThrowPolicy<>::MakeReturnImpl
Как видишь этот код не завязан ни на количество параметров ни на конвенцию вызова.
P.S. Вызов через такую обёртку даже быстрее вызова через таблицу импорта. Вот я и думаю, а не создать ли продвинутый файл windows (как string.h -> string) в котором все функции будут раскиданы по пространствам имён? Как побочный эффект своего рода антиотладка (передаю привер шароварщикам ) Эдакая МЕГАИДЕЯ
FARPROC GetProcAddress(
HMODULE hModule, // handle to DLL module
LPCSTR lpProcName // function name
);
HMODULE LoadLibrary(
LPCTSTR lpFileName // file name of module
);
(C)MSDN
... << RSDN@Home 1.1.4 rev. 142 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
A>Поддержка MT.
A>В принципе вся "опасная" часть находится внутри InitFunction (я ничего не пропустил?). Самое простое это обернуть её в CriticalSection. Это тормознёт все потоки — что плохо. С другой стороны такой казалось бы легковесный объект как event отожрал у меня около 16 тыс тиков.
Верно, но не совсем. На самом деле там 2 места в одной функции — собственно, сама функция и синглтон модуля. Т.е. надо будет по одному объекту синхронизации на модуль + по одному на каждую функцию. На первый взгляд, печально — но на самом деле, все несколько лучше — можно это все обернуть в lightweight mutex'ы — пример приводил WolfHound. Это обеспечит помимо простоты синхронизации еще и всего 4 байта оверхеда на функцию и модуль в MT версии, что имхо немного. Можно вообще LW мутекс привязать только к модулю или же к классу функций (например, сделать его параметр статическим синглтоном без конструктора, как и прокси, по параметру CDynFunction::Name или еще как — надо подумать. В общем, варианты есть, и не такие уж сложные\медленные, тем более, что все это только один раз вызываться будет).
Вообще, на крайний случай — можно засинхронизировать только синглтон модулей, а сама функция на самом деле вполне реенернабельна.
A>Поддержка соглашений о вызовах кроме __stdcall. A>Поддержка функций с переменным числом параметров.
Тут придется поправить макросы. Но я подумал — что то расхотелось мне это делать. Не так и много целевых функций имеет отличные от STDCALL конвенции, к тому же в основном это _cdecl с переменным числом параметров, а их все равно легально кроме как через V версии не передать — а они все WINAPI. Т.е. практическая необходимость сомнительна. Поэтому я (пока?) решил на это забить.
Ага. Я решил во избежание дублирования анси и не анси строк в юникодной версии (наверное, компиляторы выкинут ненужный код, но лучше не рисковать) сделать так:
A>Я тут взял на себя наглость прошёлся по коду regex'пами и проч. Изменения под Unicode и под VC7.1 внесены.
Не, мне такое форматирование не нравится Не по стандарту (нашему, по крайней мере). Одни отсупы {} чего стоят. Да и переименование макроса CAT в MERGE тоже не по стандарту — в бусте именно CAT и хочется этому хоть как то соответствовать. Опять же, у меня еще несколько изменений касательно авто-поддержки юникода (да, да, именно авто поддержки, на основе заголовков от обычных, статически линкуемых бибилотек), которые я тут еще не отражал. В общем, думаю, пока что не стоит форматировать сурсы (по крайней мере публично — локально можно конечно делать что угодно ) — бесполезный труд, у меня еще слишком много чего есть, и конкатенировать после таких изменений сложно Но в любом случае — спасибо за попытку!
Здравствуйте, Andrew S, Вы писали:
AS>Да и переименование макроса CAT в MERGE тоже не по стандарту — в бусте именно CAT и хочется этому хоть как-то соответствовать.
Это совершенно не соответствует англо-русскому словарю В доке к ## preprocessor operator так и написано
The double-number-sign or "token-pasting" operator (##), which is sometimes called the "merging" operator, is used in both object-like and function-like macros.
А о чём думали в бусте я не знаю Cat это кошка Я кошек люблю, но здесь они не к месту.
AS>Опять же, у меня еще несколько изменений касательно авто-поддержки юникода (да, да, именно авто поддержки, на основе заголовков от обычных, статически линкуемых бибилотек), которые я тут еще не отражал.
Что ещё туда добавлять? Func на FuncA или FuncW будет заменятся вне зависимости он нашего желания. Со структурами тоже самое. В unicode я это дело уже компилировал (1.06б) всё ОК.
Я что-то упустил?
AS>В общем, думаю, пока что не стоит форматировать сурсы (по крайней мере публично — локально можно конечно делать что угодно ) — бесполезный труд, у меня еще слишком много чего есть, и конкатенировать после таких изменений сложно Но в любом случае — спасибо за попытку!
AS>>Да и переименование макроса CAT в MERGE тоже не по стандарту — в бусте именно CAT и хочется этому хоть как-то соответствовать.
A>Это совершенно не соответствует англо-русскому словарю В доке к ## preprocessor operator так и написано
Соответствует. A>А о чём думали в бусте я не знаю Cat это кошка Я кошек люблю, но здесь они не к месту.
Это сокращение от concatenate и достаточно точно отражает смысл, как мне кажется В отличие от MERGE — которое значит совмещать, но не соединять. Вообше, merge на мой взгляд больше применим к множествам, а конкатинация — к последовательностям.
AS>>Опять же, у меня еще несколько изменений касательно авто-поддержки юникода (да, да, именно авто поддержки, на основе заголовков от обычных, статически линкуемых бибилотек), которые я тут еще не отражал.
A>А что ещё? Там же макросы типа A>
A>Что ещё туда добавлять? Func на FuncA или FuncW будет заменятся вне зависимости он нашего желания. Со структурами тоже самое. В unicode я это дело уже компилировал (1.06б) всё ОК. A>Я что-то упустил?
Конечно. В текущей версии DECLARE_NAME_ID(NameId, #NameId) раскроет LoadLibrary именно в "LoadLibrary" вне зависимости от нашего (не)желания. AS>>В общем, думаю, пока что не стоит форматировать сурсы (по крайней мере публично — локально можно конечно делать что угодно ) — бесполезный труд, у меня еще слишком много чего есть, и конкатенировать после таких изменений сложно Но в любом случае — спасибо за попытку!
A>Отступы только делай табуляцией.
Дык я вроде ей и делаю (точнее, VAssist делает). Если где что и упустил — или по своему недосмотру, или спостил изменения с форума. Или ты имеешь ввиду отсуп между типом и именем определения (ну или директивой\именем)? Там да, я по-привычке ставлю пробелы. Попробую поправить.
Здравствуйте, Andrew S, Вы писали:
AS>Это сокращение от concatenate и достаточно точно отражает смысл, как мне кажется В отличие от MERGE — которое значит совмещать, но не соединять.
Скорее объединять.
AS>Вообше, merge на мой взгляд больше применим к множествам, а конкатинация — к последовательностям.
Ну я за имя не дерусь, используется этот макрос всё равно только в служебных целях. Просто для меня оно показалось непонятным.
AS>Конечно. В текущей версии DECLARE_NAME_ID(NameId, #NameId) раскроет LoadLibrary именно в "LoadLibrary" вне зависимости от нашего (не)желания.
Ну и? У одних функций есть A/W версии у других нету. ИМХО лучше сделать
DL_USE_MODULE_BEGIN(kernel, "kernel32.dll")
DL_DECLARE_FUN_DUAL(GetModuleHandle, HMODULE, (LPC??что здесь писать??STR))
DL_USE_MODULE_END
A>>Отступы только делай табуляцией. AS>Дык я вроде ей и делаю (точнее, VAssist делает).
Нет, это я зря ругаюсь. Если копировать с сайта, то по любому пробелы, даже если в исходном сообщении табуляция.
Единственный шанс получить текст с табуляцией это копировать из цитирования в форме ответа
Зато если в студии выделить всё и нажать Tab, Shift+Tab то всё будет как надо но это в 7.1, а в 6ке не знаю как.
A>Ну и? У одних функций есть A/W версии у других нету. ИМХО лучше сделать A>
A>DL_USE_MODULE_BEGIN(kernel, "kernel32.dll")
A> DL_DECLARE_FUN(GetModuleHandleA, HMODULE, (LPCSTR))
A> DL_DECLARE_FUN(GetModuleHandleW, HMODULE, (LPCWSTR))
A>DL_USE_MODULE_END
A>
чем A>
A>DL_USE_MODULE_BEGIN(kernel, "kernel32.dll")
A> DL_DECLARE_FUN_DUAL(GetModuleHandle, HMODULE, (LPC??что здесь писать??STR))
A>DL_USE_MODULE_END
A>
А здесь писать
DL_USE_MODULE_BEGIN(kernel, "kernel32.dll")
DL_DECLARE_FUN_DUAL(GetModuleHandle, HMODULE, (LPCTSTR))
DL_USE_MODULE_END
В этом то и фишка. На самом деле, за нас все сделает препроцессор, маленький трюк, как и с CAT, на самом деле — заставить его вывести макрос до дальнейшего препроцессирования.
A>>>Отступы только делай табуляцией. AS>>Дык я вроде ей и делаю (точнее, VAssist делает).
A>Нет, это я зря ругаюсь. Если копировать с сайта, то по любому пробелы, даже если в исходном сообщении табуляция. A>Единственный шанс получить текст с табуляцией это копировать из цитирования в форме ответа A>Зато если в студии выделить всё и нажать Tab, Shift+Tab то всё будет как надо но это в 7.1, а в 6ке не знаю как.
У меня вроде как с табами копируется, а если целевой редактор понимает — то даже и RTF. VAssist — великая штука.
Здравствуйте, Andrew S, Вы писали:
AS>Список изменений:
AS>[list] AS>Изменены порождающие макросы (спасибо WolfHound). Теперь синтаксис стал гораздо более очевидным и нативным: AS>
Я не вижу проблемы с MT. Запись/чтение выравненного двойного слова атомарна, поэтому худшее, что может быть — лишний вызов GetProcAddress.
Ещё у меня предложение — вместо разных макросов, для разных способов обработки ошибок позволить в макросе указывать функцию-обработчик, с таким же возвращаемым значенем, как и генерируемая функция. Таким образом будет выбор, или возвратить что-то инвалидное, или сделать throw / RaiseException. Кроме того, исчезнет зависимость от sprintf'а. Конечно, указывать в каждой функции обработчик ошибок — накладно, пока могу предложить только "глобальный" обработчик, который будет указываться в DL_USE_MODULE_BEGIN.
Кстати, я вижу, что ошибки с LoadModule никак не обрабатываются, и единственный способ узнать, что dll'ки нет — это самостоятельно проверить CModule::GetModule на 0.
...
CAM>Кстати, я вижу, что ошибки с LoadModule никак не обрабатываются, и единственный способ узнать, что dll'ки нет — это самостоятельно проверить CModule::GetModule на 0.