Literal description of object type - vb.net

VB2010 with ArcObjects. Im having a problem recalling how to do this. I can test for an object type and then do something if it is the proper type. All else I want to display a message with the type that is not supported. So I have:
Dim pRasRenderer As IRasterRenderer
pRasRenderer = pRasterLayer.Renderer
If TypeOf pRasRenderer Is IRasterClassifyColorRampRenderer Then
'process the layer
Else
Debug.Print "Type not supported: " & pRasRenderer.ToString
End If
If not supported the print statement should read
"Type not supported: IRasterStretchColorRampRenderer"
or any of the other types that I do not process. But All I get back is
"Type not supported: System.__ComObject"
I tried GetType() and TypeName. Just cant remember if I can do this or not.

With COM, the type isn't IRasterStretchColorRampRenderer, it's some COM type that (most likely) implements quite a few distinctly different interfaces. Given that you're working from .NET, you'll get __ComObject any time you try to access the "type" of the object directly.
The actual "type" of the object which implements IRasterStretchColorRampRenderer, for example, is more than likely a native implementation of a COM CoClass. As such, you'll never get a "managed" type name from .NET code for this.
Unfortunately, this means that you're best solution is likely to report that the type passed in is not supported without trying to report the actual type passed into the method. This would likely be something like:
Debug.Print "Type not supported: Current layer is not using a Classify Color Ramp Renderer"

Related

How to determine the type of control (or object)?

There are three only ways, which are discussed on the Internet and on this forum in particular
How to check type of object in VB 6 - Is there any method other than 'TypeName'
How to check type of Object in VB 6 ? - I do not want to use 'TypeOf' method
How to check type of object in VB 6 - Is there any method other than 'TypeName'
Namely:
- the string method TypeName
- the clumsy TypeOf
- by name of control, defined in a specific notation
Am I right, that there are no built-in tools to get a normal numeric constant, like the MsoControlType?
.
Direct answer
Am I right, that there are no built-in tools to get a normal numeric constant, like the MsoControlType?
Yes, that is correct. Unless you implement your own, using the techniques you've listed.
Well, excluding VarType, which will return vbObject given any object reference.
Pedantic answer
What you're referring to as a "normal numeric constant" has strictly nothing to do with a control's type - these MsoControlType constants are just Enum values that the CommandBar API uses to determine the type of the control to create when you ask to create one.
MsoControlType.msoControlButton is not a type of control, it's a constant with a value of 1. Nothing more, nothing less - the type of a control is a class, not a numeric constant:
?TypeName(Application.VBE.CommandBars(1).Controls(1))
CommandBarPopup
CommandBarPopup is the class (and thus the type of the control), not msoControlPopup, and not 10:
A type is what you give to TypeOf [variable] Is [*type*], or Dim [variable] As [*type*]: it's an identifier that refers to a class/interface (in the case of an object, of course - a type could also be one of the primitives, e.g. Integer or Boolean). And given the weakness of reflection capabilities in VB6/VBA for lack of a .net-like type system where a type itself is an abstraction that can be worked with, a custom Enum type and a function taking an object, featuring a Select Case block with TypeOf checks, is your best bet for that function to return a normal numeric constant that represents the type of the provided object.

What is the vbError returned by VarType in VB6?

