How to print GeckoWebBrowser to default printer? - printing

I'm trying to print the document in a GeckoWebBrowser, but documentation is limited and to me, it's not at all clear.
I found some code on the internet that at least communicates with the printer (it starts beeping) but I think the printer is asking for a Letter size paper, but it requires the settings to be from print.GetGlobalPrintSettingsAttribute(), if I try my own settings, it gives me a NotImplementedException.
I suspect this is exception is raised on my Gecko.PrinterSettings, because when I swap ps in the print.Print(ps, null);
with the global settings, this exception isn't raised.
The code below:
var domWindow = browser.Window.DomWindow;
var print = Gecko.Xpcom.QueryInterface<Gecko.nsIWebBrowserPrint>(domWindow);
Gecko.PrintSettings ps = new Gecko.PrintSettings();
ps.SetPrintSilentAttribute(false);
ps.SetPrintToFileAttribute(false);
ps.SetShowPrintProgressAttribute(false);
ps.SetOutputFormatAttribute(1); //2 == PDF, so I assume 1 is actual printer
ps.SetPrintBGImagesAttribute(true);
ps.SetStartPageRangeAttribute(1);
ps.SetEndPageRangeAttribute(100);
ps.SetPrintOptions(2, true); // evenPages
ps.SetPrintOptions(1, true); // oddpages
ps.SetEffectivePageSize(768 * 20f, 1024 * 20f);
ps.SetShrinkToFitAttribute(true);
ps.SetScalingAttribute(1.0);
ps.SetPrintBGImagesAttribute(true);
print.Print(ps, null);

