Есть сишная либа, которую мы писали для ring-3 и есть уже некоторый объем ring-3 кода, который юзает эту либу. Сейчас понадобилось использовать либу в ring-0, в драйвере. И принято решение делать код "кроссплатформенным". С самим кодом, в общем сложностей никаких, компиляберность под wdk достигли быстро. Но уперлись в интерфейс. Часть функции в интерфейсе либы юзает wchar_t * (строки путей к файлам), для ring-3 это вполне приемлемо. А вот для ring-0 конечно же удобнее было бы использовать UNICODE_STRING.
И вот тут начинается конфликт между ring-0 и ring-3 пользователями либы. Нужно делать интерфейс, так чтобы он был удобен для всех. А варианты, которые я вижу:
1) заставить ring-3 пользователей страдать: использовать везде UNICODE_STRING
2) заставить страдать ring-0 пользователей: оставить в интерфейсе wchar_t * и заставить их формировать терминированную нулем строку из UNICODE_STRING. Т.е. перевыделять буфер строки UNICODE_STRING.Buffer, копировать оригинальный буфер + L'\0'. А потом очищать выделенную память.
3) как компромисс, сделать два аргумента: первый — строка, второй — размер буфера строки. DoSomething(wchar_t * str, int str size); Сформировать такие два аргумента из UNICODE_STRING.Buffer + UNICODE_STRING.Length легко. А вот для ring-3 аргумент размера буфера строки все равно обуза.
4) делать два разных интерфейса. Для ring-3 набор функций, например, DoSomething(wchar_t *); а для ring-0 — DoSomethingNative(UNICODE_STRING *); Но это тоже не нравится из-за дублирования.
Как вообще кроссплатфоменный принято в таких случаях оформлять?
p.s. Самое интересное, что в ring-0 в итоге строка из либы попадет в NtCreateFile(), т.е. если оставить wchar_t * в интерфейсе, то в ring-0 получается нелепая конверсия: UNICODE_STRING -> wchar_t * -> UNICODE_STRING
Здравствуйте, Hexxx, Вы писали:
H>Есть сишная либа, которую мы писали для ring-3 и есть уже некоторый объем ring-3 кода, который юзает эту либу. Сейчас понадобилось использовать либу в ring-0, в драйвере. И принято решение делать код "кроссплатформенным". С самим кодом, в общем сложностей никаких, компиляберность под wdk достигли быстро. Но уперлись в интерфейс. Часть функции в интерфейсе либы юзает wchar_t * (строки путей к файлам), для ring-3 это вполне приемлемо. А вот для ring-0 конечно же удобнее было бы использовать UNICODE_STRING. H>И вот тут начинается конфликт между ring-0 и ring-3 пользователями либы. Нужно делать интерфейс, так чтобы он был удобен для всех. А варианты, которые я вижу: H>1) заставить ring-3 пользователей страдать: использовать везде UNICODE_STRING H>2) заставить страдать ring-0 пользователей: оставить в интерфейсе wchar_t * и заставить их формировать терминированную нулем строку из UNICODE_STRING. Т.е. перевыделять буфер строки UNICODE_STRING.Buffer, копировать оригинальный буфер + L'\0'. А потом очищать выделенную память. H>3) как компромисс, сделать два аргумента: первый — строка, второй — размер буфера строки. DoSomething(wchar_t * str, int str size); Сформировать такие два аргумента из UNICODE_STRING.Buffer + UNICODE_STRING.Length легко. А вот для ring-3 аргумент размера буфера строки все равно обуза. H>4) делать два разных интерфейса. Для ring-3 набор функций, например, DoSomething(wchar_t *); а для ring-0 — DoSomethingNative(UNICODE_STRING *); Но это тоже не нравится из-за дублирования.
H>Как вообще кроссплатфоменный принято в таких случаях оформлять?
1. Сделать просто две разные функции
2. Сделать две разные библиотеки.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
В порядке безумства: взять С++ и написать обобщённый код на шаблонах, а наружу сделать extern "C" публичных функций.
А уж сделать две версии библиотеки, одна из которых инстанцирована для 0 кольца, а вторая для 3; или же одну библиотеку, где будут обе версии вместе сосуществовать — это дело вкуса и особенностей организации вашей системы сборки.
В принципе, можно поизгаляться и сделать "шаблоны для бедных".
#ifdef USING_WCHAR_T
#define STRING_TYPE wchar_t* /* как передавать */#define STRING_CONST(name, value) wchar_t* name = value; /* как определять константы */#define STRING_TAKE(name) name /* как передавать константы */
/* и т.д., что там ещё может понадобиться */#else
#define STRING_TYPE UNICODE_STRING*
#define STRING_CONST(name, value) UNICODE_STRING name = { wcslen(value), wcslen(value), value };
#define STRING_TAKE(name) &name
#endif
STRING_TYPE foo(STRING_TYPE arg)
{
STRING_CONST(bar, L"barbarbar")
return rand() ? arg : STRING_TAKE(bar);
}
(Знаю, что код адский, и не рекомендую делать именно ТАК — просто как демонстрация подхода).
Здравствуйте, Hexxx, Вы писали:
H>если оставить wchar_t * в интерфейсе, то в ring-0 получается нелепая конверсия: UNICODE_STRING -> wchar_t * -> UNICODE_STRING
в чем сложность провести такую конвертацию?
судя по http://msdn.microsoft.com/ru-RU/library/windows/desktop/aa380518(v=vs.85).aspx там все просто, строки не надо перевыделять или копировать, если они только как Input parameters
если output, то придется копировать из UNICODE_STRING в std::wstring
если конвертация легкая, то я бы заточил интерфейс на wchar_t*, в кишках где надо "конвертировал" бы в UNICODE_STRING
Здравствуйте, uzhas, Вы писали:
U>если output, то придется копировать из UNICODE_STRING в std::wstring
Библиотека сишная, а даже если и на плюсах писать, то всё равно, в нулевом кольце доступны ли сишный и плюсовой рантаймы? Придётся развлекаться с самодельными аллокаторами.
Здравствуйте, Кодт, Вы писали:
К>Библиотека сишная, а даже если и на плюсах писать, то всё равно, в нулевом кольце доступны ли сишный и плюсовой рантаймы? Придётся развлекаться с самодельными аллокаторами.
либо передавать (wchar_t* buffer, bufferSize)
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, uzhas, Вы писали:
U>>если output, то придется копировать из UNICODE_STRING в std::wstring
К>Библиотека сишная, а даже если и на плюсах писать, то всё равно, в нулевом кольце доступны ли сишный и плюсовой рантаймы? Придётся развлекаться с самодельными аллокаторами.
С-шный доступен, не полный, но многое есть.
В качестве input параметров делать const wchar_t * и не парится, они легко врапятся.
Остальное должно б/м совпадать, раз интерфейс уже С-шный. Надо только будет определиться если понадобится передавать память ring-0 to ring-3.
Здравствуйте, Hexxx, Вы писали:
H>3) как компромисс, сделать два аргумента: первый — строка, второй — размер буфера строки. DoSomething(wchar_t * str, int str size); Сформировать такие два аргумента из UNICODE_STRING.Buffer + UNICODE_STRING.Length легко. А вот для ring-3 аргумент размера буфера строки все равно обуза.
Это, плюс договориться, что размер равный -1 будет означать, что он не задан, и либа должна будет найти его сама через wcslen.
Здравствуйте, uzhas, Вы писали: U>если конвертация легкая, то я бы заточил интерфейс на wchar_t*, в кишках где надо "конвертировал" бы в UNICODE_STRING
всего лишь надо перевыделить буфер ради завершающего нуля, а потом освободить.
Здравствуйте, Hexxx, Вы писали:
H>Здравствуйте, uzhas, Вы писали: U>>если конвертация легкая, то я бы заточил интерфейс на wchar_t*, в кишках где надо "конвертировал" бы в UNICODE_STRING H>всего лишь надо перевыделить буфер ради завершающего нуля, а потом освободить.