Solved

Getting the LPT port

Posted on 1999-01-04
37
1,015 Views
Last Modified: 2010-05-18
I am trying to automatically determine the LPT port of a printer when it selected from the TPrinter.Printers list. I tried using the TPrinter.GetPrinter method, but the value passed back to the Device variable is a network path if the printer is set up on the network. Is there a way of getting the LPT port of this printer whether or not it is on the network?
0
Comment
Question by:jsweby
  • 16
  • 8
  • 7
  • +1
37 Comments
 
LVL 20

Expert Comment

by:Madshi
ID: 1354440
If you look into the properties page of the printer in the explorer shell, you'll not find the LPT port of a network printer, either.
So I'm quite sure: If windows doesn't show it in the shell, you won't be able to ask for it, either...  :-(
Sorry...

Regards, Madshi.
0
 
LVL 4

Author Comment

by:jsweby
ID: 1354441
I'm inclined to agree with you but I'll keep my options open just for a bit...

Thanks.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1354442
Of course, you should do that...  :-)
0
 
LVL 5

Expert Comment

by:heathprovost
ID: 1354443
I agree with Madshi on this one. However, if you may be able to get the information you want by using this function as per Win32 API:

WNetGetConnection

The WNetGetConnection function retrieves the name of the network resource associated with a local device.

DWORD WNetGetConnection(

    LPTSTR  lpszLocalName,      // address of local name
    LPTSTR  lpszRemoteName,      // address of buffer for remote name
    LPDWORD  lpcchBuffer       // address of buffer size, in characters  
   );      
Parameters

lpszLocalName

Points to a null-terminated string that specifies the name of the local device to get the network name for.

lpszRemoteName

Points to a buffer that receives the null-terminated remote name used to make the connection.

lpcchBuffer

Points to a variable that specifies the size, in characters, of the buffer pointed to by the lpszRemoteName parameter. If the function fails because the buffer is not big enough, this parameter returns the required buffer size.

Return Value

If the function succeeds, the return value is NO_ERROR.
If the function fails, the return value is an error code. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

Value      Meaning
ERROR_BAD_DEVICE      The string pointed to by the lpszLocalName parameter is invalid.
ERROR_NOT_CONNECTED      The device specified by lpszLocalName is not redirected.
ERROR_MORE_DATA      The buffer is too small. The lpcchBuffer parameter points to a variable that contains the required buffer size.
ERROR_CONNECTION_UNAVAIL      The device is not currently connected, but it is a persistent connection.
ERROR_NO_NETWORK      No network is present.
ERROR_EXTENDED_ERROR      A network-specific error occurred. To get a description of the error, use the WNetGetLastError function.
ERROR_NO_NET_OR_BAD_PATH      None of the providers recognized this local name as having a connection. However, the network is not available for at least one provider to whom the connection may belong.
The WNetGetConnection function returns error codes for compatibility with Windows version 3.1. For compatibility with the Win32 API, the function also sets the error code value returned by GetLastError.

