Why has my VB.net program decided to be case fussy? - vb.net

I have a small VB.net program that opens some text files, 2 Excel files, a PDF file & creates a new Word document, or opens it if it already exists. Nothing clever, no databases & it works just fine.
I have just bought a Lima device (https://meetlima.com) and have moved my data & program onto the HD attached to it. This is showing on my PC as the "L" drive and everything seems to work EXCEPT the program has now decided to be fussy about the case of the data names !!!
For instance, this code worked just fine before I moved it from my "D" drive to "L" when trying to use the file Tes1 when the value of myLeftCB is TES
myRARfile = myFolder + myLeftCB + mySession + ".zip"
Now I have had to edit the code to this
myRARfile = myFolder + StrConv(myLeftCB, VbStrConv.ProperCase) + mySession + ".zip"
The trouble is, there are a number of similar checks & I don't really want to change all of them, if possible I'd just like to know why something has changed, and where, so I can hopefully change it back !!!

Because Lima is a separate device acting as a file system it's almost certain to be running some form of *nix and that means a case sensitive file system. In order to map case insensitive Windows filenames onto case-sensitive storage they must be doing some magic, leading to your unexpected results.
I agree with #Steve that you're going to have to seek answers from the vendor documentation for this one. In particular, examine the technical documentation to see if there are settings that control how case sensitivity is managed.
If you've got a number of places where this code is duplicated then I'd say that you've already got a weak point in your code. I suggest replacing all of those lines with call to a function that returns the filename. That's a pain to do but it replaces the code duplication so if you have to change the code in future you're only changing it in one place. Your code is easier to maintain and when the Lima vendors change their API in two months you'll only have to change the code in one place to fix it.

Related

AppleScript path being replaced at compile time (New Keynote scripting trouble)

We've got an applescript that tells keynotes to delete slides based on criteria. The new keynote does not have an applescript dictionary, but leaves the old keynote in a subdirectory. So I'm trying to tell AppleScript to talk with the older app rather than the new one.
If I just
tell application "Clean Install:Applications:iWork '09:Keynote.app"
It works, but it doesn't recognize any of the keynote dictionary terms. (delete a slide). So I need to pull out my old friend "using terms from". The challenge here is that this is a precompile directive, so you have to use a string literal, which I don't have on the end user's machine due to different hard drive names.
Ok, still have a plan here. I will write out a new applescript file with the 'using terms from application "Clean Install:Applications:iWork '09:Keynote.app"' and then execute that file... Genius... except for the fact that when AppleScript compiles this line:
using terms from application "Clean Install:Applications:iWork '09:Keynote.app"
Gets changed to:
using terms from application "Keynote"
Which of course calls the new keynote's dictionary which is empty.
Any thoughts on how to keep applescript from helping me out in this way? (or is there a better plan?)
full code:
using terms from application "Clean Install:Applications:iWork '09:Keynote.app"
--using terms from application "Clean Install:Applications:iWork '09:Keynote.app"
tell application "Clean Install:Applications:iWork '09:Keynote.app"
activate
end tell
end using terms from
many thanks!
I'm flyin' blind here (don't have keynote) ... but have you tried using a pre-defined app string as a variable and raw event codes?
You can use Smile to easily get raw event codes by
making a new script window in Smile;
using the "tell" menu item from the Action menu to make that script window application-specific (no tell
block needed);
write a line of code; select line of code
then use the "Copy translate" menu item (cmd-shift-C)
to copy the raw event codes
pasting that raw event code code into a different window that has your working (normal tell block) script
This is what it looks like when I do this for the Mail app:
set origMail to "MyDrive:Applications:Mail.app"
tell application origMail
delete («class mssg» 1 of «class mbxp» "INBOX" of «class mact» 1)
end tell
( When put in a normal tell block, that line of code would be "delete (message 1 of mailbox "INBOX" of account 1)" )
I haven't tried this but I think it will work... when you compile your code with "using terms from" just place your new version of Keynote in the trash. That should force it to use the old version of Keynote's dictionary and your code should compile. If you then save that code as an "applescript application" then it should work on anybody's computer without need to recompile. NOTE: you may need to restart your computer before this trick would work.
Then you just have the problem of targeting the right application on the user's computer because they too might have both versions. Here's some code to find the path to older versions of Keynote and how you would target that.
set lsregister to "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister"
set appName to "Keynote.app"
set nonapplescriptVersion to "6.0"
-- get the path to all Keynote apps
set appPaths to paragraphs of (do shell script lsregister & " -dump | grep " & quoted form of appName)
-- find the one with a version number less than the nonapplescriptVersion of Keynote
set appPath to missing value
repeat with anApp in appPaths
try
-- extract the path
set AppleScript's text item delimiters to "/"
set tis to text items of anApp
set thisPath to "/" & (items 2 thru end of tis) as text
set AppleScript's text item delimiters to ""
-- check the version
if (version of application thisPath) is less than nonapplescriptVersion then
set appPath to thisPath
exit repeat
end if
end try
end repeat
if appPath is missing value then error "Needed application version not installed."
-- use the older version
using terms from application "Keynote"
tell application appPath
activate
-- do whatever
end tell
end using terms from

Access not exiting

Recently, my Access .mdb database started intermittently not allowing Access (both Access 2003 and 2007) to quit. If I quit (whether by pressing the X button or from the menu, then it closes the database and appears to exit Access, as well, but then it suddenly reappears (without any database open). The only way for me to exit at that point is from the task manager.
There are two significant changes that I did recently that might be related. 1) I started using the WinSCP .Net assembly to access an ftp server, which I had to install and register for COM from the instructions here. 2) I started using ODBC, first as a linked table, and then from VBA ADO code (see this). I doubt that this second change is causing this problem because I've had the problem both when I was using the linked tables and when with ADO.
This doesn't happen every time I open the database, and I haven't noticed a pattern. What could be causing this strange problem?
Edit - I found the root of the problem. By breaking my ftp download code at various points and seeing whether it will exit, I narrowed it down to the following:
Dim PDFFolders As Recordset
Set PDFFolders = CurrentDb.OpenRecordset("PDFFolders")
Dim syncOptions As TransferOptions
Set syncOptions = New TransferOptions
syncOptions.filemask = "*/*.pdf"
On Error Resume Next 'In case it doesn't exist
Do While Not PDFFolders.EOF
sess.SynchronizeDirectories SynchronizationMode_Local, info!RTFFolder, _
info!BasePDFFolder & "/" & PDFFolders!Name, False, , , _
syncOptions
PDFFolders.MoveNext
Loop
PDFFolders.Close
Set syncOptions = Nothing
Set PDFFolders = Nothing
On Error GoTo 0
If it runs the sess.SynchronizeDirectories statement, then access won't exit, otherwise it does. Looks to me like a bug win WinSCP.
I can do other things like downloading files, creating directories, etc. with no problem, but when it gets to this statement, it doesn't exit access afterwards.
Sticky instances of Access usually result from hanging object references.
If Access hangs the way you described, I would suspect a nasty circular reference.
To investigate on circular references, you basically have two options:
Inspect your code on circular dependencies - That might become tedious and not so easy. But if you know your code base deeply, you might have suspects where to look first.
Add logging to your code - In case you cannot spot the problem via inspection alone, you can consider adding consequent logging of object creation/deletion (through Class_Initialize/Class_Terminate). For larger code bases using classes heavily, this is a good investment to start with.
If your problem is with classes where you cannot control the code (as is your case), you might consider using that external classes only through wrapper classes where you can log creation/deletion. Of course in tricky cases, termination of the wrapper class does not mean termination of the wrapped class.
BTW, I strongly recommend to make sure to set every object reference explicitly to Nothing ASAP:
Set MyObj = GetMyObject()
' Proceed with coding here later
' First write the following line
Set MyObj = Nothing
Special thoughts have to be given in the case of local error handling to make sure to set the reference to Nothing in either case.
A good way to ensure this is using a With-block instead of an explicit variable (if the usage pattern allows to):
With GetMyObject()
' Use the object's members here
End With
With this pattern you save declaring the local variable and can be sure that the object reference does not survive the current method.
I still think it's a bug in WinSCP, but I found a workaround. I noticed that it only happened if I took the information from a table in the database, and not if I put in a hard-coded string. So I just added & vbNullString, which concatenates a blank string, which changes the data type from a Field to a String, and now it doesn't happen anymore.

Using ReadLine, where did my text go?

I'm pretty new to visual basic (and coding in general) so if I've made any really simple mistakes let me know.
Right now, I'm getting a pretty weird problem with my vb.net code.
The filestream is able to correctly open the file and read from it - but what's weird is that while the code is able to read a bunch of lines from the beginning of the file, when I manually open the file in notepad I'm not. Here's the code:
Dim fs, f, s 'filesystemobject, file, stream.
fs = CreateObject("Scripting.FileSystemObject")
f = fs.GetFile(CurrDataPath) ' This change made to ensure the correct file is opened
s = f.OpenAsTextStream(1, 0) ' 1 = ForReading, 0 = as ASCII (which i think is right?)
Dim param(14) As String
Dim line As String
line = s.ReadLine()
While i <= 14
i += 1
MessageBox.Show(line)
line = s.ReadLine()
End While
(I've read that arrays are a bad idea but they've been convenient and haven't caused me any problems so I've been using them anyways.)
What's weird is that when this code is run, it will (in the message boxes) show me the information I want to see - which isn't bad at all. The information that I want looks like this:
BEGINPARAM
parameter1, 0
parameter2, 7.5
ENDPARAM
EDIT:
After using Path.GetFullPath(DFile), I found that there were two files in different directories with the same name DFile. The file I had been opening in Notepad was saved in the directory where I expected it to be saved, while the file the code was reading was saved in the VB project's folder.
Once I changed the code to rely on CurrDataPath which includes the expected path, the code read from the file exactly what I did in notepad.
I do have word wrap on in notepad, so I know that's not the issue, however, I will look into getting notepad++.
The file named DFile is created in a c++ program that I'll be digging through to find out why one part of the file is written to a different folder than the rest.
Obviously I'm missing something important, and if anyone could help, that would be great.
*Note: This is a vb6 migration project so if anyone asks I can provide the old code.
Assuming the most recent version of VB.Net, the modern way to write that is like this:
For Each line As String In File.ReadLines(CurrDataPath).Take(14)
MessageBox.Show(line)
Next
I'm not 100% clear on what you're saying. There's nothing in this code that outputs to a file, so what you have to be saying is that when you open the file referenced by "DFile" on line 3 above, that file doesn't have the lines containing "parameter1, 0" and "parameter2, 7.5" in it?
Since we know that's not technically possible, do verify the answer to the question above and make sure you're really opening the same file in notepad as the script is opening. The second thing to do is to turn on Word Wrap in Notepad or download Notepad++ (a text editor I think everyone should have anyway) and make sure that the data's actually missing, and not just not showing on your screen because it's not using Windows style line endings.

VBA File Dialog .FileName removing .1 from end of file name

I am using visual basic to write a Macro for Autodesk Inventor. I created a macro that calls a file dialog, see code below. Everything works fine except when a user puts a file name in with a period and a number greater than zero following it.
For example, if a user puts testfile.test in the box and hits ok. When I ask for what they put in there using .FileName, I get "testfile.test". Just like I should.
However, if the user puts testfile.1 or testfile.10 or testfile.1mdksj or anything as long as a number greater than zero directly follows the period I get back "testfile". For some reason, everything after the period and the period gets removed.
What is the reason for this? Is this a bug in visual basic or am I doing something wrong?
'Set up the file dialog
Dim oFileDlg As FileDialog
' Create a new FileDialog object.
Call ThisApplication.CreateFileDialog(oFileDlg)
'Define the filter to select part and assembly files or any file.
oFileDlg.Filter = "All Files (*.*)|*.*"
'Define the part and assembly files filter to be the default filter.
oFileDlg.FilterIndex = 1
'Set the title for the dialog.
oFileDlg.DialogTitle = "Save File As"
'Tell the dialog box to throw up and error when cancel is hit by user
oFileDlg.CancelError = True
'Show the file dialog
On Error Resume Next
oFileDlg.ShowSave
'save the user specified file
Dim newFileName As String
newFileName = oFileDlg.FileName
UPDATE:
I ended up doing the following "hack" to make things still work while dealing with a period:
oFileDlg.fileName = sFname & "."
oFileDlg.ShowSave
fullName = Left$(oFileDlg.fileName, Len(oFileDlg.fileName) - 1)
That worked fine for quite a while on Windows 7 and then Windows 10. Unfortunately, the Windows 10 Creative update seems to have changed how the file dialog works. With the above code, fullName would come back blank if there were no periods in the name and would truncate everything from the FIRST period from the left if there was a period in the name.
I'm not really sure what changed in Windows 10, but it pretty much destroyed my hack. Windows 7 still works fine and Windows 10 before the creative update works. I ended up doing the following to make everything work again in the version of Windows I mentioned above.
oFileDlg.fileName = sFname & ".00"
oFileDlg.ShowSave
fullName = Left$(oFileDlg.fileName, Len(oFileDlg.fileName) - 3)
This is a VB property, but it may extend to VBA as well. Have you tried setting the save settings to support multidotted extensions? Try something like this:
SupportMultiDottedExtensions = True
This setting is intended permit the use dotted extensions - meaning the use of periods in the file name. See this MSDN reference for documentation and information: http://msdn.microsoft.com/en-us/library/system.windows.forms.filedialog.supportmultidottedextensions.aspx#Y129
This SO article may also shed further light: SaveAs Dialog with a period in the filename does not return extension
EDIT
After checking the autodesk documentation - a difficult and unpleasant task, in my opinion - there does indeed appear to be no support for MultidottedExtensions. I did, however, find a function on VBAExpress that I have very closely adapted. The function can be used to filter strings with contain unacceptable characters. Jimmy Pena's blog has an excellent function for just such a purpose: http://www.jpsoftwaretech.com/excel-vba/validate-filenames/. I have only substantively added a period and a replace to the code:
'A function for filtering strings, with a focus on filenames.
Function FilterFileNameString(stringToScrub As String) As String
'Filters a filename string - or any string for that matter.
Dim FilteredString As String
'A highly nested replace function.
FilteredString = Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(stringToScrub, ".","|", ""), ">", ""), "<", ""), Chr(34), ""), "?", ""), "*", ""), ":", ""), "/", ""), "\", "")
'Returns filtered string.
FilterFileNameString = FilteredString
End Function
Jimmy Pena's blog also contains a recursive version as well, although he does not recommend it.
You can filter any strings to be used as filenames with another character - a space in this case. You could use an underscore, however, or any other character you deemed pleasant.
In general, if you are trying to use periods for versioning or a similar purpose, and inventor will not let you, I would strongly advise going to another character or set of characters that can provide such an indication, such an underscore "_", a numbering system, "001", "002", a lettering system, "AAA", "AAB", or whatever makes sense for your focus.
If you are just making the application user-friendly, I would suggest filtering the strings entered before saving them in the desired filetype, and separate the filtering of the strings from the save dialog if the period filtering gives you grief. It may add an extra step, but it may be the best and easiest way to filter out pesky invalid characters without creating unnecessary extra hassles for your users.
~JOL

