By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,190 Members | 769 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,190 IT Pros & Developers. It's quick & easy.

System tray problem using a custom shell instead of windows explorer

P: n/a
Hello all, I wrote a shell program a few years ago in VB6 that needs
to be modified. The problem I have is this:

The SysAdmin uses this shell in place of Explorer, so there is no
taskbar. When his users run PC Anywhere from the shell, and minimize
it, it minimizes to the system tray. With no task bar, there is no
system tray, so there is no way to restore the PC Anywhere window.

The shell starts PC Anywhere using ShellExecute. I have found a lot
of info on Shell_NotifyIcon but this doesn't seem to do what I need.
All I need to do is restore the PC Anywhere window.

One more thing, the shell installs with no installation program (one
of the requirements for the project), and is on about 50 machines, so
I don't want to have to add and register another dll, or ocx if
possible. I found an example on how to see if the app was running,
but uses a dll that would have to be registered on every machine to
work.

Any help would be greatly appreciated
Jul 17 '05 #1
Share this Question
Share on Google+
9 Replies


P: n/a
On Sat, 31 Jul 2004 01:54:11 -0400, no**@comcast.net wrote:
Hello all, I wrote a shell program a few years ago in VB6 that needs
to be modified. The problem I have is this:

The SysAdmin uses this shell in place of Explorer, so there is no
taskbar. When his users run PC Anywhere from the shell, and minimize
it, it minimizes to the system tray. With no task bar, there is no
system tray, so there is no way to restore the PC Anywhere window.

The shell starts PC Anywhere using ShellExecute. I have found a lot
of info on Shell_NotifyIcon but this doesn't seem to do what I need.
All I need to do is restore the PC Anywhere window.

One more thing, the shell installs with no installation program (one
of the requirements for the project), and is on about 50 machines, so
I don't want to have to add and register another dll, or ocx if
possible. I found an example on how to see if the app was running,
but uses a dll that would have to be registered on every machine to
work.

Any help would be greatly appreciated


Your Shell sounds really interesting.
I wonder where PC Anywhere is getting minimized to if there simply is
no system tray

However, if it works consistently, then I doubt if that matters much.

Since you start PC Anywhere, you can easily find its main window
handle and can SendMessage commands to bring it back up again.

HTH
Jul 17 '05 #2

P: n/a
I think I'll try openeing it with CreateProcess instead of
ShellExecute. ShellExecute doesn't return the handle to the window
(bummer), so from what I understand, I would have to use the
FindWindow API to get the handle. I am not sure what the window
caption will be, and from what I can tell, there is no way to wait for
the app to start to get the caption using ShellExecute. I am afraid
if the user opens PC Anywhere, then opens another program right away,
I would get the wrong handle if I used somthing like GetForgoundWindow
to retrieve the handle. I'll let you know what I come up with.

If you want a copy of the shell, there is a trial version you can
download from my site:

http://www.theblattners.com/programm...velopment.html

Just scroll down to "Window Replacement Shell"
On Sat, 31 Jul 2004 07:44:54 +0000 (UTC), er*****@nowhere.com (J
French) wrote:
On Sat, 31 Jul 2004 01:54:11 -0400, no**@comcast.net wrote:
Hello all, I wrote a shell program a few years ago in VB6 that needs
to be modified. The problem I have is this:

The SysAdmin uses this shell in place of Explorer, so there is no
taskbar. When his users run PC Anywhere from the shell, and minimize
it, it minimizes to the system tray. With no task bar, there is no
system tray, so there is no way to restore the PC Anywhere window.

The shell starts PC Anywhere using ShellExecute. I have found a lot
of info on Shell_NotifyIcon but this doesn't seem to do what I need.
All I need to do is restore the PC Anywhere window.

One more thing, the shell installs with no installation program (one
of the requirements for the project), and is on about 50 machines, so
I don't want to have to add and register another dll, or ocx if
possible. I found an example on how to see if the app was running,
but uses a dll that would have to be registered on every machine to
work.

Any help would be greatly appreciated


Your Shell sounds really interesting.
I wonder where PC Anywhere is getting minimized to if there simply is
no system tray

However, if it works consistently, then I doubt if that matters much.

Since you start PC Anywhere, you can easily find its main window
handle and can SendMessage commands to bring it back up again.

HTH


Jul 17 '05 #3

