//----------------------------------------------------------------------------- // // // File: dsnbuff.cpp // // Description: Implementation of CDSNBuffer... class that abstracts writes // of DSN information to P2 file. // // Author: Mike Swafford (MikeSwa) // // History: // 7/3/98 - MikeSwa Created // // Copyright (C) 1998 Microsoft Corporation // //----------------------------------------------------------------------------- #include "precomp.h" //---[ CDSNBuffer::~CDSNBuffer ]----------------------------------------------- // // // Description: // Destructor for CDSNBuffer. Does NOT close file handle (caller is // responisble for that). // Parameters: // - // Returns: // - // History: // 7/3/98 - MikeSwa Created // //----------------------------------------------------------------------------- CDSNBuffer::~CDSNBuffer() { TraceFunctEnterEx((LPARAM) this, "CDSNBuffer::~CDSNBuffer"); DebugTrace((LPARAM) this, "INFO: %d File writes needed by CDSNBuffer", m_cFileWrites); //make sure we don't pass in 1 bit if (m_overlapped.hEvent) { _VERIFY(CloseHandle((HANDLE) (((DWORD_PTR) m_overlapped.hEvent) & -2))); } TraceFunctLeave(); } //---[ CDSNBuffer::HrInitialize ]---------------------------------------------- // // // Description: // Initialize CDSNBuffer object. // - Associates destination file handle with object (will not close it) // - Creates an event for synchronizing file operations // Parameters: // hDestFile - Destination File Handle (must be opend with FILE_FLAG_OVERLAPPED) // Returns: // S_OK on success // E_INVALIDARG if handle invalid is passed in // E_FAIL if CreateEvent fails for an unknown reason // History: // 7/3/98 - MikeSwa Created // //----------------------------------------------------------------------------- HRESULT CDSNBuffer::HrInitialize(PFIO_CONTEXT pDestFile) { TraceFunctEnterEx((LPARAM) this, "CDSNBuffer::HrInitialize"); HRESULT hr = S_OK; _ASSERT(pDestFile); if (!pDestFile) { hr = E_INVALIDARG; goto Exit; } m_pDestFile = pDestFile; //allow this to act as reset m_overlapped.Offset = 0; m_overlapped.OffsetHigh = 0; m_cbOffset = 0; m_cbFileSize = 0; m_cFileWrites = 0; m_overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (!m_overlapped.hEvent) { hr = HRESULT_FROM_WIN32(GetLastError()); ErrorTrace((LPARAM) this, "ERROR: Unable to create DSNBuffer event - hr 0x%08X", hr); goto Exit; } //Set low bit stop ATQ completion routine from being called m_overlapped.hEvent = ((HANDLE) (((DWORD_PTR) m_overlapped.hEvent) | 0x00000001)); Exit: TraceFunctLeave(); return hr; } //---[ CDSNBuffer::HrWriteBuffer ]--------------------------------------------- // // // Description: // Writes the given buffer, will call write file if needed // Parameters: // pbInputBuffer Buffer to write // cbInputBuffer Number of bytes to write // Returns: // S_OK on success // History: // 7/3/98 - MikeSwa Created // 10/21/98 - MikeSwa Updated to support resource conversion // //----------------------------------------------------------------------------- HRESULT CDSNBuffer::HrWriteBuffer(BYTE *pbInputBuffer, DWORD cbInputBuffer) { return HrPrivWriteBuffer(TRUE, pbInputBuffer, cbInputBuffer); } //---[ CDSNBuffer::HrWriteModifiedUnicodeString ]------------------------------ // // // IMPORTANT NOTE: // This function replaces any whitespace characters in the input string // with unicode whitespace (0x0020). Becaase fUTF7EncodeBuffer treats // whitespace characters such as 0x3000 (Japanese whitespace) as a UTF7 // "separator", it will encode strings with such characters embedded as // 2 separate UTF7 strings. By replacing these characters with 0x0020 we // guarantee that the output UTF7 string is a single encoded string. // Description: // Writes a given NULL terminated Unicode string, and will call write file // if needed. Converts to UTF7 encoding. // Parameters: // pwszString String to write // Returns: // S_OK on success // //----------------------------------------------------------------------------- HRESULT CDSNBuffer::HrWriteModifiedUnicodeString(LPWSTR pwszString) { DWORD i = 0; DWORD cbLength = lstrlenW(pwszString); _ASSERT(pwszString != NULL); //Replace whitespace characters with for(i = 0; i < cbLength; i++) { if(iswspace(pwszString[i])) pwszString[i] = L' '; } return HrPrivWriteBuffer(FALSE, (PBYTE) pwszString, cbLength * sizeof(WCHAR)); } //---[ CDSNBuffer::HrPrivWriteBuffer ]----------------------------------------- // // // Description: // Private function to handle writing UNICODE and ASCII buffers // Parameters: // fASCII TRUE if buffer is ASCII // pbInputBuffer Buffer to write // cbInputBuffer #of bytes to write // Returns: // S_OK on success // Any errors returned from flushing buffer to disk // History: // 10/21/98 - MikeSwa Created // //----------------------------------------------------------------------------- HRESULT CDSNBuffer::HrPrivWriteBuffer(BOOL fASCII, BYTE *pbInputBuffer, DWORD cbInputBuffer) { HRESULT hr = S_OK; BOOL fDone = FALSE; BYTE *pbCurrentInput = pbInputBuffer; DWORD cbInputRead = 0; DWORD cbTotalInputRead = 0; DWORD cbOutputWritten = 0; DWORD cTimesThruLoop = 0; _ASSERT(NULL != m_pDestFile); while (!fDone) { cTimesThruLoop++; //the buffer can't be *that* large... this will hopfully catch infinite loops _ASSERT(cTimesThruLoop < 100); fDone = m_presconv->fConvertBuffer(fASCII, pbCurrentInput, cbInputBuffer-cbTotalInputRead, m_pbFileBuffer+m_cbOffset, DSN_BUFFER_SIZE - m_cbOffset, &cbOutputWritten, &cbInputRead); m_cbOffset += cbOutputWritten; _ASSERT(m_cbOffset <= DSN_BUFFER_SIZE); if (!fDone) { //Update vars passed to fConvertBuffer cbTotalInputRead += cbInputRead; pbCurrentInput += cbInputRead; _ASSERT(cbTotalInputRead <= cbInputBuffer); hr = HrWriteBufferToFile(); if (FAILED(hr)) goto Exit; } } Exit: return hr; } //---[ CDSNBuffer::HrWriteBufferToFile ]--------------------------------------- // // // Description: // Write the current buffer contents to the fils // Parameters: // - // Returns: // S_OK on success // History: // 7/3/98 - MikeSwa Created // //----------------------------------------------------------------------------- HRESULT CDSNBuffer::HrWriteBufferToFile() { TraceFunctEnterEx((LPARAM) this, "CDSNBuffer::HrWriteBufferToFile"); HRESULT hr = S_OK; DWORD cbWritten = 0; DWORD dwError = 0; if (m_cbOffset) //there is stuff to write { //fix up overlapped if (!WriteFile(m_pDestFile->m_hFile, m_pbFileBuffer, m_cbOffset, &cbWritten, &m_overlapped)) { dwError = GetLastError(); if (ERROR_IO_PENDING != dwError) { hr = HRESULT_FROM_WIN32(dwError); goto Exit; } //Wait for result, so we don't overwrite buffer and overlapped if (!GetOverlappedResult(m_pDestFile->m_hFile, &m_overlapped, &cbWritten, TRUE)) { hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit; } DebugTrace((LPARAM) this, "INFO: Async write pending for FIOContext 0x%08X", m_pDestFile); } _ASSERT(m_cbOffset == cbWritten); m_cbOffset = 0; m_cbFileSize += cbWritten; m_overlapped.Offset += cbWritten; m_cFileWrites++; } Exit: TraceFunctLeave(); return hr; } //---[ CDSNBuffer::SeekForward ]----------------------------------------------- // // // Description: // Seeks buffers place in file forward specified number of bytes. Flushes // Buffer in process of doing so. // Parameters: // cbBytesToSeek Number of bytes to seek forward // pcbFileSize Returns old file size // Returns: // S_OK on succedd // History: // 7/6/98 - MikeSwa Created // //----------------------------------------------------------------------------- HRESULT CDSNBuffer::HrSeekForward(IN DWORD cbBytesToSeek,OUT DWORD *pcbFileSize) { _ASSERT(pcbFileSize); HRESULT hr = HrWriteBufferToFile(); if (FAILED(hr)) return hr; *pcbFileSize = m_cbFileSize; m_cbFileSize += cbBytesToSeek; m_overlapped.Offset += cbBytesToSeek; return S_OK; } //---[ CDSNBuffer::HrLoadResourceString ]-------------------------------------- // // // Description: // Encapsulates the functionality of LoadString... but allows you to // specify a LangId, returns read only data // Parameters: // IN wResourceId ID of the resource // IN LangId LangID to get resource for // OUT pwszResource Read-only UNICODE resource (not NULL terminated) // OUT pcbResource Size (in bytes) of UNICODE String // Returns: // S_OK on success // HRESULTS from errors trying to get load resources // History: // 10/22/98 - MikeSwa Created // //----------------------------------------------------------------------------- HRESULT CDSNBuffer::HrLoadResourceString(WORD wResourceId, LANGID LangId, LPWSTR *pwszResource, DWORD *pcbResource) { HRESULT hr = S_OK; HINSTANCE hModule = GetModuleHandle(DSN_RESOUCE_MODULE_NAME); HRSRC hResInfo = NULL; HGLOBAL hResData = NULL; WORD wStringIndex = wResourceId & 0x000F; LPWSTR wszResData = NULL; WCHAR wchLength = 0; //character representing current length _ASSERT(pwszResource); _ASSERT(pcbResource); *pwszResource = NULL; *pcbResource = NULL; if (NULL == hModule) { hr = HRESULT_FROM_WIN32(GetLastError()); _ASSERT(0 && "Unable to load resource DLL"); goto Exit; } //Find handle to string table segment hResInfo = FindResourceEx(hModule, RT_STRING, MAKEINTRESOURCE(((WORD)((USHORT)wResourceId >> 4) + 1)), LangId); if (NULL == hResInfo) { hr = HRESULT_FROM_WIN32(GetLastError()); _ASSERT(0 && "Failed to find resource for requested LangId"); goto Exit; } hResData = LoadResource(hModule, hResInfo); if (NULL == hResData) { hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit; } //Get pointer to string table segement data wszResData = (LPWSTR) LockResource(hResData); if (NULL == wszResData) { hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit; } //OK Now we have a pointer to the string table segment //Lets use some code from LoadStringOrError to handle this //There are 16 strings in a segment, which means we can look at //The low 4 bits of the wResourceId (wStringIndex) //String Table segment format //PASCAL like string count first UTCHAR is count if TCHARs //A zero length string (ie resource 0) is simply the WORD 0x0000... //This loop handles both the same... when loop is done. // wszResData - Ptr to UNICODE string // wchLenght - Length of that string (in WCHARS) while (TRUE) { wchLength = *((WCHAR *)wszResData++); if (0 == wStringIndex--) break; // Step to start if next string... wszResData += wchLength; } *pwszResource = wszResData; *pcbResource = (DWORD) wchLength*sizeof(WCHAR); Exit: return hr; } //---[ CDSNBuffer::HrWriteResource ]------------------------------------------- // // // Description: // Gets resource for specified language ID, and dumps UNICODE to DSN // content using current conversion context. // // It will assert if the resource cannot be found for the given language // ID. // Parameters: // dwResourceID The resouce ID of the resource to get // LandId The language ID to use // Returns: // S_OK on success // History: // 10/21/98 - MikeSwa Created // //----------------------------------------------------------------------------- HRESULT CDSNBuffer::HrWriteResource(WORD wResourceId, LANGID LangId) { HRESULT hr = S_OK; LPWSTR wszResource = NULL; DWORD cbResource = NULL; hr = HrLoadResourceString(wResourceId, LangId, &wszResource, &cbResource); if (FAILED(hr)) { _ASSERT(0 && "Unable to load resources"); //Fail silently in retail hr = S_OK; } //OK... now we have everything we need to write the buffer hr = HrPrivWriteBuffer(FALSE /*not ASCII */, (BYTE *) wszResource, cbResource); //$$REVIEW: Do we need to do any special cleanup here? return hr; }