Tom said:
I am converting an old application that was printing directly to a
specialized printer device (i.e. a special label printer). It was doing this
by opening a file with the file path of 'LPT1:' and then using PRINT # to
print directly to the printer device.
Obviously, this is not going to work under VB.NET - StreamWriter won't let
you open a device like LPT1: and such. I assume I am going to have to switch
to the System.Drawing.Printing namespace to do this? And if so, is this
going to work the same way? (i.e. this printer needs special codes and such
sent to it - which my code does, but it is not a general-purpose printer).
Or is there another way to do it? And, since the users default printer may
NOT be the LPT1: device (i.e. their default printer would probably be a
network printer, with the label printer as a locally attached printer), how
do I specify that I want it to print on the printer that is connected to
LPT1:?
Thanks in advance.
Tom
Hi Tom,
I'm just visiting this NG for the first time and I'm not yet a VS .NET
developer, but this is soon to change ;-)
At the moment I develop in CA-Visual Objects and have an app which, by
using several of the WinAPI functions, does some of what you need -
here is the CA-VO code to print to an UBI label-printer. The really
useful stuff is the bit entitled "Print this page" - here, the WinAPI
functions OpenPrinter, StartDocPrinter, WritePrinter, EndDocPrinter
and ClosePrinter are being used to send raw data to (in this case) a
printer attached locally to LPT1, and which has been assigned a name
via the Windows Printer setup Assistant.
If you don't wish to have to use such a name, but instead send raw
data to the port LPT1, I believe (but I haven't tried it!) that you
could use the winAPI function SetPrinter(hPrinter, dwLevel, pPrinter,
dwCommand), where the second argument (dwLevel) specifies the type of
data contained in the pPrinter argument. pPrinter is a pointer to an
array that contains one of the PRINTER_INFO_X structures, where X can
be one of 2, 3, 4, 5 or 6. Now, if dwLevel is equal to 2 (OK for Win
95 and NT+2K+XP), then the pPrinter array contains a PRINTER_INFO_2
structure and this structure contains a member pPortName, which is a
pointer to a null-terminated string that identifies the port (LPT1,
LPT2, etc.) used to transmit data to the printer. See, eg.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/prntspol_13ua.asp
for more info.
HTH, Robertino
CLASS WELabel_WAPI
PROTECT oOwner AS USUAL
PROTECT aWELData AS ARRAY
PROTECT cBkgCmd, cDataCmd AS STRING
METHOD Init(oOwner, aWELData) CLASS WELabel_WAPI
SELF

Owner := oOwner
SELF:aWELData := aWELData
RETURN SELF
METHOD Print() CLASS WELabel_WAPI
LOCAL lResult AS LOGIC
LOCAL hPrinter AS PTR
LOCAL pszPrinter AS PSZ
LOCAL pBuffer AS PTR
LOCAL dwWritten AS DWORD
LOCAL pDocInfo IS _winDoc_Info_1
LOCAL cCmdString, cEinh AS STRING
LOCAL nTotalMenge, nPerPack, nInThisPack, nDiv AS FLOAT
LOCAL nLabelCount, nTotalLabels AS DWORD
LOCAL lHasSerNums AS LOGIC
lResult := FALSE
nTotalMenge := SELF:aWELData[4]
nPerPack := SELF:aWELData[5]
lHasSerNums := !Empty(SELF:aWELData[6])
// For fractional quantities (not actually needed!!)....
IF (cEinh $ "stkpcsea") // "st", "stk", "pc", "pcs", "ea".......
IF (((nTotalMenge - Floor(nTotalMenge)) != 0) .or. ((nPerPack -
Floor(nPerPack)) != 0))
// Do nothing...
ELSE
// ...ditto...
ENDIF
ELSE
ENDIF
nDiv := FLOAT(nTotalMenge) / FLOAT(nPerPack)
nTotalLabels := Ceil(nDiv)
//TEXTbox{SELF

Owner, , "nTotalLabels = " +
NTrim(nTotalLabels)}:Show()
nLabelCount := 0
//nTotalLabels := 1 // Test...
DO WHILE (nLabelCount < nTotalLabels)
nLabelCount ++
IF (nTotalMenge >= nPerPack)
nInThisPack := nPerPack
ELSE
nInThisPack := nTotalMenge
ENDIF
nTotalMenge -= nInThisPack
//textbox{, , "nInThisPack = " + NTrim(nInThisPack)}:Show()
SELF:SetupFormBackground(nTotalLabels, nLabelCount)
SELF:SetupFormData(nInThisPack, nLabelCount)
cCmdString := SELF:cBkgCmd + SELF:cDataCmd
// Print this page.......
pszPrinter := StringAlloc(VL_PRINTER_NAME + _chr(0))
IF OpenPrinter(pszPrinter, @hPrinter, NULL)
pBuffer := StringAlloc(cCmdString + _chr(0))
pDocInfo.pDocName := String2Psz("Versand-Label")
IF StartDocPrinter(hPrinter, 1, @pDocInfo)<>0
IF WritePrinter(hPrinter, pBuffer, SLen(cCmdString), @dwWritten)
IF (dwWritten == SLen(cCmdString))
lResult := TRUE
END
ELSE
dwWritten := GetLastError()
END
EndDocPrinter(hPrinter)
ELSE
dwWritten := GetLastError()
END
MemFree(pBuffer)
ClosePrinter(hPrinter)
ELSE
dwWritten := GetLastError()
END
MemFree(pszPrinter)
// End print this page...
ENDDO
RETURN NIL
METHOD SetupFormBackground(nTotalLabels, nLabelCount) CLASS
WELabel_WAPI
LOCAL cBkg, cFarb, cXRef, cYRef, cQ, cFrmBkupMode AS STRING
cQ := _chr(34)
cFarb := "N," // N="N/W", R="W/N".......
cXRef := PadL(NTrim(Floor(Val(LABEL_X_ORIGIN) * 8)), 3, "0")
cYRef := PadL(NTrim(Floor(Val(LABEL_Y_ORIGIN) * -8)), 3, "0")
// "Form Backup" occurs when the paper is retracted at the start of a
label -
// for longer print runs (multiple labels), we want to turn this off
until
// the last label in the print run is reached. Then turn it back on
again,
// so that the last label will be in the correct "tear-off" position.
cFrmBkupMode := Iif((nLabelCount < (nTotalLabels)), "JB", "JF")
// Set up coordinates and Form (8 dots per mm.)................
cBkg := cLF // Start command
structure...
cBkg += "N"+cLF // Clear image memory...
cBkg += "M117,0,0"+cLF // All memory to Direct
Mode...
cBkg += cFrmBkupMode+cLF // Form backup-mode...
cBkg += "ZB"+cLF // Set print direction...
cBkg += "R" + cXRef + "," + cYRef +cLF // Set reference point (so
we can move whole form dynamically)...
cBkg += "q832"+cLF // Set label width
(paper-width) (104)...
cBkg += "Q440,16"+cLF // Set Form-length
(paper-height) (55) and gap-width (2)...
cBkg += "X0,0,3,800,408"+cLF // Border rectangle
(form-width and -height) (100 * 51) to leave 2mm free all round......
cBkg += "LO0,40,800,3"+cLF // Horizontal line 1......
cBkg += "LO0,184,800,1"+cLF // Horizontal line 2......
cBkg += "LO440,216,360,1"+cLF // Horizontal line 3......
cBkg += "LO640,40,1,144"+cLF // Vertical line 1....
cBkg += "LO440,184,1,224"+cLF // Vertical line 2....
cBkg += "I8,2,049"+cLF // Character-set....
//TEXTBox{, , "cBkg = " + cBkg}:Show()
// Print top headers..............................
cBkg += "A16,12,0,4,1,1,N," + cQ + "BlahBlah GmbH, Germany" + cQ +
cLF // Print text...
cBkg += "A704,12,0,4,1,1,N," + cQ + "C1572" + cQ + cLF
// Print text...
// Print mid headers..............................
cBkg += "A16,64,0,2,1,1,N,"+cQ+ "Part Number:"+cQ+cLF //
Print text...
cBkg += "A16,96,0,2,1,1,N,"+cQ+ "Part Name..:"+cQ+cLF //
Print text...
cBkg += "A16,128,0,2,1,1,N,"+cQ+ "Revision...:"+cQ+cLF // Print
text...
cBkg += "A16,160,0,2,1,1,N,"+cQ+ "Serial No..:"+cQ+cLF //
Print text...
cBkg += "A320,160,0,2,1,1,N,"+cQ+ "LBA Cert.:"+cQ+cLF // Print
text...
cBkg += "A648,160,0,2,1,1,N,"+cQ+ "Stamp"+cQ+cLF // Print
text...
// Print lower LH headers..............................
cBkg += "A16,270,0,2,1,1,N,"+cQ+ "WE-Number..:"+cQ+cLF // Print
text...
cBkg += "A16,302,0,2,1,1,N,"+cQ+ "Order No...:"+cQ+cLF // Print
text...
cBkg += "A16,334,0,2,1,1,N,"+cQ+ "Batch No...:"+cQ+cLF // Print
text...
cBkg += "A16,366,0,2,1,1,N,"+cQ+ "Charge No..:"+cQ+cLF // Print
text...
// Print lower RH headers..............................
cBkg += "A480,196,0,2,1,1,N,"+cQ+ "Limited Shelf-Life Part"+cQ+cLF
// Print text...
cBkg += "A456,248,0,2,1,1,N,"+cQ+ "Mfg Date....:"+cQ+cLF //
Print text...
cBkg += "A456,280,0,2,1,1,N,"+cQ+ "Shelf-Life..:"+cQ+cLF //
Print text...
cBkg += "A456,312,0,2,1,1,N,"+cQ+ "Expiry Date :"+cQ+cLF //
Print text...
cBkg += "A456,344,0,2,1,1,N,"+cQ+ "Storage Date:"+cQ+cLF //
Print text...
SELF:cBkgCmd := cBkg
RETURN NIL
METHOD SetupFormData(nInThisPack, nLabelCount) CLASS WELabel_WAPI
LOCAL cData, cFarb, cQ AS STRING
LOCAL cTKZ, cRev, cSNVon, cSerN, cWENum, cOrdNum, cBatch, cChargeNum,
cShLDate AS STRING
LOCAL cShLife, cMfDate, cCuDate, cWEDate, cBen AS STRING
LOCAL cZNum, cZTyp, cZJahr, cZert, cCure, cLSN, cPos AS STRING
LOCAL nDrkZahl AS BYTE
cQ := _chr(34)
cFarb := "N," // N="N/W", R="W/N".......
nDrkZahl := 1
cTKZ := SELF:aWELData[1]
cBen := SELF:aWELData[2]
cRev := SELF:aWELData[3]
cSNVon := SELF:aWELData[6]
IF !Empty(cSNVon)
cSerN := NTrim(Val(cSNVon) + nLabelCount - 1)
ELSE
cSerN := "N/A"
ENDIF
cZert := SELF:aWELData[7]
cWENum := SELF:aWELData[8]
cOrdNum := SELF:aWELData[9]
cBatch := SELF:aWELData[10]
cChargeNum := SELF:aWELData[11]
cMfDate := SELF:aWELData[12]
cShLife := AllTrim(SELF:aWELData[13])
cShLDate := AllTrim(SELF:aWELData[14])
cWEDate := AllTrim(SELF:aWELData[15])
// Print Part-Details.........................
cData += "A168,58,0,4,1,1,"+cFarb+cQ+cTKZ+cQ+cLF // Print text...
cData += "A168,90,0,4,1,1,"+cFarb+cQ+cBen+cQ+cLF // Print text...
cData += "A168,122,0,4,1,1,"+cFarb+cQ+cRev+cQ+cLF // Print text...
cData += "A168,154,0,4,1,1,"+cFarb+cQ+cSerN+cQ+cLF // Print
text...
cData += "A448,154,0,4,1,1,"+cFarb+cQ+cZert+cQ+cLF // Print
text...
cData += "A168,266,0,4,1,1,"+cFarb+cQ+cWENum+cQ+cLF // Print
text...
cData += "A168,298,0,4,1,1,"+cFarb+cQ+cOrdNum+cQ+cLF // Print
text...
cData += "A168,330,0,4,1,1,"+cFarb+cQ+cBatch+cQ+cLF // Print
text...
cData += "A168,362,0,4,1,1,"+cFarb+cQ+cChargeNum+cQ+cLF // Print
text...
cData += "A620,242,0,4,1,1,"+cFarb+cQ+cMfDate+cQ+cLF // Print
text...
cData += "A620,274,0,4,1,1,"+cFarb+cQ+cShLife+cQ+cLF // Print
text...
cData += "A620,306,0,4,1,1,"+cFarb+cQ+cShLDate+cQ+cLF // Print
text...
cData += "A620,338,0,4,1,1,"+cFarb+cQ+cWEDate+cQ+cLF // Print
text...
// Final command to printer to print.........
cData += "P1,"+LTrim(Str(nDrkZahl))+cLF // Print contents of image
buffer...
SELF:cDataCmd := cData
RETURN NIL