Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why I can call StringFromCLSID even without the calling of CoInitializeEx before?

I am learning COM through C++. From MSDN:

Applications are required to use CoInitializeEx before they make any other COM library calls except for memory allocation functions.

The memory allocation functions is CoTaskMemAlloc and CoTaskMemFree in my opinion.

But I see, my "Hello World" works fine with and without the CoInitializeEx and CoUninitialize functions calling. In my code I use the StringFromCLSID function which is declared in the combaseapi.h header. So, it is a COM function in my opinion. My code:

/* entry_point.cpp */
#include "Tools.h"
#include <objbase.h>

int main(){
  HRESULT hr = ::CoInitializeEx(nullptr, COINIT_MULTITHREADED);
  if (FAILED(hr)){
    trace("Can't initialize COM for using in the current thread.");
    keep_window_opened();
    return 1;
  }
  // {D434CF7D-2CDD-457A-A4EF-5822D629CE83}
  static const CLSID clsid =
  { 0xd434cf7d, 0x2cdd, 0x457a, { 
    0xa4, 0xef, 0x58, 0x22, 0xd6, 0x29, 0xce, 0x83 } };

  const size_t SIZE = 39;
  wchar_t* wch = nullptr;
  hr = ::StringFromCLSID(clsid, &wch);
  if (FAILED(hr)){
    trace("Can't convert CLSID to wchar_t array.");
  }
  else{
    trace("CLSID converted to wchar_t array.");
    char mch[SIZE];
    size_t count = 0;
    int result = ::wcstombs_s(&count, mch, wch, SIZE);
    if (result){
      trace("Can't convert wchar_t array to char array.");
    }
    else{
      trace(mch);
    }
    ::CoTaskMemFree(wch);
  }
  ::CoUninitialize();

  keep_window_opened();
  return 0;
}

If I remove the calls of CoInitializeEx and CoUninitialize functions, then my code works still. I expected it will not work...

Why StringFromCLSID work even without the calling of CoInitializeEx before?

Thank you.

like image 210
Andrey Bushman Avatar asked Mar 15 '23 22:03

Andrey Bushman


2 Answers

StringFromCLSID is basically a printout of GUID value (bytes) into string, then formatting it nicely with hyphens and braces. There is nothing else involved and hence COM initialization is not really needed for this call to succeed.

You have to do CoInitialize/CoInitializeEx to be safe, but not doing it you don't necessarily hit a problem right away.

like image 151
Roman R. Avatar answered Apr 08 '23 06:04

Roman R.


Why StringFromCLSID work even without the calling of CoInitializeEx before?

The key information is stated right in the documentation.

CoInitializeEx function:

You need to initialize the COM library on a thread before you call any of the library functions except ... the memory allocation functions. Otherwise, the COM function will return CO_E_NOTINITIALIZED.

StringFromCLSID function:

StringFromCLSID calls the StringFromGUID2 function to convert a globally unique identifier (GUID) into a string of printable characters.

The caller is responsible for freeing the memory allocated for the string by calling the CoTaskMemFree function.

StringFromCLSID() returns a dynamically allocated string. We can infer from the highlighted sentence above that the memory is allocated using CoTaskMemAlloc() - which is explicitly documentated as not requiring CoInitializeEx().

StringFromGUID2() formats GUID data into a caller-specified memory block. Formatting a string does not require COM functionality. The wsprintfW(), StringCbPrintfW(), or other equivalent function would suffice. So CoInitializeEx() should not be required for StringFromGUID2(), even though this is not explicitly documented. I think it would be pretty short-sighted for Microsoft to not use one of their many available string formatting functions to implement StringFromGUID2(). So I think it should be safe to say that CoInitializeEx() is not a requirement for this (unless Microsoft says otherwise).

The GUID structure simply contains a few numbers and bytes. Declaring and using a GUID is not dependent on the COM library. You can freely use a GUID in your code all you want without touching COM at all - unless you want to generate a new GUID, in which case the CoInitializeEx() requirement for CoCreateGUID() is blurry as CoCreateGUID() is in the COM library but is explicitly documented as simply calling UuidCreate(), which is in the RPC library instead.

So that is why you can call StringFromCLSID() without calling CoInitializeEx() first. A GUID on its own does not require COM initialization. The string is being allocated with a memory function that does not require COM initialization. And the string is being formatted in a manner that most likely does not require COM initialization.

like image 32
Remy Lebeau Avatar answered Apr 08 '23 06:04

Remy Lebeau