How does Windows determine which folder AppData local data goes in? - windows

I know that local application data is stored in a set location on disk for my application:
c:\Users\jonathan\AppData\Local\MyCompany\MyApp_In_Question_Url_fhjsu6dhsj673dkncsdhjfdf
This contains several sub-folders containing the application settings (user.config), which generally take the form "6.1.5944.23465".
We do a straight file copy over the install location, and running the new executable from the shortcut on the desktop for the first time usually creates a new sub-folder of the same form (i.e. 6.1.5966.34567), which requires us to call Settings.Upgrade
So far, so good (although this probably isn't good practice).
I have just recently upgraded the application from .NET 3.5 to .NET 4.6.2, and on some machines it creates a new folder entirely:
c:\Users\jonathan\AppData\Local\MyCompany\MyApp_In_Question_Url_aaabf35hhsjd4hkwn83kfcm
And a new sub-folder of the form 6.1.5977.10245.
This is an issue because the shortcut on the desktop no longer works, and the settings cannot be upgraded, and require re-entry by the end-user (who doesn't always know them).
Most machines (all the test and UAT ones) do not exhibit this behaviour.
My question is this:
What is the mechanism for deciding that an executable's settings should be stored in an entirely new location, and not a sub-folder?
As a corollary of this:
Can I set this so that it's definitely the same product, and the settings can continue to be upgraded?

I realised that sometimes the flow of code creates the first setting from a dll, and sometimes from the main executable, and I do some custom setting of My.Settings (in one of the VB chunks) which is a little messy.
In case you wondered: To recover the settings, I had to search through all the LocalApplicationData looking for my app's previous settings.
Private Shared Function FindFromPreviousSettings() As MigratableSettings
' Find the App_Data folder, and look to see if there are any other
' config settings which are valid, authenticated, etc.
Dim likelyConfigPath = New DirectoryInfo(
Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"My_Software_Company"
)
)
Dim allValidConfigs = SearchMyDirectory(likelyConfigPath, "user.config")
Dim ver As Func(Of FileInfo, Version)
ver = Function(fi)
Try
'Find out the version of this file. Bigger is better.
Return New Version(fi.Directory.Name)
Catch ex As Exception
Return New Version()
End Try
End Function
Dim latestValidFile = allValidConfigs.OrderByDescending(ver).FirstOrDefault()
Dim latestValidSettings = ReadSettingsFromConfigFile(latestValidFile)
Return latestValidSettings
End Function

Related

How to change Windows folder permission with VB.NET? (System.UnauthorizedAccessException)

I am working on this small VB.NET application which needs to copy a couple files to a Windows folder but I am getting an access denied error; then if I go to the folder, right-click it and manually write the write permission to the folder everything will work fine.
However this application is going to be used by our employees in several machines of the network and mostly of them has not this level of "expertise" meaning that the process must happen smoothly and automatically and therefore the change of the permission should be done by the application itself.
I found a code snippet online which supposed to fix the problem but it is not working for me. I am getting a runtime error with the following message:
System.UnauthorizedAccessException: 'Attempted to perform an unauthorized operation.'
And this is the code I am using:
Dim folder As String = "C:\Program Files (x86)\MyCompany\MyApp"
Dim sid As SecurityIdentifier = New SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, Nothing)
Dim writerule As FileSystemAccessRule = New FileSystemAccessRule(sid, FileSystemRights.Write, AccessControlType.Allow)
Dim fsecurity As DirectorySecurity = Directory.GetAccessControl(folder)
fsecurity.AddAccessRule(writerule)
Directory.SetAccessControl(folder, fsecurity) 'the error happens here
The error happen exactly in the line where the permission setting try to apply. Any idea?
The solution is to level up the privileges of the application. Here it is how to force the program to do it automatically without the need of right-click it and choose "run as administrator" every time:
https://mobitek-system.com/blog/2020/06/how-to-run-vb-net-code-as-an-administrator/
😁

How to list all Bluetooth devices in Visual Basic (vb.net) on WINDOWS

