Screensaver Preview framework
BlitzMax Forums/BlitzMax Programming/Screensaver Preview framework
| ||
I have seen a lot of interest in this recently, so I decided to try and convert my original Blitz+ work on this subject over to BlitzMax. The results so far are promising, but I have run into a few issues I'm hoping the community can help me solve. First, the code:Strict ' // Framework & Modules //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%// Framework BRL.GLMax2D Import BRL.Basic Import BRL.System Import BRL.Retro Import "-lshell32" ' // Win32 API //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%// Extern "win32" Function FindWindow(className:Byte Ptr, titleName:Byte Ptr) = "FindWindowA@8" Function SetWindowPos(hWnd, after, x, y, w, h, flags) Function GetWindowLong(hwnd, nIndex) = "GetWindowLongA@8" Function SetWindowLong(hwnd, index, nIndex) = "SetWindowLongA@12" Function SetParent(hWnd, parenthWnd) Function FindWindowEx(hWnd1, hWnd2, lpsz1:Byte Ptr, lpsz2:Byte Ptr) = "FindWindowExA@16" End Extern Local a$, bPre = False For a$ = EachIn AppArgs If Instr(a$, "/p", 1) > 0 Then bPre = True; Exit Next If bPre = False Then End Graphics 152, 112, 0', -1 Local bmx_hWnd = FindWindow("BlitzGL Window Class", "BlitzGL Window") If bmx_hWnd = 0 Then Notify "Blitz Window Not Found!"; End Local bmx_Style = GetWindowLong(bmx_hWnd, -16) bmx_Style = bmx_Style And $40000000 Or $800000 And $10000000 SetWindowLong bmx_hWnd, -16, bmx_Style; Delay 10 Local pre_hWnd = FindWindow("#32770", "Display Properties") If pre_hWnd = 0 Then Notify "Display Properties Window Not Found!"; End pre_hWnd = FindWindowEx(pre_hWnd, 0, "#32770", "Screen Saver") If pre_hWnd = 0 Then Notify "Screen Saver Window Not Found!"; End Local static_hWnd = FindWindowEx(pre_hWnd, 0, "Static", "") If static_hWnd = 0 Then Notify "Static Window Not Found!"; End pre_hWnd = FindWindowEx(static_hWnd, 0, "SSDemoParent", "") If pre_hWnd = 0 Then Notify "Preview Window Not Found!"; End SetParent bmx_hWnd, pre_hWnd; Delay 10 SetWindowLong bmx_hWnd, -8, pre_hWnd; Delay 10 SetWindowPos bmx_hWnd, -2, 0, 0, 152, 112, $4 Or $10 Or $40 SetClsColor 0, 0, 128 Local X = -75 Repeat Cls DrawText "Testing...", X, 52 If X < 152 Then X:+1 Else X = -75 pre_hWnd = FindWindow(Null, "Display Properties") FlushMem; Flip Until pre_hWnd = 0Compile as a non GUI app and rename to .scr, then place it in your System/32 directory to test the preview. Current problems: - If built in GUI mode, there is a long delay before the preview becomes visible - Preview stays visible when switching to other screensavers. - Doesn't close if rundll32.exe persists. Why rundll32 sometimes stays open even after the display window has closed is unknown. I'm thinking these problems are being caused by something in the BMax window style. Hopefully we can sort this out and make an open source solution for everyone - thank you. |
| ||
GREAT JOB EIKON! as always... :) |
| ||
Hello Eikon, I am netmaestro and I'm pleased to meet you. I'm very pleased to see this work of yours as I am finding it quite instructive. I am replying because I recently wrote a dll in Delphi for gamemaker programmers to use which serves this purpose. I also ran into the "refusing to quit" behavior and solved it quite effectively by making a call to the win32 dll in every step and returning true or false depending upon what IsWindowVisible(<PreviewWnd>) returns. If it comes back false, your saver should leap upon its sword without further ado. Incorporate that and I'm pretty sure most of your problems are solved. btw, if you are into gamemaker at all you can find my dll with a sample program and docs at http://www.networkmaestro.com/gm_sslib2.zip |
| ||
Hi, Eikon, me again. I just noticed that in preview mode you are issuing the command graphics 152, 112, ... etc. You don't need to do this. The SetWindowPos call instructs Windows to give your program 152 x 112 and Windows will automatically scale your 800 x600 (or whatever) window to run in this space. You don't have to worry about it. I've seen programmers write savers in two complete versions, one to run in the prev and one to run normal, and that's just a whole lot of work for nothing. |
| ||
Sorry to keep posting to this, but there is one other thing you have to do: You must create either a mutex object or a semaphore on entry and end if the creation fails. That is to prevent a second instance of your program from starting if another is already running. Tell you what, why don't I show you the full source code of my gm_sslib2.dll (which works perfectly btw): library gm_sslib2; There is really nothing to it. uses SysUtils, Classes, Windows; function SetProcessLock(SemIn: String): Double; cdecl; var MySem: THandle; SemTest: PChar; begin result := 1; SemTest := PChar(SemIn); MySem := CreateSemaphore(nil,0,1,SemTest); if ((MySem <> 0) and (GetLastError = ERROR_ALREADY_EXISTS)) then begin CloseHandle(MySem); Result := -4; end; end; function WndAssign(wndprev: string; wndgame: string): double; cdecl; var gamewnd, prevwnd: hwnd; myrect: Trect; begin gamewnd := strtoint(wndgame); prevwnd := strtoint(wndprev); setparent(gamewnd,prevwnd); getwindowrect(prevwnd, myrect); movewindow(gamewnd,0,0,myrect.Right-myrect.Left,myrect.Bottom-myrect.Top,true); result := 0; end; function CheckVisible(wndprev: string): Double; cdecl; var prevwnd: hwnd; begin prevwnd := strtoint(wndprev); if not iswindowvisible(prevwnd) then result := -4 else result := 1; end; exports SetProcessLock, WndAssign, CheckVisible; begin end. |