Maybe you could try calling each LPT port in sequence and checking to see if matches your printer.  Kind of backwards but it should work. I dont have network set up so I cant write any code :(  Madshi, you wanna give it a try?

0
 
LVL 20

Expert Comment

by:Madshi
ID: 1354444
Heathprovost,

Have no network at home, only at work. So I can't test it, either. However this is what I'm thinking:
Normally you don't share the LPT port, but the printer itself. That means you call the "NetShareAdd" function with the name of the printer (not with "LPT1" or something like that). So I guess, what you will get from the WNetGetConnection function will be the name of the printer, not the LPT port.

Regards, Madshi.
0
 
LVL 8

Expert Comment

by:ZifNab
ID: 1354445
Hi jsweby,

or you working on NT or 95?

Because if I believe Delphi uses level 4 (NT) and level 5 (95) of printer info when retrieving info from printer with GetPrinter. I believe if you use level 2, you get the info you need in the pPortname. I think level 2 can give some problems when servers are down etc.
But I must admit that I haven't tried this yet. You should call it like this... :

Var
                                 pInfo: PPrinterInfo2;
                                 bytesNeeded: DWORD;
                                 hPrinter: THandle;
         
                               Begin

                                 GetPrinter( hPrinter, 2, Nil, 0, @bytesNeeded );
                                 pInfo := AllocMem( bytesNeeded );
                                 try
                                   GetPrinter( hPrinter, 2, pInfo, bytesNeeded, @bytesNeeded );
                                   With pInfo^ Do Begin

                                   End;
                                 finally
                                   FreeMem( pInfo );
                                 end;
         
                               end;

Regards, Zif.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1354446
I mean the local printer port will look like "\\serverName\printerShare", where printerShare will point to e.g. "HP Deskjet 850". So if you call WNetGetConnection("printerShare"), you'll get "HP Deskjet 850"...   :-(
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1354447
Hi Zif,

the portname is in this case the UNC path of the server ("\\printServer\printShare"), not the LPT port...   :-(

Regards, Madshi.
0
 
LVL 8

Expert Comment

by:ZifNab
ID: 1354448
jsweby,

I'm not sure if all these things work on a network... Because, if you retrieve information from a printer which resides somewhere on the net, I don't think you get the right information of ports, because this printer isn't physically connected to your printer. Maybe you better search the registry for it. You can find the printerports in there.

But as I said, don't know the result of Print_info_2.

Zif.
0
 
LVL 8

Expert Comment

by:ZifNab
ID: 1354449
Madshi, can you explain more?

In the docs you get this explenation :

pServerName

Points to a null-terminated string identifying the server that controls the printer. If this string is NULL, the printer is controlled locally.

pPrinterName

Points to a null-terminated string that specifies the name of the printer.

pShareName

Points to a null-terminated string that identifies the sharepoint for the printer. (This string is used only if the PRINTER_ATTRIBUTE_SHARED constant was set for the Attributes member.)

pPortName

Points to a null-terminated string that identifies the port(s) used to transmit data to the printer. If a printer is connected to more than one port, the names of each port must be separated by commas (for example, "LPT1:,LPT2:,LPT3:").

Zif.
0
 
LVL 8

Expert Comment

by:ZifNab
ID: 1354450
Madshi, got it... you mean it will return the same info as with Print_info_4 and 5. Too bad.
Zif.
0
 
LVL 5

Expert Comment

by:heathprovost
ID: 1354451
MAdshi, I dont think I agree on that one.  It is funny though since neither of us can really test this :).  Bu the API reference says the function will fill lpszRemoteName with a pointer that

"Points to a buffer that receives the null-terminated remote name USED TO MAKE THE CONNECTION" (im not yelling, just highlighting)

That sounds to me like a UNC path - which is what he gets back from TPrinter.GetPrinter.  Maybe the questioner should try this since no one else can :)
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1354452
Zif,

I think on the print-server side these values will look like this:

pServerName = nil
pPrinterName = "HP Deskjet 850"
pShareName = "DESKJET"
pPortName = "LPT1:"

And on the client side:

pServerName = "printServ"
pPrinterName = "HP Deskjet 850"
pShareName = "DESKJET"
pPortName = "\\printServ\DESKJET"

Heathprovest,

I'm sorry, I misunderstood what you suggested. You want to give in "LPT1:" as lpszLocalName and you want to receive the name of the share?
That would work, but only if the LPT would be shared, not if the printer itself is shared - what is the normal way to share a printer. You CAN share a LPT, but normally you share the printer itself. Then WNetGetConnection will tell you, that LPT1 is not connected.
I first thought you wanted to call NetShareGetInfo to get the local share path that belongs to the share name.

Regards, Madshi.
0
 
LVL 5

Expert Comment

by:heathprovost
ID: 1354453
Maybe I am misunderstanding the question, i will restate in my own words - please tell me if this is correct or not:

