The following code works fine for Windows when running under Office x32 and x64 but it does not compile in VBA x64 on MacOS:
Option Explicit
Sub TestAddressOf()
Debug.Print GetAddress(AddressOf GetAddress)
End Sub
Function GetAddress(ByVal addr As LongPtr) As LongPtr
GetAddress = addr
End Function
I simply get an Out of Memory error. I've tried passing AddressOf MethodName directly to an API (declared using Declare) and I get the same result.
As soon as I remove the AddressOf operator all code compiles with no errors.
I am using MacOS 11.5.1 (20G80) with Excel x64 for Mac v16.16.27 (201012).
Can anyone test and confirm this behaviour on other versions of Mac/Excel?
Related
I am developing an app in VB.NET (for a customer with hardware using FTDI USB serial chip. Communication uses FTD2XX library and the respective Nuget package (FTD2XX.Net v1.2.1). After some update of Visual Studio (probably update to 17.1, but I am not sure) all functions except a few stopped working. Current VS version is 17.1.1.
For instance, it is possible to obtain number of devices attached by the FTDI driver:
Friend Declare Function FT_CreateDeviceInfoList Lib "FTD2XX.DLL" (ByRef lngNumDevs As Integer) As Integer
...
Dim ftStatus As Integer
Dim numDevices As Integer
ftStatus = FT_CreateDeviceInfoList(numDevices)
In the above snippet ftStatus result = 0 (i.e. OK) and numDevices is set to 1 (correct).
Problem starts when I want to do something serious:
Friend Declare Function FT_GetComPortNumber Lib "FTD2XX.DLL" (ByVal lnghandle As Integer, ByRef lplComPortNumber As Integer) As Integer
Friend Declare Function FT_Open Lib "FTD2XX.DLL" (ByVal iDevice As Integer, ByRef lnghandle As Integer) As Integer
Friend Declare Function FT_Close Lib "FTD2XX.DLL" (ByVal lnghandle As Integer) As Integer
Dim portHandle as Integer
Dim cpNumber as Long
For i% = 0 To 255
ftStatus = FT_Open(i, portHandle)
If ftStatus = FT_OK Then
ftStatus = FT_GetComPortNumber(portHandle, cpNumber)
ftStatus = FT_Close(portHandle)
' here is some non-essential code registering that port at index i% exists...
End If
Next
In the above code, FT_Open returns ftStatus = 0 (FT_OK) and sets a value for portHandle.
However, the next call, FT_GetComPortNumber, returns ftStatus = 1 (FT_INVALID_HANDLE) and the value passed to cpNumber is 0xFFFF (shows as positive, but in fact should be -1, I guess...). What is worse, FT_Close() also returns FT_INVALID_HANDLE and the port remains open. I verified it by trying to open the port from another app - access denied.
Sometimes it seems that FT_Write and FT_Read functions work despite this mess, but in my last try I could not any communication with the hardware at all.
I tried to use System.IO.Ports.SerialPort as possible workaround but that does not work at all. On top of that, I need to use bit-bang on RTS, because it controls supply voltage and reset of the hardware connected to the other side of the FTDI chip. Without possibility to bring RTS down for hundreds of milliseconds and then hold it up all the time I cannot control the hardware. AFAIK System.IO.Ports.SerialPort provides no possibility to do that.
What could be the solution?
After much trial and error, it appears to be a problem in compile configuration.
Open Solution properties Window and click on the Compile tab.
Then click on "Advanced Compile Options"
If the "Remove integer overflow checks" checkbox is not checked, check it!
I have no idea how an integer overflow check can garble a 32-bit number not involved in any arithmetic operation whatsoever, but this is what really happened. I consider this a bug in Visual Basic compiler used in Visual Studio 17.1.6 (and a number of previous versions), but I did not dig deeper in this topic.
#HansPassant writes:
The declarations are wrong, it must be lnghandle As IntPtr. The difference between Integer and IntPtr matter when you run the app in 64-bit mode. Prone to happen when targeting .NETCore, as likely in VS2022.
-- Hans Passant
I keep on getting a Compilation Error user-defined type not defined.
The error is on "Public globalRibbon As IRibbonUI"
I added more references under tools to try and resolve the issue but I am still getting the compilation error
Option Compare Database
Option Explicit
Public globalRibbon As IRibbonUI
Public Sub onRibbonLoad(ByVal ribbon As IRibbonUI)
Set globalRibbon = ribbon
End Sub
Public Sub RibOpenForm(control As IRibbonControl)
DoCmd.OpenForm (control.Tag)
End Sub
Public Sub ControlEnabled(control As IRibbonControl, ByRef enabled)
Select Case control.ID
Case "Primary"
If CurrentProject.AllForms("Primary").IsLoaded Then
enabled = False
Else
enabled = True
End If
End Select
End Sub
I expect to be able to set custom ribbon controls however it is not working.
It seems something is wrong with COM references in your VBA environment. You may try to install the latest updates and/or repair Office.
Compilation Error user-defined type not defined
Open up the VBA editor and go to Tools | References.
Scroll down until you see the following entries:
Microsoft Access X.0 Object library.
Microsoft Office X.0 Object library.
If you have multiple versions, use the latest version.
Both entries should be selected.
I'm currently updating a document for our company that no longer runs when used on a 64bit Microsoft Office suite (32bit remains fine).
I understand that functions and declarations require the 'Ptrsafe' word to be added - but when I add it to this function it tells me the syntax is wrong
Private PtrSafe Function executeSingle(Optional rurl As String = vbNullString, _
Optional qry As String = vbNullString, _
Optional complain As Boolean = True, _
Optional sFix As String = vbNullString _
) As cJobject
I have no idea why though...it works fine if you remove PtrSafe. Any ideas?
You should only need to use the "Declare" statement when you declare a reference to an external procedure in a dynamic-link library (DLL). It is always recommended that you use the PtrSafe keyword when doing this. Like A.S.H. said, you don't need to do this for your own functions. See this link for more info.
Here is an example from MSDN of the correct syntax for using PtrSafe. It includes conditional compilation syntax, which might be useful in your situation:
Declare PtrSafe Function GetActiveWindow Lib "User32" () As LongPtr
#If Vba7 Then
' Code is running in 32-bit or 64-bit VBA7.
#If Win64 Then
' Code is running in 64-bit VBA7.
#Else
' Code is not running in 64-bit VBA7.
#End If
#Else
' Code is NOT running in 32-bit or 64-bit VBA7.
#End If
I found possible to use CMD window to start typical NET GUI application.
But not so clean, with some issues.
Here is my example code:
Public Class main_form
Private Declare Function AttachConsole Lib "kernel32.dll" (ByVal dwProcessId As Int32) As Boolean
Private Declare Function FreeConsole Lib "kernel32.dll" () As Boolean
Dim mykey As String = "A01F-FFB4-0402"
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
If My.Application.CommandLineArgs.Count > 0 Then
If AttachConsole(-1) Then
Dim kill_Me As Boolean = False
Dim cArgs() As String = GetCommandLineArgs()
For c As Integer = 0 To cArgs.Length - 1
cArgs(c) = cArgs(c).ToLower()
If cArgs(c) = "getkey" Then
Console.WriteLine(mykey)
kill_Me = True
End If
Next
FreeConsole()
If kill_Me Then End
If (MessageBox.Show( _
"Asked command not present." & NewLine & "Start program with GUI normally?", "", _
MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) = _
DialogResult.Cancel) _
Then End
End If
End If
Please ignore security issues, this is just an example.
Like people here concludes problem is in terminating console. Here are approach with sending key "ENTER" to it but this is obviously not good solution.
If I start example program from CMD window with: c:\mydir>myprogram.exe getkey|more then console behaves more "natural" than without switch "more".
1) But, if I start a program with c:\mydir>myprogram.exe getkey: is it possible with VBNET to add keyword "|more" to commandline argument "getkey" before execution so program will execute "getkey|more" instead of only "getkey"?
2) Is it acceptable to terminate GUI program with just command "End" in form's _Load handler like is showed in example? I try Application.Exit() and Me.Close() where program don't behaves well.
Your application (be it .Net or native, doesn't matter) can be a console application or GUI application, but not both. This has been discussed before by smarter people than me: How do I write a program that can be run either as a console or a GUI application:
Each PE application contains a field in its header that specifies which subsystem it was designed to run under. You can say IMAGE_SUBSYSTEM_WINDOWS_GUI to mark yourself as a Windows GUI application, or you can say IMAGE_SUBSYSTEM_WINDOWS_CUI to say that you are a console application. If you are GUI application, then the program will run without a console.
The subsystem determines how the kernel prepares the execution environment for the program. If the program is marked as running in the console subsystem, then the kernel will connect the program's console to the console of its parent, creating a new console if the parent doesn't have a console. (This is an incomplete description, but the details aren't relevant to the discussion.) On the other hand, if the program is marked as running as a GUI application, then the kernel will run the program without any console at all.
So if you have a GUI application then you cannot connect the application stdin/stderr to your console, so pipes will not work, ergo things like cat, more, less, tee are all a no-go for a GUI application. Not to mention that the CMD console will not wait for your application.
Try not to cheat. Use a GUI for GUI, use a console app for console. Share common code in libs.
Is it possible to check if computer is 32 bit or 64 using vb.net code?
I just want to display the result in a message.
Please advise.
Environment.Is64BitOperatingSystem should do nicely.
Determines whether the current operating system is a 64-bit operating system.
The assumption being that a false signifies a 32bit environment.
If you want to find out if the process is 64bit (as you can run a 32bit process on a 64bit OS), use Environment.Is64BitProcess:
Determines whether the current process is a 64-bit process.
Both of these have been introduced in .NET 4.0.
IntPtr.Size won't return the correct value if running in 32-bit .NET Framework 2.0 on 64-bit Windows (it would return 32-bit).
You have to first check if running in a 64-bit process (I think in .NET you can do so by checking IntPtr.Size), and if you are running in a 32-bit process, you still have to call the Win API function IsWow64Process. If this returns true, you are running in a 32-bit process on 64-bit Windows.
Microsoft's Raymond Chen:
How to detect programmatically whether you are running on 64-bit Windows
Solution:
Private is64BitProcess As Boolean = (IntPtr.Size = 8)
Private is64BitOperatingSystem As Boolean = is64BitProcess OrElse InternalCheckIsWow64()
<DllImport("Kernel32.dll", SetLastError:=True, CallingConvention:=CallingConvention.Winapi)> _
Public Shared Function IsWow64Process( _
ByVal hProcess As Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid, _
ByRef wow64Process As Boolean) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
Public Shared Function InternalCheckIsWow64() As Boolean
If (Environment.OSVersion.Version.Major = 5 AndAlso Environment.OSVersion.Version.Minor >= 1) OrElse Environment.OSVersion.Version.Major >= 6 Then
Using p As Process = Process.GetCurrentProcess()
Dim retVal As Boolean
If Not IsWow64Process(p.Handle, retVal) Then
Return False
End If
Return retVal
End Using
Else
Return False
End If
End Function
I simply use this piece of code and it works fine:
If System.Environment.Is64BitOperatingSystem = True Then
MessageBox.Show("OS System : 64 Bit Operating System")
Else
MessageBox.Show("OS System : 32 Bit Operating System")
End If
If IntPtr.Size = 8 Then
' 64 bit machine
ElseIf IntPtr.Size = 4 Then
' 32 bit machine
End If
VB.NET: What I wanted works as below. Define the custom constant Win64 in x64 all configurations (debug, release etc), like in the diagram below, and use it as follows:
If (Win64) Then
'64 bit code
else
' 32 bit code here
End If
when u need .net 2 (to work around on all windows versions)
it has a very simple way to do it
Function isit64() As Integer
If Directory.Exists("c:\windows\syswow64") And Directory.Exists("c:\program files (x86)") Then
Return 1
Else
Return 0
End If
End Function
Msgbox (Runtime.InteropServices.Marshal.SizeOf(GetType(IntPtr)) * 8)
Use
If System.IO.Directory.Exists("C:\Program Files (x86)") Then
MsgBox("64-Bit OS")
Else
MsgBox("32-Bit OS")
End If
It will work on all the framework versions