Write the Indy 10 of Delphi Codes's to C ++ Builder's Indy 10 - delphi

I am new to learn C ++ Builder. Three days ago, I installed Embarcadero®. C++Builder® 2010. This language is very interesting for me to learn.
In Delphi, I generally write a simple proxy-server using TIdMappedPortTCP of Indy 9 and 10. I usually use its OnExecute and OnOutboundData events to modify data as it passes through the proxy.
Since I'm new in C ++ Builder, so I don't know how to convert my Delphi code to the exactly right C ++ Builder code.
I've tried and tried many ways, including reading several books, one of which is Borland C ++ Builder - The Complete Reference, by Herbert Schildt, as well as to increase knowledge. Unfortunately, in the book was not discussed at all very important things related to my condition. Also, I find references on google, but I've not found.
So, I ventured to ask for your help. I really need it.
Please help! Thank you very much.
The following is my Indy 10's Delphi code that I want to write to C ++ Builder.
......
procedure TForm.IdMappedPortTCP1Execute(AContext: TIdContext);
var
Mydata, NetData: string;
begin
if (Pos('HTTP',netstring(AContext)) <> 0) or (Pos('GET',netstring(AContext)) <> 0) then begin
NetData := netstring(AContext);
TIdMappedPortContext(AContext).OutboundClient.IOHandler.Write(AddHeader(netstring(AContext),'Connection: Keep-Alive'));
Sleep(1000);
Mydata := 'GET http://website.com/ HTTP/1.1'+#13#10+'Host: website.com'#13#10;
NetData := Mydata + Netdata;
TIdMappedPortContext(AContext).NetData := netbyte(Netdata);
TIdMappedPortContext(AContext).OutboundClient.IOHandler.Write(netbyte(Mydata + NetData));
end;
end;
......

A literal translation to C++Builder would look like this:
......
String __fastcall AddHeader(String S, String Header)
{
S = StringReplace(S, "\r\n\r\n", "\r\n" + Header + "\r\n\r\n", TReplaceFlags() << rfReplaceAll);
return S;
}
void __fastcall TForm::IdMappedPortTCP1Execute(TIdContext *AContext)
{
String Mydata, NetData;
if ((netstring(AContext).Pos("HTTP") != 0) || (netstring(AContext).Pos("GET") != 0))
{
NetData = netstring(AContext);
TIdMappedPortContext(AContext)->OutboundClient->IOHandler->Write(AddHeader(netstring(AContext), "Connection: Keep-Alive"));
Sleep(1000);
Mydata = "GET http://website.com/ HTTP/1.1\r\nHost: website.com\r\n";
NetData = Mydata + Netdata;
static_cast<TIdMappedPortContext*>(AContext)->NetData = netbyte(Netdata);
static_cast<TIdMappedPortContext*>(AContext)->OutboundClient->IOHandler->Write(netbyte(Mydata + NetData));
}
}
......
Here is a slightly condensed version:
......
String __fastcall AddHeader(String S, String Header)
{
return StringReplace(S, "\r\n\r\n", "\r\n" + Header + "\r\n\r\n", TReplaceFlags() << rfReplaceAll);
}
void __fastcall TForm::IdMappedPortTCP1Execute(TIdContext *AContext)
{
String NetData = netstring(AContext);
if ((NetData.Pos("HTTP") != 0) || (NetData.Pos("GET") != 0))
{
Sleep(1000);
String Mydata = "GET http://website.com/ HTTP/1.1\r\nHost: website.com\r\n" + AddHeader(NetData, "Connection: Keep-Alive");
static_cast<TIdMappedPortContext*>(AContext)->NetData = netbyte(Mydata);
}
}
......
But either way, this is definitely NOT a reliable way to implement a viable HTTP proxy in Indy. In fact, Indy 10 introduced a specific TIdHTTPProxyServer component for that very purpose. You should seriously consider using that instead of TIdMappedPortTCP. For example, the above can be done in TIdHTTPProxyServer like this:
class TIdHTTPProxyServerContextAccess : public TIdHTTPProxyServerContext
{
public:
void SetCommand(String Value) { FCommand = Value; }
void SetDocument(String Value) { FDocument = Value; }
void SetTarget(String Value) { FTarget = Value; }
};
void __fastcall TForm1.IdHTTPProxyServer1HTTPBeforeCommand(TIdHTTPProxyServerContext *AContext)
{
static_cast<TIdHTTPProxyServerContextAccess*>(AContext)->SetCommand("GET");
static_cast<TIdHTTPProxyServerContextAccess*>(AContext)->SetTarget ("http://website.com/");
static_cast<TIdHTTPProxyServerContextAccess*>(AContext)->SetDocument("/");
AContext->Headers->Values["Host"] = "website.com";
AContext->Headers->Values["Connection"] = "Keep-Alive";
/*
the original code was not changing the Host/Port where the
HTTP request was being sent to. But if you needed to,
you can do it like this...
static_cast<TIdTCPClient*>(AContext->OutboundClient)->Host = "website.com";
static_cast<TIdTCPClient*>(AContext->OutboundClient)->Port = 80;
*/
}
Update: the netstring() and netbyte() functions you linked to have syntax errors, and have unnecessary overhead (there is no need to involve MIME just to convert a String into a byte array and vice versa, Indy has functions specifically for that purpose). Here are the corrected versions:
String __fastcall netstring(TIdMappedPortContext* AContext)
{
return BytesToStringRaw(AContext->NetData);
}
TIdBytes __fastcall netbyte(String S)
{
return ToBytes(S, IndyTextEncoding_8Bit());
}
So, you could actually just eliminate the functions altogether:
void __fastcall TForm::IdMappedPortTCP1Execute(TIdContext *AContext)
{
TIdMappedPortContext *ctx = static_cast<TIdMappedPortContext*>(AContext)
String NetData = BytesToStringRaw(ctx->NetData);
if ((NetData.Pos("HTTP") != 0) || (NetData.Pos("GET") != 0))
{
Sleep(1000);
String Mydata = "GET http://website.com/ HTTP/1.1\r\nHost: website.com\r\n" + AddHeader(NetData, "Connection: Keep-Alive");
ctx->NetData = ToBytes(Mydata);
}
}

