- ベストアンサー
excelVBAからC#へsendmessage
- excel VBAからC#のプログラムに文字列を渡す方法について考えています。
- 作成したプログラムがうまく動作せず、表示される文字列がおかしいです。
- Windows 7、Excel 2010、.NET Framework 4を使用しています。
- みんなの回答 (1)
- 専門家の回答
質問者が選んだベストアンサー
Win32 APIをあまり使ったことないんで自信ない。 なお、俺の環境はVista(32 bit)である。 C言語の知識があると尚可 http://codezine.jp/article/detail/1718 を参考に、SendMessageAではなくSendMessageWを呼んでみた。 一応手元では成功している。(ハンドルを調べるためにC#のプログラムを先に起動している) '===========VBA側プログラム============= Option Explicit ' このVBのプログラムからは以下の引数のSendMessageという関数を呼び出した時、 ' user32.dllにあるSendMessageWを呼び出すものとする、というものだと思っているので ' ぶっちゃけわかればAliasの後ろはなんだっていいんだと思う。 Declare Function SendMessage Lib "user32.dll" Alias "SendMessageW" _ (ByVal hwd As Long, ByVal Msg As Long, ByVal wpara As Long, lpara As COPYDATASTRUCT) As Long '構造体の定義 '64bit環境ではどうなるんだろうね(Windows 7の人とかだと多そう) Public Type COPYDATASTRUCT dwData As Long ' 32 bit cbData As Long ' 32 bit lpData As Long ' 変更: 文字列へのポインタを格納することに End Type '元のコードから抜けてた。 Public Const WM_COPYDATA As Integer = &H4A Public Sub Send() Dim result As Long Dim hWnd As Long Dim cds As COPYDATASTRUCT Dim str As String 'ハンドルを調べる方法を調べるのが面倒だったので '先にC#のプログラム起動して調べた。 '起動毎に変わるので注意。> 俺 hWnd = 657792 str = "あいう" cds.dwData = 0 cds.lpData = StrPtr(str) 'サロゲートペア文字とか考慮しなければUTF-16は1文字2バイト固定 'Wの場合null文字の分要らないっぽい?。 cds.cbData = 2 * Len(str) result = SendMessage(hWnd, WM_COPYDATA, 0, cds) End Sub //============================C#側プログラム================ using System; using System.Windows.Forms; using System.Runtime.InteropServices; class Hoge:System.Windows.Forms.Form{ public const int WM_COPYDATA = 0x4A; // 自信ないけど、多分メモリの構造とか合わせないといけないと思うので // この属性をつけておく [StructLayout(LayoutKind.Sequential)] public struct COPYDATASTRUCT { // VBのLongは32bitだけど、.NET FrameworkのLongは64bit // だと思う。一応uintを使っておく。 public uint dwData; public uint cbData; // SendMessageWでUnicode文字列を送ってくるのでこの属性を一応つけてみる。 //あってるか自信なし。 [MarshalAs(UnmanagedType.LPWStr)] public string lpData; } //WndProc関数 protected override void WndProc(ref Message m){ // Textプロパティを書き換えて何度もここが走ったりしないか不安だったので // デバッグのため、一応ファイルに書き出すことに。 // 前のものを書き換えないよう、追記で。 // 自信があるなら別になくて良い処理 using(System.IO.StreamWriter sw = new System.IO.StreamWriter("D:\\logging.txt",true)){ sw.WriteLine ("test:" + m.Msg); sw.WriteLine ("wanted:" + WM_COPYDATA); switch (m.Msg){ case WM_COPYDATA: COPYDATASTRUCT mystr = (COPYDATASTRUCT)m.GetLParam(typeof(COPYDATASTRUCT)); sw.WriteLine (mystr.lpData + mystr.lpData.Length); break; } } base.WndProc(ref m); } } class Fuga{ public static void Main(){ Hoge f = new Hoge(); // 先に起動して調べておく f.Text = f.Handle.ToString (); f.ShowDialog (); } } ======================================= とまぁこんな感じにしておいて、 WM_COPYDATAに該当する74(=0x4A)を探したら test:74 あいう3 になっていた。
お礼
ありがとうございました! おかげさまで上手いこと動きました! C#側のlongをuintに変えて、 VBA側の文字列の長さをLen(str)に変えたらうまく動きました。 また、その他にもいろいろと私のしらないテクニックを見ることができて、 非常に興味深かったです! 本当にありがとうございました!