Serieller Drucker und api



  • hallo,
    ich habe einen (mini)Drucker den ich über rs232 anspreche.
    Ich möchte folgendes drucken:
    CString zumdrucken = "123456";

    Aber ohne dass ich den Drucker auswähle.
    Also Buttion1 klick und es wird sofort gedruckt.

    Idee?
    Nach was soll ich googlen?
    Kennt jemand ein tut?
    Wo soll ich ansetzen?



  • Wenn der Drucker einen Windows Druckertreiber installiert hat, dann mach ihn über die Drucker-Funktionen auf, mach ein "Dokument" im "raw" Modus, und schreib da "123456" rein. Die genauen Funktionen weiss ich nimmer auswendig, aber sehr schwer war das nicht zu finden als ich es vor ein paar Monaten brauchte. Um den Drucker aufzumachen brauchst du nur seinen Namen, den kannst du ja z.B. über ein .ini File einstellbar machen. Windows kümmert sich dann darum deine Daten auf der entsprechenden Schnittstelle rauszuschicken. Vorteil: es ist egal wie der Drucker angeschlossen ist, so lande der Windows Druckertreiber damit klarkommt. Also auch USB, Parallel, TCP/IP etc. kein Problem.

    Wenn der Drucker keinen Windows Druckertreiber installiert hat, dann mach einfach die serielle Schnittstelle auf (CreateFile auf "\.\COM1" ... "\.\COM999"), stell die nötigen Parameter ein (SetupComm, SetCommState etc.) und schick die Daten raus (WriteFile).



  • thx

    1.Weg:
    Drucken über Create(com1... war meine erste Idee, aber ich will nicht das Rad neu erfinden, dann muss ich gucken ob gerade was gedruckt wird?

    2.Weg:
    Der Weg über APi gefällt mir schon besser. 🙂
    Kann ich ein Stück Code von dir haben? Dann habe einen Anfang.
    Ist der Ansatz richtig mit CPrintSetup?



  • tomycat2009 schrieb:

    Kann ich ein Stück Code von dir haben? Dann habe einen Anfang.

    Einen Link auf ein Beispiel mit den entsprechenden WinApi-Funktionen habe ich eben in der Nachbarrubrik gepostet:

    http://www.c-plusplus.net/forum/p1986327#1986327



  • Das Beispiel von nn sollte reichen, hier nochmal der direkte Link:

    http://support.microsoft.com/kb/138594/en-us



  • erstmal thx,
    ok,ich habe einen Serialen Drucker unter win xp eingerichtet.Testdrucker ist ok.:-)

    meine Grundlage:
    http://support.microsoft.com/kb/138594/en-us

    Neue Projekt erstellt, sowie neue Funktion.
    #include <winspool.h> //neue Header.
    meine Funktion:

    int Cmein_druckerDlg::druckenx(void)
    {
    
    CString szPrinterName = _T("EPSON TM-U210D");
    LPBYTE lpData; 
    DWORD dwCount;
    
         HANDLE     hPrinter;
         DOC_INFO_1 DocInfo;
         DWORD      dwJob;
         DWORD      dwBytesWritten;
    
         // Need a handle to the printer.
         if( ! OpenPrinter( _T("EPSON TM-U210D"), &hPrinter, NULL ) )
           return FALSE;
    
         // Fill in the structure with info about this "document."
    	 DocInfo.pDocName = "1.txt";
         DocInfo.pOutputFile = NULL;
         DocInfo.pDatatype = "RAW";
         // Inform the spooler the document is beginning.
         if( (dwJob = StartDocPrinter( hPrinter, 1, (LPSTR)&DocInfo )) == 0 )
         {
           ClosePrinter( hPrinter );
           return FALSE;
         }
         // Start a page.
         if( ! StartPagePrinter( hPrinter ) )
         {
           EndDocPrinter( hPrinter );
           ClosePrinter( hPrinter );
           return FALSE;
         }
         // Send the data to the printer.
         if( ! WritePrinter( hPrinter, lpData, dwCount, &dwBytesWritten ) )
         {
           EndPagePrinter( hPrinter );
           EndDocPrinter( hPrinter );
           ClosePrinter( hPrinter );
           return FALSE;
         }
         // End the page.
         if( ! EndPagePrinter( hPrinter ) )
         {
           EndDocPrinter( hPrinter );
           ClosePrinter( hPrinter );
           return FALSE;
         }
         // Inform the spooler that the document is ending.
         if( ! EndDocPrinter( hPrinter ) )
         {
           ClosePrinter( hPrinter );
           return FALSE;
         }
         // Tidy up the printer handle.
         ClosePrinter( hPrinter );
         // Check to see if correct number of bytes were written.
         if( dwBytesWritten != dwCount )
           return FALSE;
         return TRUE;
    
    	return 0;
    }
    

    DocInfo.pDocName = "C:\\1.txt"; <--- Fehler ?!
    error C2440: '=' : cannot convert from 'const char [6]' to 'LPWSTR'

    DocInfo.pDatatype = "RAW"; <--- Fehler ?!
    error C2440: '=' : cannot convert from 'const char [4]' to 'LPWSTR'


  • Mod

    DocInfo.pDocName = "1.txt"; 
         DocInfo.pOutputFile = NULL; 
         DocInfo.pDatatype = "RAW";
    

    Setze Dich mit Unicode und MBCS auseinander.
    Wenn Du schon oben die _T Makros verwendest, dann mach es hier auch, oder compiliere Dein Programm in dem Zeichensatz, denn Du verstehst. :xmas1:
    80% der Anfragen in diesem Forum haben immer wieder nur das Thema "MBCS/Unicode" zum Inhalt...

    DocInfo.pDocName = _T("1.txt"); 
         DocInfo.pOutputFile = NULL; 
         DocInfo.pDatatype = _T("RAW");
    


  • thx,
    letzte Frage:

    if( (dwJob = StartDocPrinter( hPrinter, 1, (LPSTR)&DocInfo )) == 0 )

    error C2664: 'StartDocPrinterW' : cannot convert parameter 3 from 'LPSTR' to 'LPBYTE'



  • ähh, hab die Lösung:
    if( (dwJob = StartDocPrinter( hPrinter, 1, (LPBYTE)&DocInfo )) == 0 )

    Der Compiler gibt mir grünes Licht 🙂

    Wenn ich auf meinem Knopf(Test Druck) drücke kommt:

    Run-Time Check Failure #3 - The variable 'dwCount' is being used without being initialized.

    if( (dwJob = StartDocPrinter( hPrinter, 1, (LPBYTE)&DocInfo )) == 0 ) //<- stop

    ok, nochmal alles abgecheckt:
    meine veränderung:

    LPBYTE lpData = NULL;
    DWORD dwCount = 1;

    First-chance exception at 0x72f77954 in mein_drucker.exe: 0xC0000005: Access violation reading location 0x00000000.
    Unhandled exception at 0x72f77954 in mein_drucker.exe: 0xC0000005: Access violation reading location 0x00000000.

    dann öffnet sich eine winocc.cpp in Zeile:

    BOOL CWnd::IsDialogMessage(LPMSG lpMsg)
    {
    	ASSERT(::IsWindow(m_hWnd));
    
    	if (m_nFlags & WF_OLECTLCONTAINER)
    		return afxOccManager->IsDialogMessage(this, lpMsg);
    	else
    		return ::IsDialogMessage(m_hWnd, lpMsg);
    }  <--- Hier steht der Pfeil.
    


  • Warum denn der ganze Aufwand, wenn Du gar nichts (lpData = NULL)drucken willst 😉

    'lpData' sollte auf die Daten zeigen die Du drucken willst
    'dwCount' sollte die Anzahl Bytes enthalten welche gedruckt werden sollen

    Herzliche Grüsse
    Walter



  • @weicher

    Ich will nur hallo Welt drucken mehr nicht. 🙂

    pldata = "hallo welt"?
    dwCount <- Anzahl der Zeichen?
    hab ich was vergessen?



  • Hallo,

    ich bin mir nicht ganz sicher. Bei der Doku zu WritePrinter steht nichts über Unicode, aber mit grösster Wahrscheinlichkeit nimmt auch diese Funktion einen Unicode string.

    Darum würde ich es zuerst mal so versuchen:

    TCHAR str[] = _T("Hallo Welt!");
    lpData = (LPVOID)str;
    dwCount = _tcslen (str) * sizeof(TCHAR);
    

    Herzliche Grüsse
    Walter



  • DWORD dwCount; 
    LPBYTE lpData; 
    TCHAR str[] = _T("Hallo Welt!");
    lpData = (LPVOID)str; //zeile 164
    dwCount = _tcslen (str) * sizeof(TCHAR);
    

    nächstes Prob.

    mein_druckerdlg.cpp(164) : error C2440: '=' : cannot convert from 'LPVOID' to 'LPBYTE'
    

  • Mod

    Steht doch da. LPVOID ist eben kein LPBYTE.
    Wenn Du schon casten musst warum incht gleich in den entsprechen Typ?



  • LPWSTR szPrinterName = _T("pdf24");               //von mir erstellt
    TCHAR str[] = _T("Hallo Welt!");                  //von mir erstellt
    lpData = (LPBYTE)str;                             //von mir erstellt
    DWORD dwCount = _tcslen (str) * sizeof(TCHAR);       //von mir erstellt
    
         HANDLE     hPrinter;
         DOC_INFO_1 DocInfo;
         DWORD      dwJob;
         DWORD      dwBytesWritten;
    
         // Need a handle to the printer.
         if( ! OpenPrinter( szPrinterName, &hPrinter, NULL ) )
           return FALSE;
    
         // Fill in the structure with info about this "document."
         DocInfo.pDocName = _T("My Document"); //von mir erstellt _T() hinzugefügt
         DocInfo.pOutputFile = NULL;
         DocInfo.pDatatype = _T("RAW");        //von mir erstellt _T() hinzugefügt
         // Inform the spooler the document is beginning.
         if( (dwJob = StartDocPrinter( hPrinter, 1, (LPBYTE)&DocInfo )) == 0 ) //von LPSTR in LPBYTE umg.
         {
           ClosePrinter( hPrinter );
           return FALSE;
         }
         // Start a page.
         if( ! StartPagePrinter( hPrinter ) )
         {
           EndDocPrinter( hPrinter );
           ClosePrinter( hPrinter );
           return FALSE;
         }
         // Send the data to the printer.
         if( ! WritePrinter( hPrinter, lpData, dwCount, &dwBytesWritten ) )
         {
           EndPagePrinter( hPrinter );
           EndDocPrinter( hPrinter );
           ClosePrinter( hPrinter );
           return FALSE;
         }
         // End the page.
         if( ! EndPagePrinter( hPrinter ) )
         {
           EndDocPrinter( hPrinter );
           ClosePrinter( hPrinter );
           return FALSE;
         }
         // Inform the spooler that the document is ending.
         if( ! EndDocPrinter( hPrinter ) )
         {
           ClosePrinter( hPrinter );
           return FALSE;
         }
         // Tidy up the printer handle.
         ClosePrinter( hPrinter );
         // Check to see if correct number of bytes were written.
         if( dwBytesWritten != dwCount )
           return FALSE;
         return TRUE;
    

    Der Serial Drcuker macht kein Mux.
    Wenn ich pdf24 eintragen, dann öffnet sich pdf24 mit einem leeren Blatt.
    Der Compiler zeigt auch keine Warnung an, und jetzt? 🙂



  • hat keiner eine Idee? oder Ansatz?



  • tomycat2009 schrieb:

    hat keiner eine Idee? oder Ansatz?

    Ja, lerne Grundlagen.

    tomycat2009 schrieb:

    TCHAR str[] = _T("Hallo Welt!");                  //von mir erstellt
    

    Das ist mit ziemlicher Sicherheit falsch. Solche Drucker arbeiten meist mit ANSI-Daten, nicht mit Unicode.

    tomycat2009 schrieb:

    Der Serial Drcuker macht kein Mux.
    Wenn ich pdf24 eintragen, dann öffnet sich pdf24 mit einem leeren Blatt.

    Dann heißt dein Drucker wohl nicht "pdf24". In szPrinterName muss der Name des Druckers stehen, so wie Windows ihn unter "Drucker und Faxgeräte" anzeigt.

    tomycat2009 schrieb:

    Der Compiler zeigt auch keine Warnung an, und jetzt? 🙂

    Nochmal: Grundlagen lernen.

    Geh mit dem Debugger Schritt für Schritt durch den Code durch und schau, ob er da bei einem if rausspringt, dann siehst du, wo das Problem liegt.

    Läuft der Code durch, dann sendest du halt einfach die falschen Daten.



  • Hier mal ein Beispiel mit einem Hello World auf einem Etikettendrucker:

    using namespace std;
    
    BOOL RawDataToPrinter(LPSTR szPrinterName, LPBYTE lpData, DWORD dwCount)
    {
      // Unverändert aus dem MSDN übernommen
    }
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
      string s;
    
      s += "m m\r\n";
      s += "J\r\n";
      s += "H 100\r\n";
      s += "O R\r\n";
      s += "S l1;0,0,29,31,55\r\n";
      s += "T 10,10,0,3,8;Hallo !\r\n";
      s += "A 1\r\n";
    
      RawDataToPrinter("CAB A4+/300", (LPBYTE)s.c_str(), s.length());
    
      return 0;
    }
    

    Im Rest deines Programm kannst du mit Unicode und _T arbeiten, aber die Daten, die zum Drucker gehen sind kein Unicode, da muss du eben umwandeln.



  • ok,
    ich habe deinen Code 1 zu 1 übernommen.

    error C2664: 'OpenPrinterW' : cannot convert parameter 1 from 'LPSTR' to 'LPWSTR'

    schritt 2:

    original:
    BOOL RawDataToPrinter(LPSTR szPrinterName, LPBYTE lpData, DWORD dwCount)
    in
    BOOL RawDataToPrinter(LPWSTR szPrinterName, LPBYTE lpData, DWORD dwCount)

    neu Compiliert, dann kommt das nächste Problem:
    error C2440: '=' : cannot convert from 'const char [12]' to 'LPWSTR'

    Original:

    DocInfo.pDocName = "My Document";
    DocInfo.pOutputFile = NULL;
    DocInfo.pDatatype = "RAW";

    zu:

    DocInfo.pDocName = _T("My Document");
    DocInfo.pOutputFile = NULL;
    DocInfo.pDatatype = _T("RAW");

    neu Compiliert, dann kommt das nächste Problem:
    error C2664: 'StartDocPrinterW' : cannot convert parameter 3 from 'LPSTR' to 'LPBYTE'

    von
    if( (dwJob = StartDocPrinter( hPrinter, 1, (LPSTR)&DocInfo )) == 0 )
    zu
    if( (dwJob = StartDocPrinter( hPrinter, 1, (LPBYTE)&DocInfo )) == 0 )

    neu Compiliert, dann kommt das nächste Problem:
    error C2065: 'string' : undeclared identifier

    Warum soll ich mit string arbeiten?
    Warum nicht mit CString?
    Ich arbeite in Visual Studio 2008 und habe ein MFC Projekt.



  • tomycat2009 schrieb:

    ok,
    ich habe deinen Code 1 zu 1 übernommen.

    Ok, ich hätte noch ausführlicher werden sollen.

    Das Beispiel stammt noch von Visual Studio 2003, da ist standardmäßig kein Unicode eingestellt. Ich habe es genommen, weil ich kurzfristig nichts anderes gefunden habe. Und ich habe nicht gemeint, du sollst die Funktion ungeändert übernehmen.

    Die jetzt vom Compiler angemeckerten Teile solltest du schon von LPSTR auf LPTSTR ändern, aber nicht die Daten, die zum Drucker gehen.

    Du hast es in deinem Programm mit zwei unterschiedlichen Stringformaten zu tun. Der Druckername und der Dokumentenname sind Teil der Interaktion deines Programmes mit Windows.

    Die Daten, die zum Drucker gesendet werden, sind davon unabhängig. Deren Format hat der Druckerhersteller festgelegt und dem ist es egal, ob du in deinen Windowsprogramm Unicode verwendest oder nicht.

    Weiterhin sollte das Beispiel zeigen, dass es meist nicht reicht nur "Hallo" zum Drucker zu senden, sondern, je nach Hersteller, weiter Befehle erforderlich sind. Mehr dazu findest du, hoffentlich, in der Anleitung zu deinem Drucker.

    tomycat2009 schrieb:

    ok,
    neu Compiliert, dann kommt das nächste Problem:
    error C2065: 'string' : undeclared identifier

    Da haben wir es wieder. Grundlagen lernen.

    Das ist der std::string von C++. Ein #include <string> in der stdafx.h könnte Wunder wirken ...

    tomycat2009 schrieb:

    Warum nicht mit CString?

    Du must auf jeden Fall zwischen Stringdaten innerhalb deines Programm und denen im Druckerformat unterscheiden. Da bieten sich CStringA (nicht CString) oder std::string für die Druckerdaten an. Letzter kommt auf jeden Fall auch mit Binärdaten zurecht.


Anmelden zum Antworten