How to convert a ANSI/MB project into a UNICODE

14 05 2013

Most of the time we may need to give multiple language support for our applications. Incase if we need to support Russian or Chinese language means, definitely we have to give Unicode support for our application. So here I would like to share some tips for converting existing ANSI/MultiByte project into Unicode.

If we build our project in Multi-byte character set it will allocate 1 byte for one character. This is enough for representing all English letters. But if we build our project in Unicode character set it will allocate 2 bytes for each letters. It is required for representing Russian and Chinese letters.

Below are some suggestions for converting MBCS to Unicode project

Step 1: Create new configuration from Project Configuration Manager. Give name something like ReleaseUnicode/DebugUnicode.

Step 2: Change Character Set to Unicode from Project Settings.

Unicode

Step 3: Replace all char datatype with TCHAR. This will automatically switch to normal char or wchar_t based on it is compiled as MBCS or Unicode respectively.

Step 4: Add _T as prefix to each string text. eg: _T(“Hello World”)

Step 5: Replace LPSTR and LPCSTR with LPTSTR and LPCTSTR respectively.

Step 6: Replace following win32 APIs with corresponding Generic equivalent for same.

ANSI/MB API Generic API
strstr _tcsstr
strcmp _tcscmp
sprintf_s _stprintf_s
strlen _tcslen
_stricmp _tcscmp
strcpy_s _tcscpy_s
atol _tstol
atoi _tstoi
atof _tstof
strcspn _tcscspn
fopen_s tfopen_s
strtok_s _tcstok_s
strtol _tcstol
strtoul _tcstoul
Advertisements




How to read INI files

8 05 2013

INI files(.INI) are simple text files with a basic structure composed of sections and properties and which is used for some configuration settings. Till Microsoft introduced registry, the INI file served as the primary mechanism to configure operating system features. Even if it is obsolete, developers may still need to use it.

Windows provides APIs for reading and writing settings from classic Windows .ini files. The following APIs are available for reading data from INI files.
GetPrivateProfileInt
GetPrivateProfileSection
GetPrivateProfileSectionNames
GetPrivateProfileString
GetPrivateProfileStruct
GetProfileInt
GetProfileSection
GetProfileString

INIReader.h

class CINIReader
{

public:
CINIReader()
{
    m_pSectionList = new CStringList();
    m_pSectionDataList = new CStringList();
}

~CINIReader()
{
    delete m_pSectionList;
    delete m_pSectionDataList;
}

    void SetInfFileName(CString p_strInfFileName);
    BOOL IsValidSection(CString p_strSectionName);
    CStringList* GetSectionNames()
    CStringList* GetSectionData(CString p_lpSectionName);

private:
    CString m_strInfFileName;
    CStringList* m_pSectionList;
    CStringList* m_pSectionDataList;	    
};

INIReader.cpp

void CINIReader::SetInfFileName(CString p_strInfFileName)
{
m_strInfFileName = p_strInfFileName;
}

BOOL CINIReader::IsValidSection(CString p_strSectionName)
{
BOOL bReturnValue = FALSE;

if (!m_strInfFileName.IsEmpty())
{
TCHAR lpszReturnBuffer[nBufferSize];

DWORD dwNoOfCharsCopied = GetPrivateProfileString(p_strSectionName, NULL,
_T(""), lpszReturnBuffer, nBufferSize, m_strInfFileName);

bReturnValue = (dwNoOfCharsCopied > 0) ? TRUE : FALSE;
}

return bReturnValue;
}

CStringList* CINIReader::GetSectionNames()
{
if (m_pSectionList)
{
m_pSectionList->RemoveAll();
TCHAR lpszReturnBuffer[nBufferSize];
GetPrivateProfileSectionNames(lpszReturnBuffer, nBufferSize, m_strInfFileName);
TCHAR* pNextSection = NULL;
pNextSection = lpszReturnBuffer;
m_pSectionList->InsertAfter(m_pSectionList->GetTailPosition(), pNextSection);
while (*pNextSection != 0x00)
{
pNextSection = pNextSection + strlen(pNextSection) + 1;
if(*pNextSection != 0x00)
{
m_pSectionList->InsertAfter(m_pSectionList->GetTailPosition(), pNextSection);
}
}
}

return m_pSectionList;
}

