# VBForums CodeBank > CodeBank - Visual Basic 6 and earlier >  [VB6] IPreviewHandler: Show non-image file previews from any reg'd preview handler

## fafalone

*IPreviewHandler Example*

Many file types have registered preview handlers, not just images. Typically documents, videos, fonts, music, even registry files, all have a preview handler that you can put on your application with little effort.

*Project Updated: 03 Dec 2015*
-With the original version of this project, font previews showed all black boxes. This is a bug in the Windows font previewer, and can be fixed by resetting the background with the IPreviewHandlerVisuals interface. NOTE: It's very hard to deal with installed fonts; they can't be selected via the open dialog, and can't be expressed as a shell item like even objects like the control panel or my computer can, so: To preview installed fonts, you'll have to manually enter the path to the font file (C:\Windows\Fonts\whatever.ttf) and click preview. Font files not located in \Windows\Fonts can be selected and previewed normally.

-The update also adds an icon preview function, just to show how to make a comprehensive previewer (like the existing image previews in the original, IPreviewHandler isn't used unless your system has a custom one installed).

_This update requires oleexp v4.0 or higher and mIID.bas from the oleexp download._

*Requirements*

-Reference to oleexp, v4.0 or higher. oleexp.tlb is required for the IDE only, you do not need to distribute it with a compiled program.
-oleexp addon mIID.bas - Found in the oleexp zip.

-Recently an issue was discovered where some preview handlers may require a manifest for Common Controls 6.0. So far only Outlook 2007 .msg files have this issue (probably related to their also being the only ones using the more modern IInitializeWithItem), but there may be others. See LaVolpe's excellent project for making manifests for your app.

_Compatibility_
The current sample project won't run on XP, but if you replace the IFileDialog file selection dialog and possibly a few other things, the core IPreviewHandler and IPreviewHandlerVisuals interfaces was available in XP.

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

The registry holds registered preview handlers in the HKEY_CLASSES_ROOT\filetype\ShellEx\{8895b1c6-b41f-4c1c-a562-0d564250836f} key, but as a shortcut you can also use the AssocQueryString API with ASSOCSTR_SHELLEXTENSION as the sample project shows. 

Here's the basic code to show a preview:


```
Private Sub ShowPreviewForFile(isi As IShellItem, hWnd As Long, rc As RECT, objpic As Object, Optional sFileIn As String = "")
Dim iif As IInitializeWithFile
Dim iis As IInitializeWithStream
Dim iisi As IInitializeWithItem
Dim pVis As IPreviewHandlerVisuals
Dim pUnk As oleexp.IUnknown
Dim hr As Long
Dim sFile As String, sExt As String
Dim lp As Long
Dim tHandler As UUID
On Error GoTo e0

If (isi Is Nothing) Then
    Debug.Print "no isi"
    If sFileIn <> "" Then
        sFile = sFileIn
    End If
Else
    Debug.Print "using isi"
    isi.GetDisplayName SIGDN_FILESYSPATH, lp
    sFile = BStrFromLPWStr(lp)
End If
    Debug.Print "sFile=" & sFile
    sExt = Right$(sFile, (Len(sFile) - InStrRev(sFile, ".")) + 1)
    Debug.Print "sExt=" & sExt

If sExt = "" Then Exit Sub

If (ipv Is Nothing) = False Then
    ipv.Unload
    Set ipv = Nothing
End If


hr = GetHandlerCLSID(sExt, tHandler)
If hr = 1 Then
    Debug.Print "Got handler CLSID; attempting to create IPreviewHandler"
    hr = CoCreateInstance(tHandler, 0, CLSCTX_INPROC_SERVER Or CLSCTX_LOCAL_SERVER, IID_IPreviewHandler, ipv)
    If (ipv Is Nothing) Then
        Debug.Print "Failed to create IPreviewHandler interface, hr=" & hr
        Exit Sub
    End If
    'Set iisi = ipv 'this normally can be used in place of Set pUnk / .QueryInterface, but we need the HRESULT
    Set pUnk = ipv
'    Set iif = ipv
    If pUnk.QueryInterface(IID_IInitializeWithFile, iif) = S_OK Then
        hr = iif.Initialize(sFile, STGM_READ)
        GoTo gpvh
    Else
        Debug.Print "IInitializeWithFile not supported."
    End If

    'use IStream
    Dim hFile As Long
    Dim pstrm As IStream
    Dim lpGlobal As Long
    Dim dwSize As Long
    Debug.Print "Attempting to use IStream"
'                Set iis = ipv
    Set pUnk = ipv
    hr = pUnk.QueryInterface(IID_IInitializeWithStream, iis)
    If (iis Is Nothing) Then
        Debug.Print "IInitializeWithStream not supported."
        Set pUnk = ipv
        If pUnk.QueryInterface(IID_IInitializeWithItem, iisi) = S_OK Then
            Debug.Print "IInitializeWithItem supported."
            If (isi Is Nothing) = False Then
                hr = iisi.Initialize(isi, STGM_READ)
                GoTo gpvh
            Else
                Debug.Print "Don't have needed IShellItem."
            End If
        Else
            Debug.Print "IInitializeWithItem not supported. No more initializers."
            GoTo out
        End If
    Else
        hFile = CreateFile(sFile, FILE_READ_DATA, FILE_SHARE_READ, ByVal 0&, OPEN_EXISTING, 0, 0)
        If hFile Then
            dwSize = GetFileSize(hFile, ByVal 0&)
            Debug.Print "Got file size=" & dwSize
            If dwSize = 0 Then Exit Sub
            hGlobal = GlobalAlloc(GPTR, dwSize)
            lpGlobal = GlobalLock(hGlobal)
            If lpGlobal Then
                Call ReadFile(hFile, ByVal lpGlobal, dwSize, dwSize, ByVal 0&)
                Call GlobalUnlock(hGlobal)
                Call CreateStreamOnHGlobal(hGlobal, 1, pstrm)
                hr = iis.Initialize(pstrm, STGM_READ)
            End If
            Call CloseHandle(hFile)
        End If
    End If


gpvh:
    hr = ipv.SetWindow(hWnd, rc)
    Debug.Print "SetWindow hr=" & hr
    hr = ipv.DoPreview()
    Debug.Print "DoPreview hr=" & hr
    Dim piunk As oleexp.IUnknown
    Set piunk = ipv
    hr = piunk.QueryInterface(IID_IPreviewHandlerVisuals, pVis)
    If (pVis Is Nothing) = False Then
        Debug.Print "Handler implements IPreviewHandlerVisuals; setting bk color to white"
        pVis.SetBackgroundColor &HFFFFFF
    End If
    If (isi Is Nothing) = False Then
        isi.GetDisplayName SIGDN_NORMALDISPLAY, lp
        sFile = BStrFromLPWStr(lp)
    End If
    Label1.Caption = "DoPreview called for " & sFile
Else
    'images and videos aren't handled that way normally, so we'll do it another way
    Debug.Print "No registered handler; trying alternate method for images..."
    Dim lPcv As Long
    lPcv = FilePtypeL(sExt)
    Debug.Print "Perceived type=" & lPcv
    If lPcv = PERCEIVED_TYPE_IMAGE Then
        If Right$(sFile, 4) = ".ico" Then
            'the below methods don't properly render icons transparent
            'so we'll use a different method that does
            If DoIcoPreview(sFile, objpic.hDC, 32) = -1 Then
                GoTo gfthm
            End If
            objpic.Refresh
            Label1.Caption = "Manually generated preview for icon."
            GoTo out
        Else
gfthm:
            Dim hbm As Long
            hbm = GetFileThumbnail(sFile, 0, objpic.ScaleWidth, objpic.ScaleHeight)
            Debug.Print "hbm=" & hbm
            objpic.Cls
            hBitmapToPictureBox objpic, hbm
            objpic.Refresh
            Label1.Caption = "Manually generated preview for image."
        End If
    Else
        Label1.Caption = "Could not find registered preview handler for file type."
    
    End If
End If
out:

Set iisi = Nothing
Set iif = Nothing
Set iis = Nothing

On Error GoTo 0
Exit Sub

e0:
Debug.Print "ShowPreviewForFile.Error->" & Err.Description & " (" & Err.Number & ")"
End Sub
```

It's really simpler than it looks; the hard part it the initialization, a preview handler typically only supports 1 out of the 3 IInitialize__ interfaces, so we have to go through all of them, and IStream ones are too common to omit, and that's the only complex part.

It may vary from system to system, but plain images generally aren't supported with this method, but there's a large variety of ways to preview them.

----------------
_Project based on Using Preview Handlers in Windows Vista_


UPDATE: The image file preview in the sample project won't work on XP, here's an alternative that will:


```
Public Declare Function SHCreateShellItem Lib "shell32" (ByVal pidlParent As Long, ByVal psfParent As Long, ByVal pidl As Long, ppsi As IShellItem) As Long

Public Function GetFileThumbnail2(sFile As String, pidlFQ As Long, CX As Long, CY As Long) As Long
'alternate method
Dim isi As IShellItem
Dim pidl As Long
Dim iei As IExtractImage
Dim hBmp As Long
Dim uThumbSize As oleexp.SIZE
    uThumbSize.CX = CX
    uThumbSize.CY = CY
Dim sRet As String
Dim uThumbFlags As IEIFlags
On Error GoTo e0

If pidlFQ Then
    Call SHCreateShellItem(0&, 0&, pidlFQ, isi)
Else
    pidl = ILCreateFromPathW(StrPtr(sFile))
    Call SHCreateShellItem(0&, 0&, pidl, isi)
    Call CoTaskMemFree(pidl) 'also a change that should have been made, had originally used ILFree, which shouldn't be used on Win2k+
End If

isi.BindToHandler ByVal 0&, BHID_ThumbnailHandler, IID_IExtractImage, iei
If (iei Is Nothing) Then
    Debug.Print "GetFileThumbnail2.Failed to create IExtractImage"
    Exit Function
End If

            uThumbFlags = IEIFLAG_ORIGSIZE
            sRet = String$(MAX_PATH, 0)
            iei.GetLocation StrPtr(sRet), MAX_PATH, 0&, uThumbSize, 32, uThumbFlags
hBmp = iei.Extract()
GetFileThumbnail2 = hBmp
Set iei = Nothing

On Error GoTo 0
Exit Function

e0:
Debug.Print "GetFileThumbnail2.Error->" & Err.Description & " (" & Err.Number & ")"
End Function

'NOTE: The below are not needed if your project includes oleexp's mIID.bas
Public Function BHID_ThumbnailHandler() As UUID
'{0x7B2E650A, 0x8E20, 0x4F4A, 0xB0,0x9E, 0x65,0x97,0xAF,0xC7,0x2F,0xB0}
Static iid As UUID
 If (iid.Data1 = 0) Then Call DEFINE_UUID(iid, &H7B2E650A, &H8E20, &H4F4A, &HB0, &H9E, &H65, &H97, &HAF, &HC7, &H2F, &HB0)
 BHID_ThumbnailHandler = iid
End Function
Public Function IID_IExtractImage() As UUID
'{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}
Static iid As UUID
 If (iid.Data1 = 0) Then Call DEFINE_UUID(iid, &HBB2E617C, CInt(&H920), CInt(&H11D1), &H9A, &HB, &H0, &HC0, &H4F, &HC2, &HD6, &HC1)
  IID_IExtractImage = iid
End Function
```

*UPDATE 1 July 2016* - As was pointed out below by Steve-N, SHCreateItemFromIDList is actually Vista+ too, image preview code in this post has been changed to use SHCreateShellItem instead, which MSDN states in available as of XP SP1.

*UPDATE 24 Nov 2016* - Attached project and code in post updated to reference oleexp.tlb v4.0 or higher. Updates in post incorporated into project.

----------


## Tech99

Tested your iPreviewHandler sample, by trying to preview truetype fonts. IPreviewHandler gets TTF filetype viewer CLSID OK, creates IPREVIEWHandler ok as well, but areas drawn by font, shows as totally black retangles.

Debug window output below..
sExt=.TTF
Got handler CLSID; attempting to create IPreviewHandler
iisi.init hr=0
SetWindow hr=0
DoPreview hr=0

Shell preview works ok, as well starting fontview directly using filename..
fontview.exe S:\Fonts\TTF Fonts\TTF_A\AARCO___.TTF

----------


## fafalone

I'll look into it.. not sure what's going on. It's returning the correct CLSID that corresponds to Windows Font Previewer, and no errors are being raised. Might be tough to trace since it's a problem with drawing that's done by the preview handler rather than the host app, but I'll give it a shot.

Font Previewer (fontview.exe) draws the preview itself, and appears to be where the handler is hosted; it's not just hosting an instance of IPreviewHandler.

Just in case it was the VB picturebox's problem, I tried on a CreateWindowExW-created window in a manifested app and had the same problem.

----------


## georgekar

Maybe a CLS needed. CLS copy picture to image. Image is the showing buffer.So if we get black view then image not show the proper bitmap. I am writing from a tablet, I can't check the code above...here.

----------


## fafalone

I added a .Cls statement, with and without a following .Refresh, to no avail; the thing is it's not standard graphics drawing. All you do is specify an hWnd to the external handler. It doesn't even have to be a picturebox; you can specify your forms hwnd, a frame's hwnd, etc, and it will be drawn onto that.

----------


## voxy

Hi fafalone,

once again you post brilliant stuff that cannot be found anywhere else. Thanks a lot for your pioneering work!

I can confirm that your sample code works well on Win8.1.

I also have to confirm the issue with font files. Black rects only also here.

voxy

----------


## voxy

Conc. the font preview issue, maybe the IPreviewHandlerVisuals has to be used additionally to IPreviewHandler.

https://msdn.microsoft.com/en-us/lib...=vs.85%29.aspx

----------


## voxy

FYI, although I removed the 


```
If hGlobal Then GlobalFree hGlobal
```

line I still get random crashes after previewing PDFs. Not as often as with that line but still.

----------


## fafalone

As for PDFs, the preview handler for that is notoriously unstable; people can't seem to get it to work in other languages either. There's not even much to work with, since it's the initial creation of IPreviewHandler that fails, with the oh-so-helpful 0x80004005 'Unspecific error' message.


Edit: For fonts, IPreviewHandlerVisuals did the trick, thanks for pointing me in that direction. It's a little odd as to why, but simply using its SetBackgroundColor method (set to white) makes the fonts show up; for ttf, otf, and fon files that I tested, both installed in \Windows\Fonts and not installed ones. Haven't a clue why this works, since the background already was white, and changing the text color isn't needed (although you can change that too if you want). I'll update the project in a little bit; need to see if there's any ramifications to calling it with other file types (and will have to update the main tlb since this interface wasn't already defined).

