using activex dll in vc++ win32 project - dll

i have got a ScreenCameraSDK and it comes with a 11kb dll file, it has a documentation too which lists the functions which can be used. It says
ScreenCamera SDK ActiveX Reference Documentation
ActiveX Reference
The ActiveX ID on the system is: ScreenCameraSDK.RemoteControl
Every method on the interface returns FAIL or SUCCESS. (0 or 1).
Create an instance of the ActiveX on your application, and then call InitializeScreenCameraRemoteControl. If the return value is SUCCESS then ScreenCamera is properly installed and you can then call any other method on the ActiveX's interface. If not ScreenCamera could not be found and you should contact support.**
Now my question is, i have the dll and no other files. How can i use the functions inside it in a VC++ Project with Visual Studio 2008.
Thanks
I TRIED THE FOLLOWING CODE BUT GOT COMPILATION ERROR OF UNDEFINED IDENTIFIER
#include <stdio.h>
// This is the path for your DLL.
// Make sure that you specify the exact path.
#import "e:\ScreenCameraSDK.dll" no_namespace
void main()
{
BSTR bstrDesc;
try
{
CoInitialize(NULL);
short st = 2;
short st1;
// Declare the Interface Pointer for your Visual Basic object. Here,
// _Class1Ptr is the Smart pointer wrapper class representing the
// default interface of the Visual Basic object.
_Class1Ptr ptr;
// Create an instance of your Visual Basic object, here
// __uuidof(Class1) gets the CLSID of your Visual Basic object.
ptr.CreateInstance(__uuidof(Class1));
st1 = ptr->MyVBFunction(&st);
}
catch(_com_error &e)
{
bstrDesc = e.Description();
}
CoUninitialize();
}
it says _Class1Ptr is unknown!

BSTR bstrDesc;
try
{
HRESULT hr= CoInitialize(NULL);
CLSID clsid;
hr = CLSIDFromProgID(OLESTR("<complete class name as see in registry>"),&clsid);
short st = 2;
short st1;
//nameOfClassInOCX is placeholder for explanation. If you OCX com class name is blabla
//use _blabla and so on.
_nameOfClassInOCX * ptr;
hr = CoCreateInstance(clsid,NULL,CLSCTX_INPROC_SERVER,__uuidof(_nameOfClassInOCX ),(LPVOID*)&ptr);
cout << ptr->GetFees("hi") <<endl;
ptr->Release();
}
catch(_com_error &e)
{
bstrDesc = e.Description();
}
CoUninitialize();

First of all you have to do this is #import the dll, and the compiler will automatically generate all required definitions from it. Then create objects from the library by using either smart pointers, or CreateInstance().
#import "C:\files\test.dll" no_namespace rename("EOF", "EOFile")
...
int main() {
if (FAILED(::CoInitialize(NULL)))
return 0;
........
::CoUninitialize();
return 0;
}

Related

DLL gives Abnormal program termination on creating ADO object

I have a few datamodules, created with C++ Builder 6. Each of them uses another datamodule that initializes the connection with the database. I'm trying to make a DLL out of those datamodules.
The error is thrown on creation of DataModule_Users and says 'Abnormal program termination'.
Where do I go wrong?
Thanks in advance
datamodule_dll.bpf
USEFORM("DataModule_Connection.cpp", DataModule_Connection); /* TDataModule: File Type */
USEFORM("DataModule_Users.cpp", DataModule_Users); /*TDataModule: File Type */
//------------------------------------------------------------------
This file is used by the project manager only and should be treated like the project file
DllEntryPoint
datamodule_DLL.cpp
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
return 1;
}
extern "C" __declspec(dllexport) const char * GetUserName(const char * ID);
const char * GetUserName(const char * ID) {
CoInitialize(NULL); // datasets use COM
// This is used by DataModule_Users (normally this is done with Application->CreateForm();
DataModule_Connection = new DataModule_Connection( 0 /* Owner */ );
DataModule_Users = new DataModule_Users( 0 /* Owner */ );
return DataModule_Users->GetUserName(ID);
}
I will quote Remy Lebeau:
COM is initialized on a per-thread basis. Once a thread's COM model
(apartment vs multithreaded) has been set, it cannot be changed later.
If your DLL calls CoInitialize() before the caller does, your
parameters would take priority, which might not meet the caller's
needs. If you want to control the COM settings for your DMs without
affecting the caller, you have to move the DMs to their own thread.
Besides, DllEntryPoint() is not an appropriate place to initialize
them anyway. The OS restricts what DllEntryPoint() is allowed to do.
This solved the issue. I had to call coInitialize() before I load the library.

Managed C++, Object reference not set to an instance of an object