Related

Problems using ReadDirectoryChanges in Rad Studio

I am trying to load a file into a stream in BASS via ReadDirectoryChanges.
When I use a testfunction using FileOpenDialog I get a working result, but when I use RDC it craps out on me all the time. I must be doing something wrong, but for the life of me I can't figure it out. Maybe someone here can point me in the right direction.
Below is a snippet of the code I use:
void __fastcall TForm9::ToWav(FILE_NOTIFY_INFORMATION* File)
{
String FullFileName = OpokaClient.ImportLocation + copyfname(File);
int BassResult = 0;
LogLine("File added to: " + FullFileName, apSYSTEM);
HSTREAM convert = NULL;
convert = MyBASS_StreamCreateFile(false, FullFileName.c_str(), 0, 0, BASS_STREAM_DECODE | BASS_UNICODE);
BassResult = MyBASS_ErrorGetCode();
LogLine("Bass Result: " + IntToStr(BassResult), apSYSTEM);
}
//---------------------------------------------------------------------------
void __fastcall TForm9::Button2Click(TObject *Sender)
{
String FileName;
int BassResult = 0;
if(FileOpenDialog1->Execute()) {
FileName = FileOpenDialog1->FileName;
} else {
LogLine("No file selected. FileName empty", apWARNING);
return;
}
HSTREAM convert = NULL;
LogLine("ConverterMain: ToWav: FileName: " + FileName, apSYSTEM);
convert = MyBASS_StreamCreateFile(false, FileName.c_str(), 0, 0, BASS_STREAM_DECODE | BASS_UNICODE);
BassResult = MyBASS_ErrorGetCode();
LogLine("chan ErrorCode: " + IntToStr(BassResult), apSYSTEM);
}
//---------------------------------------------------------------------------
copyfname is in a different unit..
wchar_t* copyfname(FILE_NOTIFY_INFORMATION* pfi)
{
wchar_t* pfn;
pfn = new wchar_t[pfi->FileNameLength+1];
ZeroMemory(pfn, sizeof(wchar_t)*(pfi->FileNameLength+1));
memcpy(pfn, pfi->FileName, pfi->FileNameLength);
return pfn;
}

Sending SMS through API from Delphi

I want to send SMS from Delphi using an online API.
The API is provided by a service provider that works when used through a web browser, as below:
http://sendpk.com/api/sms.php?username=xxxx&password=xxxx&sender=Masking&mobile=xxxx&message=Hello
The above url works fine when opened through a web browser, and the SMS is sent successfully. Now, I am struggling to integrate the API into my Delphi application.
By searching through the Internet, I have found some examples, and finally I tried the below code:
var
lHTTP: TIdHTTP;
lParamList: TStringList;
begin
lParamList := TStringList.Create;
lParamList.Add('username=xxxx');
lParamList.Add('password=xxxx');
lParamList.Add('sender=Masking');
lParamList.Add('mobile=xxxx');
lParamList.Add('message=Hello');
lHTTP := TIdHTTP.Create;
try
PostResult.Lines.Text := lHTTP.Post('http://sendpk.com/api/sms.php', lParamList);
finally
lHTTP.Free;
lParamList.Free;
end;
But I am getting an error:
HTTP/1.1 406 Not Acceptable
The API Reference, as provided on service provider's website, is available below:
http://sendpk.com/api.php
Kindly guide me. What am I doing wrong, and what is the right code to use?
Edit
C# code provided in the API reference is as below:
using System;
using System.Net;
using System.Web;
public class Program
{
public static void Main()
{
string MyUsername = "userxxx"; //Your Username At Sendpk.com
string MyPassword = "xxxx"; //Your Password At Sendpk.com
string toNumber = "92xxxxxxxx"; //Recepient cell phone number with country code
string Masking = "SMS Alert"; //Your Company Brand Name
string MessageText = "SMS Sent using .Net";
string jsonResponse = SendSMS(Masking, toNumber, MessageText, MyUsername, MyPassword);
Console.Write(jsonResponse);
//Console.Read(); //to keep console window open if trying in visual studio
}
public static string SendSMS(string Masking, string toNumber, string MessageText, string MyUsername , string MyPassword)
{
String URI = "http://sendpk.com" +
"/api/sms.php?" +
"username=" + MyUsername +
"&password=" + MyPassword +
"&sender=" + Masking +
"&mobile=" + toNumber +
"&message=" + Uri.UnescapeDataString(MessageText); // Visual Studio 10-15
try
{
WebRequest req = WebRequest.Create(URI);
WebResponse resp = req.GetResponse();
var sr = new System.IO.StreamReader(resp.GetResponseStream());
return sr.ReadToEnd().Trim();
}
catch (WebException ex)
{
var httpWebResponse = ex.Response as HttpWebResponse;
if (httpWebResponse != null)
{
switch (httpWebResponse.StatusCode)
{
case HttpStatusCode.NotFound:
return "404:URL not found :" + URI;
break;
case HttpStatusCode.BadRequest:
return "400:Bad Request";
break;
default:
return httpWebResponse.StatusCode.ToString();
}
}
}
return null;
}
}
You need to use TIdHTTP.Get() instead of TIdHTTP.Post():
var
lHTTP: TIdHTTP;
lUser, lPass, lSender, lMobile, lMsg: string;
begin
lUser := 'xxxx';
lPass := 'xxxx';
lSender := 'Masking';
lMobile := 'xxxx';
lMsg := 'Hello';
lHTTP := TIdHTTP.Create;
try
PostResult.Lines.Text := lHTTP.Get('http://sendpk.com/api/sms.php?username=' + TIdURI.ParamsEncode(lUser) + '&password=' + TIdURI.ParamsEncode(lPass) + '&sender=' + TIdURI.ParamsEncode(lSender) + '&mobile=' + TIdURI.ParamsEncode(lMobile) + '&message=' + TIdURI.ParamsEncode(lMsg));
finally
lHTTP.Free;
end;
end;
Update: a 406 response code means the server could not return a response in a format that would be acceptable to the client based on the client's Accept... request header(s) (Accept, Accept-Language, Accept-Encoding, etc), so check your headers against what the API is expecting and what a browser sends.

