I am experimenting with the System.Addin MAF capability. I have a host that creates an instance of a new addin in a new appdomain and starts it running.
I'd like to have the addin call methods on the host to pass data back up. It is clear how to have the host create an instance of the addin (AddinToken.Activate), but how does the addin get a reference to the host?
I have tried passing a copy of the host down to the addin through an Initialise method, but because it needs to be serializable, this causes difficulties. I have to mark some properties as NonSerialized which mean they are null when the addin calls the methods on it. I get the feeling that although there is a View & Adapter written to support the Addin->Host contract, it is being bypassed by this method?
You don't pass a copy of the host down to the addin. Rather you need to define an interface that you pass to the addin and provide an implementation on the host side.
For example, you could define an Initialize method that the AddIn has to implement. You could specify parameters to that method that represent services provided by the host. One case where I use this is to provide a logging interface to the addin. The initialize method is defined as:
void Initialize(ILogger logger);
When the host calls initialize on the AddIn, it passes an implementation of ILogger that the Addin can then hold onto and call whenever it needs to log.
Related
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);
I've got a FTP application written in c++. Now I'm adding a simple GUI to my project via the Qt plugin for VS2010. The mechanism to connect to the server is very simple. After typing both IP and PORT the connection is stablished and an object is created. This object (from a class I've written) can call several functions such as: ask for the available files on server, download an specific file, etc.
My question is: if that object is created after pressing a button (and calling the function it is linked to) is there any way to return that object? Sure there is but, how and where in the code should it be stored/declared. Here is the code line:
connect(ui.btn_connect,SIGNAL(clicked()),this,SLOT(on_SayConnect()));
How should I call the function "on_SayConnect()" if I want an object to be returned using the connect (SIGNAL/SLOT) syntax? Thank you in advance.
There's no good way to return values using the connect method. If your goal is to have the this object (I don't think you actually gave it a name) send a value/object to other parts of the system, you could have the on_SayConnect slot emit a signal with the desired value. Any other objects that need to receive that value should implement and connect the proper slot to do so.
SOME BACKGROUND:
I'm using onCFCRequest() to handle remote CFC calls separately from regular CFM page requests. This allows me to catch errors and set MIME types cleanly for all remote requests.
THE PROBLEM:
I accidentally set some of my remote CFC functions to public access instead of remote and realized that they were still working when called remotely.
As you can see below, my implementation of onCFCRequest() has created a gaping security hole into my entire application, where an HTTP request could be used to invoke any public method on any HTTP-accessible CFC.
REPRO CODE:
In Application.cfc:
public any function onCFCRequest(string cfc, string method, struct args){
cfc = createObject('component', cfc);
return evaluate('cfc.#method#(argumentCollection=args)');
}
In a CFC called remotely:
public any function publicFunction(){
return 'Public function called remotely!';
}
QUESTION:
I know I could check the meta data for the component before invoking the method to verify it allows remote access, but are there other ways I could approach this problem?
onCfcRequest() doesn't really create the security hole, you create the security hole by blindly running the method without checking to see if it's appropriate to do so first, I'm afraid ;-)
(NB: I've fallen foul of exactly the same thing, so I'm not having a go # you ;-)
So - yeah - you do need to check the metadata before running the method. That check is one of the things that CF passes back to you to manage in its stead when you use this handler, and has been explicitly implemented as such (see 3039293).
I've written up a description of the issue and the solution on my blog. As observed in a comment below I use some code in there - invoke() - that will only work on CF10+, but the general technique remains the same.
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
I have tried to make a webservice interface to a state-holding COM component.
The webservice basically contains operations Start, Shutdown and GetCurrentState.
Start creates a COM component, Stop releases.
And GetCurrentState retrieves information from the COM component.
It seemed an easy thing, but after a day it still refuses to work.
I have tried storing the COM-reference as a member variable in the C# object. The object is constantly re-created.
Then I tried to store the COM-reference in the Session object. But still, something is still wrong.
Anyone know how one should store COM reference which should stay alive inside webservices?
/L
Assuming you are using ASMX here, and not WCF where you could control the life time little bit differently, each time a request comes in the class that services the request is recreated. This is the standard behaviour for ASMX.
What you need to do is store the COM object either inside the Cache[] or Application[] collections. It may still get destroyed when the worker pool is recycled. Some code like this is what you need:
public FooClass GetFooClassInstance()
{
FooClass instance = (FooClass)this.Context.Application["FooClassInstance"];
if (instance == null)
{
instance = new FooClass(); // Creates the RCW.
this.Context.Application["FooClassInstance"] = instance;
}
return instance;
}
The FooClass is the runtime callable wrapper for your COM object. The Application object contents is retained between requests. One thing you do need to watch out for is the threading model that the COM component is using as some can cause performance problems because they marshal calls onto a single thread.
Web service by its nature is stateless. Try creating Windows service and using Web service to control it. Start method would start Windows service and that service would instantiate COM-component. GetCurrentState method would communicate with the service and grab COM reference.
Another approach is to make your COM component COM+ accessible:
Open Administrative Tools -> Component Services.
Open COM+ Applications node.
Create new application. Select "Create an empty application" in the first wizard step. Type application name and select "Server application" option in the next step.
Create new component. Select "Install new component(s)" in the wizard. Locate and select your COM dll.
Go to component properties and enable object pooling. Set minimum and maximum pool size to 1. This will make your component a singleton.