外部プログラムから、秀丸のアウトプットNo.31876
あきくん さん 12/12/25 20:02
 
・現在、(秀丸から呼び出すの形ではない)外部プログラムから、
 秀丸のアウトプット枠に文字列を表示したいと考えております。

・外部プログラムは、いわゆる、ずっとforループしてるような
 「常駐」タイプであるため、秀丸のrunex系マクロを使用してしまうと、
 アウトプット枠のプロセスが占領されてしまい、
 他のマクロからのアウトプット枠への表示を受け付けなくなってしまいます。

・そこで、外部プログラム自身が、HmOutputPane.dllをロードし、
 (該当dllの)Output関数を実行すればよいのではないかと思い、
 実験サンプルとなるC言語プログラムを作ったのですが、
 Push関数によるクリアは機能するものの、Output関数は機能しません。

・実験で制作したソースは以下のものです。
#include <windows.h>
#include <stdio.h>


typedef int (_cdecl *PFNOUTPUT)(HWND hwnd, const char *);
typedef int (_cdecl *PFNPUSH)(HWND hwnd);

void main(void) {
 HWND hHidemaru = FindWindow("Hidemaru32Class", NULL);
 if (!hHidemaru) {
  return;
 }
 /*
 HWND hCldHidemaru = GetWindow(hHidemaru, GW_CHILD);
 printf("%d", (int)hHidemaru);
 */

 if ( !hHidemaru ) {
  MessageBox(NULL, "NOHIDE", "NOHIDE", NULL);
  return;
 }

 HMODULE hHmOutputPane=LoadLibrary("HmOutputPane.dll");
 if ( !hHmOutputPane ) {
  MessageBox(NULL, "NPANE", "NOPANE", NULL);
  return;
 }

 PFNPUSH pPush = (PFNPUSH)GetProcAddress( hHmOutputPane, "Push" );
 ((PFNPUSH) pPush)((HWND)789214);

 PFNOUTPUT pOutput = (PFNOUTPUT)GetProcAddress( hHmOutputPane, "Output" );
 ((PFNOUTPUT) pOutput)((HWND)789214, "abc\n");

 printf("End");
}

※上記ソースの789214といった数値の部分は、実際には、
 秀丸エディタのウィンドウハンドルの数値を入れる必要があります。
 (秀丸マクロでいうhidemaruhandle(0)です)

・質問の1つ目となりますが、
 上記ソースを実行した場合、Pushは実行できますが(アウトプット枠がクリアされ
る)、
 Outputは実行できません。これはなぜなのでしょうか…
 Outputを実行するにはどのようにすればよいのでしょうか。

・質問の2つ目となりますが、
 上記789214の部分は、実際には、秀丸マクロ上でのhidemaruhandle(0)相当の
 数値(ウィンドウハンドル)が必要となります。
 しかし、hidemaruhandle(0)は、秀丸のどのタブがアクティブなのかで
 変化してしまうため、事前に外部プログラムに引数として渡す(一種の静的な手段)
のには無理があります。
 C言語側で、hidemaruhandle(0)と等しいハンドルを取得する手段は
 ありますでしょうか?
 (GetWindowのwin32関数等を使って調べてみましたが、わかりませんでした…)

 以上、よろしくお願い致します。
 
  

[ ]
RE:31876 外部プログラムから、秀丸のアウNo.31878
秀丸担当 さん 12/12/26 09:45
 

内部的な話になってしまいますが、Output関数に渡した文字列ポインタは、
hidemaru.exe内で扱うため、同じアドレス空間にある必要があります。

プログラムはhidemaru.exe内で動くDLLではなくて、外部のEXEだと思いますが、
この場合は文字列ポインタは別のプロセス(別のアドレス空間)のポインタを指
しているため、このアドレスにアクセスすると通常では保護違反になってしまう
ので、Output関数においてはあらかじめ別プロセスからは呼び出せないように未
然に防いでいます。

HmOutputPane.dllの関数はマクロ以外から呼ばれることは想定されていないので、
すみませんがこれを公式にサポートすることは難しいです。

しいてなんとかするとすれば、EXEとは別の中継用のDLLを作って、マクロで
loaddllを呼んで、freedllしないでおくとロードされたままになるので、これを
中継するとできると思います。
hidemaru.exe内のDLLからOutput関数を呼ぶと同じアドレス空間になります。
その際、hidemaruhandle(0)をマクロで取得してDLLに渡しておくことで、ウィン
ドウハンドルの問題も解決できるのではないかと思います。

[ ]
RE:31878 外部プログラムから、秀丸のアウNo.31883
あきくん さん 12/12/26 19:51
 
おっしゃるとおりであることを、
HmOutputPane.dllの中身をステップ実行して概ね確認しました。

@アドレス空間の問題については、#pragma data_seg を利用した共用メモリ変数とし、
 Hidemaru.exeにdllを読ませて(残して)おくことで、解決できました。
Ahidemaruhandle(0)については、マクロ機能の自動実行の「アクティブ切替」にマク
ロを設定しておけば、@で読ませたdllに変更時に伝達できるため解決できました。


おかげさまにて、手元では、ある程度動作しはじめて、見通しがたってきました。
まだ不安定でメモリアクセス違反など起きることがあるので、
突っ込んで分析していこうと思います。

//-----------------------------------------------------

追加質問で申し訳ないのですが、

・秀丸のプロセス空間内のDLL(秀丸から呼ばれたDLL)から、
 秀丸に対して、特定の秀丸マクロファイル(もしくはマクロ文字列)を実行するような
APIが用意されてあったりしますか?
 (例:HIDEMAC.DLLをLoadLibrary⇒○○関数実行⇒解放)のような…

[ ]
RE:31883 外部プログラムから、秀丸のアウNo.31887
秀丸担当 さん 12/12/27 11:33
 

>・秀丸のプロセス空間内のDLL(秀丸から呼ばれたDLL)から、
> 秀丸に対して、特定の秀丸マクロファイル(もしくはマクロ文字列)を実行するよう
>な
>APIが用意されてあったりしますか?
> (例:HIDEMAC.DLLをLoadLibrary⇒○○関数実行⇒解放)のような…

マクロを直接実行するAPIのようなものは用意されていないです。
外部からマクロを実行する場合は hidemaru.exe の起動オプションで、
hidemaru.exe /xTest.mac
といった感じで起動するという方法があります。

直接実行する方法は無いですが、少々無理矢理ではありますが、[マクロ]→[マ
クロ登録]で登録したマクロの番号を指定して、WM_COMMANDを送るということは
できてしまうと思います。
参考までの情報として、wParamに指定するコマンド値は、
マクロ1〜15のコマンド値は146〜160
マクロ16〜30のコマンド値は205〜219
マクロ31〜のコマンド値は234〜
になっています。

[ ]
RE:31887 外部プログラムから、秀丸のアウNo.31896
あきくん さん 12/12/28 02:37
 
>参考までの情報として、wParamに指定するコマンド値は、
>マクロ1〜15のコマンド値は146〜160
>マクロ16〜30のコマンド値は205〜219
>マクロ31〜のコマンド値は234〜

ありがとうございます。

・SendMessageを組み入れて、マクロ実行トリガーを引くことで
 十分な安定性が得られました。

・常駐実行である外部EXEから、秀丸のアウトプット枠に
 安定かつ高速に出力出来るようになりました。

ありがとうございました。


[ ]