PG日誌

読者です 読者をやめる 読者になる 読者になる

PG日誌

主にc#の事を書いています

C#とC++間でchar*もしくはLPSZをやり取りする

f:id:Takachan:20170115150341j:plain

C#からC++のDLLを呼び出すためにDllImportしたときにchar*が引数にある場合のやり取りの仕方です。

C++側はシグネチャを持つコードがあった場合

// C++側宣言
uint32_t __stdcall Function(char* szMessage);

// もしくは
uint32_t __stdcall Function(LPSTR szMessage);

C#側の相互運用時の呼び出し方法は以下の通りです。

// szMessage が[IN]だけの場合
[DllImport("Hoge.dll", EntryPoint="Function", /* CharSet = CharSet.Ansi */)]
public static extern int Function(string szMessage);

// szMessage が[OUT]の場合
[DllImport("Hoge.dll", EntryPoint="Function", /* CharSet = CharSet.Ansi */)]
public static extern int Function([MarshalAs(UnmanagedType.LPStr]StringBuilder szMessage);

[IN]の場合、特に気にせずstringで渡してしまえば問題ないです。もし渡した先でszMessageが書き換えられた場合、C#側でAccessViolationExceptionが発生します。

[OUT]の場合(C++で*charが書き換わる場合)、呼び出し側で以下のように記述する必要があります。

public int MyFunction(ref string message)
{
    StringBuilder szMessage = new StringBuilder(256);

    int iRet = Function(szMessage);

    message = szMessage.ToString();
    return iRet;
}

StringBuilderは必ずキャパシティを指定します。値を指定しなかったり、C++側でバッファを超えるとAccessViolationExceptionが発生します。

Qtuoの激安ワイヤレスマウスのレビュー

このマウス、去年の4月頃に買って年末まで7か月使ってたのですが結局捨ててしまいました。そこで供養的な意味でレビューを書きたいと思います。

ちなみに商品はこれです。

スペック、使用感

現物がもう無いのでカタログスペックからひっぱて来ました。

サイズ : 10.4x7.1x3.9cm 重さ : 100g

使用感ですがかなり小さく軽いです。なので、かぶせ持ちタイプの人には物足りないかと思います。モバイルで指先で使うのが正しい使い方なのかなと。

また、5段階にDPIが中央のボタンから変更可能です。800→1200→1600→2000→2400→800のように変更できボタンのランプ点灯回数で何段目か判断できます。

値段

3,888円が75%OFFで959円ですが、発売以来、常に75%OFFなので「景品表示法の二重価格表」のような状態になっています。75%OFFではなく959円が本当の価格ですね。

良い点

  • とにかく値段が安い
    • 1000以下の小型無線マウスはなかなか無いと思います。
  • 小さくて軽く普通の形
    • つまみもち、つかみもちでもそれほど違和感が無いです。
  • DPI切り替えい安濃

悪い点

  • レシーバーの感度が微妙
    • 50cm離れた時点でドラッグ動作が途切れます
  • 全体のつくりが安っぽい
    • 900円だからと言ったらそれまでですが多少ガタついています

当方環境だけかもしれませんが、電池を交換しようとし、裏蓋を数か月ぶりに空けたところ、電池の表面が解けてでろでろになっていました。ネバネバの液体が付着していて大変恐ろしい思いをしました。

また、このマウスの最悪な欠点ですが、動作精度が悪いことです。

1ドット単位で動かそうとして、微細にマウスを移動させてもポインタが反応せず、4ドット分くらい移動させると突然3~5ドット移動する動きになり、細かい動作が全く思うようにできません。しかもどのDPIモードでも同じ挙動をするため1ドット分移動は実質不可能かと思います。(イライラ爆発でした)

まとめ

結局、欠点が我慢できずに捨ててしまったのですが、このマウスを買いかどかはだいたいこんな感じかと思います。

こんな人におすすめ

  • コスパ重視の人
  • ネットサーフィンなどのライトな使い方の人
  • 軽くて小さいマウスを探している人
  • つまみ持ちの人

こんな人は買ってはダメ

  • 細かいマウス操作が必要な方
    • FPS(などのゲーム)で使う
    • クリエーターの人
    • プログラマー系IT作業をする人
      • これらに該当する人は買わないようにしましょう。
  • 長時間マウスを使用する予定のある人
    • 全ての動作で鈍い動作のため疲労感が強いです。
  • 神経質な人

万人にはおすすめできませんが、ライトユーザーで安い無線マウスを探している方にはおすすめかなと思います。

VisualStudio2013,2015に.NET4.6.2を導入する

f:id:Takachan:20170114224940j:plain

だいぶ前に、VisualStudio2013へ.NET4.6.1の導入の仕方を書きましたが、.NET4.6.2がリリースされたので導入の手順を書きたいと思います。



【旧記事】.NET4.6.1の導入の仕方

前に書いた記事です。

takachan.hatenablog.com


概要

.NET4.6.2が2016年8月にリリースされました。今は、.NET4.6でも.NET4.6.1ともにサポート期間内で特に問題ないみたいです。ただ、まぁ、、、いつも通りある程度時間がたつと、古いバージョンが徐々に切り捨てられていく事になると思われるため、新規に開発する際はより新しいバージョンを使用したほうがよいかと思います。


サポートライフサイクルについて

SIer脳では大変重要なサポート期間の確認です。

Microsoft .NET Framework サポート ライフサイクル ポリシー

Note:

2017年1月の時点で、.NET4.6, .NET4.6.1のサポートは継続中です。.NET4.6.2は記述見当たらないですね。


現在の状態

導入前に現在の状態を確認します。VSを立ち上げてソリューションもしくはプロジェクト作成画面で選択可能な.NETのバージョンを確認します。

f:id:Takachan:20170115162810p:plain

前回導入した4.6.1までしか表示されていません。


導入方法

MSのサイトから開発者キットをダウンロード

.NET Framework 4.6.2 Developer Pack リンク切れの場合「.NET Framework 4.6.2 Developer Pack」で検索お願いします。

そこから2つexeをダウンロードし実行します。 安全のためインストーラを起動する前にVisualStudioは閉じておきましょう。

f:id:Takachan:20170115164025p:plain

両方とも選択します。

f:id:Takachan:20170115164103p:plain

ダウンロードできたら、「NDP462-DevPack-KB3151934-ENU.exe」→「
NDP462-DevPack-KB3151934-JPN.exe」の順にインストールしていきます。


VisualStudioの再起動

VSが起動したらプロジェクト作成画面を確認します。

f:id:Takachan:20170115164945p:plain

特に問題なく利用可能になっています。


最後に

ライフサイクルサポートページに4.6.2の記述がないわ、Windows10は相変わらず普及しないわ、なんだか環境は超微妙ですね。.NET Coreはオープンソース化したりVisualstudio2015は大変出来が良いのでMSの担当チームごとに温度差を感じています。

c#でJsonをシリアライズ、デシリアライズする

f:id:Takachan:20170115150341j:plain

c#でJsonデータをシリアライズデシリアライズする方法のメモです。.NET Frameworkの標準ライブラリにあるDataContractJsonSerializerを使ってファイルやネットワークから読みとったJson文字列をC#のオブジェクトへ変換したり、オブジェクトの内容をJson文字列へ変換を行います。

Json.NETは使用しません。

データ構造

今回シリアライズ、デシリアライズするデータとクラスの構成は以下の通りです。

クラス構成

c#のクラスの内容です。

using System.Runtime.Serialization.Json;

[DataContract]
public class Person
{
    [DataMember]
    public int ID { get; set; }
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public IDictionary<string, string> Attributes { get; private set; }

    public Person()
    {
        this.Attributes = new Dictionary<string, string>();
    }
}

扱うJsonデータ

クラスをシリアライズした時、もしくはデシリアライズするときに使用するデータは以下となります。

[
    {
        "ID": 0, 
        "Name": "Taka", 
        "Attribute": {
            "key1": "value1"
            "key2": "value2"
            "key3": "value3"
        }
    }, 
    {
        "ID": 1, 
        "Name": "PG", 
        "Attribute": {
            "keyAA": "valueAA"
            "keyBB": "valueBB"
            "keyCC": "valueCC"
        }
    }
]

準備

先ずはプロジェクトとコードに以下準備を行います。

(1) DataContractJsonSerializerを使用するにプロジェクトにSystem.Runtime.Serializationの参照を追加します。

(2) 使用するコードに以下using宣言を追加します。

using System.Runtime.Serialization;

(3) シリアル化対象のクラスに以下属性を指定します。

[DataContract]
public class Person

(4) 対象メンバーに以下属性を指定します。

[DataMember]
public int ID { get; set; }

補足

もしクラスとJsonでフィールドの名前が違う場合、属性にNameが指定できます。

クラス名と異なる場合

[DataContract(Name = "Taka")]
public class Person

メンバー名が異なる場合

[DataMember(Name = "key")]
public int ID { get; set; }

Note:

クラスとJsonでフィールドの名前が違う場合、属性にNameが指定できます。

リアライズ

DataContractJsonSerializerとMemoryStreamを使ってオブジェクトをJsonにシリアライズします。

public static class JsonUtility
{
    /// <summary>
    /// 任意のオブジェクトをJsonメッセージへシリアライズします。
    /// </summary>
    public static string Serialize(object graph)
    {
        using (var stream = new MemoryStream())
        {
            var serializer = new DataContractJsonSerializer(graph.GetType());
            serializer.WriteObject(stream, graph);
            return Encoding.UTF8.GetString(stream.ToArray());
        }
    }
}

使い方

使い方はこんな感じです。

static void Main(string[] args)
{
    // データの作成
    var p_1 = new Person()
    {
        ID = 0,
        Name = "Taka",
    };
    p_1.Attributes.Add("key1", "value1");
    p_1.Attributes.Add("key2", "value2");
    p_1.Attributes.Add("key3", "value3");

    var p_2 = new Person()
    {
        ID = 1,
        Name = "PG",
    };
    p_2.Attributes.Add("keyAA", "valueAA");
    p_2.Attributes.Add("keyBB", "valueBB");
    p_2.Attributes.Add("keyCC", "valueCC");

    // リストに設定する
    List<Person> pList=new List<Person>() { p_1, p_2 };

    // リストをデシリアライズ
    string json = JsonUtility.Serialize(pList);

    // 内容をコンソールへ表示
    Console.WriteLine(json);
}

これで冒頭のJsonの例と同じ値が出力されます。

デシリアライズ

今度はデシリアライズです。

public static class JsonUtility
{
    /// <summary>
    /// Jsonメッセージをオブジェクトへデシリアライズします。
    /// </summary>
    public static T Deserialize<T>(string message)
    {
        using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(message)))
        {
            //var setting = new DataContractJsonSerializerSettings()
            //{
            //    UseSimpleDictionaryFormat = true,
            //};
            var serializer = new DataContractJsonSerializer(typeof(T), /*setting*/);
            return (T)serializer.ReadObject(stream);
        }
    }
}

