Archive for April, 2008

Automatically link required libraries.

0


In our projects we use number of 3ed party API’s especially from platform SDK and other components and one burden is finding the libraries for those API’s. For Microsoft provided API’s since they have strong documentation, finding the library for particular API is not so tedious. But for other vendors, It may be. We need to dig a lot for finding the lib of that particular API. How can we get rid from this?


You can you #pragma comment( lib, “LibraryName” ) to specify the necessary library file in the header file itself. For e.g. See the following header file.

// EventLog.h
class EventLog
{
    …
};
#ifdef _DEBUG
    // If it’s a debug version…
    #pragma comment( lib, "MyEventLogLibd.lib" )
#else
    // Ooooh!!! Its release version.
    #pragma comment( lib, "MyEventLogLib.lib" )
#endif

If we include the EventLog.h header file, the library required will be automatically included. I dream for the day on which all SDK headers auto includes their libraries… ;)


Target audiance – Intermediate.

Let Visual Studio talk to you – Events in Visual Studio Object Model.

0


Did you ever wish to see a “Bye Bye!” from Visual Studio when you exit? Did you ever wish to see a message, when the build is completed, instead of that boring chime sound? The answer is – Visual Studio Object Model Events.


Visual Studio Object model Events are the ones, which Visual Studio triggers on specified events. They can be easly accessed by writing simple VBScript macros. See the following step by step instructions.

1) Start Visual Studio.
2) Take Tools -> Macro
3) Click Options -> New File and save a new macro file by specifying a name such as “VSEvents” or something like that.
4) Click Edit button and give macroname as “HelloWorld” or something like that.
5) Now you can see a VBScript editor window for editing macros. Actually we’ve added “HelloWorld” for just starting the editor. If there are no macro inside a file, it cannot be edited.
6) Now in the editor add the following lines to the bottom

Sub Application_BeforeApplicationShutDown
	' Say ByeBye to master when he leaves!
	MsgBox "Bye Bye!"
End Sub

sub Application_BuildFinish(nNumErrors, nNumWarnings)
   ' Build Finished.
   	MsgBox "Master, Wakeup! the build is finished."
end sub

7) Save everything and exit Visual Studio.
8 ) Now Start VisualStudio and try to exit. The Visual studio says “Bye Bye!”.
9) Try to compile a project, Visual Studio will shows a message when compilation is finished!

There is a couple of other events too. They are,

Application_BeforeApplicationShutDown
Application_BeforeBuildStart
Application_BeforeDocumentClose
Debugger_BreakpointHit
Application_DocumentOpen
Application_DocumentSave
Application_NewDocument
Application_WindowActivate
Application_WindowDeactivate
Application_WorkspaceClose
Application_WorkspaceOpen

Have a look at them too. See their description in MSDN.


Since its intended for beginners, i’ve described step by step. If you are advanced, then just write a .dsm file with these macro as contents and put to <VisualStudioDir>\Common\MSDev98\Macros. Then load that macro file in Visual Studio.


Targeted Audience – Beginners.

Expand/Collapse System Notification Area programmatically.

2


Windows system task bar have System notification area. There is an arrow button nearby that by which we can Expand or collapse the System notification Area. Did you notice that while minimizing yahoo messenger, it displays a message that “Yahoo messenger will be still running in the system tray”. While displaying such as message, it will be nice to animate the Notification area by expanding and collapsing it.


See the code snippet. I guess, its self explanatory.

// Find the Shell Tray Window.
HWND hTrayWnd = ::FindWindowEx( 0,
                                0,
                                _T("Shell_TrayWnd"),
                                _T(""));
// Find the Tray notification window,
// which is a child of ShellTrayWidnow.
HWND hTrayNotifyWnd = ::FindWindowEx( hTrayWnd,
                                      0,
                                      _T("TrayNotifyWnd"),
                                      _T(""));
// Find the Button which is a child of ShellTrayWidnow.
HWND hButton = ::FindWindowEx( hTrayNotifyWnd,
                               0,
                              _T("Button"),
                              _T(""));

// Now get the DialogControlID of the button.
UINT DlgId = ::GetDlgCtrlID( hButton );

// Send a WM_COMMAND message, so the button reacts.
::SendMessage( hTrayNotifyWnd, WM_COMMAND, DlgId, 0 );

// Wait a bit to have an animation effect.
Sleep( 1000 );

// Send WM_COMMAND message once again.
::SendMessage( hTrayNotifyWnd, WM_COMMAND, DlgId, 0 );


Targeted Audiance – Intermediate

Catching exceptions from the constructor

0


