UpdateLayeredWindowを使うには?

解決


DBOX  2005-08-15 20:00:08  No: 17066

http://hitokuso.kicks-ass.org/progtips.html
こちらのUpdateLayeredImageをDelphiで書き直してみました。
procedure TForm1.UpdateLayeredImage( _hwnd:HWND; hbmp:HBITMAP; x,y:integer);
var
  hdcScreen:HDC;
  hdcMemory: HDC;
  rect: TRect;
  _pos: TPoint;
  szWindow: SIZE;
  bf: BLENDFUNCTION;
  ptSrc: TPoint;
  ret: LongBool;
begin
  hdcScreen := GetDC( 0 );
  hdcMemory := CreateCompatibleDC( hdcScreen );
  SelectObject( hdcMemory, hbmp );
  GetWindowRect( _hwnd, rect);
  _pos := Point(rect. Left, rect.Top);
  szWindow.cx := x;
  szWindow.cy := y;
  ptSrc := Point( 0, 0 );
  with bf do begin
    BlendOp     := AC_SRC_OVER;
    BlendFlags  := 0;
    AlphaFormat := AC_SRC_ALPHA;
    SourceConstantAlpha := 255;//$FF;
  end;
  ret := UpdateLayeredWindow( _hwnd, hdcScreen, @_pos, 
                              @szWindow, hdcMemory,
        @ptSrc, 0, bf, ULW_ALPHA );
  ShowMessage(SysErrorMessage(GetLastError));
  DeleteDC( hdcMemory );
  ReleaseDC( 0, hdcScreen );
end;
しかし
UpdateLayeredWindowでエラー「パラメータが間違っています」
https://www.petitmonte.com/bbs/answers?question_id=874
こちらの方と同じ症状です。
・移植に失敗しているのか(上のソースがそもそも間違えているのか)、
・テストに使っているBMPファイルがおかしいのか分かりません。
またそれにともなって同ページのCreateRGBBitmapにも挑戦してみたのですが
HBITMAP hbmp = CreateDIBSection( dc, (BITMAPINFO*)&bh, DIB_RGB_COLORS, (void**)&bitptr, NULL, 0 );
・この一行をどう書き換えれば良いのかも分からない次第です。
以上長くなりましたがよろしくお願いします。


メラトニン  2005-08-15 20:34:35  No: 17067

以前も紹介しましたが、
http://forum.nifty.com/fdelphi/samples/01218.html
を参考にしてみてください


DBOX  2005-08-16 09:04:44  No: 17068

参考にさせていただきましたが同じく
ShowMessage(SysErrorMessage(GetLastError));
のところでエラーになります。
画像の一部分を半透明化するには?
https://www.petitmonte.com/bbs/answers?question_id=2696
メラトニンさんの
>32bit BitmapはR,G,B,Alphaの配列でデータが格納されるだけです。
>ScanLineでBitmapデータにアクセスしてください。
がヒントなのでしょうかもう一度出直してきます。
ありがとうございました。


メラトニン  2005-08-16 18:01:30  No: 17069

Delphi7以降だったかと思いますが、
TFormのAlphaBlendをTrueにしちゃいけませんよ。


DBOX  2005-08-17 08:51:55  No: 17070

SetLayeredWindowAttributesと衝突すると失敗するからですね。
なかなか苦戦しています。
偽の知性 -malfunctional intellect- - ほげる
http://d.hatena.ne.jp/tsx/20031210
こちらではDelphi自体がWS_EX_LAYEREDを先に設定していると
あるのですが、どうなんでしょうか。


メラトニン  2005-08-17 17:48:37  No: 17071

実際にテストしてみました。
Delphi7では動作確認できました。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, LWindow;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private 宣言 }
    BMP32:TBitmap;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  MakeLayer(Handle, BMP32);
end;

procedure TForm1.FormCreate(Sender: TObject);
var x,y:integer;
    P:PByteArray;
begin
  BMP32:=TBitmap.Create;
  BMP32.PixelFormat:=pf32bit;
  BMP32.Height:=ClientHeight;
  BMP32.Width :=ClientWidth;
  for Y:=0 to BMP32.Height-1 do
  begin
    P :=BMP32.ScanLine[y];
    for X:=0 to BMP32.Width-1 do
    begin
      p[x*4+0 ]:=  150 ;
      p[x*4+1 ]:=  150 ;
      p[x*4+2 ]:=  150 ;
      p[x*4+3 ]:=  150 ;
    end;
  end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 BMP32.Free;