Using a struct with map data

I'm relatively new to Go, I'm struggling to get my head around using POST data with structs. What I essentially want to do is submit a form, then submit that form to MongoDB (haven't got that far yet). I can't work out how to use this form data with a struct.
package main
import "net/http"
type Paste struct {
Title string
Content string
Language string
Expires int
Created int64
}
func index(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
r.ParseForm()
// r.Form = map[title:[Wadup] content:[Brother]]
}
}
func main() {
http.HandleFunc("/", index)
http.ListenAndServe(":1234", nil)
}
What I basically want to do is insert the map values into the struct, without manually assigning all of them, like you can see here: p := Paste{Title: r.Form["title"]}
Use gorilla/schema, which was built for this use-case:
package main
import(
"net/http"
"github.com/gorilla/schema"
)
type Paste struct {
Title string
Content string
Language string
Expires int
Created int64
}
var decoder = schema.NewDecoder()
func index(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
// handle error
var paste = &Paste{}
err := decoder.Decode(paste, r.PostForm)
// handle error
}
After you called r.ParseForm() you can access r.Form which holds a map[string][]string of the parsed form data. This map can be accessed by using keys (your form field names):
r.ParseForm()
form := r.Form
someField := form["someField"]
anotherField := form["anotherField"]
or loop through all available keys/ values:
r.ParseForm()
form := r.Form
for key, value := range form {
fmt.Println("Key:", key, "Value:", value)
}
Update
In case you want a more generic solution take a look at the reflect package. Just to give you a rough example it could look like this:
v := url.Values{}
v.Set("Title", "Your Title")
v.Set("Content", "Your Content")
v.Set("Language", "English")
v.Set("Expires", "2015")
v.Set("Created", "2014")
paste := Paste{}
ps := reflect.ValueOf(&paste)
s := ps.Elem()
for key, value := range v {
f := s.FieldByName(key)
if f.IsValid() && f.CanSet() {
switch f.Kind() {
case reflect.String:
f.SetString(value[0])
case reflect.Int64:
i, _ := strconv.ParseInt(value[0], 0, 64)
f.SetInt(i)
}
}
}
Play

Print barcodes from web page to Zebra printer

