[WinApi] Wyświetlanie tekstu na pulpicie

0

Witam.
Mam mały problem z wyświetlaniem tekstu na pulpicie.
Wyświetlam go za pomocą :

 PAIN:
    begin
      InvalidateRect(GetDesktopListViewHandle,@r,true);
      DC := BeginPaint(GetDesktopListViewHandle, PS);
      SetBkMode(DC, TRANSPARENT);
      SetTextColor(DC, RGB(255, 255, 255));
      i:=1;
      case dzien of
      0:  AssignFile(tf, 'plan/pn.pln');
      1:  AssignFile(tf, 'plan/wt.pln');

      2:  AssignFile(tf, 'plan/sr.pln');

      3:  AssignFile(tf, 'plan/cz.pln');

      4:  AssignFile(tf, 'plan/pt.pln');

      end;
      Reset(tf);
      While not eof(tf) do
        begin
          Readln(tf, s);
          i:= i +17;
          TextOut(DC, 1024 - 200, i, Pchar(s), Length(s));
        end;
        CloseFile(tf);
      EndPaint(GetDesktopListViewHandle, PS);
    end;

Mój DLL'ka z hookiem wygląda tak:


  If pcws.hwnd = GetDesktopListViewHandle then
  case pcws.message of
    WM_PAINT:
        PostMessage(FindWindow('Program', nil), PAIN, 0, 0);

No i niby wszystko powinno działać, jednak gdy jakieś okno pokaże się na pulpicie bądź zasłoni częściowo napis, on znika.

Gdyby po zasłonięciu napisu znikał, dałoby się to przeżyć, ale jak np. otworze okienko gg, które jest na drugim końcu ekranu, mój napis nagle znika, czasem pojawia się po kliknięciu na pulpit, czasem sam.
Ogólnie wariuje.
Chciałbym zrobić zwykły napis, który po prostu by tam był, niezależnie od tego co jeszcze jest na pulpicie.
Pomocy !

0

Takie rzeczy realizuje się własnym oknem, a nie rysowaniem po pulpicie, który system ma prawo odmalować, kiedy mu się żywnie podoba.

0

taaa, i w tym jest właśnie problem, nie da się tego w żaden sposób zrobić, żeby działało ?

Formy pokazane w linku, który podałeś są pamięciożerne, a moja aplikacja prawie nic nie zżera.

Edit: Co do Twojej propozycji, miejsce w pamięci jeszcze ujdzie, bardziej natomiast denerwuje mnie to, że niewiem jak usunąć takie okno z menu pod Alt-Tab.

Szukałem wszędzie, ale żadne z podanych rozwiązań nie działa.

0

Żadna z przedstawionych form, z wyjątkiem ustawienia przezroczystości pikseli z zachowaniem komponentów, nie jest pamięciożerna.

Usunięcie spod ALT+TAB to tylko kwestia ustawienia parametrów stylu okna, ewentualnie okna rodzica.

0

Byłbym niezmiernie wdzięczny jeśli mógłbyś podać kodzik.

0

Szkielet całości okna mógłby być taki:

program Project1;

uses
  Windows, Messages, Graphics, Types;

function WndProc(Wnd: HWND; uMsg: UINT; wPar: WPARAM; lPar: LPARAM): LRESULT; stdcall;
begin
Result := 0;
case uMsg of
  WM_DESTROY: PostQuitMessage(0);
  else Result := DefWindowProc(Wnd, uMsg, wPar, lPar);
  end;
end;

function CreateBitmap(Width:integer; Height:integer; PixelFormat:TPixelFormat):TBitmap;
begin
result:=TBitmap.Create;
result.Width:=Width;
result.Height:=Height;
result.PixelFormat:=PixelFormat;
end;

procedure DrawLayered(Window:THandle);
var blend:BLENDFUNCTION;
    P:TPoint;
    S:TSize;
    RGBA,RGB,A:TBitmap;
    X,Y:integer;
    RGBAPixel:PRGBQuad;
    RGBPixel:PRGBTriple;
    APixel:PByte;
begin
//Przygotowywanie bitmapy
RGBA := CreateBitmap(100, 100, pf32bit);
RGB := CreateBitmap(100, 100, pf24bit);
A := CreateBitmap(100, 100, pf8bit);
try

  {RYSOWANIE PO KANALE RGB}
  {RYSOWANIE PO KANALE Alpha}

  for Y := RGBA.Height-1 downto 0 do
    begin
    RGBAPixel:=RGBA.ScanLine[y];
    RGBPixel:=RGB.ScanLine[y];
    APixel:=A.ScanLine[y];
    for X := 0 to RGBA.Width-1 do
      begin
      //APixel^:=255-APixel^;
      RGBAPixel.rgbReserved := APixel^;
      RGBAPixel.rgbRed := MulDiv(RGBPixel.rgbtRed, APixel^, 255);
      RGBAPixel.rgbGreen := MulDiv(RGBPixel.rgbtGreen, APixel^, 255);
      RGBAPixel.rgbBlue := MulDiv(RGBPixel.rgbtBlue, APixel^, 255);

      inc(RGBAPixel);
      inc(RGBPixel);
      inc(APixel);
      end;
    end;