I've run into this problem before, but never in a situation like this. I'm completely confused. As the question states, I'm getting the runtime error "Object reference not set to an instance of an object." Using the debugger tools, I think I've pinpointed the problem to this line:
dataFileLocation = path;
The entire function is here:
void DATReader::SetPath(String^ path)
{
if(!File::Exists(path))
{
MessageBox::Show( "DATReader (missing dat file: \n"+path+"\n )", "Error", MessageBoxButtons::OK, MessageBoxIcon::Exclamation);
return;
}
dataFileLocation = path;
}
dataFileLocation is declared here, but nothing is assigned to it:
ref class DATReader
{
private:
System::String^ dataFileLocation;
// ...
}
Now I know the reason I'm getting the error is because dataFileLocation is assigned to nothing. But I'm having problems assigning it. When I add = 0; to it, it won't build because its a ref class. When I try to assigned it to = 0; in the constructor, it yells at me for trying to convert it from a System::String^ to an int. If I assign it to a = gcnew String(""); it builds, but throws the same runtime exception.
I don't get it, am I reading the debugger wrong, and this isn't the source of the problem at all? I've just started to use managed code recently, so I'm confused :\
You may want to check and make sure your DATReader object isn't null as well It may be throwing the exception at your DATReader.SetPath() call.
This is a nicety in C# that's missing in C++/CLI. C# generates code that ensures this can never be null. Easily seen in the debugger by setting a breakpoint on the method and inspecting "this". Here's an example program that reproduces the exception:
#include "stdafx.h"
using namespace System;
ref class Example {
String^ dataFileLocation;
public:
void SetPath(String^ path) {
dataFileLocation = path; // Set breakpoint here and inspect "this"
}
};
int main(array<System::String ^> ^args)
{
Example^ obj /* = gcnew Example */;
obj->SetPath("foo");
return 0;
}
Remove the /* */ comments to fix. Fix your code by looking at the call stack to find the method that forgot to instantiate the object.
Managed C++ uses nullptr for null references. So you can check:
if (path == nullptr) { ... }
or use:
if (!String::IsNullOrEmpty(path))

com : use an unregistered dll

I have hooked the cocreateinstance() function.
When it's called with a specific CLSID, I want to use my dll instead the dll system.
So here is my code :
HOOK_CoCreateInstance(rclsid,pUnkOuter,dwClsContext,riid,*ppv){
...
if(myCLSID){
module = LoadLibrary(mydll);
dllGetClassObject = (FUNC)GetProcAddress(module,"DllGetClassObject");
hr = dllGetClassObject(rclsid, IID_IClassFactory, &pClassFactory);
hr = pClassFactory->CreateInstance(NULL,IID_IUnknown, (void**)&data_source);
return hr;
}
else{
hr = CoCreateInstanceReal(rclsid,pUnkOuter,dwClsContext,riid,ppv);
return hr;
}
}
But it's not working.
I think the problem is in pClassFactory::CreateInstance(), with the second parameter :
I don't know how to retrieve automatically the REFIID of my dll.
And if I use riid it's not working either.
So if anyone has an idea,
Thanks !
If you want to follow proper COM conventions, you'll need to handle the CoCreateInstance parameters correct (as documented here).
The __in REFIID riid parameter is the GUID of the interface you want to use, not the DLL itself. The CLSID parameter is the class of the object, which you should know ahead of time. Because you want to return the expected interface, you really only need to know the CLSID of your new implementation (coclass) and call using that.
A simpler, but not quite COM-spec, method would be to export a factory from your DLL:
__declspec(dllexport) MyObject * CreateObject()
{
return new MyObject();
}
and call that from your wrapper:
HOOK_CoCreateInstance(rclsid,pUnkOuter,dwClsContext,riid,*ppv)
{
if(myCLSID)
{
module = LoadLibrary(mydll);
dllCreate = (FUNC)GetProcAddress(module,"CreateObject");
*ppv = dllCreate();
return S_OK;
} else {
hr = CoCreateInstanceReal(rclsid,pUnkOuter,dwClsContext,riid,ppv);
return hr;
}
}

Exposing a managed COM local server - E_NOINTERFACE