In constructors we initialize member variables by using member initialize list. The initialize list is out of constructors function body and how the exception thrown by members in initialize list can be caught by try-catch? See the code block.

class MyClass
{
public:
MyClass( int var1, int var2 )
: m_var1( var1 ),
m_obj2( var1 ) // If this one throws an exception, i can't catch it.
    {
        try
        {
           // Constructor body.
        }
        catch( … )
        { }
    }
int m_var1;
    CMyObject m_obj2;
};

Here if m_obj2 throws an exception, it cannot be catch by the try-catch block, because the initialize list is outside the try-catch block.


For catching exceptions from the initialize list, there is a special type of try-catch pattern. See the code block.

class MyClass
{
public:
    MyClass( int var1, int var2 )
    try : m_var1( var1 ),
          m_obj2( var1 )    // Now I can catch the exception.
    {
       // Constructor body.
    }
    catch( ... )
    { }
// Member variables.
    int m_var1;
    CMyObject m_obj2;
};


If you compile it in Visual Studio 6.0 it will show a couple of errors. Try next versions such as Visual Studio 2005, etc.


Targeted Audience – Intermediate.

Locate implementation of a particular Dialog in huge Codebase Easily.

0


Huge Maintenance projects usually contain a number of dialogs. Sometimes we want to modify a particular dialog in that project. During most of the case, we might be encountering that dialog for the first time( Guys digging old code base like me can understand it very well ). At that time, what usually people do to locate the dialog implementation is as follows.

  1. Iterate through all dialogs in the resource by opening it or by checking the dialog ids.
  2. Find the matching dialog.
  3. Take the dialog ID.
  4. Search the code base for reference to the Dialog ID.
  5. You found it!

If your code base have 100eds of dialogs, how much time will it take?


All dialogs have the same base class, CDialog. So the CDialog constructor will be called before the constructor of your dialog class get called. Now follow the steps.

  1. Start debugging your project by F5.
  2. Open the file – <VisualStudioDir>\VC98\MFC\SRC\DLGCORE.CPP
  3. Put breakpoints on all CDialog constructors. Note – there are many overloads for your CDialog constructor. Since its unknown how your dialog class is initialized, its better to put break points on all CDialog constructors.
  4. Now launch your dialog from your application and the debugger will break on the CDialog constructor.
  5. Now take the Call Stack by pressing Alt + 7.
  6. From the call stack you can identify the class you were searching.


The above steps only works for debug version. If you are in release version, then breakpoint at DLGCORE.CPP will be disabled at the starting itself. For that, see following steps.

1) Our problem is how to put breakpoint at CDialog in release build.
2) For that take any put any other dialog class in your workspace and put a breakpoint in its constructor and start debug by F5.
3) when the breakpoint at your dialog’s constructor is reached, right click and select “Go To Disassembly”. It will be as follows.

62:   CDlg1Dlg::CDlg1Dlg(CWnd* pParent /*=NULL*/)
63:       : CDialog(CDlg1Dlg::IDD, pParent)
64:   {
00401216   push        ebp
00401217   mov         ebp,esp
00401219   push        0FFh
0040121B   push        offset $L87331 (00401d29)
00401220   mov         eax,fs:[00000000]
00401226   push        eax
00401227   mov         dword ptr fs:[0],esp
0040122E   push        ecx
0040122F   mov         dword ptr [ebp-10h],ecx
00401232   mov         eax,dword ptr [pParent]
00401235   push        eax
00401236   push        66h
00401238   mov         ecx,dword ptr [this]
0040123B   call        CDialog::CDialog (00401a0a)
00401240   mov         dword ptr [ebp-4],0

4) From the disassembly you will get the address of CDialog constructor to be called.
5) now take the breakpoint window by pressing Ctrl+B.

6) Just add a breakpoint by specifying this memory location in “Break At” editbox. don’t forget to add 0x in front of memory location. here it will be 0x00401a0a.
7) Now you’ve successfully added a break point at CDialog constructor in release version too. Enable it only when you need it.


Targeted Audience – Beginners.

Do you know – what is Cfront?

0


Cfront was the first compiler writter for C++. Actually it converts C++ programs to C. It’s developed by the creator himself – Bjarne Stroustrup.

There were versions from 1.0 to 4.0. But Cfront 4.0 failed to implement exception handling and thus came to an end. But you can still get cfront from the shelves of SoftwarePreservation group – a museum of classic softwares. Here is the link.

Thanks Wiki for the history.


Targeted Audience – Everyone who wish to hear stories. ;)

Can C++ Style comments replace C-Style comments?

2


