How to call a com+ component? - vb.net

I'm making some archeology, dealing with COM+
I managed to enlist a simple COM dll as a COM+ component, so far so good.
So I've got this 'foobar' com+ component, with it's interface, and the method I'd like to call.
My question is then rally simple: how am I supposed to make a call to this component?
Any .NET or VB6 answer is accepted (I have to check the component is OK, don't care about the client)
Thanks
Edit (06/03/09): Well, I'm confused. so as to work properly, my COM+ component needs it's dll to be registered. Why not? But then, how to be sure I'm making a COM+ call, and not a COM one?

Simplest VB.NET code snippet possible:
Dim myCom As Object
myCom = CreateObject("MyCom.ProgId")
myCom.Method(parms)
You need to replace "MyCom.ProgId" with the actual ProgId of your component - you can get this from the General tab of the properties of the component in the Component Services admin tool (sounds like you've already got a grasp of that)
myCom.Method(parms)
is simply a place holder for whatever method you want to invoke, with the parameters that method takes.
Here's a link to some examples of the VB.NET syntax:
http://msdn.microsoft.com/library/de...eateObject.asp
http://www.samspublishing.com/articl...le.asp?p=25857
http://msdn.microsoft.com/library/en...asp?frame=true

If all you are wanting is to check the component responds when called then use a quick VBScript rather than building something in VB6/VB.NET.
Dim o : Set o = CreateObject("Lib.Class")
o.YourMethod "someParam"
Watch your COM+ app in Component Services to see if the class requested spins up.

Adam's code in VB6 is similar:
Dim myCom As Object
Set myCom = CreateObject("MyCom.ProgId")
myCom.Method(parms
This example is late bound and carries with it some performance penalty.
You could call your method in an early bound manner, which avoids the penalty. In either VB6 or VB.NET, just add the COM+ dll to your references and you can call the object in this manner:
VB6
dim myCom as MyCom.ProgId
set myCom = new MyCom.ProgId
myCom.Method
VB.NET
dim myCom as new MyCom.ProgId
myCom.Method(...)

When you want to use COM+ for RMI then use this
Dim o As Object
Set o = CreateObject("Lib.Class", "MYSERVER")
where MYSERVER is the machine name where COM+ application is created and your DLL registered. Subsequently
o.YourMethod "someParam"
will be invoked remotely. If you are using only automation compatible interfaces, COM+ will successfully create a proxy for the RMI. Otherwise you'll need to provide the typelib on the client machine. This can be a separate TLB or the DLL itself.

Related

Calling VB6 forms from .Net COM DLL?

We have a very large application that is written in VB6. It has hundreds of forms/user controls/classes etc. We have started migrating to .Net (currently on framework v2, although just about to change that to v4) with a COM exposed DLL by converting individual forms on an 'as and when' basis. This is all working just fine so far.
Some of the more complex VB6 forms call multiple other forms, which call forms etc etc, so conversion is a bottom up process. There are several instances where it would make life easier in the short term if we could call a VB6 form from the .Net DLL, perhaps by passing some form of object reference to the form into .Net. Although I'm pretty sure this isn't possible, I want to check to be certain.
So, is this possible?
We've called VB6 forms from a .Net EXE by referencing a Vb6 DLL from the EXE, it works. I think the same approach should work from a .Net DLL. If you want the VB6 form to be non-modal, you have to use a VB6 ActiveX EXE instead.
A piecemeal approach to migration is a good idea. Divide the application into manageable chunks, and migrate each chunk separately.
I don't know how clean your code is, so take this with a few grains of salt. But here is a a rough outline in pseudo-code (and vastly simplified) of the approach I would take:
In a shared library, exposed to both .NET and COM define an interface for each of your forms:
public interface ILoginForm
property UserName as String
property Password as String
function DisplayModal as Boolean 'True for login, false for cancel...or expose an enum
end interface
public interface IContactEditor
property FirstName as String
property LastName as String
property EmailAddress as String
function DisplayModal as Boolean 'True for save, false for cancel...or expose an enum
end interface
etc, etc for each form in your application.
Next, define a FormFactory interface:
public interface IFormFactory
function CreateLoginForm as ILoginForm
function CreateContactEditorForm as IContactEditor
end interface
If you like to cahce your forms, then you could chnage the interface a bit to match that use-case.
Next, in your VB6 EXE, you should implement the IFormFactory interface:
Class FormFactory Implements IFormFactory
public function IFormFactory_CreateLoginForm as ILoginForm
'let's say this form is still in VB6
Dim frm As frmLoginPage
Set frm = new frmLoginPage
Set IFormFactory_CreateLoginForm = frm
end function
public function IFormFactory_CreateContactEditorForm as IContactEditor
'let's say this form is in .NET
Dim frm As DotNetLib.ContactEditorDialog
Set frm = new DotNetLib.ContactEditorDialog
Set IFormFactory_CreateContactEditorForm = frm
end function
Throughout your VB6 app, have all form creation pass through this singleton:
Dim contactEditor as IContactEditor
Set contactEditor = modSingletons.FormFactory.CreateContactEditorForm()
contactEditor.FirstName = "Joe" 'seed with initial values
contactEditor.LastName = "Blow"
contactEditor.EmailAddress = "bubblegum#something.net"
Dim saved As Boolean
saved = contactEditor.DisplayModal()
if saved then
'read the new values back out and write to DB or whatever
end if
If you do this correctly, your main EXE should not even be aware if the forms are in .NET or VB6, you just switch them out as you go in the Factory.
Finally, you setup the same thing in the .NET lib. Create a COM exposed singleton that the VB6 exe can pass the IFormFactory instance into the .NET library. Then your .NET code can use the factory instance to invoke any form in your app.
Alternatively, you could pass the factory instance on every call into a form (to allow that form to access any other forms), but I would not do it that way. The reason for this is because there very likely are even more services aside from Form creation that you will want to start migrating over. You'd be better served with setting up a bunch of interfaces for your various application services and injecting all of them into the .NET library in a similar manner. Eventually everything will be in .NET, but your code will not need to change since it is using interfaces.

How to determine ActiveX control interface has function in client application

We are using a 3rd party ActiveX control in our application, recently as per our request they have added new function in ActiveX control interface and we are trying to access those function in our application. Due to some reason there are chances where we can not deploy our 3rd party ActiveX control but we are deploying our application. So old 3rd party ActiveX does not have new functions but our application which is consuming those function are trying access new function. Because of that we are getting some inconsistent behaviour lIke crash or message error box.
So we wanted to understand that is there any way to determine function of 3rd party ActiveX control exist or not in our application ? So based on that we wanted to avoid calling those function.
Thanks.
Well, you can get the type library information and try to read and walk it to determine if the function exists.
Or, you can call the function through IDispatch::Invoke and see if it fails. If it fails, don't call it again and call the fallback function.
So, it doesn't have a separate Guid for the two different interfaces? Technically, it is supposed to...but sometimes vendors don't provide new Guids for updated interfaces....I plead the 5th.
The way it is supposed to work is the you QueryInterface for the interface you want and use it.

Call function in VB.Net DLL without registering the DLL

Is it possible to call a function in a VB.Net dll without having registered the dll file? I need to call it from ASP Classic on shared hosting web server.
The only way to call a VB.NET DLL from Classic ASP is to make it a COM object and call it as such.
Assuming the host also support .NET you can follow those steps to achieve what you want:
Create new ASP.NET web application
Add reference to that DLL
Build .aspx web form that call the function in its Page_Load call it for example Func.aspx
In the classic ASP use XMLHTTP to send request to Func.aspx thus invoking the function and parse the results if needed.
I've done similar thing in the past to resize images on the fly from classic ASP without third party component so the concept itself is working.

Who is responsible for calling CoInitialize and CoUninitialize if surrogate process or COM+

Who is responsible for calling CoInitialize and CoUninitialize if
1- I host a COM dll within a surrogate process (either by using dcomcnfg utility or COM+ wizard)?
2- I build a ISAPI DLL that contains COM objects?
No idea on case 2, but in case 1 the surrogate process certainly calls CoInitialize()/CoUninitialize(). Here's how I know this.
We have a COM object that we host in COM+ and that itself uses MS XML 4. When you need to create an XML document object in MS XML 4 you call CoCreateInstance(). We never call CoInitialize() in our COM object, yet document creation is always successful - certainly the surrogate calls CoInitialize(). If we do the same in a stand-alone app document creation fails unless we ourself call CoInitialize().
So the bottom line is: COM+ surrogate (and I'm sure that applies to DCOM surrogate as well) calls CoInitialize() itself.
Btw you can use this to investigate the case 2 - call CoCreateInstance() inside the ISAPI dll - if it is successful CoInitialize() has already been called.

Simulating SideBySide for Out of Process ActiveX

We are adapting our client side relatively complicated application (ActiveX / .net / Delphi / C++ / COM ) to use SxS to achieve non admin deployment and isolation from older versions of our product.
We were able to achieve this goal for almost all our in proc components such as our .net ui, Delphi ui, and the COM servers we use in proc by composing a manifest file which described all the libraries used by our process, with no registration on the client of any of the components (almost).
And here comes the almost part:
At the moment, our application invokes (from it's c++ portion) an out of proc ActiveX server (Delphi ActiveX EXE), which in turn itself invokes another set of out of proc ActiveX servers (third party plugins, any thing goes here, Delphi, C++, any thing as long as it's out of proc ActiveX EXE and implements our interfaces).
As we know SxS does not support out of proc ActiveX servers. And we can't use these objects as in proc com servers in our main process because that would require a major rewrite of our application and even worst, a break of our public facing API which is used by third party tools and vendors, an api break which we can't allow.
We have stumbled on this article which describes how IHTMLDocument2 can be extracted from an Internet Explorer window running in a separate process. Which made us think of this approach:
We would create a secondary satellite application / process which will run the ActiveX as in process server.
Then we will use LresultFromObject and ObjectFromLresult to transfer a reference of the ActiveX object from the satellite application to the main application process. The satellite application will have it's own manifest file which will allow it to run in SxS mode.
Same approach will be taken to communicate between this Delphi ActiveX EXE and the third party AciveX EXE Plugins
There is an alternative solution, which for the moment we do not prefer over the proposed solution above which is to use .net remoting and .net com proxy classes to open the communication channel between the two processes, by translating the com request to .net remoting, and back to com on the second process.
So here comes the question:
What do you think about this approach ?
Do you see a better solution to the problem ?
It is possible to do. What is needed:
An application needs to start a server itself rather than relying on COM to do it. You don't need the extra indirection provided by the registry, just use CreateProcess().
A server should register its class factories in its main() method with CoRegisterClassObject().
Important: the CLSID it uses for each factory should be altered to be unique for each service instance. This ensures that the client connects to the correct server. I simply XOR the process ID with a class factory CLSID. The client knows the process ID as well so can make the same alteration.
The application should call CoCreateInstance() in a loop with a Sleep() call to wait for the object factory to appear. Don't declare failure until at least 60 seconds have passed (that bit me).
Both the application and the server need a manifest that contains a <file> element for each proxy/stub DLL and <comInterfaceExternProxyStub> elements for each interface that is remoted.
Alex,
nobugz is right, you can access the Running Object Table to create an instance of a COM Object from a currently running process of your Delphi automation exe.
However I have found a big issue that I cant explain. I can only access the object via the variant dispatch method when working this way.
Basically if my Active X exe is not registered, I get an "Interface Not Supported" error if I try to instance the object through interfaces for example:
WebUpdate : IAutomation;
WebUpdate := CoAutomation.Create; <-- Wont Work Error
WebUpdate : Variant;
WebUpdate := CreateOleObject('WebUpdate.Automation'); <-- Works Fine
If I register the active x exe using regserver the problem goes away!!
Go Figure!