Linker issue with DirectShow base class in mingw 64 bit - c++

After porting a project from visual studio to mingw. I am getting the following linker error
undefined reference to `g_Templates'
undefined reference to `g_cTemplates'
The code which it points to looks something like this
#include <tchar.h>
#endif // DEBUG
#include <strsafe.h>
#include <combase.h>
extern CFactoryTemplate g_Templates[];
extern int g_cTemplates;
HINSTANCE g_hInst;
DWORD g_amPlatform; // VER_PLATFORM_WIN32_WINDOWS etc... (from GetVersionEx)
OSVERSIONINFO g_osInfo;
//
// an instance of this is created by the DLLGetClassObject entrypoint
// it uses the CFactoryTemplate object it is given to support the
// IClassFactory interface
class CClassFactory : public IClassFactory, public CBaseObject
{
private:
const CFactoryTemplate *const m_pTemplate;
...
public:
CClassFactory(const CFactoryTemplate *);
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, __deref_out void ** ppv);
STDMETHODIMP_(ULONG)AddRef();
STDMETHODIMP_(ULONG)Release();
// IClassFactory
STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, __deref_out void **pv);
STDMETHODIMP LockServer(BOOL fLock);
// allow DLLGetClassObject to know about global server lock status
static BOOL IsLocked() {
return (m_cLocked > 0);
};
};
// --- COM entrypoints -----------------------------------------
//
// Call any initialization routines
//
void DllInitClasses(BOOL bLoading)
{
// traverse the array of templates calling the init routine
// if they have one
for (i = 0; i < g_cTemplates; i++) //<---------Cannot recognize this symbol
{
const CFactoryTemplate * pT = &g_Templates[i];
if (pT->m_lpfnInit != NULL)
{
(*pT->m_lpfnInit)(bLoading, pT->m_ClsID);
}
}
}
....
....
I have been searching on this issue for a while and have not made any progress. It seems that that this symbol exists in strmbasd.lib (debug version) and is generated from DirectShow base classes. I generated strmbasd.lib using mingw64 however I am still getting this linker error. I wanted to know if there was any other approach I could try .

I have used Direct Show for Microsoft Visual C++. And found no such issue. Microsoft SDK provides the libraries and headers as well as the base classes. You may want to check the link. I haven't used MingW, so I don't know about the issue of MingW. You may try it in MSVC, MSDN provides some handful informations and references for Direct Show. Please check the previous link mentioned above.

Your including dllentry.cpp/dllsetup.cpp from DirectShow BaseClasses assumes that you develop a filter library and you are expected to define template symbols in your code (example) to satisfy linker.
If you don't see how your code is referencing factories, you can define fake array and g_cTemplates of zero to pass through, however eventually there is something that makes linker drag these symbols into output.

Related

C++ and VBA: Building a registration-free COM DLL?

in short:
Is it possible to create a C++-based COM component that I can reference and use from VBA, without needing to register the DLL (in windows registry)?
In long:
I'm a COM novice, so maybe what I'm tryong to do here structurally doesn't work or doesn't make sense, but:
I want to create a C++ COM library that is usable from VBA registration-free.
So I've created an C++ ATL project in VS, added a custom COM type (MyClass) and added a test method to it ("AddNumbers", taking 2 long parameters and returning 1).
When building this project, I'm getting an error "Failed to register output. Please try anebling Per-User Redirection or register the component from a comment prompt with elevated permissions", likely because I'm running Visual Studio without admin permissions. However, the DLL builds fine, I assume it's just not registered after building it.
Right, so when I reference this DLL in my VBA project (Tools -> Referewnces -> Browse... and add), intellisesne works, i.e. VBA knows the type "MyClass", knows it has a method "AddNumbers" and so on.
But, it can't instantiate it:
Sub test()
Dim q As MyClass
Set q = New MyClass ' This will fail: "Run-time error '429': ActiveX component can't create object"
End Sub
Why is that? Am I right in assuming it likely fails because this COM component isn't properly registered on the machine?
If so, can I somehow circumvent this? I've read some infos about registration-free .NET based COM components, but I have no idea if this also works - or is even needed?! - for C++ based components.
MyClass.h
// MyClass.h : Declaration of the CMyClass
#pragma once
#include "resource.h" // main symbols
#include "ATLProject4_i.h"
#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."
#endif
using namespace ATL;
// CMyClass
class ATL_NO_VTABLE CMyClass :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CMyClass, &CLSID_MyClass>,
public IDispatchImpl<IMyClass, &IID_IMyClass, &LIBID_ATLProject4Lib, /*wMajor =*/ 0xFFFF, /*wMinor =*/ 0xFFFF>
{
public:
CMyClass()
{
}
DECLARE_REGISTRY_RESOURCEID(106)
BEGIN_COM_MAP(CMyClass)
COM_INTERFACE_ENTRY(IMyClass)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
return S_OK;
}
void FinalRelease()
{
}
public:
STDMETHOD(AddNumbers)(LONG Num1, LONG Num2, LONG* ReturnVal);
};
OBJECT_ENTRY_AUTO(__uuidof(MyClass), CMyClass)
MyClass.cpp
// MyClass.cpp : Implementation of CMyClass
#include "stdafx.h"
#include "MyClass.h"
// CMyClass
STDMETHODIMP CMyClass::AddNumbers(LONG Num1, LONG Num2, LONG* ReturnVal)
{
// TODO: Add your implementation code here
*ReturnVal = Num1 + Num2;
return S_OK;
}

