Archive

Archive for the ‘COM’ Category

CComPtr vs _com_ptr_t

Recently a user asked this question in forums, I was quite able to answer his query. So thought this might be useful to you guys too. ūüôā

So the basic difference is that CComPtr is an ATL class is used with using ATL COM implementations while _com_ptr_t is one of the few COM support classes to support non ATL COM development. The definitions of these COM support classes go along with the tlb files and probably that’s why they are called as COM support classes. Also their definition can be found in comdef.h too. The other classes similar to _com_ptr_t are …

  1. _bstr_t
  2. _com_error
  3. _com_ptr_t
  4. _variant_t

So what are COM support classes? These are special lightweight classes that wraps basic useful COM functionality so that ideas like COM smart pointer typedefs over raw COM inteface classes works just by using tlb file. An example on how _com_ptr_t is used…

_COM_SMARTPTR_TYPEDEF(IMyInterface, __uuidof(IMyInterface));

This above line declares _com_ptr_t specialization IMyInterfacePtr.

The library to link to for using COM support classes is comsuppw.lib.

Advertisements
Categories: C++, VC++, COM Tags: ,

How to debug a dll?

October 25, 2008 5 comments

Why?

Well debugging exe is quite easy, but ever wondered how to debug a dll. Well why? Simple, you write a dll and you wanna debug a bug just like you would do with an executable.

Can you give us some examples?

Well so what is a dll? I think of it as a parasite because just like a parasite it’s dependent on an executable to get it running. Some examples follow…

  1. A good example to think of will be rundll32.exe. Ever thought about that name “rundll32.exe”, it just means “run a 32 bit dll using this exe”, so how does this achieve this, remember the command line that we pass to it, i.e. name of the dll followed by a procedure name exported from our dll.
  2. Another example to think of is regsvr32.exe, does the same stuff i.e. registers a COM dll¬†but this time with a difference, we don’t have to give a procedure name. Because COM programming protocol defines mandatory functions to be exported from a COM dll and regsvr32.exe knows exactly which function to call based on the command line switches passed in.
  3. Another example that comes to mind is the¬†windows surrogate process “dllhost.exe”, I’ve heard people say that it’s a virus ;). Naah it’s a COM surrogate process which helps in hosting a COM dll to make the dll behave like a process hence providing the flexibility to behave like an executabable and at the same time like a dll, vice versa is not possible. Well it can at times be hosting a malicious dll too. It’s quite rare though.

What has this got to do with debugging a DLL?

The reason why I’ve given above examples is to help you understand that a DLL cannot run by itself, it needs a host process to help it run.

Exactly! same for debugging it needs a process to get it running so that execution reaches our breakpoint that we’ve set. Aha! so there must be some option to tell the debugger about the host process. Oh yeah, goto Project settings->Debugging->Executable for Debug Session. Select any process which is using your dll.

Think that you are writing a window’s shell extension, which are dlls, think on how to debug them. So for this case your target process will be explorer.exe. So you will specify explorer.exe as your process. Or imagine writing an¬†activex control, so for this case the target process will be an activex test container.

This is a shot from VC6, it’s quite similar in VC7, VC8 and VC9, instead of tabs there you have a tree menu holding¬†the “Debugging” item right at the top of the tree.

Well now just press F5 and see what happens, you will see your target process running and just try doing a button or menu click that could invoke the function in which you’ve set a breakpoint.¬† If you are writing a shell extension for e.g. extending shell context menu, then you would right click on a file in the explorer window.

Also note that if your active project is a ‘dll project’ then you’ll get prompted to enter a target process name to get the dll hosted as soon as you press F5. So no need to go to project properties.

Hope this helps you?

How to create a GUID programmatically?

Do the following…

GUID guId = { 0 };
CoCreateGuid( &guId );
// or
UUID uid = { 0 };
UuidCreate( &uid );

For converting to string use…

PUCHAR pChar = 0;

// Convert to string
UuidToString( &uid, &pChar );
MessageBox( NULL, (char*)pChar, NULL, MB_OK );