We're trying to print barcodes from a web page to our Zebra printer.
I'm wondering if there's a way to print them using the printer's own font perhaps using web fonts or if I knew the font name used?
I have been trying to use php barcode generators, that basically generates images containing the barcode. I have in fact been trying this approach for a few days already, without success.
The problem is when I print them it's not readable by the scanners. I have tried to change the image resolution to match that of the printer (203dpi), also tried playing with the image size and formats, but the barcodes after printed still can't be scanned.
So does anybody have experience with this?
Printer: Zebra TLP 2844
Barcodes required per page:
01 Code39 horizontal (scanable only if printed at very specific size and browser)
01 Code128 vertical (still can't get it to work, print is always very blurry and won't get scanned)
===========
I've made a little bit of progress, I found out this printer supports EPL2 language, so I'm trying to use it to print out the barcodes.
First I needed to enable pass through mode, I did that on Printer Options > Advanced Setup > Miscellaneous.
Now I'm able to print barcodes impeccably using the printer's built-in font :D using this command:
ZPL:
B10,10,0,1,2,2,60,N,"TEXT-GOES-HERE"
:ZPL
But I can only print it from Notepad, I'm still unable to print this from a browser... It's probably a problem with LF being replaced with CR+LF...
How to overcome this problem??
===========
The label I'm trying to print actually has a bit of text before the barcode, with some html tables formatting it nicely. So I need to print this first, and in the middle I need to stick in a nice label and then add some more text.
So I can't use pure EPL2 to print the whole thing, I'm wondering if I can use some of both html + EPL2 + html to achieve my goal or is that not allowed?? =/
You are running into a few obstacles:
1) When you print through the OS installed printer driver, the printer driver is trying to take the data that is sent to it and (re)rasterize or scale it for the output device (the Zebra printer). Since the printer is a relatively low resolution at 203dpi, then it does not take too much for the scaling the print driver is having to do for it to loose some integrity in the quality of the barcode. This is why barcodes generated using the direct ZPL commands are much more reliable.
2) Due to the security that web browsers purposefully provide by not allowing access to the client computer, you cannot directly communicate with the client connected printer. This sandboxing is what helps to protect users from malware so that nefarious websites cannot do things like write files to the client machine or send output directly to devices such as printers. So you are not able to directly send the ZPL commands through the browser to the client connected printer.
However, there is a way to do what you describe. The steps necessary are typically only going to be useful if you have some degree of control over the client computer accessing the site that is trying to print to the Zebra printers. For example this is only going to be used by machines on your company network, or by clients who are willing to install a small application that you need to write. To do this, you will need to look at the following steps:
A) You need to make up your own custom MIME type. This is basically just any name you want to use that is not going to collide with any registered MIME types.
B) Next you will define a filename extension that will map to your custom MIME type. To do this, you typically will need to configure your web server (steps for this depend on what web server you are using) to allow the new MIME type you want to define and what file extension is used for these types of files.
C) Then on your web application, when you want to output the ZPL data, you write it to a file using a filename extension that is mapped to your new MIME type. Then once the file is generated, you can either provide an HTML link to it, or redirect the client browser to the file. You can test if your file is working correctly at this point by manually copying the file you created directly to the raw printer port.
D) Next you need to write a small application which can be installed on the client. When the application is installed, you need to have it register itself as a valid consuming application for your custom MIME type. If a browser detects that there is an installed application for a file of the specified MIME type, it simply writes the file to a temporary directory on the client machine and then attempts to launch the application of the same registered MIME type with the temporary file as a parameter to the application. Thus your application now just reads the file that the browser passed to it and then it attempts to dump it directly to the printer.
This is an overview of what you need to do in order to accomplish what you are describing. Some of the specific steps will depend on what type of web server you are using and what OS your clients machines are. But this is the high level overview that will let you accomplish what you are attempting.
If you'd consider loading a java applet, qz-print (previously jzebra) can do exactly what you are describing and works nicely with the LP2844 mentioned in the comments.
https://code.google.com/p/jzebra/
What we did for our web app :
1) Download the free printfile app http://www.lerup.com/printfile/
"PrintFile is a freeware MS Windows utility program that will enable you to print files fast and easily. The program recognizes plain text, PostScript, Encapsulated PostScript (EPS) and binary formats. Using this program can save you a lot of paper and thereby also saving valuable natural resources."
When you first run PrintFile, go into the advanced options and enable "send to printer directly".
2) Setup the ZEBRA printer in windows as a Generic Text Printer.
2) Generate a file.prt file in the web app which is just a plain text EPL file.
3) Double clicking on the downloaded file will instantly print the barcode. Works like a charm. You can even setup PrintFile so that you don't even see a gui.
I am using QZ Tray to print labels from a web page to Zebra thermal printer.
In the demo/js folder of QZ Tray there are three JavaScript files that are required to communicate with QZ Tray application - dependencies/rsvp-3.1.0.min.js, dependencies/sha-256.min.js and qz-tray.js.
Include these JavaScript files in your project as follows:
<script type="text/javascript" src="/lib/qz-tray/rsvp-3.1.0.min.js"></script>
<script type="text/javascript" src="/lib/qz-tray/sha-256.min.js"></script>
<script type="text/javascript" src="/lib/qz-tray/qz-tray.js"></script>
The most simple way to print a label to Zebra thermal printer is shown below.
<script type="text/javascript">
qz.websocket.connect().then(function() {
// Pass the printer name into the next Promise
return qz.printers.find("zebra");
}).then(function(printer) {
// Create a default config for the found printer
var config = qz.configs.create(printer);
// Raw ZPL
var data = ['^XA^FO50,50^ADN,36,20^FDRAW ZPL EXAMPLE^FS^XZ'];
return qz.print(config, data);
}).catch(function(e) { console.error(e); });
</script>
See How to print labels from a web page to Zebra thermal printer for more information.
You can also send the ZPL commands in a text file (you can pack multiple labels in a single file) and have the user open and print the file via windows notepad. The only caveat is that they have to remove the default header and footer (File --> Page Setup).
Its a bit of user training, but may be acceptable if you don't have control over the client machines.
I'm developing something similar here.
I need to print in a LP2844 from my webapp. The problem is that my webapp is in a remote server in the cloud (Amazon EC2) and the printer is going to be in a warehouse desk.
My solution:
The webapp generates the EPL2 code for the label with the barcodes, then publish a PubNub message.
I wrote a little C# program that runs in the computer where the printer is connected. The program receives the message and then send the code to the printer.
I followed the idea proposed by "Tres Finocchiaro" on my application based on:
ASP.NET 4.0
IIS
Chrome, IExplorer, Firefox
Zebra TLP 2844
EPL protocolo
Unfortunatly the jzebra needs some improvements to work corectly due to the issues of security of current browser.
Installing jzebra
Downlod jzebdra and from dist directory I copy into your directory (eg. mydir):
web
mydir
js
..
deployJava.js
lib
..
qz-print.jar
qz-print_jnlp.jnlp
Create your print.html
<html>
<script type="text/javascript" src="js/deployJava.js"></script>
<script type="text/javascript">
/**
* Optionally used to deploy multiple versions of the applet for mixed
* environments. Oracle uses document.write(), which puts the applet at the
* top of the page, bumping all HTML content down.
*/
deployQZ();
/** NEW FUNCTION **/
function initPrinter() {
findPrinters();
useDefaultPrinter();
}
/** NEW FUNCTION **/
function myalert(txt) {
alert(txt);
}
/**
* Deploys different versions of the applet depending on Java version.
* Useful for removing warning dialogs for Java 6. This function is optional
* however, if used, should replace the <applet> method. Needed to address
* MANIFEST.MF TrustedLibrary=true discrepency between JRE6 and JRE7.
*/
function deployQZ() {
var attributes = {id: "qz", code:'qz.PrintApplet.class',
archive:'qz-print.jar', width:1, height:1};
var parameters = {jnlp_href: 'qz-print_jnlp.jnlp',
cache_option:'plugin', disable_logging:'false',
initial_focus:'false'};
if (deployJava.versionCheck("1.7+") == true) {}
else if (deployJava.versionCheck("1.6+") == true) {
delete parameters['jnlp_href'];
}
deployJava.runApplet(attributes, parameters, '1.5');
}
/**
* Automatically gets called when applet has loaded.
*/
function qzReady() {
// Setup our global qz object
window["qz"] = document.getElementById('qz');
var title = document.getElementById("title");
if (qz) {
try {
title.innerHTML = title.innerHTML + " " + qz.getVersion();
document.getElementById("content").style.background = "#F0F0F0";
} catch(err) { // LiveConnect error, display a detailed meesage
document.getElementById("content").style.background = "#F5A9A9";
alert("ERROR: \nThe applet did not load correctly. Communication to the " +
"applet has failed, likely caused by Java Security Settings. \n\n" +
"CAUSE: \nJava 7 update 25 and higher block LiveConnect calls " +
"once Oracle has marked that version as outdated, which " +
"is likely the cause. \n\nSOLUTION: \n 1. Update Java to the latest " +
"Java version \n (or)\n 2. Lower the security " +
"settings from the Java Control Panel.");
}
}
}
/**
* Returns whether or not the applet is not ready to print.
* Displays an alert if not ready.
*/
function notReady() {
// If applet is not loaded, display an error
if (!isLoaded()) {
return true;
}
// If a printer hasn't been selected, display a message.
else if (!qz.getPrinter()) {
/** CALL TO NEW FUNCTION **/
initPrinter();
return false;
}
return false;
}
/**
* Returns is the applet is not loaded properly
*/
function isLoaded() {
if (!qz) {
alert('Error:\n\n\tPrint plugin is NOT loaded!');
return false;
} else {
try {
if (!qz.isActive()) {
alert('Error:\n\n\tPrint plugin is loaded but NOT active!');
return false;
}
} catch (err) {
alert('Error:\n\n\tPrint plugin is NOT loaded properly!');
return false;
}
}
return true;
}
/**
* Automatically gets called when "qz.print()" is finished.
*/
function qzDonePrinting() {
// Alert error, if any
if (qz.getException()) {
alert('Error printing:\n\n\t' + qz.getException().getLocalizedMessage());
qz.clearException();
return;
}
// Alert success message
alert('Successfully sent print data to "' + qz.getPrinter() + '" queue.');
}
/***************************************************************************
* Prototype function for finding the "default printer" on the system
* Usage:
* qz.findPrinter();
* window['qzDoneFinding'] = function() { alert(qz.getPrinter()); };
***************************************************************************/
function useDefaultPrinter() {
if (isLoaded()) {
// Searches for default printer
qz.findPrinter();
// Automatically gets called when "qz.findPrinter()" is finished.
window['qzDoneFinding'] = function() {
// Alert the printer name to user
var printer = qz.getPrinter();
myalert(printer !== null ? 'Default printer found: "' + printer + '"':
'Default printer ' + 'not found');
// Remove reference to this function
window['qzDoneFinding'] = null;
};
}
}
/***************************************************************************
* Prototype function for finding the closest match to a printer name.
* Usage:
* qz.findPrinter('zebra');
* window['qzDoneFinding'] = function() { alert(qz.getPrinter()); };
***************************************************************************/
function findPrinter(name) {
// Get printer name from input box
var p = document.getElementById('printer');
if (name) {
p.value = name;
}
if (isLoaded()) {
// Searches for locally installed printer with specified name
qz.findPrinter(p.value);
// Automatically gets called when "qz.findPrinter()" is finished.
window['qzDoneFinding'] = function() {
var p = document.getElementById('printer');
var printer = qz.getPrinter();
// Alert the printer name to user
alert(printer !== null ? 'Printer found: "' + printer +
'" after searching for "' + p.value + '"' : 'Printer "' +
p.value + '" not found.');
// Remove reference to this function
window['qzDoneFinding'] = null;
};
}
}
/***************************************************************************
* Prototype function for listing all printers attached to the system
* Usage:
* qz.findPrinter('\\{dummy_text\\}');
* window['qzDoneFinding'] = function() { alert(qz.getPrinters()); };
***************************************************************************/
function findPrinters() {
if (isLoaded()) {
// Searches for a locally installed printer with a bogus name
qz.findPrinter('\\{bogus_printer\\}');
// Automatically gets called when "qz.findPrinter()" is finished.
window['qzDoneFinding'] = function() {
// Get the CSV listing of attached printers
var printers = qz.getPrinters().split(',');
for (i in printers) {
myalert(printers[i] ? printers[i] : 'Unknown');
}
// Remove reference to this function
window['qzDoneFinding'] = null;
};
}
}
/***************************************************************************
* Prototype function for printing raw EPL commands
* Usage:
* qz.append('\nN\nA50,50,0,5,1,1,N,"Hello World!"\n');
* qz.print();
***************************************************************************/
function print() {
if (notReady()) { return; }
// Send characters/raw commands to qz using "append"
// This example is for EPL. Please adapt to your printer language
// Hint: Carriage Return = \r, New Line = \n, Escape Double Quotes= \"
qz.append('\nN\n');
qz.append('q609\n');
qz.append('Q203,26\n');
qz.append('B5,26,0,1A,3,7,152,B,"1234"\n');
qz.append('A310,26,0,3,1,1,N,"SKU 00000 MFG 0000"\n');
qz.append('A310,56,0,3,1,1,N,"QZ PRINT APPLET"\n');
qz.append('A310,86,0,3,1,1,N,"TEST PRINT SUCCESSFUL"\n');
qz.append('A310,116,0,3,1,1,N,"FROM SAMPLE.HTML"\n');
qz.append('A310,146,0,3,1,1,N,"QZINDUSTRIES.COM"');
// Append the rest of our commands
qz.append('\nP1,1\n');
// Tell the applet to print.
qz.print();
}
/***************************************************************************
* Prototype function for logging a PostScript printer's capabilites to the
* java console to expose potentially new applet features/enhancements.
* Warning, this has been known to trigger some PC firewalls
* when it scans ports for certain printer capabilities.
* Usage: (identical to appendImage(), but uses html2canvas for png rendering)
* qz.setLogPostScriptFeatures(true);
* qz.appendHTML("<h1>Hello world!</h1>");
* qz.printPS();
***************************************************************************/
function logFeatures() {
if (isLoaded()) {
var logging = qz.getLogPostScriptFeatures();
qz.setLogPostScriptFeatures(!logging);
alert('Logging of PostScript printer capabilities to console set to "' + !logging + '"');
}
}
/***************************************************************************
****************************************************************************
* * HELPER FUNCTIONS **
****************************************************************************
***************************************************************************/
function getPath() {
var path = window.location.href;
return path.substring(0, path.lastIndexOf("/")) + "/";
}
/**
* Fixes some html formatting for printing. Only use on text, not on tags!
* Very important!
* 1. HTML ignores white spaces, this fixes that
* 2. The right quotation mark breaks PostScript print formatting
* 3. The hyphen/dash autoflows and breaks formatting
*/
function fixHTML(html) {
return html.replace(/ /g, " ").replace(/’/g, "'").replace(/-/g,"‑");
}
/**
* Equivelant of VisualBasic CHR() function
*/
function chr(i) {
return String.fromCharCode(i);
}
/***************************************************************************
* Prototype function for allowing the applet to run multiple instances.
* IE and Firefox may benefit from this setting if using heavy AJAX to
* rewrite the page. Use with care;
* Usage:
* qz.allowMultipleInstances(true);
***************************************************************************/
function allowMultiple() {
if (isLoaded()) {
var multiple = qz.getAllowMultipleInstances();
qz.allowMultipleInstances(!multiple);
alert('Allowing of multiple applet instances set to "' + !multiple + '"');
}
}
</script>
<input type="button" onClick="print()" />
</body>
</html>
the code provided is based on "jzebra_installation/dist/sample.html".
try creating a websocket that controls the print on the client side and send data with ajax from the page to localhost.
/// websocket
using System;
using System.Net;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
namespace Server
{
class Program
{
public static WebsocketServer ws;
static void Main(string[] args)
{
ws = new Server.WebsocketServer();
ws.LogMessage += Ws_LogMessage;
ws.Start("http://localhost:2645/service/");
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
private static void Ws_LogMessage(object sender, WebsocketServer.LogMessageEventArgs e)
{
Console.WriteLine(e.Message);
}
}
public class WebsocketServer
{
public event OnLogMessage LogMessage;
public delegate void OnLogMessage(Object sender, LogMessageEventArgs e);
public class LogMessageEventArgs : EventArgs
{
public string Message { get; set; }
public LogMessageEventArgs(string Message)
{
this.Message = Message;
}
}
public bool started = false;
public async void Start(string httpListenerPrefix)
{
HttpListener httpListener = new HttpListener();
httpListener.Prefixes.Add(httpListenerPrefix);
httpListener.Start();
LogMessage(this, new LogMessageEventArgs("Listening..."));
started = true;
while (started)
{
HttpListenerContext httpListenerContext = await httpListener.GetContextAsync();
if (httpListenerContext.Request.IsWebSocketRequest)
{
ProcessRequest(httpListenerContext);
}
else
{
httpListenerContext.Response.StatusCode = 400;
httpListenerContext.Response.Close();
LogMessage(this, new LogMessageEventArgs("Closed..."));
}
}
}
public void Stop()
{
started = false;
}
private async void ProcessRequest(HttpListenerContext httpListenerContext)
{
WebSocketContext webSocketContext = null;
try
{
webSocketContext = await httpListenerContext.AcceptWebSocketAsync(subProtocol: null);
LogMessage(this, new LogMessageEventArgs("Connected"));
}
catch (Exception e)
{
httpListenerContext.Response.StatusCode = 500;
httpListenerContext.Response.Close();
LogMessage(this, new LogMessageEventArgs(String.Format("Exception: {0}", e)));
return;
}
WebSocket webSocket = webSocketContext.WebSocket;
try
{
while (webSocket.State == WebSocketState.Open)
{
ArraySegment<Byte> buffer = new ArraySegment<byte>(new Byte[8192]);
WebSocketReceiveResult result = null;
using (var ms = new System.IO.MemoryStream())
{
do
{
result = await webSocket.ReceiveAsync(buffer, CancellationToken.None);
ms.Write(buffer.Array, buffer.Offset, result.Count);
}
while (!result.EndOfMessage);
ms.Seek(0, System.IO.SeekOrigin.Begin);
if (result.MessageType == WebSocketMessageType.Text)
{
using (var reader = new System.IO.StreamReader(ms, Encoding.UTF8))
{
var r = System.Text.Encoding.UTF8.GetString(ms.ToArray());
var t = Newtonsoft.Json.JsonConvert.DeserializeObject<Datos>(r);
bool valid = true;
byte[] toBytes = Encoding.UTF8.GetBytes(""); ;
if (t != null)
{
if (t.printer.Trim() == string.Empty)
{
var printers = "";
foreach (var imp in System.Drawing.Printing.PrinterSettings.InstalledPrinters)
{
printers += imp + "\n";
}
toBytes = Encoding.UTF8.GetBytes("No se Indicó la Impresora\nLas Impresoras disponibles son: " + printers);
valid = false;
}
if (t.name.Trim() == string.Empty)
{
toBytes = Encoding.UTF8.GetBytes("No se Indicó el nombre del Documento");
valid = false;
}
if (t.code == null)
{
toBytes = Encoding.UTF8.GetBytes("No hay datos para enviar a la Impresora");
valid = false;
}
if (valid)
{
print.RawPrinter.SendStringToPrinter(t.printer, t.code, t.name);
toBytes = Encoding.UTF8.GetBytes("Correcto...");
}
await webSocket.SendAsync(new ArraySegment<byte>(toBytes, 0, int.Parse(toBytes.Length.ToString())), WebSocketMessageType.Binary, result.EndOfMessage, CancellationToken.None);
}
else
{
toBytes = Encoding.UTF8.GetBytes("Error...");
await webSocket.SendAsync(new ArraySegment<byte>(toBytes, 0, int.Parse(toBytes.Length.ToString())), WebSocketMessageType.Binary, result.EndOfMessage, CancellationToken.None);
}
}
}
}
}
}
catch (Exception e)
{
LogMessage(this, new LogMessageEventArgs(String.Format("Exception: {0} \nLinea:{1}", e, e.StackTrace)));
}
finally
{
if (webSocket != null)
webSocket.Dispose();
}
}
}
public class Datos
{
public string name { get; set; }
public string code { get; set; }
public string printer { get; set; } = "";
}
}
raw Print:
using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO;
namespace print
{
public class RawPrinter
{
// Structure and API declarions:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class DOCINFOA
{
[MarshalAs(UnmanagedType.LPStr)]
public string pDocName;
[MarshalAs(UnmanagedType.LPStr)]
public string pOutputFile;
[MarshalAs(UnmanagedType.LPStr)]
public string pDataType;
}
[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)]
string szPrinter, ref IntPtr hPriknter, IntPtr pd);
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In(), MarshalAs(UnmanagedType.LPStruct)]
DOCINFOA di);
[DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndDocPrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, ref Int32 dwWritten);
// SendBytesToPrinter()
// When the function is given a printer name and an unmanaged array
// of bytes, the function sends those bytes to the print queue.
// Returns true on success, false on failure.
public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount, string DocName = "")
{
Int32 dwError = 0;
Int32 dwWritten = 0;
IntPtr hPrinter = new IntPtr(0);
DOCINFOA di = new DOCINFOA();
bool bSuccess = false;
// Assume failure unless you specifically succeed.
di.pDocName = string.IsNullOrEmpty(DocName) ? "My C#.NET RAW Document" : DocName;
di.pDataType = "RAW";
// Open the printer.
if (OpenPrinter(szPrinterName.Normalize(), ref hPrinter, IntPtr.Zero))
{
// Start a document.
if (StartDocPrinter(hPrinter, 1, di))
{
// Start a page.
if (StartPagePrinter(hPrinter))
{
// Write your bytes.
bSuccess = WritePrinter(hPrinter, pBytes, dwCount, ref dwWritten);
EndPagePrinter(hPrinter);
}
EndDocPrinter(hPrinter);
}
ClosePrinter(hPrinter);
}
// If you did not succeed, GetLastError may give more information
// about why not.
if (bSuccess == false)
{
dwError = Marshal.GetLastWin32Error();
}
return bSuccess;
}
public static bool SendFileToPrinter(string szPrinterName, string szFileName)
{
// Open the file.
FileStream fs = new FileStream(szFileName, FileMode.Open);
// Create a BinaryReader on the file.
BinaryReader br = new BinaryReader(fs);
// Dim an array of bytes big enough to hold the file's contents.
Byte[] bytes = new Byte[fs.Length];
bool bSuccess = false;
// Your unmanaged pointer.
IntPtr pUnmanagedBytes = new IntPtr(0);
int nLength = 0;
nLength = Convert.ToInt32(fs.Length);
// Read the contents of the file into the array.
bytes = br.ReadBytes(nLength);
// Allocate some unmanaged memory for those bytes.
pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength);
// Copy the managed byte array into the unmanaged array.
Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength);
// Send the unmanaged bytes to the printer.
bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength);
// Free the unmanaged memory that you allocated earlier.
Marshal.FreeCoTaskMem(pUnmanagedBytes);
return bSuccess;
}
public static bool SendStringToPrinter(string szPrinterName, string szString, string DocName = "")
{
IntPtr pBytes = default(IntPtr);
Int32 dwCount = default(Int32);
// How many characters are in the string?
dwCount = szString.Length;
// Assume that the printer is expecting ANSI text, and then convert
// the string to ANSI text.
pBytes = Marshal.StringToCoTaskMemAnsi(szString);
// Send the converted ANSI string to the printer.
SendBytesToPrinter(szPrinterName, pBytes, dwCount, DocName);
Marshal.FreeCoTaskMem(pBytes);
return true;
}
}
}
html page:
<!DOCTYPE html>
<html>
<head>
</head>
<body ng-app="myapp">
<div ng-controller="try as ctl">
<input ng-model="ctl.ticket.nombre">
<textarea ng-model="ctl.ticket.code"></textarea>
<button ng-click="ctl.send()">Enviar</button>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<script>
var ws = new WebSocket("ws://localhost:2645/service");
ws.binaryType = "arraybuffer";
ws.onopen = function () {
console.log('connection is opened!!!');
};
ws.onmessage = function (evt) {
console.log(arrayBufferToString(evt.data))
};
ws.onclose = function () {
console.log("Connection is Closed...")
};
function arrayBufferToString(buffer) {
var arr = new Uint8Array(buffer);
var str = String.fromCharCode.apply(String, arr);
return decodeURIComponent(escape(str));
}
var app = angular.module('myapp', []);
app.controller('try', function () {
this.ticket= {nombre:'', estado:''}
this.send = () => {
var toSend= JSON.stringify(this.ticket);
ws.send(toSend);
}
});
</script>
</body>
</html>
then send a ZPL code from html(write this on textarea code);
^XA
^FO200,50^BY2^B3N,N,80,Y,N^FD0123456789^FS
^PQ1^XZ

