delphiから、メモ帳を起動してテキストを書き込みます
小ネタです。
delphiは、windows API や メッセージを処理することもできます。
こんなことをやります。
・ShellExecute で、メモ帳を起動します。
・FindWindowW で、起動中のメモ帳のウインドウハンドルを取ります
・FindWindowEx でメモ帳の中の編集領域のウインドハンドルを取ります
・SendMessage で書き込みます
画面を作ります
ファイル >> 新規作成 >> Windows VCLアプリケーション delphi と選択して、新規のアプリを作ります。
コンポーネントのパレットから
・memo1
・edit1
・button1
を貼りつけてください。
以上で画面作りは完了です。
C:(途中省略)\Embarcadero\Studio\Projects\ の下に適当なファイルフォルダーを作って保存してください。
ファイル >> すべて保存 を選択します。ファイル名やプロジェクトの名前はデフォルトのままで問題ありません。
プログラム
メモ帳を起動するには、ShellExecute というWindowsのAPIを使用します。delphiから使用するために、uses節に Winapi.ShellAPI を書き足してください。
ちっちゃいプログラムなので全文を掲載します。
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Winapi.ShellAPI;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
lpClassName: Pchar;
Hwnd_p, Hwnd_c: HWND;
begin
//メモ帳のクラス名は'Notepad'。
lpClassName:= Pchar('Notepad'); //Pchar型に変換('Notepad')
//すでにメモ帳が起動しているか? いないか? 確認します
//メモ帳のHandle:=FindWindowW(pChar型で'Notepad', ウインドウ名省略でnil)
Hwnd_p := FindWindowW(PChar(lpClassName), nil);
//FindWindowWの結果が0のときはメモ帳が起動していません
if Hwnd_p = 0 then
//ShellExecuteでメモ帳を起動します
ShellExecuteA(Hwnd_p, '', 'notepad.exe', nil, nil, SW_SHOW);
if Hwnd_p <> 0 then
begin
//親のハンドルでメモ帳のタイトルバーに書込
SendMessage(Hwnd_p, WM_SETTEXT, 0, LPARAM(PChar(Edit1.Text)));
//子のハンドル:=FindWindowEx(親のWindowHandle, 0, 入力部分の名は'Edit','')
Hwnd_c :=FindWindowEx(Hwnd_p,0 ,PChar('EDIT'), '');
//子のハンドルで編集画面に書込
SendMessage(Hwnd_c, WM_SETTEXT, 0, LPARAM(PChar(memo1.Text)));
end;
end;
end.
実験してみましょう
まず、メモ帳が起動していない状態で、上記のアプリを実行します。
button1をクリックします。
メモ帳が起動します。
そうしたら、edit1 と memo1 に何か適当にテキストを入力してから、
もう一度、button1 をクリックしてください。
メモ帳に、文字列が転送されたら、成功です。
(なお、メモ帳のタイトルは、メモ帳にフォーカスを入れると、元に直されちゃいます)
説明
FindWindowWは、起動中のウインドウを探します。
起動していないときは、結果は0です。見つかったときは、起動中のウインドウのウインドウハンドルを返します。
Pcharに変換しているのは、Windows APIは、NULLで終わる文字列を使うためです。
Hwnd_p := FindWindowW( PChar( lpClassName ), nil ); の意味は、「クラス名またはウインドウのタイトル名から、起動中のウインドウのハンドルを探してください」です。
FindWindowWのパラメータは次のとおり
パラメータ | 意味 |
---|---|
1 lpClassName | クラス名 |
2 lpWindowName | ウインドウの名(タイトルバー) |
※参考 FindWindowW 関数
https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-findwindoww
この記事では、メモ帳の名前は、Notepadだとわかっているため、クラス名から探しています。
ここで得られたウインドウハンドル宛てに、 後述の方法でメッセージを送ります。
ShellExecuteAは、アプリを起動します。
ShellExecuteAはアプリを起動して、ウインドウハンドルを返します。
notopadつまりメモ帳は、パスが通っているらしくて、フルパスを指定しなくても起動します。本当はフルパス指定みたいです。
ShellExecuteA(Hwnd_p, '', 'notepad.exe', nil, nil, SW_SHOW);
ShellExecuteAのパラメータは次のとおり
パラメータ | 意味 |
---|---|
1 hwnd | ウインドウハンドル。起動したウインドウのハンドルを返します |
2 lpOperation | 編集や検索などの動作を指示。省略 |
3 lpFile | ファイル名。notepad.exeを指定 |
4 lpParameters | 起動時に渡すパラメーター。省略 |
5 lpDirectory | 作業ディレクトリー。省略 |
6 nShowCmd | 表示方法 SW_SHOW(ウィンドウをアクティブ化し、現在のサイズと位置で表示)を指定 |
※参考 ShellExecuteA 関数
https://learn.microsoft.com/ja-jp/windows/win32/api/shellapi/nf-shellapi-shellexecutea
FindWindowExは、子のウインドウを探します
FindWindowWが返すウインドウハンドルから直下の子のウインドウハンドルを返します。
メモ帳の編集領域のウインドウハンドル:= FindWindowEx(Hwnd_p,0 ,PChar('EDIT'), '');
です。メモ帳の編集領域を担当しているコントロールのクラス名は、ネットをさまよって調べた結果、'EDIT'という名前らしいです。
FindWindowExのパラメータは次のとおり
パラメータ | 意味 |
---|---|
1 hWndParent | 親のウインドウハンドル |
2 hWndChildAfter | 子のウインドウハンドル。孫は探さないので 0を指定 |
3 lpszClass | 探したい子のクラス名 'EDIT' |
4 lpszWindow | ウインドウの名前。省略 |
※参考 FindWindowExA 関数
https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-findwindowexa
SendMessageは、他のウインドウへお手紙を送信します。
Windowsはマウスを転がしても、かな漢字変換をしても、メッセージで処理しています。起動中の他のウインドウへお手紙を出すのが、Sendmessageです。
メモ帳のタイトルバーに書き込むのが、
SendMessage(Hwnd_p, WM_SETTEXT, 0, LPARAM(PChar(Edit1.Text)));
Hwnd_pの中身は、メモ帳のウインドウハンドルです。
メモ帳の中身、編集領域に書き込むのが、
SendMessage(Hwnd_c, WM_SETTEXT, 0, LPARAM(PChar(memo1.Text)));
Hwnd_cの中身は、メモ帳の子ウインドウの編集領域担当のコントロール'EDIT'です。
パラメータ | 意味 SendMessageでWM_SETTEXTを送信のとき |
---|---|
1 hWnd | 編集コントロールのウインドウハンドル |
2 Msg | システムに定義されているメッセージ。WM_SETTEXTを指定 |
3 wParam | WM_SETTEXTでは使用しません |
4 lParam | 書込文字列。ゼロで終わる文字列。LPARAM( )で囲っているのは、NativeIntという「プラットフォームに依存する符号付き整数を定義したもの」です。Windowsには、32ビット環境と64ビット環境がありますから、ね。 |
※参考 SendMessage 関数
https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-sendmessage
※参考 WM_SETTEXT メッセージ
https://learn.microsoft.com/ja-jp/windows/win32/winmsg/wm-settext
※参考 NativeInt
https://docwiki.embarcadero.com/Libraries/Athens/ja/System.NativeInt
delphiが、ネーティブコードを生成するコンパイラ言語なので、こんな機能があるんだと思いますけど、難しいね。