While entering to C++ world, the first thing we used to learn is – Avoid C-Style comments, always use C++ style comments and a number of drawbacks of C-Style comments. But don’t think that C++ comments are omni. Still there are places where C++ style comments cannot be used.


Usually inside macros, we don’t write comments. But if the macro is too complex, adding comments will be better for future. But can we use C++ style comments? See the following code block.

#define CHECK_AND_DELETE_PTR( ptr ) \
    // Check whether the pointer is valid \
    if( ptr ) \
    { \
        // Delete the pointer \
        delete ptr; \
}

The code block won’t compile. Because C++ style comments always look for end-of-line as termination and the backslash delimiter that we add will concatenate the next line and that too will become the part of comment. Since macro body should be in a single line, we cannot omit the backslash delimiter.

See the same macro with C-Style comments which is perfect.

#define CHECK_AND_DELETE_PTR( ptr ) \
    /* Check whether the pointer is valid */ \
    if( ptr ) \
    { \
        /* Delete the pointer */ \
        delete ptr; \
    }

Immortal C. Isn’t it? ;)


Targeted Audience – Intermediate.

Use Semaphores as Global Counters.

4

Icon Description
For certain instance, we need global counters which can be accessed from any process. For instance how many instance of application is running or if our application wants to expose some values such as its performance figures etc. We can use Semaphores as global counters.

Icon How Can I Do It?
Actually semaphore is meant for synchronization. But unlike other synchronization objects like mutex or event, semaphore can hold a count in it. And like other Kernel objects, semaphore can have a name which makes it possible to be accessed from any process across the system. We are going to utilize these properties to transform it as a Global Counter.

Create Global Counter.
Function CreateSemaphore() is Used to create the semaphore. While Creating, you can specify an initial count, a maximum count and a name. The name is used for opening the same semaphore from other applications.

Accessing Global Counter.
Function CreateSemaphore() is again used to access the existing semaphore. If the semaphore exists, the function returns a new handle to the semaphore. OpenSemaphore() also can be used.

Incrementing Global Counter.
Function ReleaseSemaphore() can be used. Actually this function is used to increment the semaphore value and there by signal a thread, which is waiting for the semaphore. But, we use this function to increment the value.

Decrementing Global Counter.
Function WaitForSingleObject() can be used. Threads uses this function to wait on semaphores until it get signled. Once signled, WaitForSingleObject decrements the semaphore count. So this is used to decrement the value of Global Counter. But a single call to WaitForSingleObject() will decrease the value by one only. So we’ve to call the WaitForSingleObject() number of times to decrement numbers greater than one.

Reading Global Counter.
Function ReleaseSemaphore() can be used again. It returns the current value. Since ReleaseSemaphore() increment the semaphore value, we’ve to call WaitForSingleObject() once again to normalize the value of semaphore.

For simplicity, i’ve implemented the logic in a class named CGlobalCounter.

class CGlobalCounter
{
public:
// Constructor and Destructor.
CGlobalCounter( const TCHAR* strGlobalCounterName );
~CGlobalCounter();

// Initialize counter.
bool Initialize();

// Increment and Decrement.
void Increment( LONG lIncrementBy );
void Decrement( LONG lDecrementBy );

// Get the Value.
LONG GetValue();

private:
HANDLE m_hGlobalCounter;  // Handle for semaphore.
CString m_csGlobalCounterName; // Semaphore name.
};

Download sample from here. Right click and Save to your harddisk and rename to .zip. Since there are some limitation in file uploading, i can’t upload zip files.

Icon Note
Advantages
1) Very simple to use.
2) less resource usage.

Disadvantage
1) Since the GetValue() – increment and decrement semaphore, the GlobalCounter can hold only upto MaxValue-1.
2) While decrementing, there can be a performance bottleneck.

Decide yourself whether you need it or not.
Quite lengthy one, but its worthy. ;)


Targeted Audience – Advanced.

List all Device Drivers running in your system.

2

Icon Description
Listing up device driver information is very easy. In Platform SDK , there is a set of functions available named “Process Status Helpers”. By using them, we can get the BaseName and FileName of all running device drivers.

Icon How Can I Do It?
Basically there are 3 functions, which we are interested in. They are -

  • EnumDeviceDrivers() – Used to get the list of ImageBaseAddress of all Device Drivers. Using this image base address, we find out the the BaseName and FileName. This function is also used to get the buffer length required for calling the function.
  • GetDeviceDriverBaseName() – If ImageBaseAddress of a Device Driver is passed, it will provide the Driver Base Name.
  • GetDeviceDriverFileName() – If ImageBaseAddress of a Device Driver is passed, it will provide the Driver FileName.

