Here is the what the interface browser has (compFlowLbmol_Hr is the
problem): ========= [id(0x00000003)] short GetStreamByID( short streamID, single* tempR, single* presPsia, single* moleVapFrac, single* enthBtu_Hr, VARIANT compFlowLbmol_Hr); ========== Here is the code that was generated ^(self invokeId: 3 withArguments: ((Array new: 6) basicAt: 1 put: streamID; basicAt: 2 put: tempR; basicAt: 3 put: presPsia; basicAt: 4 put: moleVapFrac; basicAt: 5 put: enthBtu_Hr; basicAt: 6 put: compFlowLbmol_Hr; yourself)) ========== This is what I was doing in the code. ========== flowArray := Array new: 301. 1 to: flowArray size do: [:count | flowArray at: count put: 0]. flowArray := SAFEARRAY withAll: flowArray elementClass: FLOAT. ========== There are two parts to the interface, I send values in the array for one function, and then get them back via another. I was originally using the same array for both assuming it would just overwrite the values. I do not get any errors when I set the values. However I just noticed that I am not getting the correct return values. I just get back the same values I sent. I figure this has something to do with variant wrapping an by ref or something. I did a google search and found some info, but I am still having problems getting anything to work. Does anyone have any ideas about the correct way to do this? When I try this there is no error, but there is no data either. ====== flowArray := Array new: 301. 1 to: flowArray size do: [:count | flowArray at: count put: 0]. flowArray := SAFEARRAY withAll: flowArray elementClass: FLOAT. flowArray := flowArray asVariant. ==== Then I added this line bellow, and I now get an error "Unrecognised HRESULT - 16rC0000005 (16r5: Unrecognised HRESULT - 16rC0000005)" at the external call. ==== flowArray vt: flowArray vt | (AXAutomationConstants at: #VT_BYREF). ==== Here is the VBA code (It always seems so simple in VBA ;)): ==== Dim compFlowLbmol_Hr(0 To 300) As Single check = streams.GetStreamByID(ID, TempR, presPsia, moleVapFrac, EnthBtu_Hr, compFlowLbmol_Hr) ===== Any help or suggestions would be greatly appreciated. Chris |
"Christopher J. Demers" <[hidden email]> wrote in
message news:b1pivp$15od7h$[hidden email]... > > Here is the VBA code (It always seems so simple in VBA ;)): > ==== > Dim compFlowLbmol_Hr(0 To 300) As Single > check = streams.GetStreamByID(ID, TempR, presPsia, moleVapFrac, EnthBtu_Hr, > compFlowLbmol_Hr) > ===== I still can't get this to work. I have tried many variations using FLOAT, DOUBLE, VARIANT. Every time I try to force it to be passed by reference I get the "Unrecognised HRESULT" error and when I don't I do not get return values. I also see random data for the values, but only when it is made to be by reference. Do I need to do some additional locking or something? Surely there is an easy way this can be done in Dolphin? I guess I need to know the equivalent of compFlowLbmol_Hr(0 To 300) As Single in Dolphin, and how to pass it by reference. I do like the Dolphin ActiveX interface, but unfortunately there are still these situations that just seem more complex than in VB. I don't really want to have to build my own VB wrapper just to make this work. Chris |
"Christopher J. Demers" <[hidden email]> wrote in
message news:b1srla$16hr88$[hidden email]... > "Christopher J. Demers" <[hidden email]> wrote in > message news:b1pivp$15od7h$[hidden email]... > > > > Here is the VBA code (It always seems so simple in VBA ;)): > > ==== > > Dim compFlowLbmol_Hr(0 To 300) As Single > > check = streams.GetStreamByID(ID, TempR, presPsia, moleVapFrac, > EnthBtu_Hr, > > compFlowLbmol_Hr) > > ===== > > I still can't get this to work. I have tried many variations using FLOAT, > DOUBLE, VARIANT. Every time I try to force it to be passed by reference I > get the "Unrecognised HRESULT" error and when I don't I do not get return > values. I also see random data for the values, but only when it is made > be by reference. Do I need to do some additional locking or something? > Surely there is an easy way this can be done in Dolphin? I guess I need to > know the equivalent of compFlowLbmol_Hr(0 To 300) As Single in Dolphin, and > how to pass it by reference. What documentation do you have for the interface? Its not clear from the IDL exactly how the compFlowLbmol_Hr argument should be set up, its just a loosely typed VARIANT. That could be anything from "nil" (or the Automation equivalent), to a String, or an array of other VARIANTs. Plainly put, there is not enough type information in that IDL to know how to set up that parameter correctly. Indeed if it is specified like that, then the designer of the component has effectively said that any variant compatible value _might_ be valid as an argument. What IDL does Dolphin itself reverse engineer for the interface? I think that VB(A) will pass the first parameter as a VT_I2|VT_BYREF, the float parameters as VT_R4|VT_BYREF, and the last (array) parameter as a VT_ARRAY|VT_R4, i.e. not VT_BYREF. This is because the array is already (in effect) passed by reference. I don't know whether you are expecting the component to reallocate the array completely, or modify the existing one in place, but I would have thought if you execute something like: flowArray := (SAFEARRAY length: 301 elementClass: FLOAT) asVariant. streams getStreamByID: 1 tempR: 1.1 presPsia: 0.1 moleVapFrac: 0.2 enthBtu_Hr: 0.3 compFlowLbmol_Hr: flowArray. Then on exit from the GetStreamByID call, if the method has modified the values in the array, then those modifications will be visible in the array held by the VARIANT, flowArray. Note, however, that strictly the scalar parameters should be passed by reference since their direction is not declared in the IDL and they are pointers. You might find it will work for non-reference parameters since most IDispatch implementations will coerce things over, and it is quite likely that one or more of these parameters is really an input parameter anyway. If you needed to pass them by reference then you'd need to wrap them up in instances of SWORD (for the shorts) and FLOAT. When these structures are converted to VARIANTs, the result is a byref variant, for example: > > I do like the Dolphin ActiveX interface, but unfortunately there are still > these situations that just seem more complex than in VB. I don't really > want to have to build my own VB wrapper just to make this work. I'm afraid that it is somewhat inevitable. Automation (not COM) was designed for use from VB. Active-X objects that use a lot of SAFEARRAYs and VARIANTs in their interfaces, and especially if they implement dispinterfaces (IDispatch only) rather than dual interfaces (IDispatch with additional custom methods), were probably designed for use from VB and tested against it. VARIANT is a native type in VB. The types one can hold in a VARIANT are the native VB representations for integers, strings, etc. SAFEARRAYs are the native VB array type. There's certainly room for improvement in Dolphin's use of ActiveX components, but it may not be possible to make it quite as seamless as it is from the language into which it was designed to fit (and vice versa). When the IDL is loose, then insufficient type information is available to automatically perform the necessary marshalling from the Smalltalk objects. Of course marshalling isn't necessary when the types are already in the correct representation, and the implementor of the object will probably then have tested against VB and made the component work with whatever it happens to pass. Always bear in mind that if you have a specific issue with using a COM component, then we are able to offer more help: http://www.object-arts.com/Support.htm Regards Blair |
"Blair McGlashan" <[hidden email]> wrote in message
news:b1tsr4$16pkvi$[hidden email]... > What IDL does Dolphin itself reverse engineer for the interface? The IDL is in my previous message that I replied to. Here it is again: [id(0x00000003)] short GetStreamByID( short streamID, single* tempR, single* presPsia, single* moleVapFrac, single* enthBtu_Hr, VARIANT compFlowLbmol_Hr); > effect) passed by reference. I don't know whether you are expecting the > component to reallocate the array completely, or modify the existing one in > place, but I would have thought if you execute something like: > > flowArray := (SAFEARRAY length: 301 elementClass: FLOAT) asVariant. > streams getStreamByID: 1 tempR: 1.1 presPsia: 0.1 moleVapFrac: 0.2 > enthBtu_Hr: 0.3 > compFlowLbmol_Hr: flowArray. That is one of the things I tried, it does not error, but the values are not in flowArray. > I'm afraid that it is somewhat inevitable. Automation (not COM) was designed > for use from VB. Active-X objects that use a lot of SAFEARRAYs and VARIANTs > in their interfaces, and especially if they implement dispinterfaces > (IDispatch only) rather than dual interfaces (IDispatch with additional > custom methods), were probably designed for use from VB and tested against > it. Yes, it seems that this component was designed with VBA in Excel in mind. Unfortunately I don't have any control over that. I solved my immediate problem by writing a wrapper in VB to communicate between Dolphin and the ActiveX object. Not the most elegant solution, but it solves the immediate problem. If others are interested this is how I declared the function: Public Function WrapGetStreamByID(cc5 As Object, ID As Integer, ByRef TempR As Single, ByRef presPSia As Single, ByRef moleVapFrac As Single, ByRef EnthBtu_Hr As Single, ByRef compFlowLbmol_Hr() As Single) As Integer then I make the call from there, and it just works its VB magic and the values get returned in Smalltalk. > Always bear in mind that if you have a specific issue with using a COM > component, then we are able to offer more help: > http://www.object-arts.com/Support.htm I will have to budget for this in future ActiveX projects. Chris |
"Christopher J. Demers" <[hidden email]> wrote in
message news:b1v2js$15usmv$[hidden email]... > "Blair McGlashan" <[hidden email]> wrote in message > news:b1tsr4$16pkvi$[hidden email]... > > > What IDL does Dolphin itself reverse engineer for the interface? > > The IDL is in my previous message that I replied to. Here it is again: >... OK. Is it the same from OLEView? Also how does it get represented by the VB(A) object browser? I just want to eliminate the possibility that the the Dolphin TLA is not reading the typelibrary correctly, since as you'll see below I had no problems with this declaration in a test component I built. > > > > flowArray := (SAFEARRAY length: 301 elementClass: FLOAT) asVariant. > > streams getStreamByID: 1 tempR: 1.1 presPsia: 0.1 moleVapFrac: 0.2 > > enthBtu_Hr: 0.3 > > compFlowLbmol_Hr: flowArray. > > That is one of the things I tried, it does not error, but the values are not > in flowArray. I built a test Active-X in C++/ATL using that IDL, and if I call it from Dolphin exactly like that, in order to see what VB passed in for the array. It was as I expected passed as VT_ARRAY|VT_R4, i.e. not explicitly as a VT_BYREF. I tried invoking it from Dolphin and on return from the method the array contains the updated values I stored in it. I'll zip it all up and send it to you for examination. As I say, if you require further assistance with the actual component (they vary a great deal, so it often isn't possible to give guidance in the abstract), then we can provide it. Regards Blair |
"Blair McGlashan" <[hidden email]> wrote in message
news:b1vuru$17b5rj$[hidden email]... > OK. Is it the same from OLEView? Also how does it get represented by the > VB(A) object browser? I just want to eliminate the possibility that the the > Dolphin TLA is not reading the typelibrary correctly, since as you'll see > below I had no problems with this declaration in a test component I built. The OLEView tool reports the same IDL as Dolphin for the method. This is from the VBA Object Browser in Excel: Function GetStreamByID(streamID As Integer, tempR As Single, presPsia As Single, moleVapFrac As Single, enthBtu_Hr As Single, compFlowLbmol_Hr) As Integer > I built a test Active-X in C++/ATL using that IDL, and if I call it from > Dolphin exactly like that, in order to see what VB passed in for the array. > It was as I expected passed as VT_ARRAY|VT_R4, i.e. not explicitly as a > VT_BYREF. I tried invoking it from Dolphin and on return from the method the > array contains the updated values I stored in it. I'll zip it all up and > send it to you for examination. As I say, if you require further assistance > with the actual component (they vary a great deal, so it often isn't > possible to give guidance in the abstract), then we can provide it. I looked at the example you sent to me and it works like a charm from VB and Dolphin. I had to remove a prerequisite from the package file and generate the Dolphin wrapper class in order to get it to load (the global was missing from the package). I wonder if it is possible that the actual type library is wrong, and Visual Basic doesn't care and is coercing things to make it work, but since Dolphin is playing by the rules it is not. I will explore this aspect further. I don't suppose you know of an easy way to check this theory? I am afraid it would be difficult to provide the actual component. I just wanted to make sure I was doing things the theoretically correct way. It sounds like the component is doing something strange. Thank you Blair, I really appreciate your effort. I will let you know if I can reproduce the problem with a component of my own. Chris |
"Christopher J. Demers" <[hidden email]> wrote in
message news:b21e6b$16f2hr$1@ID- > I wonder if it is possible that the actual type library is wrong, and Visual > Basic doesn't care and is coercing things to make it work, but since Dolphin > is playing by the rules it is not. I will explore this aspect further. I > don't suppose you know of an easy way to check this theory? I am not sure what exactly this proves, but I discovered something very interesting: In the component vendors VBA example when the variable that is sent the GetStreamByID message is declared as Object it works. However when the variable is declared more specifically as the correct interface it returns all 0's just like Dolphin did. Somehow this change is causing the original array to not be changed. I think I can firmly say this is a problem with the other vendors component. I guess the type library could be wrong? I bet I could make the call work if I could trick Dolphin into not using the IDL information. I have sympathy for your support of ActiveX in Dolphin, especially when there seem to be so many sloppy components out there. Once again thanks for your effort. Chris |
"Christopher J. Demers" <[hidden email]> wrote in
message news:b21j14$1831qr$[hidden email]... > ... > I am not sure what exactly this proves, but I discovered something very > interesting: > > In the component vendors VBA example when the variable that is sent the > GetStreamByID message is declared as Object it works. However when the > variable is declared more specifically as the correct interface it returns > all 0's just like Dolphin did. Somehow this change is causing the original > array to not be changed. I think I can firmly say this is a problem with > the other vendors component. I guess the type library could be wrong? I > bet I could make the call work if I could trick Dolphin into not using the > IDL information. Ah, now we're getting somewhere. I tried doing that with my dummy component, and after fixing an error or two in its IDispatch implementation, I found that VB passes in the array, in that case, as VT_R4|VT_ARRAY|VT_BYREF. So, from Dolphin: flowArray := SAFEARRAY length: 301 elementClass: FLOAT. varArray := VARIANT new. varArray reference: flowArray bytes basicYourAddress. varArray vt: 24580 "VT_ARRAY|VT_R4|VT_BYREF". streams getStreamByID: 1 tempR: 1.1 presPsia: 0.1 moleVapFrac: 0.2 enthBtu_Hr: 0.3 compFlowLbmol_Hr: varArray. flowArray inspect. Two points to note: 1) I discovered there is an error in the VARIANT>>array accessor method that prevents byref arrays printing properly - patch below. 2) It helps to add a method to VARIANT to make setting up byref array variants easier, also below. With this in place setting up the varArray becomes the simple expression: 'varArray arrayRef: flowArray'. Hope this gets you going. Blair ---------------------- !VARIANT methodsFor! array "Answer a SAFEARRAY from the receiver. Assumes that the receiver actually references an array." ^SAFEARRAY fromAddress: (self isByRef ifTrue: [self refAddress dwordAtOffset: 0] ifFalse: [self ulVal]) vt: self vartype owner: self! arrayRef: newValue "Store a reference to the <SAFEARRAY> representation of the argument, newValue, into the receiver, i.e. the receiver will be of type VT_xx|VT_ARRAY|VT_BYREF." data := newValue asSAFEARRAY. self vt: data vt | VT_BYREF. self ulVal: data bytes basicYourAddress! ! !VARIANT categoriesFor: #array!accessing!public! ! !VARIANT categoriesFor: #arrayRef:!accessing!public! ! |
"Blair McGlashan" <[hidden email]> wrote in message
news:b27so1$199u4f$[hidden email]... >... > Ah, now we're getting somewhere. I tried doing that with my dummy component, > and after fixing an error or two in its IDispatch implementation, I found > that VB passes in the array, in that case, as VT_R4|VT_ARRAY|VT_BYREF. > ... Perfect, this code works like a charm! You must be the white wizard of ActiveX! Thank you very much. However shall I take it that the root problem here is that the vendor supplied type library is not correct? Their VBA example did the same thing Dolphin did before (no values were passed back) when the variable was explicitly declared as the correct type (not Object). I take this to mean their type library is not correct. Do you concur? Chris |
"Christopher J. Demers" <[hidden email]> wrote in
message news:b299kj$1a5oca$[hidden email]... > "Blair McGlashan" <[hidden email]> wrote in message > news:b27so1$199u4f$[hidden email]... > >... > > Ah, now we're getting somewhere. I tried doing that with my dummy > component, > > and after fixing an error or two in its IDispatch implementation, I found > > that VB passes in the array, in that case, as VT_R4|VT_ARRAY|VT_BYREF. > > ... > > Perfect, this code works like a charm! You must be the white wizard of > ActiveX! Thank you very much. However shall I take it that the root > problem here is that the vendor supplied type library is not correct? Their > VBA example did the same thing Dolphin did before (no values were passed > back) when the variable was explicitly declared as the correct type (not > Object). I take this to mean their type library is not correct. Do you > concur? Well if they want to declare the argument like that, then clearly they need to be less restrictive about the type of argument they are prepared to accept, since VB(A) will pass it differently depending on whether late or early bound. It seems they also need to tighten up on their error checking since if the argument type was not acceptable, an error should have resulted. Based on your example, though, I think the IDL should probably be declaring the argument as the actual type it is, rather than as a plain VARIANT. If that had been done, then there could have been no confusion about what was expected, the component wouldn't need to do any explicit type checking, and it wouldn't have been necessary for us to deduce the correct type by finding out what VB(A) passed. It is possible they had other reasons for declaring it as a VARIANT (perhaps one can pass other types of value in?), but I have often found that VARIANTs are used needlessly where a more specific type would better serve. This was particularly common in earlier automation object models, such as many of the MS Office interfaces, where one often finds that every method parameter is declared as a VARIANT. Regards Blair |
Free forum by Nabble | Edit this page |