# VBForums CodeBank > CodeBank - Visual Basic 6 and earlier >  [VB6] Modern Shell Interface Type Library - oleexp.tlb

## fafalone

OLEEXP : Modern Shell Interfaces
Current Version: 5.1 (Released 05 November 2022)
Go to: Download | Notes | Changelog | New Interface List, or original olelib list | Related Projects

*About Project*
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 *ole*lib, forked and *exp*anded. 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. 

*Sample Projects* (53)
*NEW!* [VB6/twinBASIC] Code snippet: Close Explorer window by path - A simpler example of using IShellWindows to enumerate all open Explorer windows.

*NEW!* [VB6] Code snippet: Run unelevated app from elevated app - By making Explorer do it. 

[VB6] Using IShellWindows to register for SHOpenFolderAndSelectItems - Register a path as a shell window, then apps using the API will pass the full names of files to be opened in it.
_IShellWindows, IServiceProvider, IWebBrowserApp, IShellView_

*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._

*UPDATED 25 Jan 2022*  [VB6] ucShellTree: Full-featured Shell Tree UserControl - A TreeView for navigating the shell like ucShellBrowse.

[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] Write MP3 Album Art and other tags using the Windows Property System - You can use the Property Store interfaces to add cover art, and all the traditional tags, to your MP3 files.
_IPropertyStore, IShellItem2_

 [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] Using Structured Queries to conduct a Windows Search by any property - Advanced Windows-provided file searching technique
_ISearchFolderItemFactory, IConditionFactory2, ICondition, IObjectCollection, IShellLibrary, IShellItemArray_

 [VB6] Adding Custom Tasks and Items to the Jump List (Taskbar Right-click) - Shows how to use ICustomDestinationList to add items to the Jump List.
_ICustomDestinationList, IObjectCollection, IObjectArray, IShellLink, IPropertyStore_

[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] Display search results or other custom file set in IExplorerBrowser - Display a set of files from anywhere in the system as if they were in one folder.
_IResultsFolder, IExplorerBrowser, IColumnManager_

 [VB6, Win8+] Using the system spellchecker: Add spellcheck with only a few lines - A demo of Win8's new spellchecking feature.
_ISpellChecker, ISpellCheckerFactory, ISpellingError, IEnumSpellingErrors, IEnumString_

[VB6] Class to show a standard Explorer-style progress window - Use the IProgressDialog interface to show progress with an Explorer-style popup.
_IProgressDialog_

[VB6, Vista+] Enumerate, explore, and change all file associations - Use IQueryAssociations to get information about all registered file types.
_IQueryAssociations, IAssocHandler, IEnumAssocHandlers, IOpenControlPanel_

[VB6, Vista] List the Recycle Bin location(s) on a drive - Use folder class IDs to find the official folders.
_IPersist, IKnownFolderManager, IKnownFolder, IEnumShellItems, IShellItem_

[VB6] Dynamic Resize: Use a slider to change ListView icon/thumbnail size on the fly - Smooth and fast resizing without any quality loss.
_IImageList2, IShellItemImageFactory_

[VB6] Exclude file types from Open/Save Dialogs ('all except...'): IShellItemFilter - Instead of selecting which files to show, select which ones to hide.
_IShellItemFilter, IFileOpenDialog, IShellItem_

[VB6, Vista+] Finding and deleting invalid shortcuts with IShellLink and IShellItem Find and remove bad links with IShellLinkW and a new recursive file enumeration/search method using only IShellItem and IEnumShellItems.
_IShellLinkW, IPersistFile, IEnumShellItems, IShellItem, IFileOpenDialog_

[VB6, Vista+] Core Audio - Monitor for disabled/active, default, and property changes - Shows how to use IMMNotificationClient to be notified when audio hardware is added/removed, enabled/disabled, set as default, or had its properties change
_IMMDeviceEnumerator, IMMDevice, IMMNotificationClient, IPropertyStore_

[VB6, Vista+] Core Audio - Change the system default audio device - Uses an undocumented interface to change this much sought-after setting through code.
_IPolicyConfig, IMMDeviceEnumerator, IMMDeviceCollection, IMMDevice_

[VB6] SHBrowseForFolder - Custom filter for shown items: BFFM_IUNKNOWN/IFolderFilter - Shows what to do to actually implement a filter using that weird BFFM_IUNKNOWN message you've seen.
_IFolderFilter, IUnknown, IShellFolder, IShellItem_

[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, Vista+] Direct access to the system-wide image thumbnail cache - Uses the LocalThumbnailCache object for advanced access.
_IThumbnailCache, ISharedBitmap, IThumbnailProvider, IShellItem_

[VB6, Vista+] Remember Open/Save state per-dialog instead of per-app (IFileDialog) - The .SetClientGuid method enables automatic saved states per-dialog.
_IFileDialog/IFileOpenDialog, IShellItem_

 [VB6] Using IAutoComplete / IAutoComplete2 including autocomplete with custom lists  - Shows using autocomplete and IEnumString with oleexp interfaces. Supports custom lists and multiple sources.
_IAutoComplete, IAutoComplete2, IAutoCompleteDropDown, IEnumString, IACList, IACList2, IObjMgr_

[VB6, Vista+] Advanced Thumbnail ListView: Icons, images, videos, framed small images Uses shell interfaces and GDI+ to make a top-tier thumbnail view that handles every type of file.
_IShellItemImageFactory, IExtractImage, IShellItem[2], IShellFolder, IShellIcon, IShellIconOverlay, IParentAndItem, IEnumShellItems, IImageList_

[VB6] Drag drop any format to other apps without custom IDataObject - Drag and drop CF_TEXT, CFSTR_PNG, and more without having to implement IDataObject. Now with sample project.
_IDataObject, IDragSourceHelper2_

[VB6] Register any control as a drop target that shows the Explorer drag image - With IDropTargetHelper, any XP+ app can now show the same drag image as any modern program.
_IDropTarget, IDropTargetHelper_

[VB6, Vista+] Core Audio Basics - Demonstrates the new Core Audio interfaces added in v3.6
_IMMDeviceEnumerator, IMMDeviceCollection, IMMDevice, IAudioEndpointVolume, IAudioEndpointVolumeCallback, ISimpleAudioVolume, IAudioSessionManager2, IAudioSessionControl, IAudioSessionControl2_

[VB6] Code Snippet: View shortcut path w/variables unexpanded: IShellLinkDataList, and
[VB6] Code Snippet: Make your shortcuts request elevation with IShellLinkDataList - An introduction to the advanced flags and data blocks hidden behind IShellLink.
_IShellLink (IShellLinkW), IShellLinkDataList, IPersistFile_

[VB6] Code Snippet: Get file overlay (e.g. shortcut arrow), inc. customs like DropBox - There's way more to system icon overlays than shortcuts and shares, now you can easily find the other Windows ones and custom ones.
_IShellIconOverlay, IShellFolder_

[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, Vista+] SHBrowseForFolder: Handling a choice of Libraries (or Library), Computer, or Network - Some objects aren't valid folders themselves, but contain valid folders, and the user probably expects those objects to be treated like any other parent folder. Shell interfaces to the rescue!
_IShellLibrary, IShellItem, IShellItemArray, IEnumShellItems_

[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] Code Snippet: Get/set/del file zone identifier (Run file from internet? source) - How does Explorer know to ask? Get the basics of Alternative Data Streams and see how to change this one extremely easily thanks to IZoneIdentifier and its coclass PersistentZoneIdentifier.
_IZoneIdentifier, IInternetSecurityManager_

[VB6] Basic unzip without 3rd party DLL or shell32- IStorage-based, and
[VB6] Create a ZIP file without any DLL depends using IStorage and IDropTarget - Uses IStorage and IStream for basic zip functionality. Creating a Zip uses a neat trick with IDropTarget.
_IStorage, IStream, IEnumSTATSTG, IShellFolder, IDropTarget_

[Vista+] Code Snippet: Get and set the Rating (stars) of a file - Shows a practical example of using IShellItem/IPropertyStore to read/write properties with very few lines of code.
_IPropertyStore, IShellItem2_

[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] Enhanced Tray Message w/ custom ToolTip icon and feedback, w/o ShellNotifyIcon - Uses the new IUserNotification2 interface (Vista+)
_IUserNotification2_

[VB6] List files by level from a folder in natural sorted order using INamespaceWalk - A unique way of listing files with it's own Windows-managed progress dialog.
_INamespaceWalk, INamespaceWalkCallback, IShellFolder_

[VB6] List/Execute File Handlers: IAssocHandler and IAssocHandlerInvoker (Vista+)  - Get names, paths, and icons for all of a file type's handlers, and use it to show your own Open With menu.
_IAssocHandler, IAssocHandlerInvoker, IEnumAssocHandlers_

[VB6] Win7 Taskbar Features with ITaskbarList3 (overlay, progress in taskbar, etc) - Windows 7 allows you to add an overlay icon, turn the taskbar item into a progress bar, add buttons below the thumbnail, and more. See how to use the new ITaskbarList3 / 4 interface in VB with the TaskbarList object from oleexp.
_ITaskbarList4_

[VB6] Use IFileOperation to replace SHFileOperation for modern Copy/Move box/prompts  - Also shows usage of IShellItem; now updated to show the Advise method in action- using a class module to implement an interface to get progress feedback.
_IFileOperation, IFileOperationProgressSink, IShellItem, IShellItemArray, IShellFolder_

[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_

...more to come soon!


*64bit Support for twinBASIC*

oleexp now has a 64bit-compatible successor for use in twinBASIC: tbShellLib. It includes all interfaces, enums, types, and APIs from oleexp except a small bit of legacy Win9x stuff unusable on XP+. The twinpack format also allows all of the add-on modules to be built in. You can add this to your project via Settings->COM Type Library/ActiveX References->TWINPACK Packages->twinBASIC Shell Library (it's been uploaded to the online package repo, so no external download is needed). 

Eventually, twinBASIC will support exporting TLBs, and when that happens it will also be available for VBA7 64bit. 

[twinBASIC] tbShellLib - Shell Interface Library (x64-compatible successor to oleexp) :: VB Forums Project Thread :: Project GitHub Repository

*Add-Ons*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 5.1) - 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* - IIDs and functions used exclusively by those particular features.


*Included in the ZIP*
*oleexp51.zip*
oleexp.tlb v5.1oleexpimp.tlb v2.12 - Expanded fork of olelib2.tlb, replaces olelib2.tlb; replace all 'olelib2.<type>' with 'oleexpimp.<type>'All addon modulesFull changelog

*oleexp51-src.zip*
Source for TLBsOriginals of modified olelib filesCompile shortcutsmimelib.tlb - Original compiled against oleexp; won't work with it otherwise.oleexpwmp.tlb - wmp.inc has been moved to its own typelib to eliminate the dependency on wmp.dll for the main tlb



_Source distributed separately due to attachment size limits._

----------


## fafalone

(continued 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

And that's it! You're good to go.


*Version History*
(oleexp 5.1 - Released 05 November 2022)
-Several interfaces from shell automation were missing or only located in oleexpimp
-Added ISecurityInformation[2, 3, 4]/CreateSecurityPage API interfaces
-Added Windows Search API interfaces

(oleexp 5.03 - Released 20 October 2022)
-Added IHWEventHandler2 and IDynamicHWHandler interfaces
-(Bug fix) IShellTaskScheduler::CountTasks was incorrect and ::Status was missing.
-Misc oscure bug fixes
-(oleexpimp) Critical bug fix: Apparently, when oleeximp is compiled, MKTYPLIB favors the oleexp.tlb (imported) in SysWOW64 over the current directory. This resulted in a subtle mismatch causing 'Unexpected error (32810)' when implementing certain interfaces, even though the interface definitions themselves hadn't changed at all.

(oleexp 5.02 - Released 13 September 2022)
-Added missing oaidl interfaces ITypeMarshal, ITypeLibRegistration, ITypeLibRegistrationReader, ITypeChangeEvents, and ITypeMarshal.
-ICategoryProvider.CanCategorizeOnSCID needs to provide return value when used as a consumer. The all-HRESULT version is now in oleexpimp.tlb for providers.
-Added FILEOP_FLAGSEX with the FOFX_ values; this were already in the IFO_Flags enum with a custom prefix for displaying a combined enum for IFileOperation without showing them for SHFileOperation, but I thought they should also exist under the documented names.
-A few misc bug fixes to rarely used interfaces.
-Added a public LongPtr type; it's just an alias for Long but the idea is to enable writing code that can reused in 64bit VBA or twinBASIC.
-(oleexpimp) Added Implements-compatible versions of IPreviewHandler, IInitializeWithStream, IInitializeWithItem, and IInitializeWithFile for use in creating preview handler shell extensions.

(oleexp 5.01 - Released 16 June 2022)
-While I don't recall precisely why I put the incomplete set of shell32 automation interfaces in oleexpimp.tlb instead of oleexp.tlb, since there was no conflict, this situation has been rectified and there's now a *complete* copy of shell32 automation interfaces, with all exposed publicly rather than some hidden, in oleexp.tlb as well. They're still in oleexpimp as to not break compatibility.

(oleexp 5.0 - Released 28 May 2022)
-oleexp now includes all calls neccessary for TLB-based multithreading. Multithreading methods by The trick and Matthew Curland (PowerVB) have all calls included. For the latter, calls to the CreateThread API may need to be adjusted by pass ByVal, especially ByVal 0& for the LPSECURITY_ATTRIBUTES.
    Note: As with any multithreading with TLB project, you'll need to be careful you don't have any functions used by the multithreading code declared as Public in your project, as those will always have higher priority than a TLB.
-Added IInertiaProcessor, IManipulationProcessor, and IManipulationEvents interfaces with coclasses InertiaProcessor and ManipulationProcessor (for advanced handling of touch input). While these types are already in an addable reference, one uses unsigned longs, making that version incompatible with VB.
-Added interface IShellIconOverlayManager and coclass CFSIconOverlayManager
-Added SysReAllocStringW alias for SysReAllocString that supports a StrPtr pointer to properly support Unicode, finally relieving the need for a separate API declare for the LPWStrToStr function ubiquitous in oleexp projects (provided you add the W; I didn't want to break backwards compatibility by replacing the original). 
-Added ILVRange undocumented ListView interface. This one was *really* undocumented; I was the first to publicly document it: 
https://www.vbforums.com/showthread....T-and-ILVRange
-Added interface IShellRunDll; Implements-compatible.
-Updated SIIGBF and various other enums with flags introduced in Windows 8 or 10
-Created enum for SFVM_*... these were previously just commented out in source..
-For CoreAudio, REFERENCE_TIME and HNSTIME are now a public type alias for Currency (take care when using it).
-(Bug fix) Due to some trolling from Microsoft, IAudioClient has several members the public headers and topline documentation declare as WAVEFORMATEX. But in the fine print, you find this is a lie. They actually use WAVEFORMATEXTENSIBLE, and will not work on many systems without it. Since that was not included in the TLB, it's impossible to use. These methods now use As Any, so if the old way was working on your system, no changes are strictly neccessary (but if you're distributing it, your clients may run into it, so you should change it). This bug triggered releasing a new version now. IPolicyConfig, IPolicyConfigVista, IAudioClient2, and IAudioClient3 were also changed. 
-(Bug fix) AUDIO_VOLUME_NOTIFICATION_DATA only had a single array member for channel volume. It's set to 2 now to get two channel info, but this may change in the future if I figure out how to get 3+ channel info.
-(Bug fix) Finally corrected built-in AssocCreate API from the olelib original. It was missing 4 bytes; a CLSID is 16, but it originally had long short short long, which is 12. Now BYTE[8].
-(Bug fix) ULONG was defined as an unsigned long, but of course anyone trying to use it would get an error. It's now just an alias for a signed long. And no longer public.
-(mPKEY) SCID_DateDeleted and SCID_OriginalLocation don't have PROPERTYKEY defs in the SDK, but can still be passed (and will be received from) any Recycle Bin property store.

_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.


*Notes*
*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



*List of New Interfaces In OLEEXP (as of v5.01)*
IAccessible
IAccessibleHandler
IAccessibleWindowlessSite
IAccIdentity
IAccPropServer
IAccPropServices; coclass CAccPropServices
IApplicationAssociationRegistration*; coclass ApplicationAssociationRegistration
IApplicationAssociationRegistrationUI*; coclass ApplicationAssociationRegistrationUI 
IApplicationDestinations
IApplicationDocumentLists; coclass ApplicationDocumentLists
IAppPublisher*
IAssocHandler
IAssocHandlerInvoker
IAutoCompleteDropDown
IBrowserFrameOptions
IColumnManager
ICommDlgBrowser*
ICommDlgBrowser2*
ICommDlgBrowser3*
ICondition, coclass LeafCondition et al.
ICondition2
IConditionFactory; coclass ConditionFactory
IConditionFactory2
IConditionGenerator
IContextMenu3
IContextMenuCB
ICurrentItem
ICustomizeInfoTip
ICreateObject
ICustomDestinationsList; coclass DestinationList
IDataObjectAsyncCapability
IDefaultExtractIconInit
IDefaultFolderMenuInitialize; coclass DefFolderMenu
IDelegateFolder
IDelegateItem
IDisplayItem
IDragSourceHelperr; coclass DragDropHelper
IDragSourceHelper2r; coclass DragDropHelper
IDropTargetHelperr; coclass DragDropHelper
IEntity
IEnumAssocHandlers
IEnumerableView
IEnumExplorerCommand
IEnumFullIDList
IEnumPublishedApps*
IEnumReadyCallback
IEnumResources*
IEnumShellItems
IExecuteCommand; coclasses ExecuteFolder, ExecuteUnknown, and AppShellVerbHandler
IExecuteCommandHost
IExplorerBrowser; coclass ExplorerBrowser
IExplorerBrowserEvents
IExplorerCommandProvider
IExplorerCommandState
IExplorerPaneVisibility*
IFileDialog
IFileDialog2
IFileDialogControlEvents
IFileDialogCustomize
IFileDialogEvents
IFileIsInUse
IFileOpenDialog; coclass FileOpenDialog
IFileOperation; coclass FileOperation
IFileOperationProgressSink
IFileSaveDialog; coclass FileSaveDialog
IFileSystemBindData
IFileSystemBindData2
IFilterCondition
IFolderView2
IFolderViewOptions
IFolderViewSettings
IFrameworkInputPane; coclass FrameworkInputPane
IFrameworkInputPaneHandler
IHomeGroup; coclass HomeGroup
IIdentityName
IImageList; coclass ImageList***
IImageList2
IImageRecompress; coclass ImageRecompress
IInertiaProcessor; coclass InertiaProcessor
IInitializeCommand
IInitializeNetworkFolder, coclass NetworkPlaces
IInitializeWithBindCtx
IInitializeWithFile
IInitializeWithItem
IInitializeWithPropertyStore
IInitializeWithStream
IInitializeWithWindow
IInternetSecurityManagerEx
IInternetSecurityManagerEx2
IInternetZoneManagerEx
IInternetZoneManagerEx2
IInterval, coclass Interval
IItemFilter
IItemNameLimits
IKnownFolder
IKnownFolderManager; coclass KnownFolderManager
IManipulationProcessor; coclass ManipulationProcessor
IManipulationEvents
IMessageFilter
IMetaData
IModalWindow
IMultiQI
INamedEntity
INamedEntityCollector
INamedPropertyStore
INameSpaceTreeControl
INameSpaceTreeControl2; coclass NamespaceTreeControl
INameSpaceTreeControlAccessible
INameSpaceTreeControlCustomDraw
INameSpaceTreeControlDropHandler
INameSpaceTreeControlEvents
INameSpaceTreeControlFolderCapabilities
INamespaceWalk
INamespaceWalkCB
INamespaceWalkCB2
INewMenuClient
INewWindowManager
IObjectArray
IObjectCollection; coclass EnumerableObjectCollection
IObjectWithFolderEnumMode
IObjectWithPropertyKey
IObjMgr
IOperationsProgressDialog
IPersistFolder3
IPreviewHandler
IPreviewHandlerFrame
IPreviewHandlerVisuals
IPreviewItem
IPreviousVersionsInfo; coclass PreviousVersions
IProgressDialog
IPropertyChange
IPropertyChangeArray
IPropertyDescription
IPropertyDescription2
IPropertyDescriptionAliasInfo
IPropertyDescriptionList
IPropertyDescriptionRelatedPropertyInfo
IPropertyDescriptionSearchInfo
IPropertyEnumType
IPropertyEnumType2
IPropertyEnumTypeList
IPropertyStore
IPropertyStoreCache
IPropertyStoreCapabilities
IPropertyStoreFactory
IPropertySystem
IPublishedApp*
IPublishedApp2*
IQueryParser, coclass QueryParser
IQueryParserManager, coclass QueryParserManager
IQuerySolution
IRelatedItem
IRelationship
IResolveShellLink
IResultsFolder
IRichChunk*
ISchemaLocalizerSupport
ISchemaProvider
ISearchBoxInfo*
ISearchFolderItemFactory; coclass SearchFolderItemFactory
ISharedBitmap
ISharingConfigurationManager; coclass SharingConfigurationManager
IShellApp*
IShellChangeNotify
IShellFolderViewCB*
IShellIconOverlay
IShellIconOverlayIdentifier*
IShellIconOverlayManager; coclass CFSIconOverlayManager
IShellImageDataFactory; coclass ShellImageDataFactory
IShellImageData
IShellImageDataAbort*
IShellItem
IShellItem2
IShellItemArray
IShellItemFilter
IShellItemImageFactory
IShellItemResources
IShellLibrary
IShellLinkDataList
IShellMenu*
IShellMenuCallback*
IShellRunDll
IShellTaskScheduler; coclass ShellTaskScheduler
IShellWindows; coclass ShellWindows
ISpellingError
IStartMenuPinnedList
IStreamAsync
ISystemInformation; coclass SystemInformation
ITaskbarList3
ITaskbarList4; coclass TaskbarList
ITaskService, coclass TaskS
IThumbnailCache; coclass LocalThumbnailCache
IThumbnailHandlerFactory
IThumbnailProvider
IThumbnailSettings
ITokenCollection
ITrackShellMenu; coclass TrackShellMenu
ITranscodeImage; coclass ImageTranscode
ITransferAdviseSink*
ITransferDestination*
ITransferMediumItem
ITransferSource*
IUri
IUserNotification2; coclass UserNotification
IUserNotificationCallback
IUseToBrowseItem
IViewStateIdentityItem
IVirtualDesktopManager, coclass VirtualDesktopManager
IVisualProperties
IZoneIdentifier; coclass PersistentZoneIdentifier
IZoneIdentifier2
IZombie
Task Manager
IAction
IActionCollection
IBootTrigger
IComHandlerAction
IDailyTrigger
IEmailAction
IEventTrigger
IExecAction
IExecAction2
IIdleSettings
IIdleTrigger
ILogonTrigger
IMaintenanceSettings
IMonthlyDOWTrigger
IMonthlyTrigger
INetworkSettings
IPrincipal
IPrincipal2
IRegisteredTask
IRegisteredTaskCollection
IRegistrationInfo
IRegistrationTrigger
IRepetitionPattern
IRunningTask
IRunningTaskCollection
ISessionStateChangeTrigger
IShowMessageAction
ITaskDefinition
ITaskFolder
ITaskFolderCollection
ITaskHandler
ITaskHandlerStatus
ITaskNamedValueCollection
ITaskNamedValuePair
ITaskService; coclass TaskScheduler
ITaskSettings
ITaskSettings2
ITaskSettings3
ITaskVariables
ITimeTrigger
ITrigger
ITriggerCollection
IWeeklyTrigger
Spell Checking
IComprehensiveSpellCheckProvider
IEnumSpellingError
IOptionDescription
ISpellChecker
ISpellChecker2
ISpellCheckerChangedEventHandler
ISpellCheckerFactory; coclass SpellCheckerFactory
ISpellCheckProvider
ISpellCheckProviderFactory
ISpellingError
IUserDictionariesRegistrar
ListView
IDrawPropertyControl
IListView
IListViewFooter
IListViewFooterCallback
ILVRange
IOwnerDataCallback
IPropertyControl
IPropertyControlBase
IPropertyValue
ISubItemCallback
Shell Automation
DFConstraint
DShellFolderViewEvents, coclass ShellFolderViewOC
Folder
Folder2
Folder3
FolderItem
FolderItem2, coclass FolderItem
FolderItems
FolderItems2
FolderItems3
FolderItemVerb
FolderItemVerbs
IFolderViewOC
IShellFolderViewDual
IShellFolderViewDual2
IShellFolderViewDual3, coclass ShellFolderView
IShellDispatch
IShellDispatch2
IShellDispatch3
IShellDispatch4
IShellDispatch5
IShellDispatch6, coclass Shell
IShellLinkDual
IShellLinkDual2, coclass ShellLinkObject

*Core Audio*

IActivateAudioInterfaceAsyncOperation
IActivateAudioInterfaceCompletionHandler
IAudioAutoGainControl
IAudioBass
IAudioCaptureClient
IAudioChannelConfig
IAudioClient
IAudioClient2
IAudioClient3
IAudioClock
IAudioClock2
IAudioClockAdjustment
IAudioEndpointFormatControl
IAudioEndpointLastBufferControl
IAudioEndpointOffloadStreamMeter
IAudioEndpointOffloadStreamMute
IAudioEndpointOffloadStreamVolume
IAudioEndpointVolume
IAudioEndpointVolumeCallback
IAudioEndpointVolumeEx
IAudioInputSelector
IAudioLfxControl
IAudioLoudness
IAudioMeterInformation
IAudioMidrange
IAudioMute
IAudioOutputSelector
IAudioPeakMeter
IAudioRenderClient
IAudioSessionControl
IAudioSessionControl2
IAudioSessionEnumerator
IAudioSessionEvents
IAudioSessionManager
IAudioSessionManager2
IAudioSessionNotification
IAudioStreamVolume
IAudioSystemEffects
IAudioSystemEffects2
IAudioTreble
IAudioVolumeDuckNotification
IAudioVolumeLevel
IChannelAudioVolume
IConnector
IControlChangeNotify
IControlInterface
IDeviceSpecificProperty
IDeviceTopology
IHardwareAudioEngineBase
IKsControl
IKsFormatSupport
IKsJackContainerId
IKsJackDescription
IKsJackDescription2
IKsJackSinkInformation
IMMDevice
IMMDeviceActivator
IMMDeviceCollection
IMMDeviceEnumerator
IMMEndpoint
IMMNotificationClient
IPart
IPartsList
IPolicyConfig
IPerChannelDbLevel
ISimpleAudioVolume
ISubunit

*DirectShow***

IAMAnalogVideoDecoder
IAMAsyncReaderTimestampScaling
IAMAudioInputMixer
IAMAudioRendererStats
IAMBufferNegotiation
IAMCameraControl
IAMCertifiedOutputProtection
IAMChannelInfo
IAMClockAdjust
IAMClockSlave
IAMCollection
IAMCopyCaptureFileProgress
IAMCrossbar
IAMDecoderCaps
IAMExtendedErrorInfo
IAMExtendedSeeking
IAMMediaContent
IAMMediaContent2
IAMNetShowConfig
IAMNetShowExProps
IAMNetShowPreroll
IAMNetworkStatus
IAMStats
IBaseFilter, multiple coclasses
IBasicAudio
IBasicVideo
IBasicVideo2
ICaptureGraphBuilder
ICaptureGraphBuilder2
IDeferredCommand
IEnumFilters
IEnumMediaTypes
IEnumPins
IFileSinkFilter
IFilterGraph, coclass FilterGraph
IFilterGraph2
IFilterGraph3
IFilterInfo
IGraphBuilder
IMediaControl
IMediaEvent
IMediaEventEx
IMediaFilter
IMediaPosition
IMediaSample
IMediaSample2
IMediaSample3
IMediaTypeInfo
IPin
IPinInfo
IQueueCommand
IReferenceClock
IRegFilterInfo
ISampleGrabber, coclass SampleGrabber
ISampleGrabberCB
IVideoWindow

*Windows Imaging Component (WIC)ª*

IWICBitmap
IWICBitmapClipper
IWICBitmapCodecInfo
IWICBitmapCodecProgressNotification
IWICBitmapDecoder
IWICBitmapDecoderInfo
IWICBitmapEncoder
IWICBitmapEncoderInfo
IWICBitmapFlipRotator
IWICBitmapFrameDecode
IWICBitmapFrameEncode
IWICBitmapLock
IWICBitmapScaler
IWICBitmapSource
IWICBitmapSourceTransform
IWICColorContext
IWICColorTransform
IWICComponentFactory
IWICComponentInfo
IWICDdsDecoder
IWICDdsEncoder
IWICDdsFrameDecode
IWICDevelopRaw
IWICDevelopRawNotificationCallback
IWICEnumMetadataItem
IWICFastMetadataEncoder
IWICFormatConverter
IWICFormatConverterInfo
IWICImageEncoder
IWICImagingFactory, coclass WICImagingFactory
IWICImagingFactory2, coclass WICImagingFactory2
IWICJpegFrameDecode
IWICJpegFrameEncode
IWICMetadataBlockReader
IWICMetadataBlockWriter
IWICMetadataHandlerInfo
IWICMetadataQueryReader
IWICMetadataQueryWriter
IWICMetadataReader
IWICMetadataReaderInfo
IWICMetadataWriter
IWICMetadataWriterInfo
IWICPalette
IWICPersistStream
IWICPixelFormatInfo
IWICPixelFormatInfo2
IWICPlanarBitmapFrameEncode
IWICPlanarBitmapSourceTransform
IWICPlanarFormatConverter
IWICProgressCallback
IWICProgressiveLevelControl
IWICStream
IWICStreamProvider

*Portable Devices*

IEnumPortableDeviceConnectors****
IEnumPortableDeviceObjectIDs
IPortableDevice, coclasses PortableDevice, PortableDeviceFTM
IPortableDeviceCapabilities
IPortableDeviceConnector****
IPortableDeviceContent
IPortableDeviceContent2
IPortableDeviceDispatchFactory, coclass PortableDeviceDispatchFactory
IPortableDeviceEventCallback
IPortableDeviceKeyCollection, coclass PortableDeviceKeyCollection
IPortableDeviceManager, coclass PortableDeviceManager
IPortableDeviceProperties
IPortableDevicePropertiesBulkCallback
IPortableDevicePropVariantCollection, coclass PortableDevicePropVariantCollection
IPortableDeviceResources
IPortableDeviceService, coclass PortableDeviceService
IPortableDeviceServiceCapabilities
IPortableDeviceServiceMethodCallback
IPortableDeviceServiceMethods
IPortableDeviceServiceOpenCallback
IPortableDeviceValues, coclass PortableDeviceValues
IPortableDeviceValuesCollection
IPortableDeviceWebControl, coclass PortableDeviceWebControl
IWpdSerializer, coclass WpdSerializer

*Net Connections*

IEnumNetConnection
IEnumNetSharingEveryConnection
IEnumNetSharingPortMapping
IEnumNetSharingPrivateConnection
IEnumNetSharingPublicConnection
INetConnection
INetConnectionConnectUi
INetConnectionManager, coclass ConnectionManager
INetConnectionProps
INetSharingConfiguration
INetSharingEveryConnectionCollection
INetSharingManager, coclass NetSharingManager
INetSharingPortMapping
INetSharingPortMappingCollection
INetSharingPortMappingProps
INetSharingPrivateConnectionCollection
INetSharingPublicConnectionCollection


* - 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._

----------


## MountainMan

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.

----------


## fafalone

MORE SECTIONS FROM ABOVE NEEDED TO BE MOVED DOWN; THIS POST IS PART OF THE MAIN PROJECT POST ALONG WITH #1 and #2.

*Interfaces Included From Original OLELIB*
IACList
IACList2
IActionProgress
IActionProgressDialog
IActiveDesktop
IAddressBarParser; coclass AddressBarParser
IAdviseSink
IAuthenticate
IAutoComplete
IAutoComplete2
IBindCtx
IBindHost
IBinding
IBindProtocol
IBindStatusCallback
ICallAddRelease
ICallGION
ICallInvoke
ICallQI
ICategorizer; multiple coclasses
ICategoryProvider
ICatInformation
ICatRegister
ICDBurn; coclass CDBurn
IClassFactory
IClassFactory2
IColumnProvider
IConnectionPoint
IConnectionPointContainer
IContextMenu
IContextMenu2
IContinueCallback
ICopyHookA
ICopyHookW
ICreateErrorInfo
ICreateTypeInfo
ICreateTypeInfo2
ICreateTypeLib
ICreateTypeLib2
ICustomDoc
IDataObject
IDeskBand
IDispatch
IDocHostShowUI
IDocHostUIHandler
IDocHostUIHandler2
IDockingWindow
IDockingWindowFrame
IDockingWindowSite
IDropSource
IDropTarget
IEmptyVolumeCache
IEmptyVolumeCache2
IEmptyVolumeCacheCallBack
IEnumACString
IEnumCATEGORYINFO
IEnumConnectionPoints
IEnumConnections
IEnumExtraSearch
IEnumFORMATETC
IEnumGUID
IEnumHLITEM
IEnumIDList
IEnumMoniker
IEnumOleDocumentViews
IEnumOLEVERB
IEnumSTATDATA
IEnumSTATPROPSETSTG
IEnumSTATPROPSTG
IEnumSTATSTG
IEnumSTATURL
IEnumString
IEnumUnknown
IEnumVARIANT
IEnumWorkItems
IErrorInfo
IErrorLog
IExtractIconA
IExtractIconW
IExtractImage
IExtractImage2
IFillLockBytes
IFolderFilter
IFolderFilterSite
IFolderView
IFolderViewHost; coclass FolderViewHost
IHlink
IHlinkBrowseContext
IHlinkFrame
IHlinkSite
IHlinkTarget
IHttpNegotiate
IHWEventHandler
IInputObject
IInputObjectSite
IInternetBindInfo
IInternetHostSecurityManager
IInternetPriority
IInternetProtocol
IInternetProtocolInfo
IInternetProtocolRoot
IInternetProtocolSink
IInternetSecurityManager
IInternetSecurityMgrSite
IInternetSession
IInternetZoneManager
ILayoutStorage
ILockBytes
IMalloc
IMarshal
IMoniker
INetCrawler; coclass NetCrawler
INewShortcutHookA
INewShortcutHookW
IObjectSafety
IObjectWithSite
IOleCache
IOleClientSite
IOleCommandTarget
IOleContainer
IOleControl
IOleControlSite
IOleDocument
IOleDocumentSite
IOleDocumentView
IOleInPlaceActiveObject
IOleInPlaceFrame
IOleInPlaceObject
IOleInPlaceSite
IOleInPlaceUIWindow
IOleLink
IOleObject
IOleWindow
IParseDisplayName
IPerPropertyBrowsing
IPersist
IPersistFile; coclass ImageProperties
IPersistFolder
IPersistFolder2
IPersistIDList
IPersistMemory
IPersistMoniker
IPersistPropertyBag
IPersistPropertyBag2
IPersistStorage
IPersistStream
IPersistStreamInit
IPrint
IProfferService
IProgressDialog
IPropertyBag
IPropertyBag2
IPropertyNotifySink
IPropertySetStorage
IPropertyStorage
IPropertyUI; coclass PropertiesUI
IProvideClassInfo
IProvideTaskPage
IPublishingWizard; coclass PublishingWizard
IQueryAssociations
IQueryCancelAutoPlay; coclass QueryCancelAutoPlay
IQueryContinue
IQueryInfo
IRecordInfo
IRichEditOle
IRichEditOleCallback
IRootStorage
IRunningObjectTable
IScheduledWorkItem 
ISchedulingAgent 
ISearchContext
ISequentialStream
IServiceProvider
IShellBrowser
IShellExecuteHookA
IShellExecuteHookW
IShellExtInit
IShellFolder2
IShellFolder
IShellIcon
IShellLinkA
IShellLinkW; coclass ShellLinkW
IShellPropSheetExt
IShellView2
IShellView
ISpecifyPropertyPages
IStorage
IStream
ISupportErrorInfo
ITaskbarList
ITaskbarList2
ITask
ITaskTrigger 
ITextDocument
ITextFont
ITextPara
ITextRange
ITextSelection
ITextStoryRanges
ITypeComp
ITypeInfo
ITypeInfo2
ITypeLib
ITypeLib2
IUniformResourceLocatorA
IUniformResourceLocatorW
IUnknown
IUrlHistoryStg
IUrlHistoryStg2
IURLSearchHook
IURLSearchHook2
IUserEventTimer; coclass UserEventTimer
IUserEventTimerCallback; coclass UserEventTimerCallback
IUserNotification
IViewObject
IViewObject2
IWebWizardExtension; coclass WebWizardHost
IWindowForBindingUI
IWinInetHttpInfo
IWinInetInfo
IWizardExtension
IWizardSite


 - 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):


```
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:



```
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!



```
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



```
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.

*Related Projects*
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_

[VB6, Vista+] Undocumented ListView feature: Subsetted Groups (simple, no TLB) - Allows you to show only a given number of rows per group, with a hyperlink at the bottom the user can click to show the rest.

[VB6, Vista+] Undocumented ListView feature: Groups in Virtual Mode - Group View officially isn't compatible when the LVS_OWNERDATA style is set, but with a little work it's actually possible.
_Interfaces: IListView, IOwnerDataCallback_

[VB6] Undocumented ListView feature: Highlight column - Set a background highlight color for an individual column.

[VB6, Win7+] Undocumented ListView Feature: Multiselect in columns like Explorer - Start a selection rectangle by dragging from the whitespace next to the filenames (instead of that starting a drag/drop or doing nothing if DD disabled).

_Interfaces: IVisualProperties_

*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.

----------


## fafalone

@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?



```
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.



```
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
```

----------


## sdijakovic

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

----------


## fafalone

Answered in IFileDialog thread.

----------


## fafalone

Major project update to 2.0. Many new interfaces, sample projects, and bugfixes.

----------


## Tech99

> 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.



```
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?

----------


## 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.
> 
> 
> 
> ```
> ...


Edit... variable declaration from integer to long seemed to resolve this.


```
Private CF_FILECONTENTS As Long 'Integer
```

----------


## 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?

----------


## fafalone

> Edit... variable declaration from integer to long seemed to resolve this.
> 
> 
> ```
> 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.

----------


## fafalone

> Μ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?

----------


## georgekar

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.

----------


## fafalone

So what does the typelib entry look like now, and is there any special code like CopyMemory to retrieve the full array?

----------


## georgekar

This is a part of mdlIDispatch.cls you can find in the code in M2000 source in sign.


```
        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.



```
   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)