See the code block for iterating all device drivers in a system.

#include "psapi.h"

// Gets the required buffer length for ImageBaseAddrArray.
DWORD GetImageBaseAddrArrayLen()
{
    // Gets the number of Bytes needed for Buffer.
    // Call EnumDeviceDrivers with size as 0.
    // The required buffer length will be returned
    // via dwRequiredBufferSize.
    DWORD dwRequiredBufferSize = 0;
    EnumDeviceDrivers( 0,  // array of load addresses
                       0,  // size of array as 0.
                       // number of Required buffer size.
                       &dwRequiredBufferSize );

    return dwRequiredBufferSize;
}

// Get Driver informations such as Driver BaseName and FileName.
void GetDriverInfo( LPVOID DriverImageBaseAddr, CString& csDriverBaseName, CString& csDriverFileName )
{
    // Get driver BaseName
    TCHAR tchBuffer[ MAX_PATH ] = { 0 };
    GetDeviceDriverBaseName( DriverImageBaseAddr, tchBuffer, MAX_PATH );
    csDriverBaseName = tchBuffer;

    // Get driver filename.
    GetDeviceDriverFileName( DriverImageBaseAddr, tchBuffer, MAX_PATH );
    csDriverFileName = tchBuffer;

}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    // Allocate array for getting ImageBase addresses of
    // all drivers present in system.
    DWORD dwBufferLen = GetImageBaseAddrArrayLen();
    LPVOID* pImageBaseAddrArray = (LPVOID*)new BYTE[ dwBufferLen ];

    DWORD dwBytesReturned = 0;
    // Get the ImageBaseAddresses of all drivers.
    EnumDeviceDrivers( pImageBaseAddrArray,  // array of load addresses
                       dwBufferLen,  // size of array as 0.
                       &dwBytesReturned );

    // Get the total number of drivers. calculate it by
    // total size in bytes/sizeof(void*)
    DWORD nDrivers = dwBufferLen / sizeof(LPVOID);

    // Iterate through each driver.
    for( DWORD Index = 0; Index < nDrivers; ++Index )
    {
        // Get Device Driver informations.
        CString csDriverBaseName;
        CString csDriverFileName;
        GetDriverInfo( pImageBaseAddrArray[ Index], csDriverBaseName, csDriverFileName );

        // Print the Driver Information or do what ever you want!
        cout << csDriverBaseName.operator LPCTSTR() <<
            _T(" : ") <<
            csDriverFileName.operator LPCTSTR()
            << endl;
    }
}

Create a console appliaction with MFC support and try the source.

Icon Note
Don’t forget to add psapi.lib to your linker settings.

intermediateseries.jpg
Targeted Audience – Intermediate.

Launch control panel apps programmatically.

4

Icon Description
Normally for launching control panel application you have to go to control panel and double click the icons. Its useful if we can launch it programmatically. For instance, if the program wants the user to check the computer name, the system properties can be launched. If the program wants to uninstall some software, for easiness – the add/remove programs dialog can be launched and so and so…

Icon How Can I Do It?
There is an undocumented api – “Control_RunDLL” in the Shell32.dll which can be used to launch control panel applications. You’ve to pass the filename of control Panel application and it will be launched. See the following code block.

// Load the Shell32 dll.
HINSTANCE hShell32 = LoadLibrary(_T("Shell32.dll"));

// Typedef for function pointer for Control_RunDLL.
typedef void( CALLBACK * CONTROL_RUNDLL_FN_PTR)( HWND hwnd,
                                                 HINSTANCE hinst,
                                                 LPSTR lpszCmdLine,
                                                 int nCmdShow );

// Get the function pointer of - Control_RunDLL.
CONTROL_RUNDLL_FN_PTR pControl_RunDLL =
  (CONTROL_RUNDLL_FN_PTR)GetProcAddress( hShell32,
                                         _T("Control_RunDLL"));

// Now call the function and launch the ControlPanel App.
(*pControl_RunDLL)( 0, // hwnd
                    0, // Hinstance
                    _T("sysdm.cpl"), // ControlPanelApp filename.
                    SW_NORMAL );     // Show Normal

Icon - Where is it?
The control panel applications are located inside your windows directory. If you search the windows directory for “*.cpl” you can find a number of files. Each file is a control panel application. Even though the file extension is “.cpl“, its a dll. From the name itself you can interpret which control panel application it refers to. Go on, have a try. ;)

Icon Note
For launching some control panel apps, you’ve to provide valid hwnd and hinstance. Then only it will be shown. For instance – timedate.cpl.

intermediateseries.jpg
Targeted Audience – Intermediate.

Go to Top