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());
            }
        }
    }
}

2015/03/02

64bit対応のCygwinセットアップとTeratermの設定

32bit版の時とほぼ同じなので詳細は割愛する。

■Cygwinのダウンロード

  次のリンクから64bit対応のCygwin(setup-x86_64.exe)をダウンロードする。
  https://cygwin.com/

■Cygwinのセットアップ

ダウンロードした setup-x86_64.exe を任意の所で実行する。
・・・ほとんどデフォルトのままでセットアップできる。

・セットアップ・ディレクトリは次になっている。(32bit版は \cygwin)
  Root Directory : \cygwin64

・ダウンロード・サイト
  どこからでもOKなのだが、一応 jp サイトが無難と思われる。
  ここでは、次の山形大学からダウンロードした。
  http://ftp.yz.yamagata-u.ac.jp

・セットアップするパッケージを選択する。
  baseは必須で、後は必要なものを Install 選択する。

■環境変数の設定

  Path変数に以下を追加する。
  c:\cygwin64\bin

  ※Cygwinが32bit版の場合は、cygwin64をcygwinにする。

■TeraTerm(cygterm)インストール&設定

Teratermに付属の cygterm を使用する場合、64bit版を使う。
64bit版は、cygterm+-x86_64 フォルダーに入っているので、デフォルトの cygterm.exe と cyglaunch.exe を差し替える。

以上で cygterm からCygwinを起動できるハズだが、man コマンドがエラーとなる場合、cygterm.cfg ファイルの設定を確認修正すること。

# CygTerm setting

TERM = ttermpro.exe %s %d /E /KR=UTF8 /KT=UTF8 /VTICON=CygTerm /nossh
# SJIS for Cygwin 1.5
# TERM = ttermpro.exe %s %d /E /KR=SJIS /KT=SJIS /VTICON=CygTerm /nossh
TERM_TYPE = vt100
PORT_START = 20000
PORT_RANGE = 40
SHELL = auto
ENV_1 = MAKE_MODE=unix
ENV_2 = HOME=/home/ski
ENV_3 = LANG=
ENV_4 = TERM=xterm   ⇒ この行を追加する
LOGIN_SHELL = yes
# HOME_CHDIR = No
SSH_AGENT_PROXY = no

2012/05/23

Perl - 全角カナ⇔半角カナ 変換のサンプル

テストデータは、プログラムの後につけているので kana.txt ファイルとして利用できる。

#------------------------------------------------
# 全角カナ⇔半角カナ 変換のサンプル
#------------------------------------------------

use strict;          # 不適切な構文の使用を制限するプラグマ
use warnings;        # 不適切な構文を警告するプラグマ

use Encode;
use Encode::JP::H2Z;

require("lib_file.pl");  # ライブラリファイル取り込み

#------------------------
# サブルーチン宣言
#------------------------
sub test_kana();
sub kana_z2h($);
sub kana_h2z($);

# 全角カナ⇔半角カナのテストサンプル実行
test_kana();

#-----------------------------
# 全角カナ⇔半角カナのテストサンプル
#-----------------------------
sub test_kana()
{
    my $in_file;
    my $out_z2h;
    my $out_h2z;
    my $in_fh;
    my $z2h_fh;
    my $h2z_fh;
    my $read_data;
    my $kana_data;

    $in_file = 'kana.txt';         # 全半角カナ混在テキスト
    $out_z2h = 'kana_z2h.txt';     # 半角カナ変換後出力ファイル
    $out_h2z = 'kana_h2z.txt';     # 全角カナ変換後出力ファイル

    # 全半角カナ混在テキストオープン
    if( !open($in_fh, '<', $in_file))
    {
        logout("perl_log", qq/Can't open file "$in_file": $!/);
        exit(-1);
    }

    # 半角カナ変換後出力ファイルオープン
    if( !open($z2h_fh, '>', $out_z2h))
    {
        logout("perl_log", qq/Can't open file "$out_z2h": $!/);
        exit(-1);
    }

    # 全角カナ変換後出力ファイルオープン
    if( !open($h2z_fh, '>', $out_h2z))
    {
        logout("perl_log", qq/Can't open file "$out_h2z": $!/);
        exit(-1);
    }

    # 全半角カナ混在テキストを読出し半角/全角カナ変換後
    # 出力ファイルを作成する
    while( $read_data = <$in_fh> )
    {
        chomp($read_data);             # 末尾の改行削除

        # 全角カナ → 半角カナ変換
        $kana_data = kana_z2h($read_data);

        # 半角カナ変換後出力ファイルへ出力
        print($z2h_fh $kana_data, "\n");

        # 半角カナ → 全角カナ変換
        $kana_data = kana_h2z($read_data);

        # 全角カナ変換後出力ファイルへ出力
        print($h2z_fh $kana_data, "\n");
    }

    # オープンしたファイルをクローズ
    close($in_fh);
    close($z2h_fh);
    close($h2z_fh);
}

#------------------------------------------------
# 全角カナ → 半角カナ変換
#------------------------------------------------
sub kana_z2h($)
{
    my $str;

    $str = shift;

    Encode::from_to($str, "utf8", "euc-jp");
    Encode::JP::H2Z::z2h(\$str);
    Encode::from_to($str, "euc-jp", "utf8");

    return($str);
}

#------------------------------------------------
# 半角カナ → 全角カナ変換
#------------------------------------------------
sub kana_h2z($)
{
    my $str;

    $str = shift;

    Encode::from_to($str, "utf8", "euc-jp");
    Encode::JP::H2Z::h2z(\$str);
    Encode::from_to($str, "euc-jp", "utf8");

    return($str);
}

#------------------------------------------------
# END
#------------------------------------------------

#------------------------------------------------
# 全角カナ⇔半角カナ TEST DATA

#------------------------------------------------

■全角カナ一覧
ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾ
タダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポ
マミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶ

■半角カナ一覧
アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲンァィゥェォャュョッー゙゚。「」、・

●半角英数/記号
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]
^_`abcdefghijklmnopqrstuvwxyz{|}~

●全角ひらがな
ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞ
ただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽ
まみむめもゃやゅゆょよらりるれろゎわゐゑをん

●全角英数
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789

#------------------------------------------------
# TEST DATA END
#------------------------------------------------

«Perl - base64形式(エンコード/デコード)のサンプル