```

----------


## fafalone

varDISPID() is then filled correctly, so varDISPID(1, 2...etc) would have the correct values?

cNames is the count of items in the array being passed... why wouldn't you know this value? It's just UBound(myptr) + 1 in the code in your post.

----------


## fafalone

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?

----------


## 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.

----------


## Bonnie West

> *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
> 
> 
> 
> ```
> Dim psi As IShellItem
> ...


Manually invoking IUnknown's QueryInterface method isn't actually necessary in Visual Basic. The *Set* statement already does it for you.




> *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.
> 
> 
> 
> ```
> Dim MyRef1 As IUnknown
> Set MyRef1 = New MyObject
> ...





> *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:
> 
> 
> 
> ```
> ...


These 2 lines of code can therefore be reduced to just 1:



```
'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:



```
Call SHCreateShellItem(0, 0, pidl, psi2)
```

----------


## fafalone

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.

----------


## fafalone

> 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?

----------


## georgekar

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.

----------


## fafalone

> 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.

----------


## DracullSoft

Thanks - this is cool alone and with all the examples excellent!  :Smilie:

----------


## fafalone

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.

----------


## gigirex

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.

Thank you in advance

gigirex

----------


## fafalone

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):


```
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:


```
Dim pVTable As IBindStatusCallback
Set pVTable = Me
mOldOP = SwapVtableEntry(ObjPtr(pVTable), 7, AddressOf IBSCBOnProgress)
```

and in Class_Terminate, add:


```
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.

----------


## gigirex

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.

Regards,
Luigi Stilo

----------


## fafalone

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.

----------


## Bonnie West

> ... 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 *Sub*s (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*.

----------


## fafalone

> 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.

----------


## Ben321

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.

----------


## jpbro

Look at the bottom of the first post in the _Attached Files_ section for the download link.

----------


## fafalone

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)

----------


## RAFAAJ2000

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



```
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
```

----------


## MountainMan

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:



```
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:



```
#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:



```
#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.

----------


## RAFAAJ2000

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 



```
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 :


```
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 ? 

Thanks for your help one more time

----------


## MountainMan

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.

----------


## fafalone

> 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.

----------


## RAFAAJ2000

@ MountainMan,
Thnks ... I was in a hurry and didn't notice that the lOldAddr variable was also declared inside the HookCOMFunction procedure ... Actually I also wrongly left the lpfnAddr variable inside 

I have now sucessfully managed to override the CalculateFull Method of the excel application object AND to unhook it back ti its original as shown in the code below :


```
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 Long, _
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
Private lpfnAddr As LongPtr

Sub HookCOMFunction()
    Dim lpVtableHead 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

Sub UnHookComFunction()
    CopyMemory ByVal lpfnAddr, lOldAddr, 8
End Sub
```

Unfortunately, this only works when yielding the _CalculateFull_ Method via code as per the _Test_ Procedure above ... Can this also work when executing the CalculateFull Method via the excel user interface ?!!

----------


## RAFAAJ2000

> Well in principle, you could subclass the process and intercept the menus WM_COMMAND message, but subclassing a 64-bit app might be challenging.


@fefalone,
Thanks ... the whole idea was to replace the VTable address of a given excel Method ( in this case I arbitrarly chose the CalculateFull Method) with that of my own function and override the native Method behaviour 

I have successfully done some Subclassing/Windos hooking in office applications before but I am trying to explore VTable redirection and see what I can obtain

----------


## Bonnie West

> 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.


I have not tested this, but according to an example here, determining the interfaces that an object supports can also be done in a more VB-ish manner using *TypeOf ... Is*:



```
Select Case True
    Case TypeOf Object Is IInitializeWithFile:
    Case TypeOf Object Is IInitializeWithItem:
    Case TypeOf Object Is IInitializeWithStream:
End Select
```

----------


## fafalone

Good tip, I plugged that into the IPreviewHandler project and it worked.


```
    hr = CoCreateInstance(tHandler, 0, CLSCTX_INPROC_SERVER Or CLSCTX_LOCAL_SERVER, IID_IPreviewHandler, ipv)
    Select Case True
        Case TypeOf ipv Is IInitializeWithFile: Call MsgBox("IIF")
        Case TypeOf ipv Is IInitializeWithItem: Call MsgBox("III")
        Case TypeOf ipv Is IInitializeWithStream: Call MsgBox("IIS")
    End Select
```

That said, you should know by now that doing things "in a more VB-ish manner" is the exact opposite of what I like to do  :Big Grin:

----------


## georgekar

