The problem: Control.HorizontalAnchor or Control.VerticalAnchor gets a value out of the accepted range.
In the IDE window:
Debug.Print Btn.VerticalAnchor --> Result: 4864
In the Immediate window:
?Btn.VerticalAnchor --> 0
Same line. Same code.
I am stumped. Please help.
L.E.: apparently the value somehow gets distorted after
If Btn.HorizontalAnchor = acHorizontalAnchorRight Then
I got nearly the same issue running Microsoft Access 2013 x64 15.0.5349 (VBA 7.01).
For me the controls HorizontalAnchor property contains the value of the expected AcHorizontalAnchor enumeration plus 25344.
So if the controls HorizontalAnchor is configured to acHorizontalAnchorLeft (0) it contains 25344.
For acHorizontalAnchorRight (1) it contains 25345.
And for acHorizontalAnchorBoth (2) it contains 25346.
Comparing my value 25344 and your value 4864 I can see that their binary representation both contain additionally set bits in the higher byte:
Decimal
Binary
4864
1 0011 0000 0000
25344
110 0011 0000 0000
So the workaround I use is to ignore the high byte of HorizontalAnchor:
If (xControl.HorizontalAnchor And &HFF) = _
AcHorizontalAnchor.acHorizontalAnchorLeft Then _
Debug.Print "-> Left"
If (xControl.HorizontalAnchor And &HFF) = _
AcHorizontalAnchor.acHorizontalAnchorRight Then _
Debug.Print "-> Right"
If (xControl.HorizontalAnchor And &HFF) = _
AcHorizontalAnchor.acHorizontalAnchorBoth Then _
Debug.Print "-> Both"
It should be similar with VerticalAnchor.
Related
I've written an app which brings in a CSV export from our HR system, loops through all the records and applies the values from the HR system to active directory.
It works a treat, and when running on my machine i get no errors whatsoever.
When running it on one of our servers, where it is ultimately going to live and will be executed by a service account, I get date conversion errors...
System.InvalidCastException: Conversion from string "21/08/2020" to type 'Date' is not valid.
Right at the start of my code I'm defining the region...
Dim ukCulture = New Globalization.CultureInfo("en-GB")
System.Threading.Thread.CurrentThread.CurrentCulture = ukCulture
And if I query current culture at runtime, it shows 'en-GB', so that seems right.
If i write out the date strings, they all look right, and the compare operation is working fine.
The error seems to occur in this section of code...
Dim converted_hr_accountexpiry_timestamp= hr_row(0).Item("Termination Date") & ""
Dim hr_termdate_var() As String = converted_hr_accountexpiry_timestamp.split("/")
updatescript = updatescript.Replace("$x", "'" & hr_termdate_var(0) & "'") _
.Replace("$y", "'" & hr_termdate_var(1) & "'") _
.Replace("$z", "'" & hr_termdate_var(2) & "'")
So for context, this code is building up a powershell script which is executed to make the necessary changes in AD.
The section of that powershell code that we're looking at here is this...
$server = "MyPrimaryDNSServer.FQDN"
$exp = get-date -Day $x -Month $y -Year $z -Hour 00 -Minute 00 -Second 00
$expirydate = $exp.ToUniversalTime().AddDays(1)
It seems clear that its trying to use a US date format, because if the date provided would match an acceptable US date, ie 3/5/2020, then it will accept it and the wrong date will be applied. The error is only thrown when the day (dd) portion of the date would not be accepted as MM on an american format date, ie 31/07/2020.
And to re-iterate; this issue doesnt happen on my machine, only on the server that will eventually execute the application. I've been through all the region settings on that device itself and everything is set to united kingdom, with the correct dd/MM/yyyy formats for dates.
I'm at a total loss on this one and pulling out what little hair i have left.
Any suggestions/help appriciated!
EDIT 1:
This is the full exception, minus the users name obvs...
Error with account : Joe Bloggs (1010245)
System.InvalidCastException: Conversion from string "24/07/2020" to type 'Date' is not valid.
at Microsoft.VisualBasic.CompilerServices.Conversions.ToDate(String Value)
at Microsoft.VisualBasic.CompilerServices.Operators.CompareObject2(Object Left, Object Right, Boolean TextCompare)
at Microsoft.VisualBasic.CompilerServices.Operators.CompareObjectEqual(Object Left, Object Right, Boolean TextCompare)
at Atlas.Main.GetAccountsWithUpdates()
EDIT 2:
So it looks like there are two errors occuring, which is why I couldnt find it by commenting each related line out in turn.
This is definately one of the erroring lines...
converted_ad_expiry_timestamp = converted_ad_expiry_timestamp.ToString("dd/MM/yyyy").Split(" ")(0)
The value returned is a datetime not a date, so i use tostring and split it on the space to grab just the date portion.
The second error seems to occur in here...
If Not (converted_hr_expiry_timestamp = converted_ad_expiry_timestamp) Then updateme = True : If (hr_row(0).Item("Termination Date")) = "" Then account_expiration_date = "$null" Else account_expiration_date = converted_hr_expiry_timestamp
It looks like the problem revolves around converted_ad_expiry_timestamp which seems to be a Date (the VB type is an alias for a .NET DateTime). You put it into a specific localized format via converted_ad_expiry_timestamp.ToString("dd/MM/yyyy") and then rely on automated conversion to turn it back into a Date. The way to avoid the problem you see here (where the automated conversion uses the system locale to decide the format) is to use one of the Parse or ParseExact family to control the conversion yourself. With Parse, you can specify the locale to use, or with ParseExact you can specify the format.
Similarly, when you attempt to compare them in If Not (converted_hr_expiry_timestamp = converted_ad_expiry_timestamp) Then ..., the first item in the comparison is a string; if you want to do this comparison, you need to either use ToString on the ad_expiry or parse the hr_expiry into a Date.
I would also recommend using Option Strict if you can to turn these implicit conversions into errors, or if that would introduce to many issues, at least turn on the warning for implicit conversions.
I know this is just working around the problem, and will stop it working locally for you (or rather move the problem to your machine), but if it's only ever going to be run on that server can you not just swap X and Y values?
Dim converted_hr_accountexpiry_timestamp= hr_row(0).Item("Termination Date") & ""
Dim hr_termdate_var() As String = converted_hr_accountexpiry_timestamp.split("/")
updatescript = updatescript.Replace("$x", "'" & hr_termdate_var(1) & "'") _
.Replace("$y", "'" & hr_termdate_var(0) & "'") _
.Replace("$z", "'" & hr_termdate_var(2) & "'")
Alternatively, if you want it to work on both systems then maybe a check before running the offending code is in order, something like this has worked for me in the past:
Try
Dim TempTimeString As String = "31/01/2020 01:00 AM"
Dim ConvertedTime As Date
ConvertedTime = DateTime.Parse(TempTimeString)
'''Don't swap X and Y as it was able to convert
Catch ex As Exception
'''swap X and Y as it was unable to convert
End Try
I'm writing numbers in a text file one number in each line like this:
N=3
My.Computer.FileSystem.WriteAllText(file_name, N & vbCrLf, True)
If I then read this line with Fortran instead of returning 3 it returns Ύ╗┐3.
And if I read it with Python it returns ο»Ώ3
This only happens at the very first of the file and nowhere else. How do I get rid of it and why it's there?
This method uses UTF-8 encoding without a Byte-Order Mark (BOM). Environment.NewLine is platform independent. Requires Imports System.IO at top of file.
Private Sub OPCode()
Dim N = 3
File.AppendAllText(file_name, N & Environment.NewLine)
End Sub
Consider using vbNewLine instead of vbCrLf.
Dim N As Integer = 3
My.Computer.Filesystem.WriteAllText(file_name, N & vbNewLine, True)
This should solve your issue. Or, that problem has a high chance of happening due to text encoding problems.
I am trying to write a helper script for a colleague that will automatically open up all .doc(x) files in a directory, find any and all chinese characters, set their Font, save and close.
I already have a working version of this script. The file opening/saving/closing part is handled in Python/win32com and works fine. My big point of contention is still the VBA macro.
I know there is a regex (\p{Han}) that should be able to catch all Chinese characters, but this does not seem to work in VBA. Similarly, I have tried using Unicode Ranges and Chr(W). Nothing so far produced any output, let alone correct output.
Out of frustration, I made one last ditch attempt and simply inverted the search paramters. This is how it is now:
Sub FindReplace_zh(Rng As Range)
With Rng.Find
Do While .Execute(FindText:="[!A-ZÄÖÜa-zäöü0-9><_ ^11^13§$²³%#&/\+-]", MatchWildcards:=True)
If Rng.Font.Bold = True And Rng.Font.Name Like "Arial*" Then
Rng.Font.Name = "SimHei"
ElseIf Rng.Font.Bold = False And Rng.Font.Name Like "Arial*" Then
Rng.Font.Name = "SimSun"
End If
Rng.Collapse 0
Loop
End With
End Sub
AT LEAST THIS WORKS, but its far from elegant and still produces some undesired output.
I have yet to understand how I can substitute "[!A-ZÄÖÜa-zäöü0-9><_ ^11^13§$²³%#&/+-]" with a variable, or most anything else. Many characters are not covered by this regex, such as "(", ")" etc., but adding them (even escaped with ) will result in runtime errors in VBA.
I found a lot of tutorials and questions dealing with removing or inserting text, but my specific case of finding text and then changing the font, while leaving everything else untouched, seems rather specific.
Fun fact:
I had to add ^11 and ^13 to the regex list, as not including them would lead to the Macro inserting new linebreaks in random positions of the .doc
EDIT:
New try with comment:
Dim searchPattern As String
searchPattern = "[" & ChrW(&H2E80) & "-" & ChrW(&HFFED) & "]{1,}"
With Rng.Find
Do While .Execute(FindText:=searchPattern, MatchWildcards:=True)
Invalid operation on final line!
I also would not have concatinated a string like this. I am not sure how VBA parses this, but apprently not the way we hoped.
EDIT2: FIX
Removing "{1,}" from searchPattern did it. Now it works exactly as I expected it to :)
searchPattern = "[" & ChrW(&H2E80) & "-" & ChrW(&HFFED) & "]"
It is possible to find the value of characters that cannot be represented in the VBIDE by pasting them into an empty Word document and then using VBA to print the AscW values of each character in the text you wish to investigate. You can then use ChrW in VBA to reassemble the text in a VBA friendly way.
From
pinyin.info/news/2016/…
You can use the find string "[⺀-■]{1,}" to find any Chinese character. However as you have noted when you paste this text into the VBA IDE you get [?-?]{1,} because VBA uses UTD-8 as its character set. (I think).
The following code
Public Sub PrintCharacterValues()
Dim myIndex As Long
With ActiveDocument.Paragraphs(1).Range
For myIndex = 1 To 8
Debug.Print .Characters(myIndex), AscW(.Characters(myIndex)), Hex(AscW(.Characters(myIndex)))
Next
End With
End Sub
Gives the output of
" 34 22
[ 91 5B
? 11904 2E80
- 45 2D
? -19 FFED
] 93 5D
" 34 22
160 A0
Thus you can get the critical section of the find string as
"[" & ChrW(&H2£80) & "-" & ChrW(&HFFED) &"]"
I've been searching for two days to solve my issue but so far nothing.
There are many (Very many) vba excel tools developed where I work and our regional settings in PC-s determine comma as decimal separator but reports and data downloaded from our systems have dot as decimal separator. In these tools, when needed we just have set UseSystemSeparators = False then DecimalSeparators = "." and at the end of the macro reverted back.
Now new people have been getting windows 10 pcs and some of the tools run into errors. I got a Win10 pcs from IT to test and found out that no matter how I set in Excel settings VBA Macro uses PC regional settings while on the sheet it still uses what is determined in Excel settings. Same file, same test in my win7 pc and if set then both on sheet and vba macro use local application settings.
Does anyone know what is the reason and how it could be fixed? I can figure many workarounds but all of these mean that the tools need to be re-coded and there are just so many of these that I still keep finding out new tools used and what were developed before I joined the company in March. Changing all ~300 PC-s regional setting is not an option because it needs to be comma as decimal separator normally.
Edit: just to make it bit more clear I'll add some code:
Sub test()
Application.UseSystemSeparators = False
Application.DecimalSeparator = "."
variable = "10.1"
MsgBox CDbl(variable)
End Sub
Under Windows 7 - no problem. The variable containing a string can be converted.
Under Windows 10 - Run-time error, Type mismatch. Both PCs have "," as system separator. The funny thing is that when I change "10.1" to "10,1" then that works on both PC-s. Settings for both PC-s are same. System uses "," as separator and Excel is set to use ".".
This answer is based on your system (default) DecimalSeparator being a comma (,) and ThousandsSeparator being a point (.) - using Windows 10
Explanation:
I've done a little testing and found that the following functions only change the DecimalSeparator within Excel, not within VBA:
Application.UseSystemSeparators = False
Application.DecimalSeparator = "."
Application.ThousandsSeparator = ","
This means that when you change the DecimalSeparator by using these lines of code, it will simply update the values in your workbooks to be displayed in the format you are specifying. For example if your system format is:
100.000.000,99
Then the lines of code above would convert the values to:
100,000,000.99
However, when you run the code above and try to use a string that uses the non-system format for the DecimalSeparator then VBA will not recognise it.
Example:
(Where Application.DecimalSeparator = "," when Application.UseSystemSeparators = True)
Sub TestSeparator()
Application.UseSystemSeparators = False
Application.DecimalSeparator = "."
Application.ThousandsSeparator = ","
Debug.Print CDbl("100.99")
End Sub
This code will return 10099, not the expected double of 100,99 (in your system format) because VBA does not see the DecimalSeparator of "." as a DecimalSeparator.
Solution:
When referencing doubles within VBA you will need to always use the computer's system separators for thousands and decimals. If the doubles are being imported as strings you will need to use Replace to convert the string into a format that uses system separators.
Solution Example:
(Where Application.DecimalSeparator = "," when Application.UseSystemSeparators = True)
If you have the string of "100,000,000.99" in cell A1 and use the following code:
CDbl(Range("A1").Value)
It will produce a "Type mismatch" error. However if you convert this into a string that uses your system separators then no error will be given. You will need to use two Replace functions though, one to remove the ThousandsSeparators and one to convert the DecimalSeparators to your system ones:
CDbl(Replace(Replace(Range("A1").Value, ",", ""), ".", ",")
Perhaps this:
Set ws = ThisWorkbook.Worksheets("Name of Worksheet")
ws.Cells.Replace What:="", Replacement:="", LookAt:=xlPart, _ SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=True, ReplaceFormat:=True
Set ws = Nothing
In the recent versions Excel VBA, the VB engine converts an Integer data type to Long while maintaining the Integer overflow limits. So as a rule of thumb, I always use Long values in Excel VBA.
Does anyone know if the same is true in Access? I realize it's the same engine with different references, but as I move more into Access VBA I never want to assume.
Be careful with your assumptions.
See the following:
Sub checkForVariableMemorySizes()
Dim arrInt() As Integer
ReDim arrInt(1 To 2)
arrInt(1) = 12
arrInt(2) = 456
Dim arrLong() As Long
ReDim arrLong(1 To 2)
arrLong(1) = 12
arrLong(2) = 456
Debug.Print "Integer size:" & vbTab & VarPtr(arrInt(2)) - VarPtr(arrInt(1)) & vbTab & vbTab & "Typename: " & TypeName(arrInt(2))
Debug.Print "Long size:" & vbTab & vbTab & VarPtr(arrLong(2)) - VarPtr(arrLong(1)) & vbTab & vbTab & "Typename: " & TypeName(arrLong(2))
End Sub
this outputs:
Integer size: 2 Typename: Integer
Long size: 4 Typename: Long
You will notice that the sizes are actually different (measured by number of bytes each is incremented, 2 and 4 respectively).
Identical behavior exists for this automatic conversion as the same output from both Excel and Access (I am using Access/Excel 2010 on 32-bit Windows 7). I would be very interested to see what this outputs in older versions.
No, it is not the same in Access.
If you are dealing with numbers larger than the limits of int, you need to use long.
As just a side note, although excel VBA may do the conversion, it is not a good practice.
MS Access Q&A - Overflow Error