Office 32 to 64 VBA conversion - vba

i'm trying to port code from VBA 32 (Excel) that doesn't work in Excel 2013 64bit.
I need to read a HASP key and usually use a hasvb32.dll.
' The main hasp API function
Private Declare Sub hasp Lib "haspvb32.dll" (ByVal Service, ByVal seed, ByVal lpt, ByVal pass1, ByVal pass2, retcode1, retcode2, retcode3, retcode4 As Any)
' WriteHaspBlock function prepares memory for the WriteBlock service
Private Declare Sub WriteHaspBlock Lib "haspvb32.dll" (ByVal Service, Buff As Any, ByVal Length)
' ReadHaspBlock function prepares memory for the WriteBlock service
Private Declare Sub ReadHaspBlock Lib "haspvb32.dll" (ByVal Service, Buff As Any, ByVal Length)
have made the changes to:
' The main hasp API function
Private Declare PtrSafe Sub hasp Lib "haspvb32.dll" (ByVal Service, ByVal seed, ByVal lpt, ByVal pass1, ByVal pass2, retcode1, retcode2, retcode3, retcode4 As Any)
' WriteHaspBlock function prepares memory for the WriteBlock service
Private Declare PtrSafe Sub WriteHaspBlock Lib "haspvb32.dll" (ByVal Service, Buff As Any, ByVal Length)
' ReadHaspBlock function prepares memory for the WriteBlock service
Private Declare PtrSafe Sub ReadHaspBlock Lib "haspvb32.dll" (ByVal Service, Buff As Any, ByVal Length)
with no success. any idea?
thanks

If it's a 32-bit DLL (which it most likely is), there isn't much you can do to make it run in Office 64-bit.
If you've written it, you may recompile it using instructions given in this example. It'll give you a better sense of the parameters to be declared such as your code being Pointer-Safe, etc.
Excellent example and reference by Jonathan Lhost
https://sites.google.com/site/jrlhost/links/excelcdll

Related

How can I declare function without ptrsafe in 64bit environmnet?

My vb6 program was running on 32bit.
Now I have to move it to 64bit.
The lib that I declare below code,the system seem can't get it.
Declare:
Public Declare Function LogonUser Lib "advapi32.dll" _
Alias "LogonUserA" (ByVal lpszUsername As String, _
ByVal lpszDomain As String, ByVal lpszPassword As String, _
ByVal dwLogonType As Long, ByVal dwLogonProvider As Long, _
phToken As Long) As Long
Public Declare Function ImpersonateLoggedOnUser Lib "advapi32.dll" (ByVal hToken As Long) As Long
Public Declare Function RevertToSelf Lib "advapi32.dll" () As Long
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Run Code:
Public Sub Logon(ByVal strAdminUser As String, ByVal _
strAdminPassword As String, ByVal strAdminDomain As String)
Dim lngTokenHandle As Long
Dim lngLogonType As Long
Dim lngLogonProvider As Long
Dim blnResult As Boolean
lngLogonType = 2
lngLogonProvider = 0
blnResult = RevertToSelf()
blnResult = LogonUser(strAdminUser, strAdminDomain, strAdminPassword, _
lngLogonType, lngLogonProvider, _
lngTokenHandle)
blnResult = ImpersonateLoggedOnUser(lngTokenHandle)
CloseHandle (lngTokenHandle)
End Sub
I got the error message
Error 91:Object variable or With block variable not set
Almost people say need to add "ptrsafe" after Declare but there is no ptrsafe in vb6.
How can I declare function lib without "ptrsafe" in the 64bit and vb6 ?
Almost people say need to add "ptrsafe" after Declare but there is no ptrsafe in vb6.
How can I declare function lib without "ptrsafe" in the 64bit and vb6 ?
VBA needs to be able to deal with 64 bit Windows when its run within a 64 bit application such as one of the programs from the 64 bit Office suite.
VB6 runs on its own forever & always as a 32 bit process, it does not need to be 64 bit aware as 64 bit Windows happily emulates 32 bit code with no additional steps required.
Because of this pointer-safe types are not needed, use the 32 bit convention (Long) in VB6.
Your functions declarations are wrong.
You don't have to add the complete path for Lib, only the library name is need.
By add the path, your code fails on 32 bit OS environment, because "C:\Windows\SysWOW64 folder doesn't exists on 32 bit systems.
Public Declare Function LogonUser Lib "advapi32.dll" _
Alias "LogonUserA" (ByVal lpszUsername As String, _
ByVal lpszDomain As String, ByVal lpszPassword As String, _
ByVal dwLogonType As Long, ByVal dwLogonProvider As Long, _
phToken As Long) As Long
Public Declare Function ImpersonateLoggedOnUser Lib "advapi32.dll" (ByVal hToken As Long) As Long
Public Declare Function RevertToSelf Lib "advapi32.dll" () As Long
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
See:
https://support.microsoft.com/en-us/help/248187/how-to-impersonate-a-user-from-active-server-pages
Since you are talking about API declarations the following may be helpful. VB6 does not recognize the LongLong data type (64-bit integer) but it can be faked by using the VB6 Currency data type. The Currency numbers are actually stored as 64-bit integers. The four decimal places are only shown in display by dividing the actual number by 10,000. Depending on the specific API calls you are using, you may need to have dual API declarations and select the correct one at run time. So you also need to be able to detect the "bitness" of the system running.
See the following links:
Detect Bitness
Faking 64-bit Integers

