C++ RS-232C通信制御プログラム(パート2)

<RS232C.cpp>

#include <iostream>
#include "SerialPort.h" // シリアルポートクラスのヘッダーファイルをインクルード
int main() {
    // シリアルポート設定(ポート、データビット長、パリティチェック、ストップビッチ長)
    SerialPort serial(TEXT("COM1"), CBR_9600, 8, EVENPARITY, ONESTOPBIT);
    // シリアルポートが正常に開かれたか確認
    if (!serial.isConnected()) {
        //std::cerr <<  << std::endl;
        printf("Cannot Initialize SIO port [%s].\n","COM1");
        return 1;
    }
    // メッセージの送信
    std::string message = "Hello, Serial Port!";
    serial.TxCommand(message.c_str(), message.size());
    // データの受信
    char incomingData[256] = { 0 };
    serial.RxCommand(incomingData, sizeof(incomingData));
    // 受信したデータを表示
    std::cout << "Received data: " << incomingData << std::endl;
    return 0;
}

<COM.cpp>

#include "SerialPort.h"
#include <iostream>
#include <windows.h>
// シリアルポートのオープン
SerialPort::SerialPort(const TCHAR* portName, DWORD baudRate, BYTE byteSize, BYTE parity, BYTE stopBits) {
    hSerial = CreateFile(
        portName,
        GENERIC_READ | GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        0,
        NULL
    );
    // シリアルポートの設定
    if (hSerial != INVALID_HANDLE_VALUE) {
        DCB dcbSerialParams = { 0 };
        dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
        GetCommState(hSerial, &dcbSerialParams);
        dcbSerialParams.BaudRate = baudRate;
        dcbSerialParams.ByteSize = byteSize;
        dcbSerialParams.Parity = parity;
        dcbSerialParams.StopBits = stopBits;
        SetCommState(hSerial, &dcbSerialParams);
        connected = true;
    }
    else {
        std::cerr << "Error: Unable to open COM port." << std::endl;
        connected = false;
    }
}
SerialPort::~SerialPort() {
    if (hSerial != INVALID_HANDLE_VALUE) {
        CloseHandle(hSerial);
    }
}
bool SerialPort::TxCommand(const char* buffer, unsigned int bufferSize) {
    DWORD bytesWritten;
    if (!WriteFile(hSerial, (void*)buffer, bufferSize, &bytesWritten, NULL)) {
        std::cerr << "Error: Unable to write to COM port." << std::endl;
        return false;
    }
    return true;
}
bool SerialPort::RxCommand(char* buffer, unsigned int bufferSize) {
    DWORD bytesRead;
    if (!ReadFile(hSerial, buffer, bufferSize, &bytesRead, NULL)) {
        std::cerr << "Error: Unable to read from COM port." << std::endl;
        return false;
    }
    return true;
}
bool SerialPort::isConnected() {
    return connected;
}

<SerialPort.h>

#include <Windows.h>
class SerialPort {
public:
    // コンストラク
    SerialPort(const TCHAR* portName, DWORD baudRate, BYTE byteSize, BYTE parity, BYTE stopBits);
    // デストラク
    ~SerialPort();
    // データ送信
    bool TxCommand(const char* buffer, unsigned int bufferSize);
    // データ受信
    bool RxCommand(char* buffer, unsigned int bufferSize);
    // 接続確認
    bool isConnected();
private:
    HANDLE hSerial;
    bool connected;
};

C++ dos_getftime(),fread()に関して

#include <iostream>
#include <Windows.h>
#include <ctime>
//fopen関数を使用できるためのおまじない
#pragma warning(disable: 4996)
#define NUM_ALPHA  256
int main() {
    FILE *fp;
    char buffer[NUM_ALPHA + 1];
    int num;
    const int BUFFER_SIZE = 100;
    // File path
    const char* filePath = "C:\\Users\\sannp\\Desktop\\SAMC1\\free\\file.txt";
    if *1 != NULL) {
        num = fread(buffer, sizeof(char), 1, fp);
        std::cout << num << std::endl;
    }

    FILETIME ftLastWrite;
    SYSTEMTIME stUTC, stLocal;
    // ファイルの最終更新日時を取得
    HANDLE hFile = CreateFileA(
        filePath,
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL
    );
    if (hFile != INVALID_HANDLE_VALUE) {
        if (GetFileTime(hFile, NULL, NULL, &ftLastWrite)) {
            // ファイルタイムをUTCからローカル時刻に変換
            FileTimeToSystemTime(&ftLastWrite, &stUTC);
            SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
            // ファイルの最終更新日時を表示
            std::cout << "ファイルの最終更新日時: "
                << stLocal.wYear << "/" << stLocal.wMonth << "/" << stLocal.wDay << " "
                << stLocal.wHour << ":" << stLocal.wMinute << ":" << stLocal.wSecond << std::endl;
        }
        else {
            std::cerr << "ファイルの最終更新日時の取得に失敗しました。エラーコード: " << GetLastError() << std::endl;
        }
        CloseHandle(hFile);
    }
    else {
        std::cerr << "ファイルを開くことができませんでした。エラーコード: " << GetLastError() << std::endl;
    }
 
    return 0;
}