使い方

先ほどの例でシリアライズしたメッセージがjsonに入っている状態から以下のようにデシリアライズします。

static void Main(string[] args)
{
    // ...前略...

    // デシリアライズ
    var pDeserializeList = JsonUtility.Deserialize<IList<Person>>(json);

    // 内容の出力
    foreach (var p in pDeserializeList)
    {
        Console.WriteLine("ID = " + p.ID);
        Console.WriteLine("Name = " + p.Name);
        foreach (var att in p.Attributes)
        {
            Console.WriteLine(att.Key + " = " + att.Value);
        }
    }
}

DataContractJsonSerializerSettingsについて

DataContractJsonSerializerSettingsのUseSimpleDictionaryFormatは指定方法によってDictionaryのデータ形式の取り扱い方法が若干変わります。それぞれ動作を確認した結果は以下に載せておきます。

UseSimpleDictionaryFormat = trueの場合

trueの場合、任意のキーと任意のValueがDictionaryの値になります。

[
    {
        "ID": 0,
        "Name": "Taka",
        "Attributes": {
            "key1": "value1",
            "key2": "value2",
            "key3": "value3"
        }
    },
    {
        "ID": 1,
        "Name": "PG",
        "Attributes": {
            "keyAA": "valueAA",
            "keyBB": "valueBB",
            "keyCC": "valueCC"
        }
    }
]

