Dymo Etikett in Software wählen



  • Momentan arbeite ich damit:

    	LPTSTR pPrinterName = Printer()->Printers->Strings[Printer()->PrinterIndex].c_str();
    	PRINTER_INFO_9  * prninfo;
    
    	HANDLE hPrinter = NULL;
    	DWORD dwNeeded = 0;
    	DEVMODE *pDevMode = NULL;
    	PRINTER_DEFAULTS pd;
    	BOOL bFlag;
    	LONG lFlag;
    	DWORD bytes = 0;
    
    	ZeroMemory(&pd, sizeof(pd));
    	pd.DesiredAccess = PRINTER_ALL_ACCESS;
    	bFlag = OpenPrinter(pPrinterName, &hPrinter, &pd);
    	if (!bFlag || (hPrinter == NULL))
    		return;
    
    	bool f= GetPrinter(hPrinter, 8 ,  NULL, 0  , &bytes);
    	unsigned char biff[5000];
    
    	f= GetPrinter(hPrinter, 9 ,  biff, 5000  , &bytes);
    	if (f)
    	{
    			prninfo = (PRINTER_INFO_9  *)biff;
    
    			ListBox1->Items->Add("size " +IntToStr(prninfo->pDevMode->dmSize));
    			ListBox1->Items->Add("dmPaperSize " +IntToStr(prninfo->pDevMode->dmPaperSize));
    			ListBox1->Items->Add("dmPaperWidth " +IntToStr(prninfo->pDevMode->dmPaperWidth));
    
    	}
    
    	   ClosePrinter(hPrinter);
    

    Auf PRINTER_INFO_9 habe ich umgestellt, denn dies scheint die user Einstellung zu sein, aber auch ohne Erfolg

    Ich bekomme zwar Informationen angezeigt, wenn ich jedoch im Print-Dialog etwas ändere (bleibt auch für eine Programm-Session erhalten), und ich erneut abfrage, sind keine Daten verändert.



  • Lies dir das hier mal durch, vielleicht hilft dir das weiter.
    Was mir noch auffällt ist, dass du String::c_str() direkt an LPTSTR zuweist. Wenn du keine Unicode Anwendung hast (TCHAR = wchar_t), wovon ich bei einer VCL Anwendung mal ausgehe, dürfte das so ohne weiteres nicht klappen. Der Delphi String benutzt 16bit breite characters, LPTSTR nur 8bit breite characters. Oder täusche ich mich da und das klappt?





  • @DocShoe sagte in Dymo Etikett in Software wählen:

    Lies dir das hier mal durch, vielleicht hilft dir das weiter.
    Was mir noch auffällt ist, dass du String::c_str() direkt an LPTSTR zuweist. Wenn du keine Unicode Anwendung hast (TCHAR = wchar_t), wovon ich bei einer VCL Anwendung mal ausgehe, dürfte das so ohne weiteres nicht klappen. Der Delphi String benutzt 16bit breite characters, LPTSTR nur 8bit breite characters. Oder täusche ich mich da und das klappt?

    Danke, werde versuchen dort etwas zu finden.
    Der Aufruf von OpenPrinter funktioniert, auch ist in pPrinterName ein gültiger Inhalt. Scheint also kein Problem zu ein



  • Bin einen Schritt weiter, mit dieser Funktion erkenne ich, dass sich die Struktur ändert sobald man in den Windows-Einstellungen das gewählte Etikett ändert.

    Leider ändert sich die Struktur NICHT, wenn man den Print-Dialog öffnet, was auch dazu führt, dass wenn ich einen Druck mit Printer()->BeginDoc() starte die "falschen" Einstellungen verändert werden.

    Nun die Frage, weiß wemand wie ich die Printer()->BeginDoc() dazu bringen kann die Einstellungen zu übernehmen?

    	LPTSTR pPrinterName = Printer()->Printers->Strings[Printer()->PrinterIndex].c_str();
    	PRINTER_DEFAULTS pd;
    	HANDLE hPrinter = NULL;
    	BOOL bFlag;
    	ZeroMemory(&pd, sizeof(pd));
    	pd.DesiredAccess = PRINTER_ALL_ACCESS;
    	bFlag = OpenPrinter(pPrinterName, &hPrinter, &pd);
    	if (!bFlag || (hPrinter == NULL))
    		return;
    
    
    	PRINTER_INFO_9  * prninfo9;
    	DWORD bytes = 0;
    	bool f= GetPrinter(hPrinter, 8 ,  NULL, 0  , &bytes);
    	DWORD size  = bytes;
    	prninfo9 = (PRINTER_INFO_9 *)GlobalAlloc(GPTR, bytes);
    	char *c  =	(char *)GlobalLock(prninfo9);
    	ZeroMemory(c, size);
    	GlobalUnlock(prninfo9);
    
    	f= GetPrinter(hPrinter, 9 , (LPBYTE  ) prninfo9, size  , &bytes);
    	if (f)
    	{
    			PRINTER_INFO_9  *  firstByte =	(PRINTER_INFO_9  *)GlobalLock(prninfo9);
    			LPDEVMODE  pDevMode = firstByte->pDevMode;
    			ListBox1->Items->Add("9size " +IntToStr(pDevMode->dmSize));
    			ListBox1->Items->Add("9dmPaperSize " +IntToStr(pDevMode->dmPaperSize));
    			ListBox1->Items->Add("9dmPaperWidth " +IntToStr(pDevMode->dmPaperWidth));
    
    			GlobalUnlock(prninfo9);
    
    	}
    
    	GlobalFree(prninfo9);
    


  • Wenn ich das sehe dann kannst Du fast den Link von @DocShoe nicht gelesen haben?



  • @Swordfish sagte in Dymo Etikett in Software wählen:

    Wenn ich das sehe dannst Du fast den Link von @DocShoe nicht gelesen haben?

    Klar, ich hab auch das Beispiel dort implementiert, aber genau das gleiche Ergebnis, die Parameter werden geändert und ausgelesen, aber der Print-Dialog der VCL und die VCL Print Funktionen verwenden wohl einen anderen Satz an Parametern die nicht geändert werden.



  • Noch ein stück weiter:
    von hier: https://support.microsoft.com/de-de/help/140285/how-to-modify-printer-settings-by-using-setprinter konnte ich herausfinden, dass nach der Änderung noch eine Message versendet werden muss.
    SendMessageTimeout(HWND_BROADCAST, WM_DEVMODECHANGE, 0L, (LPARAM)(LPCSTR)pPrinterName, SMTO_NORMAL, 1000, NULL);

    Nun klappt das umstellen der Ausrichtung, aber leider kann ich immer noch nicht das Etikett auswählen. Soweit ich das bisher rausgefunden habe, ändert sich lediglich die Eigenschaft dmFormName wenn ich in der Systemsteuerung das Etikett des Druckers umstelle. diese Eigenschaft ist aber ein L-Wert....



  • Es gibt auch noch die WINAPI Formular-Funktionen, geht da vielleicht was GetForm bzw: SetForm?



  • @DocShoe sagte in Dymo Etikett in Software wählen:

    Es gibt auch noch die WINAPI Formular-Funktionen, geht da vielleicht was GetForm bzw: SetForm?

    Ui das war schon ein guter Tipp, Danke !

    Damit kann ich nun alle Forms (die wohl in allen Druckern vorhanden sind) auslesen:

    	Memo1->Clear();
    	LPTSTR pPrinterName = Printer()->Printers->Strings[Printer()->PrinterIndex].c_str();
    
    	HANDLE hPrinter = NULL;
    	DWORD dwNeeded = 0;
    	DWORD numStructs = 0;
    	//PRINTER_INFO_2 *pi2 = NULL;
    	//DEVMODE *pDevMode = NULL;
    	PRINTER_DEFAULTS pd;
    	BOOL bFlag;
    	//LONG lFlag;
    
    	// Open printer handle (on Windows NT, you need full-access because you
    	// will eventually use SetPrinter)...
    	ZeroMemory(&pd, sizeof(pd));
    	pd.DesiredAccess = PRINTER_ALL_ACCESS;
    	bFlag = OpenPrinter(pPrinterName, &hPrinter, &pd);
    	if (!bFlag || (hPrinter == NULL))
    	return ;//FALSE;
    
    
    	EnumForms(hPrinter,1, NULL, 0, &dwNeeded, &numStructs );
    
    	int sizeOfStruct = sizeof(FORM_INFO_1 ) ;
    	int stucts = dwNeeded/sizeOfStruct;
    	dwNeeded = 0;
    	numStructs = 0;
    	FORM_INFO_1 *data = new  FORM_INFO_1 [stucts];
    	bFlag = EnumForms(hPrinter,1, (LPBYTE  ) data, stucts*sizeOfStruct, &dwNeeded, &numStructs );
    
    	for (int i = 0; i < numStructs; i++)
    	{
    		String s = data[i].pName;
    		Memo1->Lines->Add(s);
    	}
    
    	delete [] data;
    	ClosePrinter(hPrinter);
    

    Es ist mir nun auch gelungen, die Windows Standard Einstellungen des Druckers zu ändern!

    int printerIndex =Printer()->PrinterIndex;
    LPTSTR pPrinterName = Printer()->Printers->Strings[printerIndex].c_str();
    
    HANDLE hPrinter = NULL;
    DWORD dwNeeded = 0;
    PRINTER_INFO_9 *pi2 = NULL;
    DEVMODE *pDevMode = NULL;
    PRINTER_DEFAULTS pd;
    BOOL bFlag;
    LONG lFlag;
    
    // Open printer handle (on Windows NT, you need full-access because you
    // will eventually use SetPrinter)...
    ZeroMemory(&pd, sizeof(pd));
    pd.DesiredAccess = PRINTER_ALL_ACCESS;
    bFlag = OpenPrinter(pPrinterName, &hPrinter, &pd);
    if (!bFlag || (hPrinter == NULL))
    return ;//FALSE;
    
    // The first GetPrinter tells you how big the buffer should be in
    // order to hold all of PRINTER_INFO_2. Note that this should fail with
    // ERROR_INSUFFICIENT_BUFFER.  If GetPrinter fails for any other reason
    // or dwNeeded isn't set for some reason, then there is a problem...
    SetLastError(0);
    bFlag = GetPrinter(hPrinter, 9, 0, 0, &dwNeeded);
    if ((!bFlag) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||          (dwNeeded == 0))
    {
    	ClosePrinter(hPrinter);
    	return ;//FALSE;
    }
    
    // Allocate enough space for PRINTER_INFO_2...
    pi2 = (PRINTER_INFO_9 *)GlobalAlloc(GPTR, dwNeeded);
    if (pi2 == NULL)
    {
    	ClosePrinter(hPrinter);
    	return ;//FALSE;
    }
    
    // The second GetPrinter fills in all the current settings, so all you
    // need to do is modify what you're interested in...
    bFlag = GetPrinter(hPrinter, 9, (LPBYTE)pi2, dwNeeded, &dwNeeded);
    if (!bFlag)
    {
    	GlobalFree(pi2);
    	ClosePrinter(hPrinter);
    	return ;//FALSE;
    }
    
    // If GetPrinter didn't fill in the DEVMODE, try to get it by calling
    // DocumentProperties...
    if (pi2->pDevMode == NULL)
    {
    	dwNeeded = DocumentProperties(NULL, hPrinter, pPrinterName, NULL, NULL, 0);
    	if (dwNeeded <= 0)
    	{
    		GlobalFree(pi2);
    		ClosePrinter(hPrinter);
    		return ;//FALSE;
    	}
    
    	pDevMode = (DEVMODE *)GlobalAlloc(GPTR, dwNeeded);
    	if (pDevMode == NULL)
    	{
    		GlobalFree(pi2);
    		ClosePrinter(hPrinter);
    		return ;//FALSE;
    	}
    
    	lFlag = DocumentProperties(NULL, hPrinter, pPrinterName, pDevMode, NULL, DM_OUT_BUFFER);
    	if (lFlag != IDOK || pDevMode == NULL)
    	{
    		GlobalFree(pDevMode);
    		GlobalFree(pi2);
    		ClosePrinter(hPrinter);
    		return ;//FALSE;
    	}
    
    	pi2->pDevMode = pDevMode;
    }
    
    int fields = pi2->pDevMode->dmFields;
    pi2->pDevMode->dmFields = 0;
    
    // Driver is reporting that it doesn't support this change...
    if (!(fields & DM_FORMNAME))
    {
    	GlobalFree(pi2);
    	ClosePrinter(hPrinter);
    	if (pDevMode)
    	GlobalFree(pDevMode);
    	return ;//FALSE;
    }
    else
    {
    	pi2->pDevMode->dmFields |= DM_FORMNAME  ;
    	strcpy(pi2->pDevMode->dmFormName, Edit3->Text.c_str());
    }
    
    
    
    
    // Update printer information...
    bFlag = SetPrinter(hPrinter, 9, (LPBYTE)pi2, 0);
    if (!bFlag)
    // The driver doesn't support, or it is unable to make the change...
    {
    	GlobalFree(pi2);
    	ClosePrinter(hPrinter);
    	if (pDevMode)
    	GlobalFree(pDevMode);
    	return ;//FALSE;
    }
    
    // Tell other apps that there was a change...
    SendMessageTimeout(HWND_BROADCAST, WM_DEVMODECHANGE, 0L, (LPARAM)(LPCSTR)pPrinterName, SMTO_NORMAL, 1000, NULL);
    
    Application->ProcessMessages();
    // Clean up...
    if (pi2)
    GlobalFree(pi2);
    if (hPrinter)
    ClosePrinter(hPrinter);
    if (pDevMode)
    GlobalFree(pDevMode);
    

    Nur haben diese Änderung eben alle anderen Anwendung "mitbekommen" nur die eigene nicht.
    Ein Neustart der Anwendung zeigt dann das umgestellte Etikett.

    Das SendMessageTimeout(HWND_BROADCAST, …. informiert wohl nicht die eigne Anwendung.

    Weiß jemand noch wie man die "eigene" Anwendung überreden kann die neuen Druckereinstellungen zu übernehmen?



  • Nochmal zusammengefasst und die Frage konkretisiert:
    ein Aufruf von PrintDialog1->Execute(); zeigt mir eine bestimmte Druckereinstellung. Ändere ich nun durch meinen Code oder durch die Windows-Systemeinstellung das Papierformat, ändert sich die Anzeige von PrintDialog1->Execute(); nicht.
    Auch ein Printer()->Refresh(); bringt keine Verbesserung. Nur ein Neustart der Anwendung.

    Wie kann ich die VCL Anwendung dazu bringen, die geänderten Druckereinstellungen zu übernehmen?



  • Hast Du SetPrinter() schon versucht?



  • @AntonWert
    Möglicherweise kriegt das VCL Framework nichts von den Sachen mit, die direkt mit der WINAPI verändert wurden. Probier mal Printer()->Refresh() und guck, ob das hilft.



  • @DocShoe sagte in Dymo Etikett in Software wählen:

    Probier mal Printer()->Refresh() und guck, ob das hilft.

    @AntonWert sagte in Dymo Etikett in Software wählen:

    Auch ein Printer()->Refresh(); bringt keine Verbesserung.


Anmelden zum Antworten