Run-time Error 458, Variable uses an Automation Type not supported in Visual Basic

11,090

Try assigning aryOuts(2) to a Long variable (lStatusBits = aryOuts(2)). There should be no problem accesing a VT_UI4 variants in VB6, unless it's choking on For Each vElem ... loops (vElem being a variant) or variant to variant assignment. There is nothing you can do in your typelib to workaround this behavior. If nothing else works you can change variant type manually with something like Call CopyMemory(aryOuts(2), VT_I4, 2) where VT_I4 = 3

COM variants are a data structure that starts with a an int16 member called vartype that defines the type of the data stored in the variable (aryOuts(2) in your case).

VarType VT_UI4 is used for unsigned int32 values. VB6 Longs are converted to a signed VT_I4 = 3 variants.

VarType VT_UI2 is used for unsigned int16 values. VB6 Integers are converted a signed VT_I2 = 2 variants.

Modifying variant type of a variable can be very dangerous unless you know what you are doing. In this case you are quite safe to convert unsigned types to their signed counterparts without leaking memory or any other side-effects.

Share:
11,090
Erx_VB.NExT.Coder
Author by

Erx_VB.NExT.Coder

I'm passionate about code, since there's nothing else that lets you to put your thoughts, ideas & mental routines - into a computer, to do things your brain could only dream about and imagine, but never perform. Parts of my brain now live on... in various computers around the world, and if you're reading this, so does yours! :) Now that's something to think about; (pun unintended).

Updated on June 04, 2022

