MFC COOKBOOK@klopix
GUIResearch


MFC stands for Microsoft Foundation Classes.


Keywords: GUI, controls, interaction, resize, dialog.


Feb 24 2010
How to prevent launching a second app instance

Warning! This will work only if app isn't minimized to tray. However, you may apply a genius solution based on Mutex.


In CYourApp::InitInstance() call EnumWindows(static_member_func_pointer, (LPARAM)this) and if it returns FALSE, then quit the app, because another instance is already running.

class CYourApp
{
private:
	// - Prevent from launching second instance of the app
	CString	m_str_title;
	HWND	m_hwnd_double;
public:
	static BOOL CALLBACK wnd_comparator(HWND hwnd, LPARAM lParam);
...
};


BOOL CYourApp::InitInstance()
{
	...
	// - Prevent from second instance of the app
	m_str_title = CRegistry::Ref().AppTitle();
	if (!EnumWindows(&CTEXTApp::wnd_comparator, (LPARAM)this))
	{
		::SetForegroundWindow(m_hwnd_double);
		return FALSE;
	}
	...
}

BOOL CALLBACK CYourApp::wnd_comparator(HWND hwnd, LPARAM lParam)
{
	CYourApp* pThis = reinterpret_cast(lParam);

	CString strTitle;
	CWnd::FromHandle(hwnd)->GetWindowText(strTitle);

	if (strTitle.Find(pThis->m_str_title) >= 0)
	{
		pThis->m_hwnd_double = hwnd;
		return FALSE; //- Found existing instance. Quit searching loop.
	}
	
	return TRUE; // - Continue enumerating.
}

Feb 24 2010
MFC SDI app custom name

Here is how you re-name app. In application's constructor you release previous string value and allocate a new one:

if (m_pszAppName)
{
	free((void*)m_pszAppName);
}
m_pszAppName = _tcsdup(_T("Whatever it is you like -- put it here"));

Oct 16 2009
ASSERT macros

ASSERT() is tricky: it's useful, but incorrect usage may cause painful debugging. To avoid any problems a single fact about ASSERT() must be known: in RELEASE version of an application all the code inside it is CUT OUT. So, if you put a function call into the macros to make sure it has completed successfully, in release version you'll get this function call CUT OUT. There won't be a call to function. We wanted to check that the function worked well, but instead we got our code cut out.

So, don't put any crucial code into the macros (like call to a function) because in release version you'll get it cut out.

Feb 6 2009
Shaping and skinning

- A google group for MFC.

- Region based shaping (very simple and cool) - flipcode.

- WinAmp skin technique http://www.codeproject.com/KB/dialog/winampwnd.aspx

Dialog shaping digest

Here is a little digest (scenario) of how to shape dialog in a cute way:

Feb 5 2009
 

Progress bar upon a status bar

Codeguru's recipe.

Status bar (originally by Nish)

1. Right-click upon app-resource.rc;
2. choose Resource symbols;
3. add several ids like ID_INDICATOR_XXX;
4. add dialog's member "CStatusBar m_bar";
5. add the following array into dialog's cpp file:

   #define STATUS_BAR_SECTIONS 2
   static UINT BASED_CODE indicators[STATUS_BAR_SECTIONS] =
   {
       ID_INDICATOR_TXT,
       ID_INDICATOR_PROGRESSBAR
   };

6. into OnInitDialog add this:

   m_status_bar.Create(this);
   m_status_bar.SetIndicators(indicators, STATUS_BAR_SECTIONS);

   CRect rect;
   GetClientRect(&rect);

   m_bar.SetPaneInfo(0, ID_INDICATOR_TXT, SBPS_NORMAL, 100);      
   m_bar.SetPaneInfo(1, ID_INDICATOR_PROGRESSBAR, SBPS_STRETCH, 0);

   RepositionBars(
	AFX_IDW_CONTROLBAR_FIRST,
	AFX_IDW_CONTROLBAR_LAST,
	ID_INDICATOR_PROGRESSBAR);

   m_status_bar.SetPaneText(0, _T("Ready"));

Feb 3 2009
 

COM import libid attributes

#pragma warning(push)
#pragma warning(disable : 4192)
//IConvertImage 
#import "libid:B6D80AF6-B6D4-411A-BFD6-77C1613F511F" named_guids no_namespace raw_interfaces_only
#pragma warning(pop)

Browse folder API

bool CFileSystem::BrowseFolderDlg(CString& strFolder, UINT nStrID/*=0*/)
{
    CString strTitle;
    if (nStrID == 0) strTitle = _T("");
    else strTitle.LoadString(nStrID);

    TCHAR path[MAX_PATH];
    BROWSEINFO bi = { 0 };
    bi.lpszTitle = strTitle;
    LPITEMIDLIST pidl = SHBrowseForFolder ( &bi );

    if ( pidl != 0 )
    {
        SHGetPathFromIDList ( pidl, path );
        //SetCurrentDirectory ( path );
        //SearchFolder( path );
        IMalloc * imalloc = 0;
        if ( SUCCEEDED( SHGetMalloc ( &imalloc )) )
        {
            imalloc->Free ( pidl );
            imalloc->Release ( );
        }

	strFolder.SetString(path);
	return strFolder.Trim().IsEmpty()? false: true;
    }

    return false;
}

Get list of folder's files

void CFileSystem::AllFilesFromFolder(CStringArray& rlstFiles, CString& strPath, CString strWildMask)
{
    WIN32_FIND_DATA FindFileData;     
    HANDLE hFind;
    CString str;

    rlstFiles.RemoveAll();
    SetCurrentDirectory(strPath);
    hFind = FindFirstFile(strWildMask, &FindFileData);

    do     
    {         
        if (INVALID_HANDLE_VALUE != hFind)
        {             
            //Is it a . or .. directory? If it is, skip, or we'll go forever.             
            if (!(wcscmp(FindFileData.cFileName, _T(".")))
	    || !(wcscmp(FindFileData.cFileName, _T(".."))))
		continue;             
         
	    str.SetString(FindFileData.cFileName);
	    if(str.Trim().IsEmpty()) continue;

	    rlstFiles.Add(strPath + _T("\\") + str);
        }     
    }    
    while (FindNextFile(hFind, &FindFileData) && INVALID_HANDLE_VALUE!=hFind);
    FindClose(hFind);
}

Jan 26 2009
 

CFileDialog's bullshit

CString filter(_T("Wave (*.wav)|*.wav||"));

CFileDialog dlg(
	TRUE, _T("wav"), _T(""),
	OFN_FILEMUSTEXIST, filter, this, sizeof(OPENFILENAME));
dlg.m_ofn.lpstrTitle = _T("Choosing an input wave file");

if (dlg.DoModal() == IDOK) {
	CString str = dlg.GetPathName().Trim();
	m_str_input.SetWindowText(str);
}

Ivan Yurlagin,