Announcement

Collapse
No announcement yet.

How to trigger a run-time error in VB COM Client from a PB COM Server?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to trigger a run-time error in VB COM Client from a PB COM Server?

    Has anyone been able to get "Method ObjResult =" to trigger a run-time error in VB or VBScript?

    I'm an old VB guy and I tend to look for analogs in PowerBasic for the things I've used in VB.

    In VB you can trigger a run-time error in a COM client by raising an error via the VB Err object:

    Code:
    Err.Raise vbObjectError + VBErrorsOffset + YourErrorNumber [,Source] [,Description] [,Helpfile] [,Helpcontext]
    It appears that the analog in PB is some combination of the "ObjResult =" and the "IDispInfo.Set" statements:

    Code:
    Method ObjResult = hResult
    or
    Property ObjResult = hResult
     
    and
     
    IDispInfo.Set code& [, source$, desc$, help$, context&]
    I've created a PowerBasic COM server that I'm instantiating from VB and whenever I execute the following method I get a fatal VB crash:

    Code:
    Method Bang <92> () As Long
      Method = 999&
      Method ObjResult = &H80040000&
    End Method
    No matter what value I've used with ObjResult, If I set the MSB, I always get a fatal VB crash.

    So, what is the trick to triggering a run-time error in a VB COM client?

    -Wes
    Last edited by WesWesthaver; 1 Mar 2009, 03:12 PM.

  • #2
    I tested PowerBASIC's handling of rich error, and it does work with VB4.0.
    I used the Glossary sample that ships with PB to do the tests. Unfortunately, the sample
    is introverted. That is, it is blindly using ANSI strings. By golly, this is COM, it should
    assume the strings it receives are Unicode. It should also return them as Unicode. It is
    fine using ANSI strings internally, but when communicating with COM objects do it using Unicode.

    To support rich error reporting, your interfaces must be dual(INHERIT IDispatch).

    Anyway, to get the Definition property from the Glossary sample to raise and exception,
    I did the following:
    Code:
        PROPERTY GET Definition(BYVAL w AS STRING) AS STRING
          LOCAL i AS LONG     
          
          w = ACODE$(w)
    
          ARRAY SCAN Glossary(), COLLATE UCASE, =w, TO i
          DECR i
          IF i < 0 THEN
            IDISPINFO.SET &H80004005&, "Glossary", "Item is not in dictionary", "", 0
            PROPERTY OBJRESULT = &H80004005& ' E_FAIL
            PROPERTY = "Undefined"
          ELSE
            PROPERTY = UCODE$(Definitions(i))
          END IF
          
        END PROPERTY
    I used the error code E_FAIL in this test, but it can be any application-defined value.
    PowerBASIC automatically sets the hResult value to DISP_E_EXCEPTION.

    It appears you are doing the same thing.
    Dominic Mitchell
    Phoenix Visual Designer
    http://www.phnxthunder.com

    Comment


    • #3
      Dominic, Thank you for posting the sample code.

      A little background: I'm using VB 6 with Service Pack 6 and my interface is derived from IDispatch.

      I tried your code and it worked. But I noticed a slight difference in the ObjResult value you used and the one I used:

      &H80004005& = Yours
      &H80040000& = Mine

      The difference has to do with the "Facility" vs. "Code" bits.

      I derived my number from some notes that I pulled from MSDN concerning COM errors many years ago. Here are my notes:

      Code:
      Some background on COM Errors:
       
      Since COM errors are structured 32 bit numbers we can consult the
      Microsoft COM documentation to discover that a COM error is structured
      like this:
       
      Bit 31 Severity Code 1=failure, 0=success 
      Bit 30 Reserved 
      Bit 29 Customer Code Flag 
      Bit 28 Reserved Bit 
      Bit 27 Reserved Bit 
      Bits 26 - 16 Facility Code:
      Bits 15 - 0 Facility Status Code 
       
      Facility Codes:
      FACILITY_NULL=0, 
      FACILITY_RPC=1, 
      FACILITY_DISPATCH=2, 
      FACILITY_STORAGE=3, 
      FACILITY_ITF=4, 
      FACILITY_WIN32=7, 
      FACILITY_WINDOWS=8, 
      FACILITY_SSPI=9, 
      FACILITY_CONTROL=10, 
      FACILITY_CERT=11 
       
      In order to propagate errors specific to a COM component back to the
      client application, Microsoft gives us the vbObjectError constant to allow
      us to properly set the hi-word of our COM errors.
       
      If we look at the bit pattern of vbObjectError:
      (10000000-00000100-00000000-00000000) (&H80040000)
      we see that it sets the Severity Code to failure and the Facility Code to
      FACILITY_ITF (interface error).
       
      So when we use vbObjectError we are declaring a failure of the COM
      interface. The Low-word (bits 15 - 0) are available for the Facility Status
      Code meaning: our custom errors.
       
      Visual Basic defines an error value to be a 16 bit number from 0 - 65535.
      Microsoft recommends that we not use the error numbers already defined
      by Visual Basic (0 - 512) for our custom errors. This leaves everything
      from 513 - 65535 undefined and available for us to use for our custom
      errors.
      The wierd thing is that the WIN32API.INC file defines things differently:

      Code:
      ' Constants from winerror.h ===================================================
      ' Values are 32 bit values layed out as follows:
      '
      '  3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
      '  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
      ' +---+-+-+-----------------------+-------------------------------+
      ' |Sev|C|R| Facility              | Code                          |
      ' +---+-+-+-----------------------+-------------------------------+
      '
      ' where
      '
      ' Sev - is the severity code
      '
      ' 00 - Success
      ' 01 - Informational
      ' 10 - Warning
      ' 11 - Error
      '
      ' C - is the Customer code flag
      '
      ' R - is a reserved bit
      '
      ' Facility - is the facility code
      '
      ' Code - is the facility's status code
      '
      '
      ' Define the facility codes
      '
      %FACILITY_WINDOWS_CE = 24
      %FACILITY_WINDOWS = 8
      %FACILITY_URT = 19
      %FACILITY_UMI = 22
      %FACILITY_SXS = 23
      %FACILITY_STORAGE = 3
      %FACILITY_STATE_MANAGEMENT = 34
      %FACILITY_SSPI = 9
      %FACILITY_SCARD = 16
      %FACILITY_SETUPAPI = 15
      %FACILITY_SECURITY = 9
      %FACILITY_RPC = 1
      %FACILITY_WIN32 = 7
      %FACILITY_CONTROL = 10
      %FACILITY_NULL = 0
      %FACILITY_MSMQ = 14
      %FACILITY_MEDIASERVER = 13
      %FACILITY_INTERNET = 12
      %FACILITY_ITF = 4
      %FACILITY_HTTP = 25
      %FACILITY_DPLAY = 21
      %FACILITY_DISPATCH = 2
      %FACILITY_CONFIGURATION = 33
      %FACILITY_COMPLUS = 17
      %FACILITY_CERT = 11
      %FACILITY_BACKGROUNDCOPY = 32
      %FACILITY_ACS = 20
      %FACILITY_AAF = 18
      It appears that the value you used defines only the "Status Code." While mine defines the "Facility Code"

      At this point, I don't know what to make of this.

      Do you have any thoughts on this?

      -Wes
      Last edited by WesWesthaver; 1 Mar 2009, 12:53 PM.

      Comment


      • #4
        The wierd thing is that the WIN32API.INC file defines things differently:
        Yes, the Severity code is made up of bits 30 and 31.

        I used 0x80004005 because I am lazy. It sets both the facility and status codes. Its facility
        code just happens to be ITF_NULL(0). Microsoft recommends that when using FACILITY_ITF you use
        errors in the range of 0x0200 to 0xffff. Therfore, try 0x0400 for the Code field to see if VB
        still crashes. This gives an error code value of 0x80040400.

        0x80040000(Invalid OLEVERB structure) is already defined by the system. Its Code field is
        set to zero. Why VB is crashing on this error code is a mystery to me. Maybe it is doing
        a CoTaskMemFree on the lpszVerbName member of an OLEVERB structure it thinks exists.
        Dominic Mitchell
        Phoenix Visual Designer
        http://www.phnxthunder.com

        Comment


        • #5
          Dominic,

          After a bit of experimentation, it appears that VB6 will crash under these two conditions:

          1) If you have a:
          "Method ObjResult = SomeValue" statement

          without an accompanying:

          "IDispInfo.Set SomeValue [, source$, desc$, help$, context&]" statement.
          2) If you use the abreviated version of the:
          "IDispInfo.Set SomeValue" statement (without the optional parameters.)
          #2 is particularly odd since the PB documentation says that the source$, desc$, help$ and context& parameters are optional. I guess that a PB COM client may consider them optional but apparently a VB6 COM client requires them.

          Also, VB6 doesn't seem to care much about the value of the hResult as your examples and mine both worked fine once I realized that VB requires both the "ObjResult =" and the "IDispInfo.Set" statements to avoid crashing.

          Now that I have all of this figured out, it looks like I'll be able to trigger run-time errors with meaningfull values in my COM clients.

          Yay!

          Thanks again,
          -Wes

          Comment


          • #6
            I guess VB4 is better written than VB6, because I had carried out tests with and without values for IDispInfo.Set and it did not crash in both cases.
            Dominic Mitchell
            Phoenix Visual Designer
            http://www.phnxthunder.com

            Comment

            Working...
            X