C#で作ったdllを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 を使用している。
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にアップ。
実行し、”1 + max(2, 3) * 4"と入力すると、"13"と返ってくる。
------------------------------------------------
# 1 + max(2, 3) * 4
OK
13
------------------------------------------------