Unresolved external symbol CLRCreateInstance

I wrote some native C++ code with the help of the Internet that loads the .NET Runtime and invokes a method that has the signature: public static int MethodNameHere(String pwzArgument) from a class in a managed assembly.
However, I can't seem to compile the code using Visual Studio into a native DLL (64-bit), because there seems to be a linking issue with CLRCreateInstance(), even though I am including "MetaHost.h" in the .cpp source file.
Here is the entire code:
#include "MetaHost.h"
extern "C" {
__declspec(dllexport) DWORD __stdcall CallManagedMethod(LPCWSTR managedDLLPath, LPCWSTR classPathInAssembly, LPCWSTR methodName, LPCWSTR parameter) {
// Bind to the CLR runtime..
ICLRMetaHost* pMetaHost = nullptr;
CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*) &pMetaHost);
ICLRRuntimeInfo* pRuntimeInfo = nullptr;
pMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID*) &pRuntimeInfo);
ICLRRuntimeHost* pClrRuntimeHost = nullptr;
pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*) &pClrRuntimeHost);
pClrRuntimeHost->Start();
// Okay, the CLR is up and running in this (previously native) process.
// Now call a method on our managed C# class library.
DWORD dwRet = 0;
pClrRuntimeHost->ExecuteInDefaultAppDomain(managedDLLPath, classPathInAssembly, methodName, parameter, &dwRet);
// Don't forget to clean up.
pClrRuntimeHost->Release();
pRuntimeInfo->Release();
pMetaHost->Release();
return dwRet;
}
}
Any help?
A .h file does not solve a linking problem, it merely adds them. The MSDN article you linked to fumbles the usual way that include and link hints are documented, "Included as a resource" is quite unhelpful. In C++ you have to link mscoree.lib to get the symbol resolved. It is the import library for mscoree.dll and included in the SDK.
Simplest way is to add #pragma comment(lib, "mscoree.lib") after your #include.

x64 DLL export function names