Deploying 32-bit Access system to 64-bit Office machine

I’m compiling my Access database from a 32-bit Office machine running Access 2010. I’m deploying as an .accdr file for use in Access 2010 Runtime. My references are:
VBE7.DLL
MSACC.OLB
stdole2.tlb
ACEDAO.DLL
EXCEL.EXE
msxml6.dll
I will need to deploy to a range of platforms, including 64-bit 2010, 2013 and so on.
I take it there is no problem with most of the references as the deployed system will be using Access 2010 Runtime. However, Excel will give me a problem. I had tried registering the Excel reference (in fact all references, just in case any any other version differed by machine) on the fly, but it seems I can’t register a 64-bit version of Excel from a 32-bit system. Or can I?
Also, would I still need to make changes to API calls (using the PtrSafe keyword) if I’m using Runtime 2010?
Here are some of the API calls I make:
Declare Function aht_apiGetOpenFileName Lib "comdlg32.dll"
Alias "GetOpenFileNameA" (OFN As tagOPENFILENAME) As Boolean
Private Declare Function apiGetLocaleInfo Lib "kernel32"
Alias "GetLocaleInfoA" (ByVal Locale As Long, ByVal LCType As Long, ByVal lpLCData As String, ByVal cchData As Long) As Long
Private Declare Function LoadLibraryRegister Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName$) As Long
Public Declare Function SetDllDirectoryA Lib "kernel32" (ByVal lpPathName As String) As Long
Private Declare Function GetProcAddressRegister Lib "kernel32" Alias _
"GetProcAddress" (ByVal hModule&, ByVal lpProcName$) As Long
Private Declare Function CreateThreadForRegister Lib "kernel32" Alias "CreateThread" (lpThreadAttributes As Any, ByVal dwStackSize&, ByVal lpStartAddress&, ByVal lpparameter&, ByVal dwCreationFlags&, ThreadID&) As Long
You need to make sure that the code is capable of running on both environments. So you could use as me how has suggested Conditional Compiling.
I normally use all the Library calls in a standard module. You should be able to do it something along the lines of:
#If Win64 = 1 And VBA7 = 1 Then
Declare PtrSafe Function aht_apiGetOpenFileName Lib "comdlg32.dll"
Alias "GetOpenFileNameA" (OFN As tagOPENFILENAME) As Boolean
Private Declare PtrSafe Function apiGetLocaleInfo Lib "kernel32"
Alias "GetLocaleInfoA" (ByVal Locale As Long, ByVal LCType As Long, ByVal lpLCData As String, ByVal cchData As Long) As Long
Private Declare PtrSafe Function LoadLibraryRegister Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName$) As Long
Public Declare PtrSafe Function SetDllDirectoryA Lib "kernel32" (ByVal lpPathName As String) As Long
Private Declare PtrSafe Function GetProcAddressRegister Lib "kernel32" Alias _
"GetProcAddress" (ByVal hModule&, ByVal lpProcName$) As Long
Private Declare PtrSafe Function CreateThreadForRegister Lib "kernel32" Alias _
"CreateThread" (lpThreadAttributes As Any, ByVal dwStackSize&, ByVal lpStartAddress&, _
ByVal lpparameter&, ByVal dwCreationFlags&, ThreadID&) As Long
#Else
Declare Function aht_apiGetOpenFileName Lib "comdlg32.dll"
Alias "GetOpenFileNameA" (OFN As tagOPENFILENAME) As Boolean
Private Declare Function apiGetLocaleInfo Lib "kernel32"
Alias "GetLocaleInfoA" (ByVal Locale As Long, ByVal LCType As Long, ByVal lpLCData As String, ByVal cchData As Long) As Long
Private Declare Function LoadLibraryRegister Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName$) As Long
Public Declare Function SetDllDirectoryA Lib "kernel32" (ByVal lpPathName As String) As Long
Private Declare Function GetProcAddressRegister Lib "kernel32" Alias _
"GetProcAddress" (ByVal hModule&, ByVal lpProcName$) As Long
Private Declare Function CreateThreadForRegister Lib "kernel32" Alias _
"CreateThread" (lpThreadAttributes As Any, ByVal dwStackSize&, ByVal lpStartAddress&, _
ByVal lpparameter&, ByVal dwCreationFlags&, ThreadID&) As Long
#End If

Library not registered, Windows XP