Using in uuid(00020400-0000-0000-C000-000000000046) the LPWSTR for *rgszNames you can't pass array of strings, so you can't handle named argouments.
.........
LONG GetIDsOfNames(
............
 [in] LPWSTR *rgszNames,

you have to replace with 

[in] long *rgszNames,

so this is a pointer to one or many names (you can provide the number of these)

I use IDispatch to communicate my Interpreter M2000 with Word using namedarguments.

usage:
 ReDim myptr(0 To fixnamearg)
            myptr(0) = StrPtr(pstrProcName)
..................so here we pass a strptr
            For lngLoop = 1 To fixnamearg
            myptr(lngLoop) = StrPtr(pargs2(lngLoop))
            Next lngLoop
                ReDim varDISPID(0 To fixnamearg)
................... so now we pass the array (beforwe we can't do that)
            lngRet = IDsp.GetIDsOfNames(rIid, myptr(0), fixnamearg + 1, cLid, varDISPID(0))
 DISPID = varDISPID(0)
End If
(this is code from M2000 Interpreter - is open source)

----------


## fafalone

Yeah in fact I've been thinking about just replacing LPWSTR across the board with longs but have been hesitant since it effects backwards compatibility with code based on olelib. I can change it in the next version coming out in a few days anyway (finishing up Core Audio interfaces)... but in the meantime just out of curiosity; the definition is currently [in] LPWSTR *rgszNames so it's passed ByRef... it doesn't work if you pass pargs2(0), UBound(pargs2) +1 ? This works in most other cases.

----------


## fafalone

New version up containing the full set of DirectShow interfaces-- I really haven't had time to play around with these however so if anyone does, let me know how it goes  :Alien Frog: 
Also new IMMNotificationClient def is live but whether to adjust similar interfaces is still an open issue. Let me know.

----------


## fafalone

*BUG ALERT!* If you downloaded oleexp 3.7 before *July 16th* do not use the olelib2.tlb that came with it without updating. Since olelib2 depends on oleexp3, it has to be recompiled against the new version. So please use the version posted on or after July 16th 2016 of olelib2. Not doing so can cause a ***major*** bug: all usercontrols and their settings will be deleted from all forms in the project when the form is loaded, and new instances of usercontrols cannot be created, if you have a class module implementing one of the interfaces from olelib2.

Very sorry about that, it's a very obscure and undocumented bug, it took an hour to even figure out that the bug was being caused by the version conflict, as there's no errors on the problem class itself, just the controls disappearing and a 'Error in loading DLL' message when trying to create new controls.

This bug only applies to people who use olelib2 and updated between July 13th, 2016 when v3.7 was posted, and July 16th, 2016 when the fixed version was posted (same version number/filename, oleexp37.zip)
Download the updated versions from the first post or here: Attachment 139493

----------


## RAFAAJ2000

Hi all,

Is it possible to hook the VTable of an *Event* Interface such as the *ICommandBarButtonEvents* of Microsoft Office Object Library ? GUID ="{55F88890-7708-ACEB-C000-006008961DA5}"

Thank you

----------


## Shaggy Hiker

I think you'd be better off starting a new thread for this. It seems somewhat related to the original question, but not entirely, and there hasn't been any activity for a month. I could split it out for you, if you'd like, but a new thread seems likely to get you better answers.

----------


## RAFAAJ2000

> I think you'd be better off starting a new thread for this. It seems somewhat related to the original question, but not entirely, and there hasn't been any activity for a month. I could split it out for you, if you'd like, but a new thread seems likely to get you better answers.


Thanks Shaggy Hiker
I'll start a new thread as suggested

----------


## chrislong2

First, thanks for this.

However, there's a rather quirky problem:

Brand new project.  Add the reference to the TLB.

Now in your Form Load add the following:


```
For z = 1 to 2
MSGBOX "Hello"
Next z
```

Try to compile.  Good luck - you'll get a compile error about how a variable can't be assigned to this expression.  Remove the TLB reference and it compiles fine as it should.

Doesn't matter where the "z" reference is in code.  I stumbled across this because I added the TLB to a very large project with lots of code and found that there were NUMEROUS places in my code that used a variable named z.  Won't compile with that.  Obviously somewhere in the TLB, "z" is being used/defined and the compiler won't allow its use outside of that context.

----------


## fafalone

Wow surprised no one has ever noticed that before; it's a typo from the url.inc file included from the original olelib.tlb this is derived from.


```
typedef [helpstring("Values for PID_INTSITE_WATCH")]
enum PIDISM {
    [helpstring("Monitor based on global setting")]
    PIDISM_GLOBAL = 0,
    [helpstring("User says watch")]
    PIDISM_WATCH = 1,
    [helpstring("User says don't watch")]
    PIDISM_DONTWATCH = 2,z
} PIDISM;
```

Having 'z' after the comma makes the compiler treat it as the next entry in the enum, so it's a global constant that =3. It's been fixed in the source and will be in the next release sometime in the next week.
In the mean time, note that the only way this bug shows up is if you're using a very bad technique- not declaring your variables. If your project had Dim z As Long, the error would not occur. If you're not up to doing it in every procedure, a slightly less bad alternative would be to add your own Public z As Variant, which is what it's being defined as currently when you haven't specified another type (or if it's always used as a Long, you can declare it publicly as that).

----------


## chrislong2

> Having 'z' after the comma makes the compiler treat it as the next entry in the enum, so it's a global constant that =3. It's been fixed in the source and will be in the next release sometime in the next week.
> In the mean time, note that the only way this bug shows up is if you're using a very bad technique- not declaring your variables. If your project had Dim z As Long, the error would not occur. If you're not up to doing it in every procedure, a slightly less bad alternative would be to add your own Public z As Variant, which is what it's being defined as currently when you haven't specified another type (or if it's always used as a Long, you can declare it publicly as that).


Thanks fafalone!  Yes, I'm a bad, bad coder - I frequently don't declare my variables when I use them for simple things like For loops.  I know lots of people frown on that, but I don't care - they can frown.  :Smilie:   The very first thing I do when I import anyone else's code is turn off Option Explicit if it's been set.  I know all the "real coders" out there are shaking their heads at me but it makes me happy.  Option Explicit just irritates the living daylights out of me.   :Smilie:   When the variable type really matters, I declare it.  When it doesn't (such as a for loop), I don't.  I'm sure back in 1998, the extra overhead between the default variant or a declared int or long mattered more, but even my 100,000+ line program with loads and loads of undeclared vars runs ultra-speedy on even super old hardware with little RAM.

As for your solution, thanks for that - I don't know why I didn't try declaring it public to solve.  Anyway, it turns out I didn't have quite as many parts of the code as I thought that used "z" (they were all in For loops), so I just changed them to a different letter.  :Wink:   :Wink:

----------


## radialapps

THIS IS SUPER AWESOME!!!
I can't believe there is still so much enthusiasm about vb6 <3

----------


## chrislong2

> THIS IS SUPER AWESOME!!!
> I can't believe there is still so much enthusiasm about vb6 <3


Well, .NET has a lot going for it and in many respects is a great choice.  But VB6, even 18 years later, still has some significant pros compared to .NET and sometimes is arguably the better choice despite what some .NET people think.  Unlike .NET, its runtime is included with Windows 2000+ (.NET varies depending on OS) and apps are noticeably speedier/faster to load.  There isn't much you can't do in VB6 by using the API.  I've got VB6 apps that take advantage of lots of newer stuff/technologies.  I do admit that it is starting to get to the point that in order to get VB6 to do what most modern desktop apps need requires LOTS of tweaking and API code, including much that is necessary to replace VB's own limited built-in functions.  But once you've done it, then it's relatively straightforward so there are those that have stuck with it over the years and now have code to get VB6 to do lots of the modern stuff a la this posting by fafalone.  While I use .NET, VB6 is still my preferred choice in some cases and I think there's plenty of others that feel the same way.  There are times that it is the better option even for some new projects IMHO (obviously depending on project type/scope).

----------


## fafalone

*Major Project Update!*

A huge number of new interfaces have been added as the major version number hits 4.0. I also took the opportunity to ditch the whole 'oleexp3' thing and make the project name version-independent again. Felt this neccessitated a new GUID for the TLB too. So reference must be changed, can't overwrite the .tlb like usual. Last time, swear! 

The first sample project with some of the new 4.0 interfaces is up too, and a whole lot more will be coming. Here's the scoop on the new version and the changelog, also found in post #2 (for now).

*OLEEXP Version 4.0*
This is a major version upgrade. Along with a large number of new additions, the TLB itself has changed and a few extra steps are needed. To upgrade existing projects:
-The TLB has a new GUID and as such is essentially a new typelib, with the original name of just oleexp.tlb restored. Remove the reference to oleexp3.tlb and add a new reference to oleexp.tlb.
-Replace all instances of 'oleexp3.<type>' with 'oleexp.<type>. No existing items were modified, so it is safe to run a Replace All with oleexp3 replaced with oleexp
-I promise this is the last time I'll switch the name of the TLB; couldn't stay with 3.x forever and just plain oleexp makes more sense.
-oleexpimp.tlb and mimelib.tlb have been compiled against oleexp 4.0; these can simply be overwritten.
*-All sample projects have been updated to use oleexp.tlb 4.0, reference changed and oleexp3. replaced with oleexp. - both attached projects and code in posts.*

A large number of additions are geared towards writing highly modernized and sophisticated namespace extensions, there will be a major project along these lines in the future.

(oleexp v4.0 - 24 Nov 2016)
-Added interfaces IThumbnailCache, IThumbnailSettings, and ISharedBitmap. Added coclasses LocalThumbnailCache and SharedBitmap. Added associated enums WTS_FLAGS, WTS_CACHEFLAGS, WTS_CONTEXTFLAGS, and struct WTS_THUMBNAILID.
-Added interface IDefaultExtractIconInit
-Added interface IApplicationDocumentLists with coclass ApplicationDocumentLists
-Added interface IHomeGroup with coclass HomeGroup; added associated enum HOMEGROUPSHARINGCHOICES
-Added interface ITrackShellMenu with coclass TrackShellMenu
-Added interface IContextMenuCB and related structs QCMINFO and DFMICS
-Added interface IExecuteCommand with coclasses ExecuteFolder, ExecuteUnknown, and AppShellVerbHandler
-Added interfaces IExplorerCommand, IEnumExplorerCommand, IExplorerCommandProvider, IExplorerCommandState, IExecuteCommandHost, and IInitializeCommand. Added associated enums EC_HOST_UI_MODE, EXPCMDFLAGS and EXPCMDSTATE.
-Added interface INewWindowManger
-Added interface IDelegateFolder
-Added interface IBrowserFrameOptions
-Added interface IFileIsInUse
-Added interface ICreateObject
-Added interface IShellChangeNotify
-Added interfaces IInitializeWithPropertyStore and IInitializeWithWindow. The latter is Win8+.
-Added coclass ApplicationAssociationRegistration for IApplicationAssociationRegistration
-Added coclass ApplicationAssociationRegistrationUI for IApplicationAssociationRegistrationUI
-Added COMDLG_FILTERSPEC struct (IFileOpenDialog/IFileSaveDialog)
-Added SysCommands enum (SC_ values; SC_CLOSE, SC_MINIMIZE, etc)
-FILEOPENDIALOGOPTIONS enum was missing FOS_SUPPORTSTREAMABLEITEMS
-Bug fix: Some features listed as included in 3.8 weren't in the release posted.
-(mIID) Added all IIDs for new interfaces
-(mIID) Added all known other SID_ values

----------


## loquat

i have one question after reading ur post

```
oleexpimp.tlb and mimelib.tlb have been compiled against oleexp 4.1
-oleexpimp.tlb - Expanded fork of olelib2.tlb, replaces olelib2.tlb; replace all 'olelib2.<type>' with 'oleexpimp.<type>'
-mimelib.tlb - same as the original except compiled against oleexp; won't work with it otherwise.
```

does oleexp 4.1 include oleexpimp or mimelib?
what is the differences?

----------


## fafalone

They're both included in oleexp41.zip, in the Implements and mime folders respectively. Oleexpimp is like olelib2, it has versions of certain interfaces that can be used with the Implements keyword in a class, where the version in oleexp.tlb cannot. Mimelib is for working with mime, a very specific set of apis. Neither of these need to be included unless you're using them.

----------


## MountainMan

You spoiled it for me! I thought you were working with pimps and mimes...  :Wink:

----------


## fafalone

Saving that for oleexp v6.9  :EEK!:

----------


## SaschaT

Looks like if there is an error in exp_explrvw.odl for *IExplorerPaneVisibility*. If I try to implement the interface in a class module I get a 'bad interface implementation' error due to the out-parameter.
I changed the declaration for *GetPaneState* to



```
    HRESULT GetPaneState(
		[in] UUID *ep,
		[in, out] EXPLORERPANESTATE *peps);
```

and recompiled the tlb. I can then implement IExplorerPaneVisibility - e.g. in your Explorer Sample/frmBasic. Nevertheless the method is never called. 
What's wrong? The declaration? Or is something missing to get the implemnt to work? 
(I didn't fully understand the related MSDN information for this interface as they talk about an additional implementation of IServiceProvider for the hosting class...)

----------


## deBUGer

How is it going with x64 support? I couldn't succeed even with x86 version build on my machine. Even with older tools versions. Could you please provide detailed HOWTO to build your TLB? I mean, environment, commands, etc.? It would be very helpful!

----------


## DEXWERX

> How is it going with x64 support? I couldn't succeed even with x86 version build on my machine. Even with older tools versions. Could you please provide detailed HOWTO to build your TLB? I mean, environment, commands, etc.? It would be very helpful!


x64 support  :EEK!:   :Confused: 

This typelib wasn't built with x64 in mind, the types are (painstakingly) hard coded to 32bit / VB6 so that it can be used in VB6.

Are you using this from MS Office (x64)?

----------


## deBUGer

> x64 support  
> 
> This typelib wasn't built with x64 in mind, the types are (painstakingly) hard coded to 32bit / VB6 so that it can be used in VB6.
> 
> Are you using this from MS Office (x64)?


Yes. Well, I don't need all the types, just very few of them - i.e. ITypeInfo, IDispatch, etc. These must have x64 bit support. But still - I get same errors even if I try to build this lib for x86. That's why I'm asking - how did you managed to do this?

----------


## DEXWERX

> Yes. Well, I don't need all the types, just very few of them - i.e. ITypeInfo, IDispatch, etc. These must have x64 bit support. But still - I get same errors even if I try to build this lib for x86. That's why I'm asking - how did you managed to do this?


modify mkex4.bat to point to your copy of mktyplib.exe

mine looks more like this.



```
REM C:\PROGRA~2\MIB055~1\VC98\Bin\MKTYPLIB.exe oleexp.odl
"C:\Program Files\Microsoft Visual Studio\Common\Tools\VB\typlib\mktyplib.exe" oleexp.odl
```

then run it. Or just run the full command from a console.


Now a question for you - What ODL type is used for pointers in VBA x64 ? 



fafalone might need to convert this to MIDL before supporting 64bit.
Last I checked he didn't know how to "redefine" built in types. 

In order to do that, you need to copy some of the base files like "unknwn.idl"
into the project directory so that those are included instead of the ones from the SDK/DDK folder.
Then you can modify the definitions in those files directly to get around MIDL's redefinition error.

Credit goes to Bruce McKinney for figuring that out (although he had help from MS). he created WinU.tlb 
My typelibs all use MIDL also.

An example of this: http://vb.mvps.org/hardweb/mckinney2a.htm



As for converting the interfaces and APIs to VBA x64 - it's ground seldom tread.
You are better off starting a typelib from scratch than using oleexp.tlb.
and then there's the issue of distributing your source - unless you replace all the MS code, you can't distribute it legally.

Bruce McKinney (and then the company who took over the typelib) worked out licensing with MS.

----------


## deBUGer

> modify mkex4.bat to point to your copy of mktyplib.exe
> 
> mine looks more like this.
> 
> 
> 
> ```
> REM C:\PROGRA~2\MIB055~1\VC98\Bin\MKTYPLIB.exe oleexp.odl
> "C:\Program Files\Microsoft Visual Studio\Common\Tools\VB\typlib\mktyplib.exe" oleexp.odl
> ...


Well, I have already tried that. I get 



```
Microsoft (R) Type Library Generator  Version 2.20.4230
Copyright (c) Microsoft Corp. 1993-1995.  All rights reserved.

fatal error M0006: unable to pre-process input file
```

--------------------

Finally I managed to compile it. The reason for M0006 was missing mspdb60.dll on my OS. Placing it next to cl.exe did the job. It builds now.

----------


## fafalone

Can you please clarify what you expect a 64-bit compilation to provide?

This TLB is exclusively for VB. The only 64-bit scenario is if you're using 64-bit VBA in MS Office. The TLB works as-is in 64-bit VBA; the vast majority of types aren't 64-bit types to begin with, in the event there is a LongLong etc other types substitute. Refer to this post earlier in this thread.

These aren't original interfaces; what differences exist between the original 32-bit and 64-bit versions? IIRC there aren't two separate versions or major differences in the SDK the original defs are copied from.

==
Building the normal x86 version is just a matter of using MKTYPLIB from the Visual Studio 6 install; as DEXWERX mentioned there's a compile shortcut you can just edit the path for. There's no setting changes from the default install.


===
My problem with compiling with MIDL is that MIDL.EXE simply does not work. Period. For anything. Either oaidl is missing, and absolutely nothing, even a blank typelib, will compile without it, some other file is missing, or there's errors in oaidl or another pre-existing dpend file, whether precompiled or not, no matter which SDK version it comes from, no matter which SDK version MIDL.EXE comes from. Just can't get it to work even for a 'hello world' empty typelib, not a problem specific to oleexp. Fresh install of new VS version, no help. Running vcvarsall that came with the fresh install, no help. Every permutation of options and versions all has some excuse or another for not compiling at all. 
It's extraordinarily frustrating, never in my life have I encountered a program so dedicated to not working.

----------


## MountainMan

the biggest difference is pointers. These obviously are 64-bit as opposed to 32-bit pointers in 32-bit windows. It's not just the returns from subs and the addresses of subs but also all handles. Microsoft says that to-date pointers are all of values that would fit in 32-bit variables even though addresses passed to/from function calls need the full 64 bits of space.

Here is what MSDN says regarding a call to the CopyFileEx function:

BOOL WINAPI CopyFileEx(
  _In_     LPCTSTR            lpExistingFileName,
  _In_     LPCTSTR            lpNewFileName,
  _In_opt_ LPPROGRESS_ROUTINE lpProgressRoutine,
  _In_opt_ LPVOID             lpData,
  _In_opt_ LPBOOL             pbCancel,
  _In_     DWORD              dwCopyFlags
);

5 of the 6 parameters are 64-bit pointers to variables and a pointer to a callback routine. If the tlb says these are 32-bit pointers to be on the stack like in VB6 and Office 64 is making a call that 64-bit Windows expects to have 5 64-bit pointers then bad things are going to happen.

----------


## fafalone

Forgive me for not being too familiar with this, but are you saying the 32-bit and 64-bit difference occurs in the same type? That on a 64-bit VBA a DWORD is no longer 4 bytes, instead of a new definition with an 8-byte variable?
How does the original source for declares like that handle things; is any change applied besides the 64-bit option for MIDL.exe?

If there's no changes and it's simply a compiler option, and someone can do that, I'd be happy to include the 64-bit version in the download, but honestly I've spent dozens of hours trying to compile _anything_ with midl.exe and aren't really up to risking my sanity to keep fighting with it myself. I mean it's telling me an unmodified file from the official MS SDK is so full of errors it can't compile just by itself, and not one of the countless solutions found from googling the errors has helped... I'm just a poor old school VB programmer who never grew up into the more advanced languages and dev tools so it's already a challenge  :Blush:

----------


## MountainMan

MS defines a DWord the same in 32 and 64-bit programs.  the difference is in pointers and handles. They even use the same words for handles and pointers but the compiler knows the difference. For example, in the previous example I posted a few minutes ago, I showed this:



```
BOOL WINAPI CopyFileEx(
_In_ LPCTSTR lpExistingFileName,
_In_ LPCTSTR lpNewFileName,
_In_opt_ LPPROGRESS_ROUTINE lpProgressRoutine,
_In_opt_ LPVOID lpData,
_In_opt_ LPBOOL pbCancel,
_In_ DWORD dwCopyFlags
);
```

LPCTSR lpExistingFileName is a pointer to the string holding the pathname of the file we want to copy. The "LP" in the name generally tells us that it is a pointer. In fact, it is is the equivalent of passing a parameter ByRef in VB6 or VBA since that passes the address on the stack instead of the actual variable itself. The compiler knows from switches that are set whether to treat the variable address as a 32 or 64-bit address.

My main exposure to the tlb-like world is via API Declare statements at the top of our code. Since in 32-bit VB or VBA there is no separate variable type for a handle, pointer or address everyone uses Long just like they do when they reference a DWord type which is our (VB) normal Long data type. That's fine in 32-bit but when we allow 64-bit then some of the Longs now have to become 64-bit instead of 32-bit. MS chose in 64-bit Office to cal this new variable type LongPtr and the compiler decides to make it 32 or 64 bit depending on whether the programmer is running 32 or 64-bit Office. So I don't know about type library code compilers but I am going to guess that the older ones that pre-date 64-bit OS's may not have a separate data type for handles, pointers and addresses but just show them as Longs. If so, then someone has a task to go back through the source and separate the DWords from the pointers and change all of the pointers to that new type (if there is one). I am hoping that this problem had come up in the shift from 16 to 32 bit and had been solved way back then but maybe not.

I'm certainly not a tlb wizard but I think the tlb info is static; I don't think it changes itself if it is being used in a 64 or 32-bit environment. I suppose it is possible for the type library file to adjust itself depending on whether the code is being compiled as a 32 or 64 bit program. My gut feel is that we need 2 separate type libraries and you make a reference to the appropriate one for whichever environment you are coding to.

----------


## deBUGer

> Can you please clarify what you expect a 64-bit compilation to provide?
> 
> This TLB is exclusively for VB. The only 64-bit scenario is if you're using 64-bit VBA in MS Office. The TLB works as-is in 64-bit VBA; the vast majority of types aren't 64-bit types to begin with, in the event there is a LongLong etc other types substitute.


Well, as you mentioned - I needed a few interfaces to be used in 64-bit VBA in MS Office. As other colleagues mentioned all the problems come from different pointers size. Namely, datastructure members and datapointers to data. It can be done by modifying ODL definitions. That's why I asked you to help with the build. Anyway, the problems with the build I had has been solved, so, no need to worry about that anymore.

Regarding using COM\OLE staff in Office VBA - it makes VBA programs bound to Windows platform. To support Office VBA on other platforms (like MAC) it's a very bad decision. So, I think it doesn't make much worth paying much attention to x64 bit COM\OLE staff. 

Thanks to everyone for your replies and thoughts!

----------


## fafalone

Well as mentioned when this first came up, in 64-bit VBA you can use a regular Long instead of LongPtr and the interfaces would work...

I'm still not entirely clear on the key point:
If you're using the interface natively, that is included from the original header/idl and not oleexp, are the arguments modified such that the ones expecting pointers now expect an 8-byte variable? Because recall the way things work, it matters, because if you change one argument to more bytes and it's not expected, then it breaks all the other arguments because there's no true separation.
To me it seems that if it *was* going to take 8-bytes in one argument that was previously 4, by the same principle you'd always have to pass 8 bytes or the rest of the alignment would be off too.

Honestly I think the first step here would be to find an API or interface in oleexp that does not work when called from 64-bit VBA. If one could be identified it would be a lot easier to figure things out.

----------


## DEXWERX

@fafalone I run midl from the "VS x86 Tools Command Prompt" shortcut that automatically runs vcvarsall.bat passing x86 as a parameter

----------


## Frank Tabacchi

(Sorry for my bad language i m from germany and i have no english in school)

Hallo i need a lot of help..... please

I create a Url process Action ..... in VB6 with webbrowser control.

In the debug mode it runs fine by these url www.web.de.....  
in executefile it crashes by these url www.web.de....

(a lot of other urls working fine)



i dont no whats wrong in the page ------ www.web.de ------ by execute or wrong in my code

i thing i make a lot of misstakes in my code or??????


thanks for your help


Implements oleexp.IInternetSecurityManager
Implements oleexpimp.IServiceProvider

Private SID_SProfferService As UUID
Private IID_IProfferService As UUID
Private IID_IInternetSecurityManager As UUID
Private ps As IProfferService
Private cookie As Long
Private sp As IServiceProvider

Public Function AddInternetSecurityManager() As Boolean

    CLSIDFromString SIDSTR_SProfferService, IID_IProfferService
    CLSIDFromString SIDSTR_SProfferService, SID_SProfferService
    CLSIDFromString IIDSTR_IInternetSecurityManager, IID_IInternetSecurityManager

    Set sp = wb.object
    sp.QueryService SID_SProfferService, IID_IProfferService, ps

    Call ps.ProfferService(IID_IInternetSecurityManager, Me)

End Function


Private Sub InternetSecurityManager_ProcessUrlAction(ByVal pwszUrl As Long, ByVal dwAction As oleexp.URLACTIONS, ByVal pPolicy As Long, ByVal cbPolicy As Long, pContext As Byte, ByVal cbContext As Long, ByVal dwFlags As oleexp.PUAF, ByVal dwReserved As Long)
Dim sURL  As String
Dim i     As Long
Dim B     As Boolean

  sURL = lpwstrPtrToString(pwszUrl)

  If dwAction = URLACTION_SCRIPT_MIN Then

    For i = 1 To ADS_SRC_COL.Count
      If InStrB(LCase(sURL), ADS_SRC_COL(i)) > 0 Then
        MoveMemory ByVal pPolicy, URLPOLICY_DISALLOW, 4&
        B = True
        Exit For
      End If
    Next i

    If B = False Then 'Call MoveMemory(ByVal pPolicy, URLPOLICY_ALLOW&, 4&)
      If RunningInIDE = False Then
        Err.Raise oleexp.HRESULTS.INET_E_DEFAULT_ACTION
      End If
    End If

  Else

   If RunningInIDE = False Then Err.Raise oleexp.HRESULTS.INET_E_DEFAULT_ACTION

  End If

End Sub


Private Sub IServiceProvider_QueryService(guidService As oleexp.UUID, riid As oleexp.UUID, ppvObject As Long)
Dim objUnknown As IUnknown
Dim lngResult As Long
Dim objISM As IInternetSecurityManager

  If GetStringFromGUID(guidService) = UCase(IIDSTR_IInternetSecurityManager) Then
    Set objUnknown = Me
    objUnknown.AddRef
    Set objISM = Me
    MoveMemory ppvObject, objISM, 4&

    Set objUnknown = Nothing
    Set objISM = Nothing

  Else
    If RunningInIDE = False Then Err.Raise oleexp.HRESULTS.E_NOINTERFACE
  End If

End Sub

----------


## Frank Tabacchi

Hallo from Germany,

I need help ....

in debug mode it runs by these side --- www.web.de --- perfect...

in execute it crashes i dont no why... 

I test it with vbMHWB control                             crash project.exe (run in debug mode)
I test it with WB control        olelib /   olelib2       crash project.exe (run in debug mode)
and now with WB control      oleexp / oleexpimp  crash project.exe (run in debug mode)


please can any one help me to solve this problem?

Other sides run in debug mode and in execute mode perfect

I use vb6 SP6

here is the code... i do for testing



Regards Frank Tabacchi


Implements oleexp.InternetSecurityManager
Implements oleexpimp.IServiceProvider

Private SID_SProfferService As UUID
Private IID_IProfferService As UUID
Private IID_IInternetSecurityManager As UUID
Private ps As IProfferService
Private cookie As Long
Private sp As IServiceProvider

Private Sub Form_Load()

    CLSIDFromString SIDSTR_SProfferService, IID_IProfferService
    CLSIDFromString SIDSTR_SProfferService, SID_SProfferService
    CLSIDFromString IIDSTR_IInternetSecurityManager, IID_IInternetSecurityManager

    Set sp = wbBrowser.object

    DoEvents

    sp.QueryService SID_SProfferService, IID_IProfferService, ps

    DoEvents

    cookie = ps.ProfferService(IID_IInternetSecurityManager, Me)

    wbBrowser.Silent = False

    wbBrowser.Navigate "http://www.web.de"


End Sub

Private Sub Form_Unload(Cancel As Integer)
    If cookie <> 0 Then
        ps.RevokeService cookie
    End If
End Sub

Public Function GetStringFromGUID(X As UUID) As String
    Dim s As String
    Dim L As Long
    s = String(100, 0)
    L = StringFromGUID2(X, s, Len(s))
    GetStringFromGUID = UCase(Left(s, L - 1))
End Function

Private Function lpwstrPtrToString(ByVal lpwstrPtr As Long) As String
    Dim lSize As Long
    If lpwstrPtr <> 0 Then
        lSize = lstrlenW(ByVal lpwstrPtr)
        If lSize > 0 Then
            ReDim b(0 To (lSize * 2) - 1) As Byte
            MoveMemory b(0), ByVal lpwstrPtr, lSize * 2
            lpwstrPtrToString = b
        End If
    End If
End Function

Private Function RunningInIDE() As Boolean
On Error Resume Next
  Debug.Print 1 / 0
  RunningInIDE = (Err <> 0)
End Function

Private Sub InternetSecurityManager_GetSecurityId(ByVal pwszUrl As Long, ByVal pbSecurityId As Long, pcbSecurityId As Long, ByVal dwReserved As Long)
If RunningInIDE = False Then Err.Raise oleexp.HRESULTS.INET_E_DEFAULT_ACTION
End Sub

Private Function InternetSecurityManager_GetSecuritySite() As oleexp.IInternetSecurityMgrSite
If RunningInIDE = False Then Err.Raise oleexp.HRESULTS.INET_E_DEFAULT_ACTION
End Function

Private Sub InternetSecurityManager_GetZoneMappings(ByVal dwZone As Long, ppenumString As oleexp.IEnumString, ByVal dwFlags As Long)
If RunningInIDE = False Then Err.Raise oleexp.HRESULTS.INET_E_DEFAULT_ACTION
End Sub

Private Sub InternetSecurityManager_MapUrlToZone(ByVal pwszUrl As Long, pdwZone As Long, ByVal dwFlags As Long)
If RunningInIDE = False Then Err.Raise oleexp.HRESULTS.INET_E_DEFAULT_ACTION
End Sub

Private Sub InternetSecurityManager_ProcessUrlAction(ByVal pwszUrl As Long, ByVal dwAction As oleexp.URLACTIONS, ByVal pPolicy As Long, ByVal cbPolicy As Long, pContext As Byte, ByVal cbContext As Long, ByVal dwFlags As oleexp.PUAF, ByVal dwReserved As Long)
If RunningInIDE = False Then Err.Raise oleexp.HRESULTS.INET_E_DEFAULT_ACTION
End Sub

Private Sub InternetSecurityManager_QueryCustomPolicy(ByVal pwszUrl As Long, guidKey As oleexp.UUID, ppPolicy As Long, pcbPolicy As Long, pContext As Byte, ByVal cbContext As Long, Optional ByVal dwReserved As Long = 0&)
If RunningInIDE = False Then Err.Raise oleexp.HRESULTS.INET_E_DEFAULT_ACTION
End Sub

Private Sub InternetSecurityManager_SetSecuritySite(ByVal pSite As oleexp.IInternetSecurityMgrSite)
If RunningInIDE = False Then Err.Raise oleexp.HRESULTS.INET_E_DEFAULT_ACTION
End Sub

Private Sub InternetSecurityManager_SetZoneMapping(ByVal dwZone As Long, ByVal lpszPattern As Long, ByVal dwFlags As oleexp.SZM_FLAGS)
If RunningInIDE = False Then Err.Raise oleexp.HRESULTS.INET_E_DEFAULT_ACTION
End Sub

Private Sub IServiceProvider_QueryService(guidService As oleexp.UUID, riid As oleexp.UUID, ppvObject As Long)
Dim objUnknown As oleexp.IUnknown
Dim lngResult As Long
Dim objISM As InternetSecurityManager

  If GetStringFromGUID(guidService) = UCase(IIDSTR_IInternetSecurityManager) Then
    Set objUnknown = Me
    objUnknown.AddRef
    Set objISM = Me
    MoveMemory ppvObject, objISM, 4&
  Else
    If RunningInIDE = False Then Err.Raise oleexp.HRESULTS.INET_E_DEFAULT_ACTION
  End If

End Sub

----------


## fafalone

I'm unable to replicate the problem; the compiled EXE does not crash on my system, Win7, although web.de does throw 100 javascript error messages at me in both IDE and EXE. What version of Windows are you on? Or do I need to do more than just run the code to trigger the crash? Or other references/module and in what order?

Can you identify the line or at least procedure where it crashes? It's hard to locate the problem since IDE vs EXE issues aren't clearly visible errors; they're generally caused by the difference in memory handling.

I can identify a couple considerations however... you're returning entirely different values for RunningInIDE=False. Err.Raise, in some but not all COM interfaces, gets reported back as the HRESULT, so you're essentially returning S_OK (0) in the IDE and INET_E_DEFAULT_ACTION (0x800C0011) in the EXE, in a lot of subs.

----
PS- Please enclose code in tags: [CODE]'code here[/CODE]

----------


## Frank Tabacchi

Hallo again,

thanks for answer here... i had a attachment where the crash starts


Unfortunately, I'm not as deep in the topic as you

So I can not find a solution without your help here

Thanks again fore your help....


reguards Frank

----------


## fafalone

What do I need to do to trigger a crash? I ran the exe, and also compiled it again, and clicked the button, it did not crash either time:


I tested in Windows 8.1 as well, it did not crash then either.
----
Is this what you mean:


???

I get that in the IDE too but it's an issue with the browser control, not with VB code.

----------


## Frank Tabacchi

Hallo again,

My system is Win7 home premium SP1 / (IE11) and VB6 SP6

it is crazy... in my system the execute file is crashed...

TEST:  I open the project.exe file and then i click the test button Web.de and then Win7 show 
          a msgbox the project1 is not functional  do you want to send the problem to mircosoft......

By click the button i dont get any script errors and i dont see the webside on my screen i get the system (win7) message immediately 
and then good by project1.exe but in debug mode it runs i dont no wat is going on, have you any idee or a sample that working in Win7?

I get this crash in Win XP / Win Vista and in Win7 (IE 11) all systems are german.

Help I'm too stupid to understand that... by test with the vbMHWB control (from www.codeproject.com) it is the same problem!
And they are more professional than me but it is crash to and ohter side are working.....


Can it be, that the crash coming because the site checks if jawascrict is active and that causes the crash?
Is this a zone security problem with german Windows (IE 9 10 11)?

When I comment out the code lines then the Webbrowser control working fine with the side but when i implements the function
then it crashed in execute mode.

this was killing me i testing a long time to solve this problem but i am have not any idee and any solution fore this...

that makes me sick.


Thanks for all writing and helping hands


Frank

----------


## fafalone

Can you describe your security settings? I changed my Internet Options control panel Internet zone to High with no change. Is JavaScript active for you? I could not locate the setting to change it (I don't use IE). I'm on Win7 as well and your code works for me, so I'm going to need to replicate the settings on your system that lead to the crash, but first, we can narrow down where the problem lies:
Please compile and run the ZIP I'm attaching. I have modified your project to log detailed debug information. After, please attach the resulting log file to your reply. I'm also attaching the output from when I run it in case you want to compare it yourself. One thing I've noticed; you know you're zeroing out security id and zone values that weren't zero right? Just wanted to make sure you intended to change them.

----------


## AAraya

Any problems with using both this and the standard OLE Automation (stdole2.dll) reference that is set by default on any new project?

----------


## fafalone

No, there's no conflict, except that it has a couple hidden members, so you need to specify oleexp.IUknown and oleexp.IDispatch if you're using those... IIRC it's only those two, but in any case definitely not any of the knownfolder stuff.

----------


## The trick

Hi fafalone. Please fix *ITransferSource* interface.
Thank for advance.

----------


## fafalone

Oh wow that's a bad one. I'll have the update out by tonight. Sorry about that.

----------


## fafalone

Update released with fix and completed new things.

Take note of a change to IContextMenu as it's very commonly used:



> -IContextMenu and IContextMenu2: .InvokeCommand has been changed to a Long, so that both CMINVOKECOMMANDINFO and CMINVOKECOMMANDINFOEX can be used. Use VarPtr(yourcommandinfovar) instead of just yourcommandinfovar.



------------------------
TheTrick - I'd be very interested to see ITransferSource in action in VB; if possible, share code of it being used if you use it?

----------


## SaschaT

Thanks for the new version!

I just wanted to mention that not all methods of *KnownFolderManager* can be called. I tried to retreive a list of registered known folders using *GetFolderIds* but the type definition for this method is not compatible with VB6, so it refused to compile.
So I changed the definition in *exp_main.odl* like this:


```
//    HRESULT GetFolderIds(
//        [out] KNOWNFOLDERID ** ppKFId,
//        [in, out] UINT *pCount);

    HRESULT GetFolderIds(
        [out] UINT *ppKFId,
        [in, out] UINT *pCount);
```

Now we are able to get the list using this demo snippet:


```
Sub TestKnownFolders()
    Dim oMngr As oleexp.KnownFolderManager
    Dim IFld As oleexp.IKnownFolder
    Dim uid() As oleexp.UUID
    Dim lUIDs As Long
    Dim sGUID As String, sPath As String
    Dim ret As Long, n As Long, i As Long
    Dim lPath As Long, cnt As Long
    
    Set oMngr = New oleexp.KnownFolderManager
    oMngr.GetFolderIds lUIDs, n
    If n > 0 Then
        ReDim uid(n - 1)
        For i = 0 To n - 1
            oleexp.MoveMemory uid(i), ByVal (lUIDs + (i * 16)), 16&
            sGUID = String(255, 0)
            ret = oleexp.StringFromGUID2(uid(i), sGUID, 255)
            If ret > 0 Then
                sGUID = Left(sGUID, ret)
                Set IFld = Nothing
                oMngr.GetFolder uid(i), IFld
                If Not IFld Is Nothing Then
                    On Error Resume Next
                    IFld.GetPath KF_FLAG_DEFAULT_PATH, lPath
                    On Error GoTo 0
                    If lPath <> 0 Then
                        cnt = cnt + 1
                        sPath = SysAllocString(lPath)
                        CoTaskMemFree lPath
                        Debug.Print cnt, sGUID, sPath
                    End If
                End If
            End If
        Next i
    End If
End Sub
```

----------


## fafalone

Thanks for pointing that out, the fix will  be included in the next release.

Note too you can copy all the IDs at once, saving MoveMemory calls,


```
Dim ct As Long
Dim tpkd As KnownFolderManager
Set tpkd = New KnownFolderManager
Dim kfptr As Long
Dim arfldr() As UUID


tpkd.GetFolderIds kfptr, ct
ReDim arfldr(ct - 1)
CopyMemory arfldr(0), ByVal kfptr, Len(arfldr(0)) * ct
```

----------


## voxy

*Retrieving Portable Device Shell Icons*

Hey fafalone, oleexp.tlb works just fine for enumerating Portable Devices, thanks a lot for that!

This line retrieves an array of pointers to Device IDs:


```
ret = MyPortableDeviceManager.GetDevices(ByVal VarPtr(pPnpDeviceIDs(0)), cPnPDeviceIDs)
```

Walking the array I turn the pointers into strings, the so-called "PNP Device IDs":


```
  For i = 0 To cPnPDeviceIDs - 1
    sPnpDeviceID(i) = PointerToStringW(pPnpDeviceIDs(i))
  Next
```

Such a "PNP Device ID" looks for example like this:


```
\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33}
```

I can retrieve the display name (e.g. "Moto G (4)" or "Nexus 10") like this:  


```
ret = MyPortableDeviceManager.GetDeviceDescription(sPnpDeviceID(i), VarPtr(bBuffer(0)), lenBuffer)
```

But how to retrieve the shell icon (the icon displayed in File Explorer)??? The 
Portable Device API does not seem to provide anything here, at least I don't see 
it.

Now in Win8.1 and earlier there is a way to retrieve the icon and some other 
shell info using SHGetFileInfoW with a pidl (it does not work with a string, 
only with pidl):


```
Call SHGetFileInfoW(pidlItem, 0&, sfiW, Len(sfiW), _
      SHGFI_PIDL Or SHGFI_SYSICONINDEX Or SHGFI_TYPENAME Or SHGFI_DISPLAYNAME)
```

The desired icon is here now:


```
sfiW.iIcon
```

I can retrieve the needed pidl using SHParseDisplayName on the "PNP Device ID" 
(prefixed with the This PC GUID "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" and 
one backslash):


```
sPnpDeviceID(i) = "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" & "\" & sPnpDeviceID(i)
  ret = SHParseDisplayName(StrPtr(sPnpDeviceID(i)), ByVal 0&, pidlItem, ByVal 0&, ByVal 0&)
```

Now the problem is: *Retrieving that pidl stopped working with Windows 10 version 
1703 (Creators Update) and later!* I found no way to turn that "PNP Device ID" 
into a pidl. BTW, I think that is a Windows bug and reported it to MS a year 
ago, but never got any reply or fix.

So, how can I get my shell icon now in all Windows versions?

Thanks,
Don

----------


## fafalone

Can you create an IShellItem? SHCreateItemFromParsingName. If it's visible with an icon in Explorer (and more importantly, check to see if my shell browser shows its icon), you should be able to get one. The first method my browser tries doesn't go through SHGetFileInfo (that's a fallback), it first tries getting the IShellIcon interface, and in the process gets pidls in a different way...


```
Dim uPI As IParentAndItem
Dim psf As IShellFolder
Dim pIcon As IShellIcon
Dim pidlPar As Long, pidlRel As Long
Dim lpIcon As Long
Dim hr As Long
'[...]

                    Set uPI = siChild 'Your IShellItem 
                    uPI.GetParentAndItem pidlPar, psf, pidlRel
                    On Error Resume Next
                    If (psf Is Nothing) = False Then
                        Set pUnk = psf
                        hr = pUnk.QueryInterface(IID_IShellIcon, pIcon)
'                        DebugAppend "QueryInterface=0x" & Hex$(hr)
                        If hr = S_OK Then
                            pIcon.GetIconOf pidlRel, GIL_FORSHELL, lpIcon
                        Else
                          Dim pidlcb As Long
                          pidlcb = ILCombine(pidlPar, pidlRel)
                          lpIcon = GetFileIconIndexPIDL(pidlcb, SHGFI_SMALLICON)
                        End If
                        If lpIcon = -1 Then lpIcon = 0
                    End If
```

If Explorer shows the icon, that will almost certainly work. Worst case scenario, you could enumerate the Computer folder and match it. 
If Explorer doesn't, you're left with manually doing it. The documentation indicates there might be a DevIcon.fil file in the device root, which is a standard icon file you can load. Or, use the device resource key WPD_RESOURCE_ICON. If both of those fail, query for the generic type (WPD_DEVICE_TYPE), and load the default icon for that type. 

(If 'all Windows versions' means even XP or earlier, the interface methods won't work)

----------


## voxy

> Can you create an IShellItem? SHCreateItemFromParsingName.


No, SHCreateItemFromParsingName fails with 0x80070057 (E_INVALIDARG).
It's the same error as SHParseDisplayName returns when trying to get the pidl.

So I think something about the PNP Device ID might be wrong.

The pidl is correctly returned for this path (it's the PNP Device ID of "Moto G (4)"):
::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33}

But it fails with E_INVALIDARG for the 2 subfolders of "Moto G (4)":
::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{C8DB0001,,63831015424}
::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,,58525089792}

In Win8.1 these paths are no problem.

----------


## voxy

> ... and more importantly, check to see if my shell browser shows its icon...


I ran your ucShellBrowse41 project both in Win8.1 and in Win10, each time using my Moto G phone as device to be browsed. Below you see the debug output. To me it looks like your project met exactly the same problem that made me post here: *"No IShellItem"* So your shell browser cannot browse those folders in Win10 (but it can in Win8.1).
What's happening there? Windows bug? Can it be worked around?



```
Win 8.1
~~~~~~~

Select device "Moto G (4)" in your Tree:
[20:49:53] CBD->SelChange
[20:49:53] DirNavigate item=9,sup=Falsch
[20:49:53] LVLoadFolder ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33},m_sCurPath=C:\Users\Donald\Desktop\Desk\ucShellBrowse41\Demo,sPrevPath=,GrpMode=0
[20:49:53] PathAttrib=SFGAO_CANLINK,SFGAO_CANRENAME,SFGAO_FOLDER,SFGAO_HASPROPSHEET,SFGAO_HASSUBFOLDER,SFGAO_STORAGEANCESTOR,
[20:49:53] ProcessColumns pathidx=9
[20:49:53] ub=37last=C:\Users\Donald\Desktop\Desk\ucShellBrowse41\Demo,cur=::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33}
[20:49:53] MyComp::Get ShellView
[20:49:53] MyComp::Get FolderView
[20:49:53] Got colmgt,ct=4
[20:49:53] NameLookup=System.ItemNameDisplay
[20:49:53] NameLookup=System.ItemTypeText
[20:49:53] NameLookup=System.Size
[20:49:53] NameLookup=System.FreeSpace
[20:49:53] SetColumns(9)=
[20:49:53] SetColumns->Finished reconcile
[20:49:53] SetColumns->Remove System.DateModified
[20:49:53] InsertListColumn System.FreeSpace
[20:49:53] excol defwidth=160
DirChange ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33}
[20:49:53] idxCB=9,lp=9
[20:49:53] pvCreateDetailPaneBkg.pidlPar=114425896,pidlrel=113577680
[20:49:53] pbh=56
[20:49:53] btm=56,cx=58,icn=58,sys=32
[20:49:53] Draw from JM
[20:49:53] Loaded 0 files and 2 folders
[20:49:53] MonitorPidl=116732936 ForPath=::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33}