*1:fp = fopen(filePath, "rb"

C++

古い_dos_getftime()関数は、DOS時代のファイルの最終更新日時を取得する関数でしたが、Windowsでその代替となる関数は標準的なC++Windows APIには存在しません。代わりに、Windowsでファイルの属性を取得するには、Windows APIGetFileAttributes() 関数や GetFileTime() 関数を使用します。以下はその例です。

#include <iostream>
#include <windows.h>
int main() {
    const char* filePath = "example.txt"; // ファイルのパスを設定
    // ファイルの属性を取得
    WIN32_FILE_ATTRIBUTE_DATA fileInfo;
    if (!GetFileAttributesEx(filePath, GetFileExInfoStandard, &fileInfo)) {
        std::cerr << "Failed to get file attributes." << std::endl;
        return 1;
    }
    // ファイルの最終更新日時を取得
    FILETIME lastWriteTime = fileInfo.ftLastWriteTime;
    // FILETIMEをSYSTEMTIMEに変換
    SYSTEMTIME systemTime;
    if (!FileTimeToSystemTime(&lastWriteTime, &systemTime)) {
        std::cerr << "Failed to convert file time to system time." << std::endl;
        return 1;
    }
    // 最終更新日時を表示
    std::cout << "Last modified time: ";
    std::cout << systemTime.wYear << "-" << systemTime.wMonth << "-" << systemTime.wDay;
    std::cout << " " << systemTime.wHour << ":" << systemTime.wMinute << ":" << systemTime.wSecond << std::endl;
    return 0;
}

このコードでは、GetFileAttributesEx() 関数を使用してファイルの属性を取得し、ftLastWriteTime メンバーから最終更新日時を取得します。そして、FileTimeToSystemTime() 関数を使用して、ファイルの最終更新日時をSYSTEMTIME構造体に変換して表示しています。

C++API

12個のボタンを描画して、1個目のボタンを押すと「Hallo!」のメッセージが表示される

#include <Windows.h>
#include <vector>

// グローバル変数
std::vector<HWND> g_buttons; // ボタンウィンドウのハンドルを格納するベクター

// ボタンクリック時の処理
void OnButtonClick(int index) {
    MessageBox(NULL, TEXT("Hallo!"), TEXT("Message"), MB_OK | MB_ICONINFORMATION);
}

// ウィンドウプロシージャ
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case WM_CLOSE:
            PostQuitMessage(0);
            break;

        case WM_COMMAND:
            for (size_t i = 0; i < g_buttons.size(); ++i) {
                if *1 {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

****************************

直線を描画(\斜め線)

#include <Windows.h>

// ウィンドウプロシージャ
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case WM_CLOSE:
            PostQuitMessage(0);
            break;

        case WM_PAINT:
            {
                PAINTSTRUCT ps;
                HDC hdc = BeginPaint(hwnd, &ps);

                // 直線を描画
                MoveToEx(hdc, 50, 50, NULL); // 始点の設定
                LineTo(hdc, 200, 200); // 終点の設定

                EndPaint(hwnd, &ps);
            }
            break;

        default:
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

// エントリーポイント
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    // ウィンドウクラスの定義
    WNDCLASS wc = {};
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = TEXT("WindowClass");

    // ウィンドウクラスの登録
    RegisterClass(&wc);

    // ウィンドウの作成
    HWND hwnd = CreateWindowEx(
        0,
        TEXT("WindowClass"),
        TEXT("Line Window"),
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 400, 300,
        NULL,
        NULL,
        hInstance,
        NULL
    );

    // ウィンドウ表示
    ShowWindow(hwnd, nCmdShow);

    // メッセージループ
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

****************************

以下は、Visual C++のWindowsAPIを使用して、黒い背景のウィンドウを作成し、青色のテキストで「Hallo!」を表示するプログラムの例です。

#include <Windows.h>

// ウィンドウプロシージャ
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case WM_CLOSE:
            PostQuitMessage(0);
            break;

        case WM_PAINT:
            {
                PAINTSTRUCT ps;
                HDC hdc = BeginPaint(hwnd, &ps);

                // 文字列を描画
                SetTextColor(hdc, RGB(0, 0, 255)); // 色を青色に設定
                SetBkColor(hdc, RGB(0, 0, 0)); // 背景色を黒に設定
                TextOut(hdc, 20, 20, TEXT("Hallo!"), 6);

                EndPaint(hwnd, &ps);
            }
            break;

        default:
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

// エントリーポイント
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    // ウィンドウクラスの定義
    WNDCLASS wc = {};
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = TEXT("WindowClass");

    // ウィンドウクラスの登録
    RegisterClass(&wc);

    // ウィンドウの作成
    HWND hwnd = CreateWindowEx(
        0,
        TEXT("WindowClass"),
        TEXT("Text Window"),
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 400, 300,
        NULL,
        NULL,
        hInstance,
        NULL
    );

    // ウィンドウ表示
    ShowWindow(hwnd, nCmdShow);

    // メッセージループ
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

****************************

黒い背景のウィンドウを作成するプログラム

#include <Windows.h>

// ウィンドウプロシージャ
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case WM_CLOSE:
            PostQuitMessage(0);
            break;

        default:
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

// エントリーポイント
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    // ウィンドウクラスの定義
    WNDCLASS wc = {};
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = TEXT("WindowClass");
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); // 背景色を黒に設定

    // ウィンドウクラスの登録
    RegisterClass(&wc);

    // ウィンドウの作成
    HWND hwnd = CreateWindowEx(
        0,
        TEXT("WindowClass"),
        TEXT("Black Window"),
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 400, 300,
        NULL,
        NULL,
        hInstance,
        NULL
    );

    // ウィンドウ表示
    ShowWindow(hwnd, nCmdShow);

    // メッセージループ
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

*1:HWND)lParam == g_buttons[i]) {
                    OnButtonClick(i);
                    break;
                }
            }
            break;

        default:
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