protecting software to run only on one computer in vb.net

I have developed a small application and now i want to protect it.
I want to run it only on my own computer and i have developed it for myself.
How can i do that?
A. Don't publish it.
B. Hard-code your computer name in the code, and make the first thing the program does to be verifying that System.Environment.MachineName matches it.
You could always check the processor ID or motherboard serial number.
Private Function SystemSerialNumber() As String
' Get the Windows Management Instrumentation object.
Dim wmi As Object = GetObject("WinMgmts:")
' Get the "base boards" (mother boards).
Dim serial_numbers As String = ""
Dim mother_boards As Object = _
wmi.InstancesOf("Win32_BaseBoard")
For Each board As Object In mother_boards
serial_numbers &= ", " & board.SerialNumber
Next board
If serial_numbers.Length > 0 Then serial_numbers = _
serial_numbers.Substring(2)
Return serial_numbers
End Function
Private Function CpuId() As String
Dim computer As String = "."
Dim wmi As Object = GetObject("winmgmts:" & _
"{impersonationLevel=impersonate}!\\" & _
computer & "\root\cimv2")
Dim processors As Object = wmi.ExecQuery("Select * from " & _
"Win32_Processor")
Dim cpu_ids As String = ""
For Each cpu As Object In processors
cpu_ids = cpu_ids & ", " & cpu.ProcessorId
Next cpu
If cpu_ids.Length > 0 Then cpu_ids = _
cpu_ids.Substring(2)
Return cpu_ids
End Function
Was taken from where: http://www.vb-helper.com/howto_net_get_cpu_serial_number_id.html
Here's a question by Jim to convert this for Option Strict.
It really depends on who is the "enemy".
If you wish to protect it from your greedy, non-cracker, friends, then you can simply have the application run only if a certain password is found in the registry (using a cryptographically secure hash function), or use the MachineName as Jay suggested.
But if you're thinking of protecting it from serious "enemies", do notice: It has been mathematically proven that as long as the hardware is insecure, any software running on it is inherently insecure. That means that every piece of software is crackable, any protection mechanism is bypassable (even secured-hardware devices such as Alladin's Finjan USB product key, since the rest of the hardware is insecure).
Since most (if not all) of today's hardware is insecure, you simply cannot get 100% security in a software.
In between, there are lots of security solutions for licensing and copy-protection. It all comes down to who is the enemy and what is the threat.
No matter how hard you try, if someone really want to run it on another computer, they will.
All need to do is reverse engineer your protection to
remove it
play with it
Another option might be to have your program ask the USER a question that has a derived answer. Here's a brain dead example....
Your Program: "What time is it now?"
You Enter: (TheYear + 10 - theDay + 11) Mod 13
In this way its actually ONLY YOU that can run the program instead of it being MACHINE dependent.
I have made things like this in VB DOS.
I either made a non-deletable file that is key to a specific machine with a code inside, and/or read the .pwl files and have several checks, that are only on your machine. The non-editable file is made with extended character sets like char 233 so when a person tries to look at it, it will open a blank copy (edit) (write.ex), so data cannot be read and it cannot be edited moved or deleted.
It needs to be certain characters; I am not sure if every charter between 128 and 255 will work it, some extended characters work to do this some will not, also it can be defeated, but it will keep some people out,
But it can be read or checked in a program environment. Nothing is totally secure, this is some of the things I mess with.
Note: the file will be very hard to delete, maybe make a test directory to test this.
I hope this is OK I am not very good at conveying info to people; I have programmed since 1982.
Another idea ... I wrote a program that cannot be run directly, it is only ran by an external file, so you could add in a password entry section to it and encrypt password so it cannot be read very easily ,I made an executable version of a vb program to test. it writes in to slack space a character so if the program sees that value it will not run, BUT the runner program has a different character, and it changes it to that character ,and the program is designed to only let in if the character is the proper one ,made only by the runner , then when it enters it changes it back so it is not left open , I have made this sorta thing, and it does work, there is always a way to defeat any protection , the goal is to slow them down or discourage them from running or using your program if you do not want them to.I may include examples at a later date.