喫茶XRAYトップページ

[▲前のスレッド]

[10283] Msg.lParamで示されたポインタで配列を操作したい返信 削除
2016/8/10 (水) 20:32:05 taki
マスター、みなさん 助けてください。

ダブルバッファで連続して音データを再生するプログラムの一部です。
MM_WOM_DONEで返されたメッセージのMsg.lParamにwhdr1またはwhdr2の
どちらかのアドレスが格納されて返ってきます。
そのアドレスでabuf1もしくはabuf2の配列を操作したいのです。

以下がソースの一部です。長くてごめんなさい。

type
  Tabuf = array[1..44100] of smallint;

var
  abuf1:Tabuf;   // abuf1:array[1..44100] of smallint;
  abuf2:Tabuf;   // abuf2:array[1..44100] of smallint;
 
  whdr1,whdr2:Twavehdr;

// 再生開始
procedure TForm1.StartPlay;
begin
  // ウェブヘッダーをセット
  with whdr1 do
  begin
    lpdata := @abuf1;
    dwbufferlength := sizeof(abuf1);
    dwbytesrecorded := 0;
    dwUser := 0;
    dwFlags := WHDR_BEGINLOOP or WHDR_ENDLOOP;
    dwloops := 1;
    lpNext := NIL;
    reserved := 0;
  end;

  with whdr2 do
  begin
    lpdata := @abuf2;
    dwbufferlength := sizeof(abuf2);
    dwbytesrecorded := 0;
    dwUser := 0;
    dwFlags := WHDR_BEGINLOOP or WHDR_ENDLOOP;
    dwloops := 1;
    lpNext := NIL;
    reserved := 0;
  end;

  // 出力デバイスを開く
  waveOutOpen(@hwo,WAVE_MAPPER,@wfe,handle,0,CALLBACK_WINDOW);
  // 波形データを準備する
  waveOutPrepareHeader(hwo,@whdr1,sizeof(Twavehdr));
  waveOutPrepareHeader(hwo,@whdr2,sizeof(Twavehdr));
  //
end;

// ここが問題の手続き
procedure SetWaveData(buf:Pointer);  // 引数で受け取る時はPointer型
var
  i:integer;
begin
  for i := 1 to Length(buf) do begin   // 内部では配列として操作したい
    buf[i] := XXX;
  end;
end;

// メッセージ処理
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
begin

  ・・・略・・・

  // MM_WOM_DONE ///////////////////////
  if Msg.message = MM_WOM_DONE then begin

  // Msg.lParam には、出力バッファを表す WAVEHDR 構造体へのポインタが格納されています

  // SetWaveData手続きでabuf1もしくはabuf2にデータをセットする
    SetWaveData(Twavehdr(Pointer(Msg.lParam)^).lpData));  // <-ここで使いたい

 // waveOutWrite(hwo,@whdr1,sizeof(Twavehdr));
    waveOutWrite(hwo,Msg.lParam,sizeof(Twavehdr));  // <-こんな感じでも使えるかも
 
  end;

  ・・・略・・・

end;


Tabuf(buf)とかすると、「正しくない型キャスト」と叱られてしまいました。


[10284] Re: Msg.lParamで示されたポインタで配列を操作したい返信 削除
2016/8/10 (水) 22:16:49 Mr.XRAY
▼ takiさん

> そのアドレスでabuf1もしくはabuf2の配列を操作したいのです。

こういうのは難しいですね.
コーディングの好みもあるかも知れません.
メッセージの処理の部分だけ.例えばです.

動作確認は Windows 7 U64(SP1) + Delphi XE(UP1) Pro です.

implementation

{$R *.dfm}

type
  Tabuf = array[1..44100] of smallint;

var
  abuf1:Tabuf;

procedure TForm1.Button1Click(Sender: TObject);
begin
  abuf1[1] := 100;
//  PostMessage(Handle, MM_WOM_DONE, 0, LPARAM(@abuf1[1]));
  PostMessage(Handle, MM_WOM_DONE, 0, LPARAM(@abuf1));
end;

// 引数の型をTaBufにした方が処理がしやすいかな,と...
procedure SetWaveData(var buf: Tabuf);
begin
  buf[1] := buf[1] + 500;
  buf[3] := 133;
end;

procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
var
  LpBuf : ^Tabuf;
  LText  : string;
begin
  if Msg.message = MM_WOM_DONE then begin
    LpBuf := Pointer(Msg.lParam);
    SetWaveData(LpBuf^);

    LText := IntToStr(LpBuf[1]) + sLineBreak +  IntToStr(LpBuf[3]);
    MessageBox(Handle, PChar(LText), '結果', MB_ICONINFORMATION);
  end;
end;