CStringList* CINIReader::GetSectionData(CString p_lpSectionName)
{
if (m_pSectionDataList)
{
m_pSectionDataList->RemoveAll();
TCHAR lpszReturnBuffer[nBufferSize];
GetPrivateProfileSection(p_lpSectionName, lpszReturnBuffer, nBufferSize, m_strInfFileName);
TCHAR* pNextSection = NULL;
pNextSection = lpszReturnBuffer;
m_pSectionDataList->InsertAfter(m_pSectionDataList->GetTailPosition(), pNextSection);
while (*pNextSection != 0x00)
{
pNextSection = pNextSection + strlen(pNextSection) + 1;
if(*pNextSection != 0x00)
{
m_pSectionDataList->InsertAfter(m_pSectionDataList->GetTailPosition(), pNextSection);
}
}
}

return m_pSectionDataList;
}

We can discuss about INI writer in our next post.





How to register a vectored exception handler

2 05 2013

Recently just after we deployed our project in a Client machine, they reported a sporadic crash issue in their machine. :(. After analyzing the dump file, our Architect team found out that its happening from a particular COM Component. Unfortunately I was responsible for that component. 😦 😦

I tried to reproduce same issue in my development machine and was able to reproduce only in release configuratiin mode. Actually I have only the source code of my component in my machine.
So I was thinking about, how to find out this crash location in my source code. Yes, you are right some loggin mechanism. 🙂 Plus some exception handling mechanism too. 🙂 🙂

In case of exception occouered in our code, the operating system try to find out a handler which tells how to proceed now. If it fails, then we will get error message that our application is going to close!!!
In order to find such exception handler, the system has a fixed order to search.
It will start with the vectored exception handlers. So we can set a Vectored exception handler for our application using Windows API AddVectoredExceptionHandler.It registers a vectored exception handler.
The parameter of exception handler is pointer to a structure EXCEPTION_POINTERS. From this structure we get exception code and address where the exception occurred. Then using the method SymGetSymFromAddr64 from Dbghelp.dll, we can locate the symbol(function name) for that address.

char *Symbol(DWORD dwAddr)
{
    typedef struct _IMAGEHLP_SYMBOL64_L {
        DWORD   SizeOfStruct;
        DWORD64 Address;
        DWORD   Size;
        DWORD   Flags;
        DWORD   MaxNameLength;
        CHAR    Name[1];
    } IMAGEHLP_SYMBOL64_L, *PIMAGEHLP_SYMBOL64_L;

    typedef BOOL (__stdcall *pfnSymInitialize) (HANDLE hProcess,
        PCSTR UserSearchPath, BOOL fInvadeProcess);
    typedef BOOL (__stdcall *pfnSymGetSymFromAddr64) (HANDLE hProcess,
        DWORD64 qwAddr, PDWORD64 pdwDisplacement, PIMAGEHLP_SYMBOL64_L  Symbol);

    static BOOL	bSymLoad;
    static char symName[1024];
    static IMAGEHLP_SYMBOL64_L *pSym = NULL;
    static pfnSymInitialize SymInit;
    static pfnSymGetSymFromAddr64 SymName;

    if (!bSymLoad)
    {
        HMODULE hMod;			
        if ( (hMod = LoadLibrary(__T("Dbghelp.dll"))) &&
            (SymInit = (pfnSymInitialize) GetProcAddress(hMod, "SymInitialize")) &&
            (SymName = (pfnSymGetSymFromAddr64) GetProcAddress(hMod, "SymGetSymFromAddr64")))
        {
            bSymLoad = SymInit(GetCurrentProcess(), NULL, true);
            pSym = (IMAGEHLP_SYMBOL64_L *) malloc(sizeof(IMAGEHLP_SYMBOL64_L) + 2000);
        }
    }

    if (bSymLoad)
    {
        DWORD64  dwDisplacement = 0;
        pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64_L);
        pSym->MaxNameLength = 2000;

        if (SymName(GetCurrentProcess(), dwAddr, &dwDisplacement, pSym))
        {
            return &pSym->Name[0];
        }
    }

    return NULL;
}