//Nakładanie bitmapy
  P.X := 0;
  P.Y := 0;
  S.cx := RGBA.Width;
  S.cy := RGBA.Height;
  blend.BlendOp := AC_SRC_OVER;
  blend.BlendFlags := 0;
  blend.AlphaFormat := AC_SRC_ALPHA;
  blend.SourceConstantAlpha := 255;
  UpdateLayeredWindow(Window, GetDC(0), nil, @S, RGBA.Canvas.Handle, @P, 0, @blend, ULW_ALPHA);
finally
  RGBA.Free;
  RGB.Free;
  A.Free;
  end;
end;


var WindowClass:TWndClass;
    Window:THandle;
    Message:TMsg;
begin
ZeroMemory(@WindowClass, sizeof(WindowClass));
WindowClass.lpszClassName := 'Gadżet';
WindowClass.hCursor:=LoadCursor(0, IDC_ARROW);
WindowClass.lpfnWndProc := @WndProc;
WindowClass.hInstance := hInstance;
WindowClass.hbrBackground := COLOR_WINDOW;

RegisterClass(WindowClass);
Window:=CreateWindowEx(WS_EX_TOOLWINDOW or WS_EX_LAYERED, WindowClass.lpszClassName, 'RSS Gadget', WS_POPUPWINDOW or WS_VISIBLE, 100, 100, 200, 200, GetDesktopWindow(), 0, hInstance, nil);
SetWindowPos(Window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE);
SetParent(Window, GetDesktopWindow());
DrawLayered(Window);

while GetMessage(Message, 0, 0, 0) do DispatchMessage(Message);

DestroyWindow(Window);
UnregisterClass(WindowClass.lpszClassName, hInstance);
end.
0

Hmm, teraz podałeś mi szkielet programu w WinApi, ale szczerze mówiąc niewiele rozumiem z tego kodu, więc również nie wiem jak np. coś tam napisać.

Nie ma jakiegoś kodu po prostu na usunięcie programu (z formami) z alt-tab ?
Bo coś mi się wydaje, że zanim zrozumiem kod, który mi podałeś minie sporo czasu.
Ja osobiście myślałem nad 3 sposobami wyświetlenia tekstu na pulpicie:

1.Poprzez to co napisałem wyżej (czyli obsługa WM_PAIN);
2.Stworzenie 'STATIC'a na pulpicie ( jak na razie najlepsze, aczkolwiek przeszkadza to, że ma tło);
3.Stworzenie zwykłej formy przyklejonej do pulpitu. (przeszkadza obecność programu w alt-tab);

No i teraz mam 4 rozwiązanie ;) Zrozumienie Twojego kodu (najprawdopodobniej się z tym pomęczę).

W każdym razie dziękuje, w pewnym sensie mi pomogłeś.

0

Zmień styl okna na WS_EX_TOOLWINDOW, jak w powyższym przykładzie.

To co dałem powyżej, to pełna, działająca aplikacja pokazująca coś (na przykład tekst - miejsce rysowania oznaczyłem komentarzem) na pulpicie - jeszcze z uwzględnioną przezroczystością, bez rysowania po samym oknie pulpitu.

0

Dobrze, więc nie zagłębiając się w tajemnice Twojego kodu, mógłbyś mi tylko powiedzieć gdzie zmienić tło na czarne ? Albo jakby się dało zrobić tak aby tło było przezroczyste, a napis nie.

na razie wygląda to tak:

try

  rgb.Canvas.Font.Color:= clRed;
  rgb.Canvas.TextOut(2, 2, 'aaaaaaa');


  for Y := RGBA.Height-1 downto 0 do
{............}
0

Musisz rysować jednocześnie po obu warstwach: RGB to rysunek, A to przezroczystość. Chcesz tło czarne, zmieniasz na RGB. Chcesz pokazać nieprzezroczysty napis na przezroczystym tle, na RGB rysujesz napis w wybranym kolorze, A wypełniasz na czarno i na biało rysujesz napis - czyli w miejscu napisu forma nie będzie przezroczysta.

0

Wielkie dzięki !
Naprawdę bardzo mi pomogłeś.
jeszcze raz dzięki :)

Edit:
Mam jeszcze jedno mały pytanko:
Jak wysłać jakiś komunikat do tego programu ?

w dll'ce daje

PostMessage(FindWindow('Program', nil), WPRAWO, 0, 0);

Oczywiście zmieniłem nazwę pliku, class name.

w programie mam:

WPRAWO:
      messagebox(getdesktoplistviewhandle, 'aa', 'aa', mb_iconinformation);

I nie działa.
Natomiast jak w dll'ce zaraz przed PostMessage dam messagebox(...) to się wyświetla, a więc problem musi być z dostarczaniem komunikatu.
O co może chodzić ?

0

Jest jeszcze lepszy sposób na wyświetlanie czegoś na pulpicie. To się nazywa OVERLAYER [!!!] Są na necie dostępne źródła w C++.