I have been searching for this all over the web, but everything is either talking about the ErrObject class, or the constant vbError returned by the VarType function. I want to know what that type actually is, e.g. an integer is something like 4, a string is something like "hello world", etc.
For a little background, here is a link to the official MSDN page about VarType, which shows all the constants it returns and what they represent. What is Error value?
If you are familiar with COM in C/C++, you should know that from that perspective VarType() is a simple function that essentially extracts the value of the vt member from the Variant passed in as a parameter. The possible values of the vt member are documented in many places, such as here.
If you check inside of the COM system headers (e.g. WTypes.h distributed as part of in the Windows SDK), you will see that the VbError value of 10 indeed maps to the C/C++ enum value of VT_ERROR.
enum VARENUM
{ VT_EMPTY = 0,
...
VT_ERROR = 10,
...
} ;
The MSDN link above describes the meaning of a vt that equals VT_ERROR as follows:
An SCODE was specified. The type of the error is specified in scode.
Generally, operations on error values should raise an exception or propagate the error to the return value, as appropriate.
So, here's basically what it means:
A Variant obviously supports storing many types of values, and among them is the obscure possibility of storing an "Error Code". More correctly, these codes are formally called scode's, because they can indicate many types of "success" as well as "failures". Most people refer to these codes as HRESULTs.
These codes are the same kind of "Error Codes" that you get from Err.Number in VB6. So, you can tell a Variant to distinguish an "Error Code" from just a plain number.
In reality, few programs or COM components - if any - will ever put error codes in Variants. Almost everybody just issues COM Exceptions to communicate errors (this mechanism is exposed in VB6 via the Err object). Even those components that return error codes outside of the COM Exception mechanism, would likely do so in typed variables (e.g. Long's).
Therefore, the reason this possible return value exists is for completeness. You will almost never see it in real life.
(Edit: Remove bit about not being able to create an "Error" variant. #Joe proved me wrong on that. You can use CVErr() to create one)
In VB6 and VBA, error values are created by calling the CVErr function.
This function returns a Variant whose VarType is vbError, and for which the IsError function returns True.
A typical use case for this is an Excel UDF that returns a Variant: if you return an error value, it will display as #VALUE!.

GetType on generic types

I'm trying register presenters with Windsor using the convention based method but trying to do this in VB.NET, but the problem is it does not want to compile this statement:
Dim type = GetType(AbstractPresenter(Of))
I am getting : Too few type arguments to AbstractPresenter(Of TView, TPresenter)
Which I don't understand because this is a valid statement according to question. Also showing valid in other C# to VB.NET converters when converting typeof(AbstractPresenter<>).
Any ideas?
There are two type arguments, and you need to specify this, just as you would do for multi-dimensional arrays:
Dim type = GetType(AbstractPresenter(Of ,))
Looks weird, but now the compiler knows that AbstractPresenter expects two type arguments.
By the way, C# has the same requirement. So the above would be written as:
var type = typeof(AbstractPresenter<,>);

In VB6, how do I call a COM object requiring a pointer to an object?

I'm having trouble with a .NET Assembly that is com visible, and calling certain methods from VB6.
What I have found is that if the parameters are well defined types, (e.g. string), calls work fine. If they are higher level objects, it raises a runtime error '438' suggesting that the property or method is not present. I suspect that this is a question of having the correct signature on the call, but I can't see how to do this correctly.
I believe that I've done everything correct on the .NET side (ComVisible, public interfaces, etc. and even have it down to a simple enough case).
Looking at the output from the typelib viewer, I have the following:
dispinterface ISimple {
properties:
methods:
[id(0x60020000)]
void Add([in] ISimpleMember* member);
[id(0x60020001)]
ISimpleMember* Create();
};
OK. So I have 2 methods in my ISimple interface. One takes an ISimpleMember (Add), whilst the other, returns an ISimpleMember.
The corresponding code in VB looks like this:
Dim item As ISimpleMember
Dim simple As simple
Set item = New SimpleMember
item.S1 = "Hello"
item.S2 = "World"
Set simple = New simple
simple.Add (item) <---- This raised the run time error 438
Set item = simple.Create <---- This works fine, returning me an ISimpleMember
I've tried a couple of things:
1. Dim item as SimpleMember (makes no difference)
2. simple.Add(ObjPtr(item)) - Syntax error
3. simple.Add(ByRef item) - Syntax error
Basically, The run time error is the same as if I had
simple.AMethodThatIHaventWritten()
Also, If I browse References in the VB6 Environment, The Add method is well defined:
Sub Add(member As SimpleMember)
I've found the answer I believe. It was very simple:
When calling a SubRoutine, I shouldn't put the name in braces. the call should have been:
simple.add member
rather than
simple.add(member)
If I change it to a function (i.e. return a value rather than void) the braces are necessary
This seems to work
(Probably) The top 3 VB6 coding mistakes made by devs who now mainly code in C#, Javascript etc. Are:-
Placing ; at the end of lines. Its a syntax error very easily spotted and picked up the compiler.
Not placing Then on the other side of an If condition expression. Again its a syntax error.
Calling a method without retrieving a value and yet using ( ) to enclose the parameter list. With multiple parameters this is a syntax error and easily found. With only one parameter the use of ( ) is interpreted as an expression. Its the result of the ( ) expression which is passed as parameter. This causes problems when ByRef is expected by the callee.

VB reflection in for each loop

I'm attempting to use an unknown type in a for each loop as per the following code:
private sub ReflectThis(ByVal rawData As Object())
Dim dataType As Type = rawData(0).GetType()
Dim properties As PropertyInfo() = dataType.getProperties()
For Each item As dataType In rawData ''//AAAA
For Each property As System.Reflection.PropertyInfo properties
''//reflected code use here
The issue that I get is on the line marked AAAA. It complains that 'dataType' is not declared, which I take to mean it does not exist as a proper class.
The intent is to call a web service elsewhere, and regardless of which web service I call, use reflection to add the resulting data struct object's information to a database.
What, if any, are the restrictions on doing something like
Dim myObject As variableInstanceOfTypeObjectHere
or am I making a more fundamental error? If I'm right, what are the workarounds, if any?
When you declare a variable "As" a type, that means you know the type at compile time. That lets the compiler check what you're doing with it. In this case, you don't know the type at compile time - you're getting it at execution time. All you know is that each item is an object - so either don't specify the type (as suggested by Joel) or specify it as Object:
For Each item As Object In rawData ''//AAAA
Just don't specify the type:
For Each item in rawData