SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE)
如果.dpr单元是
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
SetWindowPos置顶就起作用,
后来我改.dpr单元成
Form1:= TForm1.Create(nil);
Form1.ShowModal;
Form1.Free;
SetWindowPos就没起作用了,但是返回值还是true,不明白什么原因,求指教,谢谢!
6 个解决方案
#1
Form1:= TForm1.Create(nil);
这样建立, application 就管不上Tform1了
Form1:= TForm1.Create(nil);
Form1.ShowModal;
Form1.Free;
这已经是模态窗口了
这样建立, application 就管不上Tform1了
Form1:= TForm1.Create(nil);
Form1.ShowModal;
Form1.Free;
这已经是模态窗口了
#2
SetWindowPos起不起作用和application有关?不太明白
#3
Application在响应WM_ACTIVATEAPP时,调用了NormalizeTopMosts,而它调用DoNormalizeTopMosts,其内部EnumWindows的回调函数GetTopMostWindows中,判断了Application.MainForm = nil,如果是nil则将窗口句柄加入Application.FTopMostList,EnumWindows返回后,调用SetWindowPos改变FTopMostList中的窗口的Z-Order。
在Forms.pas可找到相关代码:
function GetTopMostWindows(Handle: HWND; Info: Pointer): BOOL; stdcall;
begin
Result := True;
if GetWindow(Handle, GW_OWNER) = Application.Handle then
if (GetWindowLong(Handle, GWL_EXSTYLE) and WS_EX_TOPMOST <> 0) and
(( Application.MainForm = nil) or PTopMostEnumInfo(Info)^.IncludeMain or
(Handle <> Application.MainForm.Handle)) then
Application.FTopMostList.Add(Pointer(Handle))
else
begin
PTopMostEnumInfo(Info)^.TopWindow := Handle;
Result := False;
end;
end;
procedure TApplication.DoNormalizeTopMosts(IncludeMain: Boolean);
var
I: Integer;
Info: TTopMostEnumInfo;
begin
if Application.Handle <> 0 then
begin
if FTopMostLevel = 0 then
begin
Info.TopWindow := Handle;
Info.IncludeMain := IncludeMain;
EnumWindows( @GetTopMostWindows, Longint(@Info));
if FTopMostList.Count <> 0 then
begin
Info.TopWindow := GetWindow(Info.TopWindow, GW_HWNDPREV);
if GetWindowLong(Info.TopWindow, GWL_EXSTYLE) and WS_EX_TOPMOST <> 0 then
Info.TopWindow := HWND_NOTOPMOST;
for I := FTopMostList.Count - 1 downto 0 do
SetWindowPos(HWND(FTopMostList[I]), Info.TopWindow, 0, 0, 0, 0,
SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOOWNERZORDER);
end;
end;
Inc(FTopMostLevel);
end;
end;
在Forms.pas可找到相关代码:
function GetTopMostWindows(Handle: HWND; Info: Pointer): BOOL; stdcall;
begin
Result := True;
if GetWindow(Handle, GW_OWNER) = Application.Handle then
if (GetWindowLong(Handle, GWL_EXSTYLE) and WS_EX_TOPMOST <> 0) and
(( Application.MainForm = nil) or PTopMostEnumInfo(Info)^.IncludeMain or
(Handle <> Application.MainForm.Handle)) then
Application.FTopMostList.Add(Pointer(Handle))
else
begin
PTopMostEnumInfo(Info)^.TopWindow := Handle;
Result := False;
end;
end;
procedure TApplication.DoNormalizeTopMosts(IncludeMain: Boolean);
var
I: Integer;
Info: TTopMostEnumInfo;
begin
if Application.Handle <> 0 then
begin
if FTopMostLevel = 0 then
begin
Info.TopWindow := Handle;
Info.IncludeMain := IncludeMain;
EnumWindows( @GetTopMostWindows, Longint(@Info));
if FTopMostList.Count <> 0 then
begin
Info.TopWindow := GetWindow(Info.TopWindow, GW_HWNDPREV);
if GetWindowLong(Info.TopWindow, GWL_EXSTYLE) and WS_EX_TOPMOST <> 0 then
Info.TopWindow := HWND_NOTOPMOST;
for I := FTopMostList.Count - 1 downto 0 do
SetWindowPos(HWND(FTopMostList[I]), Info.TopWindow, 0, 0, 0, 0,
SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOOWNERZORDER);
end;
end;
Inc(FTopMostLevel);
end;
end;
#4
总之就是在你调用SetWindowPos置顶后,Application又调用SetWindowPos取消了置顶。
#5
感谢s11ss指点,看了下这里面的代码好像只有mainform才能置顶?不是mainform要置顶的话还有什么办法吗?
#6
Application在响应WM_ACTIVATEAPP时,调用了NormalizeTopMosts之后,还会调用PostMessage(FHandle, CM_DEACTIVATE, 0, 0),会触发Application的OnDeactivate事件,在此事件中重新置顶即可。
procedure TForm1.doit(Sender: TObject);
begin
SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);
application.OnDeactivate := doit;
end;
procedure TForm1.doit(Sender: TObject);
begin
SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);
application.OnDeactivate := doit;
end;
#1
Form1:= TForm1.Create(nil);
这样建立, application 就管不上Tform1了
Form1:= TForm1.Create(nil);
Form1.ShowModal;
Form1.Free;
这已经是模态窗口了
这样建立, application 就管不上Tform1了
Form1:= TForm1.Create(nil);
Form1.ShowModal;
Form1.Free;
这已经是模态窗口了
#2
SetWindowPos起不起作用和application有关?不太明白
#3
Application在响应WM_ACTIVATEAPP时,调用了NormalizeTopMosts,而它调用DoNormalizeTopMosts,其内部EnumWindows的回调函数GetTopMostWindows中,判断了Application.MainForm = nil,如果是nil则将窗口句柄加入Application.FTopMostList,EnumWindows返回后,调用SetWindowPos改变FTopMostList中的窗口的Z-Order。
在Forms.pas可找到相关代码:
function GetTopMostWindows(Handle: HWND; Info: Pointer): BOOL; stdcall;
begin
Result := True;
if GetWindow(Handle, GW_OWNER) = Application.Handle then
if (GetWindowLong(Handle, GWL_EXSTYLE) and WS_EX_TOPMOST <> 0) and
(( Application.MainForm = nil) or PTopMostEnumInfo(Info)^.IncludeMain or
(Handle <> Application.MainForm.Handle)) then
Application.FTopMostList.Add(Pointer(Handle))
else
begin
PTopMostEnumInfo(Info)^.TopWindow := Handle;
Result := False;
end;
end;
procedure TApplication.DoNormalizeTopMosts(IncludeMain: Boolean);
var
I: Integer;
Info: TTopMostEnumInfo;
begin
if Application.Handle <> 0 then
begin
if FTopMostLevel = 0 then
begin
Info.TopWindow := Handle;
Info.IncludeMain := IncludeMain;
EnumWindows( @GetTopMostWindows, Longint(@Info));
if FTopMostList.Count <> 0 then
begin
Info.TopWindow := GetWindow(Info.TopWindow, GW_HWNDPREV);
if GetWindowLong(Info.TopWindow, GWL_EXSTYLE) and WS_EX_TOPMOST <> 0 then
Info.TopWindow := HWND_NOTOPMOST;
for I := FTopMostList.Count - 1 downto 0 do
SetWindowPos(HWND(FTopMostList[I]), Info.TopWindow, 0, 0, 0, 0,
SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOOWNERZORDER);
end;
end;
Inc(FTopMostLevel);
end;
end;
在Forms.pas可找到相关代码:
function GetTopMostWindows(Handle: HWND; Info: Pointer): BOOL; stdcall;
begin
Result := True;
if GetWindow(Handle, GW_OWNER) = Application.Handle then
if (GetWindowLong(Handle, GWL_EXSTYLE) and WS_EX_TOPMOST <> 0) and
(( Application.MainForm = nil) or PTopMostEnumInfo(Info)^.IncludeMain or
(Handle <> Application.MainForm.Handle)) then
Application.FTopMostList.Add(Pointer(Handle))
else
begin
PTopMostEnumInfo(Info)^.TopWindow := Handle;
Result := False;
end;
end;
procedure TApplication.DoNormalizeTopMosts(IncludeMain: Boolean);
var
I: Integer;
Info: TTopMostEnumInfo;
begin
if Application.Handle <> 0 then
begin
if FTopMostLevel = 0 then
begin
Info.TopWindow := Handle;
Info.IncludeMain := IncludeMain;
EnumWindows( @GetTopMostWindows, Longint(@Info));
if FTopMostList.Count <> 0 then
begin
Info.TopWindow := GetWindow(Info.TopWindow, GW_HWNDPREV);
if GetWindowLong(Info.TopWindow, GWL_EXSTYLE) and WS_EX_TOPMOST <> 0 then
Info.TopWindow := HWND_NOTOPMOST;
for I := FTopMostList.Count - 1 downto 0 do
SetWindowPos(HWND(FTopMostList[I]), Info.TopWindow, 0, 0, 0, 0,
SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOOWNERZORDER);
end;
end;
Inc(FTopMostLevel);
end;
end;
#4
总之就是在你调用SetWindowPos置顶后,Application又调用SetWindowPos取消了置顶。
#5
感谢s11ss指点,看了下这里面的代码好像只有mainform才能置顶?不是mainform要置顶的话还有什么办法吗?
#6
Application在响应WM_ACTIVATEAPP时,调用了NormalizeTopMosts之后,还会调用PostMessage(FHandle, CM_DEACTIVATE, 0, 0),会触发Application的OnDeactivate事件,在此事件中重新置顶即可。
procedure TForm1.doit(Sender: TObject);
begin
SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);
application.OnDeactivate := doit;
end;
procedure TForm1.doit(Sender: TObject);
begin
SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);
application.OnDeactivate := doit;
end;