|
code
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
VB6 Interface implemented in a Delphi COM ObjectWe have a VB6 app that, according to the doc's, supports COM add-ons. These add-ons are required to implement 2 interfaces (from an object in the VB6 app) and flesh out the interface methods with whatever our add-on is supposed to do. VB isn't my first language, so I wrote a Delphi COM object, imported the VB6 Type library and everything looked good, but when I registered and installed the DLL into the VB6 app, it promptly crashed. A few days of digging and I've pinned the problem down to something falling apart when my object's methods are called. I've writted a VB6 test harness and when I step through the code, when VB6 calls MyObject.Method1, what gets triggered in MyObject is Method4, the VB6 call to MyObject.Method2 triggers MyObject.Property3 and so on. This doesn't happen in the Delphi or C# test harness apps - they both work perfectly. It looks like IDispatch.Invoke is short-circuting somewhere. I'm wondering if there's anything unusual about a VB COM Interface or if anyone's come across something like this before. Any ideas or suggestions would be great. Thanks Eric *** Sent via Developersdex http://www.developersdex.com *** "Eric" <nosaint50.at.hotmail.dot.com> schrieb im Newsbeitrag VB-generated TypeLibs always derive from IDispatch,news:utAw6ocLIHA.4196@TK2MSFTNGP04.phx.gbl... > VB isn't my first language, so I wrote a Delphi COM object, > imported the VB6 Type library ... (not from pure IUnknown). With pure IUnknow your VTable-Offset is 4 (16 Bytes) With IUnknown and IDispatch your VTable-Offsets have to be 7 (28 Bytes). So you will hae to make sure, that your implementation in Delphi or whatever derive from IDispatch and not from pure IUnknown. Best way (without any trouble) is of course, to define your Interfaces with *.odl or *.idl and use MkTypLib or Midl to compile from those TypeLib-sources. This way you could omit the IDispatch-Interface VB creates under the hood of every COM-Class (in its own VB-generated TypeLibs) - and the Implementation should work in VB, C++, Delphi without problems. Olaf Hi,
Thanks for the quick response. My Delphi object is derived from IDispatch, but something still isn't working. Let me list in short form the steps I took just in case I missed something. 1. Created a tlb for the VB6 app and found the Addon Interface my object is supposed to implement. This looks like: _AddOn = interface(IDispatch) ['{E7979BD7-723E-11D6-AFAC-0050DA682487}'] procedure Refresh; safecall; procedure disconnect; safecall; procedure connect; safecall; procedure loadConfiguration; safecall; end; _AddOnDisp = dispinterface procedure Refresh; dispid 1610809350; procedure disconnect; dispid 1610809351; procedure connect; dispid 1610809352; procedure loadConfiguration; dispid 1610809353; end; CoAddOn = class class function Create: _AddOn; class function CreateRemote(const MachineName: string): _AddOn; end; 2) Created a COM DLL Project in Delphi, referencing the VB6 App TLB, with an object similar to: type TMyObj_AddOn = class(TAutoObject, _AddOn) protected procedure Refresh; safecall; procedure disconnect; safecall; procedure connect; safecall; procedure loadConfiguration; safecall; end; 3) Built, registered this Addon DLL. Then tried a test app in Delphi with a function like this, which worked as expected: procedure TForm1.Button1Click(Sender: TObject); var myO : _AddOn ; begin myO := CoAddOn.Create; myO.connect; myO.Refresh; myO.disconnect; myO.loadConfiguration; end; 4) Then tried to replicate this in VB6: Private Sub Command1_Click() Dim MyObject As Object Set MyObject = CreateObject("MyDLL.MyObj_AddOn") 'MyObject is created and does point to the DLL I created MyObject.Connect <-- Calls MyObject.Refresh MyObject.loadConfiguration <-- Calls MyObject.Connect MyObject.Refresh <-- Calls MyObject.disconnect MyObject.disconnect <-- VB6 Crashes and Quits End Sub The actual interface is slightly larger and includes some properties, but the really strange thing is if I add a watch in VB6, the information displayed is correct. EG, a Property called IsActive displays as True in the Watch window, but if I write a line of VB code bBoolean = MyObject.IsActive, the value returned is from a completely different property. In the meantime, I'll look into MIDL. Cheers Eric *** Sent via Developersdex http://www.developersdex.com *** Hi,
Quick update on this issue. I've just tried to write a C# Addon for this VB6 app, but when I add a COM Reference and view it in the Object Browser, it's different. For some reson, the following has been added to what I think is the interface: Sub _VtblGap7_3() Member of: VB6App.AddOn._AddOn Any ideas what this is??? Cheers Eric *** Sent via Developersdex http://www.developersdex.com *** "Eric" <nosaint50.at.hotmail.dot.com> schrieb im Newsbeitrag First thought is, you shouldn't work with MyObject LateBound,news:OI3ZQvdLIHA.5140@TK2MSFTNGP05.phx.gbl... as shown in your code here: > Private Sub Command1_Click() In my post I assume, that the above was just a typo in> Dim MyObject As Object > Set MyObject = CreateObject("MyDLL.MyObj_AddOn") your reply and you've instead worked early bound with MyObject inside VB (Dim MyObject As Addon). But if the behaviour below was indeed caused whilst working LateBound (As Object), then you should look at your Delphi-IDispatch-Implementation (DispIDs) and skip the rest of my post. > MyObject.Connect <-- Calls MyObject.Refresh ----Only read this, if the "wild jumping" occured with> MyObject.loadConfiguration <-- Calls MyObject.Connect > MyObject.Refresh <-- Calls MyObject.disconnect > MyObject.disconnect <-- VB6 Crashes and Quits an early bound Object--------------- You will have to take the exact Method (or Property-)order into respect (as it is defined in the original VB-Class, wich contains the interface-definition). From your calling-scheme above it doesn't seem to be a fixed VTable-Offset-Error (wich was my first thought) - instead the calls "jump around". The only cause I can imagine is, that the VB-Interface-Class has a different method/property-order than your Delphi-Interface. Your order, defined in delphi is: Refresh disconnect connect loadConfiguration If in VB, calling a method of the VB-defined-Interface as eg.: MyObject.Connect - jumps to 'Refresh' inside Delphi (wich is your first VTable-Entry after IUnknown(3), IDispatch(4)), then the method 'Connect' is probably the very first entry inside the VB-defined Class/Interface (just look at the Code-Module). Your second defined Delphi-Interface-Method is 'disconnect'. This is jumped on from VB-defined 'Refresh', probably meaning, that 'Refresh' is the second Method inside the VB-Interface-Def. etc... MyObject.disconnect resulting in a crash probably means, that inside the VB-InterfaceDef 'disconnect' is NOT the second Entry (as in your Delphi-Interface), instead it is placed somewhere behind the fourth VB-Method or Property-Definition. Just look at the code of your VB-Interface - or simply define a new one, wich has exactly the same order as your Delphi- Test-Class. '.e.g. Inside an Empty VB-Class ITest: Public Sub Refresh(): End Sub Public Sub disconnect(): End Sub Public Sub connect(): End Sub Public Sub loadConfiguration(): End Sub Olaf Hi Olaf,
Thanks for the help. This is definitely late binding, so I'm homing in on something in the registry being wrong. I asked the VB developers for a sample Addon and they've sent a VB .cls file. It looks pretty clear and I see there's a line that says "Implements Addon" and a bunch of methods Sub Addon_Connect, Sub Addon_loadConfiguration and so on. On the face of it, I can't see much of a difference between this and the way I've done it. Back to the battle on Monday. Cheers Eric *** Sent via Developersdex http://www.developersdex.com ***
Show quote
"Eric" <nosaint50.at.hotmail.dot.com> wrote in message I'm probably missing something, but it looks like you're making it hardernews:utAw6ocLIHA.4196@TK2MSFTNGP04.phx.gbl... > > Hi, > > We have a VB6 app that, according to the doc's, supports COM add-ons. > These add-ons are required to implement 2 interfaces (from an object in > the VB6 app) and flesh out the interface methods with whatever our > add-on is supposed to do. > > VB isn't my first language, so I wrote a Delphi COM object, imported the > VB6 Type library and everything looked good, but when I registered and > installed the DLL into the VB6 app, it promptly crashed. > > A few days of digging and I've pinned the problem down to something > falling apart when my object's methods are called. I've writted a VB6 > test harness and when I step through the code, when VB6 calls > MyObject.Method1, what gets triggered in MyObject is Method4, the VB6 > call to MyObject.Method2 triggers MyObject.Property3 and so on. This > doesn't happen in the Delphi or C# test harness apps - they both work > perfectly. It looks like IDispatch.Invoke is short-circuting somewhere. > > I'm wondering if there's anything unusual about a VB COM Interface or if > anyone's come across something like this before. Any ideas or > suggestions would be great. > than it should be. First off, "VB-generated TypeLibs" are NOT "always derive from IDispatch". The typelibs for VB created COM components are always DUAL Interfaces. (Dual supports both IUnknown and IDispatch but with subtle differences at this scale.) Also I'm a bit confused by why you are importing a typelib from a VB App into a COM component? If the COM component is a service for the App you should be Referencing IT within the VB app. BUT - I'm also confused by why you would be importing anything if your intention is to use Automation or Late Binding from the VB App. "Triggers"? No reflection on your expertise, but the whole thing sounds squirrely. You are likely over-thinking it. What is it you are really trying to do - and skip the "typelib" stuff? <g> But then I'm probably missing something. -ralph Hi Ralph,
You could be right ... by now, I'm suffering brain cramp like never before... The requirement is to add a new function to an existing VB6 app. The VB6 app polls a web service and returns messages. By adding objects, you can extend this app and register an interest in certain message types. It's a glorified COM based Observer pattern as I understand it. According to the developers of the VB6 app, any extension has to implement a standard interface they provide - that way they can loop and call the same methods for every registered object, passing a list of messages to them. We tell the VB app that we are a new object by adding an entry to an INI file specifying the "DLL.Object" and the message type we want to get. It sounds simple enough, but the wheels are falling off somewhere and I'm not ruling myself out. >>I'm a bit confused by why you are importing a typelib >>from a VB App into a COM component?Well, in theory, this provides me with the Interface definition I have to implement. That should let the VB app call the functions I've written via it's interface. "Triggers"? Hey-ho Silver ... Ok, it's Friday and late .... Invokes/Calls. >>I'm also confused by why you would be importing anything >>if your intention is to use Automation or Late Binding >>from the VB App.According to the devlopers of the app, they call something like this: Dim AddOnObject As Object Dim VB6Object As AddOn <-- This is the interface they insist everyone implements Set AddOnObject = CreateObject("DLL.Object") <-- The entry in the ini file for My Delphi object. Set VB6Object = AddOnObject <-- I'm guessing this is a VB6 QueryInterface variation to get at their Addon Interface inside my COM object VB6Object .Connect VB6Object .loadConfiguration VB6Object .Refresh VB6Object .disconnect I hope that's a bit clearer Cheers Eric *** Sent via Developersdex http://www.developersdex.com ***
Show quote
"Eric" <nosaint50.at.hotmail.dot.com> wrote in message So you aren't actually adding any code to the VB App?news:%237K4bafLIHA.1208@TK2MSFTNGP03.phx.gbl... > Hi Ralph, > > You could be right ... by now, I'm suffering brain cramp like never > before... > > The requirement is to add a new function to an existing VB6 app. The VB6 > app polls a web service and returns messages. By adding objects, you can > extend this app and register an interest in certain message types. It's > a glorified COM based Observer pattern as I understand it. > > According to the developers of the VB6 app, any extension has to > implement a standard interface they provide - that way they can loop and > call the same methods for every registered object, passing a list of > messages to them. We tell the VB app that we are a new object by adding > an entry to an INI file specifying the "DLL.Object" and the message type > we want to get. > > It sounds simple enough, but the wheels are falling off somewhere and > I'm not ruling myself out. > > >>I'm a bit confused by why you are importing a typelib >>from a VB App > into a COM component? > > Well, in theory, this provides me with the Interface definition I have > to implement. That should let the VB app call the functions I've written > via it's interface. > > "Triggers"? > > Hey-ho Silver ... Ok, it's Friday and late .... Invokes/Calls. > > >>I'm also confused by why you would be importing anything >>if your > intention is to use Automation or Late Binding >>from the VB App. > > According to the devlopers of the app, they call something like this: > > Dim AddOnObject As Object > Dim VB6Object As AddOn <-- This is the interface they insist everyone > implements > > Set AddOnObject = CreateObject("DLL.Object") <-- The entry in the ini > file for My Delphi object. > > Set VB6Object = AddOnObject <-- I'm guessing this is a VB6 > QueryInterface variation to get at their Addon Interface inside my COM > object > > VB6Object .Connect > VB6Object .loadConfiguration > VB6Object .Refresh > VB6Object .disconnect > > I hope that's a bit clearer > > Cheers > Then all you have do create a COM component that implements those four methods: Connect loadConfiguration Refresh disconnect (If there are also parameters then they need to match any signature given.) The only possible problem I see is perhaps the argument delivered to the VB App thru the INI file. This argument is referred to as the ProgID or AppID. There is no 'official' protocol when it comes to naming these creatures. It depends on the tool that creates the TypeLib. The variable of that type may be ... DllFilename.Class TypeLibName.Class LibraryName.Class ProgramName.Class ... [You can create your own name if you want, and it will work as long as you register it to point to the correct component.] When VB calls CreateObject and is making an assignment to an Object Reference the COMlib is loaded which then uses the Registry to seek out that ID. MyComputer\HKEY_CLASSES_ROOT\<LibraryID>.<ClassID> Under that Key will be a Key called CLSID which gives the ClassID value to lookup. For that CLSID there will be an entry for the COM Registration. You should see at least the following for a component that supports IDispatch. ImprocSeerver32 ProgID <- the animal that got you there VersionIndependentProgID TypeLib <- sometimes ... there may be additional ... Some tools expose additional "ProgIDs". But they may not actually be a variable for the correct Interface Type you need. That's coming out a bit wrong. Basically all I am suggesting is that you merely trace the argument given manually thru the Registry to insure it dereferences the expected interface. Also make sure your component is Registered. (And get rid of any old news. A good registry cleaner helps here.) So if you simply create a COM component in Delphi and configure it to support an IDispatch interface (or Dual). Register it and then set the INI file to point to the correct ProgID - all should work as planned. -ralph Hi Ralph,
No, I'm not changing the VB app at all. My first try at this was creating my own COM object with those methods, but that crashed and burned as well with a VB error 13 at run-time. The VB guys said that was because it didn't implement the _Addon interface and sent me a .cls file as a sample of what to do. On the face of it, I can't see too much difference between the cls file and the way I've coded it. I'm going to trawl the registry - all roads seem to be pointing in that direction. Cheers Eric *** Sent via Developersdex http://www.developersdex.com ***
Show quote
"Eric" <nosaint50.at.hotmail.dot.com> wrote in message Don't know that much about the newer Delphi.news:eAiX8thLIHA.5140@TK2MSFTNGP05.phx.gbl... > > Hi Ralph, > > No, I'm not changing the VB app at all. > > My first try at this was creating my own COM object with those methods, > but that crashed and burned as well with a VB error 13 at run-time. > The VB guys said that was because it didn't implement the _Addon > interface and sent me a .cls file as a sample of what to do. > > On the face of it, I can't see too much difference between the cls file > and the way I've coded it. > > I'm going to trawl the registry - all roads seem to be pointing in that > direction. > > Cheers > This might help. What they gave you was a way of creating a specific interface. It is interesting that they didn't just send a cls file that exposed those members as the public interface. So in VB you would have is two Interfaces available (The Public default and I_Addon) Not sure how you would do that in VB. The errors you are getting would be identical to what would happen if you were creating a VB component and merely created a Class and set your reference to it. -ralph
Show quote
"Ralph" <nt_consultin***@yahoo.com> wrote in message Oops!news:%23e6N5$hLIHA.4476@TK2MSFTNGP06.phx.gbl... > > "Eric" <nosaint50.at.hotmail.dot.com> wrote in message > news:eAiX8thLIHA.5140@TK2MSFTNGP05.phx.gbl... > > > > Hi Ralph, > > > > No, I'm not changing the VB app at all. > > > > My first try at this was creating my own COM object with those methods, > > but that crashed and burned as well with a VB error 13 at run-time. > > The VB guys said that was because it didn't implement the _Addon > > interface and sent me a .cls file as a sample of what to do. > > > > On the face of it, I can't see too much difference between the cls file > > and the way I've coded it. > > > > I'm going to trawl the registry - all roads seem to be pointing in that > > direction. > > > > Cheers > > > > Don't know that much about the newer Delphi. > > This might help. What they gave you was a way of creating a specific > interface. It is interesting that they didn't just send a cls file that > exposed those members as the public interface. So in VB you would have is > two Interfaces available (The Public default and I_Addon) Not sure how you > would do that in VB. > > The errors you are getting would be identical to what would happen if you > were creating a VB component and merely created a Class and set your > reference to it. > > -ralph > s/"Not sure how you would do that in VB"/"Not sure how you would do that in DELPHI."/g <g> Hi,
Just a note to say I've finally got this working ... Adding a few "Ghost" methods to the imported TLB seemed to be just what was needed. I'm not quite sure why that is, but having it work is good enough for me for the moment - when I recover a bit, I'll delve back into it. Thanks to all who offered help. Eric *** Sent via Developersdex http://www.developersdex.com *** You may want to try asking this in Borland's newsgroups, if you haven't already.
newsgroups.borland.com There are several promising-looking groups there. Rob Show quote "Eric" <nosaint50.at.hotmail.dot.com> wrote in message news:utAw6ocLIHA.4196@TK2MSFTNGP04.phx.gbl... > > Hi, > > We have a VB6 app that, according to the doc's, supports COM add-ons. > These add-ons are required to implement 2 interfaces (from an object in > the VB6 app) and flesh out the interface methods with whatever our > add-on is supposed to do. > > VB isn't my first language, so I wrote a Delphi COM object, imported the > VB6 Type library and everything looked good, but when I registered and > installed the DLL into the VB6 app, it promptly crashed. > > A few days of digging and I've pinned the problem down to something > falling apart when my object's methods are called. I've writted a VB6 > test harness and when I step through the code, when VB6 calls > MyObject.Method1, what gets triggered in MyObject is Method4, the VB6 > call to MyObject.Method2 triggers MyObject.Property3 and so on. This > doesn't happen in the Delphi or C# test harness apps - they both work > perfectly. It looks like IDispatch.Invoke is short-circuting somewhere. > > I'm wondering if there's anything unusual about a VB COM Interface or if > anyone's come across something like this before. Any ideas or > suggestions would be great. > > Thanks > > Eric > > *** Sent via Developersdex http://www.developersdex.com *** Hi Rob,
The Borland Groups are an option, but I just wanted to confirm or eliminate the VB end of it. It's the one part of this project I know very little about, so if there were any pitfalls or known "gotcha's", you guys would point it out quicker than a weasel on a rabbit. Cheers Eric *** Sent via Developersdex http://www.developersdex.com ***
Other interesting topics
|
|||||||||||||||||||||||