Test if casting an OleVariant would raise an exception (without raising an exception)

In Delphi I want to determine whether a particular OleVariant can be cast to a particular data type without raising an exception if it can't. Exceptions are not for program flow, right?
What I want is something like this, where Type could be anything supported by an OleVariant:
if TryVarAsType(variant, value) then ...
What I don't want is
try
value := Type(variant);
// case where the variant could be converted to a Type
except
// case where the variant could not be converted to a Type
end;
The case where the variant could not be converted to a Boolean is just a normal case that occurs regularly and doesn't indicate any kind of error.
you can construct such function using the VariantChangeTypeEx function.
uses
VarUtils,
Variants;
function TryVarAsType( AVariant : OleVariant; const AVarType: TVarType ) :Boolean;
var
SourceType: TVarType;
begin
SourceType:=TVarData(AVariant).VType;
//the types are ole compatible
if (AVarType and varTypeMask < varInt64) and (SourceType and varTypeMask < varInt64) then
Result:=
(SourceType=AVarType) or
(VariantChangeTypeEx(TVarData(AVariant), TVarData(AVariant), VAR_LOCALE_USER_DEFAULT, 0, AVarType)=VAR_OK)
else
Result:=False; //Here you must process the variant pascal types like varString
end;
and use like this
TryVarAsType('1',varInteger);
TryVarAsType('s',varInteger)
this will work with only with ole compatible Variant types
varEmpty = $0000; { vt_empty 0 }
varNull = $0001; { vt_null 1 }
varSmallint = $0002; { vt_i2 2 }
varInteger = $0003; { vt_i4 3 }
varSingle = $0004; { vt_r4 4 }
varDouble = $0005; { vt_r8 5 }
varCurrency = $0006; { vt_cy 6 }
varDate = $0007; { vt_date 7 }
varOleStr = $0008; { vt_bstr 8 }
varDispatch = $0009; { vt_dispatch 9 }
varError = $000A; { vt_error 10 }
varBoolean = $000B; { vt_bool 11 }
varVariant = $000C; { vt_variant 12 }
varUnknown = $000D; { vt_unknown 13 }
varShortInt = $0010; { vt_i1 16 }
varByte = $0011; { vt_ui1 17 }
varWord = $0012; { vt_ui2 18 }
varLongWord = $0013; { vt_ui4 19 }
varInt64 = $0014; { vt_i8 20 }
for the another types (pascal variants) like varString, varAny you must check the source and destination TVarType and write your own test cases.
UPDATE
As #David point me out, the locale settings can produce different results for the same values, so you must consider this answer just as initial step or tip to construct your own function and you must aware of locale settings issues caused in the proposed function.
I'm not aware of built-in support that would allow dynamic conversion checking that failed with an error code rather than an exception.
You could hand-code it yourself but doing so would produce an intolerable amount of duplication of the code in the Variants unit. In this case I think that using exceptions is less bad than the alternative of duplicating implementation dependent code.
As a counter-example to RRUZ's most ingeneous answer, I offer the following code:
procedure Main;
var
v: Variant;
i: Integer;
CanConvert: Boolean;
begin
v := '$1';
Writeln(BoolToStr(TryVarAsType(v, varInteger), True));
try
i := Integer(v);
if i>0 then begin
CanConvert := True;
end;
except
CanConvert := False;
end;
Writeln(BoolToStr(CanConvert, True));
end;
Output:
False
True

Resources