中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何使用c++調用windows api進行打印

發布時間:2020-06-28 10:38:47 來源:億速云 閱讀:374 作者:清晨 欄目:開發技術

小編給大家分享一下如何使用c++調用windows api進行打印,希望大家閱讀完這篇文章后大所收獲,下面讓我們一起去探討方法吧!

前言

在近期開發的收銀臺項目中,需要使用打印機進行小票打印,打印流程的時序圖如下所示:

如何使用c++調用windows api進行打印

在客戶的使用過程中,遇到一個問題,如果機器安裝了打印機驅動,那么調用廠商提供的 sdk 進行打印的話,會導致出現小票只打印一半的情況,對此,需要繞過廠商 sdk 使用系統的打印才能夠解決這一問題。

在 web 端打印中,需要調用瀏覽器打印 api 進行網頁打印。這意味著,之前后端編寫的esc/pos無法復用到,同時,前端還得花費精力來編寫 html 以及css 來完成打印內容的排版,這無疑增加了復雜度以及工作量。正打算開始時,得到高人指點。

可以使用 windows api 進行打印

具體參見這篇文檔

于是開始這方面的研究,功夫不負有心人,使用 windows api 完成了系統的打印,于是編寫這篇文章記錄踩過的坑。
首先看看如何進行打印:

BOOL RawDataToPrinter(LPSTR szPrinterName, LPBYTE lpData, DWORD dwCount)
{
  HANDLE   hPrinter;
  DOC_INFO_1 DocInfo;
  DWORD   dwJob;
  DWORD   dwBytesWritten;

  // Need a handle to the printer.
  if (!OpenPrinter(szPrinterName, &hPrinter, NULL)) {
    int y = GetLastError();
    cout << "openFail" << y << endl;
    return FALSE;
  }

  // Fill in the structure with info about this "document."

  DocInfo.pDocName = LPSTR("My Document\0");
  DocInfo.pOutputFile = NULL;
  DocInfo.pDatatype = NULL; // LPWSTR("RAW\0");
  // Inform the spooler the document is beginning.
  if ((dwJob = StartDocPrinter(hPrinter, 1, (LPBYTE)&DocInfo)) == 0)
  {
    int x = GetLastError();
    cout << "StartDocPrinter Fail" << x << endl;
    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;
}

在文檔中提到,打開打印機時"OpenPrinter"可以傳入 null 以使用本地打印服務,因為不知道打印機名稱,于是就傳入了 null,結果在 StartDocPrinter 時一直提示失敗,后來了解到使用 GetLastError 可以查看 error code,得到錯誤碼后一對照,發現是 handle 是無效的,也就意味這 OpenPrinter 這一步驟沒有打開需要的打印機。于是嘗試使用 設備與打印機中的打印機名稱,還真就連上了,成功調用打印服務。

但客戶電腦上的打印機名稱是不固定的,不能使用固定打印機名稱,所以得拿到已經連接了的打印機列表,于是搜索到了 EnumPrinters 這一api,具體用法如下:

void getPrinterList() {
  PRINTER_INFO_2* printerList;
  unsigned char size;
  unsigned long pcbNeeded;
  unsigned long pcReturned;

  EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &pcbNeeded, &pcReturned);

  if ((printerList = (PRINTER_INFO_2*)malloc(pcbNeeded)) == 0) {
    return;
  }

  if (!EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)printerList, pcbNeeded, &pcbNeeded, &pcReturned)) {
    free(printerList);
    return;
  }

  for (int i = 0; i < (int)pcReturned; i++) {

    string printName(printerList[i].pPrinterName);
    if (printerList[i].Attributes & PRINTER_ATTRIBUTE_NETWORK) {
      cout << "網絡打印機" << printName << endl;
    }
    else {
      cout << "本地打印機" << printName << endl;
    }
  }

  cout << "number " << pcReturned << endl;

}

通過這一方式,的確獲取到了系統中可用的打印機,可是拿到可用的打印機后還是有一個問題:“如何知道哪一個是小票打印機”&#63;

為此又進行了搜索,又找到了一個 api GetDefaultPrinter,用法如下:

string getDefaultPrinterName() {
  DWORD size = 0;
  GetDefaultPrinter(NULL, &size);

  if (size) {
    TCHAR* buffer = new TCHAR[size];
    GetDefaultPrinter(buffer, &size);
    string printerName(buffer);
    return printerName;
  }
  else {
    return "";
  }
}