I am trying to port a 32-bit dll (and application) to 64-bit and I have managed to build it without errors. When trying to load it with my 64-bit application I noticed that the exported function names differ. This is how I export the functions:
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) long __stdcall Connect(char * name, long size);
#ifdef __cplusplus
}
#endif
In Dependency Walker the exported functions have the following format:
32-bit: _Connect#8
64-bit: Connect
In the application using the dll I explicitly load the dll (LoadLibrary is successful) but GetProcAddress fails for 64-bit because it cannot find a function with the provided name.
In our application I keep the function names as follows:
#define ConnectName "_Connect#8"
...
GetProcAddress(Dll, ConnectName);
So I was wondering if it is possible to export the same function names for both 32-bit and 64-bit dlls or is this a bad idea? Or do I need to do the following in my applications:
#if _WIN64
#define ConnectName "Connect"
#else
#define ConnectName "_Connect#8"
#endif
I appreciate any help.
An option you have to export function names without any decoration (independently from the particular calling convention you used in x86, __stdcall, __cdecl, or other) and with the same undecorated name in both x86 and x64 builds, is to export your DLL functions using DEF files.
E.g. you could add a .DEF file like this to your project:
LIBRARY YOURDLL
EXPORTS
Connect #1
AnotherFunction #2
... etc. ...
Repro Follows
Create an empty solution in Visual Studio (I used VS2013), and inside that create an empty Win32 console project (the test client) and an empty Win32 DLL project (the test DLL).
Add this NativeDll.def .DEF file in the DLL project:
LIBRARY NATIVEDLL
EXPORTS
SayHello #1
Add this NativeDll.cpp C++ source code in the DLL project:
///////////////////////////////////////////////////////////////////////////////
//
// NativeDll.cpp -- DLL Implementation Code
//
///////////////////////////////////////////////////////////////////////////////
#include <Windows.h>
#include <atldef.h>
#include <atlstr.h>
//
// Test function exported from the DLL
//
extern "C" HRESULT WINAPI SayHello(PCWSTR name)
{
//
// Check for null input string pointer
//
if (name == nullptr)
{
return E_POINTER;
}
try
{
//
// Build a greeting message and show it in a message box
//
CString message;
message.Format(L"Hello %s from the native DLL!", name);
MessageBox(nullptr, message, L"Native DLL Test", MB_OK);
// All right
return S_OK;
}
//
// Catch exceptions and convert them to HRESULT codes
//
catch (const CAtlException& ex)
{
return static_cast<HRESULT>(ex);
}
catch (...)
{
return E_FAIL;
}
}
Add this NativeClient.cpp C++ source code in the client test project:
///////////////////////////////////////////////////////////////////////////////
//
// NativeClient.cpp -- EXE Test Client Code
//
///////////////////////////////////////////////////////////////////////////////
#include <Windows.h>
//
// Prototype of the function to be loaded from the DLL
//
typedef HRESULT (WINAPI *SayHelloFuncPtr)(PCWSTR /* name */);
//
// Simple RAII wrapper on LoadLibrary()/FreeLibrary().
//
class ScopedDll
{
public:
//
// Load the DLL
//
ScopedDll(PCWSTR dllFilename) throw()
: m_hDll(LoadLibrary(dllFilename))
{
}
//
// Unload the DLL
//
~ScopedDll() throw()
{
if (m_hDll)
{
FreeLibrary(m_hDll);
}
}
//
// Was the DLL loaded successfully?
//
explicit operator bool() const throw()
{
return (m_hDll != nullptr);
}
//
// Get the DLL handle
//
HINSTANCE Get() const throw()
{
return m_hDll;
}
//
// *** IMPLEMENTATION ***
//
private:
//
// The wrapped raw DLL handle
//
HINSTANCE m_hDll;
//
// Ban copy
//
private:
ScopedDll(const ScopedDll&) = delete;
ScopedDll& operator=(const ScopedDll&) = delete;
};
//
// Display an error message box
//
inline void ErrorMessage(PCWSTR errorMessage) throw()
{
MessageBox(nullptr, errorMessage, L"*** ERROR ***", MB_OK | MB_ICONERROR);
}
//
// Test code calling the DLL function via LoadLibrary()/GetProcAddress()
//
int main()
{
//
// Return codes
//
static const int kExitOk = 0;
static const int kExitError = 1;
//
// Load the DLL with LoadLibrary().
//
// NOTE: FreeLibrary() automatically called thanks to RAII!
//
ScopedDll dll(L"NativeDll.dll");
if (!dll)
{
ErrorMessage(L"Can't load the DLL.");
return kExitError;
}
//
// Use GetProcAddress() to access the DLL test function.
// Note the *undecorated* "SayHello" function name!!
//
SayHelloFuncPtr pSayHello
= reinterpret_cast<SayHelloFuncPtr>(GetProcAddress(dll.Get(),
"SayHello"));
if (pSayHello == nullptr)
{
ErrorMessage(L"GetProcAddress() failed.");
return kExitError;
}
//
// Call the DLL test function
//
HRESULT hr = pSayHello(L"Connie");
if (FAILED(hr))
{
ErrorMessage(L"DLL function call returned failure HRESULT.");
return kExitError;
}
//
// All right
//
return kExitOk;
}
Build the whole solution (both the .EXE and the .DLL) and run the native .EXE client.
This is what I get on my computer:
It works without modifications and with the undecorated function name (just SayHello) on both x86 and x64 builds.
__stdcall is not supported (and is ignored) on x64. Quoting MSDN:
On ARM and x64 processors, __stdcall is accepted and ignored by the compiler; on ARM and x64 architectures, by convention, arguments are passed in registers when possible, and subsequent arguments are passed on the stack.
The calling convention on x64 is pretty much __fastcall.
Since the calling conventions and name decoration rules on x86 and x64 differ, you have to abstract this somehow. So your idea with #if _WIN64 goes in the right direction.
You can examine x86 calling conventions and your needs and perhaps devise a macro which could automate the name selection process.
As you can tell, in 64-bit Windows names are not decorated.
In 32-bit __cdecl and __stdcall symbols, the symbol name is prepended by an underscore. The trailing '#8' in the exported name for the 32-bit version of your example function is the number of bytes in the parameter list. It is there because you specified __stdcall. If you use the __cdecl calling convention (the default for C/C++ code), you won't get that. If you use __cdecl, it makes it much easier to wrap GetProcAddress() with something like:
#if _WIN64
#define DecorateSymbolName(s) s
#else
#define DecorateSymbolName(s) "_" ## s
#endif
then just call with
pfnConnect = GetProcAddress(hDLL, DecorateSymbolName("Connect"));
pfnOtherFunc = GetProcAddress(hDLL, DecorateSymbolName("OtherFunc"));
or something similar (error checking omitted in example).
To do this, remember to declare your exported functions as:
__declspec(dllexport) long __cdecl Connect(char * name, long size);
__declspec(dllexport) long __cdecl OtherFunc(int someValue);
In addition to being easier to maintain, if during development the signature of an exported function changes, you don't have to screw around with your #define wrappers.
Downside: if during development the number of bytes in a given function's parameter list changes, it will not be caught by the application importing the function because the changing the signature will not change the name. Personally, I don't think this is an issue because the 64-bit build would blow up under the same circumstances anyway as the names are not decorated. You just have to make sure your application is using the right version of the DLL.
If the user of the DLL is using C++, you can wrap things in a better way using C++ capabilities (wrap the entire explicitly-loaded library in a wrapper class, e.g.):
class MyDLLWrapper {
public:
MyDLLWrapper(const std::string& moduleName); // load library here
~MyDLLWrapper(); // free library here
FARPROC WINAPI getProcAddress(const std::string& symbolName) const {
return ::GetProcAddress(m_hModule, decorateSymbolName(symbolName));
}
// etc., etc.
private:
HMODULE m_hModule;
// etc.
// ...
};
There's actually a lot more you can do with a wrapper class like this, it's just an example.
On edit: since OP mentioned using PInvoke in the comments - if anyone decides to do this, do not forget to add CallingConvention = CallingConvention.Cdecl in the [DllImport] declaration when using PInvoke. __cdecl might be the default for unmanaged C/C++, but is not the default for managed code.
For Win32 build:
If you use __stdcall, you will get something like this (dumped with dumpbin /exports):
__declspec(dllexport) int __stdcall
->
ordinal hint RVA name
1 0 00001240 _F1#0 = _F1#0
2 1 0000124D _F2#0 = _F2#0
And you have to use GetProcAddress("_F1#0") to locate the function pointer.
If you use __cdecl, you will get something like this:
__declspec(dllexport) int __cdecl
->
ordinal hint RVA name
1 0 00001240 F1 = _F1
2 1 0000124D F2 = _F2
And you can use GetProcAddress("F1") to locate the function pointer.
BTW, if you add a XXX.def file to your Visual Studio project. One more link option will be silently added to your linker command line /DEF:"XXX.def" in the All Options window. And if you change your .def file name later for whatever reason, this link option doesn't change accordingly. You need to manually change the def file name in the project properties window.