Select subfolder of device:
[20:50:38] Set IC flag = TRUE, item=0
[20:50:38] LVSetSelection full path=::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,,58525089792}
[20:50:38] pvCreateItemDetailPane()
[20:50:38] ucWndProc->Error: Typen unverträglich, 0xD
[20:50:38] LVItemClick 0
[20:50:38] InfoTip Cnt=2
[20:50:38] PropsList=prop:System.FreeSpace;System.Capacity
[20:50:38] Prop=Freier Speicherplatz: 46,6 GB
[20:50:38] Prop=Gesamtgröße: 54,5 GB

Dbl-click subfolder of device:
[20:52:37] Got dblclk/ret
[20:52:37] LVSetSelection full path=::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,,58525089792}
[20:52:37] LVDoubleClick idx=0,lp=1,file=Interner gemeinsamer Speicher
[20:52:37] LVDoubleClick.OpenFolder
[20:52:37] LVLoadFolder ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,,58525089792},m_sCurPath=::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33},sPrevPath=::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,,58525089792},GrpMode=0
[20:52:37] PathAttrib=SFGAO_FOLDER,SFGAO_HASPROPSHEET,SFGAO_HASSUBFOLDER,SFGAO_STORAGE,SFGAO_STORAGEANCESTOR,
[20:52:37] ProcessColumns pathidx=38
[20:52:37] ub=38last=::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,,58525089792},cur=::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,,58525089792}
[20:52:37] MyComp::Get ShellView
[20:52:37] MyComp::Get FolderView
[20:52:37] Got colmgt,ct=8
[20:52:37] NameLookup=System.ItemNameDisplay
[20:52:37] NameLookup=System.ItemTypeText
[20:52:37] NameLookup=System.Size
[20:52:37] NameLookup=System.Music.TrackNumber
[20:52:37] NameLookup=System.Music.Artist
[20:52:37] NameLookup=System.Music.AlbumTitle
[20:52:37] NameLookup=System.Media.Year
[20:52:37] NameLookup=
[20:52:37] No match, pkey={9E5E05AC-1936-4A75-94F7-4704B8B01923, 6}
[20:52:37] NameLookup=
[20:52:37] No match, pkey={9E5E05AC-1936-4A75-94F7-4704B8B01923, 13}
[20:52:37] NameLookup=
[20:52:37] No match, pkey={9E5E05AC-1936-4A75-94F7-4704B8B01923, 14}
[20:52:37] NameLookup=
[20:52:37] SetColumns(38)=
[20:52:37] SetColumns->Finished reconcile
[20:52:37] SetColumns->Remove System.FreeSpace
[20:52:37] InsertListColumn System.Media.Year
[20:52:37] excol defwidth=80
[20:52:37] InsertListColumn System.Music.AlbumTitle
[20:52:37] excol defwidth=136
[20:52:37] InsertListColumn System.Music.Artist
[20:52:37] excol defwidth=120
[20:52:37] InsertListColumn System.Music.TrackNumber
[20:52:37] excol defwidth=40
DirChange ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,,58525089792}
[20:52:37] idxCB=10,lp=38
[20:52:37] pvCreateDetailPaneBkg.Error->Typen unverträglich, 0xD
[20:52:37] Loaded 0 files and 15 folders
[20:52:37] MonitorPidl=123149952 ForPath=::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,,58525089792}
[20:52:41] terminate event

========================================================================
Win 10
~~~~~~

Select device "Moto G (4)" in your Tree:
[20:57:45] CBD->SelChange
[20:57:45] DirNavigate item=9,sup=Falsch
[20:57:45] LVLoadFolder ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33},m_sCurPath=::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33},sPrevPath=C:\Users\Public\ucShellBrowse41\Demo,GrpMode=0
[20:57:46] PathAttrib=SFGAO_CANLINK,SFGAO_CANRENAME,SFGAO_FOLDER,SFGAO_HASPROPSHEET,SFGAO_HASSUBFOLDER,SFGAO_STORAGEANCESTOR,
[20:57:46] ProcessColumns pathidx=9
[20:57:46] ub=21last=C:\Users\Public\ucShellBrowse41\Demo,cur=::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33}
[20:57:46] MyComp::Get ShellView
[20:57:46] MyComp::Get FolderView
[20:57:46] Got colmgt,ct=4
[20:57:46] NameLookup=System.ItemNameDisplay
[20:57:46] NameLookup=System.ItemTypeText
[20:57:46] NameLookup=System.Size
[20:57:46] NameLookup=System.FreeSpace
[20:57:46] SetColumns(9)=
[20:57:46] SetColumns->Finished reconcile
[20:57:46] ucShellBrowse.SetColumns->Error: Objektvariable oder With-Blockvariable nicht festgelegt, 0x5B
DirChange ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33}
[20:57:46] idxCB=9,lp=9
[20:57:46] pvCreateDetailPaneBkg.pidlPar=122406272,pidlrel=121952800
[20:57:46] pbh=56
[20:57:46] btm=56,cx=58,icn=58,sys=32
[20:57:46] Draw from JM
[20:57:46] Loaded 0 files and 2 folders
[20:57:46] MonitorPidl=139257568 ForPath=::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33}

Select subfolder of device:
[20:55:37] Set IC flag = TRUE, item=0
[20:55:37] LVSetSelection->Error: Objektvariable oder With-Blockvariable nicht festgelegt, 0x5B
[20:55:37] pvCreateItemDetailPane()
[20:55:37] LVItemClick 0
[20:55:38] No IShellItem