UseSimpleDictionaryFormat = falseの場合

false(もしくは設定しない)の場合、Key=“”, Value=“"のペアの繰り返しの配列扱いになります。多分こっちはあんまり使わないのですが、状況によってどうするか変わると思います。

[
    {
        "ID": 0,
        "Name": "Taka",
        "Attributes": [
            {
                "Key": "key1", 
                "Value": "value1"
            }, 
            {
                "Key": "key2", 
                "Value": "value2"
            }, 
            {
                "Key": "key3", 
                "Value": "value3"
            }
        ]
    },
    {
        "ID": 1, 
        "Name": "PG",
        "Attributes": [
            {
                "Key": "keyAA", 
                "Value": "valueAA"
            },
            {
                "Key": "keyBB", 
                "Value": "valueBB"
            },
            {
                "Key": "keyCC", 
                "Value": "valueCC"
            }
        ],
    }
]

コード全体

上記コード全体をGistにアップアップしました。 良かったら見てください。

JsonUtility.cs · GitHub

VisualStudio2015が使うIEバージョンの変更

f:id:Takachan:20170115150341j:plain

VisualStudio2015ってデフォルトだとIE9になっています。このままだとネットワークがIEの古いバージョンを制限していたりするとVisualStudio上からログインダイアログすら表示できないのでブラウザがIE11を使用するように変更したいと思います。

