帳票出力の新関数

PRNFILE* lpt = prn_open(L"OKI MICROLINE XXXX");

prn_printf(lpt, "\x1b@");  // 初期化
prn_printf(lpt, "test");   // 印字
prn_printf(lpt, "\f");     // 改ページ

prn_close(lpt);

---------------------------------------------------------

#include <windows.h>
#include <cstdarg>

struct PRNFILE {
    HANDLE hPrinter;
};

----------------------------------------------------------

PRNFILE* prn_open(const wchar_t* printerName)
{
    PRNFILE* pf = new PRNFILE;

    if (!OpenPrinterW*1 {
        delete pf;
        return nullptr;
    }

    DOC_INFO_1W docInfo;
    docInfo.pDocName = (LPWSTR)L"Raw Print";
    docInfo.pOutputFile = NULL;
    docInfo.pDatatype = (LPWSTR)L"RAW";

    StartDocPrinterW(pf->hPrinter, 1, (LPBYTE)&docInfo);
    StartPagePrinter(pf->hPrinter);

    return pf;
}

-------------------------------------------------------

int prn_printf(PRNFILE* pf, const char* fmt, ...)
{
    char buffer[1024];
    va_list args;
    va_start(args, fmt);
    int len = vsnprintf(buffer, sizeof(buffer), fmt, args);
    va_end(args);

    if (len <= 0) return 0;

    DWORD written;
    WritePrinter(pf->hPrinter, buffer, len, &written);
    return written;
}
-------------------------------------------------------

void prn_close(PRNFILE* pf)
{
    if (!pf) return;

    EndPagePrinter(pf->hPrinter);
    EndDocPrinter(pf->hPrinter);
    ClosePrinter(pf->hPrinter);

    delete pf;
}
------------------------------------------------------

DOSコード 置換後
FILE* lpt PRNFILE* lpt
fopen() prn_open()
fprintf() prn_printf()
fcloseall() prn_close()

まとめ(重要)

  • Windowsでは FILE* でプリンタは叩けない

  • でも 「見た目・使い方」は完全に再現できる

  • これは RS-232C → USB 移行でも王道手法

*************************
完成版 prn_printf()(実務用)

#include <cstdarg>
#include <cstdio>
#include <windows.h>

int prn_printf(PRNFILE* pf, const char* fmt, ...)
{
    if (!pf) return 0;

    char buffer[2048];   // 帳票ならこれで十分
    va_list args;

    va_start(args, fmt);
    int len = vsnprintf(buffer, sizeof(buffer), fmt, args);
    va_end(args);

    if (len <= 0) return 0;
    if (len >= (int)sizeof(buffer)) {
        // バッファ溢れ防止(切り捨て)
        len = sizeof(buffer) - 1;
    }

    DWORD written = 0;
    WritePrinter(pf->hPrinter, buffer, len, &written);
    return written;
}

④ 実務例(帳票コードが完全にそのまま)

int value = 123;

prn_printf(lpt, "\x1b@");
prn_printf(lpt, "数量:%6d\n", value);
prn_printf(lpt, "金額:%6d 円\n", value * 10);
prn_printf(lpt, "\f");

注意点(ここだけは必ず守る)

⚠ ワイド文字は使わない

❌ ダメ

 
prn_printf(lpt, L"%6d", value);

⭕ OK

 
prn_printf(lpt, "%6d", value);

ESC/Pは char(Shift-JIS)前提

 

⚠ 改行コード

文字 意味
\n 行送り
\r 復帰
\r\n 機種によりズレ



*1:LPWSTR)printerName, &pf->hPrinter, NULL

OKI ESC/P コマンド具体例

OKI(MICROLINE系)で RAW印刷 × ESC/P を前提に、実務でよく使うコマンドだけに絞ります。

※ 機種差はありますが、MICROLINE 5xxx / 8xxx 系はほぼ共通です


0️⃣ 基本(必ず最初に送る)

 
"\x1b@" // ESC @ プリンタ初期化
  • 状態リセット

  • 文字ピッチ・改行状態クリア

  • 最初の1発は必須


