An issue with reading DB when program runs at startup in vb.net - vb.net

I'm new here and to vb.net and I'm stuck on something that I feel SHOULD be simple to resolve. I setup my program to let the user decide if he or she wants to have the program run at windows start. It actually works fine as it is assigning the registry value to CurrentUser instead of Local Machine because of admin rights needing to be bypassed. However, when I restart my computer the program comes up like normal, but it will not read my access db that is located in the same folder as the program; it tries to read the DB from Windows\System32.
Is there a way to force it to read from the executablepath instead of System32?
Here is my simple code:
Private Sub startup()
If cbStartup.Checked = True Then
My.Computer.Registry.CurrentUser.OpenSubKey("Software").OpenSubKey("Microsoft").OpenSubKey("Windows").OpenSubKey("CurrentVersion").OpenSubKey("Run", True).SetValue("CC_List", System.Windows.Forms.Application.ExecutablePath)
ElseIf cbStartup.Checked = False Then
My.Computer.Registry.CurrentUser.OpenSubKey("Software").OpenSubKey("Microsoft").OpenSubKey("Windows").OpenSubKey("CurrentVersion").OpenSubKey("Run", True).DeleteValue("CC_List", False)
End If
End Sub

So when the O/S starts your program the Current Directory is %windir%\System32.
You need to either adjust all your existing paths to be explicitly relative to Application.ExecutablePath, or put
My.Computer.FileSystem.CurrentDirectory = My.Application.Info.DirectoryPath
at the start of your program (which is the modern version of ChDir ...).

Related

Managing User Settings