//Don't forget to free allocated string
RpcStringFree( &pChar );

Freeing unused libraries while using COM!

It’s a good practice to free unused COM dlls if it’s not used anymore. So is there a function call which does this?

Yes, it’s called CoFreeUnusedLibraries or CoFreeUnusedLibrariesEx!

Are the libraries immediately removed from the internal COM dll list, no there is a time delay of 10 minutes for MTAs and neutral apartment models, this is to avoid multi threaded race conditions but there is no delay for STAs.

To avoid a ten minute delay call CoFreeUnusedLibrariesEx with the delay parameter set to some reasonable value, but avoid values of zero allowing a dll to do cleanup stuff. MSDN says there will be problems if delay is set to zero.

Internally COM maintains a list of COM dlls loaded for a process, and when CoFreeUnusedLibraries is called this dll is moved to “candidate-for-removal” list as per MSDN. So just in case if the dll get’s used again while in this list, it’s moved back to the active list of COM libraries of loaded for a process.

CoFreeUnusedLibrariesEx/CoFreeUnusedLibraries calls DllCanUnloadNow to figure out whether a COM dll is ready to be unloaded, if it’s ready then it returns S_OK else S_FALSE.

How to resolve a shortcut!

September 12, 2007 Leave a comment

Ever wondered how to resolve a shortcut! There is a hidden helper¬†function if you are using MFC, it’s called AfxResolveShortcut. I customized it a bit, so that we can¬†use it independently without MFC, and here is the finished product. ūüėČ

BOOL ResolveShortcut( HWND hWnd_i,
                      LPCTSTR lpctszFileIn_i,
                      LPTSTR  lptszFileOut_o,
                      const int nPathLength_i )
{
    // Object for resolving link
    IShellLink* psl = NULL;
    *lptszFileOut_o = 0;   // assume failure            

    if (!hWnd_i)
        return FALSE;            

    SHFILEINFO info;
    if (( SHGetFileInfo(lpctszFileIn_i,
                        0,
                        &info,
                        sizeof(info),
                        SHGFI_ATTRIBUTES) == 0) || !(info.dwAttributes & SFGAO_LINK))
    {
        return FALSE;
    }            

    CoInitialize( 0 );            

    // Create instance
    HRESULT hCreateRes = CoCreateInstance( CLSID_ShellLink,
                                           0,
                                           CLSCTX_INPROC_SERVER,
                                           IID_IShellLink,
                                           reinterpret_cast<lpvoid *>( &psl ));
    if ( FAILED( hCreateRes ) || psl == NULL )
    {
        return FALSE;
    }            

    IPersistFile *ppf = NULL;
    if (SUCCEEDED(psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf)))
    {
        USES_CONVERSION; // T2COLE needs this
        if ( ppf != NULL && SUCCEEDED( ppf->Load( T2COLE( lpctszFileIn_i ), STGM_READ)) )
        {
            /* Resolve the link, this may post UI to find the link */
            if ( SUCCEEDED(psl->Resolve( hWnd_i,
                 			    SLR_ANY_MATCH)))
            {
                psl->GetPath(lptszFileOut_o, nPathLength_i, NULL, 0);
                ppf->Release();
                psl->Release();
                CoUninitialize();
                return TRUE;
            }
        }           

        if (ppf != NULL)
            ppf->Release();
    }           

    psl->Release();
    CoUninitialize();
    return FALSE;           

}// End ResolveShortcut           

//Lets test the above code...
int main()
{
  TCHAR chBuffer[MAX_PATH] = { 0 };
  ResolveShortcut( hSomeWindow,
                   _T( "C:\\shortcut to msdev.lnk" ), // Make sure the shortcut is there
                   chBuffer,
                   MAX_PATH );
  MessageBox( hSomeWindow, chBuffer, _T( "Hurray shortcut resolved" ), MB_OK | MB_ICONINFORMATION );
  return 0;
}// End main

%d bloggers like this: