oleexp.tlb is a type library containing a vast collection of Windows shell interfaces and interfaces for a number of related features, forking an older project in order to bring in the expansive set of new interfaces introduced in Windows Vista, and including the smaller number introduced in Windows 7 through 10. It also includes virtually all structures, types, and enums used by these interfaces, and a limited set of related APIs. While some of the interfaces may be present in system libraries, these, and the original versions for everything from the SDK, often use variable types that are incompatible with VB5/6; all interfaces have been reviewed and modified to use variable types that ensure compatibility with VB5 and VB6.
History
oleexp is based on Edanmo's olelib, forked and expanded. It's a very strong foundation for any desktop application.
Back in the day, E. Morcillo released the very comprehensive interface library olelib.tlb (Edanmo's OLE interfaces & functions). It contained a massive number of interfaces, enums, structs, etc. But after a point it was no longer updated and thus doesn't have any interfaces from Windows Vista or Windows 7. So I set out to bring these interfaces to VB, and quickly realized that so much would have to be duplicated and would then be conflicting, that the only sensible way to approach this would be to fork and expand olelib, particularly since anyone using oleexp would almost certainly be using olelib.
If an interface isn't included that you would like to use, or you find a bug, let me know in this thread, or through a private message or e-mail (fafalone at gmail).
This project is completely free to use and modify as you see fit, for any purpose, including commercial. All that's requested is an acknowledgement and if you're distributing a modified version publicly, to change the project GUID to avoid conflicts, found in oleexp.odl.
Requirements and Installation / Setup
Requirements
oleexp can be used with any version of Windows. If you attempt to call an interface/API that is not present on the current OS version, an error will occur, but the presence of those definitions in the library do not effect the usage of any other interfaces/APIs.
No other files are required. You do not need to add oleexpimp or mimelib unless you specifically want to use them. All of the addon modules are optional, but mIID is strongly recommended; it saves a ton of time by allowing direct IID_ / FOLDERID_ / etc usage without having to convert a string to a GUID.
Installing oleexp
oleexp.tlb (and oleexmpimp.tlb/mimelib.tlb if you're using them) should be placed in a permanent, common folder all your projects can access-- typically SysWow64 (or System32 on a 32-bit Windows install). You can register it manually, but I've never had trouble with the registration VB6 performs when you add it for the first time. IMPORTANT: oleexp is a common file, and you should only have one copy installed. Do not place multiple copies in the folders of projects that use it. Also, it's a direct replacement for olelib; a project should not have both.
The add-on modules are updated too, so those and any other files you're keeping, should go in a common directory for your VB projects, not the system folder. E.g. all the sample projects point at ..\tl_ole by default, so if you keep your projects in C:\vb\Prj1 Prj2 etc, a good spot would be C:\vb\tl_ole.
Setting up oleexp in your project
oleexp.tlb is added via Project->References. As with any typelib, a sample project may reference a different location, if so, update the location if the References window says it's 'MISSING:' NOTE: Like all TLBs, oleexp is a dependency only for the IDE. Once your project is compiled, the TLB is no longer used. It does not need to be present on end user machines. See the 'File Size' section in post #2 for additional details.
Upgrading from olelib
If you're upgrading an existing project that uses the original olelib, the vast majority of those interfaces have not been modified, but a few have had minor changes to use different variable types. Explicit declares can be changed via Replace; just replace "As olelib.vartype" (or oleexp3.vartype if upgrading from oleexp 3.x) with "As oleexp.vartype". If you get an error or something has stopped working, check the variable type and if it's ByVal or ByRef.
[VB6/Win7+] Using the Windows UI Ribbon Framework - Take advantage of the fancy Ribbon seen in Explorer, Wordpad, and Paint (and very similar to Office) in your app. Brings the basic version of my twinBASIC series to VB6. IUIRibbonFramework, IUIApplication, IUISimplePropertySet, IUICommandHandler
[VB6/Win8+] Displaying emojis with color - Using oleexp's recently added DirectX interfaces to render text with the emojis in color (where supported by the font).
UPDATED 18 Jun 2022[VB6] ucShellBrowse: A modern replacement for Drive/FileList w/ extensive features - A highly customizable UserControl for browsing the file system with all the modern shell features; customize from a simple Directory List / FileList control in VB through a full-fledged Explorer-like window, and everything in between. First use: IColumnManager, ICategoryProvider, ICategorizer, IPropertyStoreCapabilities, IPropertyEnumType, IPropertyEnumTypeList; dozens of others previously demonstrated.
[VB6, Vista+] Core Audio - Peak Meter - Check whether or not audio is playing on the default rendering device, and display the most recent peak volume level in a meter. IAudioMeterInfo, IMMDevice, IMMDeviceEnumerator
[VB6] Intro to the Windows Imaging Component (WIC): Scale and convert to JPG or PNG - Open a variety of image types then optionally scale and convert to PNG or JPG. IWICImagingFactory, IWICBitmapDecoder, IWICBitmapFrameDecode, IWICFormatConverter, IWICBitmapScaler, IWICBitmapSource, IWICBitmapEncoder, IWICStream, IWICBitmapFrameEncode, IPropertyBag2
[VB6] Virtual File Drag Drop - Virtual files are created from data that's only read when dropped, instead of beforehand. Uses some neat IDataObject tricks and also supports multiple files at once. IDataObject, IStream
[VB6, Vista+] Add the Windows Send To submenu to your popup menu - Uses shell interfaces to implement the Send To menu exactly as Explorer does. IShellItem, IShellItemImageFactory, IDataObject, IDropTarget, IEnumShellItems, IShellItemArray, IFileOpenDialog
[VB6] Get extended details about Explorer windows by getting their IFolderView - Get that interface and many more for highly detailed information about open Explorer windows and their items. Changing window settings and selections is also possible. IShellWindows, IFolderView, IFolderView2, IShellBrowser, IShellView, IEnumVARIANT, IShellItem, IDispatch
[VB6, Vista+] List all file properties, locale/unit formatted, by modern PROPERTYKEY - Demonstrates use of the modern PROPERTYKEY/IPropertyStore system, with PROPVARIANT handling made simple. Update includes a new sample project attached displaying a ListView of properties and using IPropertySystem to create a property display management technique.
See Also: A compact function to retrieve any property by name, which loads a property store directly by file name without IShellItem, and then displays a formatted string for anyone property name. IPropertyStore, IPropertyDescription, IPropertySystem, IShellItem2, IShellFolder2
[VB6] Easy image disp/edit; scale/rotate, show animated gifs, conv2JPG, +more; No GDI+/DLL - Shows off oleexp 3.1's new image interfaces, which make dealing with images and imagelists far easier. Scale, rotate, show animated GIFs, transcode to JPG/BMP, get image properties, resize an imagelist, all with mostly single-line calls. IShellImageData, IShellImageDataFactory, ITranscodeImage, IImageList, IImageList2, IShellItem, IFileOpenDialog, IShellItem, IShellItemArray, IEnumShellItems, IPersistFile, IExtractImage.
[VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handler - Don't limit your previews to just images anymore; documents, music, videos, PDFs, Powerpoint/Excel, and lots more have existing or available preview handlers you can access with IPreviewHandler. IPreviewHandler, IInitializeWithFile, IInitializeWithStream, IInitializeWithItem, IUnknown
[VB6, Vista+] Code snippet: KnownFolders made easy with IKnownFolderManager - The KnownFolderManager coclass (a default implementation you can get with the New keyword) greatly simplifies all aspects of working with special folders, their locations, properties, names, and identifiers. IKnownFolderManager, IKnownFolder, IShellItem, IShellItemImageFactory
[VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder - Use IExplorerBrowser and INamespaceTreeControl as a simple way (they have default implementations-- you don't even need a ListView, the whole thing is automatically created right on your form) to add a full-fledged Explorer view to your form. IExplorerBrowser, IExplorerBrowserEvents, INamespaceTreeControl, INamespaceTreeControlEvents, IDataObject, IShellView, IShellItem
[VB6] API File Drag from multiple paths w/o native OLE or dragsource, SHDoDragDrop - Create an IDataObject with SHCreateDataObject/SHCreateFileDataObject to initiate a drag operation with very low-level access to all elements of the drag operation. Later comments in the thread show the use of DragDropHelper coclass (IDragSourceHelper, IDragSourceHelper2). IDataObject, IDragSourceHelper2
[VB6] Using the new IFileDialog interface for customizable Open/Save (TLB, Vista+) - Has the benefit of allowing easy access to events from the dialog, as well as making it very easy to add your own controls. IFileDialog2, IFileDialogCustomize, IFileOpenDialog, IFileSaveDialog, IFileDialogEvents, IShellItem, IShellItemArray, IEnumShellItems
[VB6] Working with Libraries (Win7+) - Uses the IShellLibrary interface to get all folders in a library, add more, get the default save location, get the icon, and even create a new library. Also shows the use of IEnumShellItems and IShellItemArray. IShellLibrary, IShellItem, IShellItemArray, IEnumShellItems
Add-ons are optional modules full of definitions related to a particular feature set, like a header #include in other languages. Like adding mPKEY.bas is exactly the same as '#include propkey.h' in a C/C++ project. Only the items you actually use get compiled into the .exe, so don't worry about a bloated executable containing unused GUIDs.
mIID.bas (UPDATED with 6.6) - All IID_/BHID_/FOLDERID_/SID_ values, usable directly without CLSIDFromString, e.g. SHCreateItemFromIDList(pidl, IID_IShellItem, psi), never have to worry about converting a string. Strongly recommended for all oleexp projects.
mPKEY.bas - All PROPERTYKEY's from propkey.h, directly usable.
mCoreAudio.bas / mDirectShow.bas / mPortableDevices.bas / mWIC.bas / mDirectX.bas / mSpeech.bas / mUIA.bas - IIDs and functions used exclusively by those particular features.
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
(cont. from above due to post length limit) Known Issue
NOTE: The latest releases (4.7+) inadvertently had a new GUID from 4.6, when it was meant to have the same. It's recommended that you follow the major version upgrade procedure if you're upgrading from v4.6 or earlier:
Upgrading From Earlier Versions
Versions 1.x and 2.x have the same typelib name as 4.x+ (oleexp) but a different GUID. To upgrade from these versions, you don't have to change anything in your code (except for a few interfaces that have updated definitions), just update the reference.
1) Before opening any project, delete the old oleexp.tlb file, or oleexp3.tlb if upgrading from 3.x, assuming you correctly have it in a common location like SysWOW64. If you're updating the location you can ignore the old one. Copy the latest version of oleexp.tlb to the common location. Remember, oleexp.tlb is a common file, all projects must reference a single copy, they must not have their own.
2) Now, open any project still referring to the old version. If you get a message about the missing TLB, just ignore it and close the dialog.
3) Go to the Project->References... menu item. Uncheck the reference to oleexp.tlb, whether or not it says 'MISSING:'.
4) Click OK, then reopen the same dialog.
5) Click the Browse... button and choose the new version of oleexp.tlb. Click OK.
-
6) (Only if upgrading from version 3.x) Run a search and replace on your code to replace all instances of oleexp3 with oleexp
(oleexp 6.6 - Release 06 June 2024)
-Added Direct3D 9 interfaces(courtesy of The trick for the core interface set
-Added DXVA2 and DXVAHD interfaces
-Added all Background Intelligent Transfer Service interfaces and coclasses
-Large expansion of Direct3D 12 interfaces
-Added Direct3D 12 Video interfaces
-Some misssing Direct3D 11 interfaces
-Added Windows Media Device Manager interfaces and coclasses
-Added DirectML interfaces (directml.h, 100%)
-Added Virtual Disk Service interfaces
-Added UPnP interfaces (upnp.h, upnphost.h, 100%)
-Added INATExternalIPAddressCallback Interface, for use with NATUPnP Type Library v1.0 (NATUPNPLib, included with Windows)
-Added VBA-related interfaces from vbinterf.h (100% coverage)
-(Bug fix) MFMEDIASOURCE_CHARACTERISTICS, MF_SOURCE_READER_FLAG, and MF_SOURCE_READER_CONTROL_FLAG enums all values incorrect.
-(Bug fix) SHCreateStreamOnFileEx was defined in wrong dll.
-(Bug fix) The following UDTs contained unsupported types: LOGPALETTE, NETRESOURCE, OLEUICONVERT, PUBAPPINFO, KSJACK_SINK_INFORMATION, D3D12_META_COMMAND_DESC, D3D12_AUTO_BREADCRUMB_NODE1, D3D12_FEATURE_DATA_PROTECTED_RESOURCE_SESSION_TYPES, D3D12_VIDEO_EXTENSION_COMMAND_PARAMETER_INFO, SPDISPLAYPHRASE, BASEBROWSERDATAXP, BASEBROWSERDATALH, TOOLBARITEM, and DML_ADAM_OPTIMIZER_OPERATOR_DESC.
(oleexp 6.5 - Released 05 April 2024)
-Added all newer DirectWrite interfaces (dwrite_1.h, dwrite_2.h, dwrite_3.h)
-Added legacy Sync Manager interfaces/coclasses (mobsync.h, 100%)
-Added Photo Acquisition interfaces and coclasses (photoacquire.h, 100%)
-Added NetCon interfaces
-Added IPrintDocumentPackage* interfaces and coclasses (DocumentTarget.idl, 100%)
-Added Credential Provider interfaces
-Added UI Animation interfaces and coclasses
-Added IThumbnailStreamCache and coclass ThumbnailStreamCache. Note: Due to simple name potential conflicts, flags prefixed with TSC_. A ByVal SIZE is split into two Longs.
-Added Radio Manager interfaces and some undocumented coclasses to use them.
-Added IAccessControl/IAuditControl interfaces
-Added certain shdeprecated.h interfaces still in undocumented use
-Added security center interfaces from iwscapi.h
-(Bug fix) Several WIC interfaces had improper ByRef String (as Long) types.
-(Bug fix) IFilterCondition incorrect inheritance
-(Bug fix) ICommDlgBrowser2,3 string members incorrect.
-(Bug fix) DWRITE_RENDERING_MODE incomplete
The following was listed as added in v5.3 but was never actually compiled in until now:
-Added Sync Manager interfaces and coclasses (SyncMgr.h), including undocumented ITransferConfirmation/coclass TransferConfirmationUI.
(oleexp 6.4 - Released 10 August 2023)
-Added Sensor API and Location API. Sensor pkeys added to mPKEY.
-Added IStorageProviderHandler
-Added DirectSound8, courtesy of The trick/mossSOFT DSVBLib
-Added Distributed Transaction Manager basic interfaces
-Bug fix: Ribbon interfaces were not Implements-compatible and one used a custom UDT instead of a Variant.
(oleexp 6.3 - Released 09 June 2023)
-Added active scripting interfaces (ActivScp.h)
-Completed Core Audio interfaces
-Added Package Manager interfaces from msopc.idl/coclass OpcFactory
-Added DirectComposition Presentation Manager interfaces.
-Added some missing base OLE/COM interfaces: IDataAdviseHolder, IOleAdviseHolder, IDropSourceNotify, IEnterpriseDropTarget, IContinue, IQuickActivate, IAdviseSinkEx, IPointerInactive, IOleUndoManager, IEnumOleUndoUnits, IOleParentUndoUnit, IOleUndoUnit, IViewObjectEx, IOleInPlaceSiteWindowless, IOleInPlaceSiteEx, IOleInPlaceObjectWindowless.
-ribbon.odl, UI Ribbon interfaces, had been sitting around in the source folder unfinished forever; it's now complete and added (source file renamed exp_ribbon.odl).
-Added IContextCallback interface with coclass ContextSwitcher.
-Added Disk Quota interfaces IDiskQuotaControl (with coclass DiskQuotaControl), IDiskQuotaUser, IDiskQuotaUserBatch, IEnumDiskQuotaUsers, and IDiskQuotaEvents.
-Added missing Direct2D DrawText option flag to enable color fonts (e.g. colored emojis).
-Updated WebView2 interfaces to version 1.0.1774.30
-(oleexpimp) Added IAdviseSink and IAdviseSinkEx.
-(Bug fix) VB6 did not play nice with Implements where one argument was an HRESULT.
-(Bug fix) D3D11CreateDevice pFeatureLevels now As Any to allow passing ByVal 0.
-(Bug fix) DirectComposition vtable ordering to correct undocumented vtable reversal.
Older version history can be found in the history.txt file included in the download.
Version Archive
I have zips of all previous versions, if you ever wanted an old version for any reason, just let me know in this thread, PM, or e-mail.
-------------
Any and all feedback is welcome. Many thanks to E. Morcillo for the olelib foundation, all the olelib source is all his code.
Copyright/Redistribution
OLEEXP is open and free. You may distribute the files however you want and release your own projects based on this work, including projects for the Code Bank here, even just about using a particular interface. If you compile a modified version, please use a different GUID and note that it's your own fork as I did with olelib-- but if it's a bugfix-type change you could also just let me know and I'll immediately update the master version here. Project provided as-is.
Virus Scanners
Due to some concerns raised, oleexp 4.5 and oleexpimp were checked against VirusTotal and triggered 0 of 59 AVs (about a dozen didn't examine .tlb files). So while it may be possible false positives result from actually using some of the low level APIs declared in the TLB, the TLB itself does not trigger false positives, and only declares used go into the exe, not the whole tlb or reference (see below). I can assess with high confidence that oleexp does not result in AV false positives.
File Size
While oleexp is a large file, when you compile your exe it only takes what is used; the entire TLB isn't compiled into your file, only a few KB in most cases. The same goes for the addons- with mIID, only IIDs that are used get compiled in. In addition, a compiled exe does not maintain a reference to the tlb file, so the tlb itself need only be on the development machine; it is not necessary to distribute tlb files with your application.
Coclasses
A coclass is provided when Windows provides a default implementation of the given interface, and allows instances to be created with the New keyword instead of the CLSID and CoCreateInstance API. For single-interface coclasses, you need only the name of the coclass: Dim psl As ShellLibrary : Set psl = New ShellLibrary. Note that when a coclass is present, the underlying interface is hidden, but still present. In the example, IShellLibrary, no longer appears in the Object Browser or Properties&Methods popup list- but it is still present and can be used normally, e.g. if you were using CoCreateInstance that will still work as-is; you can also still declare As IShellLibrary.
For coclasses with multiple members, you will need to create a specific interface. Only one of the interfaces disappears from view, but it too is still there. Dim pIDSH As IDragSourceHelper[2] : Set pIDSH = New DragDropHelper Dim pIDTH As IDropTargetHelper : Set pIDTH = New DragDropHelper
* - Under development; may not be 100% error free
** - The DirectShow interface set, for convenience, contains all interfaces and types/enums from quartz.dll. You do not need a reference to it when using oleexp.
*** - Cannot be used with New keyword. IImageList can be created new (if you're making one from scratch instead of system IL) with ImageList_CoCreateInstance API.
‡ - IAsyncOperation was renamed to IDataObjectAsyncCapability. Changed some usage details.
**** - Interface located in oleexpimp.tlb due to GUID conflict
ª - WIC has numerous coclasses, too many to list clearly here. All the listed interfaces are present, so if you don't see one in the autocomplete list, don't worry it's there. See the CLSID values in mWIC for a coclass list (they're in the TLB as traditional coclasses for the New keyword, you don't need to use CoCreateInstance).
All related structures and enums are also included.
Last edited by fafalone; Jun 7th, 2024 at 12:01 AM.
Reason: Updated version history
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
Good work. Is it possible for you to recompile the TLB's in 64-bit version? I use VB6 but I also support both 32 and 64-bit Office VBA and it would be nice to use these with 64-bit Office. I don't have a version of Visual Studio that comes with a type library editor or compiler so I can't do it myself. Thanks.
† - Interface specification has been modified from the original version of olelib.
More Notes
Variable Conflicts
With TLBs, it's possible to have multiple instances of an interface, struct, or enum. For example, if you also had one of the many oleguids.tlb added, you might have two IShellFolder types, so if you have Dim psf As IShellFolder, VB isn't sure which one you mean, and will assign it based on the order in Project->References. Even worse, the high-priority default VB references contain hidden versions of IUnknown and IDispatch, which would take precedence despite being hidden.
To ensure that your variable is defined as the correct version, declare your variables explicitly if there's a conflict: Dim pUnk As oleexp.IUnknown
Dim psf As oleexp.IShellFolder
and so on. It must always be done for IUnknown/IDispatch since they have built-in conflicts, but for other interfaces it only needs to be done if there's another place it might be defined. Note: This applies to declarations in VB project code as well for user types and enums. Be careful here: while with enums it might just result in not seeing a member in the member list that pops up, but if a user type differs, you'll get an error or invalid data if you pass the wrong one to an interface or API. Public ones, or Private ones in the current object, take precedence over ones defined in a typelib, so if you need to use the typelib version, make sure to declare it explicitly, Dim tStruct As oleexp.structname.
Implements issues
Most of the interfaces in this project are not meant to be implemented in class modules. Some of them are, and some of those expect data passed back. Anything given in the typelib as an HRESULT returning function is treated as a Sub in VB, making it impossible to pass a value either way. So to get those values, many things have been changed to LONG. This allows you to receive a value there, but VB does not allow anything other than an HRESULT when you're using Implements to create your own version. All interfaces where your own version is expected, at least in my project, are already all HRESULT's, but if one is not, you can either change it and compile it yourself, or let me know and I can make an Implements-compatible version. Only needing one version would be nice, but VB went out of it's way to break this: the second problem is that sometimes when you're implementing your own version of an interface, some functionality requires that data be returned by the function instead of in one of the arguments.
To accomplish this, you'll need to swap the implementing sub in the library with a regular function. This is a little more complicated than it sounds.
First, you need the swapping code (not written by me and reused so many places I can't find the appropriate original attribution):
Code:
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSource As Any, ByVal ByteLen As Long)
Public Declare Function VirtualProtect Lib "kernel32" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flNewProtect As Long, ByRef lpflOldProtect As Long) As Long
Public Const PAGE_EXECUTE_READWRITE As Long = &H40&
Public Function SwapVtableEntry(pObj As Long, EntryNumber As Integer, ByVal lpfn As Long) As Long
Dim lOldAddr As Long
Dim lpVtableHead As Long
Dim lpfnAddr As Long
Dim lOldProtect As Long
CopyMemory lpVtableHead, ByVal pObj, 4
lpfnAddr = lpVtableHead + (EntryNumber - 1) * 4
CopyMemory lOldAddr, ByVal lpfnAddr, 4
Call VirtualProtect(lpfnAddr, 4, PAGE_EXECUTE_READWRITE, lOldProtect)
CopyMemory ByVal lpfnAddr, lpfn, 4
Call VirtualProtect(lpfnAddr, 4, lOldProtect, lOldProtect)
SwapVtableEntry = lOldAddr
End Function
It's best to put that, and your new function, into a module, unless you're feeling really adventurous.
To actually do the swap, this goes in the implementing class module:
Code:
Private m_pOldFunction As Long
Private Sub Class_Initialize()
Dim pVTable As ISomeInterface
Set pVTable = Me
m_pOldFunction = SwapVtableEntry(ObjPtr(pVTable), 4, AddressOf MyNewFunctionVB)
End Sub
Private Sub Class_Terminate()
Dim pVTable As ISomeInterface
Set pVTable = Me
m_pOldFunction = SwapVtableEntry(ObjPtr(pVTable), 4, m_pOldFunction)
End Sub
The number 4 there, which is the EntryNumber argument, is critically important- it's the ordinal of the function you're replacing. This order is NOT alphabetical order, and not what order it's in in your class module, it's the order in the actual interface definition, and starts at 4 for interfaces that inherit directly from IUnknown, which contains the first 3. Refer to the .odl/.inc source files for the proper order.
Now we're finally left with the new function itself, which now actually is a function that can return data!
Code:
Public Function MyNewFunctionVB(ByVal this As ISomeInterface, ByVal arg1 As Whatever, etc) As Long
'Handling code here
End Function
Any code that was in ISomeInterface_MyNewFunction in the class module will not be executed, but the definition line must remain in place.
The only bug is, and I've posted a discussion thread in the regular VB6 forum for ideas, is that if you run your program, then exit, and change the code in MyNewFunctionVB, then VB will crash next time the class module is created unless you exit and restart the IDE. Doesn't matter if you've swapped back and destroyed the objects, so for now just restart the IDE if you've run your program then later changed that function's code.
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 oleexp.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.
Undocumented ListView
The shell's ListView common control has a number of interfaces that expose some cool undocumented features. These interfaces are maintained as a separate typelib called lvundoc.tlb rather than included in oleexp.
Download ListView Interfaces TypeLib: lvundocsrc.zip Includes lvundoc.tlb, source, and template classes for callbacks.
NOTE: All of the Undocumented ListView Typelib, and associated types and constants, are now also in oleexp.tlb. If you are using oleexp.tlb, you now no longer need lvundoc.tlb. The download will be left up for those who just need the LV stuff and not full-blown oleexp.
Current Demos [VB6, Vista+] Undocumented ListView feature: Footer items - As seen when searching from an Explorer folder, allows a group of buttons at the bottom of a ListView. Interfaces: IListViewFooter, IListViewFooterCallback
Future Work
Subitem controls are very complex but offer incredible features. The drive display in My Computer, the Ratings stars, combo boxes, links, subitem label editing... these are all exposed through subitem controls. The type library includes the required interfaces and one closed-source VB project has succeeded, so I will figure it out at some point in the future. In the mean time, the TLB is set up to get started if you want to pursue it on your own.
Common Controls 6.0/6.1 Definitions TLB
Download Common Controls TypeLib: tl_comctl6.zip Includes CommCtrl.tlb, source, and template classes for ListView interfaces.
Decided to give my favorite typelib author's CommCtrl.tlb an upgrade as well. In addition to upgrading what was in there for the latest Common Controls version:
-Added the parts of the included controls that were defined in winuser.h. It made no sense to only include a small portion of the control definitions just because some defs were in another header.
-The definitions for the ListView control include everything from lvundoc.tlb, including all undocumented messages and interfaces. If you're using this typelib, you do not need to also have lvundoc.
Last edited by fafalone; Jun 30th, 2022 at 11:50 PM.
Reason: Added new undocumented ListView demo.
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
@MountainMan:
I'll try but it looks like a nightmare. midl.exe is complaining about errors in oaidl.idl, which isn't part of the project, which couldn't be found until I copied it into my source folder despite running vcvarsall.bat, and comes straight from the SDK so why on earth would it have errors anyway?
Code:
C:\vb6\tl_ole\source>C:\PROGRA~2\MIA713~1\\Windows\v7.0A\Bin\midl.exe /nologo /e
nv win64 /nocpp /tlb "olelib64.odl" olelib.odl
64 bit Processing .\olelib.odl
64 bit Processing .\oaidl.idl
oaidl.idl(26) : error MIDL2025 : syntax error : expecting an interface name or D
ispatchInterfaceName or CoclassName or ModuleName or LibraryName or ContractName
or a type specification near "ifndef"
oaidl.idl(27) : error MIDL2026 : cannot recover from earlier syntax errors; abor
ting compilation
I got the paths problems fixed but the big issue now is the MIDL2003 redefinition problem. It gives that error whenever you define something that's already defined in Windows. Which is everything. If anyone has dealt with this before, let me know.
Edit: What changes to the code itself would need to be made (what is the problem encountered when trying to use it in 64bit Office), assuming I can overcome the redefinition issue which might not be possible as every solution I've encountered says it's by design and to rename things.
Edit: So I installed 64-bit office, and definitely need more info about what part of the typlibs won't work. Note that olelib includes API calls, but I've had problems with these everywhere and strongly suggest always using your own declares in a module.
This is what I tried, and it worked fine with the current versions. Note that IShellItem.GetDisplayname returns a pointer, but VBA doesn't know that thus the LongPtr type isn't needed. If you needed it down the road, there apparently is a CLngPtr() function built in.
Code:
Private Sub CommandButton1_Click()
Dim pidl As Long
Dim sp As String
Dim psi As IShellItem
Dim sb As String
Dim pstr As Long
sp = "C:\temp\tracks.jpg"
pidl = ILCreateFromPathW(StrPtr(sp))
'Both of these methods work
'Call SHCreateShellItem(0&, 0&, pidl, psi)
Call SHCreateItemFromIDList(pidl, IID_IShellItem, psi)
psi.GetDisplayName SIGDN_FILESYSPATH, pstr
MsgBox BStrFromLPWStr(pstr)
Call ILFree(pidl)
End Sub
'module
Public Declare PtrSafe Function SHCreateShellItem Lib "shell32" (ByVal pidlParent As Long, ByVal psfParent As Long, ByVal pidl As Long, ppsi As IShellItem) As Long
Public Declare PtrSafe Function SHCreateItemFromIDList Lib "shell32" (ByVal pidl As Long, riid As UUID, ppv As Any) As Long
Public Declare PtrSafe Function SHCreateShellItemArrayFromIDLists Lib "shell32" (ByVal cidl As Long, ByVal rgpidl As Long, ppsiItemArray As IShellItemArray) As Long
Public Declare PtrSafe Function ILCreateFromPathW Lib "shell32" (ByVal pwszPath As LongPtr) As Long
Public Declare PtrSafe Sub ILFree Lib "shell32" (ByVal pidl As Long)
Public Declare PtrSafe Function SysReAllocString Lib "oleaut32.dll" (ByVal pBSTR As LongPtr, Optional ByVal pszStrPtr As Long) As Long
Public Declare PtrSafe Sub CoTaskMemFree Lib "ole32.dll" (ByVal pv As Long)
Public Function BStrFromLPWStr(lpWStr As Long, Optional ByVal CleanupLPWStr As Boolean = True) As String
SysReAllocString VarPtr(BStrFromLPWStr), lpWStr
If CleanupLPWStr Then CoTaskMemFree lpWStr
End Function
Public Function IID_IShellItem() As UUID
Static IID As UUID
If (IID.Data1 = 0) Then Call DEFINE_UUID(IID, &H43826D1E, CInt(&HE718), CInt(&H42EE), &HBC, &H55, &HA1, &HE2, &H61, &HC3, &H7B, &HFE)
IID_IShellItem = IID
End Function
Public Sub DEFINE_UUID(Name As UUID, l As Long, w1 As Integer, w2 As Integer, B0 As Byte, b1 As Byte, b2 As Byte, B3 As Byte, b4 As Byte, b5 As Byte, b6 As Byte, b7 As Byte)
With Name
.Data1 = l
.Data2 = w1
.Data3 = w2
.Data4(0) = B0
.Data4(1) = b1
.Data4(2) = b2
.Data4(3) = B3
.Data4(4) = b4
.Data4(5) = b5
.Data4(6) = b6
.Data4(7) = b7
End With
End Sub
Last edited by fafalone; Sep 27th, 2015 at 03:56 AM.
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
Hallo there,
I'm trying to use IFileDialog.
I added a custom button as shown bellow:
fdc.AddPushButton 1001, "Abandon"
fdc.MakeProminent 1001 'Moves to by the open button; only checkboxes, buttons, combos, menus can be made prominent
and I catch the click on it using the FD_ButtonClick event.
Everything perfect so far. But when the user clicks it I need to return to the calling Form. How is it done? How do I quit the Dialog box just if the user clicked on Cancel button?
Another question: is it possible to place the Dialog box in the position on the screen I desire?
Appreciate your reply
Slobodan Dijaković
Casa Bustelli
6864 Arzo
Switzerland
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
Originally Posted by fafalone
Major project update to 2.0. Many new interfaces, sample projects, and bugfixes.
Switching from Edanmo's olelib.tlb to this version, generates 'method or data member not found' error, when using IDataObject.GetData call.
olelib.tlb {3181A65A-CC39-4CDE-A4DF-2E889E6F1AF1}
Code causing error.
Code:
Dim m_oSource As IDataObject
Dim tFMT As FORMATETC
Dim tSTGM As STGMEDIUM
If m_oSource.GetData(tFMT, tSTGM) = S_OK Then
Doublechecked referenced version and it's from oleexp 2.0RC.zip package.
Reference=*\G{3181A65A-CC39-4CDE-A4DF-2E889E6F1AF1}#1.5e#0#olelib.tlb#Edanmo's OLE interfaces & functions v1.94 (modified for oleexp)
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
Originally Posted by Tech99
Switching from Edanmo's olelib.tlb to this version, generates 'method or data member not found' error, when using IDataObject.GetData call.
olelib.tlb {3181A65A-CC39-4CDE-A4DF-2E889E6F1AF1}
Code causing error.
Code:
Dim m_oSource As IDataObject
Dim tFMT As FORMATETC
Dim tSTGM As STGMEDIUM
If m_oSource.GetData(tFMT, tSTGM) = S_OK Then
Doublechecked referenced version and it's from oleexp 2.0RC.zip package.
Reference=*\G{3181A65A-CC39-4CDE-A4DF-2E889E6F1AF1}#1.5e#0#olelib.tlb#Edanmo's OLE interfaces & functions v1.94 (modified for oleexp)
Any idea what might cause this?
Edit... variable declaration from integer to long seemed to resolve this.
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
Μaybe mktyplib is better than MIDL2003..I have problem too with Edanmo Idispatch.tlb. I describe the solution here http://www.vbforums.com/showthread.p...an-handle-Word.
GetIDsOfNames need an array of strings so a Long* (for pointer) and original Idispatch.tlb from Edanmo has LPSTR*
So maybe there are more problems with that olelib.
My question is...Can we use IFileDialog Like I use Word.Application? Can I later bind an object from IFileDialog?
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
Originally Posted by Tech99
Edit... variable declaration from integer to long seemed to resolve this.
Code:
Private CF_FILECONTENTS As Long 'Integer
Yeah that's mentioned in the release notes up top... it was changed because of its use with clipboard formats- and RegisterClipbaordFormat was returning larger values than the (signed) Integer type could hold, so it was changed to a Long. Every change the potentially breaks code is documented, and I'm very careful to only do it when absolutely necessary.
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
Originally Posted by georgekar
Μaybe mktyplib is better than MIDL2003..I have problem too with Edanmo Idispatch.tlb. I describe the solution here http://www.vbforums.com/showthread.p...an-handle-Word.
GetIDsOfNames need an array of strings so a Long* (for pointer) and original Idispatch.tlb from Edanmo has LPSTR*
So maybe there are more problems with that olelib.
My question is...Can we use IFileDialog Like I use Word.Application? Can I later bind an object from IFileDialog?
If you're talking about passing an array TO a typelib member, it's fairly straightforward, you just change the typelib to expect a LONG and pass a pointer to the first member. If you meant receiving an array... that's a bit more complicated.
As for late-binding, I haven't really tried it. I'd imagine you probably could with objects that have default implementations like FileOpenDialog, but probably not normal interfaces, though I haven't tried. Why would you really want to?
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
GetIDsOfNames now return an array of long values. As you can see I place an long array to pass names of function in first place and named arguments in other places, and I can get the number of function and the relative numbers of named arguments. I use that in M2000 interpreter.
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
This is a part of mdlIDispatch.cls you can find in the code in M2000 source in sign.
Code:
long _stdcall GetIDsOfNames(
[in] IID* riid,
[in] long* rgszNames, previous LPSTR* rgszNames,
[in] long cNames,
[in] long lcid,
[in, out] long* rgDispId);
GetIDsOfNames expected pointers and i do the right think...Why there is a cNames? because from pointers there is no way to know how many items in the array used. So I pass the first item of an array as myptr(0). Inside that array I just put pointers to actual strings. I do a redim to varDISPID so after call I get in first place the number of function and on other places the numbers of relative parameter. The good news is that this method works..
I make the routine to work with mixed types, some named arguments and some in right place, and for working properly in M2000 language you have to place named arguments as the last arguments.
This is a line of the example as I post in the link above:
try ok_doc { method doc, "add", "", DocumentType:=WdNewWebPage as doc1 }
I call add on object doc (is word.application.documents) and i pass an empty string for the first parameter and a documenttype and I get an object the Document object.
No any special copymemory done..GetIDsOfNames only read the strings (no conversion needed) and put in the provided array the results.
With old typelib we have this LPSTR* rgszNames, so we place a string and the system place a pointer to one string, so it works but only for the ProcName not for named arguments. Before I found the solution I think to pass a safearray, but it isn't like this, it is more simple.
Code:
ReDim myptr(0 To fixnamearg)
myptr(0) = StrPtr(pstrProcName) ' this is the method to call
For lngLoop = 1 To fixnamearg
myptr(lngLoop) = StrPtr(pargs2(lngLoop)) 'these are the names
Next lngLoop
ReDim varDISPID(0 To fixnamearg)
lngRet = IDsp.GetIDsOfNames(rIid, myptr(0), fixnamearg + 1, cLid, varDISPID(0))
DISPID = varDISPID(0)
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
On an unrelated note, I've been seriously considering combining olelib and oleexp, such that there's only a single file. So it would be more of a fork of olelib rather than an expansion. Of course all credits for the original would remain. Any objections to this?
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
Sorry my English is poor. I know the size of input array. The output array has the same size. The problem for function is that these are not arrays like safe arrays where we found fields that describe the dimension and the size of it. We place the first address and in a variable the length as long items. So cNames is a size both for input and output array. Each array has a long for item, but in first array that long is a pointer to bstr. StrPtr return address of Bstr.
In old version in typelib we can only provide a string after a convertion to unicode....because vb treat string as ansi, so do a reverse conversion and then put a long as pointer to bstr. There is no way to pass more strings in an array form. So I suspect from cNames that only a buffer of longs passed. Maybe a predefined big buffer can be used for any call to this function.
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
Originally Posted by fafalone
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.
. . . 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!
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)
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
Good to know. I didn't know Set called QueryInterface internally, so had just been using the QueryInterface like I saw in the C++ examples I learned from, and just used Set for an inherited interfaces parent.
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
Originally Posted by georgekar
Sorry my English is poor. I know the size of input array. The output array has the same size. The problem for function is that these are not arrays like safe arrays where we found fields that describe the dimension and the size of it. We place the first address and in a variable the length as long items. So cNames is a size both for input and output array. Each array has a long for item, but in first array that long is a pointer to bstr. StrPtr return address of Bstr.
In old version in typelib we can only provide a string after a convertion to unicode....because vb treat string as ansi, so do a reverse conversion and then put a long as pointer to bstr. There is no way to pass more strings in an array form. So I suspect from cNames that only a buffer of longs passed. Maybe a predefined big buffer can be used for any call to this function.
The output array has the same number of items as the input array, so passed as in your code, the output array is filled for all items?
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
That is the idea when you call a function with 2 named arguments you have 3 names and you get 3 numbers. First number is the number of function and the two others is the real position of the named arguments.
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
Originally Posted by Bonnie West
Manually invoking IUnknown's QueryInterface method isn't actually necessary in Visual Basic. The Set statement already does it for you.
[...]
The one problem I've had with this; if you just use the Set statement, and QueryInterface fails (a rare scenario, but one I just encountered*), then you get a Type Mismatch error which would have to go through your error handler or have its own on error resume next statement and then verification that the new object <> nothing. With the QueryInterface method, you can get the HRESULT without an error if it fails, then proceed accordingly.
*The scenario popped up in using IPreviewHandler. To initialize it, an object may implement IInitializeWithFile, IInitializeWithStream, or IInitializeWithItem. Most only implement one of these, and there's no way to know beforehand (or if there is it's so obscure that every example still uses trial and error). There's sure to be other scenarios or true errors in QueryInterface calls.
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
So I figured the most useful place to put it was an addon to this project, but this is of wider interest:
There's a new attachment called mPKEY.zip that contains mPKEY.bas - a complete VB version of SDK 7.1's propkey.h, containing all the PROPERTYKEY variables. Like the IID module, these are set up to be used directly without conversion in any interface or API that asks for a PROPERTYKEY.
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
Hello Fafalone.
Can you help me please to transform the old IBindStatusCallback_OnProgress Sub in a Function (as it should)?
More precisely, it seems that all urlmon callback functions are defined by Morcillo as Sub instead of Functions. http://www.tek-tips.com/viewthread.cfm?qid=1626482
I wan't waste your time, so if you give me basic steps to modify tlb, it's ok.
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
It's not E.M.'s fault; VB requires any Implements interface to use only Subs. (you can see one specific as a function; but you can only do that if you're returning a variable that's the last param and marked as [out]). A few things here and there have been changed to functions in oleexp, but those interfaces aren't used with Implements.
In situations like this, where other implementations exist that rely on it being a sub, it's highly inadvisable to change the typelib (and in this specific case, impossible, since there are no [out] arguments, so the only thing to return is the HRESULT which VB doesn't allow). What you should do instead is simply swap out the function:
In a module (bas), put the following, a routine to swap them, and the new function (i'll assume you already have CopyMemory declared, if not add it):
Code:
Public Declare Function VirtualProtect Lib "kernel32" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flNewProtect As Long, lpflOldProtect As Long) As Long
Public Const PAGE_EXECUTE_READWRITE As Long = &H40&
Public Function SwapVtableEntry(pObj As Long, EntryNumber As Integer, ByVal lpfn As Long) As Long
Dim lOldAddr As Long
Dim lpVtableHead As Long
Dim lpfnAddr As Long
Dim lOldProtect As Long
CopyMemory lpVtableHead, ByVal pObj, 4
lpfnAddr = lpVtableHead + (EntryNumber - 1) * 4
CopyMemory lOldAddr, ByVal lpfnAddr, 4
Call VirtualProtect(lpfnAddr, 4, PAGE_EXECUTE_READWRITE, lOldProtect)
CopyMemory ByVal lpfnAddr, lpfn, 4
Call VirtualProtect(lpfnAddr, 4, lOldProtect, lOldProtect)
SwapVtableEntry = lOldAddr
End Function
Public Function IBSCBOnProgress(ByVal this As IBindStatusCallback, ByVal ulProgress As Long, ByVal ulProgressMax As Long, ByVal ulStatusCode As BINDSTATUS, ByVal szStatusText As Long) As Long
'all code for OnProgress goes here
End Function
You still need the prototype (Private Sub IBindStatusCallback_OnProgress...) in your class module, but all code should be relocated to the OnProgress in the module. In your class module which contains the 'Implements IBindStatusCallback' statement, add a module level variable: Private mOldOP As Long
then in Class_Initialize, add:
Code:
Dim pVTable As IBindStatusCallback
Set pVTable = Me
mOldOP = SwapVtableEntry(ObjPtr(pVTable), 7, AddressOf IBSCBOnProgress)
and in Class_Terminate, add:
Code:
Dim pVTable As IBindStatusCallback
Set pVTable = Me
mOldOP = SwapVtableEntry(ObjPtr(pVTable), 7, mOldOP)
And now everything is redirected to the function version. for reference, the '7' is the entry number we're changing, we start at 4 (1-3 are for IUnknown), so that makes OnProgress 7th.
Last edited by fafalone; Dec 8th, 2015 at 02:37 PM.
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
Woooow Fafalone!
Really, ignorantly, I supposed that the solution was more simple than that you have skilfully exposed here.
Thank you very much for the explanation. I'll test it in next days.
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
It should be easy... it makes no sense at all that VB turns HRESULT-returning function into Subs. So don't feel bad at all about it, everyone is like 'what the heck????' the first they come across it, me included. And full disclosure, somebody else wrote the SwapVtable function; not sure of the original source tho, it's appeared all over code and in books forever.
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
Originally Posted by fafalone
... it makes no sense at all that VB turns HRESULT-returning function into Subs.
It's likely due to VB's goal of hiding as much complexity from the programmer as possible. All programmer-defined methods and properties in object modules (CLS, FRM, CTL, etc.) returns a hidden HRESULT, even Subs (the HRESULT contains the error code raised in the procedure, if any). A Function's programmer-defined return value is actually declared as the last parameter and it is passed ByRef. When VB sees that a TLB-declared Function returns an HRESULT, it treats that as a Sub, unless its last argument is passed ByRef and is given the attributes [out, retval], in which case, it is recognized as a Function.
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
the HRESULT contains the error code raised in the procedure, if any
You know.. I've seen this before but had always assumed it was just for handling inside VB... if you used the Err.Raise statement inside a class sub (under the circumstances here, where's it's a VB-implemented callback for a COM interface implemented outside of VB), will that return the value specified as the HRESULT to the main interface outside VB?
Edit: Yes; but it causes a major app error where you'd have to have a custom error handler for the line it gets raised on. So SwapVtable is a better solution.
Example: INamespaceWalkCB is a callback for an Explorer-implemented NamespaceWalker object. The only way to cancel a directory walk is to return ERROR_CANCELLED as the HRESULT for INamespaceWalkCB_EnterFolder. Using Err.Raise causes a runtime error on the NamespaceWalker.Walk method that initiated the walk. If continued from that line, the walk continues, but it does provide an opportunity to resume on the next line.
Last edited by fafalone; Dec 9th, 2015 at 04:15 PM.
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
Where is the download link to get the latest version this oleexp.tlb file? There's a very very very long description of what it can do in the opening thread, but I can't find the download link. It may be buried in the text somewhere, but I didn't manage to find it. Please post the link somewhere where I can find it. I'd really like to try this thing out.
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
If I add a link at the top then it removes the icons/gray box at the bottom (could add another text link at the bottom too, but can't get the normal box with icons back).. and that I had thought would actually make it harder to find. But unless these manual plain text links are set up, the default download box is always at the bottom of the post.
Also in case you're looking for a new version of "oleexp.tlb" exactly.. when the version numbers got to 3.0 a few months ago the project was combined with olelib into a single file with a new GUID, so now oleexp3.tlb replaces both olelib.tlb and oleexp.tlb (any variables declared like Dim x As olelib.Type or Dim x As oleexp.Type can be automatically replaced with Dim x As oleexp3.Type)
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
Hi all,
I have been trying to make this following code work in Windows 64bit but without any success
Any help anyone on how to make it work for Windows 64 bit ... Thanks
Code:
Public Declare Function VirtualProtect Lib "kernel32" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flNewProtect As Long, lpflOldProtect As Long) As Long
Public Const PAGE_EXECUTE_READWRITE As Long = &H40&
Public Function SwapVtableEntry(pObj As Long, EntryNumber As Integer, ByVal lpfn As Long) As Long
Dim lOldAddr As Long
Dim lpVtableHead As Long
Dim lpfnAddr As Long
Dim lOldProtect As Long
CopyMemory lpVtableHead, ByVal pObj, 4
lpfnAddr = lpVtableHead + (EntryNumber - 1) * 4
CopyMemory lOldAddr, ByVal lpfnAddr, 4
Call VirtualProtect(lpfnAddr, 4, PAGE_EXECUTE_READWRITE, lOldProtect)
CopyMemory ByVal lpfnAddr, lpfn, 4
Call VirtualProtect(lpfnAddr, 4, lOldProtect, lOldProtect)
SwapVtableEntry = lOldAddr
End Function
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
It depends on whether you mean you want to run a 32-bit program in Windows 64 or whether you want to make a 64-bit program and then run that in 64-bit Windows. If you are using Visual Basic 6 it can't make a 64-bit program so whatever you compile to will be 32-bit, in which case you don't have to make any changes. In the VB6 case, just compile and run the program because it is very common for 32-bit programs like what VB6 makes to run inside of Windows 64.
The only way I know to make 64-bit code using VB or VBA is to run the code in VBA in a 64-bit version of Microsoft Office (not a 32-bit version running in 64-bit Windows). In this case you need to make the following changes:
1) You have to change all of the "4" values to "8" because a memory address in Windows 64 is 8 bytes long, not 4 like it is in 32-bit Windows.
2) Your pointer variables need to change to LongPtr from Long (note that LongPtr does not exist in VB6). It is somewhat confusing because in 32-bit code you use a Long variable to represent a pointer or an actual Long variable so you have to study the code a bit to figure out what are pointers that need to be changed to LongPtr. Note that LongPtr was introduced in Office 2010 and you can use it in 32 or 64 bit Office. In 32-bit Office LongPtr gets converted to Long automatically.
3) You would have to execute the code below on a 64-bit Office program in VBA. Thee is a requirement if you do that you have to add the word PtrSafe into any Windows API declaration to show that you have thought through the necessary change in the WIndows function call.
I haven't tested your code but I believe it should look like the following:
Code:
Public Declare PtrSafe Function VirtualProtect Lib "kernel32" (ByVal lpAddress As LongPtr, ByVal dwSize As Long, ByVal flNewProtect As Long, lpflOldProtect As LongPtr) As Long
Public Const PAGE_EXECUTE_READWRITE As Long = &H40&
Public Function SwapVtableEntry(pObj As LongPtr, EntryNumber As Integer, ByVal lpfn As LongPtr) As LongPtr
Dim lOldAddr As LongPtr
Dim lpVtableHead As LongPtr
Dim lpfnAddr As LongPtr
Dim lOldProtect As LongPtr
CopyMemory lpVtableHead, ByVal pObj, 8
lpfnAddr = lpVtableHead + (EntryNumber - 1) * 8
CopyMemory lOldAddr, ByVal lpfnAddr, 8
Call VirtualProtect(lpfnAddr, 8, PAGE_EXECUTE_READWRITE, lOldProtect)
CopyMemory ByVal lpfnAddr, lpfn, 8
Call VirtualProtect(lpfnAddr, 8, lOldProtect, lOldProtect)
SwapVtableEntry = lOldAddr
End Function
Now it starts getting interesting if you want to be able to run this code in 32-bit Office (what probably 99.9% of people use up to this point) AND to be able to run in 64-bit Windows without having to change code.
The way we do that is to use a conditional compilation constant that tells the code compiler which version is trying to compile it and we'll have two sets of code and tell it to only use the code for the type (32 or 64 bit) that is running. I would do this like this:
Code:
#If Win64 Then
Public Declare PtrSafe Function VirtualProtect Lib "kernel32" (ByVal lpAddress As LongPtr, _
ByVal dwSize As Long, ByVal flNewProtect As Long, lpflOldProtect As LongPtr) As Long
Public Const PAGE_EXECUTE_READWRITE As Long = &H40&
Public Function SwapVtableEntry(pObj As LongPtr, EntryNumber As Integer, ByVal lpfn As LongPtr) As LongPtr
Dim lOldAddr As LongPtr
Dim lpVtableHead As LongPtr
Dim lpfnAddr As LongPtr
Dim lOldProtect As LongPtr
CopyMemory lpVtableHead, ByVal pObj, 8
lpfnAddr = lpVtableHead + (EntryNumber - 1) * 8
CopyMemory lOldAddr, ByVal lpfnAddr, 8
Call VirtualProtect(lpfnAddr, 8, PAGE_EXECUTE_READWRITE, lOldProtect)
CopyMemory ByVal lpfnAddr, lpfn, 8
Call VirtualProtect(lpfnAddr, 8, lOldProtect, lOldProtect)
SwapVtableEntry = lOldAddr
End Function
#Else
Public Declare Function VirtualProtect Lib "kernel32" (ByVal lpAddress As Long, _
ByVal dwSize As Long, ByVal flNewProtect As Long, lpflOldProtect As Long) As Long
Public Const PAGE_EXECUTE_READWRITE As Long = &H40&
Public Function SwapVtableEntry(pObj As Long, EntryNumber As Integer, ByVal lpfn As Long) As Long
Dim lOldAddr As Long
Dim lpVtableHead As Long
Dim lpfnAddr As Long
Dim lOldProtect As Long
CopyMemory lpVtableHead, ByVal pObj, 4
lpfnAddr = lpVtableHead + (EntryNumber - 1) * 4
CopyMemory lOldAddr, ByVal lpfnAddr, 4
Call VirtualProtect(lpfnAddr, 4, PAGE_EXECUTE_READWRITE, lOldProtect)
CopyMemory ByVal lpfnAddr, lpfn, 4
Call VirtualProtect(lpfnAddr, 4, lOldProtect, lOldProtect)
SwapVtableEntry = lOldAddr
End Function
#End If
There is obviously a lot of code overlap so if you are really adventuresome you could smush stuff together and do the following:
Code:
#If Win64 Then
Public Declare PtrSafe Function VirtualProtect Lib "kernel32" (ByVal lpAddress As LongPtr, ByVal dwSize As Long, ByVal flNewProtect As Long, lpflOldProtect As LongPtr) As Long
#Else
Public Declare Function VirtualProtect Lib "kernel32" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flNewProtect As Long, lpflOldProtect As Long) As Long
#End If
' I left the two declarations above the code because it allows you to put other Windows
' calls in there if your code has any.
'
' Any other code you want to put here.
'
#If Win64 Then
Public Function SwapVtableEntry(pObj As LongPtr, EntryNumber As Integer, ByVal lpfn As LongPtr) As LongPtr
Const BytesPerAddr as Long = 8
Dim lOldAddr As LongPtr
Dim lpVtableHead As LongPtr
Dim lpfnAddr As LongPtr
Dim lOldProtect As LongPtr
#Else
Public Function SwapVtableEntry(pObj As Long, EntryNumber As Integer, ByVal lpfn As Long) As Long
Const BytesPerAddr as Long = 4
Dim lOldAddr As Long
Dim lpVtableHead As Long
Dim lpfnAddr As Long
Dim lOldProtect As Long
#End If
CopyMemory lpVtableHead, ByVal pObj, BytesPerAddr
lpfnAddr = lpVtableHead + (EntryNumber - 1) * BytesPerAddr
CopyMemory lOldAddr, ByVal lpfnAddr, BytesPerAddr
Call VirtualProtect(lpfnAddr, BytesPerAddr, PAGE_EXECUTE_READWRITE, lOldProtect)
CopyMemory ByVal lpfnAddr, lpfn, BytesPerAddr
Call VirtualProtect(lpfnAddr, BytesPerAddr, lOldProtect, lOldProtect)
SwapVtableEntry = lOldAddr
End Function
What I did above is much harder to read unless you do this a lot (like I do) so you may be better off not combining the code and using the version above.
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
Thank you very much Mountainman,
Based on your answer, I have successfully managed to override the CalculateFull Method of the Excel application object ... The CalculateFull Propery vtable offset happens to be 319 ... See code below :
Proceedings : Run the HookCOMFunction first in order to hook the CalculateFull Propery and then run the Test macro
Code:
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
Destination As Any, _
Source As Any, _
ByVal length As LongPtr _
)
Private Declare PtrSafe Function VirtualProtect Lib "kernel32" _
(ByVal lpAddress As LongPtr, ByVal dwSize As LongPtr, _
ByVal flNewProtect As LongPtr, lpflOldProtect As LongPtr) As Long
Private Const PAGE_EXECUTE_READWRITE As Long = &H40&
Private Const lFuncOffset = 319 'Excel Application.calculateFull Method VTable Offset
Private pVTable As LongPtr
Private bHooked As Boolean
Private lOldAddr As LongPtr
Sub HookCOMFunction()
Dim lOldAddr As LongPtr
Dim lpVtableHead As LongPtr
Dim lpfnAddr As LongPtr
Dim lOldProtect As LongPtr
Dim pObj As LongPtr
pObj = CLngPtr(ObjPtr(Application))
CopyMemory lpVtableHead, ByVal pObj, 8
lpfnAddr = lpVtableHead + (lFuncOffset) * 8
CopyMemory lOldAddr, ByVal lpfnAddr, 8
Call VirtualProtect(lpfnAddr, 8, PAGE_EXECUTE_READWRITE, lOldProtect)
CopyMemory ByVal lpfnAddr, AddressOf OverrideFunction, 8
Call VirtualProtect(lpfnAddr, 8, lOldProtect, lOldProtect)
End Sub
Private Function OverrideFunction(ByVal voObjPtr As Long, ByVal Param As Long) As Long
MsgBox "Excel 'CalculateFull' Method has been Hooked !!"
End Function
Sub Test()
Application.CalculateFull
End Sub
The only thing that i haven't managed to do is to restore CalculateFull Property back to its original vtable address ... the following code crashes the excel application :
Code:
Sub UnHookComFunction()
CopyMemory lpfnAddr, ByVal lOldAddr, 8
End Sub
Also, (and this is my ultimate goal) is there a way to make this work when executing the CalculateFull Method via the excel user interface (ie via the excel menu) as opposed to the hook only working when the CalculateFull Method is excecuted via code as in the Test macro aboe ?
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
I believe the problem is that you hve defined lOldAddr both in your HookCOMFunction procedure and also as a module level variable. When you first determined the value for lOldAddr you are doing it inside of the HookCOMFunction procedure but when that procedure goes out of focus you lose all of the procedure variables including lOldAddr. Normally this would cause a syntax error later when you tried to re-use it to re-set the address because in UnHookComFunction you don't have this variable. However, in this case another variable of the same name exists at the module level and although it has really never been used (i.e., it has a value of 0) your function uses it anyway which I am sure Windows doesn't like. My suggestion is to get rid of the lOldAddr variable in the HookCOMFunction procedure and only use the module-level variable of that name.
BTW, I also suggest that you don't make all of your passed parameters to be LongPtr. It is true (I think) that in 64-bit Windows all parameters passed to a function or sub are passed as 64-bit values but it can cause you problems later. For example, you are calling the Windows API function VirtualProtect whose 2nd parameter is dwSize. When the Windows documentation shows a variable starting with "dw" it means it is a double word, a 32-bit value. If you pass a LongPtr it will go on the stack as a 64-bit value and VBA will pass the whole value. This means that if somehow you were to put a value larger than a Long to be passed that VBA would just pass it along but the function is really expecting the top 4 bytes to be 0 since it is only going to use the bottom 4 bytes. I prefer to list the parameter in the call as a Long (which is what the function expects) and I will count on VBA to make the top 4 bytes a 0 when it really puts it on the stack as a 64-bit number. That way I feel a lot better than a) I own't ever mess up and give it a value that is out-of-range of what the function wants by being too big and b) when we go to a 129-bit operating system I don't have to go back in and check each variable I am passing to make sure that it is the right size. What you have done though will work; I just think you are setting yourself up for problems down the road.
Re: [VB6] Modern Shell Interface Type Library - oleexp.tlb
Originally Posted by RAFAAJ2000
Also, (and this is my ultimate goal) is there a way to make this work when executing the CalculateFull Method via the excel user interface (ie via the excel menu) as opposed to the hook only working when the CalculateFull Method is excecuted via code as in the Test macro aboe ?
Well in principle, you could subclass the process and intercept the menus WM_COMMAND message, but subclassing a 64-bit app might be challenging.