VC++编译DirectShow ActiveX时error LNK2001: unresolved external symbol "class CFactoryTemplate * g_Templates"

http://www.vbforums.com/archive/index.php/t-296274.html

 

I am writing a ocx component with Visual C++ 6.0SP4
The component itself uses DirectX 9, DirectShow filters etc. using a linked in statically linked library "My.lib". Note that it just uses some filters, it does not expose or export any DirectShow filter functionality directly.
I want to use the component as a control in Visual Basic 2003/.net

The VC++ project wizard I used was the "MFC ActiveX ControlWizard (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/_core_ActiveX_Control_Topics.asp)" which creates code & files that - on their own - compile, link, and instantiate just fine in VB 2003/.net

But as soon as I link in the "My.lib" with all my DirectX functions (which I have previously successfully used in MFC and non-MFC applications but not yet in DLLs like an ocx control) I get these errors:

VideoLib.lib(dllentry.obj) : error LNK2001: unresolved external symbol "class CFactoryTemplate * g_Templates" (?g_Templates@@3PAVCFactoryTemplate@@A)
VideoLib.lib(dllentry.obj) : error LNK2001: unresolved external symbol "int g_cTemplates" (?g_cTemplates@@3HA)


As per MSDN (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directX/htm/classfactoriesandfactorytemplates.asp), the template mechanism is used by a DirectX subclass of CClassFactory which is data driven (via the templates, declaring each available object, its creation method pointer, GUID, and some extra stuff). In my lib and other applications I always instantiate my filter subclasses directly (via new CMyFilter() etc.) not via DllGetClassObject which does a GUID lookup in the template array. So I actually get away with not declaring the g_Templates global at all. (My.lib is bundled up as a static lib)

Somehow, the Wizard generated ActiveX component files now DO require that global to exist, but what objects should I be declaring in there ?

My DShow filters ? no-they are never instantiated via GUIDs / factories
The COleControl (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_mfc_colecontrol.asp) subclass I am building ? No- it is not a DirectShow class deriving from CUnknown, so I cannot declare it in the template.
You can shut up the linker errors by setting g_Templates to NULL and g_cTemplates to 0. A similar method - setting all the params of a single fake template to NULL - was also suggested in a different codeguru thread (http://www.codeguru.com/forum/showthread.php?s=&postid=847266#post847266), but unfortunately it does not work for me at least...either method will give a Object Reference not set to an instance of an object. error in Visual Basic when you try to instantiate one of these and it will actually hard crash the ActiveX Test Container App in Visual Studio, so that wont do. Likewise, when I use oleview.exe to check out my control (Start>Run...>oleview, then in the left hand side tree view, open Object Classes>Grouped by Component Category>Control>your control class name, whatever was specified in the IMPLEMENT_OLECREATE_EX macro. Then click on the little + sign to try to instantiate the control. I get a CoGetClassObject failed. The specified module could not be found. etc. error.)

If I revert to just the basic Wizard generated skeleton (dont link w my.lib, dont call any of its functions), the ocx functions just fine. I can instantiate it in VB2003, get/set parameters, etc.

The cat that drags in the g_Templates/g_cTemplates symbols is strmbase.lib (or strmbasd.lib for debug builds). The CFactoryTemplate class itself is defined in the DirectX include file combase.h (include streams.h)

But I can't figure out
why I need to suddenly declare them in my ActiveX Component Build (whereas in app builds or the static lib build I didn't) and second
what I should be filling the CFactoryTemplate WITH

I think a significant clue is the line
"If a call to the CoGetClassObject function finds the class object that is to be loaded in a DLL, CoGetClassObject uses the DLL's exported DllGetClassObject function. "
from MSDN's DllGetClassObject documentation. (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/cmf_d2l_48fo.asp).
I interpret this as "when creating a normal application or static library, CoGetClassObject generates the object differently than when creating a DLL/ocx. In the latter case, it gives the DLL control over object creation"
If you check in the Wizard generated .def file, you will indeed see a line exporting a DllGetClassObject function. I cannot however find an implementation of it in my Wizard generated files.
I speculate that use of the IMPLEMENT_OLECREATE_EX (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcmfc98/html/_mfc_implement_olecreate_ex.asp) macro in your xxxCtrl.cpp file has something to do with that (it is defined in VC98/MFC/Include/AFXCTL.H).




Any suggestions would be very helpful/welcome !
Thanks in advance


The Solution

Thanks to Google groups search (http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&safe=off&frame=right&th=bbb73e483fa5317f&seekm=uTp11m%23BAHA.249%40cppssbbsa05#link3) and Paul Wissenbach - quoting from his post:

The problem exists because you end up linking in strmbase.lib which has entry points functions for DllGetClassObject() and DllCanUnloadNow() among others. You really don't want these entry points
defined in for your ActiveX control. They are designed for DirectShow filters, and require g_Templates to be defined by your filter.

One solution is to override the following functions by implementing them into your ActiveX control yourself. That way you don't pull in the ones from the DShow.

Regards,


Paul


/
// DllGetClassObject

extern "C"
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return AfxDllGetClassObject(rclsid, riid, ppv);
}

/
// DllCanUnloadNow

extern "C"
STDAPI DllCanUnloadNow(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return AfxDllCanUnloadNow();
}


My hero ! The code compiles and links without farting, and it instantiates just fine in Visual Basic too !

你可能感兴趣的:(C++编程,templates,class,vc++,wizard,object,mfc)