// エントリーポイント
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    // ウィンドウクラスの定義
    WNDCLASS wc = {};
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = TEXT("WindowClass");

    // ウィンドウクラスの登録
    RegisterClass(&wc);

    // ウィンドウの作成
    HWND hwnd = CreateWindowEx(
        0,
        TEXT("WindowClass"),
        TEXT("Button Window"),
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 400, 300,
        NULL,
        NULL,
        hInstance,
        NULL
    );

    // ボタンの作成
    const int buttonWidth = 100;
    const int buttonHeight = 30;
    const int buttonSpacing = 10;
    const int buttonCount = 12;
    const int buttonStartX = (400 - (buttonWidth * buttonCount + buttonSpacing * (buttonCount - 1))) / 2;
    const int buttonY = 230;

    for (int i = 0; i < buttonCount; ++i) {
        HWND button = CreateWindow(
            TEXT("BUTTON"),
            TEXT("Button"),
            WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
            buttonStartX + (buttonWidth + buttonSpacing) * i, buttonY, buttonWidth, buttonHeight,
            hwnd,
            NULL,
            hInstance,
            NULL
        );
        g_buttons.push_back(button);
    }

    // ウィンドウ表示
    ShowWindow(hwnd, nCmdShow);

    // メッセージループ
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0

C++ signal関数

#include <iostream>
#include <csignal> // signal関数を含むヘッダ
// シグナルハンドラ関数
void signalHandler(int signal) {
    std::cout << "Interrupt signal (" << signal << ") received." << std::endl;
    // プログラムの終了
    exit(signal);
}
int main() {
    // SIGINTシグナル(Ctrl+C)のハンドラを設定
    signal(SIGINT, signalHandler);
    std::cout << "Waiting for Ctrl+C..." << std::endl;
    // 無限ループ
    while (true) {
        // 何かの処理
    }
    return 0;
}

このプログラムでは、Ctrl+C(SIGINT)シグナルをキャッチし、カスタムのシグナルハンドラ関数 signalHandler() が呼び出されます。その後、プログラムはシグナルハンドラ内で exit() 関数を使用して終了します。

このように、signal() 関数を使用してシグナルを処理することで、プログラムが外部からのシグナルに対して適切に反応できるようになります。

***************************************************

#include <iostream>
#include <windows.h>
// Ctrl+C シグナル(SIGINT)のハンドラ関数
BOOL WINAPI consoleCtrlHandler(DWORD ctrlType) {
    switch (ctrlType) {
        case CTRL_C_EVENT:
            std::cout << "Ctrl+C signal received." << std::endl;
            // ここで処理を行う
            return TRUE;
        case CTRL_BREAK_EVENT:
            std::cout << "Ctrl+Break signal received." << std::endl;
            // ここで処理を行う
            return TRUE;
        default:
            return FALSE;
    }
}
int main() {
    // Ctrl+C シグナル(SIGINT)と Ctrl+Break シグナルのハンドラを設定
    if (!SetConsoleCtrlHandler(consoleCtrlHandler, TRUE)) {
        std::cerr << "Error setting console control handler." << std::endl;
        return 1;
    }
    std::cout << "Waiting for Ctrl+C or Ctrl+Break..." << std::endl;
    // 無限ループ
    while (true) {
        // 何かの処理
    }
    return 0;
}