Getting IDL (for TLB) from a COM+ dll when it is not provided

I have a .dll that contains some directshow filters (COM) with specific/custom interfaces to query.
Most 3rd party directshow components contain embedded .tlb files that can be used for cross-enviroment communication (C# typelib import).
I would hate to have to attempt to manually create the interfaces needed for c# because no idl/tlb files were provided.
Is it possible to generate a tlb (or at least, an idl, which I can MIDL compile) from a COM .dll?
Yes, it is possible to reverse engineer/disassemble IDL (or something very close to it). What you need to do is give yourself a new C++ Console Project which gives the default code of
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}
and then you insert an #import statement underneath the #include statement. So I have been playing with C# assembly marked up to function as a COM Interop DLL and I have called it ComExample2 and it lives in the same solution as the C++ console project that I added which means I can use a nice relative pathname. So my #import statement looks like
#import "..\ComExample2\bin\Debug\ComExample2.tlb" no_namespace named_guids
Then you build your console application. If you delve into the files generated during the build you will find a file that ends with .TLH which stands for type library header. So my path is
..\ComExample2\ConsoleApplication1\Debug\comexample2.tlh
Inside my file is something which looks very much like idl. Here is an edited snippet to give you a flavour....
struct __declspec(uuid("515b1b18-1602-4d42-b743-f1b3c458a0d0"))
/* LIBID */ __ComExample2;
struct /* coclass */ ComExampleClass2;
//
// Type library items
//
struct __declspec(uuid("713007fe-e74c-4fec-b91a-5ef8df279929"))
IFoo : IDispatch
{
//
// Wrapper methods for error-handling
//
_bstr_t Greeting ( );
long Sim (
long a,
long b );
//
// Raw methods provided by interface
//
virtual HRESULT __stdcall raw_Greeting (
/*[out,retval]*/ BSTR * pRetVal ) = 0;
virtual HRESULT __stdcall raw_Sim (
/*[in]*/ long a,
/*[in]*/ long b,
/*[out,retval]*/ long * pRetVal ) = 0;
};
struct __declspec(uuid("efe233b5-8ab3-4414-855e-1f027e0a72d5"))
ComExampleClass2;
// interface _Object
// [ default ] interface IFoo
All of this is generated code so that you can script C++ code against a COM library easily. You'll have to pick through what you need but hopefully that should be enough.
Kind regards,
Lord BattenBerg

