Home > Archive > Visual Basic > January 2006 > Print Problem
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
|
|
|
| Hi,
I am trying to print data from a listview from example code from here. The
problem I am having is that I need a printer object to print and I am trying
to do this in VBA (no printer object). This is not VBA for Office but
rather VBA for a third party app. Is there a way using API's to accomplish
printing a listview?
Thanks
| |
| David J Mark 2006-01-25, 6:56 pm |
|
"ted" <ted@united.com> wrote in message
news:%23FASS%23cIGHA.524@TK2MSFTNGP09.phx.gbl...
> Hi,
>
> I am trying to print data from a listview from example code from here.
> The problem I am having is that I need a printer object to print and I am
> trying to do this in VBA (no printer object). This is not VBA for Office
> but rather VBA for a third party app. Is there a way using API's to
> accomplish printing a listview?
Of course. I remember the example. It looped through the Printers
collection to find the selected printer and then used it to print. Instead,
use the returned hDC from PrntDlg (or the common dialog control) and use the
print API to render the text. You can also BitBlt the icons if you want.
>
> Thanks
>
| |
|
| I have not seen that example. I was talking about the example of printing
the listview. Could you point me to the example of using API's to get the
printer?
Thanks
"David J Mark" <nntp45534-22@newsdesk.net> wrote in message
news:7oOBf.48987$Q11.44301@tornado.ohiordc.rr.com...
>
> "ted" <ted@united.com> wrote in message
> news:%23FASS%23cIGHA.524@TK2MSFTNGP09.phx.gbl...
>
> Of course. I remember the example. It looped through the Printers
> collection to find the selected printer and then used it to print.
> Instead, use the returned hDC from PrntDlg (or the common dialog control)
> and use the print API to render the text. You can also BitBlt the icons
> if you want.
>
>
>
| |
|
|
|
| Ken,
Thanks for the info. You are correct what a pain. I am almost about to
create an activex dll to display and print the data and just reference it in
my vba project. However, the only issue is if I build inside the VBA
project I do not have distribute it because it is loaded from the server.
If I use the activex dll I will have to distribute it. Or is there a way I
can create this activex dll and have it loaded on the server only?
Thanks
"Ken Halter" <Ken_Halter@Use_Sparingly_Hotmail.com> wrote in message
news:OVPIRFfIGHA.2300@TK2MSFTNGP15.phx.gbl...
> "ted" <ted@united.com> wrote in message
> news:ukrxnsdIGHA.3036@tk2msftngp13.phx.gbl...
>
> Sheesh... No printer object... what a pain <g> I don't know if any of
> this'll help but....
>
> SetDefaultPrinter: Changing Windows' Default Printer
> http://vbnet.mvps.org/index.html?co...aultprinter.htm
>
> EnumPrinters: Enumerating Local and Network Printers
> http://vbnet.mvps.org/code/enums/enumprinters.htm
>
> How To Set Which Printer Is the System Default Printer
> http://support.microsoft.com/kb/266767/en-us
>
> --
> Ken Halter - MS-MVP-VB - Please keep all discussions in the groups..
> DLL Hell problems? Try ComGuard - http://www.vbsight.com/ComGuard.htm
> Freeware 4 color Gradient Frame? http://www.vbsight.com/GradFrameCTL.htm
>
| |
| Ken Halter 2006-01-25, 6:56 pm |
| "ted" <ted@united.com> wrote in message
news:uGUKVJfIGHA.3728@tk2msftngp13.phx.gbl...
> Ken,
>
> Thanks for the info. You are correct what a pain. I am almost about to
> create an activex dll to display and print the data and just reference it
> in my vba project. However, the only issue is if I build inside the VBA
> project I do not have distribute it because it is loaded from the server.
> If I use the activex dll I will have to distribute it. Or is there a way
> I can create this activex dll and have it loaded on the server only?
>
> Thanks
If this is an "in house" app, you can have "the latest" version of that DLL
on the server and any PC that has a connection to the server can get to it.
Each workstation will need to run Regsvr32 to register the DLL so it shows
in their registry and all workstations will need to shut down all copies of
the app each time you want to update that DLL.
imo, it's easier to keep the latest version on the server but have the app
copy and register it on the local machine before using it. The app can check
time stamps or version numbers each time it starts to make sure it has "the
latest and greatest"
--
Ken Halter - MS-MVP-VB - Please keep all discussions in the groups..
DLL Hell problems? Try ComGuard - http://www.vbsight.com/ComGuard.htm
Freeware 4 color Gradient Frame? http://www.vbsight.com/GradFrameCTL.htm
| |
| Mike Williams 2006-01-26, 7:55 am |
| "ted" <ted@united.com> wrote in message
news:uGUKVJfIGHA.3728@tk2msftngp13.phx.gbl...
> . . . what a pain. I am almost about to create an activex
> dll to display and print the data and just reference it in my
> vba project. However, the only issue is if I build inside the
> VBA project I do not have distribute . . . . .
Yep. Despite all the "knocking" it gets, the VB Printer Object is sometimes
quite useful! Personally I sometimes do my printing using the VB printer
object and sometimes I instead print to the printer device context returned
by the MS CommonDialog control, which method of course doesn't need the
printer object. If you've got the CommonDialog control in VBA then you can
do the same. Otherwise, you'll have to instead use the PrintDlgEx API and
print to the device context it returns. I've always used the CommonDialog
control to show printer dialogs myself, and I've just tried the PrintDlg API
but I seem to be having a bit of a brain fart and I can't get it to return a
device context for me, no matter what I do with the PD_RETURNDC flag!
Otherwise I'd write some code for you. If you have access to a CommonDialog
Control in VBA then post again and I'll show you how to use it for printing,
otherwise, perhaps someone else here can persuade that pesky PrintDlg API to
return a device context?
Mike
| |
|
| Mike,
I do have access to the Common Dialog Control in my projects. I am trying
to use the cod e posted on here before for printing a listview.
Public Sub PrintListView(cntlListView As ListView, Optional lLeftMarg As
Long = _
0, Optional lTopMarg As Long = 0, Optional sReportTitle As String = "",
_
Optional bPrintColHdrs As Boolean = True)
Dim itmX As ListItem, hdrX As ColumnHeader
Dim iCnt As Integer, lRightMarg As Long
Dim ColWidths() As Long, lCurX As Long, lCurY As Long
Dim bFontBold As Boolean
Dim iFontSize As Integer
Dim lPage As Long
If cntlListView.View <> lvwReport Then Exit Sub
Screen.MousePointer = vbHourglass
iFontSize = Printer.FONTSIZE
Printer.FONTSIZE = 12
With cntlListView
ReDim ColWidths(0 To .ColumnHeaders.count - 1)
' Get the text width of the longest item in each column.
' You can specify a max length if you want.
If bPrintColHdrs Then
bFontBold = Printer.FONTBOLD
Printer.FONTBOLD = True
For Each hdrX In .ColumnHeaders
If ColWidths(hdrX.SubItemIndex) <
Printer.TextWidth(hdrX.Text) _
Then
ColWidths(hdrX.SubItemIndex) =
Printer.TextWidth(hdrX.Text)
End If
Next
Printer.FONTBOLD = bFontBold
End If
For Each itmX In .ListItems
If ColWidths(0) < Printer.TextWidth(itmX.Text) Then
ColWidths(0) = Printer.TextWidth(itmX.Text)
End If
For iCnt = 1 To .ColumnHeaders.count - 1
If ColWidths(iCnt) < Printer.TextWidth(itmX.SubItems(iCnt))
Then
ColWidths(iCnt) = Printer.TextWidth(itmX.SubItems(iCnt))
End If
Next
Next
' Get the right margin
lRightMarg = lLeftMarg
For iCnt = 0 To .ColumnHeaders.count - 1
lRightMarg = lRightMarg + ColWidths(iCnt) + 200
Next
' Remove the last 200
lRightMarg = lRightMarg - 200
If lRightMarg > Printer.ScaleWidth Then
lRightMarg = Printer.ScaleWidth
End If
' Set the top margin
Printer.CurrentY = lTopMarg
' Begin printing
If sReportTitle <> "" Then
PrintCaption lTopMarg, sReportTitle
End If
If bPrintColHdrs Then
' Print the columnheaders
PrintColumnHeaders lLeftMarg, lRightMarg, cntlListView,
ColWidths()
End If
' Print the listview
lPage = 1
For Each itmX In .ListItems
If (Printer.CurrentY + Printer.TextHeight("Pg") + 100) > _
(Printer.ScaleHeight - 800) Then
PrintPageNumber lPage
lPage = lPage + 1
Printer.NewPage
If sReportTitle <> "" Then
PrintCaption lTopMarg, sReportTitle
End If
If bPrintColHdrs Then
PrintColumnHeaders lLeftMarg, lRightMarg, cntlListView,
_
ColWidths()
End If
End If
Printer.CurrentX = lLeftMarg
lCurX = Printer.CurrentX
Printer.Print itmX.Text;
For iCnt = 1 To .ColumnHeaders.count - 1
Printer.CurrentX = lCurX + ColWidths(iCnt - 1) + 200
lCurX = Printer.CurrentX
Printer.Print itmX.SubItems(iCnt);
Next
Printer.Print ""
Next
If lPage = 1 Then PrintPageNumber lPage
End With
Printer.EndDoc
Printer.FONTSIZE = iFontSize
Screen.MousePointer = vbNormal
End Sub
"Mike Williams" <Mike@WhiskyAndCoke.com> wrote in message
news:OCIoE3nIGHA.3936@TK2MSFTNGP12.phx.gbl...
> "ted" <ted@united.com> wrote in message
> news:uGUKVJfIGHA.3728@tk2msftngp13.phx.gbl...
>
>
> Yep. Despite all the "knocking" it gets, the VB Printer Object is
> sometimes quite useful! Personally I sometimes do my printing using the VB
> printer object and sometimes I instead print to the printer device context
> returned by the MS CommonDialog control, which method of course doesn't
> need the printer object. If you've got the CommonDialog control in VBA
> then you can do the same. Otherwise, you'll have to instead use the
> PrintDlgEx API and print to the device context it returns. I've always
> used the CommonDialog control to show printer dialogs myself, and I've
> just tried the PrintDlg API but I seem to be having a bit of a brain fart
> and I can't get it to return a device context for me, no matter what I do
> with the PD_RETURNDC flag! Otherwise I'd write some code for you. If you
> have access to a CommonDialog Control in VBA then post again and I'll show
> you how to use it for printing, otherwise, perhaps someone else here can
> persuade that pesky PrintDlg API to return a device context?
>
> Mike
>
>
| |
| Mike Williams 2006-01-26, 6:56 pm |
| "ted" <ted@united.com> wrote in message
news:uUZGUArIGHA.3944@tk2msftngp13.phx.gbl...
> Mike, I do have access to the Common Dialog Control in my
> projects. I am trying to use the cod e posted on here before
> for printing a listview.
Hang on. You've got me now Ted. I don't know anything at all about
VBA. Are you saying that you *do* have access to the VB CommonDialog control
but that you *do not* have access to the VB printer object? If that's the
case then of course the code you posted will not work at all, since it
relies heavily on the VB printer object. Post again if you definitely *do*
have access to the CommonDialog Control and I'll probably be able to help
you further. Try the following code snippet in your VBA project. Does it
show a printer dialog?
Private Sub Command1_Click()
CommonDialog1.flags = 0
CommonDialog1.ShowPrinter
End Sub
Mike
| |
|
| Yes I do have access to the common dialog. Thanks for the help.
"Mike Williams" <Mike@WhiskyAndCoke.com> wrote in message
news:uphjFXrIGHA.3816@TK2MSFTNGP12.phx.gbl...
> "ted" <ted@united.com> wrote in message
> news:uUZGUArIGHA.3944@tk2msftngp13.phx.gbl...
>
>
> Hang on. You've got me now Ted. I don't know anything at all
> about VBA. Are you saying that you *do* have access to the VB CommonDialog
> control but that you *do not* have access to the VB printer object? If
> that's the case then of course the code you posted will not work at all,
> since it relies heavily on the VB printer object. Post again if you
> definitely *do* have access to the CommonDialog Control and I'll probably
> be able to help you further. Try the following code snippet in your VBA
> project. Does it show a printer dialog?
>
> Private Sub Command1_Click()
> CommonDialog1.flags = 0
> CommonDialog1.ShowPrinter
> End Sub
>
> Mike
>
>
| |
| Lee Peedin 2006-01-26, 9:55 pm |
| Ted,
OK, I'm going to jump in where I probably don't belong. But before
you create your own ActiveX dll, wander over to
http://pragmaticlee.safedatisp.net and seach the page for PrintObject.
I wrapped the VB printer object in an ActiveX dll several years ago to
use with Object Rexx. I've had a much greater response from the
VBScript community than the Rexx community with the exception of one
insurance company that has it on over 1000 workstations. It's free
and you're welcomed to it. All my examples are in Rexx, but if you
understand passing methods to objects, you shouldn't have any problems
figuring it out.
Lee Peedin
VP RexxLA
On Wed, 25 Jan 2006 13:55:17 -0700, "ted" <ted@united.com> wrote:
>Ken,
>
>Thanks for the info. You are correct what a pain. I am almost about to
>create an activex dll to display and print the data and just reference it in
>my vba project. However, the only issue is if I build inside the VBA
>project I do not have distribute it because it is loaded from the server.
>If I use the activex dll I will have to distribute it. Or is there a way I
>can create this activex dll and have it loaded on the server only?
>
>Thanks
>
>"Ken Halter" <Ken_Halter@Use_Sparingly_Hotmail.com> wrote in message
>news:OVPIRFfIGHA.2300@TK2MSFTNGP15.phx.gbl...
>
| |
| Mike Williams 2006-01-27, 3:55 am |
| "ted" <ted@united.com> wrote in message
news:%23TGSnVsIGHA.528@TK2MSFTNGP12.phx.gbl...
> Yes I do have access to the common dialog. Thanks for the help.
Okay. Paste the following code into a VB Form containing a CommonDialog
Control and a Command Button (in the example they have the names
CommonDialog1 and Command1). Run the code and click the button. Check it out
and let me know how it goes.
Mike
Option Explicit
' Printing without using the VB printer object.
' Code by Mike Williams (Whisky & CokeŽ).
Private Declare Function StartDoc Lib "gdi32" Alias _
"StartDocA" (ByVal hdc As Long, lpdi As DOCINFO) As Long
Private Declare Function EndDoc Lib "gdi32" _
(ByVal hdc As Long) As Long
Private Declare Function StartPage Lib "gdi32" _
(ByVal hdc As Long) As Long
Private Declare Function EndPage Lib "gdi32" _
(ByVal hdc As Long) As Long
Private Declare Function CreateFontIndirect Lib "gdi32" _
Alias "CreateFontIndirectA" (lpLogFont As LOGFONT) As Long
Private Declare Function SelectObject Lib "gdi32" _
(ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" _
(ByVal hObject As Long) As Long
Private Declare Function TextOut Lib "gdi32" Alias _
"TextOutA" (ByVal hdc As Long, ByVal x As Long, ByVal _
y As Long, ByVal lpString As String, ByVal nCount _
As Long) As Long
Private Declare Function GetDeviceCaps Lib "gdi32" _
(ByVal hdc As Long, ByVal nindex As Long) As Long
Private Declare Function SetBkMode Lib "gdi32" _
(ByVal hdc As Long, ByVal nBkMode As Long) As Long
Private Declare Function Rectangle Lib "gdi32" _
(ByVal hdc As Long, ByVal x1 As Long, ByVal y1 As Long, _
ByVal x2 As Long, ByVal y2 As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" _
(ByVal hdc As Long) As Long
Private Const LF_FACESIZE = 32
Private Const LOGPIXELSX = 88
Private Const LOGPIXELSY = 90
Private Const PHYSICALOFFSETX = 112
Private Const PHYSICALOFFSETY = 113
Private Const PHYSICALWIDTH = 110
Private Const PHYSICALHEIGHT = 111
Private Const POINTSPERINCH = 72
Private Const NORMAL = 400
Private Const BOLD = 700
Private Const TRANSPARENT = 1
Private Const OPAQUE = 2
Private Type DOCINFO
cbSize As Long
lpszDocName As String
lpszOutput As String
lpszDatatype As String
fwType As Long
End Type
Private Type LOGFONT
lfHeight As Long
lfWidth As Long
lfEscapement As Long
lfOrientation As Long
lfWeight As Long
lfItalic As Byte
lfUnderline As Byte
lfStrikeOut As Byte
lfCharSet As Byte
lfOutPrecision As Byte
lfClipPrecision As Byte
lfQuality As Byte
lfPitchAndFamily As Byte
lfFaceName As String * LF_FACESIZE
End Type
Private Type PrinterInfo
Handle As Long
PixPerInchX As Long
PixPerInchY As Long
OffsetX As Long
OffsetY As Long
PageWidthInches As Single
PageHeightInches As Single
End Type
Private MyPrinter As PrinterInfo
Private UserCancelled As Boolean
Private myFont As LOGFONT
Private hOldfont As Long
Private hNewFont As Long
Private Sub GetMyPrinter()
UserCancelled = False
CommonDialog1.PrinterDefault = False
CommonDialog1.CancelError = True
CommonDialog1.Flags = cdlPDReturnDC
On Error GoTo dlgError
CommonDialog1.ShowPrinter
On Error GoTo 0
MyPrinter.Handle = CommonDialog1.hdc
MyPrinter.PixPerInchX = GetDeviceCaps _
(MyPrinter.Handle, LOGPIXELSX)
MyPrinter.PixPerInchY = GetDeviceCaps _
(MyPrinter.Handle, LOGPIXELSY)
MyPrinter.OffsetX = GetDeviceCaps _
(MyPrinter.Handle, PHYSICALOFFSETX)
MyPrinter.OffsetY = GetDeviceCaps _
(MyPrinter.Handle, PHYSICALOFFSETY)
MyPrinter.PageWidthInches = CSng(GetDeviceCaps _
(MyPrinter.Handle, PHYSICALWIDTH)) / _
MyPrinter.PixPerInchX
MyPrinter.PageHeightInches = CSng(GetDeviceCaps _
(MyPrinter.Handle, PHYSICALHEIGHT)) / _
MyPrinter.PixPerInchY
' GetDeviceCaps can get lots of other info
' Set up a default font to Times new Roman size 12
myFont.lfFaceName = "Times New Roman" + Chr$(0)
myFont.lfEscapement = 0 ' rotation in tenths of a degree
myFont.lfHeight = 12 * (-MyPrinter.PixPerInchY / _
POINTSPERINCH) ' 12 point text
myFont.lfWeight = NORMAL
hNewFont = CreateFontIndirect(myFont) 'Create the font
' Select our font structure and save previous font info
hOldfont = SelectObject(MyPrinter.Handle, hNewFont)
SetBkMode MyPrinter.Handle, TRANSPARENT ' FontTransparent
Exit Sub
dlgError:
UserCancelled = True
End Sub
Private Sub TextPrint(s1 As String, x As Single, y As Single)
Dim xpos As Long, ypos As Long
xpos = x * MyPrinter.PixPerInchX - MyPrinter.OffsetX
ypos = y * MyPrinter.PixPerInchY - MyPrinter.OffsetY
TextOut MyPrinter.Handle, xpos, ypos, s1, Len(s1)
End Sub
Private Sub RectPrint(x1 As Single, y1 As Single, _
x2 As Single, y2 As Single)
Rectangle MyPrinter.Handle, _
x1 * MyPrinter.PixPerInchX - MyPrinter.OffsetX, _
y1 * MyPrinter.PixPerInchY - MyPrinter.OffsetY, _
x2 * MyPrinter.PixPerInchX - MyPrinter.OffsetX, _
y2 * MyPrinter.PixPerInchY - MyPrinter.OffsetY
End Sub
Private Sub Form_Unload(Cancel As Integer)
Dim lret As Long
If MyPrinter.Handle <> 0 Then
' Reset font back to original and delete font we created
lret = SelectObject(MyPrinter.Handle, hOldfont)
lret = DeleteObject(hNewFont) 'Delete the font object
' delete the device context (I'm not sure whether the VB
' CommnonDialog will automaticallty delete the dc it
' created, but I don't suppose it can do any harm to
' delete it here).
DeleteDC MyPrinter.Handle
End If
End Sub
Private Sub Command1_Click()
Dim lret As Long, s1 As String, docinf As DOCINFO
GetMyPrinter
If UserCancelled Then
Exit Sub
End If
' start a document
docinf.cbSize = 20 ' Size of DOCINFO structure
lret = StartDoc(MyPrinter.Handle, docinf) 'Start new document
lret = StartPage(MyPrinter.Handle) 'Start a new page
' print a rectangle using the default pen to show a
' full page one inch border
RectPrint 1, 1, MyPrinter.PageWidthInches - 1, _
MyPrinter.PageHeightInches - 1
' now print some text
s1 = "Text is positioned so that the bottom left corner "
TextPrint s1, 2, 2 ' print some text at position (2, 2)
s1 = "of the *character cell* of the first character is "
TextPrint s1, 2, 2.2
s1 = "at the specified position. This example code also "
TextPrint s1, 2, 2.4
s1 = "prints a rectangle with an exact one inch border."
TextPrint s1, 2, 2.6
' end page and document
lret = EndPage(MyPrinter.Handle) 'End the page
lret = EndDoc(MyPrinter.Handle) 'End the document
End Sub
| |
| Mike Williams 2006-01-27, 3:55 am |
| "Mike Williams" <Mike@WhiskyAndCoke.com> wrote in message
news:OPCbcTyIGHA.3936@TK2MSFTNGP12.phx.gbl...
.. . . by the way, there is a slight "typo" in the code I posted. In the code
I said that text is positioned so that the bottom left corner of the
character cell is at the specified position. I of course meant to say the
*top left corner* of the character cell :-(
Mike
|
|
|
|
|