ms access create an constant on load - vba

I have an ms access database I need to run in different computers. My problem is that each computer is store the backend in different location. Until now, I only have 2 machines running, but know I need to run it in more. I stored the location of each computer in a Public Constant and with a simple If statement it was linking in the correct one.
Public Const strFolderDatabasePc1 as string "c:\DatabasePc1"
Public Const strFolderDatabasePc2 as string "c:\DatabasePc2"
....
Is it possible to create a Public Const with an if statement on database load?
Public Const strFolderDatabase as string
If Pc1 then
strFolderDatabase = FolderPc1
else if Pc2 then
strFolderDatabase = FolderPc2
else if Pc3 then
strFolderDatabase = FolderPc3
else
strError
EndIf
Thank you.
UPDATE:
Until now i have write the following code. It contains 4 Users.
'Database Folders
Public Const MainFolder As String = "\\localhost\c$\User\Main"
Public Const UserAFolder As String = "\\localhost\c$\User\UserA"
Public Const UserBFolder As String = "\\localhost\c$\User\UserB"
Public Function AdminFolder() As String
AdminFolder = Application.CurrentProject.Path & "\Admin\"
End Function
'Database Keys
Public Const MainUserKey As String = "\\localhost\c$\User\Main\Key.txt"
Public Const UserAKey As String = "\\localhost\c$\User\UserA\key.txt"
Public Const UserBKey As String = "\\localhost\c$\User\UserB\key.txt"
Public Function AdminKey() As String
AdminFolder = Application.CurrentProject.Path & "\Admin\key.txt"
End Function
Public Function FolderExists(ByVal path_ As String) As Boolean
On Error Resume Next
FolderExists = (GetAttr(path_) And vbDirectory) = vbDirectory
On Error GoTo 0
End Function
Public Function FileExists(ByVal path_ As String) As Boolean
On Error Resume Next
FileExists = (Len(Dir(path_)) > 0)
On Error GoTo 0
End Function
Public Function FolderDatabase()
If FileExists(AdminKey) And FolderExists(AdminFolder) Then
'Admin
FolderDatabase = AdminFolder
ElseIf FileExists(MainUserKey) And FolderExists(UserMainFolder) Then
'MainUser
FolderDatabase = UserMainFolder
ElseIf FileExists(UserAKey) And FolderExists(UserAFolder) Then
'UserA
FolderDatabase = UserAFolder
ElseIf FileExists(UserBKey) And FolderExists(UserBFolder) Then
'UserB
FolderDatabase = UserBFolder
Else
'Unknown User
'Do something else...
End If
End Function
And using the following code inside each form.
Sub Check()
If FolderExists(FolderDatabase) Then
'===> User, Continue Loading.
If Dir(FolderDatabase & "*.*") = "" Then
'===> Empty Folder.
'Do something...
Else
'===> Files On Folder.
'Do something...
End If
Else
'===> Not Known User.
Application.Quit acQuitSaveNone
End If
End Sub
Can I write it or do it with more simple way? Thank you.
PS:
I need to have in one place the location of each USER because I might change in the future the location or file name. Also I am using two more folders with different names and again I am using all the above.

In simple words no, but you could have a Function return the correct path by passing the pc number as argument:
Public Const strFolderDatabasePc1 as string "c:\DatabasePc1"
Public Const strFolderDatabasePc2 as string "c:\DatabasePc2"
Public Function FolderDatabase(ByVal pcNo As Long) As String
Select Case pcNo
Case 1:
FolderDatabase = strFolderDatabasePc1
Case 2:
FolderDatabase = strFolderDatabasePc2
End Select
End Function
Then just pass the pc number required:
Dim path_ As String
path_ = FolderDatabase(1)
To make it more readable, setup an Enum for the various pc's.
Public Enum Computers
Home
Work
End Enum
Public Function FolderDatabase(ByVal pc As Computers) As String
Select Case pc
Case Computers.Home:
FolderDatabase = strFolderDatabasePc1
Case Computers.Work:
FolderDatabase = strFolderDatabasePc2
End Select
End Function
Dim path_ As String
path_ = FolderDatabase(Computers.Home)

It doesn't make sense. Each computer has its own C: drive, that the others won't see.
So you can simply use:
Public Const strFolderDatabasePc As string "c:\DatabasePc"
That said, you might be better off to use a folder under C:\Users\Public as your database file isn't, as seen by Windows, an application but a document.