Dbl-click subfolder of device:
[20:56:36] Got dblclk/ret
[20:56:36] LVSetSelection->Error: Objektvariable oder With-Blockvariable nicht festgelegt, 0x5B
[20:56:36] LVDoubleClick idx=0,lp=1,file=Interner gemeinsamer Speicher
[20:56:36] LVDoubleClick->Failed to get IShellItem from parsing name
[20:56:36] No IShellItem
```

----------


## fafalone

I thought the issue was the device icon? Does the device icon show? It should, since that output looks like the device is present in the Computer folder and the dropdown. It looks like the problem is just with subfolders; do their icons show when you navigate to the device root?
Wondering because if the root works ok, can we work around by using resolving with an IShellFolder always for the root and an relative pidl from there. 
If it's working in Win8.1, it definitely sounds like a bug in the APIs though. Just one other thought... what about passing the display names 'Internet...' instead of 'SID-...' after the root? 

I'll check it out myself in a bit, it's a cell phone or tablet right? Connected mine (also Android) as both file transfer and camera and could go as deep as I wanted without issue on Win7 too; I'll have to check on my roomies Win10 laptop later.

----------


## voxy

> I thought the issue was the device icon? Does the device icon show? It should, since that output looks like the device is present in the Computer folder and the dropdown. It looks like the problem is just with subfolders; do their icons show when you navigate to the device root?
> Wondering because if the root works ok, can we work around by using resolving with an IShellFolder always for the root and an relative pidl from there. 
> If it's working in Win8.1, it definitely sounds like a bug in the APIs though. Just one other thought... what about passing the display names 'Internet...' instead of 'SID-...' after the root? 
> 
> I'll check it out myself in a bit, it's a cell phone or tablet right? Connected mine (also Android) as both file transfer and camera and could go as deep as I wanted without issue on Win7 too; I'll have to check on my roomies Win10 laptop later.


I need the pidl for the icon and also for other things, my post was indead misleading here, sorry.

Yes, in your browser the device icon shows, and also the icons in the next sub level. But then it does not go down any deeper.

> Just one other thought... what about passing the display names 'Internet...' instead of 'SID-...' after the root? 
I don't know what inspired you to this but it's exactly what I found out yesterday night by a mixture of internet and conincidence. It looks promising! I'll report back later...

BTW, although I subscribed to the topic I never get email notifications from this forum. Is this normal?

----------


## voxy

Problem solved!

Display path:


```
Moto G (4)\SD-Karte von SanDisk\Test\IMG_0001.JPG
```

This device path works in Win10 (but not in Win8.1):


```
::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SD-Karte von SanDisk\Test\IMG_0001.JPG
```

This device path works in Win8.1 (but not in Win10):


```
::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy223nmx76#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{C8DB0001,,63831015424}\{00000CAE-0001-C8DB-0000-000000000000}\{00000CB1-0001-C8DB-0000-000000000000}
```

So the workaround of this apparent Windows 10 bug is a simple string replacement.

Thanks for your help and your invaluable typelib!

Don

----------


## fafalone

Glad it worked out. I'll have to exceptions to handle this all over now too  :Mad: 
Had the idea because of a vaguely similar issue with recycle bin files a while back; can't recall the specifics. 

PS- For notifications, is the master option to receive e-mails enabled?

----------


## ChenLin

Excuse me, why can't you reference it in VB.NET? Is it my way?

----------


## voxy

@fafalone:

MSDN for *IPortableDeviceManager::GetDevices* says on *pPnPDeviceIDs*: "To learn the required size for this parameter, first call this method with this parameter set to NULL and pcPnPDeviceIDs set to zero".

I think I have to pass 0& ByVal, right?


```
ret = MyPortableDeviceManager.GetDevices(ByVal 0&, cPnPDeviceIDs)
```

Or should it be like this:


```
ret = MyPortableDeviceManager.GetDevices(0&, cPnPDeviceIDs)
```

Thanks,
Don

----------


## fafalone

@voxy That parameter is ByVal so it wouldn't matter either way. 



```
interface IPortableDeviceManager : stdole.IUnknown {
    long GetDevices(
                    [in] long pPnPDeviceIDs, 
                    [in] long *pcPnPDeviceIDs);
```

@ChenLin, you can't reference the TLB in .NET? Is it this specific typelib or all the typelibs specifically designed for VB6? I don't have time to try running code right now but I did add the TLB as a reference without error in a VB.NET project in VS2015... I'll try to run some code with it tonight.

----------


## voxy

> @voxy That parameter is ByVal so it wouldn't matter either way.


It does not look ByVal in the definition (OLEEXP - olelib With Modern Interfaces by fafalone, v4.43):


```
Function GetDevices(pPnPDeviceIDs As Long, pcPnPDeviceIDs As Long) As Long
```

----------


## voxy

OK, just saw that apparently function parameters in typelibs never show "ByVal" even if they are ByVal. So one cannot know what they are, ByVal or ByRef, without looking into the source code of the typelib?

----------


## ChenLin

“The system can't find a specified reference“

Can be added to a reference but not working properly.
Both VB 2005 and 2017 show this error. Is it my WINDOWS system problem?

----------


## fafalone

@voxy, that's unfortunately true. Sometimes there's clues in the naming conventions; and as a general rule, almost always the convention oleexp uses is to replace ByRef's for strings with ByVal and string pointers, for Unicode purposes, which is why the naming convention is broken here (it's byref in the original source as is the convention for vars prefixed with 'p'). 

@ChenLin, so not when you add the TLB but when you try to run the code? Are you calling an interface not available on the current version of Windows?

----------


## ChenLin

@fafalone,Change the computer test to confirm that there is no problem, it is the computer windows system problem.

----------


## ChenLin

It's wrong. The 3.7 edition was just tested, and 4.443 is still not acceptable.

----------


## fafalone

Of the typelib?

Can you be more specific about what exactly the error message is and when it appears?

The only difference between 3.7 and 4.43 are added interfaces/types; there haven't been any changes to the TLB structure itself since long before that.

----------


## ChenLin

Please look at the picture。

Debug error prompt:
Severity	Code	Description	Project	File	Line	Suppression State
Error		Could not resolve COM reference "f9015e81-caac-45c0-94e8-42b7da5d7557" version 4.43. The type library importer encountered an error during type verification. Try importing without class members.

----------


## fafalone

It looks like the file is in a different location than its registered to. Perhaps try unregistering then reregistering? This problem could arise if earlier 4.x versions in a different location were ever used.

----------


## Dragokas

Hi, fafalone!

Do you know why IDE time-by-time can point me this error by pressing Ctrl+F5:



```
Static iid As UUID
```




> "Compile error:
> Fixed or static data can't be larger than 64K"


in mIID.bas

(after close / re-open whole project the problem disappears)

----------


## Dragokas

fafalone, can I ask you please about adding the following missed FOLDER IDs to your mIID.bas? :




> FOLDERID_AccountPictures
> GUID	{008ca0b1-55b4-4c56-b8a8-4de4b299d3be}
> 
> FOLDERID_AppDataDesktop
> GUID	{B2C5E279-7ADD-439F-B28C-C41FE1BBF672}
> 
> FOLDERID_ApplicationShortcuts
> GUID	{A3918781-E5F2-4890-B3D9-A7E54332328C}
> 
> ...


https://docs.microsoft.com/en-us/win.../knownfolderid

There was also some IDs from Win10 version 1709, but I didn't list them because I think they are useless since they marked as:



> This FOLDERID is used internally by .NET applications to enable cross-platform app functionality. It is not intended to be used directly from an application.

----------


## fafalone

I'm not sure about that error with static data; haven't encountered it before myself. My first thought would be a potential problem with referencing too many at once... is it happening in a project where you're using a whole lot of them? It would have to really be a lot some of my bigger projects use a few dozen of them. 

FOLDERIDs Added; will be in next release. Give me a couple days, going to add the interface set you mentioned, a couple shell extention service interfaces I missed, and was going to look at possibly adding the ITbS.. remote desktop services and virtual disk services.

If you want to copy/paste for now I already ran them through my IID function builder:


```
Public Function FOLDERID_AccountPictures() As UUID
'{008ca0b1-55b4-4c56-b8a8-4de4b299d3be}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H008ca0b1, CInt(&H55b4), CInt(&H4c56), &Hb8, &Ha8, &H4d, &He4, &Hb2, &H99, &Hd3, &Hbe)
FOLDERID_AccountPictures = iid
End Function
Public Function FOLDERID_AppDataDesktop() As UUID
'{B2C5E279-7ADD-439F-B28C-C41FE1BBF672}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &HB2C5E279, CInt(&H7ADD), CInt(&H439F), &HB2, &H8C, &HC4, &H1F, &HE1, &HBB, &HF6, &H72)
FOLDERID_AppDataDesktop = iid
End Function
Public Function FOLDERID_ApplicationShortcuts() As UUID
'{A3918781-E5F2-4890-B3D9-A7E54332328C}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &HA3918781, CInt(&HE5F2), CInt(&H4890), &HB3, &HD9, &HA7, &HE5, &H43, &H32, &H32, &H8C)
FOLDERID_ApplicationShortcuts = iid
End Function
Public Function FOLDERID_AppsFolder() As UUID
'{1e87508d-89c2-42f0-8a7e-645a0f50ca58}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H1e87508d, CInt(&H89c2), CInt(&H42f0), &H8a, &H7e, &H64, &H5a, &H0f, &H50, &Hca, &H58)
FOLDERID_AppsFolder = iid
End Function
Public Function FOLDERID_CameraRoll() As UUID
'{AB5FB87B-7CE2-4F83-915D-550846C9537B}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &HAB5FB87B, CInt(&H7CE2), CInt(&H4F83), &H91, &H5D, &H55, &H08, &H46, &HC9, &H53, &H7B)
FOLDERID_CameraRoll = iid
End Function
Public Function FOLDERID_DeviceMetadataStore() As UUID
'{5CE4A5E9-E4EB-479D-B89F-130C02886155}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H5CE4A5E9, CInt(&HE4EB), CInt(&H479D), &HB8, &H9F, &H13, &H0C, &H02, &H88, &H61, &H55)
FOLDERID_DeviceMetadataStore = iid
End Function
Public Function FOLDERID_DocumentsLibrary() As UUID
'{7B0DB17D-9CD2-4A93-9733-46CC89022E7C}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H7B0DB17D, CInt(&H9CD2), CInt(&H4A93), &H97, &H33, &H46, &HCC, &H89, &H02, &H2E, &H7C)
FOLDERID_DocumentsLibrary = iid
End Function
Public Function FOLDERID_HomeGroupCurrentUser() As UUID
'{9B74B6A3-0DFD-4f11-9E78-5F7800F2E772}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H9B74B6A3, CInt(&H0DFD), CInt(&H4f11), &H9E, &H78, &H5F, &H78, &H00, &HF2, &HE7, &H72)
FOLDERID_HomeGroupCurrentUser = iid
End Function
Public Function FOLDERID_ImplicitAppShortcuts() As UUID
'{BCB5256F-79F6-4CEE-B725-DC34E402FD46}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &HBCB5256F, CInt(&H79F6), CInt(&H4CEE), &HB7, &H25, &HDC, &H34, &HE4, &H02, &HFD, &H46)
FOLDERID_ImplicitAppShortcuts = iid
End Function
Public Function FOLDERID_Libraries() As UUID
'{1B3EA5DC-B587-4786-B4EF-BD1DC332AEAE}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H1B3EA5DC, CInt(&HB587), CInt(&H4786), &HB4, &HEF, &HBD, &H1D, &HC3, &H32, &HAE, &HAE)
FOLDERID_Libraries = iid
End Function
Public Function FOLDERID_MusicLibrary() As UUID
'{2112AB0A-C86A-4FFE-A368-0DE96E47012E}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H2112AB0A, CInt(&HC86A), CInt(&H4FFE), &HA3, &H68, &H0D, &HE9, &H6E, &H47, &H01, &H2E)
FOLDERID_MusicLibrary = iid
End Function
Public Function FOLDERID_Objects3D() As UUID
'{31C0DD25-9439-4F12-BF41-7FF4EDA38722}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H31C0DD25, CInt(&H9439), CInt(&H4F12), &HBF, &H41, &H7F, &HF4, &HED, &HA3, &H87, &H22)
FOLDERID_Objects3D = iid
End Function
Public Function FOLDERID_PicturesLibrary() As UUID
'{A990AE9F-A03B-4E80-94BC-9912D7504104}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &HA990AE9F, CInt(&HA03B), CInt(&H4E80), &H94, &HBC, &H99, &H12, &HD7, &H50, &H41, &H04)
FOLDERID_PicturesLibrary = iid
End Function
Public Function FOLDERID_PublicLibraries() As UUID
'{48DAF80B-E6CF-4F4E-B800-0E69D84EE384}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H48DAF80B, CInt(&HE6CF), CInt(&H4F4E), &HB8, &H00, &H0E, &H69, &HD8, &H4E, &HE3, &H84)
FOLDERID_PublicLibraries = iid
End Function
Public Function FOLDERID_PublicRingtones() As UUID
'{E555AB60-153B-4D17-9F04-A5FE99FC15EC}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &HE555AB60, CInt(&H153B), CInt(&H4D17), &H9F, &H04, &HA5, &HFE, &H99, &HFC, &H15, &HEC)
FOLDERID_PublicRingtones = iid
End Function
Public Function FOLDERID_PublicUserTiles() As UUID
'{0482af6c-08f1-4c34-8c90-e17ec98b1e17}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H0482af6c, CInt(&H08f1), CInt(&H4c34), &H8c, &H90, &He1, &H7e, &Hc9, &H8b, &H1e, &H17)
FOLDERID_PublicUserTiles = iid
End Function
Public Function FOLDERID_RecordedTVLibrary() As UUID
'{1A6FDBA2-F42D-4358-A798-B74D745926C5}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H1A6FDBA2, CInt(&HF42D), CInt(&H4358), &HA7, &H98, &HB7, &H4D, &H74, &H59, &H26, &HC5)
FOLDERID_RecordedTVLibrary = iid
End Function
Public Function FOLDERID_Ringtones() As UUID
'{C870044B-F49E-4126-A9C3-B52A1FF411E8}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &HC870044B, CInt(&HF49E), CInt(&H4126), &HA9, &HC3, &HB5, &H2A, &H1F, &HF4, &H11, &HE8)
FOLDERID_Ringtones = iid
End Function
Public Function FOLDERID_RoamedTileImages() As UUID
'{AAA8D5A5-F1D6-4259-BAA8-78E7EF60835E}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &HAAA8D5A5, CInt(&HF1D6), CInt(&H4259), &HBA, &HA8, &H78, &HE7, &HEF, &H60, &H83, &H5E)
FOLDERID_RoamedTileImages = iid
End Function
Public Function FOLDERID_RoamingTiles() As UUID
'{00BCFC5A-ED94-4e48-96A1-3F6217F21990}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H00BCFC5A, CInt(&HED94), CInt(&H4e48), &H96, &HA1, &H3F, &H62, &H17, &HF2, &H19, &H90)
FOLDERID_RoamingTiles = iid
End Function
Public Function FOLDERID_SavedPictures() As UUID
'{3B193882-D3AD-4eab-965A-69829D1FB59F}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H3B193882, CInt(&HD3AD), CInt(&H4eab), &H96, &H5A, &H69, &H82, &H9D, &H1F, &HB5, &H9F)
FOLDERID_SavedPictures = iid
End Function
Public Function FOLDERID_SavedPicturesLibrary() As UUID
'{E25B5812-BE88-4bd9-94B0-29233477B6C3}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &HE25B5812, CInt(&HBE88), CInt(&H4bd9), &H94, &HB0, &H29, &H23, &H34, &H77, &HB6, &HC3)
FOLDERID_SavedPicturesLibrary = iid
End Function
Public Function FOLDERID_Screenshots() As UUID
'{b7bede81-df94-4682-a7d8-57a52620b86f}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &Hb7bede81, CInt(&Hdf94), CInt(&H4682), &Ha7, &Hd8, &H57, &Ha5, &H26, &H20, &Hb8, &H6f)
FOLDERID_Screenshots = iid
End Function
Public Function FOLDERID_SearchHistory() As UUID
'{0D4C3DB6-03A3-462F-A0E6-08924C41B5D4}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H0D4C3DB6, CInt(&H03A3), CInt(&H462F), &HA0, &HE6, &H08, &H92, &H4C, &H41, &HB5, &HD4)
FOLDERID_SearchHistory = iid
End Function
Public Function FOLDERID_SearchTemplates() As UUID
'{7E636BFE-DFA9-4D5E-B456-D7B39851D8A9}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H7E636BFE, CInt(&HDFA9), CInt(&H4D5E), &HB4, &H56, &HD7, &HB3, &H98, &H51, &HD8, &HA9)
FOLDERID_SearchTemplates = iid
End Function
Public Function FOLDERID_SkyDrive() As UUID
'{A52BBA46-E9E1-435f-B3D9-28DAA648C0F6}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &HA52BBA46, CInt(&HE9E1), CInt(&H435f), &HB3, &HD9, &H28, &HDA, &HA6, &H48, &HC0, &HF6)
FOLDERID_SkyDrive = iid
End Function
Public Function FOLDERID_SkyDriveCameraRoll() As UUID
'{767E6811-49CB-4273-87C2-20F355E1085B}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H767E6811, CInt(&H49CB), CInt(&H4273), &H87, &HC2, &H20, &HF3, &H55, &HE1, &H08, &H5B)
FOLDERID_SkyDriveCameraRoll = iid
End Function
Public Function FOLDERID_SkyDriveDocuments() As UUID
'{24D89E24-2F19-4534-9DDE-6A6671FBB8FE}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H24D89E24, CInt(&H2F19), CInt(&H4534), &H9D, &HDE, &H6A, &H66, &H71, &HFB, &HB8, &HFE)
FOLDERID_SkyDriveDocuments = iid
End Function
Public Function FOLDERID_SkyDrivePictures() As UUID
'{339719B5-8C47-4894-94C2-D8F77ADD44A6}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H339719B5, CInt(&H8C47), CInt(&H4894), &H94, &HC2, &HD8, &HF7, &H7A, &HDD, &H44, &HA6)
FOLDERID_SkyDrivePictures = iid
End Function
Public Function FOLDERID_UserPinned() As UUID
'{9E3995AB-1F9C-4F13-B827-48B24B6C7174}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H9E3995AB, CInt(&H1F9C), CInt(&H4F13), &HB8, &H27, &H48, &HB2, &H4B, &H6C, &H71, &H74)
FOLDERID_UserPinned = iid
End Function
Public Function FOLDERID_UserProgramFiles() As UUID
'{5CD7AEE2-2219-4A67-B85D-6C9CE15660CB}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H5CD7AEE2, CInt(&H2219), CInt(&H4A67), &HB8, &H5D, &H6C, &H9C, &HE1, &H56, &H60, &HCB)
FOLDERID_UserProgramFiles = iid
End Function
Public Function FOLDERID_UserProgramFilesCommon() As UUID
'{BCBD3057-CA5C-4622-B42D-BC56DB0AE516}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &HBCBD3057, CInt(&HCA5C), CInt(&H4622), &HB4, &H2D, &HBC, &H56, &HDB, &H0A, &HE5, &H16)
FOLDERID_UserProgramFilesCommon = iid
End Function
Public Function FOLDERID_UsersLibraries() As UUID
'{A302545D-DEFF-464b-ABE8-61C8648D939B}
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &HA302545D, CInt(&HDEFF), CInt(&H464b), &HAB, &HE8, &H61, &HC8, &H64, &H8D, &H93, &H9B)
FOLDERID_UsersLibraries = iid
End Function
Public Function FOLDERID_VideosLibrary() As UUID
'{491E922F-5643-4AF4-A7EB-4E7A138D8174 }
Static iid As UUID
 If (iid.Data1 = 0&) Then Call DEFINE_UUID(iid, &H491E922F, CInt(&H5643), CInt(&H4AF4), &HA7, &HEB, &H4E, &H7A, &H13, &H8D, &H81, &H74)
FOLDERID_VideosLibrary = iid
End Function
```

----------


## Dragokas

Hi, fafalone!

Nice! Thank you for that. BTW. I checked all of your another FOLDERID_* IDs. All of them are correct.




> I'm not sure about that error with static data; haven't encountered it before myself. My first thought would be a potential problem with referencing too many at once... is it happening in a project where you're using a whole lot of them? It would have to really be a lot some of my bigger projects use a few dozen of them.


Right after adding to my project I used maybe only 1-2 of them. That compilation error began to happen randomly and not very often, but only after I already ran project at least once.
I also using many Static in my proj. However, I don't think they could be greater than even 1 KB in sum.

----------


## fafalone

New release is up (v4.5). There's a whole other set of new FOLDERID_ values not in the list posted above, so I've got both those and the new ones in mIID now. TaskScheduler interfaces added; there were actually a few VB6 incompatibilities that had to be changed; a couple arguments were 'unsigned long' and another had a double-pointer to an array (the same bug pointed out for IKnownFolderManager.GetFolderIds... I went through the entire project and found a bunch of these that needed changing, so extra thanks for finding that Dragokas). 
PS- Per issue raised in PM, the base ITaskService interface is there, you just don't see it in Object Browser because it's the default interface for the TaskScheduler coclass.

----------


## The trick

fafalone, thank you! I didn't see it yet but i wanted to ask does it include both TaskScheduler 1.0 and TaskScheduler 2.0 interfaces?

----------


## fafalone

Yes to both; 1.0 was part of the original olelib. 2.0/3 are the new additions for this version.

----------


## Dragokas

Hi,
I wanted to know has VB6 appropriate compatible type for replacing HRESULT.
Since, you didn't replace it e.g. in KnownFolderManager -> GetFolderIds, so maybe due the some reason?
I used that code and my version of tlb* and after several attempts I got IDE crash on program unload, so I added red warning.
I didn't try your new tlb yet, however plan to make more tests.

*sorry can't add hyperlink ("Something went wrong), it's a link to your "Code snippet: KnownFolders made easy with IKnownFolderManager" topic, my post #14.

----------


## fafalone

You can replace any HRESULT with a long (byval, just long, not long*); I generally just leave it except where you really can't get by without knowing that return value, because while it's not applicable to IKnownFolderManager, switching it means you cannot use the interface with Implements, which is why oleexpimp and olelib2 before it exist. The vast majority of the time you can just check the expected output, like with GetFolderIds it failed if either the count or pointer are zero. But that's in general, here I had really forgotten that you wanted it changed to examine the specific return.. though it's not failing right? The return will be S_OK (0) unless it fails.

If there's a memory leak, it's not because HRESULT was changed to long. The most likely suspect is the array; MSDN says you need to 'free these resources' plural, so maybe just freeing the pointer isn't enough? Though first I'd check if there's still an issue when compiled.

----------


## Dragokas

Thank you for detail explanation.



> because while it's not applicable to IKnownFolderManager, switching it means you cannot use the interface with Implements


Not understant. It's already implemented. What you mean?



> here I had really forgotten that you wanted it changed to examine the specific return.


Yes, it's not important, bacause all of that methods can be checked by return values, as you already mentioned. So, in fact I have 2-level check.



> MSDN says you need to 'free these resources' plural, so maybe just freeing the pointer isn't enough?


I will be grateful.
I used your FreeKnownFolderDefinitionFields() to free each element of array and CoTaskMemFree on ptr to that array. So, I dunno, what else can be wrong. My project just silently crash on pressing "X". I lost that my version, but I'll try to reproduce.

----------


## Dragokas

Ok, I was able to reproduce.
Look like, it's 2 my mistakes.

I set FreeKnownFolderDefinitionFields under "if" scope that check only first member.
However, FreeKnownFolderDefinitionFields is not need at all, because CoTaskMemFree + ptr to array free whole resourse.
Crash happened because I tried to free it twice.

----------


## fafalone

> Thank you for detail explanation.
> 
> Not understant. It's already implemented. What you mean?
> 
> Yes, it's not important, bacause all of that methods can be checked by return values, as you already mentioned. So, in fact I have 2-level check.
> 
> I will be grateful.
> I used your FreeKnownFolderDefinitionFields() to free each element of array and CoTaskMemFree on ptr to that array. So, I dunno, what else can be wrong. My project just silently crash on pressing "X". I lost that my version, but I'll try to reproduce.


Was just talking about the default behavior. One would never use IKnownFolderManager with Implements, but most interfaces you might, so my default is to leave it at HRESULT. I'll change IKnownFolderManager to longs in the next version.

So no more crashing right?

----------


## Dragokas

Ahh, I see. Implements by other native interfaces.

Yes, after that fix, program is stable. I edited my exampe.

----------


## Dragokas

Just if somebody will expect the same issue:



> Compile error:
> Fixed or static data can't be larger than 64K"


I wrote a little parser that modify your all 676 Static in mIID.bas to module-level variable:



```
Option Explicit

Private Sub Form_Load()
    Dim ff As Integer
    Dim ff2 As Integer
    Dim sz As Long, n&
    Dim s$, r$
    ff = FreeFile()
    n = 0
    Open "iid.txt" For Input As #ff
        ff2 = FreeFile()
        Open "iid_2.txt" For Output As #ff2
            Do While Not EOF(ff)
                s = String(sz, 0)
                Line Input #ff, s
                If InStr(s, "Static iid As UUID") <> 0 Then
                    n = n + 1
                ElseIf InStr(s, " = iid") <> 0 Then
                    s = Replace(s, " = iid", " = iid(" & n & ")")
                    Print #ff2, s
                ElseIf InStr(s, "If (iid.Data1 = 0") <> 0 Then
                    s = Replace(s, "iid.", "iid(" & n & ").")
                    s = Replace(s, "iid,", "iid(" & n & "),")
                    Print #ff2, s
                Else
                    Print #ff2, s
                End If
            Loop
        Close #ff2
    Close #ff
End Sub
```

+ you need add in top something like:


```
Private iid(700) As UUID
```

----------


## fafalone

Have you found a way to reliably reproduce the error? Would love to take a look into it, but still haven't encountered it even in my largest projects that use upwards of 100 mIID refs.
Edit: btw, does this occur in the IDE, when compiled, or both?

----------


## Dragokas

This error bored me already enough. That's why at last I decided to replace those "Static".

No way to reproduce it reliably.
It just happen. Depens on what I do, how many run/stop e.t.c., I think.
The only I know, it never happen on first run after starting the project.
I think that somewhere in runtime this counter of 'Static' accumulates for some reason.

----------


## fafalone

LOL dude I think you cursed me. Never gotten that error before but tonight it just hit me. In an existing project that hadn't had any code related to static variables touched. It occured after some other errors caused an API call to behave erratically; continuing just made the triggering line change. Restarted the IDE and haven't seen it again since. Running/quitting over and over again hasn't reproduced it. Do you run MZ-Tools or CodeSMART by chance? CodeSMART frequently produces odd errors like this.

----------


## Dragokas

ahah. Epidemic =))
No, currently the only plugin I'm using it's a mouse wheel fix + patched manifest and icon resource for VB.exe + linker v14.14.

----------


## joerg74

Hello,
I am using a MS Access database to manage my projects at work. On a form I use a WebBrowser Control to show the content of the selected project folder, which is stored on a local network drive. It just provides Explorer functionality. My OS was recently upddated to windows 10 with the result that a warning window pops up, each time I want to open or right-click a file in the webcontrol. In the past that was fixed by reducing the security settings for the "local intranet" zone, but it seems like this is not possible any more. Thus I searched for an alternative for this control and found this project.   
Unfortunately I have no idea how to place an Explorer like control onto a form using VBA / MS Access. The samples above are for VB6 only.
It would be great if you could give me a hint. My programming skills are not very high, but with google's help I can write some VBA to get things done.

Greetings
Jörg

----------


## fafalone

The best option would be to use IExplorerBrowser which lets you put a frame of Explorer nearly identical to your pic on the form. 
See [VB6, Vista+] Host Windows Explorer on your form: navigation tree and/or folder 

You can use this object in VBA with just the normal adjustments, and I'd recommend forgoing the event sink. I tested this in Excel 2013 64-bit, and it ran fine.
This creates an ExplorerBrowser open to C:\Windows inside a frame (Frame1) on a VBA UserForm:


```
Option Explicit
 
Private pEBrowse As oleexp.ExplorerBrowser
Private pidlt As Long
Private lpck As Long
Private Declare PtrSafe Function ILCreateFromPathW Lib "shell32" (ByVal pwszPath As LongPtr) As Long
Private Declare PtrSafe Function GetClientRect Lib "user32" (ByVal hWnd As Long, lpRect As oleexp.RECT) As Long
Private Declare PtrSafe Sub CoTaskMemFree Lib "ole32" (ByVal pv As Long)


Private Sub UserForm_Activate()
Dim prc As oleexp.RECT
Dim rcf As oleexp.RECT
Dim pfs As FOLDERSETTINGS
Dim sPath As String
Dim lFlag As oleexp.EXPLORER_BROWSER_OPTIONS

sPath = "C:\Windows"
pidlt = ILCreateFromPathW(StrPtr(sPath))
pfs.fFlags = FWF_ALIGNLEFT
pfs.ViewMode = FVM_DETAILS
prc.Top = 18
GetClientRect Me.Frame1.[_GethWnd], rcf
prc.Bottom = rcf.Bottom - 8
prc.Left = 4
prc.Right = rcf.Right - 8

Set pEBrowse = New ExplorerBrowser
pEBrowse.Initialize Me.Frame1.[_GethWnd], prc, pfs
pEBrowse.SetOptions lFlag
pEBrowse.BrowseToIDList pidlt, 0 'if you want to use the desktop, for its own sake, or want a quick substitute
                                             'for not having C:\ , instead of pidlt use VarPtr(0) -NOT just 0.

CoTaskMemFree pidlt
End Sub
```

To change directories again manually, in another sub, you just need the ILCreateFromPathW and pEBrowse.BrowseToIDList functions again; you don't need to re-initialize the whole thing.

----------


## joerg74

Thanks a lot for your support!
One (maybe) stupid question: I created an empty form and added a Microsoft Forms 2.0 ActiveX Frame object and named it Frame1.
Unfortunately I get an error message that the object cannot be found (GetClientRect Me.frame1.[_GethWnd], rcf).
What am I doing wrong?

Regards
Jörg

----------


## joerg74

Next attempt was to try it in Excel (I use office365): I created a user form, placed a frame on it (this control should be the same as the control I used in Access, but in Access I did not have a frame inside the frame.
This time Excel stops working, when the line "pEBrowse.BrowseToIDList pidlt, 0" is executed.

Regards
Jörg

----------


## fafalone

For the frame, when you click on it the name should be there in the properties window. And the code is in the UserForm right, so the 'Me' is valid? 

For the error, try putting an error handler in the sub to see what's going on, and a check to make sure pidlt isn't 0. And talking about when you run the form right.. it crashed a couple times on me when I wrote on that line.

to add:


```
Private Sub UserForm_Activate()
On Error GoTo e0

