Apr 9

なでしこソースをC#で動かすためのdllを作ってるけどはまった

なでしこの掲示板で相談しようにもどこに書いたら良いか分らないのでメモ

C#でなでしこのソースを実行させようと思い、dnako.dllを実行するクラスを書きました。実装してる関数は少ないですが。

Nadesikom.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace NadesikoCS
{
    class Nadesikom
    {
        [DllImport("dnako.dll")]
        public extern static void nako_resetAll();
        [DllImport("dnako.dll")]
        public extern static IntPtr nako_eval(StringBuilder evalString);
        [DllImport("dnako.dll")]
        public extern static IntPtr nako_var_new(StringBuilder newString);
        [DllImport("dnako.dll")]
        public extern static uint nako_load(StringBuilder source);
        [DllImport("dnako.dll")]
        public extern static IntPtr nako_run_ex();
        [DllImport("dnako.dll")]
        public extern static void nako_free();
        [DllImport("dnako.dll")]
        public extern static void nako_addFileCommand();
        [DllImport("dnako.dll")]
        public extern static void nako_LoadPlugins();
        [DllImport("dnako.dll")]
        public extern static void nako_makeReport(StringBuilder report);
        [DllImport("dnako.dll")]
        public extern static void nako_setPluginsDir(StringBuilder path);
        [DllImport("dnako.dll")]
        public extern static StringBuilder nako_getPluginsDir();
        [DllImport("dnako.dll")]
        public extern static StringBuilder nako_getVersion();
    }

    [StructLayout(LayoutKind.Explicit)]
    public struct PHiValue
    {
        [FieldOffset(0)]
        public byte VType; // 値の型
        [FieldOffset(1)]
        public int Size;  // 値の大きさ
        [FieldOffset(5)]
        public uint VarID;    // 変数名
        [FieldOffset(9)]
        public int RefCount;  // 参照カウント for GC
        [FieldOffset(13)]
        IntPtr Setter; // Setter
        [FieldOffset(17)]
        IntPtr Getter; // Getter
        [FieldOffset(21)]
        byte ReadOnly;     // ReadOnly = 1
        [FieldOffset(22)]
        public byte Registered;   // 解放してよい値か?(これが1なら勝手に解放してはならない)
        [FieldOffset(23)]
        byte Flag1;
        [FieldOffset(24)]
        byte Flag2;
        [FieldOffset(25)]
        public int integer; // varInt
        [FieldOffset(25)]
        IntPtr ptr; // other...
        [FieldOffset(25)]
        public IntPtr ptr_s; // varStr

    }
    
}



dnako.dllではPHiValue型で値を返す関数が多いため、帰ってきた値をIntPtr型で受けてPHiValue型でマーシャリングすることにしました。PHiValue型は

typedef struct tagTHiValue{
    BYTE		VType; // 値の型
    int			Size;  // 値の大きさ
    DWORD		VarID;    // 変数名
    int			RefCount;  // 参照カウント for GC
    struct tagTHiValue	*Setter; // Setter
    struct tagTHiValue	*Getter; // Getter
    BYTE		ReadOnly;     // ReadOnly = 1
    BYTE		Registered;   // 解放してよい値か?(これが1なら勝手に解放してはならない)
    BYTE		Flag1;
    BYTE		Flag2;
    union {//case Byte of
    int integer; // varInt
    void *ptr; // other...
    char *ptr_s; // varStr
	};
} THiValue;


という構造体で中に共有体を持っているため、FieldOffsetを明示的に指定するしかありませんでした。あーめんど。

実行部は該当箇所のみ書きます。executeButtonというボタンを作って、クリック時のイベントでなでしこプログラムを実行するようにしました。
Form.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace NadesikoCS
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void executeButton_Click(object sender, EventArgs e)
        {
            Nadesikom.nako_resetAll();
                Encoding sjis = Encoding.GetEncoding(932);
                Encoding utf8 = Encoding.UTF8;
                IntPtr res = Nadesikom.nako_eval(new StringBuilder(sjis.GetString(Encoding.Convert(utf8, sjis, utf8.GetBytes("「ほげ」で戻る。")))));
                PHiValue p = (PHiValue)Marshal.PtrToStructure(res, typeof(PHiValue));
            string res = Marshal.PtrToStringAnsi(p.ptr_s);
            MessageBox.Show(utf8.GetString(Encoding.Convert(sjis, utf8, sjis.GetBytes(res))));
        }
    }
}


するとダイアログで「ほげ」と表示されました。やったね!(前提条件で、なでしこのplug-insフォルダ下にあるdnako.dllをプロジェクトフォルダ\bin\Debugフォルダに置いています)
で、調子に乗って
「ほげ」で戻る。


ほげ=「{デスクトップ}hoge.txt」を読む。ほげで戻る。

と変えてみると????動かない???
レポートしてみると何もプラグインがインストールされていませんでした。
そこでプロジェクトフォルダ\bin\Debug\plug-ins以下にnakofile.dllをコピーし、Nadesikom.nako_resetAll()以下に次のコードを追加して実行してみました。

            Nadesikom.nako_addFileCommand();
            Nadesikom.nako_LoadPlugins();

すると、「外部ライブラリが例外を返しました」とLoadPluginsの箇所で例外を返し、プラグインのロードが出来ませんでした。同じエラーがtest関数でも出ました。

そしてdnako.dllをなでしこフォルダ直下にあるものに置き換えると今度は例外は出さないのですが、プラグインを読み込んでくれませんでした。しかもnako_getVersionなどの関数は「エントリポイントがありません」という例外を出しました。サイズが小さいみたいなので、こういった関数を消してるのかもしれませんね。

結局これをどうやって原因究明して良いのか分らず終了。
きっとなでしこに関する質問にはなるんですが、どこで質問したら良いんでしょうねー?

ちなみにdnako.dllのnako_getVersion関数でバージョンを出力すると、1.519でした。

※ソースはエラー処理とか全く入れてない適当なものです。

| comment(0)