Visual Basic .NET: Difference between revisions

From OniGalore
Jump to navigation Jump to search
(Categories? Suggestion: "Script languages" for "BSL" and "Visual Basic Script". And "Programming languages" for (now only) "VB.net". -- I would find it really helpful if I could continue to drop condensed thoughts here on this wiki.)
 
m (link fix; pretty sure this is what's being referred to)
 
(11 intermediate revisions by 3 users not shown)
Line 1: Line 1:
==Visual Basic .NET==
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 documentation with focus on Oni-related aspects.


 
==Projects==
===Projects===
* [http://mods.oni2.net/node/332 Simple OniSplit GUI]
* [[User:Paradox-01/for_WIP_pages#Simple_Converter_GUI|Simple Converting GUI]] (for OniSplit)
* [[TRAM setup assistant]]
* [[TRAM setup assistant]]




===Basic knowledge===
==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).




===Code snippets===
===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_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.
Common functions that are shared among VB.net projects should have their own class.


Line 19: Line 121:




'''Class Oni'''
===Oni Class===


Functions in this class:
Functions in this class:
Line 27: Line 129:
: GetXSI - returns Mod Tool path (type string) (e.g. C:\Softimage\Softimage_Mod_Tool_7.5\Application\bin)
: 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)
: 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 System.IO ' for files and directories
Line 36: Line 138:
   
   
   
   
     Public Shared Function GetApp()
     Shared Function GetApp()
         Return Application.StartupPath().ToString()
         Return Application.StartupPath().ToString()
     End Function
     End Function
   
   
     Public Shared Function ReadRegStr(RootKey, Key, Value, RegType)
     Shared Function ReadRegStr(RootKey, Key, Value, RegType)
         Dim oCtx, oLocator, oReg, oInParams, oOutParams
         Dim oCtx, oLocator, oReg, oInParams, oOutParams
   
   
Line 59: Line 161:
     End Function
     End Function
   
   
   Public Shared Function GetAE()
   Shared Function GetAE()
         Dim OS_bitness As Integer
         Dim OS_bitness As Integer
         Dim WshShell = CreateObject("WScript.Shell")
         Dim WshShell = CreateObject("WScript.Shell")
Line 92: Line 194:
         Next
         Next
   
   
         If FoundXsi = True Then
         If FoundXsi = False Then
            Return XsiDir
        Else
             Return ""
             Return ""
         End If
         End If
Line 115: Line 215:
         End If
         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 Function
   
   
Line 120: Line 234:




===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




<!-- points allowed in category name? -->


[[Category: VB.net]]
[[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