всем драсти, вопрос такой. пишу прогу по обработке файлов реестра и в ней используется функция WideCharToMultiByte для работы с файлами в кодировке uniocde. так вот при вызове этой функции выскакивает ошибка: ошибка появляется если файл, который обрабатывает WideCharToMultiByte, весит около 160 кб и больше. как это можно объяснить? вот код: Код (Text): invoke CreateFileMappingA, hFile, eax, PAGE_READONLY, eax, ecx, eax or eax, eax je CloseFile mov hMap, eax invoke MapViewOfFile, hMap, FILE_MAP_READ, 0, 0, sFile or eax, eax je Unmap mov AdrMap, eax invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,s2File mov hMemory,eax invoke GlobalLock,hMemory mov pMemory,eax push eax push AdrMap call r2b ... ... r2b proc ;esp+8h = адрес источника ;esp+0ch = адрес приемника push ebp mov ebp, esp mov esi, dword ptr [ebp+8h] cmp word ptr [esi], 0feffh jne r2b_NoUnicode add esi, 2 invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,sFile mov hMemASCII,eax invoke GlobalLock,hMemASCII mov pMemASCII,eax invoke WideCharToMultiByte, CP_ACP, NULL, esi, sFile, eax, sFile, NULL, NULL mov esi, pMemASCII r2b_NoUnicode: mov edi, dword ptr [ebp+0ch] ... r2b endp
Leonov >обратилась к памяти по адресу 0хХХХХХХХХ Огласи точный адрес и версию ОС. xpprosp2 Код (Text): ... ;; kernel32!WideCharToMultiByte - Ord:037Fh :7C80A0C7 mov edi, edi :7C80A0C9 push ebp :7C80A0CA mov ebp, esp :7C80A0CC push edi :7C80A0CD mov edi, dword ptr [ebp+08] :7C80A0D0 cmp edi, 0000EA60 :7C80A0D6 jnb 7C825273 :7C80A0DC mov eax, dword ptr [7C883380] :7C80A0E1 cmp edi, eax :7C80A0E3 push esi :7C80A0E4 jne 7C80A280 ;; в моем kernel32.dll ;; это единственный переход ;; на адрес 7C80A280 ... :7C80A27B jmp 7C80A133 :7C80A280 mov ecx, dword ptr [7C88366C] ;; что тут может упасть? ;; память принадлежит kernel32.dll :7C80A286 cmp edi, ecx :7C80A288 jne 7C80A295 ...
адрес 0хХХХХХХХХ меняется в зависимости от выделенного файла.ОС - xppro вер. 5.1 сборка 2600 начало кода WideCharToMultiByte также, но с другими адресами, Код (Text): ... 7C80A203 FF75 0C PUSH DWORD PTR SS:[EBP+C] 7C80A206 FF75 1C PUSH DWORD PTR SS:[EBP+1C] 7C80A209 FF75 18 PUSH DWORD PTR SS:[EBP+18] 7C80A20C 52 PUSH EDX 7C80A20D 53 PUSH EBX 7C80A20E 56 PUSH ESI 7C80A20F E8 07000000 CALL kernel32.7C80A21B ... kernel32.7C80A21B 7C80A21B 8BFF MOV EDI,EDI 7C80A21D 55 PUSH EBP ... 7C80A27C 90 NOP 7C80A27D 90 NOP 7C80A27E 90 NOP 7C80A27F 90 NOP 7C80A280 0FB702 MOVZX EAX,WORD PTR DS:[EDX] ;;на что тут ругаться. EDX - адрес Unicode строки 7C80A283 8A0418 MOV AL,BYTE PTR DS:[EAX+EBX] ;;здесь идет конвертация 7C80A286 42 INC EDX ;;unicode в ASCII 7C80A287 42 INC EDX 7C80A288 8801 MOV BYTE PTR DS:[ECX],AL 7C80A28A 41 INC ECX 7C80A28B 4E DEC ESI 7C80A28C ^75 F2 JNZ SHORT kernel32.7C80A280 во время ошибки EDX содержит 0хХХХХХХХХ адрес. откуда он берется - беспонятие...
Что такое s2File и sFile? Возможно с размерами косяк. Чтобы все работало правильно лучше сначала вызвать WideCharToMultiByte для определения размера буфера, затем выделить память и вызвать WideCharToMultiByte еще раз.
cchWideChar [in] Specifies the number of wide characters in the string pointed to by the lpWideCharStr parameter. If this value is -1, the string is assumed to be null-terminated and the length is calculated automatically. The length will include the null-terminator. а у вас похоже там размер буфера передается вместо кол-ва wide буковок(которые по 2 байта, а не по 1), вот и вылазете за пределы буфера...
sFile - размер исходного файла+2 s2File - размер буфера под будущий файл (sFile*2 на всякий случай) если не трудно, начеркай примерный код вызова WideCharToMultiByte для определения размера буфера, а то с WideCharToMultiByte впервые приходится работать... Freeman но с файлами малых размеров работает правильно
Freeman int WideCharToMultiByte( UINT CodePage, // кодовая страница DWORD dwFlags, // флаги LPCWSTR lpWideCharStr, // адрес на wide-character строку int cchWideChar, // количество символов в строке LPSTR lpMultiByteStr, // адрес на буфер для новой строки int cchMultiByte, // резмер буфера LPCSTR lpDefaultChar, // параметры, которые применяются при LPBOOL lpUsedDefaultChar // обработке неправильных символов ); вроде правильно все передается...
Leonov Обрати внимание: "int cchWideChar, // количество символов" vs "sFile - размер исходного файла+2". Первое - слова, второе - байты. с файлами малых размеров работает правильно Насколько маленькие? Надо смотреть, как работает MapViewOfFile, когда ей передан маленький размер.
Leonov Во первых следует прикреплять исходник воспроизводящий ошибку (короткий тест, который можно быстро скомпилировать), во вторых GlobalAlloc это для совместимости с win16, а уже давно win 64 на дворе В третьих нафига вручную формировать прологи/эпилоги функции, если всё равно делаешь их такими же как компилятор? Зачем ещё раз выделять память в подпрограмме если ей уже передаётся адрес буфера для результата? А твоя проблема скорее всего в размерах. (у меня на большом размере файла глючит только не предназначенный для этого тестовый MessageBox).
с большими и с маленькими (примерно до 160 кб) файлами MapViewOfFile отрабатывается без ошибок. Y_Mur программа будет работать не только с файлами реестра в unicode, но и обычными файлами, напечатанными в блокноте (для этого и вставлена проверка cmp word ptr [esi], 0feffh), поэтому выделяется еще один буфер чтобы преобразовать unicode.
Пример (MFC, но должен работать CStringA UTF16toUTF8(const CStringW& utf16) { CStringA utf8; int len = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, NULL, 0, 0, 0); if (len>1) { char *ptr = utf8.GetBuffer(len-1); if (ptr) WideCharToMultiByte(CP_UTF8, 0, utf16, -1, ptr, len, 0, 0); utf8.ReleaseBuffer(); } return utf8; } (взято тут http://www.codeproject.com/KB/string/utfConvert.aspx) Вместо GetBuffer у тебя GlobalAlloc (кстати моднее использовать HeapAlloc, как тебе уже посоветовали) Сначала передаешь 0 в качестве размера буфера, в возвращаемом значении будет размер. "If the function succeeds and cchWideChar is 0, the return value is the required size for the buffer indicated by lpWideCharStr. (http://msdn.microsoft.com/en-us/library/ms776413(VS.85).aspx)"
Y_Mur немного переделал на основе твоего исходника, все получилось, как ты и говорил проблема в размерах. спасибо огромное.