Im trying to expose a local server that is written in C# to unmanaged code to allow interop! The managed code looks like that:
[Guid("A0D470AF-0618-40E9-8297-8C63BAF3F1C3")]
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IMyLocalInterface
{
void LogToServer(string message);
}
[Guid("9E9E5403-7993-49ED-BAFA-FD9A63A837E3")]
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class MyLocalClass : IMyLocalInterface
{
public MyLocalClass()
{
Console.WriteLine("Object created!");
}
public void LogToServer(string message)
{
Console.WriteLine("Log > " + message);
}
}
class Program
{
[MTAThread]
static void Main(string[] args)
{
var srv = new RegistrationServices();
var cookie = srv.RegisterTypeForComClients(typeof(MyLocalClass), RegistrationClassContext.LocalServer | RegistrationClassContext.RemoteServer, RegistrationConnectionType.MultipleUse);
Console.ReadLine();
srv.UnregisterTypeForComClients(cookie);
}
}
And my unmanaged code does the following:
#import "ManagedLocServer.tlb" no_namespace raw_interfaces_only
int _tmain(int argc, _TCHAR* argv[])
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
{
IMyLocalInterfacePtr ptr;
ptr.CreateInstance(__uuidof(MyLocalClass));
ptr->LogToServer(L"Initializing...");
}
CoUninitialize();
return 0;
}
After debugging ive seen that CoCreateInstance works without any problems, that means "Object created" is printed into the managed servers console. But then QueryInterface on that object fails with E_NOINTERFACE. Im a bit confused why this happens. Is it a problem with registration (i only have a LocalServer32 entry for my CLSID)? Is it a problem within my managed code? Would be nice if someone could give me a hint :)
Greetings
Joe
You are using out-of-process COM. That requires marshaling support, to make a method call the arguments of the method need to be serialized. That's normally done by building the proxy/stub DLL from the code generated by midl.exe from the .idl file. Or by using the standard marshaller which works with the type library. Both require registry entries in HKCR\Interface
You get the E_NOINTERFACE because COM cannot find a marshaller. This is trivial to solve if you have an .idl file but you don't, the server is implemented in .NET. No idea how to solve this, I never tried to make this work. A remote possibility is that the CLR interop layer provides marshaling support. But you'd surely at least have to use ComInterfaceType.InterfaceIsDual. This is just a guess. If I tried to make this work, I'd start from an .idl first.

How do I use WTL in a DLL?

I'm trying to use WTL within an in-process COM server DLL (an IE BHO), but am struggling with _Module.
My DLL needs CMyModule derived from CAtlDllModuleT<>:
class CMyModule : public CAtlDllModuleT< CMyModule >
{
public:
DECLARE_LIBID(LIBID_MyLib)
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_MYPROJ, "{...}")
};
CMyModule _Module;
extern "C" BOOL WINAPI DllMain(...)
{
hInstance;
return _Module.DllMain(dwReason, lpReserved);
}
...
STDAPI DllUnregisterServer(void)
{
return _Module.DllUnregisterServer();
}
But this conflicts with most WTL examples, which require something like this within stdafx.h:
extern CAppModule _Module; // WTL version of CComModule
No matter which way I do it, I (unsurprisingly) get compile errors. CMyModule derived from CAppModule borks on _Module.DllUnregisterServer(), etc. CMyModule derived from CAtlDllModuleT<> borks on code like _Module.GetMessageLoop().
Any good references on how WTL is supposed to work within a DLL? Google finds lots of questions, with few answers.
I have a project that uses WTL in a DLL. I looked at how my headers are set up and it looks like I hacked around this same problem...
I have my module set up like your sample code inheriting from CAtlDllModuleT<> except the name of the global module variable is _AtlModule rather than _Module. For example:
class CMyModule : public CAtlDllModuleT< CMyModule >
{
public:
DECLARE_LIBID(LIBID_MyLib)
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_MYPROJ, "{...}")
};
CMyModule _AtlModule;
So, all of the DllMain.cpp entry points use _AtlModule. Then in the stdafx.h file it looks like this:
// WTL includes
#define _Module (*_pModule)
#include <atlapp.h>
#include <atlctrls.h>
#include <atldlgs.h>
#undef _Module
That _pModule thing is defined in atlbase.h like:
__declspec(selectany) CComModule* _pModule = NULL;
There must be a better way, but this does work.
Have you considered the option of multiple inheritance? Try inheriting from both CAtlDllModule and CAppModule since you need both.
I use WTL in an Office add-in; the following works for me. (At the bottom of stdafx.h)
class DECLSPEC_UUID("XXXX-...") MyLib;
using namespace ATL;
/*
* Application module
*/
class CAddInModule : public CAtlDllModuleT< CAddInModule >
{
public:
CAddInModule() : m_hInstance(NULL)
{
}
DECLARE_LIBID(__uuidof(MyLib))
HINSTANCE GetResourceInstance()
{
return m_hInstance;
}
void SetResourceInstance(HINSTANCE hInstance)
{
m_hInstance = hInstance;
}
private:
HINSTANCE m_hInstance;
};
extern CAddInModule _AtlModule;
And then the DLL main use _AtlModule:
// DLL Entry Point
extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
_AtlModule.SetResourceInstance(hInstance);
return _AtlModule.DllMain(dwReason, lpReserved);
}
// Used to determine whether the DLL can be unloaded by OLE
STDAPI DllCanUnloadNow(void)
{
return _AtlModule.DllCanUnloadNow();
}
// Returns a class factory to create an object of the requested type
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
}
// DllRegisterServer - Adds entries to the system registry
STDAPI DllRegisterServer(void)
{
// registers object, typelib and all interfaces in typelib
HRESULT hr = _AtlModule.DllRegisterServer();
return hr;
}
// DllUnregisterServer - Removes entries from the system registry
STDAPI DllUnregisterServer(void)
{
HRESULT hr = _AtlModule.DllUnregisterServer();
return hr;
}