0
mgyver napisał(a)

Jest jeszcze lepszy sposób na wyświetlanie czegoś na pulpicie. To się nazywa OVERLAYER [!!!] Są na necie dostępne źródła w C++.

Tja.. jasne. Po pierwsze nazywa się Overlay, po drugie pochodzi z przestarzałego DirectX7 (bo nowe już nie wspierają), a po trzecie służy do rysowania nie po pulpicie, a pod ikonami zamiast tapety. Poczytaj może, dlaczego sam Microsoft nie zaleca jego użycia, zanim wyskoczysz z taką podpowiedzią.

Co do samego tematu: ta DLL współpracuje z aplikacją, czy jest uruchamiana w osobnej? Jeśli współpracuje, to po prostu przekaż jej od razu uchwyt okna, do którego chcesz słać komunikaty.

0

DLL'ka współpracuje. Jest to dll z hookiem który wyłapuje naciśnięcie przycisków które są tworzone na pulpicie.

(wyłapanie naciśnięcia działa prawidłowo, problem jest z przesłaniem komunikatu)

Więc idąc za Twoją radą zrobiłem tak:

zmieniłem trochę procedure SetHook, tak aby od razu przesyłała uchwyt a więc:

procedure SetHook(H: hwnd); stdcall; external 'ProjHook.dll' name 'SetHook';

a w DLL'ce :

Procedure SetHook(H: hwnd); stdcall;
begin
  Hwin := h;
  Hok := SetWindowsHookEx(WH_CALLWNDPROC, @SysMsgProc, Hinstance, 0);
end;

no i wysyłanie:

PostMessage(Hwin, WPRAWO, 0, 0);

ale nadal nie działa ?
Nie wiem co jest nie tak.

a no i jeszcze w programie:

WM_CREATE:
    begin
      SetHook(Window);
{...}

EDIT:
Błąd tkwi raczej w odbieraniu komunikatów przez aplikacje.
Jak daję np.

PostMessage(findwindow('Proj', 0), WM_DESTROY, 0, 0);

w całkiem innej aplikacji, nic się nie dzieje.
Może to program po prostu nie odbiera komunikatów ?

EDIT 2:

Problem rozwiązany.
Uchwyt okna pobrałem tak:

function GetProgHWND: THandle; stdcall;
var
  S: String;
begin
  Result := GetDesktopListViewHandle;
  Result := GetWindow(Result, GW_CHILD);
  SetLength(S, 40);
  GetClassName(Result, PChar(S), 39);
  if PChar(S) <> 'Proj' then
    Result := 0;
end;

gdyż wcześniej przeoczyłem procedure:

SetParent(Window, GetDesktopListViewHandle);

w programie. :)

Jeszcze raz bardzo dziękuję za pomoc.
Pozdro.

0

Witam ponownie, stwierdziłem, że nie ma po co zakładać nowego tematu, ponieważ problem tyczy się w sumie tego w temacie.

Wiem już jak rysować, pisać coś na pulpicie, niewiem natomiast jak stworzyć np. 2 takie okna.

Chodzi mi o to, żebym np. jeden napis narysował w górnym rogu, a drugi w dolnym.
Można to zrobić rozciągając canvas na cały ekran, jednak wtedy widać dosyć przeszkadzające przycinanie okien na pulpicie.

Dlatego chciałbym zrobić 2 takie okna jedno na dole a drugie na górze :)
Ale nie mam pojęcia jak to zrobić czy wywoływać te funkcje :

  Window:=CreateWindowEx(WS_EX_TOOLWINDOW or WS_EX_LAYERED, 'Prog',
  'Prog',WS_VISIBLE, 800, 20, 250, 250, GetDesktopListViewHandle, 0, hInstance, nil);

  SetWindowPos(Window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE);
  SetParent(Window, GetDesktopListViewHandle);
  DrawLayered(Window);

dla każdego nowego takiego okna ? czy może jakoś inaczej.
Proszę o pomoc.

0

Oczywiście, że dla każdego musisz wywołać osobno. Jak w końcu inaczej stworzysz (bo to robi te kilka linii) osobne, przezroczyste okna?

Oczywiście, aby potem się do nich odwoływać, zapamiętaj ich uchwyty pod osobnymi zmiennymi. W ogóle to zajrzyj do MSDN i dowiedz się, co poszczególne funkcje robią.

0

Hmmm ale jak potem poradzić se z obsługą komunikatów ?
Bo jak stworze powiedzmy dwa okna...to komunikaty i z pierwszego i drugiego będą przerabiane przez jedną funkcję WndProc ?
Trochę to poplątane :)

0

No i jaki w tym problem? Przejrzałeś chociaż jak zbudowana jest owa funkcja? Gdybyś to zrobił, wiedziałbyś, że jako pierwszy argument podawany jest uchwyt okna, dla którego obsługiwany jest komunikat, a więc możesz swobodnie obsłużyć okna w różny sposób.

1 użytkowników online, w tym zalogowanych: 0, gości: 1