Improve company productivity with a Business Account.Sign Up

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1093
  • Last Modified:

Getting the LPT port

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
jsweby
Asked:
jsweby
  • 16
  • 8
  • 7
  • +1
1 Solution
 
MadshiCommented:
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
 
jswebyAuthor Commented:
I'm inclined to agree with you but I'll keep my options open just for a bit...

Thanks.
0
 
MadshiCommented:
Of course, you should do that...  :-)
0
Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
heathprovostCommented:
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
 
MadshiCommented:
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
 
ZifNabCommented:
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
 
MadshiCommented:
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
 
MadshiCommented:
Hi Zif,

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

Regards, Madshi.
0
 
ZifNabCommented:
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
 
ZifNabCommented:
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
 
ZifNabCommented:
Madshi, got it... you mean it will return the same info as with Print_info_4 and 5. Too bad.
Zif.
0
 
heathprovostCommented:
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
 
MadshiCommented:
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
 
heathprovostCommented:
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
 
heathprovostCommented:
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
 
MadshiCommented:
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
 
heathprovostCommented:
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
 
heathprovostCommented:
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
 
MadshiCommented:
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
 
jswebyAuthor Commented:
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
 
MadshiCommented:
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
 
jswebyAuthor Commented:
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
 
MadshiCommented:
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
 
jswebyAuthor Commented:
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
 
ZifNabCommented:
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
 
MadshiCommented:
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
 
jswebyAuthor Commented:
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
 
MadshiCommented:
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
 
jswebyAuthor Commented:
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
 
jswebyAuthor Commented:
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
 
MadshiCommented:
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
 
jswebyAuthor Commented:
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
 
MadshiCommented:
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
 
ZifNabCommented:
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
 
MadshiCommented:
Zif, that's kind from you, thank you...  :-)

P.S: Be cautious, I need only 100.000 more points to overtake you...  :-)))
0
 
ZifNabCommented:
yes, Madshi I'm watching you closely :-)
0
 
MadshiCommented:
:-)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

  • 16
  • 8
  • 7
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now