Re[3]: Проблема с ReadFile в СОМ
От: Janis Baumanis Латвия  
Дата: 16.04.02 07:58
Оценка:
Здравствуйте DT, Вы писали:

DT>Здравствуйте Dront, Вы писали:


DT>>>Непонятная закавыка — при вызове ReadFile (COM-клиент на VB) в нижеприведенном методе происходит неожиданное завершение работы клиента (если сконфигурировать в Release) или выдается сообщение "Debug assertion failed!" c комментарием "_CrtIsValidHeapPointer(pUserData)" в файле dbgheap.c (если сконфигурировать в Debug), которого, кстати, на моей машине в принципе нет. Причем последнее сообщение появляется при освобождении памяти из-под буфера free (buffer), а если эту строчку убрать, то происходит то же самое, что и в Release. Если закомментировать ReadFile, ошибка исчезает, но и необходимые функции тоже. Что делать?


D>><skipped>

DT>>> char *buffer = new char [Len + 1];
DT>>> ::SetFilePointer(hFile,0,NULL,FILE_BEGIN);
DT>>> ::ReadFile(hFile, &buffer, Len, &NoB, NULL);
D>><skipped>

D>>еще бы не вылетало надо ::ReadFile(hFile, buffer, Len, &NoB, NULL);

D>>buffer — уже указатель.

DT>Интересно, а почему тогда у меня все замечательно работало и с указателем?


Так сказали уже, что макросы конвертации изпользует стек и из-за этого всё рушится, если конвертируемий буфер больше стека. Сам когда то на это налетел (где то тут даже про это упомянуто). Из-за этого макросы A2W, W2A, A2BSTR, BSTR2A итд. лучше не изпользовать для строк, которые длиннее 8 Kb. Я обошёлся путем выковыряния нужного кода из исходников ATL. То что получилось, можно посмотреть ниже. Работает нормально, самая длинная строка, которая попалась, была ~30 Mb

STDMETHODIMP CEDSDatabase::EDSWriteDUFFile(long lRecID, BSTR bstrFile, long lWriteMode, VARIANT_BOOL *pbResult)
{
.....
    TCHAR szFile[_MAX_PATH];
    BSTR bstrDUF = NULL;
    
    USES_CONVERSION;
    _tcscpy(szFile, OLE2T(bstrFile));

    // Load DUF from file.
    HANDLE hFile = CreateFile(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,  NULL);
    if (hFile != INVALID_HANDLE_VALUE) 
    {
        DWORD dwLen = ::GetFileSize(hFile, NULL);
        DWORD dwBytesRead;    
        char *pszDUF = new char[dwLen + 1];        // array + terminator char
        
        ReadFile(hFile, pszDUF, dwLen, &dwBytesRead, NULL);
        CloseHandle(hFile);

        if(dwLen == dwBytesRead)
        {
            char *pStartDUF = NULL;
            pszDUF[dwLen] = '\0';    // zero terminator
            // Search loaded file for DUF declaration start position.
            pStartDUF = lstrstr(pszDUF, "<DeclarationFile ");
            if(pStartDUF)
                bstrDUF = Ansi2BSTR(pStartDUF, -1, CP_BALTIC);
        }    
        delete [] pszDUF;
    }

    if(bstrDUF == NULL)
        return E_FAIL;
.....

}


// =====[ функции конвертации строк ]=====

// Convert ANSI string to unicode OLE string (BSTR). 
// Code page optional, system code page is used by default.
// Return converted BSTR or NULL, if error occurs.
inline BSTR Ansi2BSTR(LPCSTR lpsz, int nLen, UINT uiCP = CP_ACP)
{
    BSTR bstr = NULL;
    int nCnvLen = MultiByteToWideChar(uiCP, 0, lpsz, nLen, NULL, NULL);
    bstr = ::SysAllocStringLen(NULL, nCnvLen);
    if (bstr != NULL)
        MultiByteToWideChar(uiCP, 0, lpsz, -1, bstr, nCnvLen);
    return bstr;
}

// Convert unicode OLE string (BSTR) to ANSI string. 
// Code page optional, system code page is used by default.
// Return converted ANSI string and length (terminating zero 
// is not included) or zero, if conversion failed.
inline int BSTR2Ansi(BSTR bstr, LPSTR *lpsz, UINT uiCP = CP_ACP)
{
    int iChars = SysStringLen(bstr);
    int iRet = 0;
    if(iChars)
    {
        *lpsz = new char[++iChars];
        iRet = WideCharToMultiByte(uiCP, 0, bstr, -1, *lpsz, iChars, 0, 0);
    }
    return (iRet == 0) ? 0 : --iRet;
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.