I am getting so mad at trying to find out a working example. YES, I am new to VB.Net. I was used with VB6, long way back. I just cannot get that thing to do what I want.
My project: I am totally tired of using Steam and other 3rd party apps that require pairing and very hard or long configurations to emulate an XBox controller from a non-Xinput controller. I baught a RegeMoudal Pro Controller and OF COURSE, Windows does NOT read any button entries and I need to use a third party app. The problem with the apps is that they require too much configuration. I just want to transfer the controller's input into a Windows detectable input, that's it.
So, since I cannot go in FASM to do such a complexe project without breaking my head everywhere, I chose to go with the easy way, old school. I spent 2 days just figuring out that I had to reference UWP and a bunch of other things. Now, I said to myself, if I only get AT LEAST the list of devices connected on Bluetooth, I'll be able to start somewhere but nope. No matter what I find, noone has any Visual Basic codes to use in a clean way asside from very complexe code I barely understand.
Can someone please help me AT LEAST find out HOW to list all devices on Bluetooth. I do not care if they are connected or not, I just want to list the devices.
Here is what I got. A simple form with 1 single button and 1 single Label. I know, this just has a bunch of errors.
Imports Windows.Devices.Bluetooth
Imports Windows.Devices.Enumeration
Public Class FrmMain
Private Sub BouGetdev_Click(sender As Object, e As EventArgs) Handles BouGetDev.Click
Dim odevices = New DevicePicker
Dim odev As DeviceInformation
Dim sdevices As String
sdevices = ""
LabRes.Text = "Searching devices..."
For Each odev In odevices
sdevices = sdevices & Chr(13) & odev.GetType.Name
Next
End Sub
End Class
I just cannot figure out how to make this simple task so a gentle help would be nice.
I got discouraged because Windows does NOT capture any input of my controller detected as a Bluetooth Pro Controller but a simple webpage does capture every single input so I am annoyed because I was waiting for this controller since a long time because the XBOX ONE controller had serious joystick issues and made me rage quit games because the joystick would give small taps backwards when releasing it so those Xbox controllers are now on my blacklist because even when Microsoft sent it back to me, it had the exact same issue so I got a refund.
Now, I want to create my own version of Pro Controller to Xbox Controller input app. And I am insisting, Visual Basic code, not C++ or C#. And this is for WINDOWS, not android or any other systems. And refering to Microsoft's website to help does not either help because they give no samples in Visual Basic and I just don't understand the language they are using to explain everything, I'm just a simple person, oh, and the samples that can be taken need to be downloaded as project. I just want a sample code available neatly and easily without downloading anything.
So, after fideling so much with VB and trying to search. I finally found out how to list Bluetooth devices in Visual Basic (VB.Net).
FIRST of all, you NEED 32Feet.Net. I ran into the NuGet problem. I have absolutely NO clue what that is. After searching, I found out that nuGet packages can simply be unzipped using 7zip or other similar app. So here are the steps you need to do to prepare Visual Basic aka VB.Net to work with Bluetooth devices.
Go to 32Feet.Net's GitHub page here: https://github.com/inthehand/32feet
Download the "InTheHand.Net.Bluetooth - Bluetooth Classic" nuget package
Unzip the "nupkg" file in a folder of your choice
Open VB.Net
Navigate in the menus to "Project\Add a project reference..."
Click on the "Browse" button at the bottom of the project reference window
Browse in your newly downloaded and unziped nuget package folder under this path "runtimes\win\lib\netcoreapp#.#" and select the DLL "InTheHand.Net.Bluetooth.dll"
NOW you will be able to use the bluetooth functions. Next, we need to import the functions so they can be available when you code so you need to put this line at the very beginning of your project:
Imports InTheHand.Net.Sockets
Now that this is done, you can list you bluetooth devices. I will explain how I did my sample window. I put 1 button, 1 label and 1 timer object. When changing a label following the mentionned solution above with "Application.DoEvents()" My label still did not change text. So I used an old VB6 trick with a timer. I simply disable a timer object and when clicking on the button, I enable this timer which performs the actions I want. 1 VERY and excessively IMPORTANT thing, once you have started your timer actions, immediately disable your timer before performing any tasks inside this timer or else your function will repeat at the speed of your timer ticks.
So this is my complete code which lists the names of the Bluetooth devices on y computer in Visual Basic (VB.Net).
Imports InTheHand.Net.Sockets
Public Class FrmMain
Private Sub BouGetdev_Click(sender As Object, e As EventArgs) Handles BouGetDev.Click
LabRes.Text = "Searching devices..."
TmrBTScan.Enabled = True
BouGetDev.Enabled = False
End Sub
Private Sub TmrBTScan_Tick(sender As Object, e As EventArgs) Handles TmrBTScan.Tick
Dim bt_client As BluetoothClient = New BluetoothClient()
Dim odevices As BluetoothDeviceInfo() = bt_client.DiscoverDevices().ToArray()
Dim odev As BluetoothDeviceInfo
Dim sdevices As String = ""
Dim schr = ""
TmrBTScan.Enabled = False
For Each odev In odevices
sdevices = sdevices & schr & odev.DeviceName
schr = Chr(10) & Chr(13)
Next
LabRes.Text = sdevices
BouGetDev.Enabled = True
End Sub
End Class
This should list the names of all the Bluetooth devices. At least, it worked on my end and I hope this can help others that are looking for very clear steps in what to download, what to install, what to get, where to navigate, which files and what lines to code. It really is hard to get full complete instructions so I hope this helps.
Thanks for those that helped me here. I had to do some deep search, but at least I can get started on my project now.
First please fix this bug
The button_Click Event runs on the UI thread.
LabRes.Text = "Searching devices..."
the user will not see this text until the method finnished.
add this
LabRes.Text = "Searching devices..."
application.doevents()
It allows the UI to update while running code.
To get bluetooth devices in range
Private Sub SurroundingSub()
Dim client As BluetoothClient = New BluetoothClient()
Dim items As List(Of String) = New List(Of String)()
Dim devices As BluetoothDeviceInfo() = client.DiscoverDevicesInRange()
For Each d As BluetoothDeviceInfo In devices
items.Add(d.DeviceName)
Next
End Sub