Note:

基本的に最近のVisualStudioなら同じ設定で変更できるのでバージョンが違う人が読み替えでOK



変更方法

レジストリを変更することになるので、設定を変更する際の一般的な注意事項は確認してください。

VisualStudio2015を立ち上げる

まず始めにVisualStudio2015を起動します。

Note:

起動時(起動後)にこれから変更したい箇所のレジストリが書き換わってしまうのであらかじめ起動しておきます。順番大事


VisualStudio上でWebブラウザを表示してこのサイトでバージョンを確認します。

f:id:Takachan:20170115151052p:plain

見事に「IE9」と表示されていますね。


レジストリの変更

[Win]キーを押して「regedit」と入力してからエンターを入力します。レジストリエディタが立ち上がるのでエディタのツリーから以下箇所へ移動します。

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION


右側に「devenv.exe」という欄があり値gあ0x0000270f(9999)になっていると思います。この欄をダブルクリックして値を変更します。


だいたい以下のような意味なので入力欄にIE11の値を設定します。

値 (16進数) バージョンと意味
0x2AF8 Internet Explorer 11
0x2711 Internet Explorer 10
0x270F Internet Explorer 9


16進数の先頭の「0x」は入れないでください。

f:id:Takachan:20170115151727p:plain

これで[OK]して先ほど起動したVisualStudioに戻ります。


変更の確認

無事変更できました。(この画面一度表示しちゃうとIE9のままになるので表示したい場合レジストリ変更してから初回表示させてください)

f:id:Takachan:20170115152405p:plain


最後に

この設定ですが、毎回立ち上げるたびにリセットされちゃうので起動するたびに設定の変更が必要です。大変めんどくさいので設定をエクスポートしておいた方がよさそうです。