1️⃣ 印字+改ページ(最小テスト)

 
"\x1b@" "TEST PRINT" "\f"

✔ これが出なければ RAWが通っていない


2️⃣ 改行・行送り制御

内容 コマンド
改行 \n
キャリッジリターン \r
1/6インチ改行 \n
n/216インチ行送り ESC J n
 
"\x1bJ\x24" // 36/216インチ送る

3️⃣ 文字ピッチ(超重要)

内容 コマンド
10cpi ESC P
12cpi ESC M
17cpi ESC g
20cpi ESC W 1(機種依存)
 
"\x1bP" // 10cpi

4️⃣ 強調・装飾

太字

 
"\x1bE" // ON "\x1bF" // OFF

下線

 
"\x1b-\x01" // ON "\x1b-\x00" // OFF

5️⃣ 日本語(漢字)印刷【重要】

OKIは Shift-JIS + 漢字モード が基本。

 
"\x1b$B" // 漢字モード ON "テスト印字" "\x1b$@" // 漢字モード OFF

UTF-8不可
char[] で送る


6️⃣ 横位置制御(桁合わせ)

絶対位置

 
"\x1b$\x50\x00" // 80ドット位置へ

タブ設定

 
"\x1bD\x10\x20\x30\x00" "\t"

7️⃣ 用紙サイズ・マージン

左マージン

 
"\x1bl\x05" // 5桁

右マージン

 
"\x1bQ\x50" // 80桁

8️⃣ 罫線(帳票で必須)

 
"\xC4" // ─ "\xB3" // │ "\xDA" // ┌ "\xBF" // ┐ "\xC0" // └ "\xD9" // ┘

※ 半角カナ・コードページ依存
OKIは IBM拡張文字が安定


9️⃣ 実務用サンプル(帳票1枚)

 
const char data[] = "\x1b@" // 初期化 "\x1bP" // 10cpi "\x1bE" // 太字 "売上伝票\n" "\x1bF" "------------------------------\n" "\x1b$B" "商品名:テスト商品\n" "\x1b$@" "数量:10\n" "金額:1000円\n" "\f";

✔ OKI帳票印刷の王道構成


🔟 トラブル回避ルール(重要)

NG 理由
UTF-8送信 文字化け
GDI印刷 ESC無効
改ページ無し 紙詰まり
初期化省略 設定引き継ぎ

最後に(実務者向け助言)

  • ESC/Pは 「送った順=状態」

  • 毎ジョブ初期化する

  • 帳票は 固定ピッチ前提

C++プリンタ出力

結論から言うと、そのコードをそのままでは「USB接続プリンタ」には直接出力できません。
fopen("lp.txt","w")単なるテキストファイル出力 で、MS-DOS時代の LPT1: 直書きとは意味が違います。

以下、Windows + USB接続 OKIプリンタで同等のことをするための「現実的な手順」を段階的に説明します。


① まず今のコードが何をしているか

 
FILE *lpt = fopen("lp.txt","w");
fprintf(lpt, "\x1b@"); // プリンタ初期化 (ESC @)
fprintf(lpt, "test"); // 印字データ
fprintf(lpt, "\f"); // フォームフィード(改ページ)
fcloseall();

これは

  • lp.txt というファイルを作成

  • ESC/P 系の制御コードを含む 生データを書いている

だけです。

👉 USBプリンタには一切届いていません


② USBプリンタに送る方法は3つある

方法A:Windows印刷API(推奨・正攻法)

  • OpenPrinter

  • StartDocPrinter

  • WritePrinter

👉 ESC/P制御コードをそのまま送れる
👉 OKIプリンタ向き
👉 C++で制御可能

方法B:RAW印刷としてファイルを送る

  • lp.txt を作る

  • copy /b lp.txt "\\spool\OKIプリンタ名"

👉 手動 or system()
👉 簡易だが運用向きではない

方法C:LPTポートに仮想割り当て(非推奨)

  • USBプリンタを LPT1: に割り当てる

  • 古い互換用途のみ

👉 Windows10/11では不安定
👉 今はほぼ使われない


③ 一番確実な方法:Windows RAW印刷(方法A)