end;

end.


メラトニン  2005-08-17 17:49:37  No: 17072

//LWindow.pas
unit LWindow;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

function MakeLayer(wHandle:HWND; LayerBmp:TBitmap):boolean;
function MakeLayer2(wHandle:HWND; LayerBmp:TBitmap):boolean;

function UpdateLayeredWindow(_hwnd:HWND; dstHDC:HDC; pptDst:PPoint;
         ASize:PSize; srcHDC:HDC; pptSrc:PPoint; crKey:COLORREF;
         var bf : BLENDFUNCTION; dwFlag:DWORD):BOOL; stdcall;

const
  WS_EX_LAYERED = $80000;
  LWA_COLORKEY  = 1;
  LWA_ALPHA     = 2;
  ULW_COLORKEY  = 1;
  ULW_ALPHA     = 2;
  ULW_OPAQUE    = 4;
  AC_SRC_ALPHA  = 1;

function UpdateLayeredWindow;
  external 'user32.dll' name 'UpdateLayeredWindow';

implementation

function MakeLayer(wHandle:HWND; LayerBmp:TBitmap):boolean;
var
  bf : TBlendFunction;
  zerop : TPoint;
  formsz : TSize;
begin
  result:=false;
  with bf do begin
    BlendOp:=AC_SRC_OVER;
    BlendFlags:=0;
    SourceConstantAlpha:=255; // 完全にALPHAをBITMAPに依存する場合
    AlphaFormat:=AC_SRC_ALPHA;
  end;
  SetWindowLong(wHandle, GWL_EXSTYLE, GetWindowLong(wHandle, GWL_EXSTYLE) or
                WS_EX_LAYERED);
  zerop.x:=0; zerop.y:=0;
  formsz.cx:=LayerBmp.Width; formsz.cy:=LayerBmp.Height;
  if not UpdateLayeredWindow(
        wHandle, 0,
        nil, // palleteを気にしないならnilでよろし
        @formsz, // フォームの大きさの指定 : 必須!
        LayerBmp.canvas.handle, // サーフェイスを定義するDC
        @zerop, // サーフェイスを定義する画像の開始点
        0, bf, ULW_ALPHA) then begin
    ShowMessage(SysErrorMessage(GetLastError));
    Exit;
  end;
  result:=true;
end;

function MakeLayer2(wHandle:HWND; LayerBmp:TBitmap):boolean;
var
  bf : TBlendFunction;
  zerop : TPoint;
  formsz : TSize;
begin
  result:=false;
  with bf do begin
    BlendOp:=AC_SRC_OVER;
    BlendFlags:=0;
    SourceConstantAlpha:=255; // 完全にALPHAをBITMAPに依存する場合
    AlphaFormat:=AC_SRC_ALPHA;
  end;
  //SetWindowLong(wHandle, GWL_EXSTYLE, GetWindowLong(wHandle, GWL_EXSTYLE) or
  //              WS_EX_LAYERED);
  zerop.x:=0; zerop.y:=0;
  formsz.cx:=LayerBmp.Width; formsz.cy:=LayerBmp.Height;
  if not UpdateLayeredWindow(
        wHandle, 0,
        nil, // palleteを気にしないならnilでよろし
        @formsz, // フォームの大きさの指定 : 必須!
        LayerBmp.canvas.handle, // サーフェイスを定義するDC
        @zerop, // サーフェイスを定義する画像の開始点
        0, bf, ULW_ALPHA) then begin
    ShowMessage(SysErrorMessage(GetLastError));
    Exit;
  end;
  result:=true;
end;

end.


メラトニン  2005-08-17 17:50:01  No: 17073

注:コピペです。


DBOX  2005-08-18 22:08:32  No: 17074

わざわざソースをありがとうございます。
再現できました。やはりBitmapの作りがおかしかったようです。
中村さんのグラフィックの本を少し読んでみたのですが、
なかなか難しくて自分はまだまだだと思い知らされました。
あと、MakeLayerとMakeLayer2のWS_EX_LAYEREDの差にも注意ですね。

蛇足ですが
ARGAS.NET
http://www.argas.net/archive/1/2004-11-08
にMikiというUpdateLayeredWindowを用いたMediaPlayerがあります。

再度お礼申し上げます。ありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加