Option Explicit
Type DOCINFO
cbSize As Long
lpszName As String
lpszOutput As String
End Type
#If VBA7 Then
Declare PtrSafe Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As LongPtr) As LongPtr
Declare PtrSafe Function CreateCompatibleBitmap Lib "gdi32" (ByVal hdc As LongPtr, ByVal nWidth As Long, ByVal nHeight As Long) As LongPtr
Declare PtrSafe Function SelectObject Lib "gdi32" (ByVal hdc As LongPtr, ByVal hObject As LongPtr) As LongPtr
Declare PtrSafe Function DeleteObject Lib "gdi32" (ByVal hObject As LongPtr) As Long
Declare PtrSafe Function StretchBlt Lib "gdi32" (ByVal hdc As LongPtr, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As LongPtr, ByVal xSrc As Long, ByVal ySrc As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal dwRop As Long) As Long
Declare PtrSafe Function CreateDC Lib "gdi32" Alias "CreateDCA" (ByVal lpDriverName As String, ByVal lpDeviceName As String, ByVal lpOutput As String, ByVal lpInitData As Any) As LongPtr
Declare PtrSafe Function GetDC Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
Declare PtrSafe Function ReleaseDC Lib "user32" (ByVal hwnd As LongPtr, ByVal hdc As LongPtr) As Long
Declare PtrSafe Function GetDeviceCaps Lib "gdi32" (ByVal hdc As LongPtr, ByVal nIndex As Long) As Long
Declare PtrSafe Function DeleteDC Lib "gdi32" (ByVal hdc As LongPtr) As Long
Declare PtrSafe Function StartDoc Lib "gdi32" Alias "StartDocA" (ByVal hdc As LongPtr, lpdi As DOCINFO) As Long
Declare PtrSafe Function EndDoc Lib "gdi32" (ByVal hdc As LongPtr) As Long
Declare PtrSafe Function GetDefaultPrinter Lib "winspool.drv" Alias "GetDefaultPrinterA" (ByVal sPrinterName As String, lPrinterNameBufferSize As Long) As LongPtr
Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
Declare PtrSafe Function WindowFromAccessibleObject Lib "oleacc" (ByVal pacc As IAccessible, phwnd As LongPtr) As Long
#Else
Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Declare Function CreateCompatibleBitmap Lib "gdi32" (ByVal hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Declare Function StretchBlt Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal dwRop As Long) As Long
Declare Function CreateDC Lib "gdi32" Alias "CreateDCA" (ByVal lpDriverName As String, ByVal lpDeviceName As String, ByVal lpOutput As String, ByVal lpInitData As Any) As Long
Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hdc As Long) As Long
Declare Function GetDeviceCaps Lib "gdi32" (ByVal hdc As Long, ByVal nIndex As Long) As Long
Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Declare Function StartDoc Lib "gdi32" Alias "StartDocA" (ByVal hdc As Long, lpdi As DOCINFO) As Long
Declare Function EndDoc Lib "gdi32" (ByVal hdc As Long) As Long
Declare Function GetDefaultPrinter Lib "winspool.drv" Alias "GetDefaultPrinterA" (ByVal sPrinterName As String, lPrinterNameBufferSize As Long) As Long
Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Declare Function WindowFromAccessibleObject Lib "oleacc" (ByVal pacc As IAccessible, phwnd As Long) As Long
#End If
Private Const LOGPIXELSX As Long = 88
Private Const LOGPIXELSY As Long = 90
Private Const PointsPerInch = 72
Private Const SRCCOPY As Long = &HCC0020
Private Const WM_PRINT = &H317
Private Const PRF_CHILDREN = &H10&
Private Const PRF_CLIENT = &H4&
Private Const PRF_OWNED = &H20&
Function PrintWebBrowserToPDF(ByVal WbBrowser As Object, ByVal OutputFile As String) As Boolean
#If VBA7 Then
Dim hwnd As LongPtr, hWebBrowserDc As LongPtr, hPrintDc As LongPtr, hBmp As LongPtr, lMemoryDC As LongPtr, lPtr As LongPtr
#Else
Dim hwnd As Long, hWebBrowserDc As Long, hPrintDc As Long, hBmp As Long, lMemoryDC As Long, lPtr As Long
#End If
Dim tDocInfo As DOCINFO
Dim oPrevSheet As Worksheet
Dim oIa As IAccessible
Dim wd As Double, hg As Double
Dim w As Long, h As Long, lZoom As Long
If TypeName(WbBrowser) <> "WebBrowser" Or UCase(Right(OutputFile, 4)) <> ".PDF" Then Exit Function
On Error GoTo Xit
lPtr = ObjPtr(WbBrowser)
CopyMemory oIa, lPtr, LenB(lPtr)
WindowFromAccessibleObject oIa, hwnd
CopyMemory oIa, 0&, LenB(lPtr)
If hwnd Then
wd = WbBrowser.Width
hg = WbBrowser.Height
hWebBrowserDc = GetDC(hwnd)
lMemoryDC = CreateCompatibleDC(hWebBrowserDc)
hBmp = CreateCompatibleBitmap(hWebBrowserDc, wd, hg)
Call SelectObject(lMemoryDC, hBmp)
hPrintDc = GetPrinterDC()
If hPrintDc Then
With tDocInfo
.lpszName = "WebBrowser_PrintOut"
.lpszOutput = OutputFile
.cbSize = Len(tDocInfo)
End With
Call StartDoc(hPrintDc, tDocInfo)
If Not ActiveSheet Is WbBrowser.Parent Then
Set oPrevSheet = ActiveSheet
Application.ScreenUpdating = False
Application.EnableEvents = False
WbBrowser.Parent.Activate
lZoom = Application.ActiveWindow.Zoom
oPrevSheet.Activate
Application.EnableEvents = True
Else
lZoom = Application.ActiveWindow.Zoom
End If
w = PTtoPX(wd * lZoom / 100, False)
h = PTtoPX(hg * lZoom / 100, True)
SendMessage hwnd, WM_PRINT, lMemoryDC, PRF_CHILDREN + PRF_CLIENT + PRF_OWNED
Call StretchBlt(hPrintDc, 0, 0, GetDeviceCaps(hPrintDc, 8), GetDeviceCaps(hPrintDc, 10), lMemoryDC, 0, 0, w, h, SRCCOPY)
Call EndDoc(hPrintDc)
End If
End If
Xit:
Call DeleteObject(hBmp)
Call DeleteDC(hPrintDc)
Call DeleteDC(lMemoryDC)
Call ReleaseDC(hwnd, hWebBrowserDc)
Application.EnableEvents = True
PrintWebBrowserToPDF = Err.Number = 0 And Len(Dir(CreateObject("Scripting.FileSystemObject").GetParentFolderName(OutputFile), vbDirectory))
End Function
#If VBA7 Then
Function GetPrinterDC() As LongPtr
Dim hPrinter As LongPtr
#Else
Function GetPrinterDC() As Long
Dim hPrinter As Long
#End If
Dim sBuffer As String
Dim sPrinterName As String
sBuffer = Space(128)
If GetDefaultPrinter(sBuffer, 128) Then
sPrinterName = Left(sBuffer, 128 - 1)
GetPrinterDC = CreateDC("WINSPOOL", sPrinterName, vbNullString, 0&)
End If
End Function
Function ScreenDPI(bVert As Boolean) As Long
Static lDPI(1), lDC
If lDPI(0) = 0 Then
lDC = GetDC(0)
lDPI(0) = GetDeviceCaps(lDC, LOGPIXELSX)
lDPI(1) = GetDeviceCaps(lDC, LOGPIXELSY)
lDC = ReleaseDC(0, lDC)
End If
ScreenDPI = lDPI(Abs(bVert))
End Function
Function PTtoPX(Points As Single, bVert As Boolean) As Long
PTtoPX = Points * ScreenDPI(bVert) / PointsPerInch
End Function