🔧 手順概要

  1. プリンタ名を取得(Windowsの「プリンターとスキャナー」に表示されている名前)

  2. Windows APIで RAW モード印刷

  3. ESC/Pコードを直接送信


④ 実際のC++サンプルコード(コンソールアプリ)

 

#include <windows.h>
#include <string>

int main()
{
    HANDLE hPrinter;
    DOC_INFO_1 docInfo;
    DWORD dwWritten;

    // ★ Windowsに登録されているプリンタ名
    LPCWSTR printerName = L"OKI MICROLINE XXXX"; // 実際の名前に変更

    OpenPrinter((LPWSTR)printerName, &hPrinter, NULL);

    docInfo.pDocName = (LPWSTR)L"Raw Print Test";
    docInfo.pOutputFile = NULL;
    docInfo.pDatatype = (LPWSTR)L"RAW";

    StartDocPrinter(hPrinter, 1, (LPBYTE)&docInfo);
    StartPagePrinter(hPrinter);

    // 印刷データ(ESC/P)
    const char data[] =
        "\x1b@"   // 初期化
        "test"
        "\f";     // フォームフィード

    WritePrinter(hPrinter, (LPVOID)data, sizeof(data) - 1, &dwWritten);

    EndPagePrinter(hPrinter);
    EndDocPrinter(hPrinter);
    ClosePrinter(hPrinter);

    return 0;
}


⑤ 重要ポイント(OKIプリンタの場合)

ドライバは「汎用テキスト / RAW対応」になっているか

  • OKI純正ドライバでもOK

  • 「RAW印刷」を受け付ける必要あり

ESC/P対応機種か

  • OKI MICROLINE系はほぼ対応

UnicodeANSIに注意

  • 印字データは charANSI

  • プリンタ名は wchar_t


⑥ どうして fopen("LPT1:") はダメなのか?

項目 MS-DOS Windows
LPT1直書き OK
USBプリンタ 無し 標準
スプーラ 無し あり

Windowsでは 必ずスプーラ経由 が基本です。


⑦ まとめ(最短ルート)

✅ USB接続OKIプリンタ
✅ ESC/Pコードを直接送りたい

👉 Windows RAW印刷 API を使う

もし次に進むなら:

  • プリンタ名の取得方法

  • OKIドライバ設定(RAW有効化)

  • 日本語(漢字)印刷時の注意点

どこまでやりたいか、教えてください。

 

--------------------------------------------------------------------------------

追加方法の選択(ここ重要)

✔ ローカルプリンターとして追加

  • 「ローカル プリンターまたはネットワーク プリンターを手動で追加」

  • 次へ

✔ 既存ポートを使う

  • ポート:USB001 (仮想プリンタポート)
    ※数字は環境依存


ドライバ選択

  • メーカー:OKI

  • プリンタ:機種名を正確に

※ なければ
「ディスク使用」 → OKIドライバフォルダ指定


手順⑤ プリンタが出たら必ず確認する設定

プリンターのプロパティ → 詳細設定

  • スプールの処理方法

    • ☑ プログラムが印刷を完了するまでスプール

  • データ形式

    • RAW

👉 ここが RAW 以外だと ESC/P が無効


手順⑥ それでも出ない場合(強制確認)

PowerShellで確認

 
Get-PnpDevice | Where-Object {$_.FriendlyName -like "*OKI*"}

出るがプリンタ一覧に出ない
→ ドライバ破損 or 関連付け失敗


最終手段(確実)

  1. OKIドライバ アンインストール

  2. USBケーブル 抜く

  3. PC再起動

  4. ドライバ 管理者で再インストール

  5. 指示が出るまでUSBを挿さない

👉 これで9割直ります。


実務視点のアドバイス(重要)

  • USBは「挿しただけ」ではダメ

  • プリンタ一覧に出て初めて OpenPrinter() が使える

  • USBポート名(USB001)は関係ない

  • プリンタ名がすべて

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

① プリンタは出るが OpenPrinter() が失敗する

よくある原因

  1. プリンタ名が完全一致していない

  2. Unicode / ANSI の取り違え

  3. 権限不足

  4. 共有名・ポート名を使っている