Using VB6, I cannot change to VB .NET or anything else.
I'm trying to register a COM Library programmatically in the Form_Load() method of the invoking application.
The method I'm using below works as expected on Windows 7, both x86 and x64. However when I try and use the same application on Windows XP, I receive the Library not registered error:
http://imgur.com/zus2bK6
I have verified that the Library is being registered and it shows properly in the registry at HKEY_LOCAL_MACHINE\SOFTWARE\Classes\MyDll.Component as well as in HKEY_CLASSES_ROOT\AppID\Mydll.DLL
Here is the code I am using, can anyone tell me why this would be occurring on XP only and how to resolve it?
Private Declare Function DllRegisterServer Lib "MyDLL.dll" () As Long
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Any, ByVal wParam As Any, ByVal lParam As Any) As Long
Private Sub Form_Load()
ReDim ConfigFiles(0)
ReDim ConfigFilesToAdd(0)
libID = LoadLibrary("MyDLL.dll")
Dim pAdd As Long
pAdd = GetProcAddress(libID, "DllRegisterServer")
Dim lResult As Long
lResult = CallWindowProc(pAdd, 0&, 0&, 0&, 0&)
Set IGDep = CreateObject(MyDLL.Component")
End Sub
I have performed this process with all manner of permissions including the Administrator account and ensured that I had all permissions on the registry.
Thanks for any help you guys can give.

How do you correctly add an 'About' button to the System Menu?

I am trying to add an 'About' button to the System menu of my app, but the code that I found is throwing an error -
Unable to find an entry point named 'AppendMenu' in DLL 'user32'.
I wonder if someone could please take a look at the code and advise on how what I would need to do to fix it? Thanks.
Private Declare Function GetSystemMenu Lib "user32" (ByVal hWnd As IntPtr, ByVal bRevert As Boolean) As IntPtr
Private Declare Function AppendMenu Lib "user32" (ByVal hMenu As IntPtr, ByVal uFlags As Int32, ByVal uIDNewItem As IntPtr, ByVal lpNewItem As String) As Boolean
Private Const MF_STRING As Integer = &H0
Private Const MF_SEPARATOR As Integer = &H800
Private Sub AddSysMenuItems()
'Get the System Menus Handle.
Dim hSysMenu As IntPtr = GetSystemMenu(Me.Handle, False)
'Add a standard Separator Item.
AppendMenu(hSysMenu, MF_SEPARATOR, 1000, Nothing)
'Add an About Menu Item.
AppendMenu(hSysMenu, MF_STRING, 1001, "About")
End Sub
Well, the message is accurate, there is no entry point named "AppendMenu" in user32.dll. It actually has two versions of it. One is named AppendMenuA, the A means Ansi. The legacy version that uses 8-bit encoded strings, commonly used in old C programs. And AppendMenuW, the W means Wide. It takes a Unicode string like all winapi functions do on modern Windows versions.
Your old-style Declare statement is using the legacy function. You should use the Alias keyword to give the proper entrypoint name:
Private Declare Function AppendMenu Lib "user32.dll" Alias "AppendMenuA" (ByVal hMenu As IntPtr, ByVal uFlags As Int32, ByVal uIDNewItem As IntPtr, ByVal lpNewItem As String) As Boolean
Or just plain call it AppendMenuA. Using the legacy function isn't very pretty, although it won't have a problem converting "About" to Unicode. But do favor the modern way to declare pinvoke functions, it has many advantages beyond automatically mapping to the A or W version:
Imports System.Runtime.InteropServices
Imports System.ComponentModel
...
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
Private Shared Function AppendMenu(ByVal hMenu As IntPtr, ByVal uFlags As Int32, ByVal uIDNewItem As IntPtr, ByVal lpNewItem As String) As Boolean
End Function
...
If Not AppendMenu(hSysMenu, MF_STRING, IntPtr.Zero, "About") Then
Throw New Win32Exception()
End If

Shutdown function perform logoff windows while using Windows API

I have used the following code to shutdown the system but it will perform logoff windows
Private Const EWX_LogOff = 0
Private Const EWX_SHUTDOWN = 1
Private Const EWX_REBOOT = 2
Private Const EWX_FORCE = 4
Public Declare Function ExitWindowsEx Lib "user32" (ByVal uFlags As Long, ByVal dwReserved As Long) As Long
Public Sub ShutDownComputer()
Call ExitWindowsEx(EWX_FORCE, &HFFFFFFFF)
End Sub
try this
Private Const EWX_POWEROFF = 8
Call ExitWindowsEx(EWX_POWEROFF, &HFFFFFFFF)
also this link may help you
Why simply calling ExitWindowsEx won’t Shutdown/Restart the Computer
Try combining SHUTDOWN with FORCE.
In addition to what Eugene said, its better to use the declaration from pinvoke:
Declare Function ExitWindowsEx Lib "user32" (ByVal dwOptions As Int32, ByVal dwReserved As Int32) As Int32
which declares as arguments two four-bytes integers (as the ExitWindowsEx function in the dll).