LONG CALLBACK VectoredExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
{
    CString strMsg;
    strMsg.Format("Exception code: 0x%x (%s)", ExceptionInfo->ExceptionRecord->ExceptionCode,
		Symbol((DWORD) ExceptionInfo->ExceptionRecord->ExceptionAddress) );
	return EXCEPTION_CONTINUE_SEARCH;
}

BOOL InitInstance()
{
    AddVectoredExceptionHandler(1, VectoredExceptionHandler);
}


It uses few symbol handler functions from Dbghelp.dll, which gives applications easy and portable access to the symbolic debugging information of an executable image.





How to pass variable number of arguments to a function

30 04 2013

How to write functions which takes variable number of arguments in our program.

In C++, we can write functions with three dots(…) as parameter. This will make that function to support variable number of arguments. The va_arg, va_end, and va_start macros provide access to function arguments when the number of arguments is variable.

void LogError(TCHAR * format, ...)
{
   va_list args;
   int len;
   TCHAR *buffer;

   va_start(args, format);
   len = _vscprintf(format, args) + 1;
   buffer = (TCHAR *) _alloca( len * sizeof(TCHAR) );
   vsprintf_s( buffer, len, format, args );
   CString strErrMsg = buffer;
}

int Sum(int noOfArgs, ...)
{
    int nSum = 0;
    va_list args;
    va_start(args, noOfArgs);
    nSum = va_arg(args, int);
    for(int i = 2; i <= noOfArgs; i++) 
    {
        nSum += va_arg(args, int);
    }
    va_end(args);
    return nSum;
}

void main()
{
    int nSum = Sum(5, 1, 2, 3, 4, 5);
    LogError(_T("Failed - %s, ErrorCode - %d"), "AccessDenied", 111);
}


These macros are defined in STDARG.H file.





How to read Unicode text files

16 04 2013

Recently I met with a problem when I wrote some codes to read a file using MFC API CStdioFile. But unfortunately it failed to read UNICODE files :(. Then only I came to know that the MFC classes CFile and CStdioFile can read/write text files only in ANSI format. So how we will resolve it?

Windows provides another API fopen_s for Unicode file streams. This API supports encoding flag, where we cab mention the desired flag while reading a file or writing a file.

fopen_s(&fStream, “UnicodeFile.txt”, “r,ccs=encoding”);

    
BOOL ReadUnicodeFile()
{
    CString strFileName = _T("C:\\UnicodeFile.txt");
    FILE *fStream;
    errno_t errCode = _tfopen_s(&fStream, strFileName, _T("r, ccs=UNICODE"));
    if (0 != errCode)
    {
        return FALSE;
    }
    CStdioFile File(fStream);
    CString strLine;
    while(File.ReadString(strLine))
    {
        //reading line-by-line
    }
}

ccs=ENCODING
Specify the coded character set to use (ANSI, UTF-8, UTF-16LE, and UNICODE) for this file. This option is available in Visual C++ 2005 and later.





How to use enumeration for bitwise operations

28 03 2013

An enumeration is a user-defined type consisting of a set of named constants called enumerators. If we try to perform some bitwise operation on enum values, it will show compiler error (C2440).

The best way to resolve this issue is overloading bitwise operators(|, &, ~ etc) for enum.

    enum Colors
    {
        red = 1,
        blue,
        yellow,
        green
    };

    inline Colors operator|(Colors a, Colors b)
    {
        return static_cast(static_cast(a) | static_cast(b));
    }

    inline Colors operator&(Colors a, Colors b)
    {
        return static_cast(static_cast(a) & static_cast(b));
    }
    void main()
    {
        Colors c1 = red | blue;
        Colors c2 = red & blue;
    }

By default, the first enumerator has a value of 0, and each successive enumerator is one larger than the value of the previous one, unless you explicitly specify a value for a particular enumerator.





How to get parent directory from file path

12 03 2013

We usually use file paths and directory paths in our code. Sometimes they have to be processed, like how we can parse parent directory from full file path.

The Windows API PathRemoveFileSpec removes the trailing file name and backslash from a path.

#include "Shlwapi.h"

void main()
{
  TCHAR filePath = "C:\\TEST\\sample.txt";
  PathRemoveFileSpec (filePath); //filePath becomes "C:\\TEST"
}

Don’t forget to include shlwapi.lib to project settings.