Quote Originally Posted by fafalone View Post
Using QueryInterface

The issue came up again for me today when I started using IShellItem2- one of the ways to get that interface by using .QueryInterface from an IShellItem object, which is actually from its parent IUnknown. Due to the way IUnknown was set up in this project, that function isn't visible on IShellItem or any other interface (they all inherit from IUnknown). They can be made visible by changing all the : stdole.IUnknown to just IUnknown, but I'm unsure of the consequences of such a change, and olelib is too massive to confirm there's no side effects.
But fear not, if you need to access .QueryInterface, use the method in this routine that gets IShellItem2 from IShellItem

Code:
Dim psi As IShellItem
Dim psi2 As IShellItem2
Dim pUnk As olelib.IUnknown 'should be explicitly typed since there's another hidden IUnknown in VB and it will cause errors

Call SHCreateShellItem(0, 0, pidl, psi) 'pidl of whatever file/object you're working with, code omitted

Set pUnk = psi
pUnk.QueryInterface IID_IShellItem2, psi2
And now you have a ready-to-go IShellItem2. This method is also used, for example, to get an IPropertyStore interface from an IShellLinkW.
Manually invoking IUnknown's QueryInterface method isn't actually necessary in Visual Basic. The Set statement already does it for you.

Quote Originally Posted by Guy Eddon and Henry Eddon
QueryInterface: The Visual Basic Way

. . . If you need access to the other (nondefault) interfaces supported by an object, you can execute a QueryInterface using the Set statement. If needed, the Set statement calls the IUnknown::QueryInterface method to cast the rvalue interface pointer to the type of the lvalue reference. For example, the following code snippet shows two references—MyRef1 and MyRef2. MyRef1 is declared as an IUnknown interface pointer; MyRef2 is a pointer to the IMyInterface interface. When MyRef2 is set to MyRef1, a QueryInterface call that requests the IMyInterface interface pointer from the object pointed to by MyRef1 takes place.

Code:
Dim MyRef1 As IUnknown
Set MyRef1 = New MyObject

Dim MyRef2 As IMyInterface
Set MyRef2 = MyRef1 ' QueryInterface executed!
Quote Originally Posted by Jose Mojica
How Visual Basic COM+ Objects Work Internally

. . .

Why does every vtable need to have these three methods? By enforcing this rule, a client may navigate to any lookup table from any starting point. In other words, suppose that I have the following code:

Code:
Dim Checking As CChecking
Set Checking = New CChecking

Call Checking.OrderChecks(100, 132)

Dim Acct As IAccount
Set Acct = Checking

Call Acct.MakeDeposit(500)

Dim Checking2 As CChecking
Set Checking2 = Acct
The code begins by using the default lookup table, then needs to switch to using the IAccount lookup table (or vtable). The line that reads Set Acct = Checking basically calls the QueryInterface function in the default vtable. The resulting vptr is stored in the Acct variable. I can then use that lookup table to switch to any other interface. In the code above I have a second variable to store the default vtable, Checking2. Which interface can I use to switch to the default interface? I can use any other interface, because they all have the QueryInterface method first. In VB you never have to see the QueryInterface method call. However each time you change the interface you are talking to, you are basically telling VB to call QueryInterface on the particular interface to obtain a second vptr.
These 2 lines of code can therefore be reduced to just 1:

Code:
'Set pUnk = psi
'pUnk.QueryInterface IID_IShellItem2, psi2

Set psi2 = psi
The code can be simplified even further by taking advantage of the fact that the IShellItem2 interface inherits from IShellItem:

Code:
Call SHCreateShellItem(0, 0, pidl, psi2)