Reusing the web browser control - c++

I have a pure Win32 application (no MFC, etc.) to which I want to add a web browser control in a window. I know the basics of COM and can create a COM object for the browser using
hr = CoCreateInstance(
CLSID_WebBrowser,
NULL,
CLSCTX_INPROC,
IID_IWebBrowser2,
(void**) &pWebBrowser);
However, apparently one needs to call SetClientSite, passing an IOleClientSite*. How do I obtain such an interface? This example implements its own browser class, which provides the interface by deriving from it and implementing it (here). I tried to go along that path, but in order to instantiate the browser class, I would have to register it (no?). This seems awfully complicated - I just want to use an existing COM object, not implement and register my own. What am I missing?
Assuming I do implement my own ClientSite class as part of my application, is it possible to not register it, and just instantiate it by calling new ClientSite (and then fetch the interface as using QueryInterface)? Will this work, or is it mandatory to call CoCreateInstance?

There is an example on CodeGuru and another on CodeProject which contains the simplest implementation for hosting a web browser control implemented in pure C. You do have to implement your own IOleClientSite, but it is one of the easier classes to implement. Yes, it is mandatory to call CoCreateInstance or OleCreate to create the instance of the web browser control.
http://www.codeguru.com/cpp/i-n/ieprogram/article.php/c4379/Display-a-Web-Page-in-a-Plain-C-Win32-Application.htm
http://www.codeproject.com/Articles/3365/Embed-an-HTML-control-in-your-own-window-using-pla

Try WTL (header only library from MS). Install its project templates. Create a new WTL project from template and select "web browser" control option (or whatever is the name). Now you can investigate generated sources or (my personal recommendation) move your stuff into this project

I'm not sure what exactly you're trying to do ...
... but I'd start by trying to use a simple ShellExecute(), if at all possible:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb762153%28v=vs.85%29.aspx
http://support.microsoft.com/kb/224816

Related

Are IShellWindows and IWebBrowser2 objects always out of process?

I've been experimenting with instantiating CLSID_ShellWindows, and so far I've had luck only when using CLSCTX_LOCAL_SERVER. Even when I try creating it from within Explorer itself (after setting a hook and injecting a DLL), it works only when instantiated as an out-of-process object.
I was wondering if it's ever possible to obtain an in-process version of the shell windows and their related objects. Like for example, if you implement a browser helper object or Explorer toolband, and you obtain an IWebBrowser2 object/interface using the site pointer provided through SetSite, will that be an in-process object, or is that out of process as well?

Use _COM_SMARTPTR CreateInstance without Registration within the same DLL

I'm currentyl trying to write a DLL which consumes a Typelib (.tlb) registered in the system. This Typelib requires that I implement two interfaces with my own classes, and register one of them within the Running Object Table, which I did in an ATL project using Visual Studio 2015.
The Application that consumes my DLL should have no knowledge of COM at all, everything should work there behind the scenes and hidden by the DLL I'm implementing.
Within my DLL, at some point I'm trying to get Instances of a clas MyClass which implements the above mentionend COM-Interfaces of the Typelib. The code looks like this:
IInterfaceClassPtr dataPtr;
hr = dataPtr.CreateInstance(CLSID_MyClass);
IInterfaceClassPtr is actually a Macro (all of this is generated by Visual Studio), which looks like this:
_COM_SMARTPTR_TYPEDEF(IExampleInterface, __uuidof(IExampleInterface));
IExampleInterface is defined in the Typelib I consume, and implemented by MyClass.
If I'm registering my own DLL using regsvr32, everything works fine. But I want to avoid that because it requires Admin privileges.
If my DLL is not registered, the above call fails with HRESULT "0x80040154, Class is not registered". I read the article Registration free activation of COM-Components (And a few others). But I can't tweak the consuming applications' manifest here - the class (MyClass) I'm trying to activate lives in the very same DLL as the mentioned "CreateInstance" call.
What do I need to do to be able to Create Instances of these Classes without using regsvr32 or some Manifest-Tweaking?
You can create concrete instances of your objects directly within your DLL (assuming the classes are implemented there).
CComObject<CMyClass>* pMyClassPtr;
CComObject<CMyClass>::CreateInstance(&pMyClassPtr);
pMyClassPtr->AddRef();
CComObject<T>::CreateInstance creates an instance of a COM object by directly calling new CComObject<T> so it bypasses the registry.
You can then use QueryInterface on the object to get your required interface.
IInterfaceClassPtr spIInterface;
pMyClassPtr->QueryInterface(&spIInterface);

COm server accessing the application

