Thread: OpenPrinter

  1. #1
    Master of Puppets rwmarsh's Avatar
    Join Date
    Feb 2006
    Location
    Texas
    Posts
    96

    OpenPrinter

    I am just learning about API functions and writing a simple program to send data to the printer. Here is what I have so far
    Code:
    #include <iostream>
    #include <windows.h>
    #include <winspool.h>
    
    using namespace std;
    
    int main()
    {
        char test[] = "This is a test line to be printed.";
        
        LPHANDLE hPrinter;
        LPBYTE DocInfo;   
        LPVOID Buff = test;
        DWORD read;
        LPDWORD written;
    
        OpenPrinter("HP DeskJet 712C", hPrinter, NULL);
        StartDocPrinter(hPrinter, 1, (LPBYTE)&DocInfo);
        StartPagePrinter(hPrinter);
    
        WritePrinter(hPrinter, Buff, read, written); 
    
        EndPagePrinter(hPrinter);
        EndDocPrinter(hPrinter);
        ClosePrinter(hPrinter);
    
        cout<<"Test line sent to printer"<<endl
            <<"Hit <enter> to end";
        cin.get();
        return 0;
    }
    This is giving me a linker error - undefined reference to all seven printer functin calls. I have heard I have to link with 'winspool.lib' so I put this in
    Code:
    #pragma comment(lib, "winspool.lib")
    but still get the same linker error. I did a search in my compiler directories and could not find 'winspool.lib' but there was a 'libwinspool' in my lib directory. Tried that with the same linker error. Are those two files the same or different? Or is there something else wrong?

    I am using DEV-C++
    Using DEV-C++ Under Windows XP
    +------------------------------+

    "No! Do, or Do Not. There is no Try..."

  2. #2
    erstwhile
    Join Date
    Jan 2002
    Posts
    2,227
    #pragma comment(lib, "winspool.lib")
    This is specific to microsoft compilers and it's a rare (ab)user of an ms compiler who will actually bother to either wrap up such abominations within a preprocessor conditional block with __MSC_VER as the condition or actually use the linker setting in their compiler's project setting to link libraries as they arguably should be doing anyway in order to give their code half a chance of working with other compilers(winapi stuff, anyway).

    Anyway, my irreverant and possibly irrelevant rants aside, you need to link the library into your project options using MinGW/gcc syntax. Here's a copy from an old post of mine which should hopefully be of some help (I've edited it a little to better reflect your problem):
    Quote Originally Posted by Ken Fitlike
    Library names are different with MinGW, the compiler tool set for which dev-cpp is one ide for. The libraries are prefixed with 'lib' and have an 'a' extension so, winspool.lib becomes 'libwinspool.a'. However, it's more usual to pass -lname_of_lib_without_prefix_or_extension to the linker; and that is a small case letter 'L' at the start, if you're in any doubt.

    Do the following in Dev-cpp to add that particular library to your project:

    Project menu -->project options --> parameters tab, add -lwinspool to the 'linker' field.
    Last edited by Ken Fitlike; 03-24-2006 at 06:19 PM. Reason: grammar & typos
    CProgramming FAQ
    Caution: this person may be a carrier of the misinformation virus.

  3. #3
    Master of Puppets rwmarsh's Avatar
    Join Date
    Feb 2006
    Location
    Texas
    Posts
    96
    Hey, Thanks for the help, Ken!! I have been looking all over the net today (well, when I had free time at work that is) and have not been able to come up with anything or anyone that can help. I will do that tonight when I get off work and see what happens!!
    Using DEV-C++ Under Windows XP
    +------------------------------+

    "No! Do, or Do Not. There is no Try..."

  4. #4
    Master of Puppets rwmarsh's Avatar
    Join Date
    Feb 2006
    Location
    Texas
    Posts
    96
    OK, After reading your post and the link to your other post I added 'lwinspool' to Project Options -> Parameters -> Linker . Now I get "Could not create Makefile 'Makefile.win' I/O error 32". My compiler log shows this
    Code:
    Building Makefile: "C:\Dev-Cpp\References\Makefile.win"
    Executing  make...
    make.exe -f "C:\Dev-Cpp\References\Makefile.win" all
    make.exe: *** No rule to make target `all'.  Stop.
    
    Execution terminated
    I googled around and have not yet been able to find any reference to error 32. Just for reference I will post my code again.
    Code:
    #include <iostream>
    #include <windows.h>
    #include <winspool.h>
    
    using namespace std;
    
    int winmain()
    {
        char test[] = "This is a test line to be printed.";
        
        LPHANDLE hPrinter;
        LPBYTE DocInfo;   
        LPVOID Buff = test;
        DWORD read;
        LPDWORD written;
    
        OpenPrinter("HP DeskJet 712C", hPrinter, NULL);
        StartDocPrinter(hPrinter, 1, (LPBYTE)&DocInfo);
        StartPagePrinter(hPrinter);
    
        WritePrinter(hPrinter, Buff, read, written); 
    
        EndPagePrinter(hPrinter);
        EndDocPrinter(hPrinter);
        ClosePrinter(hPrinter);
    
        cout<<"Test line sent to printer"<<endl
            <<"Hit <enter> to end";
        cin.get();
        return 0;
    }
    Any ideas?
    Using DEV-C++ Under Windows XP
    +------------------------------+

    "No! Do, or Do Not. There is no Try..."

  5. #5
    erstwhile
    Join Date
    Jan 2002
    Posts
    2,227
    >>I added 'lwinspool<<

    There should be a minus (-) sign in front of that, ie:

    -lwinspool
    CProgramming FAQ
    Caution: this person may be a carrier of the misinformation virus.

  6. #6
    Master of Puppets rwmarsh's Avatar
    Join Date
    Feb 2006
    Location
    Texas
    Posts
    96
    I am sorry if I am being a pain, but this is really ticking me off. It seems like every time I get one problem solved another one comes up. I finally got the program to compile and link with no errors using '-lwinspool'. But now when the executable file runs it immediatly crashes. Windows puts up a message 'WinPrintProject.exe has encountered a problem and needs to close.' I have never encountered this problem with any of my other programs and am not sure how to resolve this, much less what the problem actually is.
    Can anyone point me in the right direction?
    Using DEV-C++ Under Windows XP
    +------------------------------+

    "No! Do, or Do Not. There is no Try..."

  7. #7
    erstwhile
    Join Date
    Jan 2002
    Posts
    2,227
    Actually, I'm surprised it compiled at all - there is no 'int winmain()'; if you're going to use WinMain as the entry point function then:
    Code:
    int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
    is the proper way. But you're program doesn't seem to need it so you're probably better to stick with 'main', particularly since you don't appear to using any 'windowing functions'. If 'main' is your entry point function, make sure you're not building a windows gui application (eg you didn't create a 'windows application' project, or haven't checked the 'win32gui' option in the project options dialog box), or don't have the -mwindows switch in your linker options, otherwise you will get errors.

    As far as working through problematic code, you should check the return values of each api function you call to ensure that it has succeeded, or any parameters you pass to such functions that are then filled or changed by calling them. For example, if OpenPrinter succeeds, its return value is non-zero. If it's not then use GetLastError to get more information about why it may have failed.

    Repeat with each function and, since you're already using std::cout(or std::cerr) you can output hopefully meaningful information. Additionally, you may prefer to use gdb (the debugger) within dev-cpp.
    CProgramming FAQ
    Caution: this person may be a carrier of the misinformation virus.

  8. #8
    Master of Puppets rwmarsh's Avatar
    Join Date
    Feb 2006
    Location
    Texas
    Posts
    96
    OK, After researching those topics for a while I have come to this conclusion..... Now I am just confused
    MSDN said that OpenPrinter(), StartDocPrinter() and the others will return a non-zero value if successful. When I call GetLastError() after each function call I got '87' for OpenPrinter and '6' for all of the others. According to MSDN that means they all succedded, but yet still nothing is being printed on the printer. After loking at GetLastError more indepth on MSDN I found a list of error codes : '87' = invalid parameter & '6' = invalid handle. But if non-zero means success then these codes cannot be what is wrong??
    Here is what I have so far. I have flagged a line that I added that turned the OpenPrinter call from '87' to 'zero'
    Code:
    #include <iostream>
    #include <windows.h>
    #include <winspool.h>
    
    using namespace std;
    
    int main()
    {
        char test[] = "This is a test line to be printed.";
        cout<<test<<endl;
        
        LPTSTR pPrinterName = "HP DeskJet 712C";
        LPTSTR pPortName = "LPT1:";  // <---Adding this line turned 
                                     //     GetLastError() for OpenPrinter(...)   
                                     //     from '87' to 'zero'     
    
        LPHANDLE phPrinter;              
        LPBYTE DocInfo = NULL;       
        LPVOID Buff = test;
        DWORD read;
        LPDWORD written;
        HANDLE hPrinter = *phPrinter;
         
        OpenPrinter(pPrinterName, phPrinter, NULL); 
            cout<<GetLastError()<<endl;
        StartDocPrinter(hPrinter, 1, (LPBYTE)DocInfo);  
            cout<<GetLastError()<<endl;
        StartPagePrinter(hPrinter);
            cout<<GetLastError()<<endl;
    
        WritePrinter(hPrinter, Buff, read, written);    
            cout<<GetLastError()<<endl;
    
        EndPagePrinter(hPrinter);                       
            cout<<GetLastError()<<endl;
        EndDocPrinter(hPrinter);                        
            cout<<GetLastError()<<endl;
        ClosePrinter(hPrinter);                         
            cout<<GetLastError()<<endl;
    
        cout<<"Test line sent to printer"<<endl
            <<"Hit <enter> to end";
    
    
        cin.get();
        return 0;
    }
    Using DEV-C++ Under Windows XP
    +------------------------------+

    "No! Do, or Do Not. There is no Try..."

  9. #9
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    The documentation is referring to the return value of OpenPrinter. The idea is that your error checking should look something like this:
    Code:
    if (!OpenPrinter( ... ))
    {
        // Call failed, use GetLastError to find out why...
        cout << GetLastError() << endl;
    }
    Other than that, I think the following links will help you:
    GetLastError rules
    There's more to calling a function than just getting the types to match
    Basic ground rules for programming - function parameters and how they are used

  10. #10
    Master of Puppets rwmarsh's Avatar
    Join Date
    Feb 2006
    Location
    Texas
    Posts
    96
    OK< Now I understand how GetLastError works. But why am I getting an Invalid Handle Error? Am I not initalizing HANDLE hPrinter correctly?
    MSDN says that OpenPrinter returns a pointer to the handle but the other functions require the handle, not a pointer. So I Though initializing hPrinter by dereferenceing phPrinter should work, but it did not.
    Last edited by rwmarsh; 03-26-2006 at 05:50 AM.
    Using DEV-C++ Under Windows XP
    +------------------------------+

    "No! Do, or Do Not. There is no Try..."

  11. #11
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    When a function takes a pointer, you need to pass it the address of a variable of that type (or NULL if the documentation says that it is an acceptable value).
    For example, when a function takes a LPDWORD, it expects the address of a DWORD, for a LPHANDLE, it expects the address of a HANDLE variable. Like this:
    Code:
        HANDLE hPrinter;
         
        OpenPrinter(pPrinterName, &hPrinter, NULL);

  12. #12
    Master of Puppets rwmarsh's Avatar
    Join Date
    Feb 2006
    Location
    Texas
    Posts
    96
    OK, Instead of dereferencing it, I need to pass the address. I understand that now.
    And forgive me if I am being a pain, I really am trying to figure this out on my own.
    BUT
    I am still getting an Invalid Parameter error on the StartDocPrinter. Everything else seems to be OK. Here is what I have now.
    Code:
    int main()
    {
        char test[] "This is a test line to be printed.";
        char printername[] = "HP DeskJet 712C";
            
        LPTSTR pPrinterName = printername; 
        LPBYTE pDocInfo;    
        LPVOID Buff = test;
        DWORD Read;
        DWORD Level = 1;
        LPDWORD Written;
        HANDLE hPrinter;
    
        OpenPrinter(pPrinterName, &hPrinter, NULL);  
        StartDocPrinter(hPrinter, Level, pDocInfo); 
        StartPagePrinter(hPrinter);           
    
        WritePrinter(hPrinter, Buff, Read, Written);
    
        EndPagePrinter(hPrinter);                   
        EndDocPrinter(hPrinter);                   
        ClosePrinter(hPrinter);                  
    
        cout<<endl
            <<"Test line sent to printer"<<endl
            <<"Hit <enter> to end";
        cin.get();
    
        return 0;
    }
    The documentation says that StartDocPrinter->pDocInfo is a pointer to a Doc Info 1 structure. I thought maybe I needed to define the members of that structure but that did not work either.
    Using DEV-C++ Under Windows XP
    +------------------------------+

    "No! Do, or Do Not. There is no Try..."

  13. #13
    Registered /usr
    Join Date
    Aug 2001
    Location
    Newport, South Wales, UK
    Posts
    1,273
    I had a look back at the one time that I actually wrote printer code. I gave pDocInfo a pointer to a DOCINFO structure with its cbSize member initialised to the size of the struct and optionally lpszDocName for the page title. Like:-
    Code:
    DOCINFO di;
    
    di.cbSize = sizeof(di);
    di.lpszDocName = "Test Page";    // not required
    StartDocPrinter(hPrinter, Level, &di);
    That said, I didn't do it like you did. I used to Print common dialog to do the hard work.

    Hope that helps.

  14. #14
    Master of Puppets rwmarsh's Avatar
    Join Date
    Feb 2006
    Location
    Texas
    Posts
    96
    Well, I got the program to compile with no errors. And all my function calls indicate success. But there is no output from the printer. I though that I would try the FlushPrinter function to empty the buffer but I got a 'FlushPrinter Undeclaired' error, So I guess my winspool library does not contain that function? Is there something with the code I am not seeing or is it something with my OS (windows XP) that I need to look at?
    Code:
    int main()
    {
        int p;
        char test[] = "This is a test line to be printed.";
        char printername[] = "HP DeskJet 712C";
        char docname[] = "Print Test";
            
        LPTSTR pPrinterName = printername; 
        LPVOID pBuf = test;
        DWORD cbBuf = sizeof(test);
        DWORD Level = 1;
        DWORD Written;
        HANDLE hPrinter;
        DOC_INFO_1 pDocInfo;
          pDocInfo.pDocName    = docname;
          pDocInfo.pOutputFile = NULL;
          pDocInfo.pDatatype   = NULL;
        
        OpenPrinter(pPrinterName, &hPrinter, NULL); 
        StartDocPrinter(hPrinter, Level, (BYTE*)&pDocInfo);
        StartPagePrinter(hPrinter);                   
          
        WritePrinter(hPrinter, pBuf, cbBuf, &Written); 
        FlushPrinter(hPrinter, pBuf, cbBuf, &Written, cSleep);
            
        EndPagePrinter(hPrinter);                  
        EndDocPrinter(hPrinter);                        
        ClosePrinter(hPrinter);                            
    
        cout<<endl
            <<"Test line sent to printer"<<endl
            <<"Hit <enter> to end";
    
    
        cin.get();
        return 0;
    }
    Using DEV-C++ Under Windows XP
    +------------------------------+

    "No! Do, or Do Not. There is no Try..."

  15. #15
    Master of Puppets rwmarsh's Avatar
    Join Date
    Feb 2006
    Location
    Texas
    Posts
    96
    Just out of curiosity... On my Inkjet printer each character printed has its own width. If I wanted to print, say a report with formated output where each word on a line was lined up to create multiple columns, would I use TabbedTextOut or can I just change settings in the TextMetrics structure? Or is there an easier way?
    Using DEV-C++ Under Windows XP
    +------------------------------+

    "No! Do, or Do Not. There is no Try..."

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. OpenPrinter function call troubles
    By stanlvw in forum Windows Programming
    Replies: 0
    Last Post: 06-05-2008, 04:23 PM