Cruncher

I'm writing a screensaver in VB .NET 2003 and everything works fine except for the preview feature (the /p <hwnd> command). I tried to get the native window for the specified hwnd but got Nothing back. The documentation for this method (.FromHandle) states that the window must be in the same process, which in this case, it isn't.

Is there a way to create a VB .NET form that is the child of a window in another process



Re: Visual Basic General Preview option in Screensaver and .NET

Bruno Yu - MSFT

CJB3BHL,

1. You can't create such a form. Windows doesn't allow a window to be owned by or to be a child of a window that is not in the same process.

2. According to your problem on preview feature of ScreenSaver, I would like to provide you the following article and hope that can help you with the problem:

Handling Screen Savers

http://msdn2.microsoft.com/zh-cn/library/aa969288.aspx

There are three required functions in a screen module: ScreenSaverProc, ScreenSaverConfigureDialog, RegisterDialogClasses. You are able to get useful information on these Screen Saver functions.

3. There is also a full example in KB article on creating Screen Saver in VB.NET, hope that can provide you some idea, too:

How to create a screen saver by using Visual Basic .NET or Visual Basic 2005

http://support.microsoft.com/kb/818359/

This step-by-step article describes how to create a screen saver by using Microsoft Visual Basic .NET or Microsoft Visual Basic 2005. You can develop a marquee screen saver with a configuration form. You can build, you can test, and you can register the screen saver in the \Windows directory.






Re: Visual Basic General Preview option in Screensaver and .NET

Matt_Fomich

There is a standard set of API's to create the preview Window in the Screensaver tab of the Windows Display Properties form. Windows exposes the handle for the preview Window, each time you select a screensaver in the list, which is how they are each able to show a "preview thumnail".

I am not saying it can't be done, but when I looked for a managed example, I could not find a managed .Net screensaver that did not use API calls to show the preview thumbnail, which is probably why Microsoft's .Net examples omit the preview window.

I am sure you have noticed that whenever the "/p" argument is passed to your screensaver, it is followed by a space, and then a number. That number is the Windows handle that you need for thumbnail preview Window. To use the Windows Hwnd, make a form, set it to the size of the preview handle, and set the preview handle as your form's parent "form", and run it.

Here's an example of a class that makes a preview thumbnail, from my Donnie Darko Screensaver app. Note that the DisplayPreviewForm sub requires an integer value argument, which is the handle that Windows supplies.

Public Class Preview

Private ThisExeName As String

Private img As PictureBox

Private ThisExe As System.Reflection.Assembly

Private imgIndex As Integer

Public Toggle As Boolean

Public PrevHandle As IntPtr

Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Integer, ByVal nIndex As Integer) As Integer

Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Integer, ByVal nIndex As Integer, ByVal dwNewInteger As Integer) As Integer

Public Declare Function GetClientRect Lib "user32" (ByVal hwnd As IntPtr, ByRef lpRect As System.Drawing.Rectangle) As Integer

Public Declare Function SetParent Lib "user32" (ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As Integer

Public Rect As System.Drawing.Rectangle

Private Sub PreviewTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs)

If imgIndex = 0 Then

img.Image = Image.FromStream(ThisExe.GetManifestResourceStream(ThisExeName & "." & "Thumb2.JPG"))

imgIndex += 1

Exit Sub

End If

img.Image = Image.FromStream(ThisExe.GetManifestResourceStream(ThisExeName & "." & imgIndex & ".JPG"))

imgIndex += 1

If imgIndex > 15 Then

imgIndex = 0

End If

End Sub

Sub DisplayPreviewForm(ByVal hWnd As Integer)

' Make a form to display.

Dim f As Form = New Form

PrevHandle = New IntPtr(hWnd)

' Get client rectangle where we will display preview.

GetClientRect(PrevHandle, Rect)

ThisExe = System.Reflection.Assembly.GetExecutingAssembly

ThisExeName = ThisExe.GetName.Name

' Set preview form controls.

img = New PictureBox

With img

.Dock = DockStyle.Fill

.SizeMode = PictureBoxSizeMode.StretchImage

.Image = Image.FromStream(ThisExe.GetManifestResourceStream(ThisExeName & "." & "Thumb1.JPG"))

Toggle = True

End With

' set the preview form.

With f

.FormBorderStyle = FormBorderStyle.None

.WindowState = FormWindowState.Normal

.ControlBox = False

.BackColor = Color.Aquamarine

.Size = Rect.Size

.Controls.Add(img)

' add child style to form

Dim style As Integer

style = GetWindowLong(f.Handle.ToInt32, -16)

style = style Or &H40000000

SetWindowLong(f.Handle.ToInt32, -16, style)

' set preview window as parent

SetParent(f.Handle, PrevHandle)

' Set the form's parent value to the preview window.

SetWindowLong(f.Handle.ToInt32, -8, hWnd)

f.Location = Rect.Location

End With

' Make a timer, and set handler.

Dim t As New Windows.Forms.Timer

t.Interval = 2300

AddHandler t.Tick, AddressOf PreviewTimer_Tick

' Start the timer.

t.Start()

' Run the preview display.

Application.Run(f)

End Sub

End Class

Here is the class that I used to for an entry point. (I made this in VS 2003, hence the Singleton Mutex, which is no longer needed in VS 2005, as it has single instance app. as a built in option.)

Option Strict On

Public Class StartUp

<STAThread()> Overloads Shared Sub main(ByVal args As String())

' Uncomment the 2 lines below when debugging.

'Application.Run(New MainForm)

'Exit Sub

Dim singleton As Threading.Mutex

singleton = New System.Threading.Mutex(False, "DonnieDarkoScrnSaver")

If Not singleton.WaitOne(0, False) Then

Exit Sub

End If

If args.Length > 0 Then

Select Case args(0).ToLower.Trim().Substring(0, 2)

Case "/s" ' Run as a screensaver.

Application.Run(New MainForm)

Case "/c" ' Settings.

Dim s As New Settings

s.ShowDialog()

Case "/p" ' Preview.

' display preview thumbnail.

Dim prev As New Preview

prev.DisplayPreviewForm(CInt(args(1)))

End Select

End If

End Sub

End Class

What I did was embed some thumbnails to display in the preview window, and as shown above, I used a timer to change the images.

I uploaded the entire project to MediaFire.com, and posted a link to it in the MSDN Show and Tell page, about a month ago. Here is a link to it: http://forums.microsoft.com/MSDN/ShowPost.aspx PostID=1563893&SiteID=1

Hope this helps,

-matt-