P: n/a
OK, feel free to call me a complete dumb ass... I have tried start
an app using CreateProcess, but this does not give the handle to the
application. It does, however, give the dwProcessID, dwThreadId,
hThread, and hProcess. I tried to use the dwProcessID and OpenProcess
API to get the handle from the PIDL, but this didn't work.

So, I launch PC Anywhere using ShellExecute, then enable a timer I
have on the main form. After 1 second, it gets the handle of the top
most window (should be PC Anywhere) using the GetForgroundWindow API.
The handle is stored in a global variable (hdlPCAnywhere), so if the
user presses the button again for PC Anywhere, the sub routine sees
this variable's value is not 0 and calls the ShowWindow(hldPCAnywhere,
9) API.

This works, but I think there is a better way - any ideas? I thought
there was a way to launch an app from VB and get the apps handle as a
return value of the call.

Your Shell sounds really interesting.
I wonder where PC Anywhere is getting minimized to if there simply is
no system tray

However, if it works consistently, then I doubt if that matters much.

Since you start PC Anywhere, you can easily find its main window
handle and can SendMessage commands to bring it back up again.

HTH


Jul 17 '05 #4

P: n/a
On Sat, 31 Jul 2004 20:23:41 -0400, no**@comcast.net wrote:
OK, feel free to call me a complete dumb ass... I have tried start
an app using CreateProcess, but this does not give the handle to the
application. It does, however, give the dwProcessID, dwThreadId,
hThread, and hProcess. I tried to use the dwProcessID and OpenProcess
API to get the handle from the PIDL, but this didn't work.

So, I launch PC Anywhere using ShellExecute, then enable a timer I
have on the main form. After 1 second, it gets the handle of the top
most window (should be PC Anywhere) using the GetForgroundWindow API.
The handle is stored in a global variable (hdlPCAnywhere), so if the
user presses the button again for PC Anywhere, the sub routine sees
this variable's value is not 0 and calls the ShowWindow(hldPCAnywhere,
9) API.

This works, but I think there is a better way - any ideas? I thought
there was a way to launch an app from VB and get the apps handle as a
return value of the call.


There is. You will find all you need in here:

Option Explicit

' J French - 27th Nov 2003 / 1st Aug 2004
' Shell and Re-Parent
' hacked from MS and KPD
' Add Two Command Buttons

Private Declare Function MoveWindow _
Lib "user32" _
(ByVal hwnd As Long, _
ByVal x As Long, _
ByVal y As Long, _
ByVal nWidth As Long, _
ByVal nHeight As Long, _
ByVal bRepaint As Long) As Long

Private Declare Function FindWindow _
Lib "user32" _
Alias "FindWindowA" _
(ByVal lpClassName As Long, _
ByVal lpWindowName As Long) As Long

Private Declare Function GetWindow _
Lib "user32.dll" _
(ByVal hwnd As Long, _
ByVal wCmd As Long) As Long

Private Declare Function GetParent _
Lib "user32" (ByVal hwnd As Long) As Long

Private Declare Function SetParent _
Lib "user32" _
(ByVal hWndChild As Long, _
ByVal hWndNewParent As Long) As Long

Private Declare Function GetWindowThreadProcessId _
Lib "user32" _
(ByVal hwnd As Long, _
lpdwProcessId As Long) As Long

Private Declare Function LockWindowUpdate _
Lib "user32" _
(ByVal hwndLock As Long) As Long

Private Declare Function GetDesktopWindow _
Lib "user32" () As Long

Private Declare Function Putfocus _
Lib "user32" _
Alias "SetFocus" _
(ByVal hwnd As Long) As Long

Private Declare Function SendMessage _
Lib "user32" _
Alias "SendMessageA" _
(ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Any) As Long

Private Declare Function WaitForInputIdle _
Lib "user32.dll" _
(ByVal hProcess As Long, _
ByVal dwMilliseconds As Long) As Long

Private Const STARTF_FORCEONFEEDBACK As Long = &H40

Private Const GW_HWNDFIRST As Long = 0
Private Const GW_HWNDNEXT = 2
'Private Const WM_QUIT As Long = &H12
Private Const WM_CLOSE = &H10
Private Const WM_SYSCOMMAND As Long = &H112
Private Const SC_CLOSE As Long = &HF060&

Private Type STARTUPINFO
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Long
hStdInput As Long
hStdOutput As Long
hStdError As Long
End Type