'(...)
pidlt = ILCreateFromPathW(StrPtr(sPath))
If pidlt = 0& Then
    Debug.Print "Couldn't get pidl"
    Exit Sub
End If
'(...)

Exit Sub
e0:
Debug.Print "Error->" & Err.Description & ", " & Err.Number
End Sub
```


Edit: I noticed in Access 2013 there's no option to add a form in VBA... is that the case in 365?  Were you trying to put it in a frame like in the table? Then yeah the 'Me' wouldn't be valid and you'd have to change it to whatever object held the frame.

----------


## joerg74

That did not help, as I do not get an Error when trying it in Excel. The app just crashes.

----------


## fafalone

Hm and you're sure it's on the .BrowseToIDList line, not the .Initialize line or on CoTaskMemFree?

Could try an alternate method... like check to see if we can navigate to an IShellFolder instead...



```
Private Declare PtrSafe Function SHGetDesktopFolder Lib "shell32" (ppshf As IShellFolder) As Long
```

Then change the navigate command...


```
'pEBrowse.BrowseToIDList pidlt, 0 'if you want to use the desktop, for its own sake, or want a quick substitute
                                             'for not having C:\ , instead of pidlt use VarPtr(0) -NOT just 0.
Dim psf As IShellFolder
SHGetDesktopFolder psf
pEBrowse.BrowseToObject psf, SBSP_DEFMODE
```

Should open the desktop. Try removing the CoTaskMemFree call and the pidlt create / check block too in case it's that line and a memory issue.

----------


## joerg74

With IShellFolder it worked without crashing.

I had to comment out the CoTaskMemFree line as you proposed, even with IShellFolder method.

----------


## fafalone

Yeah it's not needed since pidlt isn't being used anymore. So if that's the problem, and IShellFolder works, IShellItem should work too, and it's a lot easier to use non-desktop paths without dealing with pidls.

So to go back to any sPath value, try IShellItem instead...


```
Private Declare PtrSafe Function SHCreateItemFromParsingName Lib "shell32" (ByVal pszPath As LongPtr, ByVal pbc As Long, riid As UUID, ppv As Any) As Long
```

Then instead of Dim psf... BrowseToObject psf...
it's


```
Dim tiid As UUID
'IID_IShellItem={43826d1e-e718-42ee-bc55-a1e261c37bfe}
tiid.Data1 = &H43826D1E: tiid.Data2 = CInt(&HE718): tiid.Data3 = CInt(&H42EE): tiid.Data4(0) = &HBC: tiid.Data4(1) = &H55: tiid.Data4(2) = &HA1: tiid.Data4(3) = &HE2: tiid.Data4(4) = &H61: tiid.Data4(5) = &HC3: tiid.Data4(6) = &H7B: tiid.Data4(7) = &HFE
Dim psi As IShellItem
SHCreateItemFromParsingName StrPtr(sPath), 0&, tiid, psi
 pEBrowse.BrowseToObject psi, SBSP_DEFMODE
```

Hoppefully that should work as well as IShellFolder. It's finicky for me too; SHCreateItemFromParsingName crashed with the standard declare, had to switch the 2nd param from IBindCtx to Long-- make sure you copy that version of the declare from this post, because it's defined the other way in the TLB and that will crash.

----------


## joerg74

This also worked fine. The next question would be how to get the same thing done in Access. There is also a frame control in Access, but is seems to be different to the frame object in Excel.
"GetClientRect Me.Frame1.[_GethWnd], rcf" 
results in: 
"Error->Object doesn't support this property or method, 438"

----------


## joerg74

This also worked fine. The next question would be how to get the same thing done in Access. There is also a frame control in Access, but is seems to be different to the frame object in Excel.
"GetClientRect Me.Frame1.[_GethWnd], rcf" 
results in: 
"Error->Object doesn't support this property or method, 438"

----------


## joerg74

I found a similar task here: http://www.access-im-unternehmen.de/1096 but it is in German.
The combination of their solution to get the hwnd of the Detail area of the Access form and your method to navigate to the path seems to be a solution for my problem:



```
Option Compare Database

Private Const GW_CHILD As Long = 5
Private Const GW_HWNDNEXT As Long = 2
Private oExplBrowser As oleexp.ExplorerBrowser
Private hwndDetail As Long

