On startup, an application must call CoInitialize or OleInitialize before calling any other function in their respective libraries. Most 32-bit applications should use OleInitialize. You need to remember whether initialization works, usually through some variable such as m_fInitialized:
if (FAILED(CoInitialize(NULL))) //Or OleInitialize
[Fail loading the task]
m_fInitialized=TRUE;
In 32-bit OLE, both initialization functions take a NULL reserved pointer and will fail with E_INVALIDARG if you pass a non-NULL value.
Any code within the same task can call CoInitialize or OleInitialize multiple times. This allows any code (usually that in a DLL) to ensure that the OLE DLLs are initialized, even if the application that loaded the DLL is OLE-ignorant and did not perform initialization. The first successful call to [Co|Ole]Initialize will return NOERROR; subsequent successful calls will return S_FALSE, meaning that the call still worked but that it wasn't the first call. Because a DLL's LibMain is called before the application's WinMain, [Co|Ole]Initialize will never have been called by that time. It's best to defer this code to a later DLL-specific initialization call if possible, but there's no real harm in a DLL making the first call within a task. Internally, OLE associates task information with a unique number returned from the function CoGetCurrentProcess, which you can use whenever you need a process-specific (as opposed to thread-specific) identifier. This identifier is considerably closer to unique than a Windows HTASK is.
Any caller to the initialization functions must remember whether initialization worked so that it knows whether to call CoUninitialize or OleUninitialize when it shuts down. In other words, every Uninitialize must be matched one-to-one with an Initialize.