COM - Implementing DllGetClassObject

I am attempting to understand creating/using COM components without the help of MFC/ATL to know its inner workings.
I am using this codeguru article for reference.Following are the steps followed by me.
Created a Wind32 Dll,
Added a MIDL file and declared the interface IAdd and library name DemoMath; compiled the code using MIDL compiler.
Created CAddObj class deriving IAdd interface,provided implementation for IAdd and IUnknown interfaces.
Created class CAddFactory deriving from IClassFactory interface;provided implementation for IClassFactory methods.
Now creating DllGetClassObject to give client an option to invoke this function to get an instance of the class factory.
Following is the code:
#include "stdafx.h"
#include <objbase.h>
#include "AddObjFactory.h"
#include "IAdd_i.c"
STDAPI DllGetClassObject(const CLSID& clsid,
const IID& iid,
void** ppv)
{
//
//Check if the requested COM object is implemented in this DLL
//There can be more than 1 COM object implemented in a DLL
//
if (clsid == CLSID_AddObject)
{
//
//iid specifies the requested interface for the factory object
//The client can request for IUnknown, IClassFactory,
//IClassFactory2
//
CAddFactory *pAddFact = new CAddFactory;
if (pAddFact == NULL)
return E_OUTOFMEMORY;
else
{
return pAddFact->QueryInterface(iid , ppv);
}
}
//
//if control reaches here then that implies that the object
//specified by the user is not implemented in this DLL
//
return CLASS_E_CLASSNOTAVAILABLE;
}
Now where is CLSID_AddObject constant suppose to be defined
or Is it generated while compiling MIDL file(I didn't find it though)?
coclass IDL item will typically get you CLSID:
library Foo
{
//...
[
//...
]
coclass AddObject
{
//...
};
then on your "IAdd_i.c" you are already including:
MIDL_DEFINE_GUID(CLSID, CLSID_AddObject, ...);
this is what defines CLSID_AddObject.