3

I would like to create a dll library that will be loading in runtime. The library'll be using internally COM objects with MTA flag. The library will be created in main thread.

So I have question: Where there is best place where can I call 'CoInitializeEx' and 'CoUninitialize' functions. In the my dll(init/deinit functions) or client should call directly these functions?

I prefer first option. I would like avoid public dependig on COMs. Client shouldn't know I'm using COMs, but also I'd like avoid crashes when client unload my lib(then I call 'CoUninitialize' for my lib) and other libs(depend on COM) will be in undefined state.

EDIT:

ProviderApi.h

#ifndef API_H
#define API_H
class Provider;
define API __declspec(dllexport)
using ErrCode = int;
extern "C" {
 API ErrCode init(Provider** provider);
 API ErrCode deinit();
}
#endif

ProviderApi.cpp

#include <Objbase.h>
Provider* prov;
API ErrCode init(Provider** provider)
{
 const auto res = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
 // create provider
 // then I can use any com object
 *provider = prov;
}
API ErrCode deinit()
{
 CoUninitialize();
}

client code

#include <Windows.h>
class Provider;
typedef ErrCode (*f_init)(Provider**);
typedef ErrCode (*f_deinit)();
int main(int /*argc*/, char** /*argv*/)
{
 auto lib = LoadLibrary("my_lib.dll");
 auto init = (f_init)GetProcAddress(lib, "init");
 auto deinit = (f_deinit)GetProcAddress(lib, "deinit");
 Provider* prov;
 init(&prov);
 // do something
 deinit();
 return 0;
}

UPDATE 28.02.2020:

OK, I finally found the solution of my problem. To hide the COM dependency, just create a separate thread and execute COM methods in it. Bellow there is sample of usage.

ComThread.h

#ifndef COM_THREAD_H
#define COM_THREAD_H
#include <condition_variable>
#include <functional>
#include <mutex>
#include <thread>
class ComThread
{
public:
 ComThread();
 ComThread(const ComThread&) = delete;
 ComThread(ComThread&&) = delete;
 ~ComThread() noexcept;
 ComThread& operator=(const ComThread&) = delete;
 ComThread& operator=(ComThread&&) = delete;
 void doTask(std::function<void(void)> comTask);
private:
 std::thread m_thread;
 std::mutex m_mutex;
 std::mutex m_taskMutex;
 std::condition_variable m_cv;
 bool m_stop;
 std::function<void(void)> m_currentTask;
 void worker();
};
#endif // COM_THREAD_H

ComThread.cpp

#include "ComThread.h"
#include <cassert>
#include <objbase.h>
ComThread::ComThread()
 : m_stop(false),
 m_thread(std::thread(&ComThread::worker, this))
{
}
ComThread::~ComThread() noexcept
{
 m_stop = true;
 m_cv.notify_one();
 if (m_thread.joinable())
 m_thread.join();
}
void ComThread::doTask(std::function<void()> comTask)
{
 std::lock_guard lock(m_taskMutex);
 m_currentTask = comTask;
 m_cv.notify_one();
 std::unique_lock taskLock(m_mutex);
 m_cv.wait(taskLock, [this] () { return !m_currentTask; });
}
void ComThread::worker()
{
 const auto res = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
 assert(res == S_OK);
 while (true)
 {
 {
 std::unique_lock lock(m_mutex);
 m_cv.wait(lock, [this] () { return m_stop || m_currentTask; });
 }
 if (m_stop)
 break;
 assert(m_currentTask);
 m_currentTask();
 m_currentTask = nullptr;
 m_cv.notify_one();
 }
 CoUninitialize();
}

main.cpp

#include "DeckLinkAPI_h.h
#include "ComThread.h"
int main(int /*argc*/, char** /*argv*/)
{
 ComThread comThread;
 IDeckLinkIterator* deckLinkIterator = nullptr;
 HRESULT hr = S_OK;
 comThread.doTash([&hr, &deckLinkIterator]() {
 hr = CoCreateInstance(
 CLSID_CDeckLinkIterator,
 nullptr,
 CLSCTX_ALL,
 IID_IDeckLinkIterator,
 reinterpret_cast<void**>(&deckLinkIterator));
 });
 if (hr != S_OK)
 return -1;
 // do other things
}
asked Jul 30, 2019 at 19:51
3
  • 1
    What does "publicly depending" mean? When you distribute this dll are you distributing these com objects? Commented Jul 30, 2019 at 23:57
  • @candied_orange In the 'public depending' I mean dependency about 'COM' world. If I want use these object I have to initialize 'COM' by the call 'CoInitalizeEx' function and when the library is no longer needed I call 'CoUninitialize', but if another client code use COM's the app may crash after release my lib. For the easiest understand, I've update main post and I added sample code which show what I'd like achieve. No don't distributing these com objects. Commented Jul 31, 2019 at 17:17
  • Do you actually have (need) a technical requirement that your DLL be unloadable? (That is, the requirement that certain cleanup code needs to be executed, and afterwards all resources need to be cleanly released, when the client calls FreeLibrary.) In my opinion, for all non-trivial COM DLL code I've seen so far, I've not encountered a case where a "clean" cleanup and release is ever achievable. Once a COM DLL is loaded into a process, you better assume that it will stay with the process, until the process terminates. If there's requirement (e.g. to delete the file), use multiple processes. Commented Dec 28, 2019 at 23:39

1 Answer 1

1

Microsoft advises against calling these from the Dll load/unload functions:

Because there is no way to control the order in which in-process servers are loaded or unloaded, do not call CoInitialize, CoInitializeEx, or CoUninitialize from the DllMain function.

Reference

https://docs.microsoft.com/en-us/windows/win32/api/objbase/nf-objbase-coinitialize

answered Jul 31, 2019 at 1:16
2
  • 1
    Yes, I understand. I don't wanted call these function in DllMain. Commented Jul 31, 2019 at 17:19
  • @pbieguszewski: Putting those calls in functions that should be called on load/unload of your DLL leads to the exact same problems as why Microsoft issued this advice. Commented Aug 2, 2019 at 11:07

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.