即効対処

✅ プリンタ名を再確認

PowerShell

 
Get-Printer | Select Name

C++

 
L"OKI MICROLINE 5650SU-R" // 完全一致

※ 空白・全角半角も一致必須


UnicodeAPIを使う

 
OpenPrinterW((LPWSTR)L"OKI MICROLINE 5650SU-R", &hPrinter, NULL);

✅ 管理者権限で実行


✅ 失敗理由を取得

 
DWORD err = GetLastError(); printf("OpenPrinter error=%lu\n", err);

代表例:

エラー 意味
5 アクセス拒否
1801 プリンタ名不正

② 印刷は出るが制御コード(ESC/P)が効かない

よくある原因

  1. RAW印刷になっていない

  2. ドライバがGDI変換している

  3. ESC/P非対応モード


即効対処

✅ プリンタのプロパティ

詳細設定タブ

  • データ形式RAW

  • ☑ プログラムが印刷を完了するまでスプール


✅ OKIドライバ設定

  • 印刷設定

  • エミュレーション:ESC/P または EPSON

  • PCL / PS は不可


✅ RAW指定をコードで明示

 
docInfo.pDatatype = (LPWSTR)L"RAW";

✅ テスト用最小データ

 
const char data[] = "\x1b@Hello\f";

これで初期化+印字+改ページが効けばOK。


③ 日本語が文字化けする

よくある原因

  1. 文字コード不一致

  2. フォント未指定

  3. プリンタ漢字ROM未対応


即効対処(OKI向け)

✅ Shift-JISで送る

 
const char data[] = "\x1b@" "\x1b$B" // 漢字モード(機種依存) "テスト" "\x1b$@" // 漢字解除 "\f";

※ OKIのESC/Pマニュアル参照


Windows側で文字変換しない

  • wchar_t は使わない

  • UTF-8 は送らない


✅ フォント指定(英数のみなら不要)

 
"\x1bk\x01" // フォント指定例(機種依存)

④ 印刷されるが途中で止まる/真っ白

原因

  • StartPagePrinter() / EndPagePrinter() 不足

  • フォームフィード未送信

  • データ長ミス


対処

 
WritePrinter(hPrinter, (LPVOID)data, strlen(data), &dwWritten);

sizeof ではなく strlen を使うケースも確認


⑤ 何も出ない(無反応)

原因

  • プリンタがオフライン

  • キュー詰まり

  • ドライバ破損


対処チェックリスト

  • 印刷キューを全削除

  • プリンタ再起動

  • ドライバ再インストール

  • テストページ印刷成功確認


⑥ 動作確認の「黄金テスト手順」

  1. Windowsテストページが出る

  2. PowerShellでプリンタ名確認

  3. C++"Hello\f" をRAW送信

  4. ESC/P制御を足す

  5. 日本語を足す

👉 1つずつ積み上げる


まとめ(実務的結論)

症状 最重要ポイント
OpenPrinter失敗 名前・権限
制御効かない RAW + ESC/P
文字化け Shift-JIS
無反応 ドライバ

ここまで理解できていれば、USBプリンタをDOS感覚で直接叩く用途はほぼ制圧です。

RS-232C送受信(3/3)

int TxCommand(const char *str)
{
    int f = 0, state = 0, retry = 0;
    int c, n, lrc;
    clock_t t;

    t = clock();

    while (f == 0) {
        switch (state) {

        case 0: // ENQ送信
            if (retry < 2) {
                retry++;
                SioSend(ENQ);
                t = clock();
                state = 1;
            } else {
                f = 2;
            }
            break;

        case 1: // ACK/NAK待ち
            while *1 == 0) {
                if (t + 1000 < clock()) {
                    state = 0;
                    break;
                }
            }
            if (c == ACK) {
                retry = 0;
                state = 2;
            } else if (c == NAK) {
                state = 0;
            }
            break;

        case 2: // データ送信
            if (retry < 2) {
                retry++;
                SioSend(STX);
                lrc = 0;

                for (n = 0; str[n]; n++) {
                    lrc ^= str[n];
                    SioSend(str[n]);
                }

                SioSend(IntToHex(lrc >> 4));
                SioSend(IntToHex(lrc & 0x0F));
                SioSend(ETX);

                t = clock();
                state = 3;
            } else {
                f = 3;
            }
            break;

        case 3: // ACK/NAK待ち
            while *2 == 0) {
                if (t + 2000 < clock()) {
                    state = 2;
                    break;
                }
            }
            if (c == ACK) {
                state = 4;
            } else if (c == NAK) {
                state = 2;
            }
            break;

        case 4:
            SioSend(EOT);
            f = 1;
            break;
        }
    }

    return f - 1;
}

 

