Archive

Archive for the ‘MFC’ Category

MFC support for MBCS deprecated in Visual Studio 2013 and 2015

November 19, 2014 Leave a comment

Introduction

I’m writing this post to tell my readers that MFC support for MBCS is now deprecated. I’ve been reading several posts and internal emails within Microsoft. For customer’s who are deep rooted into MBCS, please wake up, start removing this piece from your codebase (so easy to say).

MFC support for MBCS is now Deprecated

MFC support for MBCS is now deprecated in Visual Studio 2013 and Visual Studio 2015. So eventually MBCS will be removed from the product entirely but (could be, maybe) could remain as a separate download. The term deprecation means gradually this thing will be removed. We normally start with warnings and then eventually we remove it. So now in 2013 is you build a project with MBCS support note that you’ll start to see a warning saying MFC support for MBCS is deprecated, time to move on. You can of course, as always, disable this warning using #define NO_WARN_MBCS_MFC_DEPRECATION.

Reasons why MFC support for MBCS is Deprecated

After reading blogs and comments the reasons that I could gather are as follows…

  • Research by Microsoft has shown that usage of MBCS by customer’s has significantly gone down.
  • Unicode is already popular and it can represent almost every language.
  • Native Windows API’s has been supporting Unicode interface for a long time now hence MFC will now be more aligned with the SDK as well, gets rid of the performance hits customer’s run into while using non-Unicode API’s. These API’s will eventually convert non-Unicode parameters to Unicode and then call corresponding Unicode version of this API, for e.g. GetWindowTextA will eventually call GetWindowTextW to get a window’s text.
  • Faster downloads. Reduced size of MFC libraries since these days Visual Studio is downloaded instead of being written onto a disk. MBCS libraries are now available as a separate download package. The size of the package is showing up as 64.3 MB. Doesn’t sound that huge though!

Why Would Somebody Still Require MFC Support for MBCS?

Few reasons that I could think off are as follows…

  1. Large codebase.
  2. Huge cost on testing code changes as the changes will be significant and impact will be huge as well. The benefits of this change to end customer is pretty trivial though.
    1. For him the application worked then and it will continue working.
    2. End customer will also might have do some heavy testing if they’re dependent on a library which removed MBCS support. So library vendors will have a pain there as well.
    3. Government customers will be affected as well as they have their own code validation process before accepting an application from a vendor.
  3. Reading in old data files or data from databases (?).
  4. Customer’s who have portable code cannot convert to UTF-16 just like that. They might have to eventually rewrite something just for Windows. Surprised smile

Workaround?

  • MBCS as of now will come as a separate download. See below screenshot…
    VS2015 download link
    MFC support for MBCS
  • Do not move to a newer version of Visual Studio which doesn’t support MBCS, that’s what I would do if I’m worried about about MBCS eventually not being supported by an IDE version.
  • Raise your voice, let it be heard.

References

MFC support for MBCS deprecated in Visual Studio 2013
Download Visual Studio 2015

Troubleshooting side by side issues using sxstrace

February 27, 2014 35 comments

What does Side by Side Mean?

Side by Side implementation allows binaries co-exist side by side even with identical names. Well internally the binaries are placed into different folders based on type, name, version, processorArchitecture and publickeytoken. All these elements make up a unique folder/file name. For developers all they need is to embed a manifest into their application which I guess most of you would know. Mostly side by side dependencies are specified via #pragma comment statements or Visual Studio creates a manifest file which is then embedded into the binary using mt.exe. Visual Studio creates a manifest file in the intermediate output folder which follows the following naming convention.

AppOutputFileName.exe.embed.manifest

How is a manifest embedded into an application?

If you build your application then you should see following line in the build output window…

1>Copyright (C) Microsoft Corporation. All rights reserved.
1>Linking...
1>Embedding manifest...

This file will be embedded into the binary as a resource of type RT_MANIFEST which is just an XML file. The OS application loader will pick up this file from the application’s resource section and will figure out application dependencies from the manifest entries.