Managed to come up with a solution.
What was throwing an exception was
public void SetPersistMarginBoxSettingsAttribute(bool aPersistMarginBoxSettings)
{
throw new NotImplementedException();
}
The above is in PrinterSettings.cs, so it is hard-coded coded to throw a NotImplementedException on a number off attributes (the attribute above isn't the only one hard-coded to throw the exception) as it is not finished(?), so I cannot use it.
However, I can use the GetGlobalSettingsAttribute() as it uses the same interface as PrinterSettings (nsiPrintSettings), so therefore it will have the same attributes all populated for me.
So what can I do is:
I simply copy the GetGlobalPrintSettingsAttribute() into my own printer settings, and adjust them as necessary.
var mySettings = print.GetGlobalPrintSettingsAttribute();
mySettings.SetPrintSilentAttribute(true);
mySettings.SetPrintToFileAttribute(true);
mySettings.SetShowPrintProgressAttribute(false);
mySettings.SetOutputFormatAttribute(2); //2 == PDF
mySettings.SetToFileNameAttribute(#"c:\temp\temp.pdf");
mySettings.SetPrintBGImagesAttribute(true);
mySettings.SetStartPageRangeAttribute(1);
mySettings.SetEndPageRangeAttribute(100);
mySettings.SetPrintOptions(2, true); // evenPages
mySettings.SetPrintOptions(1, true); // oddpages
mySettings.SetShrinkToFitAttribute(true);
mySettings.SetScalingAttribute(1.0);
mySettings.SetPrintBGImagesAttribute(true);
print.Print(mySettings, new Gecko.WebProgressListener());
Please notice I reverted back to PDF for now, in the SetOutputFormatAttribute(2); //2 == PDF
Also changed the print.Print(ps, null); to print.Print(mySettings, new Gecko.WebProgressListener()); but I think having null or Gecko.WebProgressListener() won't make a difference.
Et voilĂ ! - Now, onto the next step, which is to print to a printer, and not as a PDF file.

Related

Java 8 issues printing PS to network printer

Got a weird question for you. Recently upleveled my old project from java 7(jdk1.7.0_10) to java 8(1.8.0.91.x86_64). In java 7 it printed the post script file with no issues and now it is printing the postscript file as plain text instead of converting the file. This is on a redhat linux environment. Simply I am trying to print a string containing a post script file of a file itself.
Here is my original code
DocFlavor flavor = DocFlavor.INPUT_STREAM.POSTSCRIPT;
PrintService pService = PrintServiceLookup.lookupDefaultPrintService();
// In a field environment, send to the printer
if (System.getenv("USER_DEFINED_RELTOP") == null || pfr.exists()) {
if (pService.getName().isEmpty()) {
LOGGER.error("No printer selected");
} else {
LOGGER.info("Printing to " + pService.getName());
DocPrintJob pj = pService.createPrintJob();
try {
InputStream is = new ByteArrayInputStream(data.getBytes("UTF8"));
Doc doc = new SimpleDoc(is, flavor, null);
PrintJobWatcher pjw = new PrintJobWatcher(pj);
pj.print(doc, null);
pjw.waitForDone();
is.close();
} catch (PrintException | IOException e) {
LOGGER.error(e);
} // try block
} // no printer selected
// Otherwise, send to a file
} else {
That worked fine in java 7, I updated it to the oracle spec found here for java 8.
https://docs.oracle.com/javase/8/docs/api/javax/print/PrintService.html#createPrintJob--
https://docs.oracle.com/javase/8/docs/technotes/guides/jps/spec/printing.fm6.html
DocFlavor psFlavor = DocFlavor.INPUT_STREAM.POSTSCRIPT;
PrintRequestAttributeSet attrs = new HashPrintRequestAttributeSet();
attrs.add(MediaSizeName.ISO_A4);
PrintService[] pservices = PrintServiceLookup.lookupPrintServices(psFlavor,
attrs);
File pfr = new File(PFR_INDICATOR);
// In a field environment, send to the printer
if (System.getenv("USER_DEFINED_RELTOP") == null || pfr.exists()) {
//Check we have a printer capable of post script
if (pservices.length > 0) {
LOGGER.info("Printing to " + pservices[0].getName());
DocPrintJob pj = pservices[0].createPrintJob();
try {
InputStream fis = new ByteArrayInputStream(data.getBytes("UTF8"));
//byte[] ba =data.getBytes("UTF8");
Doc doc = new SimpleDoc(fis, psFlavor, null);
LOGGER.info("Doc Flavor " + doc.getDocFlavor());
PrintJobWatcher pjw = new PrintJobWatcher(pj);
LOGGER.info("PrintJob Attributes : " + pj.getAttributes());
pj.print(doc, attrs);
pjw.waitForDone();
fis.close();
} catch (IOException e) {
LOGGER.error(e);
NotificationDialog.show(NotificationDialog.NOTICE_TYPE.ERROR, PRINT_ERROR);
} catch (PrintException e) {
LOGGER.error(e);
}
} else { // no printer selected
This gives me an error java.awt.print.PrinterIOException: java.io.IOException: /usr/bin/lpr: where it looks to not find lpr.
If I keep it the way it was originally (not write to file) it prints the postscript as plain text even if adding the check to check if the printer is post script capable. If I use the new way of printing file I get a lpr not found error. If I print the PS document using the command lpr it converts it as expected and prints fine. If I use lpr -l that doesn't format it prints it document as plain text as well.
Any suggestion/help would be great. I am lost on what to do. I really don't want to convert it to an image and print that.
At a guess I'd say that your printer is an HP or at least PCL + PS printer, not a pure PostScript-only printer.
In that case you generally need to prepend the PostScript with a language selection PJL string. If you don't do this then it usually defaults to PCL and if you don't send any PCL commands (which all begin with 0x1B) then everything is treated as plain ASCII text. That would explain why both your application and lpr -l end up writing text, but lpr itself doesn't (presumably it adds the PJL).
You could try prepending the PostScript file with something like:
%-12345X#PJL JOB
#PJL ENTER LANGUAGE=POSTSCRIPT
NB the first byte there, before the % should be a 0x1b ESC character, but I can't readily paste binary....
Try sending the file with lpr -l if that works then you could try your old printing method.

FireDAC TFDTable CreateTable

I am trying to use the CreateTable() method of FireDAC's TFDTable class to create a table on my MySQL Server.
void __fastcall TFormMain::ButtonCreateTableClick(TObject *Sender)
{
TFDTable *Table = new TFDTable(this);
try
{
Table->Connection = FDConnection;
Table->TableName = "Setting";
Table->Exclusive = true;
//Table->FieldDefs->Add( "SettingCode", ftString, 99 );
//Table->FieldDefs->Add( "SettingValue", ftString, 255 );
TField *Field;
Field = new TStringField( this );
Field->Name = "FieldSettingCode";
Field->FieldName = "SettingCode";
Field->Size = 100;
Field->DataSet = Table;
Field = new TStringField( this );
Field->Name = "FieldSettingValue";
Field->FieldName = "SettingValue";
Field->Size = 255;
Field->DataSet = Table;
// Fires "Table 'Setting' doesn't exist" error
Table->CreateTable( false, TFDPhysCreateTableParts() << tpTable << tpPrimaryKey << tpIndexes );
Table->Open();
Table->Insert();
Table->FieldByName("SettingCode")->Value = "test2";
Table->FieldByName("SettingValue")->Value = "testValue2";
Table->Post();
// Table->CreateDataSet();
}
__finally
{
Table->Free();
}
}
As soon as I call the CreateTable method it throws an error that the table xxxx.Setting does not exist:
Im Projekt DBCreator.exe ist eine Exception der Klasse EMySQLNativeException mit der Meldung '[FireDAC][Phys][MySQL] Table 'setting' already exists' aufgetreten.
So far so good: This error message is correct - but the real fun fact is, that the table has been successfully created and the code has been inserted.
This also happens using SQLite instead of MySQL.
I am using Embarcadero C++ Builder XE10 Seattle.
How should I handle this correctly?
Is there a way to supress this pretty useless error message?
Edit:
It turned out that EMySQLNativeException is only thrown when the debugger is running. So I just clicked the checkbox to ignore these exceptions and everything is good.
Creating databases with TFDTable and CreateTable() works like charm. Unfortunately it is just undocumented at all (like almost everything #Borland/CodeGear/Embarcadero)...
That exception is thrown by the FireDAC engine and is caused by an attempt to create table without checking if already exists. It is internally handled and the engine acts properly, so what you see is a debugger exception message. If you called the CreateTable method with the recreation parameter enabled:
Table->CreateTable( True, TFDPhysCreateTableParts() << tpTable << tpPrimaryKey << tpIndexes );
the table would be first deleted and you would not get the mentioned exception for this reason.

Set "ouf of paper" status for print job from the driver (programmatically)

My goal is to implement functionality in the driver which allows to define is it possible print new page. This code asks printer if there's enough paper to print current page and if not then it should set "out of paper" status (like it works for HP printer).
For doing this I use DDI hooks (for Start Page). What I did here is:
LPJOB_INFO_1 pJobInfo = NULL;
GetJob(hPrinter, pOemPDEV->JobId, 1, NULL, 0, &dwNeeded);
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
return FALSE;
pJobInfo = (LPJOB_INFO_1) AllocSplMem(dwNeeded);
if (!pJobInfo)
return FALSE;
BOOL getJobRes = GetJob(hPrinter, pOemPDEV->JobId, 1, (LPBYTE)pJobInfo, dwNeeded, &dwNeeded);
if (!getJobRes)
return FALSE;
wsprintf(string, L"pJobInfo->Status %d", pJobInfo->Status);
VERBOSE(string);
pJobInfo->Status |= JOB_STATUS_PAPEROUT;
BOOL a = SetJob(hPrinter, pOemPDEV->JobId, 1, (LPBYTE)pJobInfo, JOB_CONTROL_PAUSE);
In result I have:
SetJob returns FALSE and error is 5 (Access denied)
status changed to "Paused", however Out-Of-Paper did not appear:
The question is how to set JOB_STATUS_PAPEROUT. Thanks in advance.
Late to the party, sorry. I follow the tag print-spooler-api. Anyway, you probably solved this months ago, but you might get Access Denied if you don't set Position to JOB_POSITION_UNSPECIFIED.

Reading / writing file on local machine

I pretty much copied this code right out of the MDN File I/O page.. except I added an if statement to check if the file exists already and if it does, read it instead.
Components.utils.import("resource://gre/modules/NetUtil.jsm");
Components.utils.import("resource://gre/modules/FileUtils.jsm");
var file = Components.classes["#mozilla.org/file/directory_service;1"].
getService(Components.interfaces.nsIProperties).
get("Desk", Components.interfaces.nsIFile);
file.append("test.txt");
if (!file.exists()) {
this.user_id = Math.floor(Math.random()*10001) +'-'+ Math.floor(Math.random()*10001) +'-'+ Math.floor(Math.random()*10001) +'-'+ Math.floor(Math.random()*10001);
var ostream = FileUtils.openSafeFileOutputStream(file)
var converter = Components.classes["#mozilla.org/intl/scriptableunicodeconverter"].
createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
var istream = converter.convertToInputStream(this.user_id);
// The last argument (the callback) is optional.
NetUtil.asyncCopy(istream, ostream, function(status) {
if (!Components.isSuccessCode(status)) {
alert('Error '+ status);
return;
}
alert('File created');
});
} else
{
NetUtil.asyncFetch(file, function(inputStream, status) {
if (!Components.isSuccessCode(status)) {
alert('error '+ status);
return;
}
// The file data is contained within inputStream.
// You can read it into a string with
this.user_id = NetUtil.readInputStreamToString(inputStream, inputStream.available());
});
alert('File exists already, do not create');
}
alert(this.user_id);
It creates the file just fine, I can open it and read it. If the file already exists however, it does not populate this.user_id.. just equals null. So my issue is specifically with reading the file.
File reading in your code works asynchronously - meaning that your code completes (including the alert() call which will show that this.user_id is null), then at some point the callback from NetUtil.asyncFetch() gets called with the data. Until that happens this.user_id won't be set of course. If you move alert(this.user_id) into the callback function it should show the correct value.
Note that it is highly recommended to keep file I/O operations asynchronous because they might take significant time depending on the current state of the file system. But you have to structure your code in such a way that it doesn't assume that file operations happen immediately.

writing to text file in blackberry

is there any way out that we can make the data in text file persistent? everytime a user finishes playing a game, in my program his name and respective score is written to a text file. When the next player comes the previous one gets overwritten. since am writing in write mode, I am not sure whether append mode is supported to save scores of this sort in blackberry...any suggestions are welcome
You should really use the PersistentStore to store this type of information - it's much easier to use and probably more reliable than trying to write files.
However, if you insist on writing files, here's the general code to open a file for appending:
private OutputStream openFileForWriting(String filePath) {
try {
FileConnection fconn = (FileConnection) Connector.open(filePath);
// If no exception is thrown, then the URI is valid, but the file may or may not exist.
if (!fconn.exists()) {
fconn.create(); // create the file if it doesn't exist
}
return fconn.openOutputStream(fconn.fileSize());
} catch (IOException ioe) {
System.out.println("Could not open " + filePath + " for writing");
}
return null;
}

Resources