Set printer driver specific data - delphi

We have an application that prints 2 invoice copies - 1 on white (for the cust) and 1 on blue (for us).
We print a LOT of these so we are getting a printer with 3 big trays. One tray (tray 5) holds 4000 sheets and the other two (trays 3 and 4) are a tandem set holding 1600 and 2000 sheets. The application automatically generates the invoice and sends one document to the tray with the white paper and one to the tray with the blue paper.
The user has no input in this process.
Now, my problem is this - if I specifically send the blue copy to tray 3 and there is no paper in tray 3, the job will go on hold until someone loads it up even though tray 4 has 2000 more sheets ready to go. On the other hand, if I tell the printer to print on Blue 8 1/2x11" paper, it is smart enough to know that that type of paper is in both trays and to pull from either one until they are both empty. So, I want to change our application to select a paper type/size and color instead of a specific tray.
The program is written in Delphi and I have been looking at the DEVMODE structure returned by TPrinter.GetPrinter. The DEVMODE structure has a memory size in dmDriverExtra that indicates how much extra data the print driver is adding to the structure for its own storage.
Does anyone know of anyway to access this data and make changes to it? If you have examples in other languages, I can probably adapt it to Delphi so anything will help.

There are actually two different items in the questions:
How to set the pater size and type:
PaperSize would be stored in dmPaperSize (value DMPAPER_LETTER)
PaperType is a bit more difficult. I'd guess that it's in dmMediaType (use DeviceCapabilities to retrieve available media types and their names)
How to access / edit "DriverExtra" data:
In short: don't!
A bit longer: dmDriverExtra is described as "Contains the number of bytes of private driver-data that follow this structure". So this data is private to the driver (which means that you need very good documentation for the driver to actually know the format and content of this data. It's not guaranteed that different versions of the driver use the same format).
So the only thing you can do is to use a print dialog, retrieve the DevMode structure and store it for further use (however as I said: If the driver changes, this data may become invalid...)

Related

what is Printer-based Barcodes,How is it implemented?

How is this technique implemented?
I noticed that they(like Bartender) don't directly concatenate commands like ZPL (etc.).
And also they don't use bitmap(GDI,GDI+ images) transfer to printer-driver.
Printer-based Serialization In print jobs that include serial numbers, many printers can accept a starting value and the incremental
step size. When you use this printer-based serialization, you can
print a large number of serialized items without having to send any
data after the first label.
Printer-based Barcodes Printers that have built-in barcode functionality make it possible for software programs to request
complex barcodes by using simple text strings (such as “1234”). This
process is much faster than sending bitmap images (or pictures) of
barcodes that consume hundreds or thousands of extra bytes per printed
item. (When you use software other than BarTender, our driver fonts
give you some limited functionality.)
Printer-based barcodes are, as you mention, barcodes that have the symbology / definition stored in the printer firmware. Much like a DLL that you give "12345" and as a result gets a bitmap, an SVG file etc etc.
Many modern label printers know a bunch of common symbologies such as EAN, DM, QR, UPC and similar.
The benefit is obviously that it makes transfer of data much more efficient. Instead of sending a (large) image for every print, the software just sends initial definition (layout, symbology choice and options, ..) + the value needed. Taken to the next level, the printer could receive metadata such as "take this layout, make 500 labels, and in the barcode start at 1, increase 1 every label".
Some disadvantages are
is that the appearance is left to the firmware designer of the printer firmware
There may be less coordination between what's being designed and what's being printed, although typically the driver for the printer should adress this.
The printer firmware may not be updated if the barcode symbology specifications has been updated
The printer firmware may contain only a subset of the barcode definition
In short, simplificy vs freedom of parameters and appearance.
How it is technically implemented (at printer end, from receiving the number to drawing the actual barcode) is probably out of scope for this forum.
Example specification (in newer printer model)
Looking at a random Zebra Printer (ZT600) the built-in barcodes covers nearly every use:
1D symbologies
Code11, Code39, Code93, Code128 (all subsets),
UCC, ISBT, UPC, EAN 8 / 13, UPC/EAN extensions,
Plessey, Postnet, 2of5, Logmars, MSI, Codabar and Planet Code
2D symbologies
codablock, PDF417, Code49, Datamatrix,
QR, TLC39, MicroPDF, RSS14 +composite and Aztec.
When you print an element on a label (barcode or text) you can do that by sending a graphic field or by instructing the printer to pick up the element internally and build the element with the configuration you need.
For example, in case you want to print a text, the ZPL command will include the font you want to use, vertical and horizontal size, position of the text and so on.
In the case of a barcode, the barcode selector contained in the ZPL command, will automatically recall the .BAR file stored in the Z memory, which contains the instructions for the printer to build the barcode, then, in the same command and likewise for the text, you have also provide the size of the barcode (usually it's a ratio between the narrow and the bold line), the position, the human readable line and so on.
The graphic method is used for example when a font which is not stored on the printer memory is used: the printer doesn't recognize the font and so it can't build the text, so the print can happen only after a conversion of the text field into a graphic field. This works well with text fields, but the barcodes can have quality issues as, due to how a thermal printers physicall works, the lines of a barcode can be printed like a sort of saw. Moreover you can't see or edit the data since the code is basically unreadable, that's why it's impossible to send serialized data, unless you use a software.
The element printing is not affected by this type of quality issues and allows you to edit the data.
If you want to see the difference, try to use zebradesigner and print to file a label with a barocode. When you select a barcode, you can choose to print it as a graphic or to use the printer element and you'll see that the .prn files will contains different data.
This is what you get using the printer element (128 barcode containing 123456789012)
https://justpaste.it/66gvp
and this is the same barcode printed as graphic field
https://justpaste.it/27abu

Using HERE in Forth for temporary space

I'm writing a game in Forth (for learning purposes).
The game is played on a "10 cell board". I'm trying new stuff so I did
here 10 [char] - fill
to set up the space for the board.
Then, to play 'X' in position 3
[char] X here 3 + c!
This has been working fine, but raises the question
Is this OK?
What if the board was a million cells wide?
Thanks
The described approach has the certain environmental dependencies, so your program just have to match the environmental restriction on programs of your Forth system (i.e. that you use).
1. Size of the data space
The word UNUSED returns "the amount of space remaining in the region addressed by HERE". So, a program can check the available space.
Also, according to the subsection 4.1.3 Other system documentation of the Forth Standard:
A system shall provide the following information:
[...]
program data space available, in address units;
So, you have just to check whether your Forth system provides enough data space for you program, and how the available data space can be configured (if any).
2. Transient regions
In the general case, it is not safe for a portable program to use the data space without reserving it.
According to the section 3.3.3.6 Other transient regions of the Forth Standard, the contents of the data space regions identified by PAD, WORD, and #> may become invalid after the data space is allocated. Сonsequently, the contents of the region identified by HERE may become invalid after the contents of the regions identified by PAD, WORD, and #> are changed.
See also A.3.3.3.6 Other transient regions:
In many existing Forth systems, these areas are at HERE or just beyond it, hence the many restrictions.
Moreover, some Forth systems may use the region identified by HERE in internal purposes during translation. E.g. Gforth 0.7.9 uses this region when decoding escaped strings.
The phrase:
s\" test\-passed" cr here over type cr type cr
outputs:
test-passed
test-passed
So, you have to check the restrictions of your Forth system whether you may use the region identified by HERE without reserving the space (and in what conditions).

nand2tetris. Memory implementation

I realized Data memory implementation in nand2tetris course. But I really don't understand some parts of my implementation:
CHIP Memory {
IN in[16], load, address[15];
OUT out[16];
PARTS:
DMux4Way(in=load, sel=address[13..14], a=RAM1, b=RAM2, c=scr, d=kbr);
Or(a=RAM1, b=RAM2, out=RAM);
RAM16K(in=in, load=RAM, address=address[0..13], out=RAMout);
Screen(in=in, load=scr, address=address[0..12], out=ScreenOut);
Keyboard(out=KeyboardOut);
Mux4Way16(a=RAMout, b=RAMout, c=ScreenOut, d=KeyboardOut, sel=address[13..14], out=out);
}
Is responsible for what load here. I understand that if load is 0 - out of Dmux4Way in any case will be 0 0 0 0. But i don't understand how it works in that case after that. Namely how it allows don't load data in Memory.
At least incomprehensible why in Screen we fed address[0..12] instead address[0..14] - full address. In my opinion we should use second because Screen memory map stay after RAM memory map and if we want to request for Screen memory map - we should use range (16 384 - 24 575) - decimal or (100000000000000 - 101111111111111) - binary. But how we can represent that range use just 13 width buss (address[0..12]) ??? It's impossible.
Therefore if we want to represent Screen memory map we should use range which was presented above. And that range has 15 width or address[0..14] BUT not address[0..12] (width 13). But why works just address[0..12] and doesn't work address[0..14](full address)
DMux4Way(in=load, sel=address[13..14], a=RAM1, b=RAM2, c=scr, d=kbr);
I'm sorry to criticize you at the beginning, but questions you ask suggest that you didn't do this exercise yourself or didn't start the whole course from the beginning.
To answer your questions:
Ad.1.
You demultiplex a single bit (load bit) to the correct memory part. Thereafter, you then feed the input data to all memory parts at the same time.
It's easier and neater than doing it the other way around, namely, to direct 16-bit input to the correct part (RAM16K, screen, or keyboard) while having a load bit that is connected and active at every register in all the parts.
To clarify. You have 2 possible destinations when writing data: RAM and Screen. The smallest demultiplexer you have is a 4-way multiplexer and that's what you're using. When you write into memory, you need to provide 2 pieces of information: the data and destination, both at the same time.
You might demultiplex the input data with DMux4Way16 and separately single load bit with DMux4Way but that would take 2 demultiplexers, and we can do better than that. That's what's done here, you direct data input to both RAM and Screen and then only use one demultiplexer : DMux4Way to select one of 2 possible destinations, only the one selected will be loaded with new data, on the other data input will be ignored. Knowing that, you need to study A-instruction format: when bit 14 and 13 of A-instruction (or data residing in A-register) have the binary value 00 or 01, the destination is RAM. When bit 14 and 13 have the binary value 10, it means the screen is the destination.
When you notice that you choose these 2 bits as sel for your demultiplexer. Selections 0 and 1 have the same meaning, so you can OR them and feed the output as load to RAM. Selection 2 means Screen will be loaded with a, new value, so load bit goes there. Selection 3 is never used so we don't care about it - output d of demultiplexer will not be connected anywhere. We make use of the demultiplexer's feature: The selected output will have value 1 and all other outputs will yield 0 as a result. It means only 1 memory destination will be loaded.
Ad.2.
Screen is separate device, it has nothing to do with RAM, ROM or Keyboard memory devices here. You, and only you, give meaning to what bits mean what to this specific device. To answer your question, when you address some register in Screen you address it in its own internal address space. In its internal address space first address will be 0, but from whole Memory it will be 16384. It's your job to make this transition. In this particular case, size of Screen memory device it is not necessary to use 14-bit address bus, 13 bits is all you need. What would 14th bit mean in this case? It wouldn't add any value. Also, you are user and not designer of Screen, you only look at and follow its interface description.
Hope it answers your questions, if not I urge you to go back and study more carefully previous hardware related chapters from course.

Sorting 20GB of data

In the past I had to work with big files, somewhere about in the 0.1-3GB range. Not all the 'columns' were needed so it was ok to fit the remaining data in RAM.
Now I have to work with files in 1-20GB range, and they will probably grow as the time will pass. That is totally different because you cannot fit the data in RAM anymore.
My file contains several millions of 'entries' (I have found one with 30 mil entries). On entry consists in about 10 'columns': one string (50-1000 unicode chars) and several numbers. I have to sort the data by 'column' and show it. For the user only the top entries (1-30%) are relevant, the rest is low quality data.
So, I need some suggestions about in which direction to head out. I definitively don't want to put data in a DB because they are hard to install and configure for non computer savvy persons. I like to deliver a monolithic program.
Showing the data is not difficult at all. But sorting... without loading the data in RAM, on regular PCs (2-6GB RAM)... will kill some good hours.
I was looking a bit into MMF (memory mapped files) but this article from Danny Thorpe shows that it may not be suitable: http://dannythorpe.com/2004/03/19/the-hidden-costs-of-memory-mapped-files/
So, I was thinking about loading only the data from the column that has to be sorted in ram AND a pointer to the address (into the disk file) of the 'entry'. I sort the 'column' then I use the pointer to find the entry corresponding to each column cell and restore the entry. The 'restoration' will be written directly to disk so no additional RAM will be required.
PS: I am looking for a solution that will work both on Lazarus and Delphi because Lazarus (actually FPC) has 64 bit support for Mac. 64 bit means more RAM available = faster sorting.
I think a way to go is Mergesort, it's a great algorithm for sorting a
large amount of fixed records with limited memory.
General idea:
read N lines from the input file (a value that allows you to keep the lines in memory)
sort these lines and write the sorted lines to file 1
repeat with the next N lines to obtain file 2
...
you reach the end of the input file and you now have M files (each of which is sorted)
merge these files into a single file (you'll have to do this in steps as well)
You could also consider a solution based on an embedded database, e.g. Firebird embedded: it works well with Delphi/Windows and you only have to add some DLL in your program folder (I'm not sure about Lazarus/OSX).
If you only need a fraction of the whole data, scan the file sequentially and keep only the entries needed for display. F.I. lets say you need only 300 entries from 1 million. Scan the first first 300 entries in the file and sort them in memory. Then for each remaining entry check if it is lower than the lowest in memory and skip it. If it is higher as the lowest entry in memory, insert it into the correct place inside the 300 and throw away the lowest. This will make the second lowest the lowest. Repeat until end of file.
Really, there are no sorting algorithms that can make moving 30gb of randomly sorted data fast.
If you need to sort in multiple ways, the trick is not to move the data itself at all, but instead to create an index for each column that you need to sort.
I do it like that with files that are also tens of gigabytes long, and users can sort, scroll and search the data without noticing that it's a huge dataset they're working with.
Please finde here a class which sorts a file using a slightly optimized merge sort. I wrote that a couple of years ago for fun. It uses a skip list for sorting files in-memory.
Edit: The forum is german and you have to register (for free). It's safe but requires a bit of german knowledge.
If you cannot fit the data into main memory then you are into the realms of external sorting. Typically this involves external merge sort. Sort smaller chunks of the data in memory, one by one, and write back to disk. And then merge these chunks.

To set a value on a PowerBuilder textbox

I am developing a billing system using PowerBuilder 12.5 Classic and I need to set 0 for a textbox; like in vb.net txtchange.Text = 0
i have two drop down list boxes
ddlb_price (defines the price value of an item)
ddlb_cash (the cash amount given by the customer)
sle_change (the change that the cashier is to give the customer)
the system should set the value for sle_change when the cashier inputs the cash.
1. this gives me syntax error;
if cash=price then
sle_fare.settext=0
end if
2. this gives 'incompatible types in assinment
if cash=price then
sle_fare.text=0
end if
The single line edit (sle) control is designed to hold text. You're trying to assign it a numeric value. You will have to change the number into a string if you want the sle to display it:
sle_fare.text = "0"
or
sle_fare.text = string(variableHere)
Once again, I'm going to step back, ignore the actual questions, and look at how a DataWindow would help as an alternative.
You seem to want a control with a data type behind it. The DataWindow has those types of controls. Don't forget that a DataWindow doesn't have to have a SELECT statement behind it; it can have a stored procedure, web service, or nothing at all (external DataWindow) behind the data set. Once you have a control with a numeric data type behind it, you get (for free) some basic editing controls, such as not allowing alpha characters in the field and making sure the entered value is really a number (e.g. "0-.2.1" would fail).
A step beyond that is looking at one of your coming requirements: calculating change. On a DataWindow, you can create a compute with an expression that will automagically calculate your change for you, once price and cash are entered.
I certainly don't want to say you can't do things the way you're proceeding, but there are many issues that a DataWindow would remove over some other approach. The strength of PowerBuilder is in the DataWindow.
Good luck,
Terry

Resources