Comments

  • Erx_VB.NExT.Coder
    Erx_VB.NExT.Coder almost 2 years

    Basically, I'm getting this error when I try to call a function inside the upnp.dll using VB6, where upnp.dll is returning a datatype that is not supported by VB6. Previously, this same error occured but on a different function/variable, and the resolution was to open up upnp.dll in oleview.exe (to view Type Library Information) and to replace all occurences of "Unsigned Long" with just "Long" and then compile a new TypeLib with the "Unsigned" keywords removed, this solved the problem for that senario.

    Now, I need to solve the same problem but for a different function/variable, but the problem is, I have no idea which variable datatype I need to change or remove when I'm in oleview's TypeLib view of upnp.dll.

    For completeness, I'll let you know where this error is occuring, and then I will show you the relevant part of the oleview/TypeLib view that I am having trouble modifying. (for your information, upnp.dll is contained in windows\system32 and oleview.exe comes with the Windows SDK Toolkit if you do not already have it on your machine).

    I am calling the function .InvokeAction sActionName, aryIns, aryOuts where aryIns and aryOuts are Variants declared like this: Dim aryIns As Variant, aryIns As Variant - basically, I declare it generally, put any input data I need inside aryIns and I will get aryOuts with the results of the InvokeAction call. The good thing is, InvokeAction turns my general Variant into a properly dimensioned array reflecting the number of output items that are returned for the ActionName I'm using.

    Re the point I'm getting the error, I am using (for sActionName) "GetStatusInfo" on a "WanIPConnection" under the "WAN Connection Device". I don't need to define any items for aryIns since this call doesn't require or need any input arguments, but it provided (returns) 3 items (results) and puts them in aryOuts. So aryOuts ends up as an array with items from index 0 to 2 (3 items total)... and when I loop through this aryOuts array, the items 0 and 1 are printed out and viewed perfectly (without problems) but on the 3rd item (aryOuts(2)) I get the above exception.

    Basically, the first 2 arguments are just simple strings (no problem accessing these) but the 3rd argument is defined by the UPnP people as an Unsigned 4 Byte Integer (and this is where the problem lays), VB6 is unable to interpret this datatype and is not letting me access this array item (aryOuts(2)), and I could not figure out what part of the TypeLib I need to modify, since the definition for InvokeAction aryOuts is just stated as a VARIANT* in the TypeLib, and here is the relevant part of the TypeLib for your view (I've included the area I understand to be relevant, if you would like additional areas posted, let me know and I can do this):

    [
      odl,
      uuid(A295019C-DC65-47DD-90DC-7FE918A1AB44),
      helpstring("IUPnPService Interface"),
      dual,
      nonextensible,
      oleautomation
    ]
    interface IUPnPService : IDispatch {
        [id(0x600209c5), helpstring("method QueryStateVariable")]
        HRESULT QueryStateVariable(
                        [in] BSTR bstrVariableName, 
                        [out, retval] VARIANT* pValue);
        [id(0x600209c6), helpstring("method InvokeAction")]
        HRESULT InvokeAction(
                        [in] BSTR bstrActionName, 
                        [in] VARIANT vInActionArgs, 
                        [in, out] VARIANT* pvOutActionArgs, 
                        [out, retval] VARIANT* pvRetVal);
        [id(0x600209c7), propget, helpstring("property ServiceTypeIdentifier")]
        HRESULT ServiceTypeIdentifier([out, retval] BSTR* pVal);
        [id(0x600209c8), helpstring("method AddStateChangeCallback")]
        HRESULT AddCallback([in] IUnknown* pUnkCallback);
        [id(0x600209c9), propget, helpstring("property Id")]
        HRESULT Id([out, retval] BSTR* pbstrId);
        [id(0x600209ca), propget, helpstring("property LastTransportStatus")]
        HRESULT LastTransportStatus([out, retval] long* plValue);
    };
    

    The aryOuts() array I was talking about before is defined by the [in, out] VARIANT* pvOutActionArgs line in the InvokeAction declaration (in the TypeLib above). Basically, the whole array is defined as a VARIANT* (which is fine) but I am having trouble accessing the 3rd element (index item number 2) of the pvOutActionArgs array defined above, how do I modify the TypeLib around this problem?

    For reference, and those of you that are interested, Hans Passant (@HansPassant) helped me in solving the similar scenario by asking me to remove the Unsigned section of Text from the upnp.dll TypeLib exposed by oleview.exe - he helped me do this (and the rest of the steps necessary to produce and compile the new TypeLib (upnp.tbl) in the following post: Function or interface marked as restricted, or the function uses an Automation type not supported in Visual Basic

    • paulsm4
      paulsm4 over 11 years
      Let me get this straight: 1) you're trying to call a function in "upnp.dll", 2) you're trying to do this from VB6, and 3) you're getting a "Run-time Error 458" returned to you when you try to run your VB6 program in the VB6 debugger. Correct? Q: Can you post the VB code that's generating the error? Q: is this the standard "upnp.dll" system .dll that comes with Windows? Q: Which version of Windows are you running?
    • Erx_VB.NExT.Coder
      Erx_VB.NExT.Coder over 11 years
      This is the standard upnp.dll that comes with Windows (I am using Win7), all the other UPnP functions work perfectly, there is no major compatibility issues between upnp.dll and VB6, in a previous scenario, I've modified the TypeLib so that VB6 understands the types returned by upnp.dll, this is just another case of needing modification, but I'm unsure how to make this modification when the array items aren't explicitely declared (and the entire array is just declared as VARIANT*), I'm asking if anyone knows how I need to modify the array declaration in the TypeLib to make it VB6 compatible.
    • Erx_VB.NExT.Coder
      Erx_VB.NExT.Coder over 11 years
      By VB6 compatible, I mean, if anyone knows how to modify the array declaration (pvOutActionArgs) so that when a particular item in this array is an unsigned 4 byte integer (or anything unsigned, since VB6 doesnt support unsigned anything) it is made readable/accessible by VB6. Currently, its throwing the 458 error. I just need to modify the [in, out] VARIANT* pvOutActionArgs line to state that pvOutActionArgs should be turned into an array (while ensuring all items in the array are of String datatype), that (i think) would work, as VB6 can read an array with items that are of String datatype.
    • wqw
      wqw over 11 years
      Try assigning aryOuts(2) to a Long variable (lStatusBits = aryOuts(2)). There should be no problem accesing a VT_UI4 variants in VB6, unless it's choking on For Each vElem ... loops (vElem being a variant) or variant to variant assignment. There is nothing you can do in your typelib to workaround this behavior. If nothing else works you can change variant type manually with something like Call CopyMemory(aryOuts(2), VT_I4, 2) where VT_I4 = 3
    • Erx_VB.NExT.Coder
      Erx_VB.NExT.Coder over 11 years
      @wqw You are a ledgend! Your CopyMemory idea worked! I just ran CopyMemory aryOuts(2), 3, 2 (without brackets, ran it as a subroutine, & not a function), and then right after running CopyMemory with aryOuts(2) I tried to access aryOuts(2) to print out the value, and it worked! Print aryOuts(2) worked flawlessly. Without the CopyMemory, trying to assign it to a Long alone did not work, but after running it through CopyMemory, I was able to assign it to anything & read from it without issue. Feel free to copy/pase your comment as an answer as I would love to upvote it & accept it as the answer.
    • Erx_VB.NExT.Coder
      Erx_VB.NExT.Coder over 11 years
      @wqw also, jsut curious on the CopyMemory function, i read that the last argument represents the number of bytes to copy, and since it's an unsigned 4 byte int, why does it work when we specify 2 bytes instead of 4? Also, what does the number 3 signify (is VT_I4 just a constant?). Feel free to elaborate on any of this in your answer, as API docs are telling me the second argument is supposed to be the value I am copying to the 1st argument (confused). it's working, but would love to know how/why it is working if you feel like elaborating for anyone else that is interested. thanks again mate.
    • Erx_VB.NExT.Coder
      Erx_VB.NExT.Coder over 11 years
      @wqw also just curious, because upnp.dll also returns UI2's (unsigned 2 byte integers), what parameters do I need to pass to the CopyMemory function to make an aryOuts item that is UI2 readable by VB6? Do i pass 3 & 2 just like before or does anything need to change? Thanks man, you're a life saver. Had no idea CopyMemory could be used instead of altering the TypeLib for incompatible datatypes, and i'm sure many others will find this beneficial as i've had this problem before and it was never talked about or even mentioned. Big help!
    • yoka
      yoka over 11 years
      Looks me that wqw approach alters variant internal datatype (replaces VT_UI4 with VT_I4), not value. For 2 byte integers different constant (VT_I2) needs to copied.
    • Erx_VB.NExT.Coder
      Erx_VB.NExT.Coder over 11 years
      @Arvo What is the value of VT_I2, and what would you need to pass into the third (3rd) argument when passing VT_I2 as the second (2nd) argument? Also, I'm unsure what you mean by "alters variant internal datatype" - do you mean internal datatype on windows or my application/exe/running instance alone? Could this cause a problem for me in other areas of my the application that I should be aware of? In other words, is the meaning of Variant permanently altered in my application instance from that point onwards? If so, how? (or, is that even the right question), lol, sorry, just confused.
    • yoka
      yoka over 11 years
      "Alters variant internal datatype" means that suggested code changes underlying type of this variable only. Like wqw answered, variants are internally not only values, but entire structures.
    • Erx_VB.NExT.Coder
      Erx_VB.NExT.Coder over 11 years
      @Arvo so does this mean the Variant datatype will permanently become and unsigned 4 byte integer for the remainder that my exe instance is alive? Therefore, any other attempts at using Variant datatype may throw overflow or type mismatch exceptions? Do I need to do something to change things back to how they were before? If so, what CopyMemory call do I need to run in order to revert things to how they used to be after I have accessed and used my aryOuts(2) variable?
    • yoka
      yoka over 11 years
      No, just that single Variant type variable changes type.
    • Bob77
      Bob77 over 11 years
      Ok, it looks like you are after the NewUptime argument, which has the connection's "uptime" in seconds. The answer is to fiddle with the Variant's subtype as others have already described.
    • Erx_VB.NExT.Coder
      Erx_VB.NExT.Coder over 11 years
      @BobRiemersma thanks bob, basically writing a freeware interface where people can retreive all values from router, and I didn't want to get stuck out on the UI4 and UI2 types (the alternative was to ignore them and return empty string)... but i have been saved from doing that, also glad CopyMemory was mentioned, had no idea about this but it surely solves many problems.
  • Erx_VB.NExT.Coder
    Erx_VB.NExT.Coder over 11 years
    thank you very much for your answer, just a quick question, when calling CopyMemory for VT_I2, what do I pass for the last argument? I recall, when we called CopyMemory using VT_I4, we passed 2 for the last argument. What do we pass for this last argument when we call CopyMemory with VT_I2? Thanks. Upvoted & Accepted.
  • yoka
    yoka over 11 years
    Last argument is always 2 - it is size of variant type identifier.
  • Erx_VB.NExT.Coder
    Erx_VB.NExT.Coder over 11 years
    @arvo thanks for that clarification, that totally solves the problem.