int RxCommand(char *str)
{
    int state = 0, c, f = 0, cnt = 0;
    unsigned int lrc, lrc0;
    clock_t t = clock();

    while (f == 0) {
        switch (state) {

        case 0:
            while *3 == 0) {
                if (t + 5000 < clock()) {
                    f = 2;
                    break;
                }
            }
            if (c == ENQ) state = 1;
            break;

        case 1:
            SioSend(ACK);
            t = clock();
            state = 2;
            break;

        case 2:
            while *4 == 0) {
                if (t + 1000 < clock()) {
                    state = 0;
                    break;
                }
            }
            if (c == STX) {
                cnt = 0;
                t = clock();
                state = 3;
            }
            break;

        case 3:
            while *5 == 0) {
                if (t + 1000 < clock()) {
                    state = 0;
                    break;
                }
            }
            if (c == ETX) {
                state = 4;
            } else {
                str[cnt++] = c;
            }
            break;

        case 4:
            str[cnt] = '\0';
            lrc0 = (HexToInt(str[cnt-2]) << 4) | HexToInt(str[cnt-1]);
            str[cnt-2] = '\0';

            lrc = 0;
            for (int i = 0; str[i]; i++) lrc ^= str[i];

            if (lrc != lrc0) {
                SioSend(NAK);
            } else {
                SioSend(ACK);
            }
            state = 5;
            t = clock();
            break;

        case 5:
            while *6 == 0) {
                if (t + 1000 < clock()) {
                    f = 3;
                    break;
                }
            }
            if (c == EOT) f = 1;
            break;
        }
    }
    return f - 1;
}

 

int main()
{
    if (!OpenComPort("\\\\.\\COM1")) return 1;

    char buf[256];
    TxCommand("HELLO");
    RxCommand(buf);

    printf("RX:%s\n", buf);
    CloseHandle(hCom);
}