I have written a simple dialog based MFC application using a thirdd party soft tree control. I am trying to write a automation client for the application. For this I wrote a singleton out-of-process COM Testing Agent for the dialog based application sample app. The Com server exposes a Run method to the automation client. This Run method access the gut of the mfc app and actually mimicks a click on the GUI. The problem i am facing is when the automation client tries to invoke Run method on the Com object it is able to invioke it but when the Run method crashes when it tries to access the control's methods such as getCaretInedx.
I have tried to cach the exception and log the message to a file but have not been able to do so.
My question is: Is there any limitation in the way a com object can access the application? Or am i missing anything to facilitate this.
Any help or pointer is greatly appreciated. Since this is my first in COM I have not been able to make much progress.
Thanks
Is your client's window actually being created? If not, the hwnd doesn't exist, which is probably why it crashes. Furthermore, your client may be hidden behind another window when it is started, and may exhibit different behavior than when the user called it through regular interaction.
In general, calling code that relies on or interacts with the UI from a COM server is fraught with peril, especially when that code is not written in the first place to behave like this. Most UI isn't that defensive about HWND's existing etc.

How do you create a COM DLL in Visual Studio 2008?

It's been ages since I've written a COM dll. I've made a couple of classes now, that inherit from some COM interfaces, but I want to test it out. I know I have to put a GUID somewhere and then register it with regsvr32, but what are the steps involved?
Edit: Sorry, forgot to mention I'm using C++.
To create a new ATL COM project you can proceed as follow:
File/New Project
Visual C++/ATL/ATL Project
Customize it settings, and press finish when done
You have created a new dll, but it is empty, to add a COM object you can do this:
Project/Add Class
Visual C++/ATL/ATL simple object, press add
Give the name you want (like MyObject), and press finish to add it
If you want that an object implement an interface
In the class view select the object class (CMyObject)
Right click/Add/Implement Interface...
You can select which Interface will implement
From an .idl file already in your projects files
From a .tlb/.dll/.exe which have a type library embedded
From an object already registered
When done press finish
PS: It is much easier to create a new ATL project with the same name in a different folder, and add the files you have customized. The wizard does several tasks and create several customized files.
For larger projects that are difficult to add file by file, I do the same but instead of adding my files to the new project I start copying the settings from the new projects to the old one, and adding any additional file that the wizard has created and fixing headers like stdafx.h to merge the new settings.
PPS: If you want that your dll to support MFC, instead of selecting ATL Project you have to select MFC/MFC Dll. When you add the ATL Simple Object the wizard will ask to add ATL support to the project.
You need to write a function called DllGetClassObject and export it. That function is responsible for allocating a "class factory", which you also have to write, and which is in turn capable of allocating instances of your COM object. It has to implement IClassFactory.
It's not too hard to do. The alternative is to use ATL (see xhantt's answer) which in theory does this for you, but in practice it's a real mess. Somehow it manages to encapsulate the complexity of COM inside an abstraction layer that is even more complicated. Good luck trying to move an object between DLLs for example.
But you could run the ATL wizard just to see an example of how to declare DllGetClassObject. Implementing IClassFactory is very easy - just one method that news-up an object.
Then you need to register your DLL - i.e. put keys into the registry. The regsvr32 tool cannot do this without further help from you. You have to write and export another function called DllRegisterServer, which does all the hard work. All that regsvr32 does is load the DLL, look up DllRegisterServer and call it.
Again, ATL has a way of implementing this for you, but it does it by reading a kind of script full of registry modification instructions, stored in an .rgs file that gets embedded into your DLL's resources. If you accidentally put any kind of syntax error into this file, the registration fails silently.
So again, you may actually find it simpler to write a few lines of code to tweak the registry yourself. Here are the details.
If you used C# instead, you wouldn't have any of these problems. Everything is encapsulated very cleanly. It actually works much better than C++ as a tool for developing COM objects.
When you build the solution, it automatically registers the dll.
And also it creates two files _i.c and .h file.
To test the dll create the sample application:
Create sample Win32 application. Include the _i.c and .h in the cpp file of the win32 application which has main function
Call CoInitialize();
Declare a interface pointer
CComPtr pMyInterface = NULL; // where IMyInterface is declared in _i.c
Create the instance
pMyInterface.CoCreateInstance(CLSID_MyClass); // CLSID_MyClass is GUID representing the
CoClass
Call the APIs present in the Interface
Call CoUnInitialize();

How to host licensed .Net controls in unmanaged C++ app?

I need to host and run managed controls inside of a purely unmanaged C++ app. How to do this?
To run unlicensed controls is typically simple:
if (SUCCEEDED(ClrCreateManagedInstance(type, iid, &obj)))
{
// do something with obj
}
When using a licensed control however, we need to somehow embed a .licx file into the project (ref application licensing). In an unmanaged C++ app, the requisite glue does not seem to work. The lc.exe tool is supposed to be able to embed the license as an assembly resource but either we were not waving the correct invocation, or it failed silently. Any help would be appreciated.
The answer depends on the particular component you're using. Contact your component help desk OR read up the documentation on what it takes to deploy their component.
Basically component developers are free to implement licensing as they deem fit. With the .licx file the component needs to be able to do whatever the developer wished via GetKey and IsValidKey (explained in the link you posted).
So if GetKey checks for a .licx file in the component directory - you just need to make sure its there.
AFAIK the client assembly doesn't need to do anything except instantiate the control.
Also if you post the name of the component and the lc.exe command you're using, people could take a look..