Private Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessID As Long
dwThreadID As Long
End Type
Private Declare Function CreateProcessA _
Lib "kernel32" _
(ByVal lpApplicationName As String, _
ByVal lpCommandLine As String, _
ByVal lpProcessAttributes As Long, _
ByVal lpThreadAttributes As Long, _
ByVal bInheritHandles As Long, _
ByVal dwCreationFlags As Long, _
ByVal lpEnvironment As Long, _
ByVal lpCurrentDirectory As String, _
lpStartupInfo As STARTUPINFO, _
lpProcessInformation As PROCESS_INFORMATION) As Long

Private Declare Function WaitForSingleObject _
Lib "kernel32" _
(ByVal hHandle As Long, _
ByVal dwMilliseconds As Long) As Long

Private Declare Function CloseHandle Lib "kernel32" _
(ByVal hObject As Long) As Long

Private Const NORMAL_PRIORITY_CLASS = &H20&
Dim mWnd As Long

Function InstanceToWnd(ByVal target_pid As Long) As Long
Dim test_hwnd As Long, _
test_pid As Long, _
test_thread_id As Long

'Find the first window top level window
test_hwnd = FindWindow(ByVal 0&, ByVal 0&)
test_hwnd = GetWindow(test_hwnd, GW_HWNDFIRST)

Do While test_hwnd <> 0
'Check if the window isn't a child (??)
If GetParent(test_hwnd) = 0 Then
'Get the window's thread
test_thread_id = GetWindowThreadProcessId(test_hwnd, _
test_pid)
If test_pid = target_pid Then
InstanceToWnd = test_hwnd
Exit Do
End If
End If
'retrieve the next window
test_hwnd = GetWindow(test_hwnd, GW_HWNDNEXT)
Loop
End Function

Public Function ExecCmd(cmdline$) As Long
Dim proc As PROCESS_INFORMATION
Dim start As STARTUPINFO
Dim Ret&

' Initialize the STARTUPINFO structure:
start.cb = Len(start)
start.dwFlags = STARTF_FORCEONFEEDBACK

' Start the shelled application:
Ret& = CreateProcessA(vbNullString, cmdline$, _
0&, 0&, 1&, _
NORMAL_PRIORITY_CLASS, _
0&, vbNullString, _
start, proc)
' --- let it start - this seems important
Call WaitForInputIdle(proc.hProcess, 500)
' we should check the result of this

If Ret Then
ExecCmd = InstanceToWnd(proc.dwProcessID)
Me.Print Ret, ExecCmd
Call CloseHandle(proc.hThread)
Call CloseHandle(proc.hProcess)
End If

End Function
Private Sub Command1_Click()
'KPD-Team 1999
'URL: http://www.allapi.net/
'E-Mail: KP*****@Allapi.net
' ---
Me.AutoRedraw = True

'Lock the window update
LockWindowUpdate GetDesktopWindow

'Execute notepad.Exe
mWnd = ExecCmd("notepad.exe")
'If mWnd = 0 Then MsgBox "Error starting the app"

Me.Print Str$(mWnd)
' Set the notepad's parent
If mWnd Then
SetParent mWnd, Me.hwnd
' -
Me.ScaleMode = vbPixels
Call MoveWindow(mWnd, 0, 0, _
Me.ScaleWidth, _
Me.ScaleHeight, 1)
' Put the focus on notepad
Putfocus mWnd
End If

' Unlock window update
LockWindowUpdate False
End Sub
Private Sub Command2_Click()
Call SendMessage(mWnd, WM_CLOSE, 0, ByVal 0&)
'Call SendMessage(mWnd, WM_SYSCOMMAND, SC_CLOSE, ByVal 0&)

End Sub

Private Sub Form_Load()
Command1.Caption = "Start Notepad"
Command2.Caption = "Close Notepad"
End Sub

Jul 17 '05 #5

P: n/a

I think that will do it! Thanks man, I really appreciate it!

On Sun, 1 Aug 2004 09:09:53 +0000 (UTC), er*****@nowhere.com (J
French) wrote:
Option Explicit

' J French - 27th Nov 2003 / 1st Aug 2004
' Shell and Re-Parent
' hacked from MS and KPD
' Add Two Command Buttons

Private Declare Function MoveWindow _
Lib "user32" _
(ByVal hwnd As Long, _
ByVal x As Long, _
ByVal y As Long, _
ByVal nWidth As Long, _
ByVal nHeight As Long, _
ByVal bRepaint As Long) As Long