Related

Visual studio Vb.net | Usb detection code partially working

I had to re-write the post because stackoverflow detects the post as already solved in another thread and i had to delete it. But the thread that referenced the forum was for C# and in anycase even reading it I can't find out a solution for my problem.
So, hello again guys :D
I did find somewhere online a code that allows me to detect usb devices and relative files,
it works but not very well because each time i plug or unplug the usb device i get:
"System.NullReferenceException", i will not write the rest of the error to avoid that stackoverflow closes the thread, anyway you should have understood my issue.
Here the code:
Imports System.IO
Public Class Form1
#Region "USB EVENT"
Private WM_DEVICECHANGE As Integer = &H219
Public Enum WM_DEVICECHANGE_WPPARAMS As Integer
DBT_CONFIGCHANGECANCELED = &H19
DBT_CONFIGCHANGED = &H18
DBT_CUSTOMEVENT = &H8006
DBT_DEVICEARRIVAL = &H8000
DBT_DEVICEQUERYREMOVE = &H8001
DBT_DEVICEQUERYREMOVEFAILED = &H8002
DBT_DEVICEREMOVECOMPLETE = &H8004
DBT_DEVICEREMOVEPENDING = &H8003
DBT_DEVICETYPESPECIFIC = &H8005
DBT_DEVNODES_CHANGED = &H7
DBT_QUERYCHANGECONFIG = &H17
DBT_USERDEFINED = &HFFFF
End Enum
Private Structure DEV_BROADCAST_VOLUME
Public dbcv_size As Int32
Public dbcv_devicetype As Int32
Public dbcv_reserved As Int32
Public dbcv_unitmask As Int32
Public dbcv_flags As Int16
End Structure
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
Try
If m.Msg = WM_DEVICECHANGE Then
Dim Volume As DEV_BROADCAST_VOLUME
Volume = DirectCast(Runtime.InteropServices.Marshal.PtrToStructure(m.LParam, GetType(DEV_BROADCAST_VOLUME)), DEV_BROADCAST_VOLUME)
If Not GetDriveLetterFromMask(Volume.dbcv_unitmask).ToString.Trim = String.Empty Then
Dim DriveLetter As String = (GetDriveLetterFromMask(Volume.dbcv_unitmask) & ":\")
Select Case m.WParam
Case WM_DEVICECHANGE_WPPARAMS.DBT_DEVICEARRIVAL
LblUSB.Text = DriveLetter
GetFiles()
MsgBox("Usb connected")
' Code When add USB
Case WM_DEVICECHANGE_WPPARAMS.DBT_DEVICEREMOVECOMPLETE
LblUSB.Text = ""
CheckedListBox1.Items.Clear()
MsgBox("Usb disconnected")
' Code When Remove USB
End Select
End If
End If
Catch ex As Exception
End Try
MyBase.WndProc(m)
End Sub
Private Function GetDriveLetterFromMask(ByRef Unit As Int32) As Char
For i As Integer = 0 To 25
If Unit = (2 ^ i) Then
Return Chr(Asc("A") + i)
End If
Next
Return ""
End Function
#End Region
Sub GetFiles()
Try
Dim Path = LblUSB.Text
Dim LstFiles = My.Computer.FileSystem.GetFiles(Path, FileIO.SearchOption.SearchTopLevelOnly)
For Each File In LstFiles
Dim F As New IO.FileInfo(File)
CheckedListBox1.Items.Add(F.Name)
Next
Catch ex As Exception
End Try
End Sub
End Class
The System.NullReferenceException i get is at this point:
Volume = DirectCast(Runtime.InteropServices.Marshal.PtrToStructure(m.LParam, GetType(DEV_BROADCAST_VOLUME)), DEV_BROADCAST_VOLUME)
I did read that this error happens when the value is null and there should be a value associated,
i tried different approaches but none did work and i hope that someone of you could give me a solution and an explaination to better understand that.
Thank you very much guys for the help!
When one runs the code in VS 2019, beneath the System.NullReferenceException it states: System.Runtime.InteropServices.Marshal.PtrToStructure(...) returned Nothing which occurs because m.LParam is 0. This can be observed by placing the following code just before the DirectCast statement:
Debug.WriteLine($"m.LParam: '{m.LParam.ToString()}'").
There isn't a need to attempt to get a drive letter until it's been detected that the USB device has been inserted. If one refactors the code as shown below, the issue doesn't occur:
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_DEVICECHANGE Then
Debug.WriteLine($"m.LParam: '{m.LParam.ToString()}'")
Select Case CInt(m.WParam)
Case WM_DEVICECHANGE_WPPARAMS.DBT_DEVICEARRIVAL
Debug.WriteLine($" DBT_DEVICEARRIVAL")
Dim Volume As DEV_BROADCAST_VOLUME
Volume = DirectCast(Runtime.InteropServices.Marshal.PtrToStructure(m.LParam, GetType(DEV_BROADCAST_VOLUME)), DEV_BROADCAST_VOLUME)
If Not GetDriveLetterFromMask(Volume.dbcv_unitmask).ToString.Trim = String.Empty Then
Dim DriveLetter As String = (GetDriveLetterFromMask(Volume.dbcv_unitmask) & ":\")
LblUSB.Text = DriveLetter
GetFiles()
MsgBox("Usb connected")
' Code When add USB
End If
Case WM_DEVICECHANGE_WPPARAMS.DBT_DEVICEREMOVECOMPLETE
LblUSB.Text = ""
CheckedListBox1.Items.Clear()
MsgBox("Usb disconnected")
' Code When Remove USB
End Select
End If
MyBase.WndProc(m)
End Sub
A side note: It's recommended to enable Option Strict for your project.
Update:
After enabling Option Strict, one receives the following compiler error: BC30512: Option Strict On disallows implicit conversions from 'String' to 'Char' in function GetDriveLetterFromMask because of the statement: Return "". To fix the issue, try one of the following:
Option 1:
Private Function GetDriveLetterFromMask(ByRef Unit As Int32) As String
For i As Integer = 0 To 25
If Unit = (2 ^ i) Then
Return Chr(Asc("A") + i)
End If
Next
Return ""
End Function
Option 2:
Private Function GetDriveLetterFromMask(ByRef Unit As Int32) As Char
For i As Integer = 0 To 25
If Unit = (2 ^ i) Then
Return Chr(Asc("A") + i)
End If
Next
Return Chr(0)
End Function
Resources:
Marshal.PtrToStructure Method
DirectCast Operator (Visual Basic)
CType Function (Visual Basic)

Random assembly / application name everytime the applicaiton is launched VB.NET code

I have been trying to figure out a way to make it so everytime i launch my application it renames the application to a random string.
My application is in VB.NET
This is my frmLogin.vb (i put the code inside same class as login, since login is my start window, didnt know where else to put it)
Code:
Private Shared Sub Main(ByVal args As String())
Const REGISTRY_KEY As String = "HKEY_CURRENT_USER\Prototype"
Const REGISTY_FIRSTRUN As String = "FirstRun"
Const REGISTY_LASTNAME As String = "LastName"
Dim RandomTitle As String = RandomString(RandomShit.[Next](5, 15)) & ".exe"
Try
If Convert.ToInt32(Microsoft.Win32.Registry.GetValue(REGISTRY_KEY, REGISTY_FIRSTRUN, 0)) = 0 Then
Console.Title = RandomTitle
Dim TempPath As String = Convert.ToString(Microsoft.Win32.Registry.GetValue(REGISTRY_KEY, REGISTY_LASTNAME, 0))
If AppDomain.CurrentDomain.FriendlyName <> "RandomShit.exe" Then
File.Delete("RandomShit.exe")
End If
If File.Exists(TempPath) Then
File.Delete(TempPath)
End If
Microsoft.Win32.Registry.SetValue(REGISTRY_KEY, REGISTY_FIRSTRUN, 1, Microsoft.Win32.RegistryValueKind.DWord)
Microsoft.Win32.Registry.SetValue(REGISTRY_KEY, REGISTY_LASTNAME, Directory.GetCurrentDirectory() & "\" + AppDomain.CurrentDomain.FriendlyName, Microsoft.Win32.RegistryValueKind.String)
End If
Finally
End Try
End Sub
I am not sure whether below code completely satisfied your requirement. I hope below works for you to rename an executable file:
File.Move(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName, Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "randomstring.exe"))

Threading Problems (I don't understand it)

There's lots and lots of pages on the internet regarding threading but I can't seem to get my head around it.
I have a Form, which on the click of a button, loops through a file and reads it line by line. Each line is the login details for different FTP sites.
When it reads a line, it Dim's a variable as a new instance of a class named CallFTP using the login details.
It then Dim's a variable as a new Thread using a function in CallFTP named PerformFTP.
PerformFTP returns a string with the results of the FTP and I want to add this to a ListBox on the form that began it all.
The code for the button goes like this...
Private Sub cmdRun_Click(sender As Object, e As EventArgs) Handles cmdRun.Click
For Each _FTPLine As String In Split(_FTPDetails, vbNewLine)
Dim _Active As Boolean = CBool(Split(_FTPLine, "|")(7))
If _Active Then
_CurNum += 1
_ID = Format(Now.Year, "0000") & Format(Now.Month, "00") & Format(Now.Day, "00") & Format(Now.Hour, "00") & Format(Now.Minute, "00") & Format(Now.Second, "00") & Format(Now.Millisecond, "000") & Format(_CurNum, "00000")
Dim _FTP As New CallFTP(_ID, Split(_FTPLine, "|")(0), Split(_FTPLine, "|")(1), Split(_FTPLine, "|")(2), Split(_FTPLine, "|")(3), Split(_FTPLine, "|")(4), Split(_FTPLine, "|")(5), Split(_FTPLine, "|")(6))
Dim _Thread = New Thread(New ThreadStart(AddressOf _FTP.PerformFTP))
With _Thread
.IsBackground = True
.Start()
End With
End If
Next _FTPLine
End Sub
The class is as below (not quite but you don't need the rest of the code lol)
Public Class CallFTP
Private _ID As String = ""
Private _Response As String = ""
Private _IPAddress As String = ""
Private _Port As String = ""
Private _User As String = ""
Private _Pass As String = ""
Private _Remote As String = ""
Private _Local As String = ""
Private _InOut As String = ""
Public Sub New(ID As String, Server As String, PortNum As String, Username As String, Password As String, RemoteDir As String, LocalDir As String, InOrOut As String)
_ID = ID
_IPAddress = Server
_Port = PortNum
_User = Username
_Pass = Password
_Remote = RemoteDir
_Local = LocalDir
_InOut = InOrOut
End Sub
Public Function PerformFTP() As String
Return "This is a test"
End Function
End Class
Could anyone explain how I would call a sub named LogMessage on a module named modMisc (which adds a string to a ListBox on the main form)?
I've read that you need to invoke it but everything I read seems to give me a headache and make me need to lie down in a dark room for a few hours.
Is anyone capable of explaining as though you're speaking to a 2 year old? :)
Any help would be much appreciated.
You need to invoke a delegate to update your GUI if you're going to update it from another thread that from where it was created.
1º Your delegate must match (have the same signature) than the method you'll use:
Delegate Sub LogMessageExampleDelegate(ByVal x As Integer, ...)
Signature means that the delegate must return and receive the same types than your function/method.
2º Call your function to update GUI using delegate. This for example inside your update GUI function:
If yourListBox.InvokeRequired Then
yourListBox.Invoke(New LogMessageExampleDelegate(AddressOf THE_FUNCTION_WHICH_UPDATES_THE_GUI_NAME), parameter_value)
Else
'Just call your function
End If
With, as example:
sub addToListBox(byval text as string)
myListBox.Items.add(text)
end sub
So your invoke would be:
If yourListBox.InvokeRequired Then
yourListBox.Invoke(New LogMessageExampleDelegate(AddressOf addToListBox), "Item 1")
Else
'Just call your function
addToListBox("Item 1")
End If
PS: I wrote it two times so hope I didn't mess up with something without noticing it.

Unable to call google api from Azure virtual machine

Public Class Geocode
Public Structure GeocodeResult
Public Latitude As String
Public Longitude As String
Public Result As String
End Structure
Public Shared Function GetGeocode(ByVal Address As String) As GeocodeResult
Dim strLat As String = ""
Dim strLon As String = ""
Dim strResult As String = ""
Dim oXmlDoc As Object
GetGeocode.Latitude = ""
GetGeocode.Longitude = ""
GetGeocode.Result = ""
Try
Dim baseURL As String = "https://maps.google.com/maps/api/geocode/xml?sensor=false&address=" & Address
baseURL = Replace(baseURL, " ", "+")
oXmlDoc = CreateObject("Microsoft.XMLDOM")
With oXmlDoc
.Async = False
If .Load(baseURL) And Not .selectSingleNode("GeocodeResponse/status") Is Nothing Then
GetGeocode.Result = .selectSingleNode("GeocodeResponse/status").Text
If Not .selectSingleNode("GeocodeResponse/result") Is Nothing Then
GetGeocode.Latitude = .selectSingleNode("//location/lat").Text
GetGeocode.Longitude = .selectSingleNode("//location/lng").Text
Return GetGeocode
End If
End If
End With
oXmlDoc = Nothing
Return GetGeocode
Exit Function
Catch ex As Exception
Throw (ex)
End Try
Return GetGeocode
End Function
End Class
Ok so this works fine in production, qa, and localhost until we moved it to an Azure VM. From the VM we can go use a browser to get to the https://maps.google.com/maps/api/geocode/xml?sensor=false&address= URL. but when another page calls the getgeocode function the results are always blank meaning the rest api call failed in some way.
I don't think its the domain key restrictions because a) im not using a key in this call and b) i set my google api key to any domain to test it.
EDIT: I have tried using another service with the same result. It works in dev and on local machines but not on the Azure VMs. What I do not understand is how the REST apis are accessible via the browser, but return nothing when called from code.
Any ideas?
Explicitly creating a web client and loading that into the xml document has fixed this issue for me.
Imports Microsoft.VisualBasic
Imports System.Xml
Imports System.Linq
Imports System.Xml.Linq
Imports System.Net
Imports System.IO
Public Class Geocode
Public Structure GeocodeResult
Public Latitude As String
Public Longitude As String
Public Result As String
End Structure
Public Shared Function GetGeocode(ByVal Address As String) As GeocodeResult
Dim oXmlDoc As Object
GetGeocode.Latitude = ""
GetGeocode.Longitude = ""
GetGeocode.Result = ""
Try
Dim baseURL As String = "https://maps.google.com/maps/api/geocode/xml?sensor=false&address=" & Address
baseURL = Replace(baseURL, " ", "+")
Using WC As New WebClient()
oXmlDoc = CreateObject("Microsoft.XMLDOM")
With oXmlDoc
.Async = False
If .Load(WC.DownloadData(baseURL)) And Not .selectSingleNode("GeocodeResponse/status") Is Nothing Then
GetGeocode.Result = .selectSingleNode("GeocodeResponse/status").Text
If Not .selectSingleNode("GeocodeResponse/result") Is Nothing Then
GetGeocode.Latitude = .selectSingleNode("//location/lat").Text
GetGeocode.Longitude = .selectSingleNode("//location/lng").Text
Return GetGeocode
End If
End If
End With
oXmlDoc = Nothing
End Using
Return GetGeocode
Exit Function
Catch ex As Exception
Throw (ex)
End Try
Return GetGeocode
End Function
End Class

Declaring constant in VBA from a INI file

I have some const in a VBA module but I would like to put them in a INI file because I have other applications that use the same constants. This works:
Public Const PATH_DB As String = "\\server\folder\bdd.mdb"
This however doesn't work:
Public Const PATH_DB As String = getFromIni("path","db","C:\config.ini")
Public Function getFromIni(ByVal strSectionName As String, ByVal strEntry As String, ByVal strIniPath As String) As String
Dim x As Long
Dim sSection As String, sEntry As String, sDefault As String
Dim sRetBuf As String, iLenBuf As Integer, sFileName As String
Dim sValue As String
sSection = strSectionName
sEntry = strEntry
sDefault = ""
sRetBuf = Strings.String$(256, 0) '256 null characters
iLenBuf = Len(sRetBuf$)
sFileName = strIniPath
x = GetPrivateProfileString(sSection, sEntry, "", sRetBuf, iLenBuf, sFileName)
sValue = Strings.Trim(Strings.Left$(sRetBuf, x))
If sValue <> "" Then
getFromIni = sValue
Else
getFromIni = vbNullChar
End If
End Function
# C:\config.ini
[path]
db=\\server\folder\bdd.mdb
My getFromIni function actually works pretty well but not when I want to declare constants (it doesn't compile at all). I tried a global variable instead but for some reason, it doesn't work either, the variable cannot be found when used from another form in the same project (it only works when it's declared as a const, but I can't declare it as a const when getting the value from a function).
What's wrong?
You cannot assign a function call as the value of a CONST string. I would expect you to receive the error "Constant expression required" when running this.
Change
Public Const PATH_DB As String = getFromIni("path","db","C:\config.ini")
to
Public PATH_DB As String
Place the following call that gets the value from INI file in a initialize method (say Database Open event)
PATH_DB = getFromIni("path","db","C:\config.ini")