I created a MS Access front end that utilizes specific file locations. I originally created this as a tool for myself to be the only user. Since I sometimes work on it at home, I needed it to be able to detect if I was using it at home or on my work computer because the file locations are different. So, I created a table “tblSettings” and load the settings (based on which computer I’m using) when my Access FE opens.
In a module, I declare:
Public Const conHOME_ENVIRON = "{Me on Home Computer Name}"
Public Const conWORK_ENVIRON = "{Me on Work Computer Name}"
I then set a global string variable when my Startup form loads:
gstrUserComputer = VBA.Environ("USERNAME") & " on " & VBA.Environ("USERDOMAIN")
Throughout my code, I’ll use something like:
If gstrUserComputer = conWORK_ENVIRON then
Do stuff at work
ElseIf gstrUserComputer = conHOME_ENVIRON then
Do stuff at home
Else
Do other stuff
End if
All this works just fine (I know my computer’s names), but now I need to share this front end with other users at work and I don’t know how to manage the other users in my front end (I don't know their computer names). I want to make it so “ANY” user can use this app and set their own settings.
Is there a better way to manage users settings and how should I go about it? Please keep it as simple to understand as possible since I’m a novice at this. Sample code would be a big help.
Thanks in advance for your help. I am using Access for MS 365 if that matters.
You can get the computer name, user logon with this:
dim strcomputerName as string
strComputerName = Environ("computername")
and to get the current windows logon name, you can use:
dim strWindowsUser as string
strWindowsUser = Environ("USERNAME")
So, you don't need nor want to use a "constant", but on startup you can use above to get the name - thus not hard coded.
So either always use some pubic function name, or on startup setup some global variables. Using function names is probably better if you use a accDB. But, if you always send users a compiled accDE, then global variables will never re-set - even with unhandled errors. but, global vars in a accDB? They can and will get re-set for un-handled errors. For this reason, often sending and disribution your code compiled as accDE has advantages.
But, perhaps you don't bother with a constant, and just create two public functions in a standard code module.
say like:
Public Function GetUser() as string
GetUser = Environ("USERNAME")
End function
Public Function GetComputerName as string
GetComputerName = Environ("computername")
End Function
So, now you can use the above two functions anywhere in code.

Access to path is denied when trying to import from the client's desktop with SSIS

I'm creating a html page that will import an excel file in to a tracking system. On a button click event excel file is located / ssis package is fired / data imported then closed out. Thats the idea work flow. Problem is the excel file access is being denied before the package even executes
Here is the exact error :
I've tried :
excel file properties have been shared to everyone
identity impersonate set to true
hard coding the path
here is the VB code
Protected Sub bntExecute_Click(sender As Object, e As EventArgs) Handles btnExecute.Click
Dim app As Application = New Application()
Dim package As Package = Nothing
'Dim fileName As String = "C:\Users\Desktop\T. Bryant III\PTSID_Update_Template"'
Try
Dim fileName As String = Server.MapPath(System.IO.Path.GetFileName(FileUpload1.PostedFile.FileName.ToString()))
FileUpload1.PostedFile.SaveAs(fileName)
package = app.LoadPackage("#C:\Users\Desktop\T.Bryant III\KitImport", Nothing)
'excel connection from package'
package.Connections("SourceConnectionExcel").ConnectionString = "provider=Microsoft.Jet.OLEDB.4.0data source =" + fileName + "Extended Properties = Excel 8.0"
'Execute the pakage'
Dim results As Microsoft.SqlServer.Dts.Runtime.DTSExecResult = package.Execute()
Catch ex As Exception
Throw ex
Finally
package.Dispose()
package = Nothing
End Try
End Sub
Thanks in advance or if there is an easier way to do this please let me know. The package when executing it in ssis works fine with its own connection manager etc.
A few things to try. If they don't work for you as permanent solutions, they should at least confirm that your code is working and you are dealing with a persmissions issue (which appears to be the case).
Move your file to the public folder (C:\Users\Public).
Run your application (or web browser) as an administrator (if applicable to your version of Windows).
If you are using a web browser, try using a different one.
If nothing else works, try pasting your code into a Windows Form Application.
If you still get the same error after trying all of this, it's time to take another look at your code. Remove the Try/Catch block to determine precisely which line is throwing the error. If you've tried hard coding, I'm guessing it's the SaveAs method. I'm not sure what class FileUpload1 is, but some SaveAs methods won't overwrite existing files unless you explicitly tell them to. Check the appropriate documentation and see if you don't need to pass a True value somewhere along with filename.
Update us with the results. At the very least, this should narrow down your problem and allow for a better diagnosis of it.

Monitor Executable Use

My goal is to set up a service to watch a network folder containing about 200 .exe files. What I'd like is to have the service update a log each time one of the .exes is launched. Basically I'd like to log usage of each application by recording every time one one of them is used.
I've tried using the FileSystemWatcher class to accomplish this, code below, figuring that the LastAccess filter would do the trick, but it seems it won't. When I run this code no event is raised when the applications are opened.
Is there some way of using the FileSysteWatcher class to do this kind of monitoring? Is there any way to do what I'm attempting?
Private Sub StartWatch()
Dim exeWatcher As New FileSystemWatcher
exeWatcher.Path = "<path>"
exeWatcher.Filter = "*.exe"
exeWatcher.IncludeSubdirectories = True
exeWatcher.NotifyFilter = (NotifyFilters.LastAccess Or NotifyFilters.LastWrite Or NotifyFilters.FileName Or NotifyFilters.DirectoryName Or NotifyFilters.Attributes)
AddHandler exeWatcher.Changed, AddressOf ExeChanged
exeWatcher.EnableRaisingEvents = True
End Sub
Private Sub ExeChanged(source As Object, e As FileSystemEventArgs)
Console.WriteLine("File: " & e.FullPath & " " & DateTime.Now.ToString())
End Sub
Take a look at this Stack Overflow answer, which involves monitoring WMI Win32_Process instance creation events (basically, when WMI registers that a new process has been created). This is probably the most effective way outside of a C++ kernel hook to find out when a process has started.
At that point, you just need to use a regular expression to test the file path against to see if it's originating from that folder, and respond appropriately if it is.
The file system watcher cannot be used to accomplish this because it doesn't know why the file is being accessed. It could be accessed to show the properties of the executable or someone copied it to their local hard drive.
If your goal is to see what machines are running your executable, you can use Windows Management Instrumentation (WMI) to remotely query a machine for Win32_Process and determine if your process is running there.

Opening a file using impersonation

I have been searching the web looking for a way to open a WORD file from a secure network folder by impersonating a user who has access. The closest I've come to finding the answer was this from 2 years ago:
Impersonating in .net (C#) & opening a file via Process.start
Here is the code that I am using. When I set the arguments = LocalFile_Test, everything works perfectly because the user is accessing the local c:\ that is has access to. But when I set arguments = RemoteFile_Test, Word opens up a blank document which is the same effect as if I put garbage in the arguments. So it appears that it cannot find the file even though when I login with the user/domain/password that I specify in the properties below, I can find that exact file name and it is not empty. Does anything jump out at you right away? I appreciate your time.
Dim LocalFile_Test As String = "C:\New.docx"
Dim RemoteFile_Test As String = "\\Server1\Apps\File\New.docx"
Dim MyStartInfo As New System.Diagnostics.ProcessStartInfo
MyStartInfo.FileName = "C:\Program Files\Microsoft Office\Office12\WINWORD.exe "
MyStartInfo.Arguments = LocalFile_Test
MyStartInfo.LoadUserProfile = True
MyStartInfo.UseShellExecute = False
MyStartInfo.UserName = "specialuser"
MyStartInfo.Domain = "mydomainname"
MyStartInfo.Password = New System.Security.SecureString()
MyStartInfo.Password.AppendChar("p"c)
MyStartInfo.Password.AppendChar("a"c)
MyStartInfo.Password.AppendChar("s"c)
MyStartInfo.Password.AppendChar("s"c)
Process.Start(MyStartInfo)
My understanding is that you are trying to get a password protected file from a server, and when you do process start, it just opens up a blank word doc. I think the error is how you are trying to get the file, I think you have to map the actual physical path of the file on the server, like
System.Web.HttpContext.Current.Server.MapPath("\\Server1\Apps\File\New.docx")
From there, I am fairly certain, you need to create network credentials for the user like
System.Net.NetworkCredential=New NetworkCredential(userName:=, password:=)
Finally, once that is done, you can either write the file, or transmit the file like so...
System.Web.HttpContext.Current.Response.TransmitFile(file name)
System.Web.HttpContext.Current.Response.WriteFile(file name)
Then,once you get the file, you can try to open it with process start.
Hope that helps, let me know if what I said doesn't work.

How to find 64-bit process info using a 32-bit process

I have a 32 bit application that shells a second application that can be 32 or 64-bit depending upon the computer it's running on.
I only want one instance of the second application to run at a time, and I need the first application to prevent the second from being launched more than once.
I want to be able to use GetProcessesByName to obtain the running processes. This seems to work fine. It's when I attempt to obtain the module data to find out what folder the second application was run from that things fall apart.
Does anyone have a suggestion for identifying 64-bit processes and their folder of origin from a 32-bit application?
Thank you,
SH
You can use the WMI API (System.Management namespace) for this, specifically the ManagementObjectSearcher. The example below shows to get the process id and full command line from all running notepad instances.
Imports System.Management
Module Module1
Sub Main()
Dim wmi = New ManagementObjectSearcher("SELECT ProcessId, CommandLine FROM Win32_Process WHERE CommandLine LIKE ""%notepad%""")
Dim result = wmi.Get().OfType(Of ManagementObject)()
For Each r In result
Console.WriteLine("Process ID: {0}, Command Line: {1}" r("ProcessId"), r("CommandLine"))
Next
End Sub
End Module
I think it could be easier if you set a Mutex when launching second app.
In main app you could do this: if Mutex doesn't exist you run second app (which creates Mutex when run and release it when closing), otherwise you skip...
EDITED:
You can't edit second app to insert the creation of a mutex, ok.
But you can do this in main app:
Create a background worker BackgroudWorker wrk
Set a private bool to true: bool running = false
Execute wrk when you want the new app run: if (running) return; running = true;
wrk creates a Process and waits for its end
when wrk ends running = false
Just an idea...
EDITED AGAIN:
If you close first app and reopen it, user is able to run second app again.
So you could do this:
Create a background worker BackgroudWorker wrk
Write a tmp file (on NTFS it can be empty)
Execute wrk when you want the new app run:
if your tmp file exists then exit;
wrk creates a Process and waits for its end
when wrk ends deletes tmp file
With this method, even if user quits your first app, tmp file remains on hdd; so when user runs first app again, second app will not be executed.
Remeber that if user is smart enough to undestand this, he could manully delete file and the trick is done.
Finally: are you sure user cannot run directly second app?