There are several issues I did not mention.
One of them is IDispatch support.
Can IDispatch work without registration ? The answer is yes, of course.
Now I will talk about ATL::IDispatchImpl class for implementing IDispatch. I am not going to write about whole investigation, just the points to understand it.
At first use it didn’t work.
How come ? The answer is simple if we look for IDispatchImpl declaration:
template <class T, const IID* piid = &__uuidof(T), const GUID* plibid = &CAtlModule::m_libid, WORD wMajor = 1,
WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
class ATL_NO_VTABLE IDispatchImpl : public T
What is it CComTypeInfoHolder ? It is a helper class for providing information about type library.
In GetTI method it calls LoadRegTypeLib which goes to Registry!
hRes = LoadRegTypeLib(*m_plibid, m_wMajor, m_wMinor, lcid, &pTypeLib);
Hmm, the solution is simple, write our NoRegistryComTypeInfoHolder which will call LoadTypeLib and load type library from the file instead of using the registry.
Btw, ATL uses TLB from resource if possible, so you do not have to change anything in this case.
The tricky part to implement our class is the strange code in ATL::IDispatchImpl:
#ifdef _ATL_DLL_IMPL
// Do not cache type info if it is used in atl71.dll
IDispatchImpl() : _tih(piid, plibid, wMajor, wMinor)
{
}
virtual ~IDispatchImpl()
{
}
protected:
_tihclass _tih;
HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
{
return _tih.GetTI(lcid, ppInfo);
}
#else
protected:
static _tihclass _tih;
static HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
{
return _tih.GetTI(lcid, ppInfo);
}
#endif
};
#ifndef _ATL_DLL_IMPL
template <class T, const IID* piid, const GUID* plibid, WORD wMajor, WORD wMinor, class tihclass>
typename IDispatchImpl<T, piid, plibid, wMajor, wMinor, tihclass>::_tihclass
IDispatchImpl<T, piid, plibid, wMajor, wMinor, tihclass>::_tih =
{piid, plibid, wMajor, wMinor, NULL, 0, NULL, 0};
#endif
WTF ??
It seems that our class must not implement constructor unless _ATL_DLL_IMPL is defined and then it must implement it. In addition the class must have only POD types because of initialization list when _ATL_DLL_IMPL is not defined.
Here a mess comes over. We need an additional function in our class to set TLB path varibale.
Again we cannot use object in our class 
I use ATL::CComTypeInfoHolder to decrease coding.
Here comes a class:
struct NoRegistryComTypeInfoHolder
{
// Aggregate this first to not break the compilation
CComTypeInfoHolder type_holder_;
// Our data
ATL::CComBSTR* tlb_path_;
#ifdef _ATL_DLL_IMPL
// Constructor
NoRegistryComTypeInfoHolder(const GUID* pguid, const GUID* plibid, WORD wMajor, WORD wMinor)
: type_holder_(pguid, plibid, wMajor, wMinor)
{
}
#endif // _ATL_DLL_IMPL
HRESULT EnsureTI(LCID lcid)
{
HRESULT hr = S_OK;
if (m_pInfo == NULL || m_pMap == NULL)
hr = GetTI(lcid);
return hr;
}
HRESULT GetTI(LCID lcid)
{
// Here comes almost the same code as CComTypeInfoHolder but we use LoadTypeLib
// ...
// Do not forget to add our Cleanup function to term functions.
// Path to TLB wasn't set !!!
if(!tlb_path_)
return E_FAIL;
}
void SetTLBPath(ATL::CComBSTR tlb_path)
{
delete tlb_path_;
tlb_path_ = new ATL::CComBSTR(tlb_path);
}
private:
// This function is called by the module on exit
// It is registered through _pAtlModule->AddTermFunc()
static void __stdcall Cleanup(DWORD_PTR dw)
{
ATLASSERT(dw != 0);
if (dw == 0)
return;
NoRegistryComTypeInfoHolder* p = reinterpret_cast dw;
delete p->tlb_path_;
tlb_path_ = NULL;
}
public:
// Delegate calls
HRESULT Invoke(IDispatch* p, DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
// We must call our EnsureTI
HRESULT hRes = EnsureTI(lcid);
if (m_pInfo != NULL)
return type_holder_.Invoke(p, dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexceptinfo, puArgErr);
return hRes;
}
// ... There are some other functions to delegate
};
Now use it instead of the default class and you have IDispatch without need for registry but you must supply tlb file.
Just great !! You can use your code with IDispatch without any problem. TLB is not really needed for implementing IDispatch but it makes life so simple !