|
I have a web application that utilizes a large assortment of client side COM DLL's written in ATL COM. One of the components is a COM server (EXE) written to be Single Instance (at least in the class factory). It's a multi-threaded apartment to accomplish all the tasks required of it. Therefore, to be useable by scripting languages like VB Script and JavaScript it needs a wrapper object written as an STA. This "Interface" object is a COM DLL that either starts the COM server or connects to a running instance. In this way, many of the interface objects can be loaded simultaneously giving each frame in the browser it's own object to instantiate and use.
My question is the general usage of the COM server itself. In this project, the COM server EXE is being continually polled for information by the Interface object which uses connection points and available IDispatch interfaces to deliver content to the frame in the web page that's loaded it. In this case, the COM server's methods can be accessed by many different objects simultaneously. The COM server has 2 "data stores" using STL maps. These stores are each protected by their own mutexes and are therefore "safe" from being hit simultaneously. However, do I also need to protect each exposed function call with it's own mutex? I'm a bit new to using a Single Instance object in this way so I'm not sure what kinds of protection I need to include in it... yes, the object's methods are currently unprotected and yes it could very well be called into simultaneously from various interface objects.
Thanks for the help.
Matt
|
|
|
|
|
Must protect only shared memory access "data stores" inside that object.
soptest
|
|
|
|
|
Is there any way to load a COM (in my case an exe) without having to register it? I would like my component to be used in computers with restricted accounts that don't allow registering components.
Is there any other way to do it?
Thank you.
|
|
|
|
|
I could very well be incorrect... but I'll just say no. COM is registry dependent. If you can't use the registry, just make yourself a plain DLL.
|
|
|
|
|
Matt is correct. Remember that COM basically is nothing more than DLLs with published interfaces (through a TLB file) where the COM runtime couples interfaceid to componen't implementation code through the registry. Obviously, I'm over-simplyfying what can be very complex, but the point is that the registry is an integral part of how COM gets from a requested interface id to the server.
Cheers,
Tom Archer
Author, Inside C#
A total abstainer is one who abstains from everything but abstention, and especially from inactivity in the affairs of others.
|
|
|
|
|
In case of COM inproc server (DLL):
#import "c:\tmp\testobj\debug\testobj.dll"
typedef DWORD (WINAPI _DllGetClassObject)(REFCLSID rclsid, REFIID riid, LPVOID* ppv);
int main(int argc, char* argv[])
{
::CoInitialize(0);
{
HINSTANCE hi = ::CoLoadLibrary(L"c:\\tmp\\testobj\\debug\\testobj.dll", TRUE);
HRESULT hr;
_DllGetClassObject *f;
f = (_DllGetClassObject*)::GetProcAddress(hi, "DllGetClassObject");
hr = ::GetLastError();
//CLSID of you COM object CLSID_test
CLSID clsid = {0xC795331E,0x0C56,0x11D6,0xA0,0xFD,0x00,0xB0,0xD0,0xC3,0xD9,0xBD};
::IClassFactory *pcf;
::TESTOBJLib::Itest *pObj;
hr = f(clsid,IID_IClassFactory,(void**)&pcf);
if(SUCCEEDED(hr))
{
hr = pcf->CreateInstance(0,__uuidof(::TESTOBJLib::Itest), (void**)&pObj);
pcf->Release();
if(SUCCEEDED(hr))
{
hr = pObj->In("test");
pObj->Release();
}
}
}
::CoUninitialize();
return 0;
}
soptest
|
|
|
|
|
I need to pass a menu from one COM object to another. Is this possible? The menu would be an out parameter, do I need to allocate memory for this? Or can I just pass a HMenu and duplicate (DuplicateHandle (???)) this on the other side?
|
|
|
|
|
idl definition:
[id(11), helpstring("method GetMenu")] HRESULT GetMenu([out] HMENU* pmh);
C++ implementation:
STDMETHODIMP Ctest::GetMenu(HMENU *pmh)
{
if(!pmh) return E_POINTER;
*pmh = m_hMenu;
return S_OK;
}
soptest
|
|
|
|
|
Thanx for answering. But when you pass something as out parameter, the caller is responsible for freeing the allocated memory, so mustn't the server copy the HMENU? If so, how do you do this? There does not seem to be a method for copying HMENU's.
|
|
|
|
|
HMENU is DWORD, so
in application:
HMENU rhm = 0;
pObj->GetMenu(&rhm);
if(rhm)
{
//rhm now has value
}
soptest
|
|
|
|
|
Hi All,
I was trying to write a connection point console client using c++ and ATL.
Can any body give me some pointers in this. I dont want to use MFC.
Thanks in Advance
Anil.S
|
|
|
|
|
I'm accustomed to using COM in one of two ways:
- As a client when I need to call into an interface for a given method to perform a specific task
- As a component that performs a finite task
However, with the COM+ Loosely Coupled Events I'm confused about how a particular scenario would play out. Let's say I have a CodeProject like application where I want certain subsystems to be alerted any time a new article has been added to the system. Therefore, ...
- I create an ATL project (NewArticle) and add an ATL component to it with an interface called INewArticleEvent and a method called NewArticle.
- I create a new COM+ application (NewArticleApp) and add the INewArticleEvent component as an event class.
- I create another ATL project (LatestUpates) and add an ATL component to it and implement the INewArticleEvent interface.
- For this second component, I create a new COM+ application (LatestUpdatesApp) and add the component as a regular class (as opposed to an event class).
- I add a subscription to the component and specify the INewArticle.NewArticle interface.
- Now when I write code to fire the NewArticle event, the subscribing component in my LatestUpdates component is called as it should be by COM+.
So, it's all good, right? However, here's my question. What if I want to update a currently GUI as a result of an event having been fired? I have this LatestUpdates component that's getting called. But, how can I somehow tie that to my MFC application so that I now list the new article on it's form view?
I'm sure this is COM+ 101, but I'm at a loss.
Thanks for anyone that can help me!!!
Cheers,
Tom Archer
Author, Inside C#
A total abstainer is one who abstains from everything but abstention, and especially from inactivity in the affairs of others.
|
|
|
|
|
Your object that implements the INewArticleEvent interface can be any type of object that you want, as long as it implements that interface. Simply triger the UI update functionality that you would like to happen in your implementation of the INewArticleEvent interface. You can have more than one implementation of this interface. The event sink will blindly call the interface function that you give it.
There are two very good articles in MSDN about event sinks:
Dr. GUI and COM Events PArt 1
Dr. GUI and COM Events PArt 2
Good Luck
Build a man a fire, and he will be warm for a day Light a man on fire, and he will be warm for the rest of his life!
|
|
|
|
|
I'll definitely have to check out the articles because when I create an MFC app and add an ATL object to it (in order to implement INewArticleEvent) COM+ won't allow me to make it a subscriber - maybe EXEs can't contain subscribers (?)
Cheers,
Tom Archer
Author, Inside C#
A total abstainer is one who abstains from everything but abstention, and especially from inactivity in the affairs of others.
|
|
|
|
|
Tom, check this article
COM+ Events hands on
Exes can contain subscribers, subscribers should be implemented in dlls and added to COM+ component services snap-in in your COM+ application.
And since you like books, I strongly advise you to buy "COM and .NET Component Services " by Juval Lowy at amazon BEST book on COM+ ever!!!!
And Tom , do yourself a nice thing ... go to sleep
Cheers,
Joao Vaz
Frustrated TCL programmer,good c++ programmer wannabe
|
|
|
|
|
Hi Joao!
Actually, Jeff's article is too simplistic. He's doing the standard old "display a message box when your method gets called from COM+" bit that I (and many others) have already done in books and articles past. I need a more practical application where the subscriber is part of a gui app that updates a real application. For example, let's say that I have an MFC SDI app with a listview listing auto parts. When a new part gets added to the system, I want my listview to be notified and be updated accordingly. This is the sort of thing nobody does in their articles or chapters.
Joao Vaz wrote:
Exes can contain subscribers, subscribers should be implemented in dlls and added to COM+ component services snap-in in your COM+ application.
Ok. It's early so bear with me You just said that exe can contain subscribers, but then you immediately reversed that and said that they must be in dlls In my tests, I have not been able to create an MFC app and add an ATL object that will implement my event class, COM+ won't allow me to define a application using that component's tlb as a subscription component.
Joao Vaz wrote:
And since you like books, I strongly advise you to buy "COM and .NET Component Services " by Juval Lowy at amazon BEST book on COM+ ever!!!!
Actually, I know Juval very well and he's definitely bright. I'll have to check his book out. However, I'm a bit under the gun now and need a more immediate resolution.
Joao Vaz wrote:
And Tom , do yourself a nice thing ... go to sleep
If only ....
Cheers,
Tom Archer
Author, Inside C#
A total abstainer is one who abstains from everything but abstention, and especially from inactivity in the affairs of others.
|
|
|
|
|
Okay, I will try to explain better ...
quoting Juval:
For COM+ to implement an event class for you, you have to provide COM+ with the sink interfaces definitions, the event class CLSID, and the interface each event class supports. You provide this information in the form of a type library. The type library has to be embedded as a resource in a DLL. The Component Install Wizard knows how to read the type library from the DLL and detect the CoClass definitions inside.
For every CoClass in the type library, COM+ tries to generate an event class and add it to your application as a component. COM+ synthesizes implementation only to interfaces that are part of the event class CoClass definition in the type library.
For example, to define the event class MyEventClass that supports the sink interface IMySink (shown earlier), your IDL file should look like this:
[
uuid(0A9B9E44-E456-4153-9FC8-5D72234B7C82),
version(1.0),
helpstring("Event Class 1.0 Type Library")
]
library EVENTCLASSLib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
importlib("SubApp.tlb");//The subscribers' TLB
[
uuid(5CAF8E95-3FEF-40F1-94C3-3F408240D53B),
helpstring("MyEventClass Class")
]
coclass MyEventClass
{
interface IMySink;
};
};
To avoid repeating the definition of the sink interfaces in both the subscriber application and the event class type library, the event class IDL file should import the sink interface (IMySink) definitions from the type library of the subscribers. This is what the line importlib("SubApp.tlb");was used for in the previous example.
end of quotation ...
You should only put your event class in the dll, do not mix with other coclasses ... because this surely will confuse the com+ install wizard, also you should provide your registration logic, this can be achieve inserting a dummy atl object and assert the methods,because this methods aren't never to be called in the first place.
For instance and taken from Juval book
class CMyEventClass :
public CComObjectRootEx<CComMultiThreadModel> ,
public CComCoClass<CMyEventClass,&CLSID_MyEventClass> ,
public IMySinkInterfaceThatYouWantToImplement
{
public:
CMyEventClass( ){};
DECLARE_REGISTRY_RESOURCEID(IDR_MYEVENTCLASS)
DECLARE_PROTECT_FINAL_CONSTRUCT( )
BEGIN_COM_MAP(CMyEventClass)
COM_INTERFACE_ENTRY(IMySinkInterfaceThatYouWantToImplement)
END_COM_MAP( )
// IMySink
public:
STDMETHOD(OnEvent1)( ){ATLASSERT(0);return E_NOTIMPL;};
STDMETHOD(OnEvent2)( ){ATLASSERT(0);return E_NOTIMPL;};
};
The interface could be a custom or automation and should only have [in] parameters, forget the [in] and [in,out] ...
Hope this clears a tiny bit ????
Cheers,
Joao Vaz
Frustrated TCL programmer,good c++ programmer wannabe
|
|
|
|
|
Tom, I forgot to mention , that probably you only can achieve what you want with Transient Subscription model ?(not sure), this can be programmed using only the COM+ Catalog Api , this model is designed for apps that are already running, in opposite way you have the Persistent Subscription model, that can be added with COM+ snap-in .
To add a transient subscription , you must follow these steps:
Create the catalog object (CLSID_COMAdminCatalog) and get a pointer to ICOMAdminCatalog.
Call ICOMAdminCatalog::GetCollection( ) to retrieve a collection called TransientSubscription and get back an ICatalogCollection interface pointer.
Call ICatalogCollection::Add( ) to get ICatalogObject.
Call ICatalogObject::put_Value( ) once for each desired property of the transient subscription you want to set. Some examples are the event class you want to subscribe to, subscribing interfaces, and the subscription name. An important property you need to set is whether or not you want to enable the subscription.
Call ICatalogCollection::SaveChanges( ).
Release everything.
(The steps are coorect, I think is still from Juval book)
To have to do a similiar thing to unregister the subscription when you application ends (if ends after all)
Cheers,
Joao Vaz
Frustrated TCL programmer,good c++ programmer wannabe
|
|
|
|
|
I truly appreciate the long posts and attempt to help. However, all of this I have down pat and have done dozens of times. What I haven't done is to have a subcription component communicate with an GUI application once it gets the event notification with what I'd call an elegant means. For example, I typically post a message to the application from the component. However, what I'm wanting to know is if an MFC applciation can also have defined an ATL component that is itself the subscriber to a COM+ event. That way, I can simply call AfxGetApp from the component and commnicate with my app that way. Sorry if I'm not explaining this well as I'm under the gun for a deadline and going back and forth between this and the code.
Thanks again though for your help!!
Cheers,
Tom Archer
Author, Inside C#
A total abstainer is one who abstains from everything but abstention, and especially from inactivity in the affairs of others.
|
|
|
|
|
Yes , you can have a MFC app that have a ATL object that's itself part of the subscriber to a COM+ event.
I think that i'm already did this using the posts above with a mfc app, but that was in january , and I don't remember the details
But yesterday night I found that O'reilly have the book online and the examples from the Juval book, if i'm not mistaken , there is a sample using MFC and ATL to do this kind of thing that you want to do.
Sample code of the COM and .NET book
I post here the link, because the book have some very good points about subscriptions and other COM+ juicy stuff
Read the COM and .NET online
I hope you don't get shoot
Cheers,
Joao Vaz
Frustrated TCL programmer,good c++ programmer wannabe
|
|
|
|
|
By the way, thanks for the help! Sorry. I'm not awake yet.
Cheers,
Tom Archer
Author, Inside C#
A total abstainer is one who abstains from everything but abstention, and especially from inactivity in the affairs of others.
|
|
|
|
|
i am a new of com,can you give me some advice
@viruslee@
|
|
|
|
|
Purchase a book called COM Programming by Example and dive in!
Cheers,
Tom Archer
Author, Inside C#
A total abstainer is one who abstains from everything but abstention, and especially from inactivity in the affairs of others.
|
|
|
|
|
|
Get a copy of Essential COM if you really want to understand it.
I'd also look into ATL as it makes COM programming a lot easier. The Wrox Press ATL books are very good.
Michael
Communication is the first step towards enlightenment.
|
|
|
|
|