[10285] Re2: Msg.lParamで示されたポインタで配列を操作したい返信 削除
2016/8/10 (水) 22:39:21 Mr.XRAY
>     LText := IntToStr(LpBuf[1]) + sLineBreak +  IntToStr(LpBuf[3]);

逆参照なので正確には以下ですが,ほとんど^は省略可能でしたよね...

    LText := IntToStr(LpBuf^[1]) + sLineBreak +  IntToStr(LpBuf^[3]);


[10286] ポインタ型を定義する方法もある返信 削除
2016/8/10 (水) 22:56:30 Mr.XRAY
> コーディングの好みもあるかも知れません.

よく見かけるのは,Type 宣言の時にポインタ型も定義してしまうやつですね.

type
  Pabuf = ^Tabuf;      //分かりにくかったら PTabuf でもいいと思う...
  Tabuf = array[1..44100] of smallint;

そうするとキャストの処理の見通しがよくなる場合があります.
Pointer 等という味気のないのを使う必要がなくなります.

procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
var
  LpBuf : Pabuf;
  LText : string;
begin
  if Msg.message = MM_WOM_DONE then begin
    LpBuf := Pabuf(Msg.lParam);
    SetWaveData(LpBuf^);

    LText := IntToStr(LpBuf[1]) + sLineBreak +  IntToStr(LpBuf[3]);
    MessageBox(Handle, PChar(LText), '結果', MB_ICONINFORMATION);
  end;
end;


[10287] Re: ポインタ型を定義する方法もある返信 削除
2016/8/10 (水) 23:09:09 Mr.XRAY
> よく見かけるのは,Type 宣言の時にポインタ型も定義してしまうやつですね.

そうすると,SetWaveData(LpBuf) の引数の逆参照を使わずに
以下のように SetWaveData の引数にポインタ型が使用でき,
var が必要なくなります.

procedure SetWaveData(buf: Pabuf);
begin
  buf[1] := buf[1] + 500;
  buf[3] := 133;
end;


[10288] Re2: ポインタ型を定義する方法もある返信 削除
2016/8/11 (木) 07:41:39 taki
▼ Mr.XRAYさん
> > よく見かけるのは,Type 宣言の時にポインタ型も定義してしまうやつですね.
>
> そうすると,SetWaveData(LpBuf) の引数の逆参照を使わずに
> 以下のように SetWaveData の引数にポインタ型が使用でき,
> var が必要なくなります.
>


マスター ありがとうございます。

ありがたや、ありがたや。


[10289] Re3: ポインタ型を定義する方法もある返信 削除
2016/8/11 (木) 12:10:10 Mr.XRAY
>type
>  Pabuf = ^Tabuf;      //分かりにくかったら PTabuf でもいいと思う...
>  Tabuf = array[1..44100] of smallint;


このようなポインタ型の使用は,実はかなり強力です.
Pointer では型の情報は分かりません.
上の Pabuf は Tabuf のポインタ型というのが明確です.

特にレコード型のメンバを操作する時は便利です.
VCL のソースコード内をみてみると多くのレコード型で定義されています.


[10293] Re4: ポインタ型を定義する方法もある返信 削除
2016/8/11 (木) 16:29:31 Mr.XRAY
> このようなポインタ型の使用は,実はかなり強力です.

でも,ほら,敷居が高いとか難解とか言う人には無理かも知れません.
そのような方は,あきらめるしかないでしょう.
ホホホッ.ワーハッハハ ...


[10296] Re5: ポインタ型を定義する方法もある返信 削除
2016/8/12 (金) 20:57:47 Mr.XRAY
> でも,ほら,敷居が高いとか難解とか言う人には無理かも知れません.

ですが,折角なので記事にしました.

[メッセージの引数に配列を渡す例 - ポインタ型の定義]
http://mrxray.on.coocan.jp/Delphi/Others/TypeArray.htm#07


[10297] Re6: ポインタ型を定義する方法もある返信 削除
2016/8/14 (日) 14:38:39 Mr.XRAY
> [メッセージの引数に配列を渡す例 - ポインタ型の定義]
> http://mrxray.on.coocan.jp/Delphi/Others/TypeArray.htm#07


タイトルを内容に合わせて変更しました.
TBitmap の例も書いておきました.
PostMessage ではなく SendMessage を使用しています.

足が短くて,あるいはメタボのために「敷居が高い」と思う方は無理かもしれません.


[10303] TObjectと型キャスト返信 削除
2016/8/16 (火) 21:36:11 Mr.XRAY
いい題材があったので,ついでに
質問のタイトルはちょっと ? ですが.

[Bool(StringGrid1.Objects[4,i])をtrueにセットしたいのですが]
https://forums.embarcadero.com/thread.jspa?threadID=228954&tstart=0

配列をメッセージに渡す時は配列ですが,
取り出す時は,どんな型として取り出すかを決めない正しく取り出せません.
よく使用されている Sender: TObject と同じです.

procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Lines.Text := 'テスト文字列';
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  LText : string;
begin
  //TObjectには何でも入っちゃう
  Sender := Memo1;

  //取り出す時は何として取り出すのかを指定する
  LText := TMemo(Sender).Text;
  MessageBox(Handle, PChar(LText), '結果', MB_ICONINFORMATION);
end;



[10305] Re:TObjectと型キャスト返信 削除
2016/8/17 (水) 07:10:30 Mr.XRAY
>   //TObjectには何でも入っちゃう
>   Sender := Memo1;


Sender は TObject です.
TMemo のご先祖様は TObject です.
したがって,そのまま代入できます.

そうではない Integer, String 型のような単純型の場合は,次のようにできます.

procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Lines.Clear;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  LIntValue : Integer;
begin
  //TObjectには何でも入っちゃうけど...
  //SenderはTObjectなのでTObjectでキャストする
  //TMemo等は大元がTObjectなのでキャストの必要はない
  Sender := TObject(150);

  //取り出す時は何として取り出すのかを指定する
  LIntValue := Integer(Sender);
  Memo1.Lines.Add(IntToStr(LIntValue));
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  LpStrText : PString;
  LText     : string;
begin
  //文字列は,動的なメモリ領域を確保してから
  New(LpStrText);

  try
    //逆参照でポインタ型の変数代入して
    //SenderはTObjectなのでTObjectでキャストする
    //TMemo等は大元がTObjectなのでキャストの必要はない
    LpStrText^ := 'Delphi-ABC';
    Sender     := TObject(LpStrText);

    //取り出す時は何として取り出すのかを指定する
    //これも逆参照で実の値を取り出す
    LText := PString(Sender)^;
    Memo1.Lines.Add(LText);
  finally
    //動的に確保したメモリ領域は解放しなければならない
    Dispose(PString(TObject(Sender)));
  end;
end;



[10306] Re2:TObjectと型キャスト返信 削除
2016/8/17 (水) 07:20:57 Mr.XRAY
>   Sender := TObject(150);
>
>   //取り出す時は何として取り出すのかを指定する
>   LIntValue := Integer(Sender);


で,問題のコミュニティの TStringGrid の場合ですが,
  TStringGrid.Objects[XX,XX] は TObject 型なんです.
論理型のご先祖様は TObject ではありません(ご先祖様いたっけ ?).
したがって,Integer, String 型と同じように,単純型と同じようにします.

毎日開発で忙しいとは思いますが,こういう機会に勉強しておくと,

『ありがとうございました.おかげでメモ帳を起動することができました.
そこで,少し欲張って今度はエクセルを起動したいと思っています.
エクセルはどのように起動したらよいのでしょうか ?』

という質問をしなくても済むようになるかも知れません.
(欲張らなくてもいいから... (^^; )


えっ? 奥歯に何か挟まっているような感じがする ?
そうですか,でもあまり気にしない方がいいですよ.
あまり気にするとハゲますから.
えっ ? もうハゲている ? そうですか.ホホホ.

続きは,またいい題材を見つけたらということで.


[10294] Re4: ポインタ型を定義する方法もある返信 削除
2016/8/11 (木) 16:33:31 taki
▼ Mr.XRAYさん
 
> このようなポインタ型の使用は,実はかなり強力です.
> Pointer では型の情報は分かりません.
> 上の Pabuf は Tabuf のポインタ型というのが明確です.
>


マスターのおかげでプログラムは動くようになりました。

Pointer型だけでは型の情報が無いので、
Tabuf = array[1..44100] of smallint; を定義する事まで
思いついたのですが、それからが分かりませんでした。

SetWaveData()手続きで引数を受け取る前に型キャストするべき
だったのですね。

ポインタを手続きの引数で扱う時の注意については、
「今更きけない 動的配列…」でも学習したはずなんだけどなぁ。
「壁」を乗り越えられていなかったみたい。

いや、忘却(もしくは加齢)と言う絶望的な「壁」かも…。


[10295] 優秀な頭脳返信 削除
2016/8/11 (木) 16:40:50 Mr.XRAY
> 「今更きけない 動的配列…」でも学習したはずなんだけどなぁ。
> 「壁」を乗り越えられていなかったみたい。


ホホホッ.
私は,人にパソコン関係を教える時はこう言っています.

『分からなくなったら,何度でも同じこと訊いて.
でも,私と違って,自分は 1 回訊いただけで完全に理解できる脳みそを
持っているという自信があるなら別だけどね』

今,オリンピックの最中です.
水泳,体操が話題になっていますが,どんな選手も,何回も何回も同じことを
練習しているんです.


[▼次のスレッド]
INCM/CMT
Cyclamen v3.82