Issues while converting a windows app to windows service

I created a monitoring utility that checks cpu, ram, drive space stats and emails if the usage goes above set threshold. It works great in the system tray but I realized that the exe will stop when I log out of windows server. That led me to believe that I needed to create a windows service. I would like to use the existing GUI Form to save data to application settings and use those settings in windows service. Here are the steps I took so far,
Added a Windows Service class.
Modified the original code to get rid of any interactive items that were related to GUI Form.
Added the code to this class.
Added a Service installer.
Added this code to it-->
public ProjectInstaller()
{
InitializeComponent();
ServiceProcessInstaller serviceProcessInstaller = new ServiceProcessInstaller();
ServiceInstaller serviceInstaller = new ServiceInstaller();
serviceProcessInstaller.Account = ServiceAccount.LocalSystem;
serviceProcessInstaller.Username = null;
serviceProcessInstaller.Password = null;
serviceInstaller.StartType = ServiceStartMode.Automatic;
serviceInstaller.ServiceName = "Server Monitoring";
this.Installers.Add(serviceProcessInstaller);
this.Installers.Add(serviceInstaller);
}
Change Start up object to Utility.Program.
When I try installing this through installUtil I get this error
System.IO.FileNotFoundException: Could not load file or assembly 'file:///C:\Use
rs\AdminUser\Desktop\Temp\Server' or one of its dependencies. The system cannot
find the file specified..
Thanks!
If you are saving these application settings into a file that is in the same directory as the Windows service, that is going to be your problem. All Windows Services are run in the C:/Windows directory (or a sub-directory in there) so when you access files you will need to do one of two things:
Change the executing directory
You can change the 'current directory' for the executing app back to the folder that contains the exe with the following line of code:
System.IO.Directory.SetCurrentDirectory(System.AppDomain.CurrentDomain.BaseDirectory);
This will make all relative files become relative to the executable location once again.
Make all file request full paths
This one is easier for some files than others. System files are the hardest. So if you are trying to get to a .config file, that's going to be a nightmare.

How Do I Prevent the Installer from Running when Application Data Files are Removed?