*1:c = SioReceive(

*2:c = SioReceive(

*3:c = SioReceive(

*4:c = SioReceive(

*5:c = SioReceive(

*6:c = SioReceive(

RS-232C送受信(2/3)

// シリアルポートオープン

#include <windows.h>
#include <stdio.h>
#include <time.h>

HANDLE hCom;

bool OpenComPort(const char* portName)
{
    hCom = CreateFileA(
        portName,
        GENERIC_READ | GENERIC_WRITE,
        0,
        nullptr,
        OPEN_EXISTING,
        0,
        nullptr
    );

    if (hCom == INVALID_HANDLE_VALUE) {
        printf("COMポートオープン失敗\n");
        return false;
    }

    DCB dcb = {0};
    dcb.DCBlength = sizeof(DCB);
    GetCommState(hCom, &dcb);

    dcb.BaudRate = CBR_9600;
    dcb.ByteSize = 8;
    dcb.Parity   = NOPARITY;
    dcb.StopBits = ONESTOPBIT;

    SetCommState(hCom, &dcb);

    COMMTIMEOUTS to = {0};
    to.ReadIntervalTimeout         = 1;
    to.ReadTotalTimeoutMultiplier  = 1;
    to.ReadTotalTimeoutConstant    = 1;
    SetCommTimeouts(hCom, &to);

    return true;
}

 

// 1バイト送信(SioSend 相当)

void SioSend(unsigned char c)
{
    DWORD written;
    WriteFile(hCom, &c, 1, &written, nullptr);
}

 

// 1バイト受信(SioRecieve 相当)

int SioReceive()
{
    unsigned char c;
    DWORD read;

    if (ReadFile(hCom, &c, 1, &read, nullptr) && read == 1) {
        return c;
    }
    return 0; // 受信なし
}

RS-232C送受信(1/3)

これは MS-DOS時代のBIOS/独自ドライバ前提のRS-232C制御なので、
Windows 10 では Win32 API(CreateFile / ReadFile / WriteFile)で置き換えるのが正解です。

以下では方針 → 最小構成の通信ラッパ → TxCommand / RxCommand の移植例、という順で説明します。
通信プロトコルのロジックは極力そのままにしています)


全体方針(重要)

  • SioSend()WriteFile

  • SioRecieve()ReadFile(1バイト)

  • COM1"\\\\.\\COM1"Windows表記)

  • タイムアウトCOMMTIMEOUTS + clock()

  • コンソールアプリでOK(MFC不要)


制御文字(明示しておく)

 
#define ENQ 0x05 #define ACK 0x06 #define NAK 0x15 #define STX 0x02 #define ETX 0x03 #define EOT 0x04

1️⃣ RS-232C 基本ラッパ(Windows10用)

シリアルポートオープン

 
#include <windows.h> #include <stdio.h> #include <time.h> HANDLE hCom; bool OpenComPort(const char* portName) { hCom = CreateFileA( portName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr ); if (hCom == INVALID_HANDLE_VALUE) { printf("COMポートオープン失敗\n"); return false; } DCB dcb = {0}; dcb.DCBlength = sizeof(DCB); GetCommState(hCom, &dcb); dcb.BaudRate = CBR_9600; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; SetCommState(hCom, &dcb); COMMTIMEOUTS to = {0}; to.ReadIntervalTimeout = 1; to.ReadTotalTimeoutMultiplier = 1; to.ReadTotalTimeoutConstant = 1; SetCommTimeouts(hCom, &to); return true; }

1バイト送信(SioSend 相当)

 
void SioSend(unsigned char c) { DWORD written; WriteFile(hCom, &c, 1, &written, nullptr); }

1バイト受信(SioRecieve 相当)

 
int SioReceive() { unsigned char c; DWORD read; if (ReadFile(hCom, &c, 1, &read, nullptr) && read == 1) { return c; } return 0; // 受信なし }

2️⃣ TxCommand(Windows版)

 
int TxCommand(const char *str) { int f = 0, state = 0, retry = 0; int c, n, lrc; clock_t t; t = clock(); while (f == 0) { switch (state) { case 0: // ENQ送信 if (retry < 2) { retry++; SioSend(ENQ); t = clock(); state = 1; } else { f = 2; } break; case 1: // ACK/NAK待ち while ((c = SioReceive()) == 0) { if (t + 1000 < clock()) { state = 0; break; } } if (c == ACK) { retry = 0; state = 2; } else if (c == NAK) { state = 0; } break; case 2: // データ送信 if (retry < 2) { retry++; SioSend(STX); lrc = 0; for (n = 0; str[n]; n++) { lrc ^= str[n]; SioSend(str[n]); } SioSend(IntToHex(lrc >> 4)); SioSend(IntToHex(lrc & 0x0F)); SioSend(ETX); t = clock(); state = 3; } else { f = 3; } break; case 3: // ACK/NAK待ち while ((c = SioReceive()) == 0) { if (t + 2000 < clock()) { state = 2; break; } } if (c == ACK) { state = 4; } else if (c == NAK) { state = 2; } break; case 4: SioSend(EOT); f = 1; break; } } return f - 1; }

3️⃣ RxCommand(Windows版)

 
int RxCommand(char *str) { int state = 0, c, f = 0, cnt = 0; unsigned int lrc, lrc0; clock_t t = clock(); while (f == 0) { switch (state) { case 0: while ((c = SioReceive()) == 0) { if (t + 5000 < clock()) { f = 2; break; } } if (c == ENQ) state = 1; break; case 1: SioSend(ACK); t = clock(); state = 2; break; case 2: while ((c = SioReceive()) == 0) { if (t + 1000 < clock()) { state = 0; break; } } if (c == STX) { cnt = 0; t = clock(); state = 3; } break; case 3: while ((c = SioReceive()) == 0) { if (t + 1000 < clock()) { state = 0; break; } } if (c == ETX) { state = 4; } else { str[cnt++] = c; } break; case 4: str[cnt] = '\0'; lrc0 = (HexToInt(str[cnt-2]) << 4) | HexToInt(str[cnt-1]); str[cnt-2] = '\0'; lrc = 0; for (int i = 0; str[i]; i++) lrc ^= str[i]; if (lrc != lrc0) { SioSend(NAK); } else { SioSend(ACK); } state = 5; t = clock(); break; case 5: while ((c = SioReceive()) == 0) { if (t + 1000 < clock()) { f = 3; break; } } if (c == EOT) f = 1; break; } } return f - 1; }

4️⃣ main例

 
int main() { if (!OpenComPort("\\\\.\\COM1")) return 1; char buf[256]; TxCommand("HELLO"); RxCommand(buf); printf("RX:%s\n", buf); CloseHandle(hCom); }

補足(重要)

C++プリンタ

Windows 10 + OKI(USB) なら、一番安全で確実な方法はこれ一択です。


結論(最短ルート)

👉 「Generic / Text Only」プリンタを追加して、そこに生データ(ESC制御)を流す

これで

 
fprintf(lpt, "\x1b@"); fprintf(lpt, "\f");

のような プリンタ制御コードがそのまま有効になります。

 

手順①:Generic / Text Only プリンタを追加

1️⃣ プリンタ追加

  1. 設定

  2. バイス

  3. プリンターとスキャナー

  4. プリンターまたはスキャナーを追加

※ 一覧に出てこなければ
👉 「プリンターが一覧にない場合」


2️⃣ 手動で追加

  • ローカルプリンターまたはネットワークプリンターを手動設定で追加

  • 既存のポートを使用

    • USB001(仮想プリンタポート)


3️⃣ ドライバー選択

  • メーカー:Generic

  • プリンタ:Generic / Text Only

名前例:

 
OKI_TEXT

手順②:Windows側の重要設定(必須)

プリンタのプロパティ

  1. バイスとプリンター

  2. OKI_TEXT を右クリック → プリンターのプロパティ

📌 詳細設定タブ

  • 印刷プロセッサWinPrint

  • 既定のデータの種類RAW

👉 これが超重要(ESCコードを壊さない)


手順③:印刷方法

方法A:ファイル経由(おすすめ)

あなたの既存コードを 一切変更しない方法です。

 
FILE *lpt = fopen("lp.txt", "w"); fprintf(lpt, "\x1b@"); fprintf(lpt, "TEST PRINT\r\n"); fprintf(lpt, "\f"); fclose(lpt);

印刷コマンド

 
copy /b lp.txt "\\localhost\OKI_TEXT"

/b を必ず付ける(制御コード保護)


方法B:アプリから直接送る(少し上級)

 
FILE *lpt = fopen("\\\\localhost\\OKI_TEXT", "w");

※ 権限や環境依存が強い
👉 方法Aの方が安定


OKIプリンタでの注意点(重要)

  • OKIは ESC/P互換モード または テキストモード が必要な場合あり

  • 機種によっては

    • ページ記述言語:ESC/P

    • Emulation:EPSON
      を設定する

👉 プリンタ本体メニューで確認


動作確認用ミニテスト

 
fprintf(lpt, "\x1b@"); // 初期化 fprintf(lpt, "OKI TEST\r\n"); fprintf(lpt, "1234567890\r\n"); fprintf(lpt, "\f"); // 改ページ
  • 正常 → 印字されて紙が送られる

  • 文字化け → エミュレーション設定不一致


まとめ(迷ったらこれ)

項目 設定
OS Windows 10
プリンタ OKI USB
ドライバ Generic / Text Only
印刷方法 copy /b
データ形式 RAW
制御コード ESC/P 有効

ここまでやって 印字されない/制御が効かない場合は、

  • OKIの 正確な型番

  • 今出している 制御コード一覧

を出してください。
機種別に ESC/P → OKI 向けに最適化します。