----------


## fafalone

Project updated with font preview fix (must update tlb too).

Added after ipv.DoPreview()


```
    
    Dim pVis As IPreviewHandlerVisuals    
    Dim piunk As oleexp3.IUnknown
    Set piunk = ipv
    hr = piunk.QueryInterface(IID_IPreviewHandlerVisuals, pVis)
    If (pVis Is Nothing) = False Then
        Debug.Print "Handler implements IPreviewHandlerVisuals; setting bk color to white"
        pVis.SetBackgroundColor &HFFFFFF
    End If
```

----------


## Tech99

ShowPreviewForFile subroutine throws an 'Object variable or With block variable not set 91' (error) in some computers (W7-64). Error does not happen all W7-64 machines, but only couple of.

Shows preview window and font face rendering in it OK, but throws an error. Not yet known what is causing that. 
Tested running your sample in few machines. Running compiled executable, worked ok - also runs ok in computer which is used to compile source.

----------


## fafalone

Throws an error after rendering the font? Or when you do something else afterwards? Or on different file?

If it's an IDE error you should be able to just comment out the On Error Goto e0 statement and get the line where it's occuring.

..I think I do recall an unusual bug like you described; but not after a successful preview. I remember something was returning S_OK for pUnk.QueryInterface(IID_IInitializeWithItem, iisi), but then right after that throwing an error saying iisi wasn't set. Actually, in production apps I've commented out the whole IInitializeWithItem section, as it's so rare that no other sample I've seen uses it, and no file I've seen actually supports it but not one of the others. _Edit: Turns out Outlook .msg files actually do only support IInitializeWithItem. So leave it in, but put if after IStream; and don't validate with the hr; check if Is Nothing.
_
If it is after showing a font, refer to the installed fonts issue descibed in the main text. If you've selected an installed font, you can't get a valid IShellItem for it, and isi.GetDisplayName SIGDN_NORMALDISPLAY, lp could cause that error... there should be an Is Nothing check before that statement really; I'll update it tomorrow. To confirm that's the case, is it when dealing with fonts from \Windows\Fonts\, and if it works sometimes, is it possible not all machines have the underlying issue to begin with? (I'm on Win7x64 as well; will fire up a VM with 8 later too). And if the error is immediately after the font preview shows the correct preview without boxes, regardless of the cause that isi.GetDisplayName line is the only possible statement that could trigger that error, so the Is Nothing check will resolve it.

----------


## voxy

> As for PDFs, the preview handler for that is notoriously unstable; people can't seem to get it to work in other languages either. There's not even much to work with, since it's the initial creation of IPreviewHandler that fails, with the oh-so-helpful 0x80004005 'Unspecific error' message.


I don't see that error here, but still get crashes on various systems after PDF preview. One system uses the Adobe preview handler, the other the PDF-XChange preview handler. The crash happens after calling IPV.Unload, but not immediately but at the point when the handler's DLL gets unloaded, which is one or two minutes later (no idea what triggers this unloading, it just happens by itself -- you can watch it happen in Process Explorer).

So, something is wrong here. A notorious issue with PDF previews has always been the focus stealing. I tried to control the focus with IPV.QueryFocus() but to no avail. Currently out of ideas.

----------


## fafalone

I can't load the Adobe preview handler at all.. but are you saying both of those work, but just later crash when unloaded? Is it only if you manually invoke unload; what if you just let IPV go out of context/set it to nothing?
There's .SetFocus() too, and SetWindow... what if you set the window to 0 after the preview is already displayed? That might help with the crash too.

Will try PDF-XChange viewer on my system and see if I can reproduce the issue.

Edit: I'm unable to reproduce the error with PDF-XChange. That handler works without issue. So; OS version, product version, and if applicable more specific steps? (i previewed a pdf then exited the program; then also previewed a pdf then loaded a new file that used a different handler; then in a 3rd run previewed a pdf then previewed another pdf.. nothing caused a crash on Win7x64)

Edit2: The font black boxes were certainly a bizarre issue with an even more bizarre solution. Setting the bk color triggered something it shouldn't have. PDF-XChange's handler implements IPreviewHandlerVisuals as well; are you using the updated code that calls the SetBackgroundColor function, even if you want to keep it white? I have no idea how this might be preventing the crashes and it wouldn't make sense; but after it preventing black boxes it wouldn't surprise me if it helped here too
(and speaking of the new version; it forgoes using ANY GlobalFree call... that may be an issue as well in the older version since PDF-XChange's handler uses the IStream method)

----------


## voxy

OK, this is Win8.1. Here is the steps.

- Install PDF-Viewer 2.5.214.2 from PDF-XChange. (well, this is mine, probably other versions do as well)
- Compile your latest sample project IPreviewHandlerSampleV2 (native code, optimized for speed)
- Run Project1.exe and preview *one* PDF file.
- Now close the EXE (click X-button).
- In Task Manager you will see that it did not unload. This is a symptom of the problem.

- Now, when you do the same thing, but preview *two* (or more) PDF files, you can close the EXE and it will unload completely.

Note that I was not able to crash Project1.exe before unloading it. (Something in my own project is probably responsible for this crash; but I also get the crash-on-unload in my own project. I think it's all the same bug.)

Does this tell you anything? (I hope you can reproduce it.)

voxy

PS: I don't use the SetBackgroundColor code. No GlobalFree calls anywhere.

----------


## voxy

Now I was able to crash your sample project (compiled to EXE) just the same way as my own project.

- preview *one* PDF
- unload that preview using this code (you see the "Unload IPV" button I added to your sample in the screenshot):



```
Private Sub Command3_Click()
  If (ipv Is Nothing) = False Then
      ipv.Unload
      Set ipv = Nothing
  End If
End Sub
```

- finally put any other window to the foreground! The crash only happens if Project1.exe is a background window. (another hint that *focus* plays a role here)

- now wait 1-3 minutes doing nothing. At some point the window will become unresponsive and look like this:

----------


## Tech99

> Throws an error after rendering the font?


After rendering font, visually all seems fine ie. renders font OK, but throws an error. Tried previewing non installed fonts, residing in network share, but able to reproduce also with installed fonts in same machine throwing error.

I will report back when some tests are made, with compiled program added some feedback to pinpoint code line causing error.

----------


## fafalone

@Tech99: Did you add the check to make sure it's not the isi.GetDisplayName line? No object code executes between that statement and a subsequent user action.

@voxy: Still not getting a crash or lingering processes. To me this suggests either the problem is elsewhere, or the same magic that resolved font black boxes is working here and you should add the IPreviewHandlerVisuals call (this was also available in XP so would not break that compatibility if that was a concern). I haven't tried with the older version you're using yet either though, theoretically could have been solved between your 2.5.214 and my 2.5.315.

----------


## Tech99

> @Tech99: Did you add the check to make sure it's not the isi.GetDisplayName line? No object code executes between that statement and a subsequent user action.


Not sure yet. I haven't been able to reproduce error since, in that user workstation. Rebooted that machine, in the beginning of testing and no error since.

----------


## fafalone

It's still a good idea to add the check; even if it's not the cause of your crashes, in case of unforseen issues that cause it to not be set.
You're using the default Windows Font Previewer right, not a 3rd party preview handler? Did you ever get the crash with a different file type?


Edit:
NOTE: I had to withdraw my earlier statement about removing IInitializeWithItem. Found out that Outlook .msg files support it, but not either of the other IInitialize's. I'm working on a general bugfix update that will do this, but in the mean time I recommend checking for it after both the others, and validating it If iisi Is Nothing instead of If hr = S_OK (as per the bug I described with it).

----------


## voxy

> @voxy: Still not getting a crash or lingering processes. To me this suggests either the problem is elsewhere, or the same magic that resolved font black boxes is working here and you should add the IPreviewHandlerVisuals call (this was also available in XP so would not break that compatibility if that was a concern). I haven't tried with the older version you're using yet either though, theoretically could have been solved between your 2.5.214 and my 2.5.315.


Bingo!!!  :Alien Frog:  Upgrading to 2.5.315 fixed it! Wonderful, thanks!
(And I don't care so much for bugs with Adobe. They are known to be buggy.)

Just for completeness: Before upgrading PDF-XChange I tried your suggestion with IPreviewHandlerVisuals, but it did not change anything.

----------


## Tech99

> It's still a good idea to add the check; even if it's not the cause of your crashes, in case of unforseen issues that cause it to not be set.
> You're using the default Windows Font Previewer right, not a 3rd party preview handler? Did you ever get the crash with a different file type?


Yes, using standard Windows Font Previewer app (fontview.exe), tried couple of other filetypes - mostly bitmap formats (png, jpg, tif) seems to work ok.

However i changed your sample a bit, by adding resizing. Needed to remove frame1, for dynamic resizing to work.

----------


## Tech99

> I can't load the Adobe preview handler at all...


Same here.

Got handler CLSID; attempting to create IPreviewHandler
IInitializeWithFile not supported.
IInitializeWithItem not supported.
Attempting to use IStream

hr = pUnk.QueryInterface(IID_IInitializeWithStream, iis) returns -2147467259 as hr value.

----------


## fafalone

Yup that's the base-10 of the 80004005 'unspecific error' code. I like the 3rd party previewer solution, Adobe sux anyway. There's FoxIt or somesuch too that has a preview handler that should work.

Wait.. if that's on QueryInterface, your call to CoCreateInstance succeeded in creating the preview handler at least then?

----------


## Tech99

> Wait.. if that's on QueryInterface, your call to CoCreateInstance succeeded in creating the preview handler at least then?


Actually no, that was from machine where Adobe full featured Acrobat package was installed. Plain Adobe Reader DC (latest version) fails in CoCreateInstance.

GetHandlerCLSID succeeds for .pdf extension tHandler(CLSID/GUID) returned {DC6EFB56-9CFA-464D-8880-44885D7DC193} for Adobe Reader DC, but the CoCreateInstance fails with hresult -2147467259 value.



```
Public Function IID_IPreviewHandler() As UUID
'{8895b1c6-b41f-4c1c-a562-0d564250836f}
Static iid As UUID
 If (iid.Data1 = 0) Then Call DEFINE_UUID(iid, &H8895B1C6, CInt(&HB41F), CInt(&H4C1C), &HA5, &H62, &HD, &H56, &H42, &H50, &H83, &H6F)
 IID_IPreviewHandler = iid '<- this line takes quite long time to execute.
End Function
```

https://forums.adobe.com/thread/303008?tstart=0
Excerpt from page 3...



> This is from Adobe staff from this April "Sorry for the trouble. We had to remove the thumbnail preview functionality from Acrobat and Reader DC for technical reasons. We know there are users who value it but certain design considerations forced us to make this change."

----------


## fafalone

DC is what is on my system too, that appears to be the problem. I get that for whatever reason they removed the previewer from it, but it's just terrible programming to still register the handler and just fling errors instead of a message it's been removed or just removing the registration entirely. No wonder their products are gaping security holes with the World's Worst Updater.

----------


## Tech99

> No wonder their products are gaping security holes with the World's Worst Updater.


Indeed and Adobe Reader is massive bloatware nowadays - DC version is whopping 120 Mb in size.

Looking for alternatives, MuPDF is small, fast but seems to lack of iPreviewHandler support.

----------


## fafalone

The PDF-XChange viewer me and voxy were talking about is free (have to grab just the viewer, the editor and others are just trials) and works well. There's also one called Foxit thats free and widely used. Both of these support IPreviewHandler well.

----------


## Jonney

> The PDF-XChange viewer me and voxy were talking about is free (have to grab just the viewer, the editor and others are just trials) and works well. There's also one called Foxit thats free and widely used. Both of these support IPreviewHandler well.


I tested Foxit Reader PDF Printer. It produces poor quality of pdf file (Alpha lost). PDF Creator produces normal good quality pdf.

----------


## Steve-N

Using iPreviewHandlerSampleV2 and oleexp v3.3 on Windows 7 with Office 2007 I see an issue with saved Outlook email .msg files.

Previewing .msg files doesn't show any message body text. The message header is shown (Title, From, To and Date Sent) but not the actual message. No error occurs.

But when looking at Windows Explorer preview pane the full message text shows also.

It doesn't make any difference if the internal format of the .msg file is Plain Text, Rich Text or HTML.

I assume Windows Explorer uses iPreviewHandler, so I would have expected the same results.

----------


## fafalone

Windows does it's own thing. IPreviewHandler is implemented and registered by the application, but Windows does a bunch of extra stuff, and there's little documentation about what to do. For example, there was zero documentation about the necessity of IPreviewHandlerVisuals to render fonts.

Can you post a sample file? I can plug it into a version with far more extensive debug output, since the problem doesn't appear with newer versions.

----------


## Steve-N

I'll post a sample file when I am back in the office.
Meanwhile here is the debug output:-
Got handler CLSID; attempting to create IPreviewHandler
IInitializeWithFile not supported.
iisi.init hr=0
SetWindow hr=0
DoPreview hr=-2147467259

----------


## fafalone

That's odd, DoPreview is throwing an error that's usually a crash (the hr should be 0 [S_OK] if successful), but then it's still showing a partial preview? And are you running the sample straight, or integrated into a project-- perhaps the preview rect is just cutting it off? Definitely need a sample file.. although I am concerned that even if the message was created by 2007, it would still be rendered by my newer version (2010).

----------


## Steve-N

I found the issue.  I added a manifest to use common controls v 6.0.0.0
The message body is now shown.

I guess the Outlook previewer must use v6 of the common controls.

This is using your downloaded sample, unmodified.

----------


## fafalone

Yeah that makes sense.. I'll make a note about it in the requirements section, thanks for the report. I've been kinda presuming anyone modernizing their app with this kinda stuff would already be manifested, but I've never seen it required except for one other (IImageList/IImageList2)-- but MSDN documented that. But yet another undocumented requirement for IPreviewHandler.

----------


## pershiran

hi

i want use IPreviewHandler by file listbox.
but it need to set isi by fileopendialog.
please help me




thanks.

----------


## fafalone

You mean from a FileListBox right? You could do something similar to what the 'Preview' button does, just with the file list instead of the textbox:


```
Dim psi As IShellItem
Dim rc As RECT
Dim pidl As Long
Dim sFile As String
sFile = Dir1.Path & "\" & File1.List(File1.ListIndex)
pidl = ILCreateFromPathW(StrPtr(sFile))
Call SHCreateItemFromIDList(pidl, IID_IShellItem, psi)

    rc.Top = 16
    rc.Bottom = (Picture1.Height / Screen.TwipsPerPixelY) - 16
    rc.Left = 16
    rc.Right = (Picture1.Width / Screen.TwipsPerPixelX) - 16
    ShowPreviewForFile psi, Picture1.hWnd, rc, Picture1, sFile
```

Also in your picture you're selecting a JPG, which may not by default have an IPreviewHandler; the sample project has code that manually draws image file previews, so you'd have to make sure you had that part too.

----------


## Steve-N

I haven't tried this yet, but the XP code you give for image file preview (post #1) uses 

```
SHCreateItemFromIDList
```

Doesn't this have a minimum requirement of Vista ?

----------


## fafalone

Ah apparently so, good catch I thought it just required 6.0.

Fortunately it can be easily replaced with SHCreateShellItem, which MSDN says: "Minimum supported client Windows XP with SP1 [desktop apps only]"

Public Declare Function SHCreateShellItem Lib "shell32" (ByVal pidlParent As Long, ByVal psfParent As Long, ByVal pidl As Long, ppsi As IShellItem) As Long

I'll update it with the minor change:


```
If pidlFQ Then
    Call SHCreateShellItem(0&, 0&, pidlFQ, isi)
Else
    pidl = ILCreateFromPathW(StrPtr(sFile))
    Call SHCreateShellItem(0&, 0&, pidl, isi)
    Call CoTaskMemFree(pidl) 'also a change that should have been made
End If
```

Sorry I didn't find out about this earlier my XP diehards, and thanks for pointing this out Steve  :Blush:

----------


## Stu2

Using the iPreview sample (v3) I have a problem.

On Windows 10 (64 bit) with Adobe Reader XI and a fix for the 64bit Adobe Reader preview handler ( https://pretentiousname.com/adobe_pd...fix/index.html )

Admittedly this isn't a common configuration, but I don't have control over this. It isn't possible to change this in the short term.

The debug output from the sample program is as follows:


```
using isi
sFile=C:\Test\00000017.PDF
sExt=.PDF
Got handler CLSID; attempting to create IPreviewHandler

...and after a delay of over 1 minute...

Failed to create IPreviewHandler interface, hr=-2147467259
```

The configuration works fine in File Explorer and Outlook, PDFs can be previewed. In File Explorer you even get thumbnails of the first page of the PDF.

If I install say PDF-XChange viewer I can then preview PDFs, but unfortunately this isn't allowed.

I accept this is largely a problem created by Adobe, but because Explorer and Outlook can work with this configuration it should be possible to get the iPreviewHandler to work too.

What should I try?

----------


## fafalone

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.

----------


## Schmidt

> 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


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

----------


## fafalone

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.

----------


## wqweto

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

----------


## fafalone

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.

----------


## wqweto

Yes, I see your point. oleexp is a very valuable project to the community.

Keep up the good work! 

cheers,
</wqw>

----------


## Stu2

I changed the argument to CLSCTX_LOCAL_SERVER.



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

----------


## DEXWERX

This may not be convenient for oleexp, but I keep string constants of GUID/IIDs stored in my Direct2D typelib.

----------


## Schmidt

> 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

----------


## Stu2

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

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

----------


## fafalone

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:


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

----------


## VB6 Programming

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?

----------


## fafalone

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)

----------


## VB6 Programming

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

----------

