CareyJ
asked on
How To: Tell which users are running an EXE file
Have you ever tried to replace an .EXE file but couldn't because
another user was currently running the program?
The network is NT4, but the EXE files are located on a Netware Server.
From a VB function, how can I tell who is using another program?
another user was currently running the program?
The network is NT4, but the EXE files are located on a Netware Server.
From a VB function, how can I tell who is using another program?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
This solution also works well if you are remotly supporting you clients, as I do either using radmin via the internet or by PcAnywhere. You can just blat your new version onto the system with no more pain.
Been there! Done that! Ain't goin back!
Been there! Done that! Ain't goin back!
Another tip is to create a timer which autocloses the application say at 10:00pm after all users have gone home, before a backup starts. In case sombody left there pc switch on but still running you app.
Also another tip:
When your app starts up it trys to open a signal file for exclusive non shared access. If it gains access you are the only user of the system you then clear a files from a current users folder. And reopen the sginal file for shared access. You then save the current logged in user login name to a file in the current users folder example "s:\Users\Nick.txt", "s:\Users\Jim.txt" when the main form unloads you delete (Kill) the user's file ans also close the signal file.
In this way you can see who is on the system ans also operations like a month end update can know if they are the only user, and create a message file to stop any new users running the application.
Also another tip:
When your app starts up it trys to open a signal file for exclusive non shared access. If it gains access you are the only user of the system you then clear a files from a current users folder. And reopen the sginal file for shared access. You then save the current logged in user login name to a file in the current users folder example "s:\Users\Nick.txt", "s:\Users\Jim.txt" when the main form unloads you delete (Kill) the user's file ans also close the signal file.
In this way you can see who is on the system ans also operations like a month end update can know if they are the only user, and create a message file to stop any new users running the application.
The "NetFileEnum" API function can be used to get this information, BUT this requires that you are a member of the Administrators or Account Operators local group. If you are just a regular user you are out of luck.
One way to solve this problem (if you get along well with your network administrator...) is to implement a Windows NT service that runs on the administrators account and then have the service communicate with a VB client via a pipe or something similar. I experimented with such a solution a while ago, but the need for it disappeared before it was finished... :-)
One way to solve this problem (if you get along well with your network administrator...) is to implement a Windows NT service that runs on the administrators account and then have the service communicate with a VB client via a pipe or something similar. I experimented with such a solution a while ago, but the need for it disappeared before it was finished... :-)
What I do is create a little program that the users run which copies the exe from the server into a local directory on the clients PC. That way you can happily replace the exe on the server and just tell the users to restart the app.
I have this program running ALL our in house apps, I just pass the name of the exe as a command line parameter and then it copies it to the local drive and runs it.
I know this doesn't specifically answer what you asked but i hope it helps.
I have this program running ALL our in house apps, I just pass the name of the exe as a command line parameter and then it copies it to the local drive and runs it.
I know this doesn't specifically answer what you asked but i hope it helps.
You have a couple of problems to deal with here.
1. You need to get existing users out of the application, hopefully gracefully.
2. You need to prevent new users from launching the application.
RESOLUTION:
You need two files to make this arrangement work. The first file is your executable. The second is a file I name permissions.cfg.
========================== ========== ========== ==========
' IMPLEMENTATION:
At runtime both files need to be on the server it is not required they be in the same directory. To allow program execution leave permissions.cfg wherever it is. To halt program execution and to prevent further access delete permissions.cfg.
========================== ========== ========== ==========
In your executable you have either Sub Main() or a Form_Load() that signals the beginning of your application. In whichever routine you use call a function named AllowExecute. In your call give the location of the permissions.cfg file as the argument. (Function Below)
I.E. AllowExecute("\\ntserver\p ublic\exe\ MyApp\Perm issions\pe rmissions. cfg")
If AllowExecute is False display a message box to the user that says:
MsgBox("This application is being modified by the Administrator and is currently not available.")
Then close gracefully.
This will deal with problem 2.
To deal with problem 1 you need to timers on a form. I will call them tmrPermissions and tmrCloseGracefully.
tmrPermissions needs to have an interval of 30000 or 30 seconds. tmrPermissions calls AllowExecute. If AllowExecute returns true then tmrPermissions does nothing and keeps running. If AllowExecute returns false then tmrPermissions has a message box that states:
MsgBox("This program will be closed in 10 minutes for server administration please save your work and exit.")
tmrPermissions then set tmrCloseGracefully to 10 minutes and enables it then shuts itself off. tmrCloseGracefully does nothing for 10 minutes. If at the end of 10 minutes it is still up it calls a routine that saves all work and closes down.
Now you may replace the executable.
Here is the code I would use:
'------------------------- ---------- ---------- --------->
Private Sub Form_Load()
If AllowExecute = False Then
MsgBox("("This application is being modified by the Administrator and is currently not available.")
CloseGracefully
End If
tmrPermissions.Interval = 30000
tmrPermissions.Enabled = True
End Sub
'------------------------- ---------- ---------- --------->
Private Function AllowExecute(ByVal CFG_PATH As String) As Boolean
If Dir(CFG_PATH) <> "" Then
AllowExecute = True
Else
AllowExecute = False
End if
End Function
'------------------------- ---------- ---------- --------->
Public Sub CloseGracefully()
'Comments: This routine should save all work and application settings prior to ending session.
'*-- You must define what needs to be done here.
End Sub
'------------------------- ---------- ---------- --------->
Private Sub tmrPermissions()
If AllowExecute = False Then
tmrPermissions.Enabled = False
MsgBox("This program will be closed in 10 minutes for server administration please save your work and exit.")
tmrCloseGracefully.Interva l = 100000
tmrCloseGracefully.Enabled = True
End If
End Sub
'------------------------- ---------- ---------- --------->
Private Sub tmrCloseGracefully()
'SafetyCheck
If AllowExecute = False Then
tmrCloseGracefully.Enabled = False
CloseGracefully
Else
tmrCloseGracefully.Enabled = False
tmrPermissions.Interval = 30000
tmrPermissions.Enabled = True
End If
Exit Sub
1. You need to get existing users out of the application, hopefully gracefully.
2. You need to prevent new users from launching the application.
RESOLUTION:
You need two files to make this arrangement work. The first file is your executable. The second is a file I name permissions.cfg.
==========================
' IMPLEMENTATION:
At runtime both files need to be on the server it is not required they be in the same directory. To allow program execution leave permissions.cfg wherever it is. To halt program execution and to prevent further access delete permissions.cfg.
==========================
In your executable you have either Sub Main() or a Form_Load() that signals the beginning of your application. In whichever routine you use call a function named AllowExecute. In your call give the location of the permissions.cfg file as the argument. (Function Below)
I.E. AllowExecute("\\ntserver\p
If AllowExecute is False display a message box to the user that says:
MsgBox("This application is being modified by the Administrator and is currently not available.")
Then close gracefully.
This will deal with problem 2.
To deal with problem 1 you need to timers on a form. I will call them tmrPermissions and tmrCloseGracefully.
tmrPermissions needs to have an interval of 30000 or 30 seconds. tmrPermissions calls AllowExecute. If AllowExecute returns true then tmrPermissions does nothing and keeps running. If AllowExecute returns false then tmrPermissions has a message box that states:
MsgBox("This program will be closed in 10 minutes for server administration please save your work and exit.")
tmrPermissions then set tmrCloseGracefully to 10 minutes and enables it then shuts itself off. tmrCloseGracefully does nothing for 10 minutes. If at the end of 10 minutes it is still up it calls a routine that saves all work and closes down.
Now you may replace the executable.
Here is the code I would use:
'-------------------------
Private Sub Form_Load()
If AllowExecute = False Then
MsgBox("("This application is being modified by the Administrator and is currently not available.")
CloseGracefully
End If
tmrPermissions.Interval = 30000
tmrPermissions.Enabled = True
End Sub
'-------------------------
Private Function AllowExecute(ByVal CFG_PATH As String) As Boolean
If Dir(CFG_PATH) <> "" Then
AllowExecute = True
Else
AllowExecute = False
End if
End Function
'-------------------------
Public Sub CloseGracefully()
'Comments: This routine should save all work and application settings prior to ending session.
'*-- You must define what needs to be done here.
End Sub
'-------------------------
Private Sub tmrPermissions()
If AllowExecute = False Then
tmrPermissions.Enabled = False
MsgBox("This program will be closed in 10 minutes for server administration please save your work and exit.")
tmrCloseGracefully.Interva
tmrCloseGracefully.Enabled
End If
End Sub
'-------------------------
Private Sub tmrCloseGracefully()
'SafetyCheck
If AllowExecute = False Then
tmrCloseGracefully.Enabled
CloseGracefully
Else
tmrCloseGracefully.Enabled
tmrPermissions.Interval = 30000
tmrPermissions.Enabled = True
End If
Exit Sub
Hi rawinnlnx9, don't forget that you can't use message box as it will disable the timer. So it you try to close the app after the user went to the dentist it will just keep running until somebody presses enter.
ASKER
I believe all of you have encountered this "net app developer" problem because you are describing the problem better than I did in the Question.
All of my apps have user "User Logging". The user log for this app is appended as each user runs the program.
Looking at the user log only shows me who has ran it today...not who is still in the program. The app is started about 50 times an hour....some short visits, some long visits.
I also use a timer to check for the existence of a lock file. I place a lock file in the App directory whenever I need users to exit the program. Normally, after a minute passes, all users have exitted the program. The lock file also stops other users at startup by showing the "Busy...try again later" form for 5 seconds then unloading the app. This is innefective when a user is in the program, sitting at a dialog box or on some other form in the program.
Jonyv suggested an API call. That's the sort of answer I'm looking for. I want to see who is in the program "right now". Do any of you have examples of usage of "NetFileEnum"?
All of my apps have user "User Logging". The user log for this app is appended as each user runs the program.
Looking at the user log only shows me who has ran it today...not who is still in the program. The app is started about 50 times an hour....some short visits, some long visits.
I also use a timer to check for the existence of a lock file. I place a lock file in the App directory whenever I need users to exit the program. Normally, after a minute passes, all users have exitted the program. The lock file also stops other users at startup by showing the "Busy...try again later" form for 5 seconds then unloading the app. This is innefective when a user is in the program, sitting at a dialog box or on some other form in the program.
Jonyv suggested an API call. That's the sort of answer I'm looking for. I want to see who is in the program "right now". Do any of you have examples of usage of "NetFileEnum"?
ASKER
Oh, btw, InTheDark...I don't have access to the Netware server to run "System Monitor". The server is at another site. I have to send a request to network support at that site and wait for their answer. By then, the current users list will have changed completely.
I am the Netware "file owner" and "folder owner".
I am the Netware "file owner" and "folder owner".
I made a quick "VB version" of NetFileEnum, BUT I'm not in a network environment at the moment so I haven't been able to test if it actually works :-)
Anyway, if it works as it's supposed to the call to NetFileEnum will return an array of FILE_INFO_3 structures, the "pathname" and "username" members can be used to see what files are open by what users. The enumeration can be limited with the "BasePath" and "UserName" parameters to NetFileEnum.
And as mentioned before: This code must be run with administrators privileges to even have a remote chance of working...
Put the following code in a BAS module and just call NetFileEnum with the servername (like "\\servername"). Specify "VbNullString" for "BasePath" and "UserName" if you're not going to use them.
*begin code*
Private Declare Function NetApiBufferFree Lib "Netapi32.dll" (ByVal lpBuffer As Long) As Long
Private Declare Function Internal_NetFileEnum Lib "Netapi32.dll" Alias "NetFileEnum" (ByVal ServerName As String, _
ByVal BasePath As String, _
ByVal UserName As String, _
ByVal level As Long, _
ByRef BufPtr As Long, _
ByVal prefmaxlen As Long, _
ByRef entriesread As Long, _
ByRef TotalEntries As Long, _
ByRef resume_handle As Long _
) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, _
pSource As Any, _
ByVal dwLength As Long)
' Converts a Unicode string to an ANSI string
Private Declare Function WideCharToMultiByte Lib "kernel32" _
(ByVal Codepage As Long, _
ByVal dwFlags As Long, _
lpWideCharStr As Any, _
ByVal cchWideChar As Long, _
lpMultiByteStr As Any, _
ByVal cchMultiByte As Long, _
ByVal lpDefaultChar As String, _
ByVal lpUsedDefaultChar As Long) As Long
Private Const ERROR_ACCESS_DENIED = 5&
Private Const ERROR_INVALID_LEVEL = 124&
Private Const ERROR_MORE_DATA = 234
Private Const ERROR_NOT_ENOUGH_MEMORY = 8
Private Const NERR_Success As Long = 0&
Private Const MAX_PREFERRED_LENGTH = &HFFFFFFFF
Private Const NERR_BufTooSmall = &H84B
Private Const CP_ACP = 0 ' ANSI code page
Private Type Internal_FILE_INFO_3 ' As declared in Lmshare.h
fi3_id As Long
fi3_permissions As Long
fi3_num_locks As Long
fi3_pathname As Long
fi3_username As Long
End Type
Public Type FILE_INFO_3 ' VB version of the above structure
fi3_id As Long
fi3_permissions As Long
fi3_num_locks As Long
fi3_pathname As String
fi3_username As String
End Type
' NetFileEnum "VB Style"
Public Function NetFileEnum(ServerName As String, BasePath As String, UserName As String) As FILE_INFO_3()
Dim Buffer() As Internal_FILE_INFO_3
Dim BufPtr As Long
Dim RetBuffer() As FILE_INFO_3
Dim NrOfEntries As Long
Dim TotalEntries As Long
Dim Status As Long
Dim i As Integer
' request level 3 information
Status = Internal_NetFileEnum(Serve rName, BasePath, UserName, 3, BufPtr, MAX_PREFERRED_LENGTH, NrOfEntries, TotalEntries, ByVal CLng(0))
If Status <> NERR_Success Or NrOfEntries <= 0 Then Exit Function
ReDim Buffer(0 To NrOfEntries - 1) ' Allocate temporary buffer
ReDim RetBuffer(0 To NrOfEntries - 1) ' Allocate return value array
CopyMemory Buffer(0), ByVal BufPtr, NrOfEntries * Len(Buffer(0)) ' Copy enumerated data into temporary buffer
For i = 0 To UBound(Buffer) ' Copy and convert temporary buffer into array of FILE_INFO_3
With RetBuffer(i)
.fi3_id = Buffer(i).fi3_id
.fi3_num_locks = Buffer(i).fi3_num_locks
.fi3_permissions = Buffer(i).fi3_permissions
.fi3_pathname = GetStrFromPtrW(Buffer(i).f i3_pathnam e)
.fi3_username = GetStrFromPtrW(Buffer(i).f i3_usernam e)
End With
Next i
NetApiBufferFree BufPtr 'Free buffer returned from NetFileEnum
NetFileEnum = RetBuffer
End Function
' Returns an ANSI string from a pointer to a Unicode string.
Private Function GetStrFromPtrW(lpszW As Long) As String
Dim sRtn As String
sRtn = String$(lstrlenW(ByVal lpszW) * 2, 0) ' 2 bytes/char
' WideCharToMultiByte also returns Unicode string length
' sRtn = String$(WideCharToMultiByt e(CP_ACP, 0, ByVal lpszW, -1, 0, 0, 0, 0), 0)
Call WideCharToMultiByte(CP_ACP , 0, ByVal lpszW, -1, ByVal sRtn, Len(sRtn), 0, 0)
GetStrFromPtrW = GetStrFromBufferA(sRtn)
End Function
' Returns the string before first null char encountered (if any) from an ANSII string.
Private Function GetStrFromBufferA(sz As String) As String
If InStr(sz, vbNullChar) Then
GetStrFromBufferA = Left$(sz, InStr(sz, vbNullChar) - 1)
Else
' If sz had no null char, the Left$ function
' above would return a zero length string ("").
GetStrFromBufferA = sz
End If
End Function
Anyway, if it works as it's supposed to the call to NetFileEnum will return an array of FILE_INFO_3 structures, the "pathname" and "username" members can be used to see what files are open by what users. The enumeration can be limited with the "BasePath" and "UserName" parameters to NetFileEnum.
And as mentioned before: This code must be run with administrators privileges to even have a remote chance of working...
Put the following code in a BAS module and just call NetFileEnum with the servername (like "\\servername"). Specify "VbNullString" for "BasePath" and "UserName" if you're not going to use them.
*begin code*
Private Declare Function NetApiBufferFree Lib "Netapi32.dll" (ByVal lpBuffer As Long) As Long
Private Declare Function Internal_NetFileEnum Lib "Netapi32.dll" Alias "NetFileEnum" (ByVal ServerName As String, _
ByVal BasePath As String, _
ByVal UserName As String, _
ByVal level As Long, _
ByRef BufPtr As Long, _
ByVal prefmaxlen As Long, _
ByRef entriesread As Long, _
ByRef TotalEntries As Long, _
ByRef resume_handle As Long _
) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, _
pSource As Any, _
ByVal dwLength As Long)
' Converts a Unicode string to an ANSI string
Private Declare Function WideCharToMultiByte Lib "kernel32" _
(ByVal Codepage As Long, _
ByVal dwFlags As Long, _
lpWideCharStr As Any, _
ByVal cchWideChar As Long, _
lpMultiByteStr As Any, _
ByVal cchMultiByte As Long, _
ByVal lpDefaultChar As String, _
ByVal lpUsedDefaultChar As Long) As Long
Private Const ERROR_ACCESS_DENIED = 5&
Private Const ERROR_INVALID_LEVEL = 124&
Private Const ERROR_MORE_DATA = 234
Private Const ERROR_NOT_ENOUGH_MEMORY = 8
Private Const NERR_Success As Long = 0&
Private Const MAX_PREFERRED_LENGTH = &HFFFFFFFF
Private Const NERR_BufTooSmall = &H84B
Private Const CP_ACP = 0 ' ANSI code page
Private Type Internal_FILE_INFO_3 ' As declared in Lmshare.h
fi3_id As Long
fi3_permissions As Long
fi3_num_locks As Long
fi3_pathname As Long
fi3_username As Long
End Type
Public Type FILE_INFO_3 ' VB version of the above structure
fi3_id As Long
fi3_permissions As Long
fi3_num_locks As Long
fi3_pathname As String
fi3_username As String
End Type
' NetFileEnum "VB Style"
Public Function NetFileEnum(ServerName As String, BasePath As String, UserName As String) As FILE_INFO_3()
Dim Buffer() As Internal_FILE_INFO_3
Dim BufPtr As Long
Dim RetBuffer() As FILE_INFO_3
Dim NrOfEntries As Long
Dim TotalEntries As Long
Dim Status As Long
Dim i As Integer
' request level 3 information
Status = Internal_NetFileEnum(Serve
If Status <> NERR_Success Or NrOfEntries <= 0 Then Exit Function
ReDim Buffer(0 To NrOfEntries - 1) ' Allocate temporary buffer
ReDim RetBuffer(0 To NrOfEntries - 1) ' Allocate return value array
CopyMemory Buffer(0), ByVal BufPtr, NrOfEntries * Len(Buffer(0)) ' Copy enumerated data into temporary buffer
For i = 0 To UBound(Buffer) ' Copy and convert temporary buffer into array of FILE_INFO_3
With RetBuffer(i)
.fi3_id = Buffer(i).fi3_id
.fi3_num_locks = Buffer(i).fi3_num_locks
.fi3_permissions = Buffer(i).fi3_permissions
.fi3_pathname = GetStrFromPtrW(Buffer(i).f
.fi3_username = GetStrFromPtrW(Buffer(i).f
End With
Next i
NetApiBufferFree BufPtr 'Free buffer returned from NetFileEnum
NetFileEnum = RetBuffer
End Function
' Returns an ANSI string from a pointer to a Unicode string.
Private Function GetStrFromPtrW(lpszW As Long) As String
Dim sRtn As String
sRtn = String$(lstrlenW(ByVal lpszW) * 2, 0) ' 2 bytes/char
' WideCharToMultiByte also returns Unicode string length
' sRtn = String$(WideCharToMultiByt
Call WideCharToMultiByte(CP_ACP
GetStrFromPtrW = GetStrFromBufferA(sRtn)
End Function
' Returns the string before first null char encountered (if any) from an ANSII string.
Private Function GetStrFromBufferA(sz As String) As String
If InStr(sz, vbNullChar) Then
GetStrFromBufferA = Left$(sz, InStr(sz, vbNullChar) - 1)
Else
' If sz had no null char, the Left$ function
' above would return a zero length string ("").
GetStrFromBufferA = sz
End If
End Function
Oops, just noticed that I missed a declaration in the code above...
Add this at the beginnig of the module:
Private Declare Function lstrlenW Lib "kernel32" (lpString As Any) As Long
Add this at the beginnig of the module:
Private Declare Function lstrlenW Lib "kernel32" (lpString As Any) As Long
ASKER
Not in a development environment? Me neither. I'm on vacation until 3/31. I can try it then. Can you try it before then?
You can load rconsole on the server to be able to see it remotely.
Just a thought, If your company is into Netware then you should download the VB netware controls from their site. These are free. There are hoards of things you can do with them. You just add the control you need to your form and away you go.
But the simple way is to load a starter exe, if compiled to pcode its only about 10k and so the user does not see any time delay.
Just a thought, If your company is into Netware then you should download the VB netware controls from their site. These are free. There are hoards of things you can do with them. You just add the control you need to your form and away you go.
But the simple way is to load a starter exe, if compiled to pcode its only about 10k and so the user does not see any time delay.
I managed to test it in a very small scale on my local computer. You need to make a small change to the code above, in NetFileEnum, change:
' request level 3 information
Status = Internal_NetFileEnum(Serve rName, BasePath, UserName, 3, BufPtr, MAX_PREFERRED_LENGTH, NrOfEntries, TotalEntries, ByVal CLng(0))
If Status <> NERR_Success Or NrOfEntries <= 0 Then Exit Function
To:
BufPtr = 0
' request level 3 information
Status = Internal_NetFileEnum(StrCo nv(ServerN ame, vbUnicode), StrConv(BasePath, vbUnicode), StrConv(UserName, vbUnicode), 3, BufPtr, MAX_PREFERRED_LENGTH, NrOfEntries, TotalEntries, ByVal CLng(0))
If Status <> NERR_Success Or NrOfEntries <= 0 Then
If BufPtr <> 0 Then NetApiBufferFree BufPtr
Exit Function
End If
Now it should work fine :-)
' request level 3 information
Status = Internal_NetFileEnum(Serve
If Status <> NERR_Success Or NrOfEntries <= 0 Then Exit Function
To:
BufPtr = 0
' request level 3 information
Status = Internal_NetFileEnum(StrCo
If Status <> NERR_Success Or NrOfEntries <= 0 Then
If BufPtr <> 0 Then NetApiBufferFree BufPtr
Exit Function
End If
Now it should work fine :-)
InTheDark,
Yes you are right. I forgot that problem and I forgot to mention I use a form based message box. I also forgot to include the CFG_PATH in my call to AllowExecute.
'= New Comment
I have noticed that many people are going for highly technical API based solutions. I have tried all of them and unless you have Admin rights on the server they are very difficult if not impossible to pull off. My advice we be to implement a very simple but effective solution and then get on with your actual system programming. Problems like the one you describe can consume enormous resources when the fix (any fix, simpler the better) is actually a trivial solution. Try not to go for the coolest fanciest fix out there. Just get something that works and move on. You can always revisit the problem later. I am sure your boss would agree with me on this too.
Just pick an easy solution that has a simple ZERO dependency implementation. Do not rely on API's not rely on Admin rights do not rely on anything but what you can do in the IDE with no declares, references or hooks. I would just get something up and working. You can slay dragons later. :)
Just my two cents. But I have burned days on stuff like this only to learn that I could not see the forest there were too many trees.
Good Luck and See Ya,
Rex
Yes you are right. I forgot that problem and I forgot to mention I use a form based message box. I also forgot to include the CFG_PATH in my call to AllowExecute.
'= New Comment
I have noticed that many people are going for highly technical API based solutions. I have tried all of them and unless you have Admin rights on the server they are very difficult if not impossible to pull off. My advice we be to implement a very simple but effective solution and then get on with your actual system programming. Problems like the one you describe can consume enormous resources when the fix (any fix, simpler the better) is actually a trivial solution. Try not to go for the coolest fanciest fix out there. Just get something that works and move on. You can always revisit the problem later. I am sure your boss would agree with me on this too.
Just pick an easy solution that has a simple ZERO dependency implementation. Do not rely on API's not rely on Admin rights do not rely on anything but what you can do in the IDE with no declares, references or hooks. I would just get something up and working. You can slay dragons later. :)
Just my two cents. But I have burned days on stuff like this only to learn that I could not see the forest there were too many trees.
Good Luck and See Ya,
Rex
ASKER
JonYV:
I think I'm having trouble with the functions paramters.
Please show me how I would call the function to find all users currently running a program as described below:
Server Name : "MyServer"
App Path/Name: "P:\NetApps\MyProgram\MyPr ogram.exe"
User Name : "CareyJ"
Rex:
I agree with everything that you say. My apps have simple
fixes...user logging, triggering to cause user exit, and some have inactivity time-out exit routines.
It's just that "sometimes" when I try to update an app, I run into this problem. Usually the app is sitting at a dialog so the fixes can't work and I can't easily determine who is holding the program open.
I'm not dedicating a lot of time to developing this (that's why I asked this question here - so if someone else had already done it, I wouldn't have to do it also)
Unfortunately, I can't even afford to put a lot of time into testing JonYV's suggestion. I really need a solution that works straight off of the screen. It sounds like you work like I do. I don't have time to slay dragons either. :)
Thanks for adding your comment because other visitors here who view this PAQ later need to learn early to approach these situations without dependency where possible.
I think I'm having trouble with the functions paramters.
Please show me how I would call the function to find all users currently running a program as described below:
Server Name : "MyServer"
App Path/Name: "P:\NetApps\MyProgram\MyPr
User Name : "CareyJ"
Rex:
I agree with everything that you say. My apps have simple
fixes...user logging, triggering to cause user exit, and some have inactivity time-out exit routines.
It's just that "sometimes" when I try to update an app, I run into this problem. Usually the app is sitting at a dialog so the fixes can't work and I can't easily determine who is holding the program open.
I'm not dedicating a lot of time to developing this (that's why I asked this question here - so if someone else had already done it, I wouldn't have to do it also)
Unfortunately, I can't even afford to put a lot of time into testing JonYV's suggestion. I really need a solution that works straight off of the screen. It sounds like you work like I do. I don't have time to slay dragons either. :)
Thanks for adding your comment because other visitors here who view this PAQ later need to learn early to approach these situations without dependency where possible.
I would do something like this:
Dim OpenResources() As FILE_INFO_3
OpenResources = NetFileEnum("\\MyServer", vbNullString, vbNullString)
On Error GoTo Skip
For i = 0 To UBound(OpenResources)
If InStr(1, OpenResources(i).fi3_pathn ame, "MyProgram.exe") <> 0 Then Debug.Print "MyProgram.exe is openend by " & OpenResources(i).fi3_usern ame
Next i
Skip:
Quick explanation of the parameters again:
ServerName - Like it says...
BasePath - BasePath to limit the search. BUT this may not be very useful in this case since this has to be the local path as seen on the SERVER. So if you have the server mapped as P: but the application is on drive C: on the server it's the C:\whatever\path you have to specify here. This is why I just pass vbNullString to get everything and filter the results afterwards.
UserName - If you specify this, the function will only return resources opened by this user, This is probably not what you want, so just use vbNullString here too.
The On Error Goto thing is just because VB doesn't have an easy way to tell if the returned array is empty...
If it still doesn't work, step through the code and check the return value from the internal NetFileEnum API call, it should be zero if it worked.
Dim OpenResources() As FILE_INFO_3
OpenResources = NetFileEnum("\\MyServer", vbNullString, vbNullString)
On Error GoTo Skip
For i = 0 To UBound(OpenResources)
If InStr(1, OpenResources(i).fi3_pathn
Next i
Skip:
Quick explanation of the parameters again:
ServerName - Like it says...
BasePath - BasePath to limit the search. BUT this may not be very useful in this case since this has to be the local path as seen on the SERVER. So if you have the server mapped as P: but the application is on drive C: on the server it's the C:\whatever\path you have to specify here. This is why I just pass vbNullString to get everything and filter the results afterwards.
UserName - If you specify this, the function will only return resources opened by this user, This is probably not what you want, so just use vbNullString here too.
The On Error Goto thing is just because VB doesn't have an easy way to tell if the returned array is empty...
If it still doesn't work, step through the code and check the return value from the internal NetFileEnum API call, it should be zero if it worked.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
I assume that you are refering to the parameters being passed as regular VB strings in the call to NetFileEnum in my original post?
In that case you will find that I already posted a correction for this, so I don't think Unicode is a problem here (unless you have spotted some other problem that I missed?)
I have successfully executed the code above (with the fix) and got valid results back, so I think it works :-)
In that case you will find that I already posted a correction for this, so I don't think Unicode is a problem here (unless you have spotted some other problem that I missed?)
I have successfully executed the code above (with the fix) and got valid results back, so I think it works :-)
ASKER
I get valid results back when I run it against the SQL server but I get nothing back when I run it against the Netware server.
In NetFileEnum, Status = 53 instead of 0 is returned when I run against the Netware server.
In NetFileEnum, Status = 53 instead of 0 is returned when I run against the Netware server.
ASKER
I get valid results back when I run it against the SQL server but I get nothing back when I run it against the Netware server.
In NetFileEnum, Status = 53 instead of 0 is returned when I run against the Netware server.
In NetFileEnum, Status = 53 instead of 0 is returned when I run against the Netware server.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Hi CareyJ. You are going the up hill way. By using 2 EXE files the job would be finished in 2 minutes and also it would mean that you just dont need to care who is on the network, you could be playing golf instead of waiting for users to quit the application.
Hi CareyJ,
This old question (QID 20563253) needs to be finalized -- accept an answer, split points, or get a refund. Please see http://www.cityofangels.com/Experts/Closing.htm for information and options.
This old question (QID 20563253) needs to be finalized -- accept an answer, split points, or get a refund. Please see http://www.cityofangels.com/Experts/Closing.htm for information and options.
ASKER
Well...I haven't forgotten about this question
The need for an answer still exists.
Jonyv was closest to the answer when he offered an NT Server solution but I still need the Netware solution.
I don't want to delete the question because it has some good information pertaining to this problem.
I don't want to close the question because I hope someone sees it soon and offers the Netware solution.
What do you recommend CleanupPing? Do you really need it closed?
The need for an answer still exists.
Jonyv was closest to the answer when he offered an NT Server solution but I still need the Netware solution.
I don't want to delete the question because it has some good information pertaining to this problem.
I don't want to close the question because I hope someone sees it soon and offers the Netware solution.
What do you recommend CleanupPing? Do you really need it closed?
CareyJ:
This old question needs to be finalized -- accept an answer, split points, or get a refund. For information on your options, please click here-> http:/help/closing.jsp#1
Experts: Post your closing recommendations! Who deserves points here?
This old question needs to be finalized -- accept an answer, split points, or get a refund. For information on your options, please click here-> http:/help/closing.jsp#1
Experts: Post your closing recommendations! Who deserves points here?
ASKER
Well...I haven't forgotten about this question
The need for an answer still exists.
Jonyv was closest to the answer when he offered an NT Server solution but I STILL need the Netware solution.
I don't want to delete the question because it has some good information pertaining to this problem.
I don't want to close the question because I hope someone sees it soon and offers the Netware solution.
What do you recommend CleanupPing? Do you really need it closed?
The need for an answer still exists.
Jonyv was closest to the answer when he offered an NT Server solution but I STILL need the Netware solution.
I don't want to delete the question because it has some good information pertaining to this problem.
I don't want to close the question because I hope someone sees it soon and offers the Netware solution.
What do you recommend CleanupPing? Do you really need it closed?
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:
-->PAQ - with points refunded
Please leave any comments here within the next seven days.
PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER
GPrentice00
Cleanup Volunteer
I will leave a recommendation in the Cleanup topic area that this question is:
-->PAQ - with points refunded
Please leave any comments here within the next seven days.
PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER
GPrentice00
Cleanup Volunteer
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
If you go look at my original solution I posted and change the message box call to a custom form you design to look like a message box it will work just fine. Then it will not matter who is logged in. They have 10 minutes and then they get iced. You can only do so much to help people. Or make it 30 minutes either way... Put in a custom form and things will work no matter what server you are trying to hit. You are not going to find a "silver bullet" on this one.
- Rex
- Rex
MsgBox message,vbExclamation "System Close"
End