Ошибка при работе WideCharToMultiByte

Тема в разделе "WASM.BEGINNERS", создана пользователем Leonov, 15 ноя 2008.

  1. Leonov

    Leonov Николай

    Публикаций:
    0
    Регистрация:
    14 ноя 2008
    Сообщения:
    14
    Адрес:
    Астрахань
    всем драсти, вопрос такой.
    пишу прогу по обработке файлов реестра и в ней используется функция WideCharToMultiByte для работы с файлами в кодировке uniocde. так вот при вызове этой функции выскакивает ошибка:
    ошибка появляется если файл, который обрабатывает WideCharToMultiByte, весит около 160 кб и больше. как это можно объяснить?
    вот код:
    Код (Text):
    1. invoke CreateFileMappingA, hFile, eax, PAGE_READONLY, eax, ecx, eax
    2.     or eax, eax
    3.     je CloseFile
    4.     mov hMap, eax
    5.     invoke MapViewOfFile, hMap, FILE_MAP_READ, 0, 0, sFile
    6.     or eax, eax
    7.     je Unmap
    8.     mov AdrMap, eax
    9.     invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,s2File
    10.     mov  hMemory,eax
    11.     invoke GlobalLock,hMemory
    12.     mov  pMemory,eax
    13.     push eax
    14.     push AdrMap
    15.     call r2b
    16.     ...
    17.     ...
    18. r2b proc
    19. ;esp+8h = адрес источника
    20. ;esp+0ch = адрес приемника
    21.     push ebp
    22.     mov ebp, esp
    23.     mov esi, dword ptr [ebp+8h]
    24.     cmp word ptr [esi], 0feffh
    25.     jne r2b_NoUnicode
    26.     add esi, 2 
    27.     invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,sFile
    28.     mov  hMemASCII,eax
    29.     invoke GlobalLock,hMemASCII
    30.     mov  pMemASCII,eax 
    31.     invoke WideCharToMultiByte, CP_ACP, NULL, esi, sFile, eax, sFile, NULL, NULL
    32.     mov esi, pMemASCII
    33. r2b_NoUnicode:
    34.     mov edi, dword ptr [ebp+0ch]
    35.     ...
    36. r2b endp
     
  2. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    Leonov
    >обратилась к памяти по адресу 0хХХХХХХХХ
    Огласи точный адрес и версию ОС.

    xpprosp2
    Код (Text):
    1. ...
    2. ;; kernel32!WideCharToMultiByte - Ord:037Fh
    3. :7C80A0C7  mov edi, edi
    4. :7C80A0C9  push ebp
    5. :7C80A0CA  mov ebp, esp
    6. :7C80A0CC  push edi
    7. :7C80A0CD  mov edi, dword ptr [ebp+08]
    8. :7C80A0D0  cmp edi, 0000EA60
    9. :7C80A0D6  jnb 7C825273
    10. :7C80A0DC  mov eax, dword ptr [7C883380]
    11. :7C80A0E1  cmp edi, eax
    12. :7C80A0E3  push esi
    13. :7C80A0E4  jne 7C80A280          ;; в моем kernel32.dll
    14.                      ;; это единственный переход
    15.                      ;; на адрес 7C80A280
    16. ...
    17.  
    18. :7C80A27B  jmp 7C80A133
    19. :7C80A280  mov ecx, dword ptr [7C88366C] ;; что тут может упасть?
    20.                      ;; память принадлежит kernel32.dll
    21.  
    22. :7C80A286  cmp edi, ecx
    23. :7C80A288  jne 7C80A295
    24. ...
     
  3. Leonov

    Leonov Николай

    Публикаций:
    0
    Регистрация:
    14 ноя 2008
    Сообщения:
    14
    Адрес:
    Астрахань
    адрес 0хХХХХХХХХ меняется в зависимости от выделенного файла.ОС - xppro вер. 5.1 сборка 2600
    начало кода WideCharToMultiByte также, но с другими адресами,
    Код (Text):
    1. ...
    2. 7C80A203   FF75 0C          PUSH DWORD PTR SS:[EBP+C]
    3. 7C80A206   FF75 1C          PUSH DWORD PTR SS:[EBP+1C]
    4. 7C80A209   FF75 18          PUSH DWORD PTR SS:[EBP+18]
    5. 7C80A20C   52               PUSH EDX
    6. 7C80A20D   53               PUSH EBX
    7. 7C80A20E   56               PUSH ESI
    8. 7C80A20F   E8 07000000      CALL kernel32.7C80A21B
    9. ...
    10.                 kernel32.7C80A21B
    11. 7C80A21B   8BFF             MOV EDI,EDI
    12. 7C80A21D   55               PUSH EBP
    13. ...
    14. 7C80A27C   90               NOP
    15. 7C80A27D   90               NOP
    16. 7C80A27E   90               NOP
    17. 7C80A27F   90               NOP
    18. 7C80A280   0FB702           MOVZX EAX,WORD PTR DS:[EDX] ;;на что тут ругаться. EDX - адрес Unicode строки
    19. 7C80A283   8A0418           MOV AL,BYTE PTR DS:[EAX+EBX] ;;здесь идет конвертация
    20. 7C80A286   42               INC EDX                 ;;unicode в ASCII
    21. 7C80A287   42               INC EDX
    22. 7C80A288   8801             MOV BYTE PTR DS:[ECX],AL
    23. 7C80A28A   41               INC ECX
    24. 7C80A28B   4E               DEC ESI
    25. 7C80A28C  ^75 F2            JNZ SHORT kernel32.7C80A280
    во время ошибки EDX содержит 0хХХХХХХХХ адрес. откуда он берется - беспонятие...
     
  4. Gnil

    Gnil New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2008
    Сообщения:
    41
    Что такое s2File и sFile? Возможно с размерами косяк.
    Чтобы все работало правильно лучше сначала вызвать WideCharToMultiByte для определения размера буфера, затем выделить память и вызвать WideCharToMultiByte еще раз.
     
  5. Freeman

    Freeman New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2005
    Сообщения:
    1.385
    Адрес:
    Ukraine
    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), вот и вылазете за пределы буфера...
     
  6. Leonov

    Leonov Николай

    Публикаций:
    0
    Регистрация:
    14 ноя 2008
    Сообщения:
    14
    Адрес:
    Астрахань
    sFile - размер исходного файла+2
    s2File - размер буфера под будущий файл (sFile*2 на всякий случай)
    если не трудно, начеркай примерный код вызова WideCharToMultiByte для определения размера буфера, а то с WideCharToMultiByte впервые приходится работать...
    Freeman
    но с файлами малых размеров работает правильно
     
  7. Leonov

    Leonov Николай

    Публикаций:
    0
    Регистрация:
    14 ноя 2008
    Сообщения:
    14
    Адрес:
    Астрахань
    Freeman
    int WideCharToMultiByte(

    UINT CodePage, // кодовая страница
    DWORD dwFlags, // флаги
    LPCWSTR lpWideCharStr, // адрес на wide-character строку
    int cchWideChar, // количество символов в строке
    LPSTR lpMultiByteStr, // адрес на буфер для новой строки
    int cchMultiByte, // резмер буфера
    LPCSTR lpDefaultChar, // параметры, которые применяются при
    LPBOOL lpUsedDefaultChar // обработке неправильных символов
    );
    вроде правильно все передается...
     
  8. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    Leonov
    Обрати внимание: "int cchWideChar, // количество символов" vs "sFile - размер исходного файла+2". Первое - слова, второе - байты.

    с файлами малых размеров работает правильно
    Насколько маленькие? Надо смотреть, как работает MapViewOfFile, когда ей передан маленький размер.
     
  9. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    Leonov
    Во первых следует прикреплять исходник воспроизводящий ошибку (короткий тест, который можно быстро скомпилировать), во вторых GlobalAlloc это для совместимости с win16, а уже давно win 64 на дворе ;)
    В третьих нафига вручную формировать прологи/эпилоги функции, если всё равно делаешь их такими же как компилятор? Зачем ещё раз выделять память в подпрограмме если ей уже передаётся адрес буфера для результата?
    А твоя проблема скорее всего в размерах. (у меня на большом размере файла глючит только не предназначенный для этого тестовый MessageBox).
     
  10. Leonov

    Leonov Николай

    Публикаций:
    0
    Регистрация:
    14 ноя 2008
    Сообщения:
    14
    Адрес:
    Астрахань
    с большими и с маленькими (примерно до 160 кб) файлами MapViewOfFile отрабатывается без ошибок.
    Y_Mur
    программа будет работать не только с файлами реестра в unicode, но и обычными файлами, напечатанными в блокноте (для этого и вставлена проверка cmp word ptr [esi], 0feffh), поэтому выделяется еще один буфер чтобы преобразовать unicode.
     
  11. Gnil

    Gnil New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2008
    Сообщения:
    41
    Пример (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)"
     
  12. Leonov

    Leonov Николай

    Публикаций:
    0
    Регистрация:
    14 ноя 2008
    Сообщения:
    14
    Адрес:
    Астрахань
    Y_Mur
    немного переделал на основе твоего исходника, все получилось, как ты и говорил проблема в размерах. спасибо огромное.