Visual Basic .NET: Difference between revisions
Paradox-01 (talk | contribs) m (toying around with registry ... file associations look promising) |
m (link fix; pretty sure this is what's being referred to) |
||
(6 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
This page serves as a brief documentation of VB.net with a focus on Oni-related aspects. | |||
This page serves as a brief VB.net | |||
==Projects== | |||
* [http://mods.oni2.net/node/332 Simple OniSplit GUI] | |||
* [ | |||
* [[TRAM setup assistant]] | * [[TRAM setup assistant]] | ||
==Basic knowledge== | |||
: Q: How can I use functions from another class? | : Q: How can I use functions from another class? | ||
: A: '''First condition:''' The function must be a "Shared" one. For example "Shared Function GetApp()". '''Second condition:''' in the ''target code'', the class must be written beforehand (for example "Oni.GetApp" whereby "Oni" is the ''source class's'' name). | : A: '''First condition:''' The function must be a "Shared" one. For example "Shared Function GetApp()". '''Second condition:''' in the ''target code'', the class must be written beforehand (for example "Oni.GetApp" whereby "Oni" is the ''source class's'' name). | ||
====Registry | |||
===Command-line functions within a forms application=== | |||
Since you have to watch out for multiple events, the argument processing should happen in a separate function so the code can be easily re-used. | |||
' Form1.vb (main form) | |||
Public Function processArgs(ByVal args() As String) | |||
For Each a In args | |||
MsgBox(a) | |||
Next | |||
End Function | |||
; Catch arguments from form load event | |||
' Form1.vb (main form) | |||
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load | |||
If My.Application.CommandLineArgs.Count > 0 Then | |||
processArgs(My.Application.CommandLineArgs.ToArray) | |||
End If | |||
' [...] | |||
end sub | |||
; Catch arguments when a single-instance application is already running | |||
The load event can't be triggered if the application can't be opened more than once at a time. This is named a "single-instance application" and will trigger an StartupNextInstance event. Read [https://stackoverflow.com/questions/28831765/pass-command-line-to-first-instance-of-a-single-instance-app here] for details. | |||
'ApplicationEvents.vb | |||
Imports Microsoft.VisualBasic.ApplicationServices | |||
Namespace My | |||
Partial Friend Class MyApplication | |||
Private Sub MyApplication_StartupNextInstance(sender As Object, e As StartupNextInstanceEventArgs) Handles Me.StartupNextInstance | |||
Dim f = Application.MainForm | |||
If f.GetType Is GetType(Form1) Then | |||
CType(f, Form1).processArgs(e.CommandLine.ToArray) | |||
End If | |||
End Sub | |||
End Class | |||
End Namespace | |||
===Registry=== | |||
Data in '''HKEY_CLASSES_ROOT''' can only be changed by admins. | Data in '''HKEY_CLASSES_ROOT''' can only be changed by admins. | ||
Line 23: | Line 69: | ||
Since .bsl in an unique suffix it would be enough to set 2 nodes: | Since .bsl in an unique suffix it would be enough to set 2 nodes: | ||
SOFTWARE\Classes\bsl_auto_file\shell\edit\command, ""(leave value name empty), (path to bsl editor), RegistryValueKind.String | SOFTWARE\Classes\bsl_auto_file\shell\edit\command, ""(leave value name empty), (path to bsl editor plus file as argument), RegistryValueKind.String | ||
SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.bsl\OpenWithProgids, bsl_auto_file, New Byte() {}, RegistryValueKind.None | SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.bsl\OpenWithProgids, bsl_auto_file, New Byte() {}, RegistryValueKind.None | ||
Line 33: | Line 79: | ||
===Code snippets | ==Code snippets== | ||
===Registry=== | |||
; Check if key exists | |||
Private Function getXsiFromRegistry() As String() | |||
Dim oRegKey As RegistryKey = Registry.CurrentUser.OpenSubKey("Software\\Softimage\\SOFTIMAGE Application") | |||
Dim XsiPathInReg As String = "" | |||
If oRegKey Is Nothing Then | |||
XsiPathInReg = "" | |||
Else | |||
Dim Arr = oRegKey.GetSubKeyNames | |||
For Each n In Arr | |||
If InStr(n, "Softimage_Mod_Tool_7.5|Application|bin") > 0 Then | |||
XsiPathInReg = Replace(n, "|", "\") | |||
If Directory.Exists(XsiPathInReg) = False Then | |||
XsiPathInReg = "" | |||
End If | |||
End If | |||
Next | |||
oRegKey.Close() | |||
End If | |||
If XsiPathInReg = "" Then | |||
Return New String() {"", "notvalid"} | |||
Else | |||
Return New String() {XsiPathInReg, "valid"} | |||
End If | |||
End Function | |||
If getXsiFromRegistry(1) = "valid" Then | |||
MsgBox(getXsiFromRegistry(0)) | |||
End If | |||
: example of a valid, returned path: C:\Softimage\Softimage_Mod_Tool_7.5\Application\bin | |||
==Code snippets (old)== | |||
Common functions that are shared among VB.net projects should have their own class. | Common functions that are shared among VB.net projects should have their own class. | ||
Line 39: | Line 121: | ||
===Oni Class=== | |||
Functions in this class: | Functions in this class: | ||
Line 152: | Line 234: | ||
===Drag and drop=== | |||
The target element must have its "AllowDrop" property set to "true". | The target element must have its "AllowDrop" property set to "true". | ||
Line 180: | Line 262: | ||
[[Category: | [[Category:Modding tutorials]] |
Latest revision as of 01:26, 5 April 2021
This page serves as a brief documentation of VB.net with a focus on Oni-related aspects.
Projects
Basic knowledge
- Q: How can I use functions from another class?
- A: First condition: The function must be a "Shared" one. For example "Shared Function GetApp()". Second condition: in the target code, the class must be written beforehand (for example "Oni.GetApp" whereby "Oni" is the source class's name).
Command-line functions within a forms application
Since you have to watch out for multiple events, the argument processing should happen in a separate function so the code can be easily re-used.
' Form1.vb (main form) Public Function processArgs(ByVal args() As String) For Each a In args MsgBox(a) Next End Function
- Catch arguments from form load event
' Form1.vb (main form) Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load If My.Application.CommandLineArgs.Count > 0 Then processArgs(My.Application.CommandLineArgs.ToArray) End If ' [...] end sub
- Catch arguments when a single-instance application is already running
The load event can't be triggered if the application can't be opened more than once at a time. This is named a "single-instance application" and will trigger an StartupNextInstance event. Read here for details.
'ApplicationEvents.vb Imports Microsoft.VisualBasic.ApplicationServices Namespace My Partial Friend Class MyApplication Private Sub MyApplication_StartupNextInstance(sender As Object, e As StartupNextInstanceEventArgs) Handles Me.StartupNextInstance Dim f = Application.MainForm If f.GetType Is GetType(Form1) Then CType(f, Form1).processArgs(e.CommandLine.ToArray) End If End Sub End Class End Namespace
Registry
Data in HKEY_CLASSES_ROOT can only be changed by admins.
Data in HKEY_CURRENT_USER is for everyone accessible.
Customizing file associations
Because of restriction of CLASSES ROOT, file associations are easier to be registered in CURRENT USER where they also don't affect other accounts.
Since .bsl in an unique suffix it would be enough to set 2 nodes:
SOFTWARE\Classes\bsl_auto_file\shell\edit\command, ""(leave value name empty), (path to bsl editor plus file as argument), RegistryValueKind.String SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.bsl\OpenWithProgids, bsl_auto_file, New Byte() {}, RegistryValueKind.None
Same can be done with oni files.
Xml files would need more attention as they are an universal file type used by many other apps.
Anyway, file associations can be used to increase usability: in some cases you don't want to use OniSplit or an GUI and pull off something complex - sometimes you just want the basic conversion from oni to xml or vice versa. This can be done by telling the associated app to execute a commandline function. It's something that Vago or SimpleOniSplitGUI should deliver in the future.
Code snippets
Registry
- Check if key exists
Private Function getXsiFromRegistry() As String() Dim oRegKey As RegistryKey = Registry.CurrentUser.OpenSubKey("Software\\Softimage\\SOFTIMAGE Application") Dim XsiPathInReg As String = "" If oRegKey Is Nothing Then XsiPathInReg = "" Else Dim Arr = oRegKey.GetSubKeyNames For Each n In Arr If InStr(n, "Softimage_Mod_Tool_7.5|Application|bin") > 0 Then XsiPathInReg = Replace(n, "|", "\") If Directory.Exists(XsiPathInReg) = False Then XsiPathInReg = "" End If End If Next oRegKey.Close() End If If XsiPathInReg = "" Then Return New String() {"", "notvalid"} Else Return New String() {XsiPathInReg, "valid"} End If End Function
If getXsiFromRegistry(1) = "valid" Then MsgBox(getXsiFromRegistry(0)) End If
- example of a valid, returned path: C:\Softimage\Softimage_Mod_Tool_7.5\Application\bin
Code snippets (old)
Common functions that are shared among VB.net projects should have their own class.
That way, the functions don't need be rewritten each time and it helps to keep the code more clear.
Oni Class
Functions in this class:
- GetApp - returns app path (type string)
- GetAE - returns AE home path (type string) (e.g. C:\Oni)
- GetXSI - returns Mod Tool path (type string) (e.g. C:\Softimage\Softimage_Mod_Tool_7.5\Application\bin)
- GetOniSplit - outputs an array with (0) as path (type string) and (1) as version (type string)
- OniSplitConvert - tells OniSplit to do something (needed inputs: OniSplit path, command, output path, input path)
Imports System.IO ' for files and directories Imports Microsoft.Win32 ' for registry keys Public Class Oni Shared Function GetApp() Return Application.StartupPath().ToString() End Function Shared Function ReadRegStr(RootKey, Key, Value, RegType) Dim oCtx, oLocator, oReg, oInParams, oOutParams oCtx = CreateObject("WbemScripting.SWbemNamedValueSet") oCtx.Add("__ProviderArchitecture", RegType) oLocator = CreateObject("Wbemscripting.SWbemLocator") oReg = oLocator.ConnectServer("", "root\default", "", "", , , , oCtx).Get("StdRegProv") oInParams = oReg.Methods_("GetStringValue").InParameters oInParams.hDefKey = RootKey oInParams.sSubKeyName = Key oInParams.sValueName = Value oOutParams = oReg.ExecMethod_("GetStringValue", oInParams, , oCtx) ReadRegStr = oOutParams.sValue End Function Shared Function GetAE() Dim OS_bitness As Integer Dim WshShell = CreateObject("WScript.Shell") If InStr(WshShell.RegRead("HKLM\HARDWARE\DESCRIPTION\System\CentralProcessor\0\Identifier"), "64") > 0 Then OS_bitness = 64 Else OS_bitness = 32 End If Const HKEY_LOCAL_MACHINE = &H80000002 Return ReadRegStr(HKEY_LOCAL_MACHINE, _ "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{B67333BB-1CF9-4EFD-A40B-E25B5CB4C8A7}}_is1", _ "InstallLocation", _ OS_bitness) End Function Shared Function GetXsi() Dim oRegKey As RegistryKey = Registry.CurrentUser.OpenSubKey("Software\\Softimage\\SOFTIMAGE Application") Dim XsiDir As String Dim FoundXsi As Boolean = False Dim Arr = oRegKey.GetSubKeyNames For Each n In Arr If InStr(n, "Softimage_Mod_Tool_7.5|Application|bin") > 0 Then XsiDir = Replace(n, "|", "\") If Directory.Exists(XsiDir) = True Then Return XsiDir FoundXsi = True End If End If Next If FoundXsi = False Then Return "" End If oRegKey.Close() End Function Shared Function GetOniSplit() As String() Dim OSpath As String = "" Dim FSO = CreateObject("Scripting.FileSystemObject") If File.Exists(Application.StartupPath().ToString & "\OniSplit.exe") Then OSpath = Application.StartupPath().ToString & "\OniSplit.exe" Return New String() {OSpath, FSO.GetFileVersion(OSpath)} ElseIf File.Exists(GetAE() & "AE\Tools\OniSplit.exe") Then OSpath = GetAE() & "AE\Tools\OniSplit.exe" Return New String() {OSpath, FSO.GetFileVersion(OSpath)} Else Return New String() {"", ""} End If End Function ' example ' Oni.OniSplitConvert(OSpath, "-extract:xml", outputFolder, inputFolder) Shared Function OniSplitConvert(OSpath As String, cmd As String, input As String, output As String) Dim objProcess As System.Diagnostics.Process Try ' the quotes are used to prevent possible errors by paths with spaces objProcess = Process.Start(OSpath, cmd & " " & """" & output & """" & " " & """" & input & """") objProcess.WaitForExit() objProcess.Close() Catch MessageBox.Show("Could not start: " & OSpath & " " & cmd & " " & """" & output & """" & " " & """" & input & """") End Try End Function End Class
Drag and drop
The target element must have its "AllowDrop" property set to "true".
In the following there's a textbox named "tbXml1". In order to allow only certain file types to be dropped, the code checks the file extension. If the extension is allowed during drag, the user will see a plus sign.
Private _OniTypes As New HashSet(Of String)(".xml .oni".Split) Private Sub tbXml1_DragEnter(sender As Object, e As DragEventArgs) Handles tbXml1.DragEnter If Not e.Data.GetDataPresent(DataFormats.FileDrop) Then Return For Each s In DirectCast(e.Data.GetData(DataFormats.FileDrop), String()) If _OniTypes.Contains(Path.GetExtension(s)) Then e.Effect = DragDropEffects.Copy Return End If Next End Sub Private Sub tbXml1_DragDrop(sender As Object, e As DragEventArgs) Handles tbXml1.DragDrop ' how many files were dropped at same time ? ' MsgBox(e.Data.GetData(DataFormats.FileDrop).length) For Each s In DirectCast(e.Data.GetData(DataFormats.FileDrop), String()) If _OniTypes.Contains(Path.GetExtension(s)) Then tbXml1.Text = Path.GetFullPath(s) End If Next End Sub