Home‎ > ‎Windows programming‎ > ‎

Miscellaneous functions

Executing code for all exceptions

The try-catch(...) thing only catches some non-serious exceptions. E.g. it does not catch division by zero errors. Under windows, to be able to react on all exceptions, SEH (structured exception handling) is to be used. This has been tested on wince 6, but I guess this should work on all Windows.

int mycleanupfunc()
{
    // cleanup
    exit(-1);
}

int _tmain(int argc, _TCHAR* argv[])
{
    __try
    {
        // do your stuff. If anything goes wrong that would lead to a crash,
        // mycleanupfunc() will be called
    }
    __except(mycleanupfunc())
    {
    }
}


For mass file operations (like copy dirs recursively etc) see this API

SHFileOperation (http://msdn.microsoft.com/en-us/library/bb762164%28v=VS.85%29.aspx)

Traverse directory recursively

// Declaration:

typedef void (TraverseFS_CB)(std::wstring dirname);
static void TraverseFS(std::wstring path, TraverseFS_CB* fileCB, TraverseFS_CB* enteringDirCB, TraverseFS_CB* leavingDirCB);

//Implementation:

void CUtils::TraverseFS(std::wstring path, TraverseFS_CB* fileCB, TraverseFS_CB* enteringDirCB, TraverseFS_CB* leavingDirCB)
{
    HANDLE hFind;

    try
    {
        if (path.size() < 2)
        {
            throw std::exception("CUtils::TraverseFS invalid path, less than 2 characters long");
        }
        int pos = path.find_last_of(L'\\');
        int size = path.size();
        if (pos != size - 1)
        {
            throw std::exception("CUtils::TraverseFS no trailing slash after path");
        }
       
        BOOL bContinue = TRUE;

        std::wstring curDirPath = path + L"*.*"; // Build current path

        WIN32_FIND_DATA data;
        hFind = FindFirstFile(curDirPath.c_str(), &data);
        if (INVALID_HANDLE_VALUE == hFind)
        {
            throw std::exception("FindFirstFile returned invalid handle");
           
        }

        // If we have no error, loop thru the files in this dir
        while (hFind && bContinue)
        {
            // Check if this entry is a directory
            if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
            {
                // Make sure this dir is not . or ..
                if (std::wstring(data.cFileName) != L"." &&
                    std::wstring(data.cFileName) != L"..")
                {
                   
                    std::wstring newDirPath = path + data.cFileName + L"\\";
                    if (enteringDirCB)
                    {
                        enteringDirCB(newDirPath);
                    }
                    TraverseFS(newDirPath, fileCB, enteringDirCB, leavingDirCB); // Recurse into the function
                    if (leavingDirCB)
                    {
                        leavingDirCB(newDirPath);
                    }
                }
            }
            else
            {
                if (fileCB)
                {
                    fileCB(path + data.cFileName);
                }
            }
            bContinue = FindNextFile(hFind, &data);
        }   
        FindClose(hFind); // Free the dir structure
    }
    catch(...)
    {
        FindClose(hFind);
        throw;
    }
}


Debugger break

Same as Debugger.Launch() in C#
__asm int 3;

Make and unmake a window "always on top"

void MemberFuncOfAnyDlg(bool bAlwaysOnTop)
{
    if (bAlwaysOnTop)
    {
        SetWindowPos(&wndTopMost, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
    }
    else
    {
        SetWindowPos(&wndBottom, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
        SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
    }
}

Capture screen-shot and save it into a jpg file

bool CaptureScreenshot(HWND hwnd, CString sBmpFile)
{
    HDC WinDC;
    HDC CopyDC;
    HBITMAP hBitmap;
    ULONG bWidth, bHeight;
   
    // Use either NULL for the screen or hwnd for a window
    WinDC = GetDC (hwnd);
    CopyDC = CreateCompatibleDC (WinDC);
   
    bWidth =  GetDeviceCaps(WinDC, HORZRES);
    bHeight = GetDeviceCaps(WinDC, VERTRES);
   
    hBitmap = CreateCompatibleBitmap (WinDC, bWidth, bHeight);
   
    SelectObject (CopyDC, hBitmap);
               
    BitBlt (CopyDC,
        0,0,
        bWidth, bHeight,
        WinDC,
        0, 0,
        SRCCOPY);
               

    // This bitmap is temporary and does not need to be deleted.
    // It is valid in the context of 1 windows event. See MSDN
    // for more.
    CBitmap* bitmap = CBitmap::FromHandle(hBitmap);

    CImage image;
    image.Attach(*bitmap);
    image.Save(sBmpFile, Gdiplus::Gdiplus::ImageFormatJPEG);

    ReleaseDC(NULL, WinDC);
    DeleteDC(CopyDC);

    return true;
}

MFC code that wraps text 

An MFC code that performs the wrapping of text.  sTxtIn is the input string, maxX and cdc specify the maximum width of the text. sTxtWrapped will contain the lines of the wrpped text.

void WrapText(CString sTxtIn,
                                const unsigned int maxX,
                                const CDC* cdc,
                                std::vector<CString>& sTxtWrapped,
                                unsigned int& maxWidth)
{
    sTxtWrapped.clear();

    TCHAR* pLastBreak = sTxtIn.GetBuffer(0);
    TCHAR* pNextBreak = NULL;

    TCHAR* pCurrPtr = pLastBreak;
    while(true)
    {
        if (*pCurrPtr == 0)
        {
            CString line(pLastBreak, (int)((pCurrPtr)-pLastBreak));
            line.Replace("\n", "");
            sTxtWrapped.push_back(line);
            break;
        }

        if (*pCurrPtr == ' ' || *pCurrPtr == '\n')
        {
            if (cdc->GetTextExtent(pLastBreak, (int)(pCurrPtr-pLastBreak)).cx > (int)maxX)
            {
                // simple line break case
                if (pNextBreak)
                {
                    CString line(pLastBreak, (int)(pNextBreak-pLastBreak));
                    line.Replace("\n", "");
                    sTxtWrapped.push_back(line);
                    pLastBreak = pNextBreak + 1;
                    pCurrPtr = pLastBreak;
                    pNextBreak = NULL;
                }
                else
                {
                    // too long text with no space case
                    while(true)
                    {
                        int tempi =  (int)(pCurrPtr-pLastBreak);
                        CString temps;
                        temps.Append(pLastBreak, tempi);

                        pCurrPtr--;
                        if (cdc->GetTextExtent(pLastBreak, (int)(pCurrPtr-pLastBreak)).cx <= (int)maxX)
                        {
                            CString line(pLastBreak, (int)((pCurrPtr)-pLastBreak));
                            line.Replace("\n", "");
                            sTxtWrapped.push_back(line);
                            pLastBreak = pCurrPtr + 1;
                            pCurrPtr = pLastBreak;
                            pNextBreak = NULL;
                            break;
                        }
                    }
                }
            }
            // line break in string case
            else if (*pCurrPtr == '\n')
            {
                CString line(pLastBreak, (int)((pCurrPtr)-pLastBreak));
                line.Replace("\n", "");
                sTxtWrapped.push_back(line);
                pLastBreak = pCurrPtr;
                pCurrPtr = pLastBreak;
                pNextBreak = NULL;
            }
            // string is not long enough to break at this space, but
            // let's remember the last space position, probably the next space is
            // over the limit
            else
            {
                pNextBreak = pCurrPtr;
            }
        }
        pCurrPtr++;
    }
    maxWidth = 0;
    CString strToCheck;
    for (unsigned int i=0; i<sTxtWrapped.size(); i++)
    {
        unsigned int w;
        if (( w = cdc->GetTextExtent(sTxtWrapped[i]).cx) > maxWidth)
            maxWidth = w;

        strToCheck += sTxtWrapped[i];
    }
    strToCheck.Replace("\n", "");
    sTxtIn.Replace("\n", "");
    strToCheck.Replace(" ", "");
    sTxtIn.Replace(" ", "");

    ASSERT(sTxtIn==strToCheck);

}

Browse for folder dialog

CString ShowBrowseForFolderDlg(HWND ownerWnd)
{
    CString strTitle("Select a Folder");
    CString strDisplayName;
   
    BROWSEINFO bi;

    bi.hwndOwner      = ownerWnd; // Handle of the owner window
    bi.pidlRoot       = NULL;     // Desktop folder is used
    bi.lpszTitle      = strTitle.GetString(); // Title of the dialog box
    bi.pszDisplayName = strDisplayName.GetBuffer(MAX_PATH); // Buffer for selected
                                                            // folder name
    bi.ulFlags        = BIF_RETURNONLYFSDIRS|BIF_RETURNFSANCESTORS; // Only returns
                                                                    // directories
    bi.lpfn           = NULL;
    bi.lParam         = 0;

    LPITEMIDLIST pItemIDList = SHBrowseForFolder(&bi);
    strDisplayName.ReleaseBuffer();

    CString sPath;

    if (pItemIDList)
    {
        if (!SHGetPathFromIDList(pItemIDList, sPath.GetBuffer(MAX_PATH)))
        {
           TRACE("Failed to call SHGetPathFromIDList()");
        }

        // Avoid memory leaks by deleting the PIDL using the shell's task allocator
        IMalloc* pMalloc = NULL;
        if (SHGetMalloc(&pMalloc) != NOERROR)
        {
            TRACE("Failed to get pointer to shells task allocator");
            return "";
        }
       
        pMalloc->Free(pItemIDList);
        if (pMalloc)
            pMalloc->Release();
    }

    sPath.ReleaseBuffer();
    return sPath;
}

Split CString

Use Tokenize() instead!!

Get info about a binary file

bool GetBinaryFileInfo(std::wstring sFilePath, std::wstring& companyName, std::wstring& versionInfo)
{
    char* rcData = NULL;

    try
    {
        LPDWORD handle = 0;
        DWORD dwSize;
        dwSize = ::GetFileVersionInfoSize(const_cast<wchar_t*>(sFilePath.c_str()), handle);
        if(!dwSize)
            throw 1;
   
        rcData = new char[dwSize];
        // get valid resource data using path, handle, and size
        if ( ! ::GetFileVersionInfo(const_cast<wchar_t*>(sFilePath.c_str()), 0, dwSize, (LPVOID)rcData))
        {
            throw 1;
        }

        // get all the language info
        // langCodePage[0] is Language, langCodePage[1] is CodePage
        WORD* langCodePage = NULL;
        UINT langCodePageSize = 0;
        if (! ::VerQueryValue(rcData, TEXT("\\VarFileInfo\\Translation"),
                                    (LPVOID*)&langCodePage, &langCodePageSize))
        {
            throw 1;
        }

        // get the language id that matches the situation the best
        // lets see if we have what GetUserDefaultLangID() returns
        // if we don't, we'll just use the first one in the array
        DWORD dwLangCode = 0;
        LANGID langId = GetUserDefaultLangID();
        for (LPWORD lpwData = langCodePage; lpwData < langCodePage+langCodePageSize; lpwData+=2)
        {
            if (*lpwData == langId)
            {
                dwLangCode = *((DWORD*)lpwData);
                break;
            }
        }
        // the default is not found, so let's pick the first one
        if (dwLangCode == 0)
        {
            dwLangCode = *((DWORD*)langCodePage);
        }

        // Get the info with the selected language Id
        LPVOID lpInfo = NULL;
        UINT unInfoLen = 0;

        // and example for the string here would be "\\StringFileInfo\\00000000\\"
        std::wstringstream strSubBlock;
        strSubBlock << L"\\StringFileInfo\\" << std::setw( 4 ) << std::setfill( L'0' ) << std::hex << (dwLangCode&0x0000FFFF)
                     << std::setw( 4 ) << std::setfill( L'0' ) << std::hex << ((dwLangCode&0xFFFF0000)>>16) << L"\\";

        std::wstring sTmp;
        sTmp = strSubBlock.str() + L"CompanyName";
        if (::VerQueryValue(rcData, (LPWSTR)sTmp.c_str(), &lpInfo, &unInfoLen))
        {
              companyName = std::wstring((LPCTSTR)lpInfo);
        }

        sTmp = strSubBlock.str() + L"FileVersion";
        if (::VerQueryValue(rcData, (LPTSTR)(LPCTSTR)(sTmp.c_str()), &lpInfo, &unInfoLen))
        {
            versionInfo = std::wstring((LPCTSTR)lpInfo);
        }   
    }
    catch(...)
    {
        delete []rcData;
        return false;
    }

    delete []rcData;
    return true;
}

Add console output messages to Dialog based apps 

// This only works on XP and later so change the version defines in the stdafx.h accordingly

        FILE *fp1 = NULL;
        if (AttachConsole(ATTACH_PARENT_PROCESS))
        {
            // redirect unbuffered STDOUT to the console
            intptr_t iStdHandle = (intptr_t)GetStdHandle(STD_OUTPUT_HANDLE);

            int hConHandle = _open_osfhandle(iStdHandle, _O_TEXT);
            fp1 = _fdopen( hConHandle, "w" );
            *stdout = *fp1;
            setvbuf( stdout, NULL, _IONBF, 0 );

            // redirect unbuffered STDIN to the console
            //iStdHandle = (intptr_t)GetStdHandle(STD_INPUT_HANDLE);
            //hConHandle = _open_osfhandle(iStdHandle, _O_TEXT);
            //fp2 = _fdopen( hConHandle, "r" );
            //*stdin = *fp2;
            //setvbuf( stdin, NULL, _IONBF, 0 );

            std::cout << "Executing..." << std::endl;
        }
        else
        {
            //AfxMessageBox("could not attach to console");
        }


        // Do your stuff here e.g. display your dialog or anything else

        std::cout << "Done." << std::endl;

        if (fp1)
        {
            fclose(fp1);
            //fclose(fp2);
            _fcloseall();
            FreeConsole();
        }


Simple windows message loop
I had the need to simulate a modal dialog. A dialog was displayed by a 3rd party dll that did not fill the owner window properly therefore messages (even paint messages) did not reach the main window of my application. My solution was to show that dialog from a background thread and while the dialog was shown I executed my own message loop. Below is this message loop.

 
   while (bDialogDisplayed)
    {
        MSG msg;
        if (activeWnd && PeekMessage(&msg, activeWnd->GetSafeHwnd(), 0, 0, PM_NOREMOVE) != 0)
        {
            GetMessage(&msg, activeWnd->GetSafeHwnd(), 0, 0);

            // we ignore non-paint messages
            if (msg.message == WM_NCPAINT ||
                msg.message == WM_PAINT)
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
            if (::GetForegroundWindow() == activeWnd->GetSafeHwnd())
            {
                ::SetForegroundWindow(hwndDialog);
            }
        }
    }


Get path of currently running executable

TCHAR buf[MAX_PATH];
memset(buf, 0, MAX_PATH*sizeof(TCHAR));

GetModuleFileName(GetModuleHandle(NULL), buf, MAX_PATH);

CreateProcess example

DWORD RunCommand(const std::wstring& sCommand, const std::wstring& sWorkingDir)
{
    DWORD exitCode = -1;
 
    STARTUPINFO si;
    memset(&si, 0, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
 
    PROCESS_INFORMATION pi;
    memset(&pi, 0, sizeof(PROCESS_INFORMATION));
     
    if (::CreateProcess(NULL,
                        const_cast<wchar_t*>(sCommand.c_str()),
                        NULL,
                        NULL,
                        TRUE,
                        NULL,
                        NULL,
                        sWorkingDir.c_str(),
                        &si,
                        &pi) == FALSE)
    {
        DWORD err = GetLastError();
 
        std::wstringstream strm;
        strm << L"ERROR! RunCommand failed: " << sCommand << L" GetLastError() returned: " << err;
        Log(strm.str());
 
        return err;
    }
 
    WaitForSingleObject(pi.hProcess, INFINITE);
 
     
    if (GetExitCodeProcess(pi.hProcess, &exitCode) == FALSE)
    {
        DWORD err = GetLastError();
 
        std::wstringstream strm;
        strm << L"ERROR! GetExitCodeProcess failed: " << sCommand << L" GetLastError() returned: " << err;
        Log(strm.str());
 
        // Failed to get real exit code
        exitCode = err;
    }
 
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
    return exitCode;
}


Win32 Process functions

class AutoHandle
{
public:
    AutoHandle(HANDLE h)
    {
        m_h = h;
    }

    ~AutoHandle()
    {
        Close();
    }

    HANDLE Get()
    {
        return m_h;
    }
    void Close()
    {
        if (m_h != NULL)
        {
            ::CloseHandle(m_h);
            m_h = NULL;
        }
    }
private:
    HANDLE m_h;
};

int FindProcessIds(std::wstring processName, std::vector<DWORD>& processIds)
{
    processIds.clear();

    DWORD aProcesses[1024], cbNeeded, cProcesses;
    if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
        return GetLastError();

    // Calculate how many process identifiers were returned.
    cProcesses = cbNeeded / sizeof(DWORD);

    for (unsigned int i = 0; i < cProcesses; i++ )
    {
        if( aProcesses[i] == 0 )
            continue;

        TCHAR szProcessName[MAX_PATH];
        memset(szProcessName, 0, sizeof(TCHAR)*MAX_PATH);

        // Get a handle to the process.
        AutoHandle procHandle(OpenProcess( PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE, aProcesses[i] ));
        if (procHandle.Get() == NULL)
        {
            // log error?
            continue;
        }

        // Get the process name.
   
        HMODULE hMod;
        DWORD cbNeeded;

        if ( EnumProcessModules( procHandle.Get(), &hMod, sizeof(hMod),
             &cbNeeded) )
        {
            GetModuleBaseName( procHandle.Get(), hMod, szProcessName,
                               sizeof(szProcessName)/sizeof(TCHAR) );
        }

        std::wstring enumProcName(szProcessName);

        if (enumProcName == processName)
        {
            processIds.push_back(aProcesses[i]);
        }
    }
    return 0;
}

int KillProcess( DWORD procId )
{
    AutoHandle killProcHandle(OpenProcess( PROCESS_TERMINATE, FALSE, procId ));
    if (killProcHandle.Get() == NULL)
    {
        int ret = GetLastError();
        std::wstringstream strm;
        strm << L"CUtils::KillProcess - Open process returned NULL. GetLastError() returns: " << ret;
        Log(strm.str());
        return ret;
    }

    if (TerminateProcess(killProcHandle.Get(), -1) == FALSE)
    {
        Log(L"Process was NOT killed successfully");
        return GetLastError();
    }
    else
    {
        Log(L"Process was killed successfully");
    }

    return 0;
}

int IsModuleLoadedIntoProcess( DWORD procId, const std::wstring& moduleName, bool& bLoaded )
{
    bLoaded = false;

    // Get a handle to the process.
    AutoHandle procHandle(OpenProcess( PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE, procId));
    if (procHandle.Get() == NULL)
    {
        int ret = GetLastError();
        std::wstringstream strm;
        strm << L"CUtils::IsModuleLoadedIntoProcess - Open process returned NULL. GetLastError() returns: " << ret;
        Log(strm.str());
        return ret;
    }

    HMODULE hMod[4096];
    memset(hMod, 0, sizeof(HMODULE)*MAX_PATH);

    DWORD cbNeeded;
    if ( !EnumProcessModules( procHandle.Get(), hMod, sizeof(HMODULE) * 1024, &cbNeeded) )
    {
        int ret = GetLastError();
        std::wstringstream strm;
        strm << L"CUtils::IsModuleLoadedIntoProcess - EnumProcessModules returned false. GetLastError() returns: " << ret;
        Log(strm.str());
        return ret;
    }

    TCHAR szModuleName[MAX_PATH];
    memset(szModuleName, 0, sizeof(TCHAR)*MAX_PATH);

    int modCnt = cbNeeded/sizeof(HMODULE);

    for (int i=0; i<modCnt; ++i)
    {
        GetModuleBaseName( procHandle.Get(), hMod[i], szModuleName,
                           sizeof(szModuleName)/sizeof(TCHAR) );

        if (std::wstring(szModuleName).find(moduleName) != std::wstring::npos)
        {
            bLoaded = true;
        }
    }

    return 0;
}

Comments