At my work we're dealing with a lot of PHP files written by a third-party company and sometimes we want to quickly look at these files in Notepad rather than having to open up a full IDE.The problem is that these files have \n line endings which as many of you know Notepad doesn't handle correctly. Sure, there are solutions like installing Notepad++ but everyone knows that the first rule of engineering is that you always reinvent the wheel every chance you get. I'm kidding, I just really like coding.My solution: write a wrapper for Notepad that silently converts files containing Unix line endings into Windows/DOS style line endings and then opens the file in Notepad.Program Source Code:#include <Windows.h>#include <strsafe.h>// Defines for the line-ending conversion function#define LESTATUS INT #define LE_NO_CHANGES_NEEDED (0)#define LE_CHANGES_SUCCEEDED (1)#define LE_CHANGES_FAILED   (-1)LESTATUS WINAPI ConvertLineEndings(BYTE *inData, INT inLen, BYTE *outData, INT outLen, INT *bytesWritten){    INT sourceIndex = 0, destIndex;    // Fail immediately; no chance of success here.    if (outLen < inLen)        return LE_CHANGES_FAILED;    // Try to determine if changes are needed    while (sourceIndex < inLen)    {        // If an \r is immediately followed by an \n, no changes are needed to inData.        if (inData[sourceIndex] == '\r')        {            if (sourceIndex < inLen - 1 && inData[sourceIndex + 1] == '\n')            {                memcpy(outData, inData, inLen);                *bytesWritten = inLen;                return LE_NO_CHANGES_NEEDED;            }            // If we encountered an \r without a following \n then changes are needed.            break;        }        // If we encounter an \n without a preceding \r then changes are needed.        if (inData[sourceIndex] == '\n')            break;        sourceIndex++;    }    // But, up to the point where we encountered the bad line ending, we can copy *that* much into outData.    memcpy(outData, inData, sourceIndex);    // If, however, that was the end of the array, then we still don't need to make changes.    if (sourceIndex == inLen)        return LE_NO_CHANGES_NEEDED;    // Now, we begin the actual copying/rewriting of the array, so set destIndex to sourceIndex to begin counting.    destIndex = sourceIndex;    // Loop through the remainder of inData; if an \n or \r is encountered, rewrite it as appropriate into outData.    // If outData's limits are reached before we're done, report that changes failed.    while (sourceIndex < inLen)    {        switch (inData[sourceIndex])        {        case '\n':        case '\r':            sourceIndex++;            if (destIndex + 2 >= outLen)                return LE_CHANGES_FAILED;            outData[destIndex++] = '\r';            outData[destIndex++] = '\n';            break;        default:            outData[destIndex++] = inData[sourceIndex++];        }    }    *bytesWritten = destIndex;    return LE_CHANGES_SUCCEEDED;}INT APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, INT nShowCmd){    STARTUPINFO si;    PROCESS_INFORMATION pi;    DWORD dwExit, dwHigh, dwLow, dwRead = 0, dwWritten = 0, dwLen;    WCHAR *wszArgQuote = NULL;    BYTE *bIn = NULL, *bOut = NULL;    HANDLE hHeap = GetProcessHeap(), hFile;    INT nWritten = 0;    LESTATUS leResult;    StringCchLength(lpCmdLine, STRSAFE_MAX_CCH, &dwLen);    if(dwLen<=0)    {        MessageBox(0, LNo filename specified, LNotepad Wrapper, MB_OK | MB_ICONSTOP);           return 0;    }    hFile = CreateFile(lpCmdLine, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);    if(hFile == INVALID_HANDLE_VALUE)    {        MessageBox(0, LFile not found or access denied, LNotepad Wrapper, MB_OK | MB_ICONSTOP);         return 0;    }    // HeapAlloc is most likely going to fail on a file > 2GB    dwLow = GetFileSize(hFile, &dwHigh);    if(dwHigh>0 || (dwLow&0x80000000)==0x80000000)    {        MessageBox(0, LFile is too large, LNotepad Wrapper, MB_OK | MB_ICONSTOP);           return 0;    }    bIn = (BYTE *)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, dwLow+1);    // Worst case scenario: *every* character in the file is a newline - bOut must be at least double the size of bIn    bOut = (BYTE *)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, (dwLow+1)*2);    if(bIn==NULL || bOut == NULL)    {        MessageBox(0, LOut of memory, LNotepad Wrapper, MB_OK | MB_ICONSTOP);        return 0;    }    ReadFile(hFile, bIn, dwLow, &dwRead, NULL);    leResult = ConvertLineEndings(bIn, dwLow, bOut, dwLow*2, &nWritten);    if(leResult == LE_CHANGES_FAILED)    {        MessageBox(0, LCould not convert line endings in file, LNotepad Wrapper, MB_OK | MB_ICONSTOP);          return 0;    }    // Reset file pointer so that we write the new data to the start of the file    SetFilePointer(hFile, 0, 0, FILE_BEGIN);    WriteFile(hFile, bOut, nWritten, &dwWritten, NULL);    CloseHandle(hFile);    HeapFree(hHeap, 0, bIn);    HeapFree(hHeap, 0, bOut);    // Done converting file, now open it up in Notepad    wszArgQuote = (WCHAR *)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, (dwLen + 10) * sizeof(WCHAR));    if(wszArgQuote==NULL)    {        MessageBox(0, LOut of memory, LNotepad Wrapper, MB_OK | MB_ICONSTOP);        return 0;    }    // Surround filepath with quotes     StringCchPrintf(wszArgQuote, dwLen+10, L \%s\, lpCmdLine);    // Preparation & CreateProcess call    ZeroMemory(&si, sizeof(STARTUPINFO));    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));    si.cb = sizeof(STARTUPINFO);    CreateProcess(LC:\\Windows\\system32\\notepad.exe, wszArgQuote, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);    HeapFree(hHeap, 0, wszArgQuote);    // Return notepad.exe's exit code    WaitForSingleObject(pi.hProcess, INFINITE);    GetExitCodeProcess(pi.hProcess, &dwExit);    CloseHandle(pi.hProcess);    CloseHandle(pi.hThread);    return dwExit;}Registry ChangesREGEDIT4[HKEY_CLASSES_ROOT\.php]@=phpfile[HKEY_CLASSES_ROOT\phpfile\DefaultIcon]@=%SystemRoot%\\system32\\imageres.dll,-102[HKEY_CLASSES_ROOT\phpfile\shell\open\command]@=C:\\Utilities\\npwrap.exe %1Any comments/suggestions for improvement?
Win32/C: Notepad wrapper that automatically converts Unix line endings to Windows line endings
c;strings;windows;winapi
Architecture idea:Code reads the entire file into memory, coverts it and then conditionally  writes it out.ReadFile(hFile, bIn, dwLow, &dwRead, NULL);leResult = ConvertLineEndings(bIn, dwLow, bOut, dwLow*2, &nWritten);...SetFilePointer(hFile, 0, 0, FILE_BEGIN);WriteFile(hFile, bOut, nWritten, &dwWritten, NULL);Consider an alternative that does not delete the original until the new one is fully created.  This avoids losing the file should something go wrong.  An additional benefit is no real CPU memory limitation.open input for readingopen temp file output for writingWhile reading a line of the file  convert  append to outputclose inputclose output (temp file)rename input to temp file 2rename temp file to originaldelete temp file 2If a non-zero length file does not end with \r\n, this is a condition that often causes trouble for various text based programs.  Consider an option to insure a final \r\n.Robust code would check the result of file operations// Missing check of return values.ReadFile(hFile, bIn, dwLow, &dwRead, NULL);...SetFilePointer(hFile, 0, 0, FILE_BEGIN);WriteFile(hFile, bOut, nWritten, &dwWritten, NULL);CloseHandle(hFile);Note that \n\ris translated into \r\n\r\n - Unlikely a major concern.I found the excessive wide code unnecessarily challenging to follow.  Recommend to re- auto-format to the width of the presentation of this site.  CreateProcess(LC:\\Windows\\system32\\notepad.exe, wszArgQuote, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);vs.CreateProcess(LC:\\Windows\\system32\\notepad.exe, wszArgQuote, NULL, NULL, FALSE,    CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE,     NULL, NULL, &si, &pi);Minor: Consider using the size of the object, rather than the supposed type of the object.  Less chance for error and easier maintenance. // ZeroMemory(&si, sizeof(STARTUPINFO));ZeroMemory(&si, sizeof si);