LoadStringW, неизвестный размер

Общие вопросы, не зависящие от языка реализации.

Модераторы: Duncon, Hawk, Romeo, Eugie

Apokal
Сообщения: 81
Зарегистрирован: 14 янв 2008, 19:02

Добрый день всем, подскажите незнающему как рещить проблемку.

Для правильной работы функции LoadStringW нужно в качестве одного из параметров указать разер буфера, в которой будет записана строка. Но как быть если пользователь предоставляет только указатель на будущий буфер? Тобишь мне самому нужно как то выяснить размер строки которая загрузится и выделить память на которую будет ссылатся переданый мне указатель... Как бы это сделать?
For Those Who About The Rock We Salute You!!!
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Тогда тебе должны передавать не только указатель на массив, но и его длину.
Либо эта величина должна быть предопределена в виде константы, например так:

#define MAX_BUFF_LEN 512

В этом случае пользователь должен будет использовать эту константу для создания массива и
ты её сможешь использовать в качестве параметра для LoadString.

В качестве альтернативы можно передавать не указатель на массив символов, а ссылку на класс типа CString.
Тогда ты сможешь просто вызывать метод CString::LoadString() без всяких дополнительных параметров.
Поумнеть несложно, куда труднее от дури избавиться.
Apokal
Сообщения: 81
Зарегистрирован: 14 янв 2008, 19:02

Спасибо за ответ. Вариант с заранее определенным размером мне не подходит. Идея использовать CString интересна, но всетаки хотелось бы ограничится стандартным windows.h, но на крайняк можно и зделать так как Вы описали. Еще раз спасибо.
For Those Who About The Rock We Salute You!!!
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Если хочешь ограничиться функциями Windows API, то могу порекомендовать использовать функции GlobalAlloc() для выделения памяти и GlobalFree() для удаления. В саму функцию нужно передавать не указатель на массив, а переменную HGLOBAL. С помощью функции GlobalSize() можно будет узнать размер выделенной памяти. Чтобы обратиться к указателю на массив по переменной HGLOBAL, нужно использовать функции GlobalLock() и GlobalUnlock().
Поумнеть несложно, куда труднее от дури избавиться.
BBB
Сообщения: 1298
Зарегистрирован: 27 дек 2005, 13:37

Из описания параметра nBufferMax в MSDN:
nBufferMax [in]
int

The size of the buffer, in characters. The string is truncated and null-terminated if it is longer than the number of characters specified. If this parameter is 0, then lpBuffer receives a read-only pointer to the resource itself.


Если вам хочется ТОЧНО выделить размер памяти, то, как я понял из описания, можно указать nBufferMax, в качестве lpBuffer передать свой указатель. После вызова функция заполнит его "read-only pointer"-ом. Далее с помощью lstrlen можно получить размер строки ресурса, выделить соответсвующее колиечство памяти (длина + 1) уже по "своему" указателю, и скопировать туда строку из полученного при вызове LoadString указателя.
Apokal
Сообщения: 81
Зарегистрирован: 14 янв 2008, 19:02

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

Я решил пойти немножко по-другому пути, но и тут возникла непонятная ошибка, прошу помочь.
Суть в том что вначале выделяю минимальный обьем памяти в который бы смог записать 10 WCHAR. Потом сравниваю количество записаных символов функцией LoadStringW в переменную size и размер буфера nBuffSize, если результат 1 или меньше значит буфер был мал для строки, поэтому освобождаю выделенную под него память, увеличию размер буфера и выделяю опять память, и так пока не будет достаточно места для строки.

Но происходит ошибка при вызове функции LocalFree() ( TestDll.exe -- прога в которой динамически гружу дллку, в которой находится функция с данным кодом)
Windows has triggered a breakpoint in TestDll.exe.
This may be due to a corruption of the heap, which indicates a bug in TestDll.exe or any of the DLLs it has loaded.

В следущем окне
Unhandled exception at 0x7765283b in TestDll.exe: 0xC0000374: Куча была повреждена.

Немогу понять в чем ошибка работы с кучей?

Код: Выделить всё

        LPTSTR pszBuf = NULL;
	size_t size = 0, nBuffSize = 10*sizeof(WCHAR);
	pszBuf = (LPTSTR)LocalAlloc(LPTR,nBuffSize);
        size=LoadStringW(GetModuleHandle(TEXT("RW7_Res.dll")),(uId+uLanguageId),pszBuf,nBuffSize);
        if((nBuffSize-size)<=1)
		do
		{
			LocalFree(pszBuf);
			nBuffSize+=(10*sizeof(WCHAR));
			pszBuf = (LPTSTR)LocalAlloc(LPTR,nBuffSize);
			size=LoadStringW(GetModuleHandle(TEXT("RW7_Res.dll")),(uId+uLanguageId),pszBuf,nBuffSize);
		} while((nBuffSize-size)<=1);
For Those Who About The Rock We Salute You!!!
BBB
Сообщения: 1298
Зарегистрирован: 27 дек 2005, 13:37

Пробовал использовать особенность параметра nBufferMax, но к сожалению в предоставленый мною указатель ничего не записывалось.
Рискну предположить, что что-то Вы не так поняли/делали. Т.к. скорее поверю в это, чем в то, что MSDN нагло врет :)

По ошибке.
Рискну предположить, что при присвоении значения переменной nBuffSize не нужно умножать на sizeof(WCHAR). Т.к. в ф-ию LoadStringW размер, по моему разумению, передается именно в WCHAR-ах! А Вы, по сути, передали размер в байтах. Т.е. LoadStringW, при такой подаче, в результате рассчитывает на буфер в два (sizeof(WCHAR)) раз бОльшего размера, чем ВЫ передали. Отсюда и развал хипа в конечном итоге.

Ну и немного "причесывания" кода. Зачем Вы сначала используете IF, а зтем while С ТЕМ ЖЕ САМЫМ условием? :)

Код: Выделить всё

if(<условие>)
        do
        {
            .............
        } while(<условие>);
Ведь то же самое можно записать как:

Код: Выделить всё

do while(<условие>)
        {
            .............
        };
Hawk
Сообщения: 216
Зарегистрирован: 17 фев 2004, 14:52
Откуда: СПб
Контактная информация:

А к чему цикл вообще ?
размер уже известен почему бы не сделать -

Код: Выделить всё

       if( (size + 1) > (nBuffSize / sizeof(WCHAR)) )
        {
            LocalFree(pszBuf);
            nBuffSize = (size + 1)*sizeof(WCHAR);
            pszBuf = (LPTSTR)LocalAlloc(LPTR, nBuffSize );
            size = LoadStringW(GetModuleHandle(TEXT("RW7_Res.dll")),(uId+uLanguageId),pszBuf, size);
            pszBuf[size] = 0;
        } 
не уверен на 100% но думаю первый вызов можно без буфера сделать чтобы только размер получить -

size = LoadStringW(GetModuleHandle(TEXT("RW7_Res.dll")),(uId+uLanguageId), NULL, 0);
sriditerrs
Сообщения: 22
Зарегистрирован: 21 окт 2012, 22:31
Откуда: Россия
Контактная информация:

Об этом и об востановление экономики , доллар растёт и об Австралийский доллар под давлением
на http://rus-crediter.ru/
На нашем сайте всегда интересные новости.
sriditerrs
Сообщения: 22
Зарегистрирован: 21 окт 2012, 22:31
Откуда: Россия
Контактная информация:

Ответить