通過此方法獲取到系統默認打印機,客戶只需要設置默認的打印機為小票打印機就完美解決問題了。

以下是完整代碼:

#include <iostream>
#include <windows.h>
#include "node.h"
#include "base64.h"

using namespace std;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Object;
using v8::String;
using v8::Value;
using v8::Integer;
using v8::Int8Array;

BOOL RawDataToPrinter(LPSTR szPrinterName, LPBYTE lpData, DWORD dwCount);
string getDefaultPrinterName();

void localPrintRawData(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  Local<v8::Context> context = isolate->GetCurrentContext();
  v8::String::Utf8Value portString(isolate, args[0]);
  std::string base64Str(*portString);

  vector<BYTE> bytes = base64_decode(base64Str);
  char* buffer = new char[bytes.size()];
  copy(bytes.begin(), bytes.end(), buffer);
  string printerName = getDefaultPrinterName();
  if (printerName.size() > 0) {
    printerName += "\0";
    wstring ws(printerName.begin(), printerName.end());
    RawDataToPrinter(const_cast<char*>(printerName.c_str()), &bytes[0], bytes.size());
  }
  else {
    cout << "no printer" << endl;
  }
}

BOOL RawDataToPrinter(LPSTR szPrinterName, LPBYTE lpData, DWORD dwCount)
{
  HANDLE   hPrinter;
  DOC_INFO_1 DocInfo;
  DWORD   dwJob;
  DWORD   dwBytesWritten;

  // Need a handle to the printer.
  if (!OpenPrinter(szPrinterName, &hPrinter, NULL)) {
    int y = GetLastError();
    cout << "openFial" << y << endl;
    return FALSE;
  }

  // Fill in the structure with info about this "document."

  DocInfo.pDocName = LPSTR("My Document\0");
  DocInfo.pOutputFile = NULL;
  DocInfo.pDatatype = NULL; // LPWSTR("RAW\0");
  // Inform the spooler the document is beginning.
  if ((dwJob = StartDocPrinter(hPrinter, 1, (LPBYTE)&DocInfo)) == 0)
  {
    int x = GetLastError();
    cout << "StartDocPrinter Fial" << x << endl;
    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;
}

void getPrinterList() {
  PRINTER_INFO_2* printerList;
  unsigned char size;
  unsigned long pcbNeeded;
  unsigned long pcReturned;

  EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &pcbNeeded, &pcReturned);

  if ((printerList = (PRINTER_INFO_2*)malloc(pcbNeeded)) == 0) {
    return;
  }

  if (!EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)printerList, pcbNeeded, &pcbNeeded, &pcReturned)) {
    free(printerList);
    return;
  }

  for (int i = 0; i < (int)pcReturned; i++) {

    string printName(printerList[i].pPrinterName);
    if (printerList[i].Attributes & PRINTER_ATTRIBUTE_NETWORK) {
      cout << "網絡打印機" << printName << endl;
    }
    else {
      cout << "本地打印機" << printName << endl;
    }
  }

  cout << "number " << pcReturned << endl;

}

string getDefaultPrinterName() {
  DWORD size = 0;
  GetDefaultPrinter(NULL, &size);

  if (size) {
    TCHAR* buffer = new TCHAR[size];
    GetDefaultPrinter(buffer, &size);
    string printerName(buffer);
    return printerName;
  }
  else {
    return "";
  }
}

void Initialize(Local<Object> exports) {
  NODE_SET_METHOD(exports, "localPrintRawData", localPrintRawData);
}

NODE_MODULE(zq_device, Initialize)

看完了這篇文章,相信你對如何使用c++調用windows api進行打印有了一定的了解,想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

班戈县| 阜平县| 祁东县| 苍南县| 江孜县| 理塘县| 许昌市| 长宁县| 五莲县| 伊春市| 康乐县| 普安县| 土默特右旗| 南投市| 济源市| 昌江| 永兴县| 鸡东县| 三江| 宝清县| 周口市| 威信县| 前郭尔| 环江| 沁水县| 新乡市| 邮箱| 靖边县| 临漳县| 阜宁县| 寿光市| 石渠县| 静宁县| 江安县| 左权县| 开远市| 顺昌县| 海淀区| 广元市| 五常市| 曲松县|