You want to find out what LPT port a printer that is shared on another machine is mapped to.  i.e. if the said printer has a parallel port mapped to it, what port is it?  

Scenerio: You have a pinter called "HP Deskjet" which resides on another machine on the network.  It has been mapped to LPT2:.  You want to programmically determine what LPT port it is mapped to given the UNC path of the printer.

If my understanding of question is correct, please let me know.
0
 
LVL 5

Expert Comment

by:heathprovost
ID: 1354454
BTW, I am not sure I understand what you mean by "Sharing the LPT port".  How do you share a port?  Wouldnt that be the same thing as mapping a port to a UNC share?  I am confused.  Please respond.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1354455
Heathprovost,

there are two different methods to share a printer. I'll describe them by looking at my win95 printer properties dialog box (with german texts). I hope you can follow me...

(1) In the "details" page there's a button like "connect printer port" and a button "delete connection" or something like that. I mean the two big buttons under the driver combo box. With these buttons you can connect a printer port - let's say "LPT1:" to an UNC path - let's say "\\printServ\lpt1Share". Right? From what you're writing I guess this is the method you're thinking of. In the top edit/combobox ("printer port") there is still written "lpt1:". The printer-server has to share his lpt1 with the share name "lpt1Share". That means if you write "dir >lpt1" in dos the listing will be printed on the server printer.
(2) The second method is that the printer server does not share his LPT1 port but his printer driver (with the name "HP DeskJet"). It doesn't matter to which port the printer driver at the server is connected to. Now in the client dialog box you don't connect lpt1 to "printServ\lpt1Share". You don't connect LPT1 at all, but you simply write into the port edit/combobox the UNC path of the server printer driver share "printServ\DESKJET". That means if you call "dir >lpt1", windows will show an error message, because there's simply no printer at the local port lpt1. But if you print in WinWord to the local printer driver "HP DeskJet", everything is fine. You can change the printer port from the printer driver at the server without having to adjust the client settings.
The second solution is the mostly used solution - and if you look at the original question text - you'll see that jsweby gets the UNC path of the printer from the Port property (-> from the port edit/combobox). That means he's using the second solution, too.

Uffff... Man, that was hard stuff...   :-)

Regards, Madshi.
0
 
LVL 5

Expert Comment

by:heathprovost
ID: 1354456
We were thinking along the same lines then.  What my solution would provide is the LPT port that a printer is using IF and only IF an LPT port has been mapped to it.  If an LPT port is NOT mapped to it, I dont understand what information he would be trying to get.  Could it be the LPT port on the remote machine? I mean the one with the printer physically attached? If that is the case I humbly withdraw my solution because it DEFINITELY would not work.  I dont know of a way to do that.
0
 
LVL 5

Expert Comment

by:heathprovost
ID: 1354457
Let me clarify this way.  Regardless of whether a remote printer has an LPT port mapped to it or not, wouldnt TPrinter.GetPrinter return the UNC path?  I mean you cant have an LPT port mapped to nothing and UNC paths are the default method of refering to remote printer shares.  Is my logic flawed?
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 20

Expert Comment

by:Madshi
ID: 1354458
Hmm. I didn't test whether the GetPrinter returns the UNC path or the local lpt port when you've mapped the LPT port. I thought it would return the local lpt port.
However, neither of these possibilites would help, since jsweby wants to know (AFAIK understand him) to what lpt port the printer is mapped AT THE SERVER. And since the printer mapping normally goes to the server printer driver and not to the server printer port, we'll probably have no chance to get this information.
Do we agree that the printer server shares his printer driver and NOT his printer port?

Regards, Madshi.
0
 
LVL 4

Author Comment

by:jsweby
ID: 1354459
Hey guys, I wasn't expecting such a great response, cheers. Using Win '95, BTW. To clarify:

I want to send a text file to a printer of user's choosing. We are adding control strings to it and all sorts, and basically I don't want Windows to have anything to do with it. If I send the text file to the print queue for a printer, Windows wraps it all up nicely and the resulting print is different to what was in the text file. However, if you say in DOS:

copy temp.txt > lpt1

then the text file is sent directly to LPT1 without Windows interfering. If you say:

copy temp.text \\Server\printer1

then nothing happens.

The DOS command above is translated into Delphi as:

CopyFile(PChar('temp.txt'),PChar('LPT1'),False);

What I want is to let the user pick a printer from the list available and for me to work out its printer port. But as you've correctly pointed out so far, some printers don't have an LPT port assigned to them if they are a Windows only printer and so the GetPrinter method returns the UNC address of the printer.

Therefore, I don't think there is a surefire way of getting the LPT port of any networked printer, because some don't have an LPT port.

Right? So can anyone suggest another method of printing that stops Windows intercepting the print job and wrapping it?
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1354460
Hmm. If the printer is located at another computer AND there's no LPT connection to the printer? How should that work? I don't think your printer is able to get the data through telepathy...  :-)
So either you will have to let Windows do the work (and wrap the job :-() or you could temporarely map a lpt port to the printer and unmap it after the printing, again. But that's quite difficult, because how do you know if the printing is ready? Perhaps you would unmap the port before all pages are printed.

Hmmm. Tell me what is different if you let windows print the text? And HOW did you let windows print the text?

Regards, Madshi.
0
 
LVL 4

Author Comment

by:jsweby
ID: 1354461
A Windows printer does not have an LPT port assigned to it automatically through a network, only on the print server or the machine it is connected to. On the network, a printer is accessed by its UNC address, not by its LPT port, unless the printer has been set up to deal with MS-DOS print jobs, in which case an LPT port is assigned.

I like the idea of capturing a port at run-time and then ending the capture when I'm finished with it. Any idea how to do that in Delphi/API?

The reason I am doing it like this is because I am printing official documents , some of which are on listing paper, which unfortunately means dot-matrix printers. If I send my job through Windows (using the TPrintdialog.Execute, etc.), then Windows takes my file, wraps it up all nicely and tells the printer what to do with it. However, this isn't always what I want because in some cases, I need to print in small characters (10cpi), but any control characters I send get overwritten by Windows before the printer starts its job. If I send the job to the LPT port, the control characters are not overwritten by Windows.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1354462
You can use WNetAddConnection2 to establish the lpt port connection and WNetCancelConnection to cancel the connection. But as I said, I don't know from where you can get if all pages are printed...

Regards, Madshi.
0
 
LVL 4

Author Comment

by:jsweby
ID: 1354463
I have practiced using the WNetAdd/CancelConnection functions and they are almost perfect. The one thing that would be better wuold be to use the API command GetPrinter (not to be confused with the Delphi TPrinter.GetPrinter method).

I've written the following procedure:

procedure TfrmMain.Button4Click(Sender: TObject);
Var
   tBuffer: TPrinterInfo5;
   iVal: PDWord;
begin
     Printer.PrinterIndex := ComboBox1.ItemIndex;
     Printer.GetPrinter(Device,Driver,Port,DeviceMode);

     iVal := PDWord(100);
     GetPrinter(Printer.Handle,5,@tBuffer,100,iVal);
     Label5.Caption := tBuffer.pPrinterName;
     Label5.Caption := Label5.Caption +','+tBuffer.pPortName;
end;

However, I get an Access Error and nothing is displayed at Label5.Caption, except gibberish sometimes. Why doesn't this work? It would be ideal because it lists the LPT ports that the specified printer has assigned to it, in the Buffer.pPortName property.
0
 
LVL 8

Expert Comment

by:ZifNab
ID: 1354464
jsweby, I don't know if this would give you the correct info :

see my proposal at  From: ZifNab  Date: Monday, January 04 1999 - 10:14AM PST (From: ZifNab Date: Monday, January 04 1999 - 10:27AM PST). In this example we don't use the GetPrinter from TPrinter.GetPrinter, we use the windows API GetPrinter.

see for following comments to get the idea, why we think it will not give you the right info, especially at :  From: Madshi Date: Monday, January 04 1999 - 11:45AM PST

Try your example with code I gave you. And report results. Thanks.

Zif.

0
 
LVL 20

Expert Comment

by:Madshi
ID: 1354465
jsweby,

the windows.GetPrinter function returns more than the size of TPrinterInfo5. You tell him that the buffer you give in (tBuffer) would have a size of 100 bytes, but it has only a size of "sizeOf(TPrinterInfo5)" bytes. So windows.GetPrinter overwrites memory.

However Zif is right, we've already thought about this windows.GetPrinter solution. It doesn't return more useful info for you then the Printer.GetPrinter function does...

So it won't help you. Buffer.pPortName will give you the UNC path, too...   :-(

Regards, Madshi.
0
 
LVL 4

Author Comment

by:jsweby
ID: 1354466
I had a root around the registrey and under:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Print\Printers

is a list of the printers by name. If you look at each printer, there is a key called "Port" which lists either a UNC address or an LPT port. This could be the breakthrough!
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1354467
That's the same information the you get from windows.GetPrinter and from Printer.GetPrinter. (Actually Printer.GetPrinter is based on windows.GetPrinter and windows.GetPrinter is based on this registry keys).
It's either an UNC address or an LPT port - not both. So if the printer is located at another computer, it's again only the UNC path...  :-(

Regards, Madshi.
0
 
LVL 4

Author Comment

by:jsweby
ID: 1354468
No, if the printer is located at another computer, it isn't always the UNC path. We have 3 printres here on a print server. Two are set up as Windows printers and the registry key shows their port as a UNC address. The third printer is set up in Windows but with the MS-DOS printing turned on, and the Port key in the registry is "LPT1:".
0
 
LVL 4

Author Comment

by:jsweby
ID: 1354469
How about this:

Check to see if an LPT port has a printer assigned to it (WNetGetConnection). If so, then move to another LPT port and check that.

Continue to do this until we find a free LPT port. Then temporarily capture the printer in question to the LPT port, do the print job, then disconnect the capture.

The only thing that would go one better would be to look at the printer and see if it has an LPT port assigned. Do you think I could rely on the registry key mentioned above to provide this information consistently?
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1354470
Hmm. As I said, I think windows.GetPrinter is based on this registry key. So if the one printer with MS-DOS printing turned on has the lpt port in the registry, I'm quite sure, GetPrinter for THIS printer will give you the lpt port, too. Please try that...

So I would suggest this method:
(1) Check if you get a lptX port. If yes: then use it.
(2) If not, look for a free port and map it temporarily.

Regards, Madshi.
0
 
LVL 4

Author Comment

by:jsweby
ID: 1354471
Madshi,

That is exactly what I'm going to do. If you want the points, convert your last comment into an answer. It's a shame I can't split the points between you all. First come, first served...

Regards and thanks,

Jason (jsweby)
0
 
LVL 20

Accepted Solution

by:
Madshi earned 100 total points
ID: 1354472
I think often the points should be splitted between several experts...

Sorry, heathprovost and ZifNab, but since I had the idea with the temporarily mapping, I'm impudent enough to steal the points this time...    :-)

Thanx for the points, Jason!

Regards, Madshi.
0
 
LVL 8

Expert Comment

by:ZifNab
ID: 1354473
Madshi, my pleasure :-). But your lucky, because I could have answered this question already at 7:15 AM PST. But I found that some people deserved it more.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1354474
Zif, that's kind from you, thank you...  :-)

P.S: Be cautious, I need only 100.000 more points to overtake you...  :-)))
0
 
LVL 8

Expert Comment

by:ZifNab
ID: 1354475
yes, Madshi I'm watching you closely :-)
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1354476
:-)
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now