Private Declare Function FindWindow _
Lib "user32" _
Alias "FindWindowA" _
(ByVal lpClassName As Long, _
ByVal lpWindowName As Long) As Long

Private Declare Function GetWindow _
Lib "user32.dll" _
(ByVal hwnd As Long, _
ByVal wCmd As Long) As Long

Private Declare Function GetParent _
Lib "user32" (ByVal hwnd As Long) As Long

Private Declare Function SetParent _
Lib "user32" _
(ByVal hWndChild As Long, _
ByVal hWndNewParent As Long) As Long

Private Declare Function GetWindowThreadProcessId _
Lib "user32" _
(ByVal hwnd As Long, _
lpdwProcessId As Long) As Long

Private Declare Function LockWindowUpdate _
Lib "user32" _
(ByVal hwndLock As Long) As Long

Private Declare Function GetDesktopWindow _
Lib "user32" () As Long

Private Declare Function Putfocus _
Lib "user32" _
Alias "SetFocus" _
(ByVal hwnd As Long) As Long

Private Declare Function SendMessage _
Lib "user32" _
Alias "SendMessageA" _
(ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Any) As Long

Private Declare Function WaitForInputIdle _
Lib "user32.dll" _
(ByVal hProcess As Long, _
ByVal dwMilliseconds As Long) As Long

Private Const STARTF_FORCEONFEEDBACK As Long = &H40

Private Const GW_HWNDFIRST As Long = 0
Private Const GW_HWNDNEXT = 2
'Private Const WM_QUIT As Long = &H12
Private Const WM_CLOSE = &H10
Private Const WM_SYSCOMMAND As Long = &H112
Private Const SC_CLOSE As Long = &HF060&

Private Type STARTUPINFO
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Long
hStdInput As Long
hStdOutput As Long
hStdError As Long
End Type

Private Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessID As Long
dwThreadID As Long
End Type
Private Declare Function CreateProcessA _
Lib "kernel32" _
(ByVal lpApplicationName As String, _
ByVal lpCommandLine As String, _
ByVal lpProcessAttributes As Long, _
ByVal lpThreadAttributes As Long, _
ByVal bInheritHandles As Long, _
ByVal dwCreationFlags As Long, _
ByVal lpEnvironment As Long, _
ByVal lpCurrentDirectory As String, _
lpStartupInfo As STARTUPINFO, _
lpProcessInformation As PROCESS_INFORMATION) As Long

Private Declare Function WaitForSingleObject _
Lib "kernel32" _
(ByVal hHandle As Long, _
ByVal dwMilliseconds As Long) As Long

Private Declare Function CloseHandle Lib "kernel32" _
(ByVal hObject As Long) As Long

Private Const NORMAL_PRIORITY_CLASS = &H20&
Dim mWnd As Long

Function InstanceToWnd(ByVal target_pid As Long) As Long
Dim test_hwnd As Long, _
test_pid As Long, _
test_thread_id As Long

'Find the first window top level window
test_hwnd = FindWindow(ByVal 0&, ByVal 0&)
test_hwnd = GetWindow(test_hwnd, GW_HWNDFIRST)

Do While test_hwnd <> 0
'Check if the window isn't a child (??)
If GetParent(test_hwnd) = 0 Then
'Get the window's thread
test_thread_id = GetWindowThreadProcessId(test_hwnd, _
test_pid)
If test_pid = target_pid Then
InstanceToWnd = test_hwnd
Exit Do
End If
End If
'retrieve the next window
test_hwnd = GetWindow(test_hwnd, GW_HWNDNEXT)
Loop
End Function

Public Function ExecCmd(cmdline$) As Long
Dim proc As PROCESS_INFORMATION
Dim start As STARTUPINFO
Dim Ret&

' Initialize the STARTUPINFO structure:
start.cb = Len(start)
start.dwFlags = STARTF_FORCEONFEEDBACK

' Start the shelled application:
Ret& = CreateProcessA(vbNullString, cmdline$, _
0&, 0&, 1&, _
NORMAL_PRIORITY_CLASS, _
0&, vbNullString, _
start, proc)
' --- let it start - this seems important
Call WaitForInputIdle(proc.hProcess, 500)
' we should check the result of this

If Ret Then
ExecCmd = InstanceToWnd(proc.dwProcessID)
Me.Print Ret, ExecCmd
Call CloseHandle(proc.hThread)
Call CloseHandle(proc.hProcess)
End If

