|
-
Dec 7th, 2018, 11:18 PM
#41
Re: [VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handle
You can try making sure the handler is registered properly with a utility like ShellExView... but I've been getting the same problem on my system lately and they appear to be properly installed. It's a tough thing to address... that error is thrown on the very first step after getting the CLSID (CoCreateInstance); it's just that one call. Maybe adjust the CLSCTX_ flags? Are there any alternatives to CoCreateInstance that could be tried (I'm not sure in this situation since the CLSIDs aren't constants, though if you wanted to lock it into your system you could try adding a coclass to a TLB and creating it with New.
-
Dec 7th, 2018, 11:41 PM
#42
Re: [VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handle
 Originally Posted by fafalone
Maybe adjust the CLSCTX_ flags? ...
Yep, the AcroReader will need to be instantiated as an OutOfProcess COMServer to work properly.
Below comes Class-Code I've written a while ago (not using any typelib - though depending on a few helper-methods of the RC5) -
feel free to rip out what you want (and take a look at the last Helper-Routine in the Class and its Optional Param):
cPreviewHandler
Code:
Option Explicit
Private Declare Function CLSIDFromString Lib "ole32" (ByVal lpszGuid As Long, pGuid As Any) As Long
Private Declare Function CoCreateInstance Lib "ole32" (rclsid As Any, ByVal pUnkOuter&, ByVal dwClsContext&, riid As Any, ppObj As stdole.IUnknown) As Long
Private Declare Function CreateStreamOnHGlobal Lib "ole32" (ByVal hGlob&, ByVal fDeleteOnRelease&, ppstm As stdole.IUnknown) As Long
Private Declare Function AssocQueryStringW Lib "shlwapi" (ByVal Flags&, ByVal Astr&, ByVal sExt&, ByVal sIID&, ByVal sOut&, cOut&) As Long
Private Enum eIPrevH
QueryInterface '(reqIID, ppObj) HRESULT
AddRef '() int
Release '() int
SetWindow '(hwnd, pRect) HRESULT
SetRect '(pRect) HRESULT
DoPreview '() HRESULT
Unload '() HRESULT
SetFocus '() HRESULT
QueryFocus '(phWnd) HRESULT
TranslateAccelerator '(pMSG) HRESULT
End Enum
Const sIID_IPreviewHandler$ = "{8895b1c6-b41f-4c1c-a562-0d564250836f}" 'see VTable-Method-Definitions in the above Enum
Const sIID_IPreviewHandlerVisuals$ = "{196bf9a5-b346-4ef0-aa1e-5dcdb76768b1}" 'IPreviewHandlerVisuals (only one method is used:
Const sIID_IInitializeWithFile$ = "{b7d14566-0509-4cce-a71f-0a554233bd9b}" 'only one Method: Initialize(pszFilePath, grfMode) HRESULT
Const sIID_IInitializeWithStream$ = "{b824b49d-22ac-4161-ac8a-9916e8fa3f7f}" 'only one Method: Initialize(pstream, grfMode) HRESULT
Private mPVH As stdole.IUnknown, Stream As stdole.IUnknown
Private IID_IWF(15) As Byte, IID_IWS(15) As Byte, IID_PHV(15) As Byte
Private Sub Class_Initialize()
CLSIDFromString StrPtr(sIID_IInitializeWithFile), IID_IWF(0)
CLSIDFromString StrPtr(sIID_IInitializeWithStream), IID_IWS(0)
CLSIDFromString StrPtr(sIID_IPreviewHandlerVisuals), IID_PHV(0)
End Sub
Public Function ShowPreviewForFile(FileName As String, ByVal ParentHwnd As Long, x, y, dx, dy) As Long
Dim sClsIdHandler As String, Rct(0 To 3) As Long, HRes As Long
Dim FContent() As Byte, BytesWritten As Long
Dim IWF As stdole.IUnknown, IWS As stdole.IUnknown, PHV As stdole.IUnknown
If ObjPtr(mPVH) Then
New_c.vtblCall vbLong, ObjPtr(mPVH), eIPrevH.Unload
Set mPVH = Nothing
Set Stream = Nothing
End If
sClsIdHandler = GetHandlerClsID(FileName)
If Len(sClsIdHandler) = 0 Then Err.Raise vbObjectError, , "Couldn't find a PreviewHandler-IID for this FileType"
If mPVH Is Nothing Then
Set mPVH = CreateInstanceUnk(sClsIdHandler, sIID_IPreviewHandler, True)
If mPVH Is Nothing Then Err.Raise vbObjectError, , "Couldn't create the PreviewHandler-Instance"
End If
'Now test for available Init-Interfaces: IInitializeWithFile first, ...
If New_c.vtblCall(vbLong, ObjPtr(mPVH), eIPrevH.QueryInterface, VarPtr(IID_IWF(0)), VarPtr(IWF)) = 0 Then
'call IInitializeWithFile.Initialize (at vTable-Index = 3)
If New_c.vtblCall(vbLong, ObjPtr(IWF), 3, StrPtr(FileName), 0&) Then Err.Raise vbObjectError, , "Couldn't initialize with File: " & FileName
'... and IInitializeWithStream second
ElseIf New_c.vtblCall(vbLong, ObjPtr(mPVH), eIPrevH.QueryInterface, VarPtr(IID_IWS(0)), VarPtr(IWS)) = 0 Then
CreateStreamOnHGlobal 0, 1, Stream
If Stream Is Nothing Then Err.Raise vbObjectError, , "Couldn't create the IStream-Instance"
FContent = New_c.FSO.ReadByteContent(FileName)
' call IStream.Write (at vTable-Index = 4)
HRes = New_c.vtblCall(vbLong, ObjPtr(Stream), 4, VarPtr(FContent(0)), UBound(FContent) + 1, VarPtr(BytesWritten))
If HRes Then Err.Raise HRes
If BytesWritten <> UBound(FContent) + 1 Then Err.Raise vbObjectError, , "Couldn't write all Filedata to the IStream-Instance"
'call IInitializeWithStream.Initialize (at vTable-Index = 3)
If New_c.vtblCall(vbLong, ObjPtr(IWS), 3, ObjPtr(Stream), 0&) Then Err.Raise vbObjectError, , "Couldn't initialize with Stream"
Else 'the above attempts failed
Err.Raise vbObjectError, , "Neither IInitializeWithFile nor IInitializeWithStream are supported"
End If
'we are through (basically) - what's left, is calling SetWindow and DoPreview
HRes = New_c.vtblCall(vbLong, ObjPtr(mPVH), eIPrevH.SetWindow, ParentHwnd, VarPtr(Rct(0)))
If HRes Then Err.Raise HRes, , "IPreviewHandler.SetWindow was not successful"
If New_c.vtblCall(vbLong, ObjPtr(mPVH), eIPrevH.QueryInterface, VarPtr(IID_PHV(0)), VarPtr(PHV)) = 0 Then
New_c.vtblCall vbLong, ObjPtr(PHV), 3, vbWhite '<- call SetBackgroundColor when IPreviewHandlerVisuals exists
End If
MovePreviewWindow x, y, dx, dy
HRes = New_c.vtblCall(vbLong, ObjPtr(mPVH), eIPrevH.DoPreview)
If HRes Then Err.Raise HRes, , "IPreviewHandler.DoPreview was not successful"
End Function
Public Sub MovePreviewWindow(x, y, dx, dy)
Dim Rct(0 To 3) As Long
Rct(0) = x: Rct(2) = x + dx
Rct(1) = y: Rct(3) = y + dy
If ObjPtr(mPVH) Then New_c.vtblCall vbLong, ObjPtr(mPVH), eIPrevH.SetRect, VarPtr(Rct(0))
End Sub
Private Function GetHandlerClsID(FileName As String) As String
Dim sExt As String
sExt = Mid$(FileName, InStrRev(FileName, ".") + 1)
GetHandlerClsID = GetRegEntryForExt("." & sExt)
If Len(GetHandlerClsID) = 0 Then GetHandlerClsID = GetRegEntryForExt(sExt & "file")
End Function
Private Function GetRegEntryForExt(sExt As String) As String
Const ASSOCSTR_SHELLEXTENSION = 16
GetRegEntryForExt = Space$(64)
AssocQueryStringW 0, ASSOCSTR_SHELLEXTENSION, StrPtr(sExt), StrPtr(sIID_IPreviewHandler), StrPtr(GetRegEntryForExt), 64
GetRegEntryForExt = Trim$(Left$(GetRegEntryForExt, 38))
End Function
Private Sub Class_Terminate()
If ObjPtr(mPVH) Then New_c.vtblCall vbLong, ObjPtr(mPVH), eIPrevH.Unload
Set mPVH = Nothing
Set Stream = Nothing
End Sub
Private Function CreateInstanceUnk(ClsID As String, IID As String, Optional ByVal OutOfProcess As Boolean) As stdole.IUnknown
Const CLSCTX_INPROC_SERVER = 1, CLSCTX_LOCAL_SERVER = 4
Static bClsID(0 To 15) As Byte, bIID(0 To 15) As Byte, HRes As Long
If Len(ClsID) <> 38 Or Len(IID) <> 38 Then Exit Function
CLSIDFromString StrPtr(ClsID), bClsID(0)
CLSIDFromString StrPtr(IID), bIID(0)
HRes = CoCreateInstance(bClsID(0), 0, IIf(OutOfProcess, CLSCTX_LOCAL_SERVER, CLSCTX_INPROC_SERVER), bIID(0), CreateInstanceUnk)
If HRes Then Err.Raise HRes
End Function
HTH
Olaf
-
Dec 8th, 2018, 05:22 AM
#43
Re: [VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handle
Not sure if it will work for Stu2 but changing the argument to CLSCTX_LOCAL_SERVER exclusively had no effect on my PDF previewer, same unspecified error, and the .docx previewer returns an odd error... 0x8001010A (RPC_E_SERVERCALL_RETRYLATER).
Excel and PowerPoint previewers still work fine.
No difference between compiled exe and IDE run.
-
Dec 8th, 2018, 05:46 AM
#44
Re: [VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handle
@fafalone: Just FYI, notice how Olaf declares IIDs/GUIDs -- IID_IWF(15) As Byte and notice how these get initialized -- CLSIDFromString StrPtr(sIID_IInitializeWithFile), IID_IWF(0)
That is why I find your DEFINE_UUID translation of C/C++ macro verbose to write and use, and then the definition of GUID struct "by the book" IMO is utterly inconvenient. Why would anyone need a separate mIID.bas just to initialize some static 16-bytes opaque blobs? :-))
cheers,
</wqw>
-
Dec 8th, 2018, 10:26 AM
#45
Re: [VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handle
There's no difference between the initialization methods; both troubled handlers return the same errors.
The way I have things in mIID.bas is largely because that's how it was in legacy projects, I added new IIDs I needed in the same format as the ones I was using. To me it's really no more or less inconvenient than the other ways, and had inertia. Having to go redefine the dozens I started with would have been inconvenient (the rest are auto-generated by parsing the tlb source or pasting a guid into a generator, there is no writing them. Usage cannot possibly be more convienient, it's just typing the IID/BHID/etc you need.), and having a module to drop in with every GUID like that is super convenient over having to cut and paste individual defs every time when you use a lot of them. The idea behind recommending it for even small projects is that these demos are always for pieces of larger applications, so never having to worry about initializing IIDs, BHIDs, and FOLDERIDs (and PKEYs with the other module) becomes a significant time saver--- take my shell browser control, I spent tons of time just having to go over to mIID and copy over new GUIDs every other function.
So tl;dr, DEFINE_UUID is used because that's how others started things (oleexp and all my shell programming really, is standing on shoulders to look farther). mIID is used because it's super convenient to have everything readily defined and maximum code clarity as projects get larger. And init method almost never makes a difference to the API/interface it's passed to.
Last edited by fafalone; Dec 8th, 2018 at 10:30 AM.
-
Dec 9th, 2018, 03:38 AM
#46
Re: [VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handle
Yes, I see your point. oleexp is a very valuable project to the community.
Keep up the good work!
cheers,
</wqw>
-
Dec 9th, 2018, 07:07 PM
#47
New Member
Re: [VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handle
I changed the argument to CLSCTX_LOCAL_SERVER.
Code:
hr = CoCreateInstance(tHandler, 0, CLSCTX_LOCAL_SERVER, IID_IPreviewHandler, ipv)
This seems to work for me, though I've only tried it on 1 PC. I'll do some more testing on end-user PCs.
So is there a way of knowing whether I should be using CLSCTX_LOCAL_SERVER exclusively or not?
Or should I just test for a .pdf extension?
-
Dec 10th, 2018, 03:02 PM
#48
Re: [VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handle
This may not be convenient for oleexp, but I keep string constants of GUID/IIDs stored in my Direct2D typelib.
-
Dec 10th, 2018, 06:35 PM
#49
Re: [VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handle
 Originally Posted by Stu2
So is there a way of knowing whether I should be using CLSCTX_LOCAL_SERVER exclusively or not?
Or should I just test for a .pdf extension?
For me, it works with the CLSCTX_LOCAL_SERVER setting for PDF- and Font-Viewing and also the Office-stuff.
To handle potential "exceptions to the rule" (to harden it a bit for cases as reported by fafalone in #43) -
I'd start out with a call that uses CLSCTX_LOCAL_SERVER (since it does not seem to "block" all that long, if something goes wrong) -
and then take a look at the HResult-return-value.
If there was an error - you could try a second "fallback-call" using CLSCTX_INPROC_SERVER as a follow-up-step...
Olaf
-
Dec 11th, 2018, 07:30 AM
#50
New Member
Re: [VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handle
OK, I've tried the sample program (modified to use CLSCTX_LOCAL_SERVER only) on a few 'real-life' end-user PCs.
It worked on everything I tried - including Win 10 + Adobe Reader XI, Win 10 + Adobe Reader DC, Win 7 + Adobe Reader DC. Mainly 64 bit OSs, plus a couple of Win 7 32bit.
Other common apps (Word, Excel, etc.) worked too.
I think I'll follow Olaf's suggestion and use CLSCTX_LOCAL_SERVER only, then if an error occurs try CLSCTX_INPROC_SERVER.
Here is the debug output from a PDF preview...
Code:
using isi
sFile=C:\Test\00000017.PDF
sExt=.PDF
Got handler CLSID; attempting to create IPreviewHandler
IInitializeWithFile not supported.
IInitializeWithItem not supported.
Attempting to use IStream
Got file size=405169
QI.hr=0
SetWindow hr=0
DoPreview hr=0
Last edited by Stu2; Dec 11th, 2018 at 07:35 AM.
-
Dec 14th, 2018, 12:32 AM
#51
Re: [VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handle
So after adding both fallback options, my PDF previewer is once again working.
Resolved!
MS Word wasn't the default handler for .docx or anything else on my system, so when opened wouldn't do anything until you acknowledged the nag prompt asking you to change or ignore that. I conclude that since the preview handler functionality is in WINWORD.EXE, the full blown main app, that the 'Busy' error was this prompt blocking even shell previews from loading, despite not being possible to see it without opening the program normally and not as a shell extension. As soon as I closed it with 'don't ask again' checked, the preview handler functionality once again worked.
Of course, still many thanks for the idea to try both flags, since the PDF previewer had a different problem.
The original detailed issue report remains below in case anyone else is ever searching for this error.
But .docx is still coming back with the same error. It's just so odd, it's the standard handler that came with MS Office (2013, 64bit, Win7), just like the ones for XLSX and PPTX, and both of those work quickly and perfectly (and ShellExView shows zero difference in version number, modification date, or anything else). The handler isn't loaded anywhere else, nor is any Office app, such that the odd 'retry later' error desc. might make sense--- the first time at least, because WINWORD.EXE does launch, then hangs until force closed, but does not have a handle to the target file.
The worst part, it already caused the whole app to hang for a minute while it tried, so now it's 2-3x as long (depending if I also try them in combination with Or).
The LOCAL (and LOCAL Or INPROC) hr is 0x8001010A (RPC_E_SERVERCALL_RETRYLATER) (Also, this is the way xlsx and pptx load)
The INPROC hr is different; 0x80040154 (Class not registered)
Any ideas guys?
The fallback path I wound up using is:
Code:
hr = GetHandlerCLSID(sExt, tHandler)
If hr = 1 Then
DebugAppend "Got handler CLSID; attempting to create IPreviewHandler"
hr = CoCreateInstance(tHandler, 0, CLSCTX_LOCAL_SERVER Or CLSCTX_INPROC_SERVER, IID_IPreviewHandler, ipv)
If hr <> S_OK Then
DebugAppend "CoCreateInstance failed, trying alternate args... (hr=0x" & Hex$(hr) & ")"
hr = CoCreateInstance(tHandler, 0, CLSCTX_LOCAL_SERVER, IID_IPreviewHandler, ipv)
DebugAppend "LOCAL hr=0x" & Hex$(hr)
If hr <> S_OK Then
hr = CoCreateInstance(tHandler, 0, CLSCTX_INPROC_SERVER, IID_IPreviewHandler, ipv)
DebugAppend "INPROC hr=0x" & Hex$(hr)
End If
End If
Last edited by fafalone; Dec 14th, 2018 at 01:10 AM.
-
Jan 6th, 2020, 05:14 AM
#52
Re: [VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handle
I've been using IPreviewHandler to view Office documents.
Now I've found on a new installation that uses Outlook 2019 64bit, viewing Outlook .msg files doesn't work. (ShellExecute will display the .msg file OK).
It doesn't work in the Windows File Explorer preview pane either.
It appears Microsoft 'forgot' a 64bit previewer.
Does anyone have a fix to enable previewing Outlook .msg files when 64bit Outlook is installed?
Last edited by VB6 Programming; Jan 7th, 2020 at 02:48 AM.
-
Jan 7th, 2020, 07:08 PM
#53
Re: [VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handle
All Office docs or just Outlook?
With the viewer for docx, xlsx, etc, it's because 64-bit Office versions install a 64-bit msoshext.dll that can't be loaded by 32-bit apps, but if it's not working in Explorer the handler might have somehow got deleted all together... check if there's still a registered preview handler and if the file still physically exists? (Nirsoft's Shell Extension Viewer is great for this if you don't want to write code or go poking about the registry)
-
Mar 12th, 2020, 10:10 AM
#54
Re: [VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handle
 Originally Posted by fafalone
All Office docs or just Outlook?
Word and Excel preview OK. It is just Outlook (.msg) that doesn't preview when 64 bit MS Office 2019 (Outlook) is installed.
Here is the fix I used:
In Regedit, find the registry entry:
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{53BEDF0B-4E5B-4183-8DC9-B844344FA104}
The AppID for this is set as follows {534A1E02-D58F-44f0-B58B-36CBED287C7C}
Change the AppID to {6d2b5079-2f0b-48dd-ab7f-97cec514d30b}
NOTE 1: On Windows 10 I found you weren't allowed to Edit/Write the AppID's contents.
To give yourself permission to do this, right click on the {53BEDF0B-4E5B-4183-8DC9-B844344FA104} (in the left-hand column), choose 'Permissions...', press the ‘Advanced’ button, then click the ‘Change’ link.
Then in the ‘Select User or Group’ window, in the ‘Enter the object name to select’ box type your Windows user account (or your email address if you have a Windows account) and press the ‘Check Names’ button.
Then in the ‘Permissions’ window select the Users group and choose the ‘Allow’ check box next to the ‘Full Control’ permission (or just give permission to your own account if you prefer). Click ‘OK’
In Registry Editor you should now be able to change the AppID.
NOTE 2: Only do this if you have 64 bit Outlook (or 64 bit Office) installed. If you have 32 bit Outlook installed on 64 bit Windows do not do this.
-
Jan 15th, 2024, 12:20 PM
#55
Re: [VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handle
There's now a 64-bit compatible version of this project for twinBASIC!
https://github.com/fafalone/PreviewHandler
In addition to 64bit support, I updated the code to work better with the crappy Adobe PDF handler while not breaking the crappy MS TXT Preview handler, and additionally fixed an issue where local server created objects escape the automatic DPI scaling applied to your dpi unaware app.These changes can be backported to VB6 with a little effort, but I haven't done so yet.
Last edited by fafalone; Jan 16th, 2024 at 10:03 AM.
-
Jul 13th, 2025, 08:35 AM
#56
Fanatic Member
Re: [VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handle
Absolute last man on the ball 
But I this API SHCreateStreamOnFile can replace the CreateFile/ReadFile/Closehandle process.
It's the same but in one API.
Code:
Public Declare Function SHCreateStreamOnFile Lib "shlwapi" Alias "SHCreateStreamOnFileW" (ByVal pszFile As Long, ByVal grfMode As STGM, ppSTM As Any) As Long
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|