このプログラムでは、Windows上でCtrl+CとCtrl+Breakのシグナルを処理する方法を示しています。SetConsoleCtrlHandler() 関数を使用して、コンソールのCtrl+CとCtrl+Breakのシグナルを処理するためのハンドラ関数を登録します。その後、シグナルが発生すると、登録されたハンドラ関数が呼び出されます。

C++ RS-232C通信制御プログラム

指定されたシリアルポート(COM1)を開き、指定されたボーレート(9600bps)で通信を行います。指定されたデータを送信し、受信したデータを取得して表示します。必要に応じてポート名やボーレートを変更してください。
#include <iostream>
#include <Windows.h>
// シリアルポートを開く関数
HANDLE openSerialPort(const char* portName, DWORD baudRate) {
    HANDLE hSerial = CreateFile(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
    if (hSerial == INVALID_HANDLE_VALUE) {
        std::cerr << "Failed to open serial port." << std::endl;
        return NULL;
    }
    DCB dcbSerialParams = { 0 };
    dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
    if (!GetCommState(hSerial, &dcbSerialParams)) {
        std::cerr << "Failed to get serial port parameters." << std::endl;
        CloseHandle(hSerial);
        return NULL;
    }
    dcbSerialParams.BaudRate = baudRate;
    dcbSerialParams.ByteSize = 8;
    dcbSerialParams.StopBits = ONESTOPBIT;
    dcbSerialParams.Parity = NOPARITY;
    if (!SetCommState(hSerial, &dcbSerialParams)) {
        std::cerr << "Failed to set serial port parameters." << std::endl;
        CloseHandle(hSerial);
        return NULL;
    }
    COMMTIMEOUTS timeouts = { 0 };
    timeouts.ReadIntervalTimeout = 50;
    timeouts.ReadTotalTimeoutConstant = 50;
    timeouts.ReadTotalTimeoutMultiplier = 10;
    timeouts.WriteTotalTimeoutConstant = 50;
    timeouts.WriteTotalTimeoutMultiplier = 10;
    if (!SetCommTimeouts(hSerial, &timeouts)) {
        std::cerr << "Failed to set serial port timeouts." << std::endl;
        CloseHandle(hSerial);
        return NULL;
    }
    return hSerial;
}
// シリアルポートをクローズする関数
void closeSerialPort(HANDLE hSerial) {
    if (hSerial != INVALID_HANDLE_VALUE) {
        CloseHandle(hSerial);
    }
}
// データを送信する関数
bool sendData(HANDLE hSerial, const char* data, DWORD dataSize) {
    DWORD dwBytesWritten;
    if (!WriteFile(hSerial, data, dataSize, &dwBytesWritten, NULL)) {
        std::cerr << "Failed to write to serial port." << std::endl;
        return false;
    }
    return true;
}
// データを受信する関数
bool receiveData(HANDLE hSerial, char* buffer, DWORD bufferSize) {
    DWORD dwBytesRead;
    if (!ReadFile(hSerial, buffer, bufferSize, &dwBytesRead, NULL)) {
        std::cerr << "Failed to read from serial port." << std::endl;
        return false;
    }
    return true;
}
int main() {
    const char* portName = "COM1";
    const DWORD baudRate = CBR_9600;
    HANDLE hSerial = openSerialPort(portName, baudRate);
    if (hSerial == NULL) {
        std::cerr << "Failed to open serial port." << std::endl;
        return 1;
    }
    const char* sendDataStr = "Hello, RS-232C!";
    if (sendData(hSerial, sendDataStr, strlen(sendDataStr))) {
        std::cout << "Data sent: " << sendDataStr << std::endl;
    }
    char receiveBuffer[256];
    if (receiveData(hSerial, receiveBuffer, sizeof(receiveBuffer))) {
        std::cout << "Data received: " << receiveBuffer << std::endl;
    }
    closeSerialPort(hSerial);
    return 0;
}

日時、日時取得

Visual C++ (VC++) で日付と日時を取得するためには、Windows API の GetSystemTime() 関数を使用します。以下は、この関数を使用して現在の日付と日時を取得するプログラムの例です。

#include <iostream>
#include <Windows.h>

int main() {
    SYSTEMTIME systemTime;

    // 現在のシステム日時を取得
    GetSystemTime(&systemTime);

    // 取得した日時を表示
    std::cout << "Year: " << systemTime.wYear << std::endl;
    std::cout << "Month: " << systemTime.wMonth << std::endl;
    std::cout << "Day: " << systemTime.wDay << std::endl;
    std::cout << "Hour: " << systemTime.wHour << std::endl;
    std::cout << "Minute: " << systemTime.wMinute << std::endl;
    std::cout << "Second: " << systemTime.wSecond << std::endl;

    return 0;
}