End Function


Jul 17 '05 #6

P: n/a
On Sun, 01 Aug 2004 14:56:36 -0400, Eddie B <> wrote:

I think that will do it! Thanks man, I really appreciate it!


You are welcome

You might find that you need to wait a bit longer to find the main
PCAnyWhere Window, some Apps put up a top level window while loading,
then kill it

You can also use WaitForSingleObject to see whether a process has
terminated
- you might find that useful
Jul 17 '05 #7

P: n/a
OK, I have a twist, and another problem. The guy I am doing this for
lives in Louisianna, I live in Georgia. I sent him the updated
program, and he said it didn't work. I have come to find out that he
is running PC Anywhere as a service that starts with Windows and
minimizes to the system tray - he forgot to tell me this :( I was
under the impression that the user started PC Anywhere.

The shell I made has a task bar, similar to windows task bar. When
you click the Start button (the only button on the task bar), the
shell gets a list of running applications (using the GetWindow API)
to display a list to the user (using the GetWindowText API). This
way, if they had started a program, and minimized it, their program
will show up in this list. PC Anywhere is not showing up in the list
- it is running as a service.

Any suggestions on how to restore the window on a service that is not
started by my shell?
On Mon, 2 Aug 2004 08:29:51 +0000 (UTC), er*****@nowhere.com (J
French) wrote:
On Sun, 01 Aug 2004 14:56:36 -0400, Eddie B <> wrote:

I think that will do it! Thanks man, I really appreciate it!


You are welcome

You might find that you need to wait a bit longer to find the main
PCAnyWhere Window, some Apps put up a top level window while loading,
then kill it

You can also use WaitForSingleObject to see whether a process has
terminated
- you might find that useful


Jul 17 '05 #8

P: n/a
On Mon, 02 Aug 2004 19:20:47 -0400, Eddie B <> wrote:
OK, I have a twist, and another problem. The guy I am doing this for
lives in Louisianna, I live in Georgia. I sent him the updated
program, and he said it didn't work. I have come to find out that he
is running PC Anywhere as a service that starts with Windows and
minimizes to the system tray - he forgot to tell me this :( I was
under the impression that the user started PC Anywhere.

The shell I made has a task bar, similar to windows task bar. When
you click the Start button (the only button on the task bar), the
shell gets a list of running applications (using the GetWindow API)
to display a list to the user (using the GetWindowText API). This
way, if they had started a program, and minimized it, their program
will show up in this list. PC Anywhere is not showing up in the list
- it is running as a service.

Any suggestions on how to restore the window on a service that is not
started by my shell?


I think the easiest way is to side step the problem

Start PCAnyWhere yourself, perhaps transparently

Out of curiousity, what OS is he using

I've had very little experience with services, but my understanding is
that the user communicates with them via a 'real' App that then uses
SendMessage or TCP/IP to talk to the 'hidden' Service
Jul 17 '05 #9

P: n/a
He is unning under 98, 2000, and xp. If I find a way to restore the
service's window, I'll let you know. Thanks for all the help!

On Tue, 3 Aug 2004 06:26:49 +0000 (UTC), er*****@nowhere.com (J
French) wrote:
On Mon, 02 Aug 2004 19:20:47 -0400, Eddie B <> wrote:
OK, I have a twist, and another problem. The guy I am doing this for
lives in Louisianna, I live in Georgia. I sent him the updated
program, and he said it didn't work. I have come to find out that he
is running PC Anywhere as a service that starts with Windows and
minimizes to the system tray - he forgot to tell me this :( I was
under the impression that the user started PC Anywhere.

The shell I made has a task bar, similar to windows task bar. When
you click the Start button (the only button on the task bar), the
shell gets a list of running applications (using the GetWindow API)
to display a list to the user (using the GetWindowText API). This
way, if they had started a program, and minimized it, their program
will show up in this list. PC Anywhere is not showing up in the list
- it is running as a service.

Any suggestions on how to restore the window on a service that is not
started by my shell?


I think the easiest way is to side step the problem

Start PCAnyWhere yourself, perhaps transparently

Out of curiousity, what OS is he using

I've had very little experience with services, but my understanding is
that the user communicates with them via a 'real' App that then uses
SendMessage or TCP/IP to talk to the 'hidden' Service


Jul 17 '05 #10

This discussion thread is closed

Replies have been disabled for this discussion.