VC++

2016/11/24

Stringのマネージ ⇒ アンマネージ変換ってこんな感じ

private: System::Void MarshalStringConvert(String^ iStr, std::string& ostr) {
    // マネージ String ⇒ アンマネージ ANSI(char)変換
    using namespace Runtime::InteropServices;
    const char* chars = (const char*)(Marshal::StringToHGlobalAnsi(iStr)).ToPointer();
    ostr = chars;
    Marshal::FreeHGlobal(IntPtr((void*)chars));
}

private: System::Void MarshalStringConvert(String^ iStr, std::wstring& owstr) {
    // マネージ String ⇒ アンマネージ UniCode(wchar)変換
    using namespace Runtime::InteropServices;
    const wchar_t* wchars = (const wchar_t*)(Marshal::StringToHGlobalUni(iStr)).ToPointer();
    owstr = wchars;
    Marshal::FreeHGlobal(IntPtr((void*)wchars));
}

■INIファイルへの保存/取得に使ってみる

    const wchar_t *wcSec;           // セクション
    const wchar_t *wcKey;           // キー
    const wchar_t *wcFile;         // INIファイル名
    wchar_t       wc[70];            // INIファイル読み出し域
    String^       stW;                // 書き込み用
    String^       stR;                // 読み出し結果

    std::wstring    wsStr;             // INIファイル書き込みデータ
    wcSec = L"SECTION2";
    wcKey = L"KEY2";
    wcFile = L"./ski.ini";

    wsStr.clear();                                 // 書き込みデータ初期化
    stW = "INIファイル書込み";               // 書き込みデータ設定

    MarshalStringConvert(stW, wsStr);            // String to wstring変換

    // INIファイルへ出力

    WritePrivateProfileString(wcSec, wcKey, wsStr.c_str(), wcFile);

    // INIファイルから読出し

    GetPrivateProfileString(wcSec, wcKey, L"", wc, sizeof(wc), wcFile);
    stR = gcnew String(wc);

■結果

[SECTION2]
KEY2=INIファイル書き込み

2016/11/21

C++ でシリアル通信クラスを書いてみた

■ヘッダーファイル
#include <Windows.h>
#include  "Winbase.h"

#pragma once

unsigned __stdcall ThreadFunc(void *p);

class CSerial
{
public:
    CSerial(void);
    ~CSerial(void);

    // 指定ポートをオープンし受信開始
    void Start(LPCSTR comPortName, DCB* portConfig);
    // COMポートを閉じ処理終了
    void End(void);

    DWORD RecvData(void);

    // 受信済みのデータを buffer に格納し buffer に格納したデータのバイト数を返す
    DWORD GetRecvData(LPVOID buffer);

    // buffer に格納されたデータを length バイト送信する
    DWORD SendData(LPVOID buffer, int toWriteBytes);

private:
    HANDLE mHComPort;           // COM ポート用ハンドル
    HANDLE mThreadId;           // スレッド ID
    HANDLE mMutex;              // mRecvDataBuff,mRecvDataBuffLen を排他するためのMutex
    BYTE* mRecvDataBuff;        // 受信用内部データバッファ
    DWORD mRecvDataBuffLen;     // mRecvDataBuff に格納されている受信データのバイト数
};

■ソースファイル
#include "CSerial.h"
#include <process.h>

unsigned __stdcall ThreadFunc(void *p)
{
    CSerial *pp = (CSerial*)p;

    return pp->RecvData();
}

CSerial::CSerial(void)
    : mHComPort(NULL), mRecvDataBuff(NULL), mRecvDataBuffLen(0)
{
    mMutex = CreateMutex(NULL, TRUE, NULL);
}

CSerial::~CSerial(void)
{
    CloseHandle(mMutex);
    if(mRecvDataBuff != NULL) {
        delete mRecvDataBuff;
        mRecvDataBuff = NULL;
    }
    mMutex = NULL;
}

void CSerial::Start(LPCSTR comPortName, DCB* portConfig)
{
    bool    nBret;

    // 指定ポートを開く
    mHComPort = CreateFile(
        (LPCTSTR)comPortName,
        GENERIC_READ | GENERIC_WRITE,               // 読み書きを指定
        0,
        NULL,
        OPEN_EXISTING,
        0,
        NULL);

    if(mHComPort != INVALID_HANDLE_VALUE)
    {
        // ポートのボーレート、パリティ等を設定
        nBret = SetCommState(mHComPort, portConfig);
    }

    if(nBret != FALSE )
    {
        mThreadId = (HANDLE)_beginthreadex(
            NULL,
            0,
            ThreadFunc,
            this,
            0,
            NULL);
    }
}

void CSerial::End()
{
    if (mHComPort != NULL)
    {
        CloseHandle(mHComPort);
    }
}

DWORD CSerial::RecvData(void)
{
    BYTE buffer[1024];
    DWORD toReadBytes = 1024;
    DWORD readBytes;

    while(ReadFile(mHComPort, buffer, toReadBytes, &readBytes, NULL))
    {
        if(readBytes > 0)
        {
            WaitForSingleObject(mMutex, 0);

            // 受信したデータは、mRecvDataBuff に受信済みで取り出されていない
            // データに続けて保持しておく
            BYTE* tmpBuf = new BYTE[mRecvDataBuffLen + readBytes];
            if(mRecvDataBuff != NULL)
            {
                memcpy(tmpBuf, mRecvDataBuff, mRecvDataBuffLen);
                delete [] mRecvDataBuff;
            }
            memcpy(tmpBuf, buffer, readBytes);
            mRecvDataBuffLen += readBytes;
            mRecvDataBuff = tmpBuf;

            ReleaseMutex(mMutex);
        }
    }

    return S_OK;
}

DWORD CSerial::GetRecvData(LPVOID buffer)
{
    DWORD length;

    WaitForSingleObject(mMutex, 0);

    buffer = new BYTE[mRecvDataBuffLen];
    memcpy(buffer, mRecvDataBuff, mRecvDataBuffLen);
    length = this->mRecvDataBuffLen;

    ReleaseMutex(mMutex);

    return length;
}

DWORD CSerial::SendData(LPVOID buffer, int toWriteBytes)
{
    DWORD writeBytes;
    DWORD index = 0;

    // 指定されたデータを全て書き込む為にループを廻す
    while (toWriteBytes > 0)
    {
        WriteFile(
            mHComPort,
            ((BYTE*)buffer) + index,
            toWriteBytes,
            &writeBytes,
            NULL);
        index += writeBytes;
        toWriteBytes -= writeBytes;
    }

    return writeBytes;
}

マネージコードで、propertyキーワードでgetter/setterを書く

#include <msclr/marshal_cppstd.h>

namespace Test_Project_001 {

    using namespace System;
    ....
    ....
    using namespace msclr::interop;

    /// <summary>
    /// MyForm の概要
    /// </summary>
    public ref class MyForm : public System::Windows::Forms::Form
    {
        // マネージコードでは、propertyキーワードでgetter/setterを書く
        property String^ mGetDate
        {
            String^ get(void)
            {
                // Cのchar* => C#のString
                return marshal_as<System::String^>(pCTime->m_GetDate);
//              return gcnew String(pCTime->m_GetDate);
            }
            void set(String^ value)
            {
                // C#のString => C++のstring, Cのchar*
                std::string s_cpp = marshal_as<std::string>(value);
                strcpy(pCTime->abc, s_cpp.c_str());
            }
        }
    }
}

その他のカテゴリー