dcsimg
Page 2 of 2 FirstFirst 12
Results 41 to 51 of 51

Thread: [VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handler

  1. #41

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    2,080

    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.

  2. #42
    PowerPoster
    Join Date
    Jun 2013
    Posts
    3,903

    Re: [VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handle

    Quote Originally Posted by fafalone View Post
    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

  3. #43

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    2,080

    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.

  4. #44
    Fanatic Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    892

    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>

  5. #45

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    2,080

    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.

  6. #46
    Fanatic Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    892

    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>

  7. #47
    New Member
    Join Date
    Feb 2018
    Posts
    6

    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?

  8. #48
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,137

    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.

  9. #49
    PowerPoster
    Join Date
    Jun 2013
    Posts
    3,903

    Re: [VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handle

    Quote Originally Posted by Stu2 View Post
    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

  10. #50
    New Member
    Join Date
    Feb 2018
    Posts
    6

    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.

  11. #51

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    2,080

    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

Page 2 of 2 FirstFirst 12

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
  •  



Featured


Click Here to Expand Forum to Full Width