Viewing Manifest file embedded into an executable file

Viewing Manifest file embedded into an executable file

What does Side by Side Solve?

The intention was to solve dll hell but this itself went on to become a bigger hell making bloggers like me to blog on this issue. Side by Side errors are hard to figure out hence there is a dedicated tool to help figure the errors out. Side by Side concept is cool but got screwed by the numerous ifs and buts that got into this technology.

How does a Side by Side error look like?

Side by side errors are troublesome to troubleshoot. You run an MFC/CRT application on customer machine and you run into error dialogs similar to the one shown below…

image

Don’t get overawed by the error. Its quite easy to troubleshoot, hmm well.

How to troubleshoot Side by Side errors using sxstrace?

As the error message suggests let use sxstrace.exe. The usage of sxstrace is pretty easy to understand…

C:\windows\system32>sxstrace
WinSxs Tracing Utility.
Usage: SxsTrace [Options]
Options:
   Trace -logfile:FileName [-nostop]
       Enabling tracing for sxs.
       Tracing log is saved to FileName.
       If -nostop is specified, will not prompt to stop tracing.
   Parse -logfile:FileName -outfile:ParsedFile  [-filter:AppName]
       Translate the raw trace file into a human readable format and save the re
sult to ParsedFile.
       Use -filter option to filter the output.
   Stoptrace
       Stop the trace if it is not stopped before.
Example:  SxsTrace Trace -logfile:SxsTrace.etl
          SxsTrace Parse -logfile:SxsTrace.etl -outfile:SxsTrace.txt
Collecting sxstrace logs

The command usage message shows us two sample commands and that’s exactly what we’re going to try. Please make sure you’re running an elevated command prompt…

Run the following command…

C:\>SxsTrace Trace -logfile:SxsTrace.etl
Tracing started. Trace will be saved to file SxsTrace.etl.
Press Enter to stop tracing...

So now you’re in tracing mode. Go ahead and run your application which threw the side by side error. Press enter on the command prompt window once you’re done repro’ing the error, this will stop the side by side tracing that’s going on. Once you press enter the ETL trace file will be dumped into the current folder. The dumped trace file is not in human readable format…

Binary output from SxsTrace tool

Binary output from SxsTrace tool

Parsing sxstrace logs

To make it readable, we’ll need to parse this file using sxstrace tool. Run following command to do that…

C:\>SxsTrace Parse -logfile:SxsTrace.etl -outfile:SxsTrace.txt
Parsing log file SxsTrace.etl...
Parsing finished! Output saved to file SxsTrace.txt.

So now we have a text file as output. Lets open the file and find out what went wrong… Contents are as follows…

Parsed output from sxstrace

Parsed output from sxstrace

I’ve annotated the above screenshot for your convenience.

Sample location of a side by side assembly

So basically side by side works based on version of a dll. All side by side binaries go in the winsxs folder located in C:\Windows. For e.g. on my machine msvcr90d.dll is located in the following folder…

Viewing a side by side assembly

Viewing a side by side assembly

If you noticed, the folder name is made up of version number as well. So dll’s belonging to different versions are put in unique folders hence they exists “side by side” hence the name “side by side”.

So the above error means the application couldn’t find msvcr90d.dll in the above location. The way I would solve this is to create a setup project in VC9 and install the merge modules onto the target machine. Please note the dll’s are debug binaries else you could have just installed the redist’s.

Hope this will help you.

[Debugging] How to find length of a CString string in application memory or in a dump

December 9, 2013 Leave a comment

Recently a colleague of mine asked where’s the length of CString string stored in memory. Hmm so lets dig around. Please note I’ve declared the following CString object in my code…

CString TestCString = _T("Nibu is testing CString");

If you dump CString type in the debugger we see following…

0:000> dt TestCString
Local var @ 0xb4fcd4 Type ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > >
   +0x000 m_pszData        : 0x00dfa2f8  "Nibu is testing CString"