I have an application written in VB.Net with Visual Studio 2005. The application allows the user to create and save project files. When I distribute the application, I include some demo project files, which I install in the common application data folder.
XP - C:\Documents and Settings\All Users\Application Data
Vista & 7 - C:\Program Data
I have discovered an unexpected behavior -- if any file in the common application data folder is removed, and the application is run from the start menu, then the install procedure will start and attempt to restore the missing file(s). If the MSI file no longer exists at its original location or has been changed, then the application will fail to run. I perceive that this is a "feature", but it is one I don't want. Can anyone tell me what is going on and how I can avoid it?
Some more details:
I created the setup package by using a Visual Studio deployment
project.
This behavior will not occur if I launch the EXE directly. I
expect, therefore, that the behavior has something to do with the
start menu shortcut. I've noticed that the shortcut isn't a normal
shortcut -- it doesn't have a "Target Location".
All advice is appreciated.
-TC
I have learned that this behavior involves something called "Install-on-Demand" (aka "Self Heal"). The unusual shortcuts created by the setup package are called "Advertised Shortcuts". Now that I have a name for the problem, it is easy to find information on how to fix it. Notably:
http://msdn.microsoft.com/en-us/library/aa368297.aspx
http://groups.google.com/group/microsoft.public.dotnet.distributed_apps/browse_thread/thread/401847045f104af3
http://blog.jtbworld.com/2007/11/enable-target-and-change-icon-of.html
Those pages contain a wealth of information. For the convenience of others who may stumble upon this post, I will summarize what they say:
Advertised shortcuts are special shortcuts which do some fancy things. Most notably, they reinstall damaged application before launching their target. There is some debate over whether they are good, evil, or harmless. In my opinion, they do something most users don't expect, and that makes them evil. Therefore, I'd like to disable them for my application.
Visual Studio setup projects automatically create MSI packages which generate advertised shortcuts by default. It is easy to override that default when installing the MSI package by using DISABLEADVTSHORTCUTS=1 as a command-line argument for Setup.exe. Also, with a utility like Orca, you can manually change the default by inserting DISABLEADVTSHORTCUTS=1 as a property of the MSI. However, if you want Visual Studio to automatically create MSI packages which don't create advertised shortcuts, that is harder. I did it this way:
First, I created a VBS file using the DisableAdvt code provided by Gary Chang in one of the links above (I've repeated that code below). Just create a text file, paste in the code. and save it as DisableAdvt.vbs.
Then, create a post-build event for your setup project. The exact syntax will depend on your file locations. Because my DisableAdvt.vbs is in a "Tools" subfolder of the solution folder, my post-build event looks like this:
"$(ProjectDir)..\Tools\DisableAdvt\DisableAdvt.vbs" "$(BuiltOuputPath)"
That's all I had to do. It works like a charm.
-TC
Some notes:
In Visual Studio 2005, Build events are accessed differently for setup projects than they are for other types of projects. Click on the project name in the solution explorer, then look for PostBuildEvent in the Properties pane.
Orca is a utility that can be used to manually insert the DISABLEADVTSHORTCUTS property into the MSI file. With my approach, Orca is not necessary. However, it is useful for verifying that the build event is making the expected change.
http://www.technipages.com/download-orca-msi-editor.html
In the build event, the misspelling "BuiltOuputPath" is intentional.
Here is Gary Chang's DisableAdvt.vbs code (note that I fixed a typo on line 21 -- Very important!):
Option Explicit
Const msiOpenDatabaseModeTransact = 1
Dim argNum, argCount:argCount = Wscript.Arguments.Count
Dim openMode : openMode = msiOpenDatabaseModeTransact
' Connect to Windows installer object
On Error Resume Next
Dim installer : Set installer = Nothing
Set installer = Wscript.CreateObject("WindowsInstaller.Installer") :
CheckError
' Open database
Dim databasePath:databasePath = Wscript.Arguments(0)
Dim database : Set database = installer.OpenDatabase(databasePath, openMode) : CheckError
' Process SQL statements
Dim query, view, record, message, rowData, columnCount, delim, column
query = "INSERT INTO Property(Property, Value) VALUES ('DISABLEADVTSHORTCUTS', '1')"
Set view = database.OpenView(query) : CheckError
view.Execute : CheckError
database.Commit
If Not IsEmpty(message) Then Wscript.Echo message
Wscript.Quit 0
Sub CheckError
Dim message, errRec
If Err = 0 Then Exit Sub
message = Err.Source & " " & Hex(Err) & ": " & Err.Description
If Not installer Is Nothing Then
Set errRec = installer.LastErrorRecord
If Not errRec Is Nothing Then message = message & vbLf & errRec.FormatText
End If
Fail message
End Sub
Sub Fail(message)
Wscript.Echo message
Wscript.Quit 2
End Sub

Registry key editing vb6 startup

Is it possible that someone here could explain how to use this code. Please keep in mind i am a complete amateur, so simplifications may be needed.
Private Const cPGM = "C:\VB Forum\startup\Example.exe"
Dim oShell As IWshShell_Class
Set oShell = New IWshShell_Class
oShell.RegWrite "HKLM\Software\Microsoft\Windows\CurrentVersion\Run\MyVBApp", _
cPGM, "REG_SZ"
How exactly is this code used? Is it saved as an .exe file and ran or what? Thanks for your prompt reply and informational feedback.
All this code does is add a value to the registry. It adds an item to the key
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
with the name MyVBApp, and the value C:\VB Forum\startup\Example.exe
As it states in the article, this registry entry will cause the program C:\VB Forum\startup\Example.exe to launch automatically at system startup.
In order to use this code it does somehow have to be executed which, of course, requires an executable. If you want to see this code in action, the simplest thing to do would be to create a new "Standard EXE" project, add a reference to the Windows Script Host Object Model, paste the code into the Form_Load event, then run the app. Look at this registry key and you'll see this new entry. Be sure and delete it though because I assume you don't have some executable named C:\VB Forum\startup\Example.exe that you wish to run every time Windows starts, do you?

Resources