Hello All,
I want to write a screensaver in assembly. A screensaver is like a normal program, the only difference is, that the ending is .scr instead of .exe.
I want to use mci, so that the program can be used by everyone with a windows operating system. The user need not to have directX.
I tried to start a procedure from the main program like in Iczelions Turorial part 14:
http://win32assembly.programminghorizon.com/tut14.html (http://win32assembly.programminghorizon.com/tut14.html)
The called procedure is a short program, that consists in starting the playing of the video.
include \masm32\include\winmm.inc
includelib \masm32\lib\Winmm.lib
.data
MsgOrder db "play video.wmv fullscreen repeat"
.code
start:
invoke mciSendString, addr MsgOrder, NULL, 0, 0
But when the video ist playing, how can I stop it? The main program, that contains the message loop is not active.
How can I make it, that the main program can receive messages from windows?
Key is pressed or mouse is moved-> stop the process!
Regards, Guenther
not really a "normal" exe, per se
i think it's a special dialog class....
http://msdn.microsoft.com/en-us/library/cc144066%28v=vs.85%29.aspx#About_Screen_Savers (http://msdn.microsoft.com/en-us/library/cc144066%28v=vs.85%29.aspx#About_Screen_Savers)
Good link, Dave. Thank you. :t
Gunther
i seem to recall some examples on the old forum
never wanted to write one, so i don't have one handy
There is a little bit more to screensavers than just renaming to .scr -- there are various things you need to respond to, particularly when there was user activity.
More info: http://www.wischik.com/scr/howtoscr.html (http://www.wischik.com/scr/howtoscr.html)
As for controlling your video playback, you'll have to create your own MCI window, so you have a handle to direct messages at - then you can tell it when to play and stop, but that's obviously a bit more involved than a one-liner. Start with MCIWndCreate.
Thank's Tedd for that link. :t
BTW: create thread for video and stop it, if user move mouse or hit key.
i think you can use mciSendCommand to terminate any video or audio that's playing
Quote from: TWell on November 01, 2013, 02:26:02 AM
BTW: create thread for video and stop it, if user move mouse or hit key.
How would you stop it? TerminateThread?
Thanks for the replies and the links!
@ dedndave: You are right, in the old forum are some information:
http://www.masmforum.com/board/index.php?PHPSESSID=143b067e31fa6d7971f9bd4a87780197&action=search2 (http://www.masmforum.com/board/index.php?PHPSESSID=143b067e31fa6d7971f9bd4a87780197&action=search2)
And I can stop the Video with the following Code:
mciSendString(TEXT("Close"), NULL, 0, 0);
@ jj2007:
I think I have to terminate the Video. If start a thread, then I have to get the focus back from the called thread to the calling program. Here are some possibilities:
http://www.masmforum.com/board/index.php?topic=2415.0 (http://www.masmforum.com/board/index.php?topic=2415.0)
Now I will have a closer look to the two links. I will post the code when I am ready.
Regards, Guenther
Hello,
I was not able to implement it like in the links from Dedndave and Tedd. The linker can not find "DefScreenSaverProc". I looked in the internet and found the following side:
http://www.asmcommunity.net/forums/topic/?id=21139 (http://www.asmcommunity.net/forums/topic/?id=21139)
Here they build a screensaver with Masm. The also use a definition file (like in the link from Dedndave), but I have no idea, how to work with it.
So, I wrote a screensaver two or three months ago in C#. I was able to play a video file with mci. I played it in a picture box, so that the main window has the input focus. It works sometimes. It had worked on my windows 7. Later I have installed the windows SDK. After that it doesn't work.
And on a windows 8 I got a shame error. Later I changed the framework and it runs after that.
But I want that the screensaver works on every windows and is independent which framework is used. This was the reason, to write it with using the win32 api.
So it must be possible to write it with the win32 api, too. The video is located in C:\Windows\Temp. I did the following steps:
- Create a fullscreen window
- Create a PictureBox in Win 32
- Play the video in the Picture Box
- Stop the program
Create a fullscreen windowTo create a fullscreen window I need the size of the desktop. I get this with with the GetSystemmetrix funciton:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724385%28v=vs.85%29.aspx (http://msdn.microsoft.com/en-us/library/windows/desktop/ms724385%28v=vs.85%29.aspx)
The background color should be black.
invoke CreateSolidBrush,0
mov wc.hbrBackground,eax
Create a PictureBox in Win 32In the following links this is done:
http://stackoverflow.com/questions/1754037/how-to-add-picture-box-in-win32-api-using-visual-c (http://stackoverflow.com/questions/1754037/how-to-add-picture-box-in-win32-api-using-visual-c)
http://social.msdn.microsoft.com/Forums/en-US/fe6963e8-db6e-4e5e-b145-9cef74d49b57/picturebox-in-win32c?forum=vssmartdevicesnative (http://social.msdn.microsoft.com/Forums/en-US/fe6963e8-db6e-4e5e-b145-9cef74d49b57/picturebox-in-win32c?forum=vssmartdevicesnative)
I used "static" as a class name and "SS_BITMAP" as one of the window styles. As size I used the size of the video. The value of the upper left corner of the picture box is calculated with the video size and the desktop size.
Play the video in the Picture BoxHere I found a way how to play a video in a picture box:
http://social.msdn.microsoft.com/Forums/vstudio/de-DE/8d9d3dec-368a-491b-b628-c314d2751f57/how-to-play-video-in-c2008?forum=csharpgeneral (http://social.msdn.microsoft.com/Forums/vstudio/de-DE/8d9d3dec-368a-491b-b628-c314d2751f57/how-to-play-video-in-c2008?forum=csharpgeneral)
In the .data section I declared some orders:
Order0 db "open C:\\windows\\temp\\video.wmv Type mpegvideo alias MyVideo1",0
Order1 db "window MyVideo1 handle ",0
Order2 db "seek MyVideo1 to 0",0
Order3 db "play MyVideo1 repeat",0
The handle of the picture box I got from the CreateWindowEx function in the step ago, I only have to convert this handle to a string and to cat this string to Order1.
invoke ltoa,hwndPictureBox,ADDR buffer
invoke szCatStr,ADDR Order1,ADDR buffer
Stop the program The program should stop, when it receives messages like WM_KEYDOWN or WM_MOUSEMOVE. So the parent window should have the input focus.
invoke SetFocus, hWnd
The program should react on the Message WM_MOUSEMOVE, but it doesn't if the cursor is inside the picture box. So I set the cursor out of it.
invoke SetCursorPos, x_cursor, y_cursor
The problem is, that the program receives this message although the mouse is not moved. I had to get the cursor position and compare it to the coordinates i had set the cursor to.
invoke GetCursorPos, ADDR pt
mov eax,pt.x
.IF eax!=x_cursor
invoke PostQuitMessage,NULL
.ENDIF
mov eax,pt.y
.IF eax!=y_cursor
invoke PostQuitMessage,NULL
.ENDIF
The function GetCursorPos gives the coordinates back in a Point Structure.
POINT STRUCT
x DWORD ?
y DWORD ?
POINT ENDS
pt POINT <>
My problem is, that there is still a thin grey border around it, I can still see the cursor and, the biggest problem, I still can see the task bar. In the old forum there is a solution, I will try it in the near future.
http://www.masmforum.com/board/index.php?PHPSESSID=d52d81140238854679a6a365274e53d4&topic=17221.msg144070#msg144070 (http://www.masmforum.com/board/index.php?PHPSESSID=d52d81140238854679a6a365274e53d4&topic=17221.msg144070#msg144070)
I attached the source code. If You try it, please add a file "video.wmv" in the temp dictionary.
This is my first big project in MASM32. If You have comments or ideas, what I could make better, please tell me.
Regards, Guenther
to activate a screensaver, the system sends WM_SYSCOMMAND (check the docs)
i see there is an issue with DefScreenSaverProc, however
in the masm32 version 10 package, there was a scrnsave.inc and scrnsave.lib that had DefScreenSaverProc
but, i see it's not present in the version 11 package scrnsave.inc/lib files :redface:
you might be able to make one of these work:
1) use LoadLibrary and GetProcAddress, PROTO, TYPEDEF
2) use the old versions of scrnsave.inc/lib
3) create a new scrnsave.inc/lib by updating the ones in masm32 version 11
I remember from a while back a program that allowed a desktop wallpaper that was animated. I don't remember the name,but it might be dremples or something. I found it,I don't know if there is any source or an explanation of how it was done. It also mentions it can be a screen saver.
http://www.geisswerks.com/about_drempels.html
Just checked and there is source code you can DL,not sure what language it is in,but it might offer some insights.
http://www.geisswerks.com/drempels/index.html
Source is at the second link
Hello!
@Dedndave:
I took the example from http://www.asmcommunity.net/forums/topic/?id=21139 (http://www.asmcommunity.net/forums/topic/?id=21139) and added the new old scrnsave.lib. Now I have the unresolved external symbol __except_list. But I found _except_list in the library file (I opened it with the editor). But now the linker found the missed function DefScreenSaverProc.
@anunitu:
Thanks for the links, I will have a look at them later.
Regards, Guenther
Hello,
I saw that there is one underline more in the error message (_except_list) than in the lib-file (_except_list). I added a "_" it in the .lib-file. Now comes the linker error LNK1102 (out of memory). "Not enough memory for tool to run" says msdn.
Regards, Günther
Maybe this will be helpful:
http://forum.nasm.us/index.php?topic=1749.0 (http://forum.nasm.us/index.php?topic=1749.0)
Hello,
@vogelsang:
Thanks for this interesting link.
@dedndave:
I was not able to make the screensaver run with your solution.
The best way is to play the video in fullscreen. The video is big and there is now task bar. The only problem is, that it does not react on messages like WM_KEYDOWN and WM_MOUSEMOUVE.
I found another solution!!!!
I use the timer, on every WM_TIMER message the program gets the position of the cursor and compare it with its position it had during WM_CREATE!
The only problem is, that it does not stop at keyboard pressing or mouse clicks...
But it stops if the user moves the mouse!
Best Regards, Guenther
Quote from: Guenther78 on December 22, 2013, 01:18:06 AM
I found another solution!!!!
I use the timer, on every WM_TIMER message the program gets the position of the cursor and compare it with its position it had during WM_CREATE!
Günther,
That will work in most cases but notebooks in particular may show slowly "creeping" mouse cursors. Perhaps you could compare the distance between two WM_TIMER messages, and ignore those with a one pixel value.
Cheers,
Jochen
Hi Guenter,
Im sorry I havent had any advice yet about playing a movie on windows, I only know how to use camera using capCreateWindows. Maybe capCreateWindows can open a movie file too but I havent tried it yet.
Hello!
@ jj2007
Good idea, I will implement it.
@ Farabi
playing a movie on windows works with mci, in my first example the program plays the movie in a picture box:
.data
Order0 db "open C:\\windows\\temp\\video.wmv Type mpegvideo alias MyVideo1",0
Order1 db "window MyVideo1 handle ",0
Order2 db "seek MyVideo1 to 0",0
Order3 db "play MyVideo1 repeat",0
...
.code
...
invoke mciSendString,ADDR Order0,0,0,0
invoke ltoa,hwndPictureBox,ADDR buffer
invoke szCatStr,ADDR Order1,ADDR buffer
invoke mciSendString,ADDR Order1,0,0,0
invoke mciSendString,ADDR Order2,0,0,0
invoke mciSendString,ADDR Order3,0,0,0
...
And in my second example the program plays the movie in fullscreen:
.data
Order4 db "play C:\\windows\\temp\\video.wmv fullscreen repeat",0
...
.code
...
invoke mciSendString, ADDR Order4,0,0,0
...
But the function capCreateCaptureWindow may help me in my next projects.
Best regards,
Günther
Hello!
Now I am trying to ignore differences of cursor positions with one pixel difference. Here is the code:
; Get current position
invoke GetCursorPos, ADDR pt
; Has the cursor moved more than one pixel?
mov eax,pt.x
sub eax,x_cursor
.IF eax > 1
.IF eax < -1
invoke PostQuitMessage,NULL
.ENDIF
.ENDIF
mov eax,pt.y
sub eax,y_cursor
.IF eax > 1
.IF eax < -1
invoke PostQuitMessage,NULL
.ENDIF
.ENDIF
; Save current cusor position
mov eax,pt.x
mov x_cursor,eax
mov eax,pt.y
mov y_cursor,eax
Is this all right? Do you have better ideas?
I chose 500ms for the timer. Is that to long?
Best regards,
Günther
.IF eax > 1
.IF eax < -1
See Tips, Tricks and_Traps (http://www.webalice.it/jj2006/Masm32_Tips_Tricks_and_Traps.htm), "The .if eax<0 trap"
Otherwise it looks convincing ;-)
Thanks, I will replace ".if eax<0" by ".if sdword ptr eax<0".
Günther
Hello,
the screensaver works. But I want that it plays a special Video:
http://www.youtube.com/watch?v=e2nMHAI1dU4 (http://www.youtube.com/watch?v=e2nMHAI1dU4)
I have this video file with a better quality and a darker ambient.
So I tried to implement it as an embedded resource and created a file rsrc.rc:
#define ID_VIDEO 100
ID_VIDEO RCDATA "FetteKiste.wmv"
How to use embedded binary resources is explained here:
http://blog.kowalczyk.info/article/zy/Embedding-binary-resources-on-Windows.html (http://blog.kowalczyk.info/article/zy/Embedding-binary-resources-on-Windows.html)
If the video can not be played cause it does not exist, I create the file new:
; Play the video in fullscreen
invoke mciSendString, ADDR Order4,0,0,0
.IF eax != NULL
invoke FindResource,NULL,ID_VIDEO,RT_RCDATA
mov hwndVideo,eax
invoke LoadResource,NULL,hwndVideo
mov hwndVideoData,eax
invoke LockResource,hwndVideoData
mov firstByteVideo,eax
invoke SizeofResource,NULL,hwndVideo
mov sizeOfVideo,eax
invoke CreateFile,ADDR videoname,\
GENERIC_READ or GENERIC_WRITE ,\
FILE_SHARE_READ or FILE_SHARE_WRITE,\
NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_ARCHIVE,\
NULL
mov hFile,eax
invoke WriteFile,hFile,firstByteVideo,sizeOfVideo,ADDR SizeReadWrite,NULL
invoke CloseHandle,hFile
; Try again to play the video
invoke mciSendString, ADDR Order4,0,0,0
.ENDIF
I have the problem that Avira Antivir thinks that my program have the "TR/ATRAPS.Gen" trojan. I think it has to do with the RCDATA value. If I use RT_RCDATA like in the .asm file, then the program runs and Avira is not constraining it.
But if I remove the .wmv file, the file is not created. So I have to use RCDATA in the .rc file.
I think it will be the best, if the screensaver and the video file are in the same dictionary. I mean that other people can download a zip file with the two files in it. The video is not embedded in the screensaver.
I wanted that the video file is an embedded resource that will be saved under Windows/Temp. In this folder I have writing permissions without running a program as admin. If the video file is in the same folder like the screensaver, than it can not be in the Windows/System32 (where the default screensavers are) folder, because videos can not be played from this folder (I use Windows 7).
So, I think the best way is to make a zip file with both files in it, a screensaver and a video that is played. Or do anyone of you have an idea how I can embedded and save a file without being constrained by antivirus programs? I have attached the .rc and the .asm files that works with the video file as an embedded resource.
Best Regards, Guenther
Hello,
I tried to implement another Video:
http://www.youtube.com/watch?v=RQJRfJVHT-I
The solution with the video inside the folder with the screensaver does not run. The .exe and the .scr runs, but if I installed the saver, than a small black box in the upper left of the desktop appears, that means, that the saver does not find the video.
So I got back to implement the video in the program. The program writes it to Windows/Temp.
And that works. Also if Avira is activated (see my post before). Also the problem is not the code, it is the embedded resource!
I added another file in the previous screensaver as a resource. I thought, that Avira sees some bytes in the video, that are similar to this one in a trojan. And after adding another file in the .rc file, Avira makes no trouble.
I hope, that this project is done now. But if You have some ideas, please let me know.
Regards, Guenther
you might try this routine
use RT_RCDATA as the resource type (in both the RC file and the function call)
;###################################################################################################
LoadFromRsrc PROTO :HINSTANCE,:LPSTR,:UINT
;###################################################################################################
.CODE
;***************************************************************************************************
LoadFromRsrc PROC USES EBX ESI EDI hinstLfr:HINSTANCE,lpszLfr:LPSTR,uTypeLfr:UINT
;Load From Resource - DednDave, 9-2012
;
;Call With: hinstLfr:HINSTANCE = handle of module containing the resource (NULL = current process)
; lpszLfr:LPSTR = pointer to resource name string or integer resource ordinal
; uTypeLfr:UINT = integer type of resource
;
; Returns: EAX = hgLfrData:HGLOBAL, global allocation handle or 0 if error
; ECX = uLenLfrData:UINT , size of resource data or 0 if error
; EDX = lpLfrData:LPVOID , pointer to resource data or 0 if error
;
; Note: When done using the resource data, use GlobalUnlock and GlobalFree as follows:
;
; INVOKE GlobalUnlock,hgLfrData
; INVOKE GlobalFree,hgLfrData
;--------------------------------------------
LOCAL hrsrcLfr :HRSRC
LOCAL hgLfr :HGLOBAL
LOCAL uLenLfrData :UINT
LOCAL lpLfrData :LPVOID
;--------------------------------------------
xor ebx,ebx
mov uLenLfrData,ebx
mov lpLfrData,ebx
INVOKE FindResource,hinstLfr,lpszLfr,uTypeLfr
.if eax
mov hrsrcLfr,eax
INVOKE LoadResource,hinstLfr,eax
.if eax
mov hgLfr,eax
INVOKE LockResource,eax
.if eax
xchg eax,esi
INVOKE SizeofResource,hinstLfr,hrsrcLfr
.if eax
mov uLenLfrData,eax
add eax,31
and al,-32
INVOKE GlobalAlloc,GMEM_MOVEABLE,eax
.if eax
xchg eax,ebx
INVOKE GlobalLock,ebx
.if eax
mov ecx,uLenLfrData
xchg eax,edi
mov edx,ecx
mov lpLfrData,edi
shr ecx,2
rep movsd
and edx,3
.if !ZERO?
mov ecx,edx
rep movsb
.endif
.else
xchg eax,ebx
INVOKE GlobalFree,eax
mov uLenLfrData,ebx
.endif
.else
mov uLenLfrData,eax
.endif
.endif
.endif
INVOKE FreeResource,hgLfr
.endif
.endif
mov edx,lpLfrData
xchg eax,ebx
mov ecx,uLenLfrData
ret
LoadFromRsrc ENDP
;***************************************************************************************************
Hello,
thank You for this program, dedndave. I tried to implement it. I call the function after receiving WM_CREATE:
invoke LoadFromRsrc, NULL, ID_VIDEO, RT_RCDATA
But the eax register after the call is 0, I think, that is because the allocation failed.
And if I use RCDATA instead of RT_RCDATA in the .rc file, it works. But Avira makes trouble.
I have no idea, the solution with adding a second file in the .rc works, but that is no real solution.
Regards, Guenther
Hello,
I found the error in the rc file: the value of RT_RCDATA is unknown, because the rc compiler does not know it. I had a look to windows.inc and I see that the value is 10.
#define RT_RCDATA 10
#define ID_VIDEO 100
ID_VIDEO RT_RCDATA "FetteKiste.wmv"
But Avira still does not like it.
Rgards, Guenther
Hello,
the error must be in the video file. I converted it from wmv to mpg and it runs now. Avira makes no trouble!
I have attached both .rc and .asm file. Saving an embedded resource is done with the function from dedndave, in my old code I have done it without allocating memory.
Best Regards,
Guenther
Hello,
the screensavers are ready now:
http://klingdesign.de/html/bildsch_schoner.html
You can choose between two videos, please click on the preferred picture. After downloading the zip-folder, extract it, mark the .scr-file, press the right mouse button and choose "install". We have tested it on a Windows XP, a Windows 7 and a Windows 8 Computer. If there are any problems, please tell me.
Thanks for the help in writing this application!
Best Regards,
Guenther