From above dump of type CString we see that CString class defines just one variable: m_pszData. I don’t see a length variable here so where is the length stored for CString string?

Length of a CString string is stored at a negative offset from m_pszData. The data structure that resides at the negative offset is: ATL::CStringData

0:000> dt mfc100ud!ATL::CStringData
   +0x000 pStringMgr       : Ptr32 ATL::IAtlStringMgr
   +0x004 nDataLength      : Int4B
   +0x008 nAllocLength     : Int4B
   +0x00c nRefs            : Int4B

CStringData is retrieved via a call to function: GetData()

CStringData* GetData() const throw()
{
   return( reinterpret_cast<CStringData*>( m_pszData )-1);
}

The above code is bit of pointer arithmetic, first m_pszData is cast to a pointer to CStringData and then the casted type is deducted by –1 (which will equate to -sizeof(CStringData). So lets see while debugging if we can get to the CStringData located at a negative offset. First lets get the size of ATL::CStringData in memory.

0:045> ?? sizeof(ATL::CStringData)
unsigned int 0x10

Size of ATL::CStringData comes to 0x10 bytes. So in my test application lets find out what is located at a negative offset of 0x10 bytes. In my current frame I’ve the following locals. My CString object is called TestCString, highlighted in bold in the below code snippet.

0:000> dv
           this = 0x00ef6ba8
        cmdInfo = class CCommandLineInfo
       ttParams = class CMFCToolTipInfo
      InitCtrls = struct tagINITCOMMONCONTROLSEX
   pDocTemplate = 0xcccccccc
    TestCString = class ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > > 
     pMainFrame = 0xcccccccc

Deduction of 0x10 bytes from address of m_pszData (0x00dfa2f8) gives us the address: 00dfa2e8

0:000> ? 0x00dfa2f8-0x10
Evaluate expression: 14656232 = 00dfa2e8

Lets try dumping out CStringData located at the address: 00dfa2e8. See below

0:000> dt 00dfa2e8 TestStack!ATL::CStringData
   +0x000 pStringMgr       : 0x786cb8e4 ATL::IAtlStringMgr
   +0x004 nDataLength      : 0n23
   +0x008 nAllocLength     : 0n23
   +0x00c nRefs            : 0n1

Dump type says, length of string is: 0n23 which is correct. The length of string “Nibu is testing CString” is indeed 23.

Code documentation of CStringData says this about its member variables…

struct CStringData
{
    IAtlStringMgr* pStringMgr;  // String manager for this CStringData
    int nDataLength;  // Length of currently used data in XCHARs (not including terminating null)
    int nAllocLength;  // Length of allocated data in XCHARs (not including terminating null)
    long nRefs;     // Reference count: negative == locked
    // XCHAR data[nAllocLength+1]  // A CStringData is always followed in memory by the actual array of character data
}

Difference between nDataLength and nAllocLength is quite evident from the above documentation. Hope this helps.

[MFC Feature Pack] Select an MDI tab programmatically in a Document View application

October 23, 2013 Leave a comment

Why do you need to Select an MDI tab programmatically?

A customer recently asked this question on how to select an MDI tab programmatically, thought I’ll share the solution out here. When creating an MFC MDI application we have an option to enable tabbed view of MDI documents. Once this is done here’s how the resultant application will look like…

MFC MDI TabsMFC MDI Tab Groups

MFC MDI Tab Groups

Note that except for the first sample image you have multiple tab groups in the rest of the screenshots , this is a facility provided by the tabbing framework of MFC. This is important when you select an MDI tab programmatically: You’ll also have to decide which MDI tab from which group you would like to select.

Code to Select an MDI tab programmatically

In MFC framework tab groups are represented by CMDIClientAreaWnd::GetMDITabGroups() which returns a member variable of type CObList. This is how the code looks like…

const CObList& GetMDITabGroups() const { return m_lstTabbedGroups; }

This is a list of tab controls. Each tab control in this group denotes a tab group. So when activating a tab we’ll have to decide which tab in a tab group should be activated.

Following sample code activates the first tab in all the tab groups. Please note tab index starts at zero.

void CMainFrame::OnViewActivatetab()
{
    const CObList& TabGrps = m_wndClientArea.GetMDITabGroups();
    for (POSITION pos = TabGrps.GetHeadPosition(); pos != 0;)
    {
        CMFCTabCtrl* pNextWnd = DYNAMIC_DOWNCAST(CMFCTabCtrl, TabGrps.GetNext(pos));
        pNextWnd->ActivateMDITab(1);
    }
}

[MFC]Application migrated from VS2005 to VS2010 crashes on XP

October 16, 2013 Leave a comment

The crash happens as a result of requesting a non-existent API via GetProcAddress, the API is GetThreadPreferredUILanguages. GetProcAddress returns 0xFFBADD11 (a known issue with windows XP where GetProcAddress returns NON-NULL) which means LDRP_BAD_DLL.

To fix this issue override CWinApp::LoadAppLangResourceDLL and prevent loading of the lang dll or set the WINVER macro to target XP builds so that the code using the non-existent API is not compiled into the application (hope its wrapped in a #define).

[MFC] Resize CComboBox drop down list based on contents

October 7, 2013 Leave a comment

Code Snippet to Resize CComboBox Drop Down List

I had this post in my draft for a long time. This code snippet resizes a combo box’s drop down list. Please note an application sends the CB_SETDROPPEDWIDTH message to set the minimum allowable width, in pixels, of the list box of a combo box with the CBS_DROPDOWN or CBS_DROPDOWNLIST style.

Note: MFC function CComboBox::SetDroppedWidth is just a wrapper for CB_SETDROPPEDWIDTH.

// Fill out combo box with strings of random width, for demo purpose only
void FillCombo(CComboBox&amp; Combo)
{
	LPCTSTR lpAVeryLongString = _T("This is a very long string, the purpose of which is to test out width calculation of a combo drop down");
	TCHAR Buf[200] = {0};
 
	const int Len = _tcslen(lpAVeryLongString);
 
	Combo.Clear();
 
	for(int Index = 0; Index &lt; 100; ++Index)
	{
		const int TrimLen = rand() % Len;
		_stprintf_s(Buf, _T("%.*s"), TrimLen, lpAVeryLongString);
		Combo.AddString(Buf);
	}
}
 
// Resize combo box drop down width based on contents
void AutoAdjustComboWidth(CComboBox&amp; Combo)
{
	if(!Combo.GetSafeHwnd() || !::IsWindow(Combo.GetSafeHwnd()))
	{
		ASSERT(FALSE);
		return;
	}
 
	CDC&amp; ComboDC = *Combo.GetDC();
	const int RestorePoint = ComboDC.SaveDC();
	CFont&amp; ComboFont = *Combo.GetFont();
 
	ComboDC.SelectObject(&amp;ComboFont);
 
	int MaxX = -1;
 
	const UINT ItemCount = Combo.GetCount();
	for(UINT Index = 0; Index &lt; ItemCount; ++Index)
	{
		CString Text;
		Combo.GetLBText(Index, Text);
 
		// Get width of item string.
		const SIZE sz = ComboDC.GetTextExtent(Text);
 
		if(sz.cx &gt; MaxX)
		{
			MaxX = sz.cx;
		}
	}// End for
 
	if(MaxX &gt;  0)
	{
		const int ScrollWidth = ::GetSystemMetrics(SM_CXVSCROLL);
		const int Border = ::GetSystemMetrics(SM_CXEDGE) * 2;
		Combo.SetDroppedWidth(MaxX + ScrollWidth * 2);
	}
 
	ComboDC.RestoreDC(RestorePoint);
}

Some people might find this inconvenient as the list box width grows bigger. The way to workaround this issue is to use CComboBox::SetHorizontalExtent function as demonstrated here.

If you see bugs let me know,will fix those.

Using the good old SysLink/CLinkCtrl class

June 13, 2013 2 comments

What’s a SysLink/CLinkCtrl?

In MFC and in Win32 we have a dedicated control for managing/displaying hyperlinks, the control is pretty old(I guess the MFC feature pack has come up with a new control). In Win32 its called SysLink and in MFC the wrapper class is called CLinkCtrl.

Pain points of using SysLink/CLinkCtrl?

Using the control is pretty straight forward but in my opinion its usage is not well documented. There are several users who are struggling to find out a way to change the caption of a SysLink control. Of course we do have functions for setting URL (well its URLs) and retrieving it.

As most of us know one SysLink control can display multiple URLs. The control is aware of anchor tag: <a></a>. So it is able to parse out information from the anchor tag. Each URL has a unique index, we’ll have to use this index for setting/retrieving a URL.

Can SysLink/CLinkCtrl display multiple URL’s?

So how do we display multiple URL’s in a syslink/CLinkCtrl class. Here is a screenshot of how the syslink control looks…

SysLink/CLinkCtrl demo

We accomplished this via the following one line of code…

m_SysLinkCtrl.SetWindowTextW( _T("<a href=\"ntcoder.com\">First URL</a></pre>
<pre><a href=\"ntcoder.com/bab\">Second URL</a>"));

Note the spaces between URLs in the above call. You’ll see the same identical spaces in the caption of the control as well. Now ‘Nibu’ and ‘Rediff’ are two different URLs in the same control. Since we have mutliple URLs hence the control provides an index to access them. So at index 0 the URL will be http://ntcoder.com while at index 1 the URL will be http://ntcoder.com/bab.

How to handle events from SysLink/CLinkCtrl?

To handle clicks on the control we’ll have to provide a message map entry in MFC…

ON_NOTIFY(NM_CLICK, IDC_SYSLINK1, &CSysLinkDlg::OnNMClickSyslink1)

The notification details are stored in the structure NMLINK. The message handler function definition mostly looks like this…

void CSysLinkDlg::OnNMClickSyslink1(NMHDR *pNMHDR, LRESULT *pResult)
{
    PNMLINK pClick = (PNMLINK)pNMHDR;
    MessageBox(pClick->item.szUrl, _T("You clicked on...";), MB_ICONINFORMATION);

    *pResult = 0;
}

Now when we click on the URLs in the control, this is what we get…

Clicking SysLink/CLinkCtrl Clicking SysLink/CLinkCtrl

 

How to modify captions and URL’s in a SysLink/CLinkCtrl?

Both URLs have separate focus rectangles as well! The only way (from what I’ve found so far) to change the text of the control is call SetWindowText again but of course you can change the URL by calling CLinkCtrl::SetItemUrl. Few examples on changing URL’s…

m_SysLinkCtrl.SetItemUrl(0, _T("<a href="http://www.msn.com">http://www.msn.com</a>"));
m_SysLinkCtrl.SetItemUrl(1, _T(<a href="http://www.hotmail.com">http://www.hotmail.com</a>));

So the next time you click on the URLs in the control this is what we get…

Clicking SysLink/CLinkCtrl Clicking SysLink/CLinkCtrl

You can also provide ids to these URL’s, these can be done via m_SysLinkCtrl.SetItemID(0, _T(“Custom ID”));. These ids can retrieved via m_SysLInkCtrl.GetItemID.

Some issues when working with ComboBox

August 11, 2009 2 comments

The main reason for posting this issue is to help MFC/Win32 beginners. But anyway it’s a good read ;), so once upon a time…

If you’re a beginner with window’s ComboBox controls then you might end up with a bald head thinking and thinking about a weird behavior of combo’s after it’s creation. The combo as such is a great control but there are certain important things to keep in mind while creating a combo.

So what are the problems? Well make it singular, “Problem”. One and the only problem with this control is shown in this screenshot…

Drop down not visible

Drop down not visible

I’ve clicked the drop down arrow but cannot see the dropdown. This one is created via resource editor. The problem here is, just adding a combo is not enough but we’ve also got to set the size of the drop down via resource editor. So follow these steps, as shown in the screen shot to fix this issue…

Resizing a combo drop down

Resizing a combo drop down

So that’s it. The white drag rectangle denotes combo drop down size. Press Ctrl + T to test this. Please note that this is not a bug but a feature of resource editor since there isn’t an another way to set drop down size for a combo via resource editor. But I agree that they should’ve set a better default drop down size instead of a zero height drop down.

Now this was via resource editor. It’s bit different when creating dynamically via code using CComboBox::Create function. Note that you have to give a valid height value. This height value will be the dropdown size for this combo.

See this e.g.

m_Combo.Create( WS_VISIBLE | WS_TABSTOP | WS_BORDER | CBS_DROPDOWNLIST | CBS_SORT,
                CRect( 10, 10, 200, 300 ),
                this,
                IDC_COMBO1 + 1 );
m_Combo.SetFont( GetFont(), TRUE );

Hope you’ve noticed the last big value given to Combo via CRect, 300. That’s the drop down height. Normally beginners set it to 30 or 40 which results in this issue.

See the resultant screenshot…

Result of properly creating a combo

Result of properly creating a combo

Not a big deal for experts but for beginners, well I’ve been a beginner too, it’s one painful issue. 🙂

Add horizontal scrollbar to a combo box

May 28, 2009 4 comments

CComboBox has a function called SetHorizontalExtent which doesn’t work. SDK equivalent is CB_SETHORIZONTALEXTENT which also doesn’t work. The reason for this bug is pretty lame, because WS_HSCROLL style for combo box is not set, which in turn the VS dialog editor does not provide :(. So a workaround is to open .rc file in a text editor and add WS_HSCROLL style manually for this combo.

This is how a combo box will look with a horizontal scrollbar…

Horizontal scrollbar in a combo box

Horizontal scrollbar in a combo box

Here is a sample code from MSDN which is adapted a bit for this purpose…

void CDialoTestDlg::AddHScroll( CComboBox& Cmb )
{
  // Find the longest string in the combo box.
  CString str;
  CSize sz;
  int dx = 0;

  TEXTMETRIC tm = { 0 };
  CDC* pDC = Cmb.GetDC();
  CFont* pFont = Cmb.GetFont();

  // Select the listbox font, save the old font
  CFont* pOldFont = pDC->SelectObject(pFont);

  // Get the text metrics for avg char width
  pDC->GetTextMetrics(&tm);

  for (int i = 0; i < Cmb.GetCount(); i++)
  {
    Cmb.GetLBText(i, str);
    sz = pDC->GetTextExtent(str);

    // Add the avg width to prevent clipping
    sz.cx += tm.tmAveCharWidth;

    if (sz.cx > dx)
      dx = sz.cx;
  }

  // Select the old font back into the DC
  pDC->SelectObject(pOldFont);
  Cmb.ReleaseDC(pDC);

  // Set the horizontal extent so every character of all strings can
  // be scrolled to.
  Cmb.SetHorizontalExtent(dx);
}// End AddHScroll

Setting horizontal extent is useful to prevent the combo’s drop down width from extending beyond screen limits. Note that there is another function called SetDroppedWidth which sets the drop down’s width but with no scrolling.

Where can I find MFC feature pack samples?

May 5, 2009 5 comments

People are having trouble finding feature pack samples installed in the samples directory. I too had a similar problem. So what you need to do is to uninstall the previous sample exe that you’ve installed. Then install the samples from here. Good thing about this is that you’ll have an updated samples package.

If you’re still having problems, I’ve uploaded them for you to my blog, please rename this file to zip after downloading or save as zip.