C#で作ったdllをExcel/VBAから呼び出す方法。

課題

  • 関数にsummaryを書き、xmlを生成したが、Excel/VBAでは表示されない。
  • 下記のコードの意味がよく分からない。
[ComRegisterFunctionAttribute]
private static void RegisterFunction(Type type)
{
    Registry.ClassesRoot.CreateSubKey(
      GetSubKeyName(type, "Programmable"));
    RegistryKey key = Registry.ClassesRoot.OpenSubKey(
      GetSubKeyName(type, "InprocServer32"), true);
    key.SetValue("", System.Environment.SystemDirectory + @"\mscoree.dll",
      RegistryValueKind.String);
}
[ComUnregisterFunctionAttribute]
private static void UnregisterFunction(Type type)
{
    Registry.ClassesRoot.DeleteSubKey(
                    GetSubKeyName(type, "Programmable"), false);
}
private static string GetSubKeyName(Type type,
  string subKeyName)
{
    System.Text.StringBuilder s = new System.Text.StringBuilder();
    s.Append(@"CLSID\{");
    s.Append(type.GUID.ToString().ToUpper());
    s.Append(@"}\");
    s.Append(subKeyName);
    return s.ToString();
}

調査(途中)

  • COMとは、Mincrosoftが提唱する技術仕様。この仕様に基づいてデータのやり取りができるパーツのことをCOMコンポーネントと呼ぶ。COMコンポーネントは、どの言語からも使用できる。
  • CLSIDとは、COMコンポーネント固有のID。世界中の開発者がCOMコンポーネントを作ってもかぶらないようになっている。
  • C#のTypeクラスはGUIDというプロパティを持っている。
  • ComRegisterFunctionAttributeは属性でComRegisterFunctionとしても同じ。
  • ComRegisterFunctionを付けると、RegAsm.exeがその関数を呼ぶようになる。
  • CLSIDのsub keyとして、ProgrammableとInprocServer32を作成し、InprocServer32にmscoree.dllを設定すれば良い。

パースしたJSONを違うobjectに変換する。

したいこと

{"person" : {"name" : "testname", "age" : 29}}
のようなデータから

class Person {
    std::string _name;
    int _age;
};

class Data {
    Person _person;
};

のDataクラスに変換する。

ソースコード

int main()
{
	std::string jsonData = "{\"person\" : {\"name\" : \"testname\", \"age\" : 29}}";
	Object obj = load(jsonData);


	addConstructRule<Data, Person>("person");
	addConstructRule<Person, std::string, double>("name", "age");

	Data d = as<Data>(obj);

	std::cout << d._person._name << std::endl;
	std::cout << d._person._age << std::endl;
	return 0;
}
    addConstructRule<Data, Person>("person");
    addConstructRule<Person, std::string, double>("name", "age");

上記のようにコンストラクターを登録する必要があるのがいけていない。
C#のConstructorInfo::Invokeのようなことができればよいのだけれでも。

JSONのパースは http://nsb248.hatenablog.com/entry/2016/02/08/151330 を使用している。

JSON構文

JSONの原典

JSON

JSONの構文

  • データは "name" : value
  • データはカンマ区切り
  • 波括弧{}はオブジェクト
  • 角括弧[]は配列を表す

JSONのvalueの型

  • 数値
  • 文字列
  • ブール
  • 配列
  • オブジェクト
  • null

JSON構文チェック

下記サイトで構文を確認できる。
https://syncer.jp/json-prettyprint

  • {"name" : "nnn", "age" : 22}

boost::spiritを使ってjsonをパースする

enum classをfor文で回す。

#define GENERATE_ENUM_ITERATOR(T) \
inline T operator++(T& x) { return x = (T)(std::underlying_type<T>::type(x) + 1); } \
inline T operator*(T c) { return c; } \
inline T begin(T r) { return static_cast<T>(0); } \
inline T end(T r) { T l = T::LAST; return l; }

enum class  Color{
    red, blue, LAST
}

GENERATE_ENUM_ITERATOR(Color);

int main() {
    for (Color c : Color()) {
        doSomething(c);
    }
}

boost::spirit::qiを使って電卓っぽいものを作る。

コードをgithubにアップ。

nishiba/boost_spirit_sample

 

実行し、”1 + max(2, 3) * 4"と入力すると、"13"と返ってくる。

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

# 1 + max(2, 3) * 4
OK
13

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