How to control placement of app on startup

G

Guest

I want to start an app, and at the same time control where it is placed. I
use the following code, but it doesn't seem to work. The MoveWindow call
doesn't move the window. What am I doing wrong? Isn't the shell function
supposed to return the handle to the window? Or is this just a process id
and
am I then supposed to make another call to translate this into a window
handle? Or what else is wrong?

Public Class Form1
Inherits System.Windows.Forms.Form
Declare Sub MoveWindow Lib "User32" (ByVal hWnd As Long, _
ByVal X As Long, ByVal Y As Long, ByVal Width
As Long, _
ByVal Height As Long, ByVal bRepaint As
Boolean)
....
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim cProgram As String = "Notepad.exe"
Dim nHandle As Integer = Shell(cProgram)
MoveWindow(nHandle, 10, 10, 500, 300, True)
End Sub
End Class

Another question: Are there any calls inside the .net framework to support
this?

Any help appreciated


Peter
 
T

Tom Shelton

I want to start an app, and at the same time control where it is placed. I
use the following code, but it doesn't seem to work. The MoveWindow call
doesn't move the window. What am I doing wrong? Isn't the shell function
supposed to return the handle to the window? Or is this just a process id
and

Well, the docs say it's the process ID. So, presumably you can use the
System.Diagnostics.Process class to get the window handle...

Hmmm... Time to experiment:

Option Strict On
Option Explicit On

Imports System
Imports System.Diagnostics

Module Module1

Declare Function MoveWindow Lib "user32" _
(ByVal hWnd As IntPtr, _
ByVal X As Integer, _
ByVal Y As Integer, _
ByVal nWidth As Integer, _
ByVal nHeight As Integer, _
ByVal bRepaint As Boolean) As Boolean

Sub Main()
Dim procId As Integer = Shell("notepad.exe",
AppWinStyle.NormalFocus)
Dim proc As Process = Process.GetProcessById(procId)

proc.WaitForInputIdle() ' give the window a chance to
initialize

' move it where we want it...
MoveWindow(proc.MainWindowHandle, 10, 10, 500, 300, True)
End Sub

End Module

This seems to work. Obviously, you might want to do a little more error
handling :) Just a note, this also seems to work without the
WaitForInputIdle call - but I put it in just to make sure the main
window is fully initialized and ready to accept messages anyway.
am I then supposed to make another call to translate this into a window
handle? Or what else is wrong?

Public Class Form1
Inherits System.Windows.Forms.Form
Declare Sub MoveWindow Lib "User32" (ByVal hWnd As Long, _
ByVal X As Long, ByVal Y As Long, ByVal Width
As Long, _
ByVal Height As Long, ByVal bRepaint As
Boolean)

Your declare is wrong... Datatype sizes have changed in VB.NET. Long
is a 64-bit integer. It should be Integer, as that is now 32-bit.
Also, handles should be declared as System.IntPtr...

Declare Function MoveWindow Lib "user32" _
(ByVal hWnd As IntPtr, _
ByVal X As Integer, _
ByVal Y As Integer, _
ByVal nWidth As Integer, _
ByVal nHeight As Integer, _
ByVal bRepaint As Boolean) As Boolean
...
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim cProgram As String = "Notepad.exe"
Dim nHandle As Integer = Shell(cProgram)
MoveWindow(nHandle, 10, 10, 500, 300, True)
End Sub
End Class

Another question: Are there any calls inside the .net framework to support
this?

No, not really. You'll need to do interop for this.
 
G

Guest

Thanks Tom, that works like a charm,

now I have to go the other way too. When the user has positioned the app
that I just started, I have to log the new position, to be able to start it
at the new position the next time. I have fiddled around a bit with
GetWindowRect, but I can't get it to work.

I have tried the following code:

Structure RECT
Public left As Long
Public top As Long
Public right As Long
Public bottom As Long
End Structure

Declare Function GetWindowRect Lib "user32.dll" _
(ByVal hWnd As IntPtr, _
ByVal lPRect As RECT) As Long

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button3.Click
Dim proc As Process = Process.GetProcessById(Me._procid)
Dim objRect As New RECT()
If GetWindowRect(proc.MainWindowHandle, objRect) <> 0 Then
MsgBox(objRect.top & " " & objRect.left)
End If
End Sub

But I get "Object reference not set to an instance of an object." on the
GetWIndowRect Call.
proc.MainWIndowHandle returns a valid handle, and objRect seems to be a
valid rect structure.
If I replace the RECT with the .net Rectangle object I get the same error.

What's wrong?

Peter
 
T

Tom Shelton

Just figured that one out myself. Forgot to declare the Rectangle "ByRef"

Peter

Peter...

I'm glad you got it working. But, you still have some issues :)
Remeber datatype sizes have changed in VB.NET. So, all the longs in
your declarations, really should be declared as Integer or Int32.
 
G

Guest

Thank you Tom. Actually, I did know that, but forgot to change it. This is
just a test case built on cut-and-paste sample code from msdn kb. I will
remember that when I make the actual implementation.

Thanks for your help

Peter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top