Delphi初心者です。
作成環境:WinXP pro Delphi7
メモ帳に書かれたテキストを取得し、メモコントロールなどに出力したいのですが、色々なサイトなどで、調べた結果
-------------------------------------------------
var
buf:integer;
begin
SendMessage(WND,WM_GETTEXT,255,integer(@buf));
-------------------------------------------------
SendMessageでWM_GETTEXTを投げるという所までは、わかったのですが、第4引数のinteger(@buf)だと、integer型なので、16バイト以上取得しようとすると、メモリの書き込みエラーですといったような事になってしまいます。
どんな長さでも、自由に取得できる方法があれば、教えてください。
> var
> buf:integer;
bufはテキストを受け取るバッファですので、例えば
buf: array[0..1024] of Char;
というような宣言になると思いますよ。
むちゃくちゃ早いレスありがとうございます!!m(__)m
文字列の取得できました!!。
質問には、メモ帳と書きましたが、わかりやすいと思い書いた物で、実際には、他アプリのリッチエディットから文字列を取得したいという物です。
ふぐちゃんさんの教えてくださった通り、buf: array[0..1024] of Char;で宣言したら、取得はできたのですが、0〜1024までのインデックスを持つ配列を宣言しているんですよね?
ど素人なもので、、なぜ配列なのかが理解できません。。。(すいません・・・)もしよろしければ、そのあたりの、解説をヨロシクお願いします。 すいません。。。
> なぜ配列なのかが理解できません。。。
APIでは文字型の配列が文字列なので、APIから文字列を受け取る場合には
Char型の配列を使うことが多いです。
Delphiの文字列型を使ってもできないことはないです。
その場合、SetLengthでメモリを確保して使います。
Msg := SendMessage(WND,WM_GETTEXTLENGTH,0,0);
で、取得するデータのサイズを取りたいのですが、メモリーなんとかエラーが出てしまいます。。。
buf: array[0..1024] of Char;という固定的なサイズでしか使用できないのでしょうか、、、
また、取得したデータをリッチエディットに出力していますが、内容を見るのに、毎回行の一番上にカーソル(スクロール)が行ってしまいますが、これを逆(一番下の行)にするプロパティなどはないのでしょうか。
脱線した質問になってしまいすいません。別スレ立てたほうがよいのでしょうか。。。
> Msg := SendMessage(WND,WM_GETTEXTLENGTH,0,0);
> で、取得するデータのサイズを取りたいのですが、メモリーなんとかエラーが出てしまいます。。。
ヌルの分のメモリを確保していないということはないでしょうか?
Msgという変数名も気になります。
できればもう少しコードを提示してください。
> buf: array[0..1024] of Char;という固定的なサイズでしか使用できないのでしょうか、、、
上でも書きましたが、長い文字列型の変数とSetLengthで実行時にサイズを設定できます。
> また、取得したデータをリッチエディットに出力していますが、内容を見るのに、
> 毎回行の一番上にカーソル(スクロール)が行ってしまいますが、
> これを逆(一番下の行)にするプロパティなどはないのでしょうか。
> 脱線した質問になってしまいすいません。別スレ立てたほうがよいのでしょうか。。。
そうですね、別のスレッドにした方がよいと思います。
参考までに、私ならバーチャルキーを使うかもわかりません。
すいません。中途半端なソースの提示で、よけいややこしくなってしまいますね。。。以下がその部分のソースです。クラス名などは、とりあえず****に置き換えてあります。ソース上ではきちんと書いています。
------------------------------------------------------------------
procedure TForm1.Timer1Timer(Sender: TObject);
var
WND: HWND;
Msg:integer;
buf: array[0..8024] of char;
begin
//ハンドル取得
WND := FindWindow('AfxFrameOrView42', nil);
WND := GetWindow(WND,GW_CHILD);
WND := GetWindow(WND,GW_HWNDNEXT);
WND := GetWindow(WND,GW_HWNDNEXT);
WND := FindWindowEx(WND,0,'****', '****');
WND := FindWindowEx(WND,0,'RICHEDIT', nil);
try
Msg := SendMessage(WND,WM_GETTEXT,8160,integer(@buf));
RichEdit1.text := string(integer(@buf));
except
RichEdit1.text := '取得に失敗しました';
end;
end;
----------------------------------------------------------------
以上がソースです。
タイマーを使って毎秒取得しています。
わたしの D5 では Windows.pas で
function SendMessage(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
type
LRESULT = Longint;
となっていますので SendMessage() の戻り値は LongInt です。
ワードパッドからテキストを取得し、それを RichEdit1 に表示し、キャレットを
末尾にもっていって、スクロールする例をあげておきます。
procedure TForm1.Button1Click(Sender: TObject);
var
hRichEdit:HWND;
Ret:LongInt;
s:string;
begin
hRichEdit := FindWindow('WordPadClass',nil);
hRichEdit := FindWindowEx(hRichEdit,0,'RichEdit20W',nil);
if hRichEdit = 0 then exit;
Ret := SendMessage(hRichEdit,WM_GETTEXTLENGTH,0,0);
s := StringOfChar(#0,Ret+1);
Ret := SendMessage(hRichEdit,WM_GETTEXT,Ret,LParam(PChar(s)));
SetLength(s,Ret);
RichEdit1.Text := s;
RichEdit1.SelStart := Length(s);
Richedit1.Perform(EM_SCROLLCARET,0,0);
RichEdit1.SetFocus;
end;
jokさんの書いてくださったコード、私もとても勉強になりました。
どうもありがとうございます。
>shimippyさん
環境はXPとのことですので、XP上でjokさんのコードを試されるときには、
hRichEdit := FindWindowEx(hRichEdit,0,'RichEdit20W',nil);
を
hRichEdit := FindWindowEx(hRichEdit,0,'RichEdit50W',nil);
に変更するのをお忘れなく。
jokさん、ふぐちゃんさん、大変参考になる内容ありがとうございます。
無事解決しました。と言っても、ほとんど丸写しの様な結果になってしまいましたが(汗)・・・
私は、クラス名やキャプションを取得するのに、Winspector spy というツールを使っています。今回のリッチエディットのクラス名が、'RICHEDIT'だったんですが、20Wとか50Wというのは、リッチエディットのバージョンなのでしょうか。そのツールを使って、ワードパットのエディット部分のクラス名を見たら、50Wが付いていたので、今回、取得している物とは、別の物なのかなと思います。
なにわともあれ、お二人には大変感謝しています。
今後、頂いたサンプルコードの理解を深めていきたいと思います。
複数回にわたる返信ありがとうございました。
ツイート | ![]() |