Private Declare PtrSafe Function GetClassName Lib "user32.dll" Alias "GetClassNameA" (ByVal hWnd As Long, _
                                                ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare PtrSafe Function GetWindow Lib "user32.dll" (ByVal hWnd As Long, ByVal wCmd As Long) As Long
Private Declare PtrSafe Function SHCreateItemFromParsingName Lib "shell32" (ByVal pszPath As LongPtr, ByVal pbc As Long, riid As UUID, ppv As Any) As Long

Private Function GetDetailHwnd() As Long
     Dim hWnd As Long
     Dim ret As Long
     Dim rct As RECT
     Dim sClass As String
     
     hWnd = GetWindow(Me.hWnd, GW_CHILD)
     Do
         sClass = String(255, 0)
         ret = GetClassName(hWnd, sClass, 255)
         sClass = Left(sClass, ret)
        hWnd = GetWindow(hWnd, GW_HWNDNEXT)
     Loop Until sClass = "OFormSub"
     GetDetailHwnd = hWnd
End Function

Private Sub Form_Load()
    Dim rct As oleexp.RECT
    Dim pfs As oleexp.FOLDERSETTINGS
    pfs.fFlags = FWF_ALIGNLEFT 'Or FWF_NOWEBVIEW
    pfs.ViewMode = FVM_DETAILS
    rct.Bottom = Me.Section(acDetail).Height \ 15
    rct.Right = Me.InsideWidth \ 15
    Set oExplBrowser = New oleexp.ExplorerBrowser
    oExplBrowser.Initialize GetDetailHwnd, rct, pfs
    'oExplBrowser.SetOptions EBO_SHOWFRAMES
    sPath = "C:\"
    Dim tiid As UUID
    tiid.Data1 = &H43826D1E: tiid.Data2 = CInt(&HE718): tiid.Data3 = CInt(&H42EE): tiid.Data4(0) = &HBC: tiid.Data4(1) = &H55: tiid.Data4(2) = &HA1: tiid.Data4(3) = &HE2: tiid.Data4(4) = &H61: tiid.Data4(5) = &HC3: tiid.Data4(6) = &H7B: tiid.Data4(7) = &HFE
    Dim psi As IShellItem
    SHCreateItemFromParsingName StrPtr(sPath), 0&, tiid, psi
     oExplBrowser.BrowseToObject psi, SBSP_DEFMODE
End Sub

Private Sub Form_Unload(Cancel As Integer)
     oExplBrowser.Destroy
End Sub
```

----------


## fafalone

Yeah you can draw it on any container hWnd, it doesn't have to be a frame. You could even just put it right on the form (the RECT doesn't have to fill the whole thing) since in Access there seems to be a Form.hWnd property.

And hey that article actually uses my typelib  :Big Grin:  Cool stuff  :Alien Frog: 

Edit: And btw if you wanted to display a custom file list instead of a folder, or customize the columns that are shown, I recently posted this project.

----------


## joerg74

Thank a lot for your great support!

----------


## fafalone

You're welcome, any other issues pop up don't hesitate to ask.  :Thumb:

----------


## joerg74

I am wondering how to read out the actual path of the explorer. Is there an easy solution?

----------


## dmrvb

First post, new to this forum, have been using oleexp for a couple of months. Thank you, it is great that people are still putting all this effort into VB6.
My interest is audio (and VB6)
oleexp has finally given me full access to CoreAudio Device Topology, thank you.
Yesterday I was evaluating AudioCapture but had compile error issues with IAudioClient.GetMixformat. I have just found your latest tlb version and this now works.
I am curious, why do we have to use a Long and then memorycopy into a WaveFormatX type?  I do not understand why WaveFormatX  is not a valid VB data type, especially as it works ok with IAudioClient.Initialize ?????

----------


## dmrvb

Sorry to bother you!!!! I think can answer my own question.
WaveformatX is ok as a "read" or input parameter, but CoreAudio can NOT write into a supplied WaveFormatX. I think it creates its own  WaveFormatX and so can only return the address of that WaveFormatX, hence the need to a memorycopy into a local WaveFormatX type.

----------


## fafalone

> I am wondering how to read out the actual path of the explorer. Is there an easy solution?


I'll have to adjust it for VBA later but in the mean time here's the VB6 code


```
Dim pfv As IFolderView
Dim lp As Long
Dim sPath As String, lpPath As Long
Dim pFol As IShellItem

pEBrowse.GetCurrentView IID_IFolderView, pfv
pfv.GetFolder IID_IShellItem, lp
vbaObjSetAddRef pFol, lp

If (pFol Is Nothing) = False Then
    pFol.GetDisplayName SIGDN_DESKTOPABSOLUTEPARSING, lpPath
    sPath = LPWSTRtoStr(lpPath)
    Debug.Print sPath
End If
```

Edit: You can also use the event sink (see the original explorer browser demo I posted) which has events for OnNavigationPending and OnNavigationComplete, so you'd get a pidl for each new location as it happened which can be readily turned into a path with SHGetPathFromIDListW. But I'm not sure how well or even if it would work in VBA.

----------


## fafalone

> First post, new to this forum, have been using oleexp for a couple of months. Thank you, it is great that people are still putting all this effort into VB6.
> My interest is audio (and VB6)
> oleexp has finally given me full access to CoreAudio Device Topology, thank you.
> Yesterday I was evaluating AudioCapture but had compile error issues with IAudioClient.GetMixformat. I have just found your latest tlb version and this now works.
> I am curious, why do we have to use a Long and then memorycopy into a WaveFormatX type?  I do not understand why WaveFormatX  is not a valid VB data type, especially as it works ok with IAudioClient.Initialize ?????


WAVEFORMATEX is itself a valid VB data type, but that particular method returns a pointer to a pointer. VB doesn't support passing a user-defined type in that manner. Initialize is just a regular pointer instead of a pointer-to-pointer. That was fixed in the most recent version, along with a few others (including other audio interfaces). Other languages do support passing UDT/arrays in that manner though, which is why the original definition (and oleexp until the issue was discovered) was set up differently.



```
HRESULT GetMixFormat(
  WAVEFORMATEX **ppDeviceFormat
);

HRESULT Initialize(
                   ...
              const WAVEFORMATEX *pFormat,
```

Single *  vs. Double ** pointer.

----------


## joerg74

> I'll have to adjust it for VBA later but in the mean time here's the VB6 code


I receive errors for "IID_IFolderView", "vbaObjSetAddRef" and "LPWSTRtoStr"

Greetings

----------


## fafalone

They were all defined in the original IExplorerBrowser demo; the IIDs in mIID.bas from the oleexp download... in any case here they all are again:



```
Public Declare Function SysReAllocString Lib "oleaut32.dll" (ByVal pBSTR As Long, Optional ByVal pszStrPtr As Long) As Long
Public Declare Function vbaObjSetAddRef Lib "msvbvm60.dll" Alias "__vbaObjSetAddref" (ByRef objDest As Object, ByVal pObject As Long) As Long
Public Function LPWSTRtoStr(lPtr As Long, Optional ByVal fFree As Boolean = True) As String
SysReAllocString VarPtr(LPWSTRtoStr), lPtr
If fFree Then
    Call CoTaskMemFree(lPtr)
End If
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 Function IID_IFolderView() As UUID
'{cde725b0-ccc9-4519-917e-325d72fab4ce}
Static iid As UUID
 If (iid.Data1 = 0) Then Call DEFINE_UUID(iid, &HCDE725B0, CInt(&HCCC9), CInt(&H4519), &H91, &H7E, &H32, &H5D, &H72, &HFA, &HB4, &HCE)
 IID_IFolderView = 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
```

It's just some of those might be a little iffy converting to VBA so I was going to rewrite it a bit... should have time tomorrow but there's the defs if you want to have a go at it.

----------


## dmrvb

Using oleexp for CoreAudio. Some Help and Advice needed please.

I am exploring data capture with IAudioClient and IAudioCaptureClient (working in Exclusive Mode) using VB6. I would like to do some essential buffer handling in a CallBack Event using  IAudioClient.SetEventHandle.

I just can not work out how to do this, is it even possible in VB6???? What do I supply as the long EventHandle required in SetEventHandle?  And where does my buffer handling code go????
In the past I have used "addressof" to supply a callback subroutine in a code module, but I think that a CallBack Event is a very different thing. 

I am hoping that the BufferFull event can be executed in a high priority callback so that it can execute even if my code is otherwise busy. If its all about sending a windows message to a Form then this is likely no good as VB6 message handling stops when my code is busy.

----------


## DEXWERX

I'm assuming you would use CreateEvent to create your event handle.

https://docs.microsoft.com/en-us/win...i-createeventa
https://docs.microsoft.com/en-us/win...-event-objects

Have you seen this awful example? MS basically just sleeps and poles GetNextPacketSize. *shrugs*
https://docs.microsoft.com/en-us/win...uring-a-stream

This code here is on the other end of the spectrum, it sets up another thread, and uses WaitForMultipleObjects, and waits for the capture event to be raised, but at least it's complete.
https://graphics.stanford.edu/~mdfis...pture.cpp.html

----------


## dmrvb

Thanks, I have seen these links whilst searching for info. The CreateEvent API call looks like the likely way to go but I don't know how to get the resulting event in VB6. I really want the event to invoke some CallBack code rather than just a windows message.
There is some stuff on the www about people using the Create Event then just doing await loop waiting for the event to occur!!!!.
I am hoping to use the Event/Callback to simulate a bit of multi threading.
 As a last resort I can use a timer to poll the buffer state but this might loose data as it looks like the internal buffer is only 2 seconds long maximum which is a bit tight for my needs.

----------


## voxy

Hi fafalone,

I have a very large project here (around 350,000 lines) with lots of everything (variables, controls, procedures), and recently I'm getting "Out of memory" errors in the VB6 IDE when I try to declare a new variable. Clearly I'm touching the limits of the IDE (see VB6 Project Limitations: https://docs.microsoft.com/en-us/pre...28v%3dvs.60%29). Now oleexp.tlb is very big and growing (which is good!), but I need only 10% of what's in it. So here's my question: How can I create a smaller custom version of it?

Thanks,
voxy

----------


## voxy

Hi fafalone,

I have a very large project here (around 350,000 lines) with lots of everything (variables, controls, procedures), and recently I'm getting "Out of memory" errors in the VB6 IDE when I try to declare a new variable. Clearly I'm touching the limits of the IDE (see VB6 Project Limitations: https://docs.microsoft.com/en-us/pre...28v%3dvs.60%29). Now oleexp.tlb is very big and growing (which is good!), but I need only 10% of what's in it. So here's my question: How can I create a smaller custom version of it?

Thanks,
voxy

----------


## fafalone

Hmm.. I'm not even sure why TLB contents would effect this; only the portions that get used should be touched outside the object browser. If you compile a tiny exe that only uses a single variable or API from a typelib, the exe still just comes out to a KB or two above normal, so clearly the whole 1.2MB isn't being carried around. So first I'd be sure external depend's unused definitions even count (I highly suspect oleexp+standard refs exceeds 32k identifiers as defined in that article just by themselves).

But if that is the case, the easiest-to-deal-with targets would be the separate systems like TaskScheduler, NetCon, Devices, CoreAudio, and DirectShow if you're not using them. Those can be removed simply by removing their includes from oleexp.odl. Also the ListView interfaces/definitions added to support undocumented features. 


```
#include "tasksch.odl"
#include "exp_audio.odl";
#include "exp_dshow.odl";
#include "exp_device.odl";
#include "exp_netcon.odl";
#include "exp_listview.odl";
```

There's a few more easily removable parts, mostly exp_ files, but they're a lot smaller. There's also API declares in modules named for their respective DLLs that most people declare locally instead. 

Of course, this all presumes interfaces and APIs, count, even if the whole TLB does. Removing enums outside of those files you can remove entirely might be difficult, since most of them are used by interfaces, which you'd then have to replace with a generic 'long', or remove the interface, provided it's not among the ones passed specifically by type to another interface.

(Edit: Also in oleexp.odl is the GUID, which is advisable to change to avoid a conflict)

----------


## SaschaT

> Yeah you can draw it on any container hWnd, it doesn't have to be a frame. You could even just put it right on the form (the RECT doesn't have to fill the whole thing) since in Access there seems to be a Form.hWnd property.
> 
> And hey that article actually uses my typelib  Cool stuff


Well, I am the author.  :wave: 
I intent to publish a series of acticles from time to time to support your library. It's a pity that so many VBA developers overlook VB6 sites like this. oleexp has the potential to realize tasks that could not be acheived in any other way.

----------


## fafalone

Wow... well, nice article! By all means continue with other articles and even put up demo projects with them if you want; it's as fully open as its foundation olelib is.  :Thumb:  :Thumb: 

And yeah, that's been oleexp's mission from the beginning, to pick up where Edanmo left off and take all the cool new shell features that have come between Vista and 10 and bring VB6 into this millennium. Some people prefer calling the v-table directly with DispCallFunc to implement the interfaces, but the way I see it is apart from the simplicity and time investment (few interfaces have already been implemented in classes), the TLB approach is much more efficient for things like having your current file as an IShellItem, then pass it directly to tons of other interfaces and APIs that call for an IShellItem. 
So many VB6 apps look exactly like you'd expect from a IDE and language from the 90s; I take great pride in helping apps to look and behave indistinguishable from ones made in the latest shiny, along with others like LaVolpe and his manifest maker, and Leandro with clsMenuImage et al. 
From time to time I've considered making an independent website dedicated to it; at first there wasn't enough content, but now... would that make the reach better? Of course here wouldn't change, I really like the community so would always keep this thread current. But I see the merit... it wasn't samples here that got me hooked on shell programming, it was Brad Martinez's site and projects. But again on the other hand an effort has been made to make this thread like a mini-site with how the first through third posts are-- master list linking to project pages, intro/install/documentation/common issues. So I dunno. 


But back to the actual coding... VBA seems tough. I don't know if it's just me, do you (or anyone else reading this) get crashes when you trigger an intellisense popup while coding? The LongPtr thing inflicts some pain too. All the experience with VBA is just the issues in this thread, as it's not something I really use.

----------


## voxy

> Hmm.. I'm not even sure why TLB contents would effect this; only the portions that get used should be touched outside the object browser. If you compile a tiny exe that only uses a single variable or API from a typelib, the exe still just comes out to a KB or two above normal, so clearly the whole 1.2MB isn't being carried around. So first I'd be sure external depend's unused definitions even count (I highly suspect oleexp+standard refs exceeds 32k identifiers as defined in that article just by themselves).
> 
> But if that is the case, the easiest-to-deal-with targets would be the separate systems like TaskScheduler, NetCon, Devices, CoreAudio, and DirectShow if you're not using them. Those can be removed simply by removing their includes from oleexp.odl. Also the ListView interfaces/definitions added to support undocumented features. 
> 
> 
> ```
> #include "tasksch.odl"
> #include "exp_audio.odl";
> #include "exp_dshow.odl";
> ...


Thanks, I will try that and let you know if it makes any difference.

Which version of MKTYPLIB.EXE do you use for compiling?

----------


## fafalone

> Using oleexp for CoreAudio. Some Help and Advice needed please.
> 
> I am exploring data capture with IAudioClient and IAudioCaptureClient (working in Exclusive Mode) using VB6. I would like to do some essential buffer handling in a CallBack Event using  IAudioClient.SetEventHandle.
> 
> I just can not work out how to do this, is it even possible in VB6???? What do I supply as the long EventHandle required in SetEventHandle?  And where does my buffer handling code go????
> In the past I have used "addressof" to supply a callback subroutine in a code module, but I think that a CallBack Event is a very different thing. 
> 
> I am hoping that the BufferFull event can be executed in a high priority callback so that it can execute even if my code is otherwise busy. If its all about sending a windows message to a Form then this is likely no good as VB6 message handling stops when my code is busy.


Sorry for the lo9ng delay in reply, but today I did look at some sample code for this, and it's indeed a standard event handle createable with CreateEvent; see e.g. this file. And this thread talks a little about using CreateEvent in VB6

----------


## fafalone

> Thanks, I will try that and let you know if it makes any difference.
> 
> Which version of MKTYPLIB.EXE do you use for compiling?


2.30.4230; the version that came with my copy of VS6 Pro.

And yeah definitely let me know, I'm curious about this. Set up a circumstance where you can reliably repeat the error, change nothing except oleexp, then try to raise the error again.

Edit: Also to note, just constants, 6,282, API 577, 489 typedefs enum, 208 typedef struct so that's 7,556 identifiers without interfaces, then 755 interfaces+coclasses so there's potentially 8,311 identifiers in oleexp.

----------


## voxy

> Edit: Also to note, just constants, 6,282, API 577, 489 typedefs enum, 208 typedef struct so that's 7,556 identifiers without interfaces, then 755 interfaces+coclasses so there's potentially 8,311 identifiers in oleexp.


Thanks for counting.  :Smilie: 

BTW, while editing oleexp.odl I noted that "exp_wic.odl" is not referenced/included anywhere? Is that on purpose?

----------


## fafalone

I was planning on adding it at one point, can't recall at the moment why I stopped the effort since it looks like was a year ago but it's just the prelimary copy of the SDK, it won't compile in MKTYPLIB and modification to avoid VB6 incompatible arguments isn't complete (looks like I stopped half way on line 886). Left the source in for possible inclusion in the future or if someone else was interested.

----------


## voxy

Non-final report: I removed some includes, gave it a new GUID, compiled it, copied it over to SysWOW64, had to re-reference it in VB IDE (probably because of the new GUID), and everything worked just fine. So I did not exclude anything I needed, good. oleexp.tlb is now 989.352 bytes, so roughly 200 KB smaller. Don't know about the inner counts. So far I had no "Out of memory" error, but it's too early to say. Give me some days...

----------


## voxy

Well, reducing the typelib by commenting out some components seems to have made a difference. The error message has not come up since I did it.

FYI, these are the parts I took out:

#include "tasksch.odl";
#include "exp_explrvw.odl";
#include "exp_audio.odl";
#include "exp_dshow.odl";
#include "exp_netcon.odl";
#include "exp_listview.odl";
#include "exp_spellcheck.odl";

----------


## voxy

Update: I now think reducing the size of the typelib did not have such a large effect. The error is coming back even with the smaller typelib.

I currently assume it might have to do with the Undo/Redo cache of the VB6 IDE. When I get the error I can simply close and reopen the IDE and work on for some hours.

----------


## Dragokas

voxy, maybe it can help.

----------


## voxy

Thanks, but my error is not "Fixed or static data can't be larger than 64K". It's not a compile error at all. It pops while typing or pasting into the IDE, usually when I declare a new variable.

----------


## Dragokas

I know. Maybe it somehow related.

----------


## The trick

Hi fafalone.
Can you fix the *STGOPTIONS* structure definition? Also make StgCreateStorageEx to has the optional parameter. 
It should contain the two short fields instead long, and the long one instead ULONG.
Thank you in advance!

----------


## fafalone

Sure thing. Will finish a couple other things and update this weekend.

Edit: Sorry I haven't updated yet. Forgot what a massive mess of other partially finished things were in the current dev version, was gone for a week, then got wrapped up in something else. Will definitely get it done over the next few days.

----------


## loquat

I have found one problem


```
Dim pVal As PROPVARIANT
Dim iPropStg as IPropertyStorage
iPropStg.ReadMultiple 1, pSpec, pVal
```

this will give a error information
we can just move the type PROPVARIANT definition from exp_prop.odl to propstg.inc to fix it.
is that right?

----------


## fafalone

It's not defined as PROPVARIANT, it's defined as Variant, which should be used in place of PROPVARIANT, which never works right. Use VB's Variant type then PropVariantToVariant (to another VB Variant); you can use the propvariant API's to change types if needed.

----------


## loquat

but why Variant to replace with PropVariant?

----------


## fafalone

Well in this particular case, that's how it was defined in the original olelib that this project expanded.

But more generally, VB doesn't support user-defined structures with unions, so you can't define a real PROPVARIANT period, and always having it as a long pointer to a variable has always failed wherever I've tried it. I've even tried specifically defined propvar structs for certain data types, and things still failed every time. After many hours, using a Variant instead is the only way I've ever been able to use functions that require PROPVARIANT, and they've always worked just about perfectly-- because Variant and PROPVARIANT have very similar internal structures.

----------


## fafalone

> Hi fafalone.
> Can you fix the *STGOPTIONS* structure definition? Also make StgCreateStorageEx to has the optional parameter. 
> It should contain the two short fields instead long, and the long one instead ULONG.
> Thank you in advance!


Trick in StgCreateStorageEx how do I declare it to be optional? It's saying 'invalid attribute for this item' no matter how I declare it, despite optional parameters working in interface definitions.

----------


## softv

Originating thread: https://www.vbforums.com/showthread....=1#post5478421 




> The way the control works is just to enumerate the items and use the system Property Store.
> ... .. .
> Now if you needed the additional information on the individual multi-style fonts (where you'd double click one in the control and then an entry would show up for each), the quickest shortcut would be to check the Folder attribute (siFont.GetAttributes SFGAO_FOLDER, dwAttribs: If (dwAttribs And SFGAO_FOLDER) = SFGAO_FOLDER Then), and then just take siFont and enumerate that in the same way that was done for the font folder...
> siFont.BindToHandler 0&, BHID_EnumItems, IID_IEnumShellItems, pEnum2
> Do While pEnum2.Next(1&, siSubFont, pcl) = S_OK
> etc. ... .. .


*Thanks a ton* to your invaluable "extended" guidance (with sample code lines), I was easily able to obtain the multiple styles for fonts which possess the same. Two points of interest in this regard:


For whatever reason, in the primary 'Fonts' folder screen, Windows (I have Windows 10) does not show the individual file names for fonts with multiple styles. This has been raised as an issue too here (in a Microsoft Windows forum). But, thanks to you, now in my program, additionally, *I can show the file names for multiple styles too*, in a grid which I have created (to show fonts info, in the same way as shown in the 'Fonts' folder).
_Note_: Even for fonts without multiple styles, for whatever reason, Windows shows all the file names in uppercase, totally. I am showing the same in my grid now, in the exact case in which the path&file names are existing in the system.As far as I can see, Windows is showing the 'Size' info cumulatively for fonts with multiple styles. For instance, for Arial, it shows it as 4,240 KB (cumulatively, considering all the nine Arial .ttf fonts). But now, in my program, since I am showing the file name for each of the individual styles, I am able to show the* file size too for each of the individual font styles*.

I was able to give the above-mentioned additional info in my grid only because you took the time to give extended guidance on how to recurse through fonts which have multiple font styles. I remain ever in thankfulness to you. *Thank you so... much*.  

*Note:* I have been trying to post this message since 24-May-2020 itself (in the originating thread mentioned at the top of this message) but every time I am meeting with errors only - of more than one kind. I am just unable to post. I tried posting through 3 different browsers. So, I am posting this message in this thread itself now, instead of in the thread specified at the very top of this message. Anyway, as such, this is the right thread for me to post this message since I have availed your library only so far and not your ucShellBrowse control. So, hopefully, no issues. 

Prayers and Kind Regards.

----------


## fafalone

Glad everything is working out, you're welcome  :Alien Frog: 

The control/code here is just pulling data through the same methods that Explorer is; I checked the Fonts folder there and combined sizes and upper case names is how everything is shown in Explorer too, so not too much to be done there besides manually changing it yourself like you're doing. 

As always, I'm happy to help and don't hesitate to post if any issues come up  :Thumb:

----------


## Semke

hi!
nice work. I am a bit confused, does *oleexp.tlb* include the interfaces etc. that exist in *oleexmpimp.tlb*/*mimelib.tlb*.
also does it include the windows api declarations, structures and constants.

----------


## fafalone

oleexpimp.tlb contains slightly different versions of a small number of interfaces. For example, in oleexp.tlb, IEnumIDList.Next is a function that returns a Long, because knowing the return value is important for that call. But VB does not allow you to implement a class that contains functions, only subs, so if you wanted to implement that interface yourself in a class (Implements IEnumIDList), you'd use the version in oleexpimp.tlb instead, because that version is written without any return values. You don't need to include a reference to oleexpimp.tlb unless you specifically need one of these alternate versions for a class module Implements statement. 

Only a few API declarations are included, most of which are related to or frequently used by the interfaces. All of that ones that are included are oleexp.tlb. 

mimelib.tlb is interfaces specifically for MIME in messages; interfaces mostly starting with IMime____. It's very unlikely you'll need this one, and don't need to reference it.

----------


## fafalone

*Project Updated to Version 4.7*

In one of the sample projects, an issue came up where the enum IUN_Flags and NII_Flags had all the same entries, so produced an ambiguous name error. I had not realized such an issue could make it through compiling the TLB, so had not checked. After realizing that was possible, I created a tool that scanned the code for duplicate constants or enum names, and found a number of them. So it was important to get this new version released to avoid bugs like that. But I had also done quite a bit of other work, so there's a bunch of other new stuff in the release too. 

Here's the full changelog:



```
(oleexp 4.7 - Released 23 Dec 2020)
-Added interfaces IFrameworkInputPaneHandler and IFrameworkInputPane, with coclass FrameworkInputPane.
-Added interface IShellTaskScheduler with coclass ShellTaskScheduler.
-Added interface ISharingConfigurationManager with coclass SharingConfigurationManager.
-Added interface IDefaultFolderMenuInitialize with coclass DefFolderMenu.
-Added interfaces IAccessible, IAccessibleHandler, IAccessibleWindowlessSite, IAccIdentity, IAccPropServer, and IAccPropServices (with coclass CAccPropServices) from oleacc.h, and related consts. 
-Added undocumented interface ICustomizeInfoTip
-Added coclass PropertyChangeArray
-CHANGE TO MAJOR OLELIB INTERFACES: IFolderView has been updated to use As Any in a ByRef Long to get objects in .Items and .GetFolder. Also associated SVGIO enum for several members. Changed ByRef Long for interface pointers in IShellView and IShellView2 .GetItemObject, ICategoryProvider .CreateCategory 
-IPropertyStore.SetValue and .Commit were already functions, made the rest of the methods into one as well.
-Added a number of error/success consts including OLE_E_, REGDB_E_, STG_E_, and RPC_E_ error codes.
-The wmp.dll dependency has been removed from oleexp.tlb, and placed in its own dependent tlb, oleexpwmp.tlb. The source is in \source\wmp\, which just moves the wmp.inc source file from olelib/oleexp and like mimelib.tlb, it's compiled including oleexp.tlb. 
-Bug fix: IItemNameLimits is typically used for Implements, but had out-only parameters making that impossible. 
-Bug fix: IUN_Flags and NII_Flags contained duplicate enum values. This caused an error using any of them and you had to specify which to use. The former has been removed. Change any instance of 'IUN_Flags' to 'NII_Flags'. The values themselves are unchanged.
-Bug fix: After the above issue popped up, I created a tool to root out any further duplicates. Unfortunately, there were many, as I had never worried about this under the assumption that a compile error would be triggered for such a situation.
          The following were fixed: Two SVSI_Flags enums, one with additional values. Two SVGIO_Flags enums, ditto. Full duplicates of SVUIA_STATUS and SV2GV_Flags. ISCM_FLAGS was not used anywhere, and contained only a single value found in MUTZ_FLAGS. The URLACTION enum contained some duplicate values from URLPOLICIES.
-(oleexpimp) oleexpimp.tlb has been recompiled using oleexp 4.7
-(oleexpimp) Bug fix: This used the IShellFolder definition from olelib2, but VB says that's a bad interface for Implements
-(mWIC) Added WebP and Heif container format UUIDs.
```

----------


## SaschaT

Thanks again to your efforts to continue the development of this great library!

I'd like to know how you do the conversion of the headers to ODL? All manually? Like to share how it's done? Some others could then support you.
I ask because I did some modifications and enhancements to the library because some of the declarations seem not to work.
(Have you ever used IServiceProvider of oleexpimp.tlb? It always crashes if I implement it. I had to change the code like this to get it working:


```
  interface IServiceProviderExplorerPane : IUnknown {
    HRESULT _stdcall QueryService(
      [in, out] UUID* guidService, 
      [in, out] UUID* riid, 
      [out, retval] oleexp.IExplorerPaneVisibility** ppvObject
    );
```

As you can see one has to set a pointer to a specific interface (here IExplorerPaneVisibility) instead of a general long pointer to an interface. I found this to be required also for other implemented ServiceProviders.)

Back to the question: I tried to automate the conversion of the MSDN headers using a self developed parser. But it's really hard concerning all the conditional statements an includes. I am now at the state to generate a ODL that then further needs some manual adjustments. But that still is hard work.
My actual target is the Media Foundation API (https://docs.microsoft.com/en-us/win...api/mfobjects/). And especially a replacement for DirectShows Sample Grabber (https://docs.microsoft.com/en-us/win...i/mfreadwrite/) as the new methods are much easier to implement; much less code!
It would be an exceptional addition to oleexp if it included the media foundation interfaces and functions!

----------


## fafalone

Was it crashing on entry or when you tried to set the pointer to an object? I'm not familiar with IServiceProvider but I've never had an issue with ObjPtr()/vbaObjSetAddRef for a generic object, which pops up fairly often. Though sometimes I've had to implement the function in a standard module with a vtable swap.

But to the question, I do it all mostly manually, just find/replace for common conversions and aliasing data types so not so many of them have to be changed; I use a modern VS to keep a project with all the files, have 2 panes side by side, and have syntax highlighting.(*) As you found, trying to automate it is just too complex to be practical. I've looked at it briefly before, but always just concluded between the time to make a tool and all the manual touching up, it would be quicker to just do it by hand; can do it quite quickly now after so much practice. I've tried to convert every argument using a type that's worked before, but sometimes interfaces have individual quirks that cause issues... like it won't accept a pointer to a GUID so it has to be passed as 4 Longs (why 4 Longs specifically you may ask? Structuring it any other way crashed). And of course sometimes there's just mistakes, it would be way too time consuming to test every single interface in VB when tons of them I'm not even familiar with. I also never went through and checked all the original code from the olelib project this is forked from, which includes ISP.

If you've found and corrected bugs, by all means share and I'll update the project, and credit you for the help. With IServiceProvider here I'd really want to try to find a workaround that didn't result in everyone having to compile their own custom version, so I'll have a look into that. 

The Media Foundation API looks great, would love to include it! It does look like a ton of interfaces though; what have you done so far, maybe I can tackle a few of the headers when I get back tonight?


-
* - I do have some code that automates converting to VB... like create IID_IWhatever() UUID functions for mIID.bas or PKEYs for mPKEY/related, or to convert structs to Types in VB code, or to convert enums. But none of it is for automating the C headers to VB6-compatible ODLs.

----------


## The trick

> My actual target is the Media Foundation API (https://docs.microsoft.com/en-us/win...api/mfobjects/). And especially a replacement for DirectShows Sample Grabber (https://docs.microsoft.com/en-us/win...i/mfreadwrite/) as the new methods are much easier to implement; much less code!


If you're interesting here is a small example where you can extract the images from a youtube video frames using Media Foundation API. The example is intended for extracting slides from a video so it analyzes frames and extract the slides and skip animations. For example if you have a video with a slideshow which are animated it should extract the static images:

----------


## SaschaT

> Was it crashing on entry or when you tried to set the pointer to an object? I'm not familiar with IServiceProvider but I've never had an issue with ObjPtr()/vbaObjSetAddRef for a generic object, which pops up fairly often. Though sometimes I've had to implement the function in a standard module with a vtable swap.


The sample I've posted is for handling the panes of an explorer browser control. It's somehow complicated: You have to implement IServiceProvider in a class module to hook the *GetPaneState* calls of *IExplorerPaneVisibility*, which is also implemented in this class. So the first step ist to tell ExplorerBrowser where to find the *IExplorerPaneVisibility* interface. The method I found for this is *IUnknown_SetSite* [oExplBrowser], Me. oExplBrowser then calls the implemented *IServiceProvider* several times. If the queried IID is the one of *IExplorerPaneVisibility* I return *Set ... =  Me* as the functions result. It crashes in this case if I use the declaration in *oleexpimp*. But not with my altered declaration above. 
(I have tried this also with a vtable swap but the result was the same.) BTW: I have all the samples from Morcillo; there is no one that uses the implements version of IServiceProvider, so I had to test that myself.
Time to update your sample.  :wave: 




> But to the question, I do it all mostly manually, ...


That has been my guess. The most difficult cirumstance to automate the ODL creation for me are the many aliases for types. You have to jump into many includes to find e.g. what the result DBAPI means... finally it's just a DWORD.




> If you've found and corrected bugs, by all means share and I'll update the project, and credit you for the help.


No, no, I have not found bugs. Just the issue with IServiceProvider caused me to modify *oleexpimp*. (Another addition to oleexp are the *ActiveScript* interfaces that I borrowed and extended from D. Zimmer.)




> The Media Foundation API looks great, would love to include it! It does look like a ton of interfaces though; what have you done so far, maybe I can tackle a few of the headers when I get back tonight?


Looks like *TheTrick* has already done the job! Wow!

----------


## SaschaT

> If you're interesting here is a small example where you can extract the images from a youtube video frames using Media Foundation API. The example is intended for extracting slides from a video so it analyzes frames and extract the slides and skip animations. ...


Incredible! That's what I have dreamed of! A nearly complete type library for the Media Foundation objects!
I am just missing some functions in mfreadwrite like *MFCreateSourceReaderFromByteStream* and so. But I'll make this up by myself.

The same question to you: How do you manage to create the ODLs?

----------


## The trick

> The same question to you: How do you manage to create the ODLs?


I manually parse C/C++ headers.

----------


## Dragokas

Hi, *fafalone*. Thanks for continue supporting this library.




> ```
> Public Function GUIDToString(tg As UUID, Optional bBrack As Boolean = True) As String
> 'StringFromGUID2 never works, even "working" code from vbaccelerator AND MSDN
> ```


Dunno about vbAccelerator, however, this one is working well for me:



```
Public Declare Function StringFromGUID2 Lib "ole32.dll" (rguid As UUID, ByVal lpsz As Long, ByVal cchMax As Long) As Long

Private Function GUIDToString(uGuid As UUID)
    Dim sGUID$
    sGUID = String$(39, 0)
    If StringFromGUID2(uGuid, StrPtr(sGUID), Len(sGUID)) > 0 Then
        GUIDToString = Left$(sGUID, 38)
    End If
End Function
```

----------


## fafalone

Ah well I think I tried a few different things and after an example from MSDN didn't work either I just said screw it, I'll do it manually  :Ehh:

----------


## xiaoyao

> [CENTER]OLEEXP : Modern Shell Interfaces
> Current Version: 4.7 (Released 23 Dec 2020) 
> 
> _Source distributed separately due to attachment size limits._


eleexp47.tlb Registration Failed(Error:8002801c)
where to download 4.6 version?

now it's ok!
it take me more times

need add by me:
Reference=*\G{F9015E81-CAAC-45C0-94E8-42B7DA5D7557}#4.3#0#..\..\Windows\SysWow64\oleexp.tlb#OLEEXP - olelib With Modern Interfaces by fafalone, v4.3
Reference=*\G{F9015E81-CAAC-45C0-94E8-42B7DA5D7557}#4.3e#0#..\..\Windows\SysWow64\oleexp.tlb#OLEEXP - olelib With Modern Interfaces v4.62
Reference=*\G{F9015E81-CAAC-45C0-94E8-42B7DA5D7557}#4.6#0#..\..\Windows\SysWow64\oleexp.tlb#OLEEXP - olelib With Modern Interfaces v4.6

Reference=*\G{F9015E81-CAAC-45C0-94E8-42B7DA5D7558}#4.7#0#C:\Windows\SysWow64\oleexp.tlb#OLEEXP - Modern Shell Interfaces for VB6, v4.7

----------


## fafalone

You shouldn't need to register it manually, VB handles that when you load it.

That was a mistake changing the GUID but as long as the path is still right VB will load and use the new one without issue. But you can update the file by going to References, uncheck oleexp, click ok, open References again, and check oleexp again.

----------


## xiaoyao

> You shouldn't need to register it manually, VB handles that when you load it.
> 
> That was a mistake changing the GUID but as long as the path is still right VB will load and use the new one without issue. But you can update the file by going to References, uncheck oleexp, click ok, open References again, and check oleexp again.


{F9015E81-CAAC-45C0-94E8-42B7DA5D7557}#4.6
{F9015E81-CAAC-45C0-94E8-42B7DA5D7558}#4.7
because ,it's use not same GUID

----------


## fafalone

Right but it doesn't matter. It's still just an upgrade of the previous version. Just follow the steps I listed in any app that's already using it. Uncheck it in references, close that dialog, open it again, and select oleexp. You don't need to do anything with registration outside VB.

----------


## 7edm

Excuse my ignorance being new to this with tlbs', but after reading the "requirements" and "installation" paragraphs in post #1 I'm a bit confused. The requirements says:



> 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.


Ok



> *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).


So how do I deal with the addon modules and where do I put them? As it's .Bas files the natural way seems to be to put them in my project folder and include them in my project, but after looking at some of the sample projects for guidance none seems to take that approach, and placing .bas files into in SysWow64 doesn't seem right to me... Sorry, I'm probably the dumbest person in the forum as no one else seems to talk about it, or you're all here way beyond you first cautious tlb steps and others don't dare to ask such a stupid question you just are supposed to know about! :-)

----------


## 7edm

ok maybe I get it now. Previously I was just unzipping the sample projects looking for any of these BAS files, but when I now actually loaded a sample project I noticed that it complained about these files missing in the tl_ole parent folder. Still could have been some mentioning of how this is setup rather than have to go by trial and error... so all well and ready to explore further ;-)

----------


## fafalone

Yeah the .tlb is good to keep in the system folder, but for the modules, say all your projects are C:\VB\Project1, C:\VB\Project2, etc, the easiest thing to do (and what sample projects referencing them expect by default, though you can change it), is to have all the addon modules in C:\VB\tl_ole.

You're right though I should make that more clear.

Everyone was new to all this at one point, never feel bad about asking questions, that's what this site is here for  :Alien Frog:

----------


## xiaoyao

WebBrowser1.Navigate App.Path & "\123.svg"
Webbrowser selects the SVG file and right-clicks "Save Picture As" to save it in transparent PNG format. How to use the code to make him save as, it is best not to pop up a window.

The image saved by webbrowser has a white background, how to make it transparent?
You can draw the control in the memory by querying the IViewObject interface of the control



```
Private Sub DoSave_Click()
Dim tIv As IViewObject
Dim trc As RECT
trc.Right = 100
trc.Bottom = 100
'USE OLELB.TLB
Set tIv = WebBrowser1.Document
 
Picture1.Cls
tIv.Draw DVASPECT_CONTENT, 1, ByVal 0, ByVal 0, Picture1.hDC, Picture1.hDC, trc, trc, ByVal 0, ByVal 0
Picture1.Refresh
End Sub
```

----------


## fafalone

You're better off asking in the main forum as I'm not at all familiar with the WebBrowser control and transparency hates me, but this might help:

http://access.mvps.org/access/modules/mdl0062.htm

----------


## vbLewis

Hi fafalone, I have taken the opportunity to optimize all the extra addon bas modules and some functions. Take a look if you wish, and i you feel like it could add value to your project feel free to use it, or reject , totally up to you.

----------


## xiaoyao

Can you add a TLB wrapper for the edge chrome kernel?

----------


## xiaoyao

HOW to get Library Name by Com DLL with vb6?
https://www.vbforums.com/showthread....m-DLL-with-vb6

----------


## drpatt

I found this library recently. Vey impressive.

There is a slight bug in the call back function for pNotify.afChannelVolumes(1) in IAudioEndpointVolumeCallback_OnNotify(pNotify As AUDIO_VOLUME_NOTIFICATION_DATA)
The  afChannelVolumes array is limited to channel 0.

I had a quick look at your source code.
Perhaps the typedef structure should be float afChannelVolumes[2]; ?

typedef struct AUDIO_VOLUME_NOTIFICATION_DATA
{
    UUID guidEventContext;            // Context associated with the originator of the event.
    BOOL bMuted;
    float fMasterVolume;
    UINT nChannels;
    float afChannelVolumes[1];

I also found it quite a challange to return callback values to the main form.
After much testing with subclassing and other over-complications..
I overcame the crashes by copying to global values then enabling a 1ms Time control in the main form to process the global variables.
Absolutely no crashing.

I found I could enable callbacks for default speaker and microphone concurrently, with careful programming.
However there appeared to be no way to differentiate the callback data by the device type that originated the callback.
Is there a way?
Does the secret lie in the pnotify.guidEventContext field ?
What is the significance of the 4 parameters?

Or to set up a second callback class with a different identity?

David

----------


## anemos_78

> 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.


"oleexp.tlb" is very useful but not compatible with 64 Excel VBA.
As you know, Handle and Pointer (memory address) have 8 bytes of data in 64-bit processes. Therefore, this TLB must be recompiled as 64-bit.

E.g; User32.FindWindow function, which is one of the frequently used functions, throws an overflow exception because it returns a 64-bit number when using the existing 32-bit oleexp.tlb.

As another example; The IDispatch.GetTypeInfo.AddressOfMember function must return a 64-bit integer.

Since some structures and functions in TLB take the data type as ByRef, we cannot send type conversion functions such as CLngPtr.

For these reasons 64-bit compilation is required.

As a solution, if you describe how you overcome the "redefined" and "same uuid" errors that are printed on the screen when compiling the IDL content I have given as an example below with MIDL.EXE, everyone, especially me, can compile the interfaces they need.

Simple IDL:



```
[
  uuid(035AE7E1-92D3-47F9-BACA-E9DF8FD28333),
  version(1.0),
  helpstring("Test type library")
]
library test
{    
    importlib("stdole2.tlb"); 
    
    interface IUnknown;   

    typedef struct UUID {
        LONG  Data1;
        SHORT Data2;
        SHORT Data3;
        BYTE  Data4[8];
    } UUID;

    [
        odl,
        uuid(00000000-0000-0000-C000-000000000046)
    ]
    interface IUnknown {
        LONG QueryInterface(
        [in, out] UUID *riid,
        [in, out] void *ppvObject);
        LONG AddRef();
        LONG Release();
    };

};
```

----------


## anemos_78

Hello @fafalone, I solved the 64 bit compilation problem with MIDL.EXE. I worked with Visual Studio 2022.
You can upgrade your project to new version with this.

Example IDL and descriptions:



```
/*************************************************************************
 MIDL.EXE, can automatically add types inherited to the interface 
 or defined in the parameters of interface members to the "Type Library".

 However, it requires some modifications (before copy them your project dir) to the imported SDK IDL files.
 For example, if there is "<Unsupported variant type>" in Object Browser, 
 this indicates that it is not compatible with OLE automation. (UINT, ULONG.. etc).
 Or you may need to change/delete/add unwanted interface members.
 Microsoft has defined ITypeInfo members very differently in the IDL file in the SDK.
 You can delete them and rewrite them as they should be.

 The following IDL example will inject the types that the IDispatch and ITypeInfo2 interfaces
 are associated with. This includes Structures and Enumerations.

 You can give any UUID value to the "__NeededInjectionTypes" interface.

 Note that there is no import("stdole2.tlb") line. This line should not exist for automatic
 injection of types. If you use this line, you have to randomly assign the interface UUID value
 in the IDL files in the SDK. In our own IDL file, we need to write one by one with the
 original interface UUID value.

 For Handle and Pointer : LONG_PTR? __int3264?

 You can use "LONG_PTR" if you are designing Type Library for Office 2010 and above (VBE7).
 This will appear in Object Browser as "LongPtr" VBA type. The advantage of this is that
 you can use the TLB file that you will compile as 32-bit with in 64-bit Office.

 "__int3264" should be used if it is desired to be compatible for pre-Office 2010 as well.
 It directly converts the numeric type type to VBA "Long" type for 32 bit and VBA "LongLong" for 64 bit.
 This means making two separate TLB files for 32 and 64 bit Office.

 Best regards,
 Zeki Gürsoy

Example commanline:
REM ----------------------------------------------------------------
CD "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64"

REM For 64 bit:
midl /no_warn ^
/I "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um" ^
/I "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\shared" ^
/cpp_cmd C:\PROGRA~1\MIB055~1\2022\PROFES~1\VC\Tools\MSVC\1430~1.307\bin\Hostx64\x64\cl.exe ^
/tlb "D:TLBproject\test.tlb" "D:TLBproject\test.idl"

REM For 32 bit (only need add /win32 switch):
midl /no_warn /win32 ^
/I "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um" ^
/I "C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\shared" ^
/cpp_cmd C:\PROGRA~1\MIB055~1\2022\PROFES~1\VC\Tools\MSVC\1430~1.307\bin\Hostx64\x64\cl.exe ^
/tlb "D:TLBproject\test.tlb" "D:TLBproject\test.idl"
REM --------------------------------------------------------------------------

*************************************************************************/
[
  uuid(902C3131-525C-4F45-AF75-4F1923DF0853),
  version(1.0),
  helpstring("Test type library")
]
library test
{ 
    [odl,  restricted, hidden, uuid(00000000-0000-0000-0000-000000000001)]
    interface __NeededEnjectionTypes : IDispatch
    {
        /* You can declare another 'NeededTypes?' if parameters many. */
        HRESULT NeededTypes1(
                          [in] ITypeInfo2 *neededType1);
                       /* [in] ITypeLib2  *neededType2); */
    }; 

};
```

----------


## fafalone

> Hi fafalone, I have taken the opportunity to optimize all the extra addon bas modules and some functions. Take a look if you wish, and i you feel like it could add value to your project feel free to use it, or reject , totally up to you.


Definitely seems like a good option if performance is key, however one potential Con I'd like to point out, besides the added complexity of all the steps to use it, that method results in compiling the entirety of each used module into your exe/ocx. One of the reasons I used the old method, in addition to being the format used by notable shell projects before me for consistency's sake, is that it would only result in what you used being compiled into the binary; the compiler would prune the unused code. Here it's all used so all included.

Also, where did dbg_enumstore come from? That's definitely not the oleexp modules unless maybe it got left in for a much older one? I checked 4.7 (current) and 4.62. It looks like something from my shell browser project.

----------


## fafalone

> I found this library recently. Vey impressive.
> 
> There is a slight bug in the call back function for pNotify.afChannelVolumes(1) in IAudioEndpointVolumeCallback_OnNotify(pNotify As AUDIO_VOLUME_NOTIFICATION_DATA)
> The  afChannelVolumes array is limited to channel 0.
> 
> I had a quick look at your source code.
> Perhaps the typedef structure should be float afChannelVolumes[2]; ?
> 
> typedef struct AUDIO_VOLUME_NOTIFICATION_DATA
> ...


[2] would give it 3 channels; it's zero based.

One of the demos uses that interface, did you look at [VB6, Vista+] Core Audio Basics

Needless to say I had a difficult time getting it working too, but it did work out.

I'm really not too familiar with whether you can get notifications in the same callback... can you print the guidEventContext and see if it's different depending on where you trigger an event? If so then there must be some way to associate the GUID with a device.

----------


## fafalone

> Hello @fafalone, I solved the 64 bit compilation problem with MIDL.EXE. I worked with Visual Studio 2022.
> You can upgrade your project to new version with this.
> 
> Example IDL and descriptions:
> 
> 
> 
> ```
> /*************************************************************************
> ...


I haven't really worked with this at all... is there an automated way to handle this or would it be going through every single interface by hand?

If it's just a question of returning 64-bit types, you can change them to do that with MKTYPLIB too; I was never able to get midl to work.

----------


## drpatt

The audio callback works with everything except pNotify.afChannelVolumes(1)
pNotify.afChannelVolumes(0) returns the left channel volume correctly, pNotify.afChannelVolumes(1) produces subscript out of range.

Debug output when the callback code runs:
 0.27 
Subscript out of range       1



```
Option Explicit

Implements IAudioEndpointVolumeCallback

Private Sub IAudioEndpointVolumeCallback_OnNotify(pNotify As AUDIO_VOLUME_NOTIFICATION_DATA)
' transfer to global variables
Cmuted = pNotify.bMuted
Cvol = pNotify.fMasterVolume
Cchannels = pNotify.nChannels

' problem in oleexp.tlb - limited to channel 0
On Error GoTo bad1
Dim I As Integer
    If Cchannels > 1 Then
    I = 0
    Debug.Print (pNotify.afChannelVolumes(I))
    I = 1
    Debug.Print (pNotify.afChannelVolumes(I))
    End If

' enable data processing in main form using timer, if not already enabled
' use timer to create interrupt in form1 thread
' tried other methods: eg https://stackoverflow.com/questions/4169028/how-to-write-a-callback-in-vb6
' but this is simple and it works

    If Form1.Tcallback.Enabled = False Then Form1.Tcallback.Enabled = True
Exit Sub

bad1:
Debug.Print Err.Description, I
Err.Clear

If Form1.Tcallback.Enabled = False Then Form1.Tcallback.Enabled = True
End Sub
```

If the array I suggested is the correct code point and is zero based, what else will be causing this issue?

I tried trapping the pNotify.guidEventContext.Data
All I got was a sequence of zero's, regardless of whether I used the speaker or microphone as the callback device.
I would be interested to hear from anyone else applying the same test.



```
' Store data in global variables for analysis using a timer event
A(1) = pNotify.guidEventContext.Data1
A(2) = pNotify.guidEventContext.Data2
A(3) = pNotify.guidEventContext.Data3
' There are 7 bytes in data4
Dim i As Byte
For i = 0 To 7
B(i) = pNotify.guidEventContext.Data4(i)
Debug.Print i, pNotify.guidEventContext.Data4(i)
Next i
```

David

----------


## fafalone

Ok so changing it to 2 does give it the two channels, but presumably the number of channels would be greater than two with surround sound audio right?

Core Audio is extremely finicky with callbacks and the two normal methods aren't working, so it'll take me some time to fix it for the general case, for now here's a version of the typelib with it defined as 2, I confirmed that gives values for both channels.

----------


## drpatt

> Ok so changing it to 2 does give it the two channels, but presumably the number of channels would be greater than two with surround sound audio right?
> 
> Core Audio is extremely finicky with callbacks and the two normal methods aren't working, so it'll take me some time to fix it for the general case, for now here's a version of the typelib with it defined as 2, I confirmed that gives values for both channels.


I have both channels working with your patch. Thank you!
I can see 2 possibilities with surround sound.
1) More than 2 channels on the same device base
2) Multiple bases for rear, side and sub woofer.
I don't use surround sound so cannot tell you how this PC works.
You are spot on with finicky. Absolutely no outside functions can be used in the callback.
Even debug seems to cause failure.
As does on error.
After much experimenting I now have:



```
' In a global module, for callback use
Public Cvol As Single
Public Cmuted As Long
Public Cchannels As Long

' Patch worked 21/01/2022
Public Cleft As Single
Public Cright As Single

Public A(1 To 3) As Long
Public B(8) As Byte
Public ShowContext As Boolean

' in cAudioEndpointVolumeCallback.cls
Option Explicit

Implements IAudioEndpointVolumeCallback

Private Sub IAudioEndpointVolumeCallback_OnNotify(pNotify As AUDIO_VOLUME_NOTIFICATION_DATA)
    If Cdisable Then Exit Sub

' transfer to global variables
Cmuted = pNotify.bMuted
Cvol = pNotify.fMasterVolume
Cchannels = pNotify.nChannels

    If ShowContext Then         ' copy Context variables
    A(1) = pNotify.guidEventContext.Data1
    A(2) = pNotify.guidEventContext.Data2
    A(3) = pNotify.guidEventContext.Data3
    Dim i As Byte
        For i = 0 To 7
        B(i) = pNotify.guidEventContext.Data4(i)
        Next i
    End If
    
' problem in oleexp.tlb - limited to channel 0
' Unless patched

Cleft = -0.01
Cright = -0.01
    If Cchannels > 1 Then
    Cleft = pNotify.afChannelVolumes(0)
    Cright = pNotify.afChannelVolumes(1)
    End If
    
    ' enable data processing in main form using timer, if not already enabled
    ' use timer to create interrupt in form1 thread
    If Form1.Tcallback.Enabled = False Then Form1.Tcallback.Enabled = True

End Sub
```

I can service the global callback data from a timer event fired by the callback.
I used GUIDToString() in mIID.bas to process the context data, having assumed that the data was in the UUID structure format :



```
    If ShowContext Then
    Dim i As Byte
    Dim context As UUID
    context.Data1 = A(1)
    context.Data2 = A(2)
    context.Data3 = A(3)
    
    msg = "Context: " + Str(A(1)) + "," + Str(A(2)) + "," + Str(A(3))
        For i = 0 To 7
        msg = msg + "," + Str(B(i))
        context.Data4(i) = B(i)
        Next i
    msg = msg + " : " + GUIDToString(context, True)
    showme msg       ' Write the data to the rich text box
    End If
```

The context data is not particularly useful for speaker and microphone.
I did get some consistant context field data from the advanced section of my Realteck digital output device.
However, this hardly helps in differentiating between microphone and speaker callbacks.

David

----------


## drpatt

> Ok so changing it to 2 does give it the two channels, but presumably the number of channels would be greater than two with surround sound audio right?
> 
> Core Audio is extremely finicky with callbacks and the two normal methods aren't working, so it'll take me some time to fix it for the general case, for now here's a version of the typelib with it defined as 2, I confirmed that gives values for both channels.


I have now succeeded in  creating  a method to service input and output device callbacks running concurrently.
Others might find this helpful.
The callback context values are a red herring!
My solution was to create a second class object duplicating the code in cAudioEndpointVolumeCallback, called MAudioEndpointVolumeCallback. (Watch out for the character limit in naming the class)
A public variable Ccall is set to "m" for the input class and "s" for the speaker class



```
Option Explicit
' MAudioEndpointVolumeCallback
' for inputs

Implements IAudioEndpointVolumeCallback

Private Sub IAudioEndpointVolumeCallback_OnNotify(pNotify As AUDIO_VOLUME_NOTIFICATION_DATA)
    If CdisableM Then Exit Sub

' transfer to global variables
Ccall = "m"
Cmuted = pNotify.bMuted
Cvol = pNotify.fMasterVolume
Cchannels = pNotify.nChannels

    If ShowContext Then         ' copy Context variables
    A(1) = pNotify.guidEventContext.Data1
    A(2) = pNotify.guidEventContext.Data2
    A(3) = pNotify.guidEventContext.Data3
    Dim i As Byte
        For i = 0 To 7
        B(i) = pNotify.guidEventContext.Data4(i)
        Next i
    End If
    
' problem in oleexp.tlb - limited to channel 0
' Unless patched

Cleft = -0.01
Cright = -0.01
    If Cchannels > 1 Then
    Cleft = pNotify.afChannelVolumes(0)
    Cright = pNotify.afChannelVolumes(1)
    End If
    
    ' enable data processing in main form using timer, if not already enabled
    ' use timer to create interrupt in form1 thread
    If Form1.Tcallback.Enabled = False Then Form1.Tcallback.Enabled = True

End Sub
```

Variables used for input and output callback setup must be unique:



```
Private cVolCallback As cAudioEndpointVolumeCallback     ' speakers
Private cVolCallbackM As MAudioEndpointVolumeCallback  ' mic

Private callDefCaptureMM As IMMDevice                       ' Mic callback capture
Private callVolMMM As IAudioEndpointVolume                 ' Mic callback volume

Private callDefRenderMM As IMMDevice                        ' speakers callback render
Private callVolMM As IAudioEndpointVolume                   ' speakers callback volume
```

To read the callback data I use a 1mS delay Timer control in the main form:
The timer is enabled by the callback.
It first disables itself, then determines the callback source by examining the public variable Ccall.


David

----------


## Symundo

Just an idea for oleexp.tlb:
When using interfaces derived from IUnknown you are using stdole.IUnknown

i.e.
interface IObjectSafety : stdole.IUnknown

This is of course the restricted version of IUnknown, where you can't use AddRef or Release functions in VB.
Wouldn't it be possible to use the unrestricted version of olelib.IUnknown and to make AddRef and Release visible and useable?

----------


## fafalone

Have you tried setting it to the unrestricted version?



```
Dim pUnk As oleexp.IUnknown
Set pUnk = whatever
pUnk.AddRef/Release
```

I don't recall if using Set will increment the reference counter, if that's an issue CopyMemory or vbaObjSet might be better.

You also might be able to avoid an issue with reference counter increments in some scenarios by setting with vbaObjSetAddRef, which as the name suggests will set it and increment the reference counter.

----------


## Symundo

Hi fafalone,

I have tried it in example with



```
    [
        odl,
        uuid(00020401-0000-0000-C000-000000000146),
    ]
    interface ITypeInfo : IUnknown {

...
```

instead of



```
    [
        odl,
        uuid(00020401-0000-0000-C000-000000000146),
    ]
    interface ITypeInfo : stdole.IUnknown {

...
```

There I get in VB the unrestricted functions AddRef/Release/QueryInterface and I can obviously use them. With your standard implementation these functions are not browsable and restricted.

It is much easier to have these functions available than making a query of IUnknown, when these functions are part of the queried interface anyway.
I use as well the very good typelib of Michel Rutten (VBVM6Lib), which has abbreviations like MemLong(ptr As Long) (Let/Get) or AsLong(pVar As Any), which allows very nice code for direct memory manipulation

----------


## Symundo

By the way: when I compile my version of your typelib ODLs (etc.) with MKTYPLIB I get an error in file tasksch.odl

Maybe I have an old version of it. I skipped this file while compiling.

C:\Projekt\Source\OLE Typelib Extension\oleexp47-source\source>cmd
Microsoft Windows [Version 10.0.22000.493]
(c) Microsoft Corporation. Alle Rechte vorbehalten.

C:\Projekt\Source\OLE Typelib Extension\oleexp47-source\source>MKTYPLIB.exe oleexp.odl
Microsoft (R) Type Library Generator  Version 2.20.4054
Copyright (c) Microsoft Corp. 1993-1995.  All rights reserved.

tasksch.odl (743) : fatal error M0001: Syntax error near line 743 column 21:  Type is not OleAutomation-compatible

----------


## fafalone

IIRC there were a few problems I ran into trying to inherit from the unrestricted IUnknown defined in the TLB, though I can't recall specifically what they were. Also I think if you do that you'd have to manually implement the IUnknown methods every time you used an interface with Implements. So that's unfortunately a non-starter as I shouldn't put out an update that breaks large amounts of existing code and requires major rewrites. But that's why open source is great, if that issue won't effect you, by all means compile an updated version!  :Smilie:  (But please remember to change the project GUID in oleexp.odl if you're going to post it publicly to avoid conflicts, probably a good idea to note the change in the title as well)

Line 743 in tasksch.odl is just [in] SYSTEMTIME* pstStart,, so I have no idea why that would error, especially since that's near the end of the compiling order and it had to have run into systemtime numerous other times; although the version of mktyplib that comes with VS6 is indeed the later 2.20.4230, so that could well be the issue.

----------


## Attilio

Hello to everyone.
There is some video tutorial of this Interface?
Best Regards

----------


## fafalone

No I haven't made video tutorials for anything, but I'm not exactly sure what you videos could tell you that the posts don't, except perhaps the few samples that are snippets instead of full projects. 

If you're new to VB6 there's video tutorials for other projects that will acquaint you with the basics of starting a project and doing simpler things rather than jumping right into COM interfaces; just search vb6 on YouTube.

----------


## taishan

Absolutely incredible work, thank you!

----------


## fafalone

*Project Updated to Version 5.0
*
I had meant to upload this a few weeks back due to major bugs with Core Audio interfaces, and just realized I hadn't. As the major version number suggests, there's also a lot of other updates:




> (oleexp 5.0 - Released 28 May 2022)
> -oleexp now includes all calls neccessary for TLB-based multithreading. Multithreading methods by The trick and Matthew Curland (PowerVB) have all calls included. For the latter, calls to the CreateThread API may need to be adjusted by pass ByVal, especially ByVal 0& for the LPSECURITY_ATTRIBUTES.
>     Note: As with any multithreading with TLB project, you'll need to be careful you don't have any functions used by the multithreading code declared as Public in your project, as those will always have higher priority than a TLB.
> -Added IInertiaProcessor, IManipulationProcessor, and IManipulationEvents interfaces with coclasses InertiaProcessor and ManipulationProcessor (for advanced handling of touch input). While these types are already in an addable reference, one uses unsigned longs, making that version incompatible with VB.
> -Added interface IShellIconOverlayManager and coclass CFSIconOverlayManager
> -Added SysReAllocStringW alias for SysReAllocString that supports a StrPtr pointer to properly support Unicode, finally relieving the need for a separate API declare for the LPWStrToStr function ubiquitous in oleexp projects (provided you add the W; I didn't want to break backwards compatibility by replacing the original). 
> -Added ILVRange undocumented ListView interface. This one was *really* undocumented; I was the first to publicly document it: 
> https://www.vbforums.com/showthread....T-and-ILVRange
> -Added interface IShellRunDll; Implements-compatible.
> ...

----------


## wqweto

Btw, the code section above is completely unreadable. Might want to try putting this in a quote section instead.

cheers,
</wqw>

----------


## loquat

any one update this tlb for 64bit vba?

----------


## fafalone

There was a post about it above in #202, but I don't know how reliable that is. A lot of types were changed from their original, and not all sizes doubled. I'd imagine it would likely have to be a top to bottom manual review, which there's just no way I have time for. 

Should just use 32bit Office. Are you really hitting the limits of it?

----------


## Dragokas

hi, what am I doing wrong with Shell init? I assumed it's analogue.


```
    'this works
    Dim objShell As Object
    Set objShell = CreateObject("Shell.Application")
    
    'this returning "Class does not support automation or does not support expected interface"
    Dim objShell As oleexp.Shell
    Set objShell = New oleexp.Shell
```

----------


## fafalone

I'll have to look into it. I assumed it would work because it's an unmodified copy+paste of the source (which was already VB-compatible) I just put in to avoid conflicts. 

The original IShellDispatch it all inherits from... perhaps it should be specified as stdole.IDispatch instead of oleexp's unrestricted IDispatch which I think has priority (and why most objects inherit from stdole.IUnknown instead of oleexp.IUnknown; I know I've had some problems with that (see post 214 above).



In other oleexp news, making it able to be compiled with midl (the first step to x64 versions) has been an unmitigated nightmare. midl force-includes oaidl.idl, which contains dozens of interfaces that need to redefined for VB compatibility, but midl doesn't allow redefinitions. Substituting a fake oaidl results in excluding *all* the built in types except for a few primitives (e.g. there is no LONG, you need typedef long LONG :Wink: ; and some of those are defined by absolute nightmares of C++ code that are nigh impossible to decipher. And then it looks like MS has put it deliberate efforts to prevent fake oaidls, because it rejects them if they're too small. After spending hours fixing that, midl has moved on to throwing obscure errors for which there is no solution I've found anywhere that won't cause serious compatibility problems with existing oleexp-using code.

----------


## wqweto

> I'll have to look into it. I assumed it would work because it's an unmodified copy+paste of the source (which was already VB-compatible) I just put in to avoid conflicts. 
> 
> The original IShellDispatch it all inherits from... perhaps it should be specified as stdole.IDispatch instead of oleexp's unrestricted IDispatch which I think has priority (and why most objects inherit from stdole.IUnknown instead of oleexp.IUnknown; I know I've had some problems with that (see post 214 above).
> 
> 
> 
> In other oleexp news, making it able to be compiled with midl (the first step to x64 versions) has been an unmitigated nightmare. midl force-includes oaidl.idl, which contains dozens of interfaces that need to redefined for VB compatibility, but midl doesn't allow redefinitions. Substituting a fake oaidl results in excluding *all* the built in types except for a few primitives (e.g. there is no LONG, you need typedef long LONG; and some of those are defined by absolute nightmares of C++ code that are nigh impossible to decipher. And then it looks like MS has put it deliberate efforts to prevent fake oaidls, because it rejects them if they're too small. After spending hours fixing that, midl has moved on to throwing obscure errors for which there is no solution I've found anywhere that won't cause serious compatibility problems with existing oleexp-using code.


Btw, IDL is pretty simple language to parse and ICreateTypeLib interface is not so complicated too :-))

cheers,
</wqw>

----------


## fafalone

C++ not so much, and cpp_quote makes that an issue. And the bigger problem is the way the midl compiler works. Do you have a solution besides all codebases depending on oleexp having to be updated to replace an unrestricted IUnknown with a new name?

Like what's the simple solution I'm missing to this:

midl\oleaut32.dll : error MIDL2020 : error generating type library : Could not add UUID, STDOLE2.TLB probably needs to be imported : IDispatch (0x800288C6)

when importing that is literally the first line of code?



```
[
    uuid(f9015e81-caac-45c0-94e8-42b7da5d7558),
    version(5.03),
	helpstring("OLEEXP - Modern Shell Interfaces for VB6, v5.03"),
	lcid(0x0)
]
library oleexp {

    // OLE Automation
    importlib("stdole2.tlb");
```

Edit: And actually, renaming the oleexp versions breaks other things. For instance the unrestricted IDispatch can't inherit from the new IUnknownUnrestricted (even though that's how it worked with MKTYPLIB).

interface IDispatchUnrestricted : IUnknownUnrestricted <- unresolved type declaration (yes, it's defined in a higher up file)

interface IDispatchUnrestricted : oleexp.IUnknownUnrestricted <- syntax error : expecting { near "."

If I forget about that and just let it inherit from stdole, I now arrive back at

"midl\oleaut32.dll : error MIDL2020 : error generating type library : Could not add UUID, STDOLE2.TLB probably needs to be imported : IUnknown (0x800288C6)"

*with no errors at all*, just a few warnings telling me optional params should be variants.

This is simple for you? I hope so because I really need some help here.

----------


## fafalone

FYI, if anyone wanted to pursue native 64bit development with code based on this project (or are just interested in migrating to IMO the future of the language), I have a successor project for twinBASIC that provides 64-bit compatible versions (using LongPtr so also still 32bit compatible), using the native language ability to define interfaces, as for the sake of my sanity I've given up with midl. tB will eventually support exporting TLBs, so there is a future expectation of VBA7 compatibility as well. 

[twinBASIC] tbShellLib - Shell Interface Library (x64-compatible successor to oleexp). Also on GitHub.

It's compiled into a .twinpack file you can add as a reference much the same as a TLB. This format allows the add-on modules to be built in, since you can mix interface defs and regular code. 

There's not 100% coverage of everything in oleexp yet, as I have to double check a whole bunch of longs that aren't obviously/obviously not pointers against the SDK/MSDN (and unfamiliar types-- can be tricky, HREFTYPE-- you'd think that's a handle needing LongPtr right? Wrong.), and up until recently there was a lot of work in syntax conversion, but a great deal is already done, particularly things that are common, or I have a sample project about. The VBForums link above has tables showing which interfaces are available. For special sets, Task Manager, ListView, SpellCheck, Shell Automation (except dispinterface), CoreAudio, and PortableDevices are all 100% available (as far as what was in oleexp), but DirectShow, WIC, and NetCon have not been started. Importantly, for the kinds of shell extensions that still work on Windows 7+, I've also made those available so native x64 versions of those can be produced.

The main incompatibilities are lack of coclass support, as a workaround, you can use CreateObject with the provided CLSID strings... e.g.
Dim pExpBrowse As ExplorerBrowser
Set pExpBrowse = New ExplorerBrowser
would be replaced by
Dim pExpBrowse As IExplorerBrowser = CreateObject(sCLSID_ExplorerBrowser)
(all such CLSID strings are predefined for any implemented interface with a coclass)

And also a lack of PreserveSig support... in the TLB, most things are defined as returning an HRESULT. VB drops this and turns it into a Sub. You can get around that by changing it to long; vb then recognizes it as a function and returns the HRESULT. This is not yet available in tB (for in-language defined interfaces, like coclasses it can consume TLBs with them). As a workaround, the HRESULT is available in Err.LastHResult:

Dim pUnk As IUnknownUnrestricted
Set pUnk = pShellItem
hr = pUnk.QueryInterface(IID_IParentAndItem, upi)

you would instead use

pUnk.QueryInterface(IID_IParentAndItem, upi)
hr = Err.LastHResult

----------


## fafalone

*Project Updated*

Apparently I thought I posted 5.02 but didn't. Updated to 5.03/oleexpimp 2.12. This fixes a critical bug with oleexpimp.tlb causing error 32810; which I still don't fully understand as it indicates the defs didn't match, even though they were unchanged. It may be related to compiling against the wrong oleexp.tlb version. Numerous minor, obscure bug fixes, some dating back to olelib, were also applied as I went through everything for tbShellLib (see previous comment). 

This version now includes a LongPtr type usable in VB6, so projects using oleexp don't need my recent VB6LongPtr.tlb typelib to add it.

Also added Implements-compatible versions of IPreviewHandler and related in oleexpimp.tlb, to implement a preview handler shell extension (demo coming soon).

Full changelog:



```
(oleexp 5.03 - Released 20 October 2022)
-Added IHWEventHandler2 and IDynamicHWHandler interfaces
-(Bug fix) IShellTaskScheduler::CountTasks was incorrect and ::Status was missing.
-Misc oscure bug fixes
-(oleexpimp) Critical bug fix: Apparently, when oleeximp is compiled, MKTYPLIB favors the oleexp.tlb (imported) in SysWOW64 over the current directory. This resulted in a subtle mismatch causing 'Unexpected error (32810)' when implementing certain interfaces, even though the interface definitions themselves hadn't changed at all.

(oleexp 5.02 - Released 13 September 2022)
-Added missing oaidl interfaces ITypeMarshal, ITypeLibRegistration, ITypeLibRegistrationReader, ITypeChangeEvents, and ITypeMarshal.
-ICategoryProvider.CanCategorizeOnSCID needs to provide return value when used as a consumer. The all-HRESULT version is now in oleexpimp.tlb for providers.
-Added FILEOP_FLAGSEX with the FOFX_ values; this were already in the IFO_Flags enum with a custom prefix for displaying a combined enum for IFileOperation without showing them for SHFileOperation, but I thought they should also exist under the documented names.
-A few misc bug fixes to rarely used interfaces.
-Added a public LongPtr type; it's just an alias for Long but the idea is to enable writing code that can reused in 64bit VBA or twinBASIC.
-(oleexpimp) Added Implements-compatible versions of IPreviewHandler, IInitializeWithStream, IInitializeWithItem, and IInitializeWithFile for use in creating preview handler shell extensions.
```

----------


## fafalone

*Project Updated
*
oleexp.tlb was missing some shell automation interfaces I could have sworn were in it; some were in oleexpimp.tlb, but some were in neither. Also added an expanded set of Windows Search interfaces, and some security page related interfaces.



```
(oleexp 5.1 - Released 05 November 2022)
-Several interfaces from shell automation were missing or only located in oleexpimp
-Added ISecurityInformation[2, 3, 4]/CreateSecurityPage API interfaces
-Added Windows Search API interfaces
```

----------

