Function GetUNC(strMappedDrive As String) As String
Dim objFso As FileSystemObject
Set objFso = New FileSystemObject
Dim strDrive As String
Dim strShare As String
'Separated the mapped letter from
'any following sub-folders
strDrive = objFso.GetDriveName(strMappedDrive)
'find the UNC share name from the mapped letter
strShare = objFso.Drives(strDrive).ShareName '<<<< this is the line that the code fails on
'The Replace function allows for sub-folders
'of the mapped drive
GetUNC = Replace(strMappedDrive, strDrive, strShare)
Set objFso = Nothing 'Destroy the object
End Function
It works fine on my laptop and network, but when a colleague uses the same spreadsheet with the same code on their laptop and network the code throws a run-time error 5 exception 'invalid procedure call or argument' at the following line:
strShare = objFso.Drives(strDrive).ShareName
When I hover over the line of code I see: when I run the code to this point I see a file path.
My colleague has tried running the code on his local drive as well as a network drive with no success. We both have the same references selected as well. Does anyone know what I need to do to get this working on my colleagues machine?
Not entirely sure what the issue is, but it might be worth using an API call instead:
#If Win64 Then
Declare PtrSafe Function WNetGetConnection32 Lib "MPR.DLL" Alias "WNetGetConnectionA" (ByVal lpszLocalName As String, ByVal lpszRemoteName As String, lSize As Long) As Long
#Else
Declare Function WNetGetConnection32 Lib "MPR.DLL" Alias "WNetGetConnectionA" (ByVal lpszLocalName As String, ByVal lpszRemoteName As String, lSize As Long) As Long
#End If
Dim lpszRemoteName As String * lBUFFER_SIZE
Dim lSize As Long
Const NO_ERROR As Long = 0&
Const lBUFFER_SIZE As Long = 255&
Function GetUNC(ByRef strDriveLetter As String) As String
strDriveLetter = UCase$(strDriveLetter) & ":"
GetUNC = IIf(WNetGetConnection32(strDriveLetter, lpszRemoteName, lBUFFER_SIZE) = NO_ERROR, lpszRemoteName, "Error")
End Function
Then simply use something like:
MsgBox GetUNC("S")
I am working in Access 2013 and try to get GetRawInputDeviceList, GetRawInputDeviceInfo, RegisterRawInputDevices and GetRawInputData equivalents for VBA with no success. I have also searched in vain for a procedure, function or module to get a list of connected HID devices to a computer to pick out a barcode scanner. This is the beginning of the third week so I am on my knees begging for assistance. Do any of you all have a module you're willing to share, a link to a website where this is dealt with? Any help is greatly appreciated.
Using the GetRawInputDeviceList API from VBA would be pretty tricky because of the pRawInputDeviceList parameter. Unless you're willing to jump through a ton of hoops to manage your own memory and manually handle the resulting array of RAWINPUTDEVICELIST in raw memory, you'll be better off coming at this from another direction.
Most barcode scanners I've dealt with present themselves to Windows as a keyboard. One possible solution would be to use a WMI query to enumerate attached Win32_Keyboard devices:
Private Sub ShowKeyboardInfo()
Dim WmiServer As Object
Dim ResultSet As Object
Dim Keyboard As Object
Dim Query As String
Query = "SELECT * From Win32_Keyboard"
Set WmiServer = GetObject("winmgmts:root/CIMV2")
Set ResultSet = WmiServer.ExecQuery(Query)
For Each Keyboard In ResultSet
Debug.Print Keyboard.Name & vbTab & _
Keyboard.Description & vbTab & _
Keyboard.DeviceID & vbTab & _
Keyboard.Status
Next Keyboard
End Sub
Note: If it doesn't turn up there, you can enumerate all of the USB devices by querying CIM_USBDevice: Query = "SELECT * From Win32_Keyboard"
EDIT: Per the comments, the above code won't return the handle needed to register to receive raw input events. This should get you started though - the RegisterRawInputDevices and GetRawInputData aspects are beyond the scope of what will easily go in an answer. Take a hack at it, and if you run into any problems post your code in another question.
Declarations:
Private Type RawInputDeviceList
hDevice As Long
dwType As Long
End Type
Private Type RidKeyboardInfo
cbSize As Long
dwType As Long
dwKeyboardMode As Long
dwNumberOfFunctionKeys As Long
dwNumberOfIndicators As Long
dwNumberOfKeysTotal As Long
End Type
Private Enum DeviceType
TypeMouse = 0
TypeKeyboard = 1
TypeHID = 2
End Enum
Private Enum DeviceCommand
DeviceName = &H20000007
DeviceInfo = &H2000000B
PreParseData = &H20000005
End Enum
Private Declare Function GetRawInputDeviceList Lib "user32" ( _
ByVal pRawInputDeviceList As Long, _
ByRef puiNumDevices As Long, _
ByVal cbSize As Long) As Long
Private Declare Function GetRawInputDeviceInfo Lib "user32" Alias "GetRawInputDeviceInfoW" ( _
ByVal hDevice As Long, _
ByVal uiCommand As Long, _
ByVal pData As Long, _
ByRef pcbSize As Long) As Long
Private Declare Function GetLastError Lib "kernel32" () As Long
Sample of retrieving device names with GetRawInputDeviceInfo:
Private Sub SampleCode()
Dim devices() As RawInputDeviceList
devices = GetRawInputDevices
Dim i As Long
For i = 0 To UBound(devices)
'Inspect the type - only looking for a keyboard.
If devices(i).dwType = TypeKeyboard Then
Dim buffer As String
Dim size As Long
'First call with a null pointer returns the string length in size.
If GetRawInputDeviceInfo(devices(i).hDevice, DeviceName, 0&, size) = -1 Then
Debug.Print "GetRawInputDeviceInfo error " & GetLastError()
Else
'Size the string buffer.
buffer = String(size, Chr$(0))
'The second call copies the name into the passed buffer.
If GetRawInputDeviceInfo(devices(i).hDevice, DeviceName, StrPtr(buffer), size) = -1 Then
Debug.Print "GetRawInputDeviceInfo error " & GetLastError()
Else
Debug.Print buffer
End If
End If
End If
Next i
End Sub
Private Function GetRawInputDevices() As RawInputDeviceList()
Dim devs As Long
Dim output() As RawInputDeviceList
'First call with a null pointer returns the number of devices in devs
If GetRawInputDeviceList(0&, devs, LenB(output(0))) = -1 Then
Debug.Print "GetRawInputDeviceList error " & GetLastError()
Else
'Size the output array.
ReDim output(devs - 1)
'Second call actually fills the array.
If GetRawInputDeviceList(VarPtr(output(0)), devs, LenB(output(0))) = -1 Then
Debug.Print "GetRawInputDeviceList error " & GetLastError()
Else
GetRawInputDevices = output
End If
End If
End Function
Sorry about the side scrolling.
I have a text file on my website that contains only the string "1.15" (for the version of the application I am writing). Upon initialization of the user form, I would like to read that file from its URL and have the string "1.15" returned so that I can check it against the application's version (stored as a const string).
Here is the format I'd like to have...
Const version As String = "1.14"
Const currentVersionURL As String = "http://mywebsite.com/currentversion.txt"
Sub UserForm_Initialize()
If version <> GetCurrentVersionNumber() Then
MsgBox "Please update the application."
End If
End Sub
Function GetCurrentVersionNumber() As String
' What do I put here? :(
End Function
I am aware of the Workbooks.OpenText method, but I don't want to write the string into a workbook. I have tried using the ADODB.LoadFromFile and WinHttp.WinHttpRequest.Open methods, but both are unable to read the file.
Any suggestions for what to fill GetCurrentVersionNumber() with would be greatly appreciated. :)
While it doesn't directly answer your question, a simpler approach would be to make it an XML file instead of a text file. There are more built-in tools to easily open an XML file from a URL. The secondary advantage is that it also makes it more flexible, so you can more easily add new data elements to the XML file later on.
For instance, if you made a http://mywebsite.com/currentversion.xml file that looked like this:
<?xml version="1.0" encoding="utf-8" ?>
<AppData>
<Version>1.14</Version>
</AppData>
Then, in VB.NET you could easily read it like this:
Function GetCurrentVersionNumber() As String
Dim doc As New XmlDocument()
doc.Load("http://mywebsite.com/currentversion.xml")
Return doc.SelectSingleNode("/AppData/Version").InnerText
End Function
Or, in VBA, you could read it like this:
Function GetCurrentVersionNumber() As String
Dim doc As MSXML2.DOMDocument?? ' Where ?? is the version number, such as 30 or 60
Set doc = New MSXML2.DOMDocument??
doc.async = False
doc.Load("http://mywebsite.com/currentversion.xml")
GetCurrentVersionNumber = doc.SelectSingleNode("/AppData/Version").Text
End Function
You will need to add a reference to the Microsoft XML, v?.? library, though.
Try this (UNTESTED)
Option Explicit
Private Declare Function URLDownloadToFile Lib "urlmon" _
Alias "URLDownloadToFileA" (ByVal pCaller As Long, _
ByVal szURL As String, ByVal szFileName As String, _
ByVal dwReserved As Long, ByVal lpfnCB As Long) As Long
Private Declare Function GetTempPath Lib "kernel32" Alias "GetTempPathA" _
(ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Private Const MAX_PATH As Long = 260
Const currentVersionURL As String = "http://mywebsite.com/currentversion.txt"
Const version As String = "1.14"
Dim Ret As Long
Sub UserForm_Initialize()
If version <> GetCurrentVersionNumber() Then
MsgBox "Please update the application."
End If
End Sub
Function GetCurrentVersionNumber() As String
Dim strPath As String
'~~> Destination for the file
strPath = TempPath & "currentversion.txt"
'~~> Download the file
Ret = URLDownloadToFile(0, currentVersionURL, strPath, 0, 0)
'~~> If downloaded
If Ret = 0 Then
Dim MyData As String, strData() As String
Open "C:\MyFile.Txt" For Binary As #1
MyData = Space$(LOF(1))
Get #1, , MyData
Close #1
GetCurrentVersionNumber = MyData
Else
MsgBox "Unable to download the file"
GetCurrentVersionNumber = ""
End If
End Function
'~~> Get Users Temp Path
Function TempPath() As String
TempPath = String$(MAX_PATH, Chr$(0))
GetTempPath MAX_PATH, TempPath
TempPath = Replace(TempPath, Chr$(0), "")
End Function
I want to get the full name of the user (logged in already) in VBA. This code I found online would do getting the username:
UserName = Environ("USERNAME")
but I want the user's real name. I found some hint about NetUserGetInfo but not sure what to think or do. Any hints will be appreciated
Regards,
Even if this thread is rather old, other users might be still googling around (like me).
I found an excellent short solution that worked for me out-of-the-box (thanks to Mr.Excel.com).
I changed it because I needed it to return a string with the user's full name.
The original post is here.
EDIT:
Well, I fixed a mistake, "End Sub" instead of "End Function" and added a variable declaration statement, just in case. I tested it in Excel 2010 and 2013 versions. Worked fine on my home pc too (no domain, just in a workgroup).
' This function returns the full name of the currently logged-in user
Function GetUserFullName() as String
Dim WSHnet, UserName, UserDomain, objUser
Set WSHnet = CreateObject("WScript.Network")
UserName = WSHnet.UserName
UserDomain = WSHnet.UserDomain
Set objUser = GetObject("WinNT://" & UserDomain & "/" & UserName & ",user")
GetUserFullName = objUser.FullName
End Function
I found the API answer complex as well in addition to needing recoding from a form to module
The function below comes courtesy of Rob Sampson from this Experts-Exchange post. It is a flexible function, see code comments for details. Please note it was a vbscript so the variables are not dimensioned
Sub Test()
strUser = InputBox("Please enter a username:")
struserdn = Get_LDAP_User_Properties("user", "samAccountName", strUser, "displayName")
If Len(struserdn) <> 0 Then
MsgBox struserdn
Else
MsgBox "No record of " & strUser
End If
End Sub
Function Get_LDAP_User_Properties(strObjectType, strSearchField, strObjectToGet, strCommaDelimProps)
' This is a custom function that connects to the Active Directory, and returns the specific
' Active Directory attribute value, of a specific Object.
' strObjectType: usually "User" or "Computer"
' strSearchField: the field by which to seach the AD by. This acts like an SQL Query's WHERE clause.
' It filters the results by the value of strObjectToGet
' strObjectToGet: the value by which the results are filtered by, according the strSearchField.
' For example, if you are searching based on the user account name, strSearchField
' would be "samAccountName", and strObjectToGet would be that speicific account name,
' such as "jsmith". This equates to "WHERE 'samAccountName' = 'jsmith'"
' strCommaDelimProps: the field from the object to actually return. For example, if you wanted
' the home folder path, as defined by the AD, for a specific user, this would be
' "homeDirectory". If you want to return the ADsPath so that you can bind to that
' user and get your own parameters from them, then use "ADsPath" as a return string,
' then bind to the user: Set objUser = GetObject("LDAP://" & strReturnADsPath)
' Now we're checking if the user account passed may have a domain already specified,
' in which case we connect to that domain in AD, instead of the default one.
If InStr(strObjectToGet, "\") > 0 Then
arrGroupBits = Split(strObjectToGet, "\")
strDC = arrGroupBits(0)
strDNSDomain = strDC & "/" & "DC=" & Replace(Mid(strDC, InStr(strDC, ".") + 1), ".", ",DC=")
strObjectToGet = arrGroupBits(1)
Else
' Otherwise we just connect to the default domain
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingContext")
End If
strBase = "<LDAP://" & strDNSDomain & ">"
' Setup ADO objects.
Set adoCommand = CreateObject("ADODB.Command")
Set ADOConnection = CreateObject("ADODB.Connection")
ADOConnection.Provider = "ADsDSOObject"
ADOConnection.Open "Active Directory Provider"
adoCommand.ActiveConnection = ADOConnection
' Filter on user objects.
'strFilter = "(&(objectCategory=person)(objectClass=user))"
strFilter = "(&(objectClass=" & strObjectType & ")(" & strSearchField & "=" & strObjectToGet & "))"
' Comma delimited list of attribute values to retrieve.
strAttributes = strCommaDelimProps
arrProperties = Split(strCommaDelimProps, ",")
' Construct the LDAP syntax query.
strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
adoCommand.CommandText = strQuery
' Define the maximum records to return
adoCommand.Properties("Page Size") = 100
adoCommand.Properties("Timeout") = 30
adoCommand.Properties("Cache Results") = False
' Run the query.
Set adoRecordset = adoCommand.Execute
' Enumerate the resulting recordset.
strReturnVal = ""
Do Until adoRecordset.EOF
' Retrieve values and display.
For intCount = LBound(arrProperties) To UBound(arrProperties)
If strReturnVal = "" Then
strReturnVal = adoRecordset.Fields(intCount).Value
Else
strReturnVal = strReturnVal & vbCrLf & adoRecordset.Fields(intCount).Value
End If
Next
' Move to the next record in the recordset.
adoRecordset.MoveNext
Loop
' Clean up.
adoRecordset.Close
ADOConnection.Close
Get_LDAP_User_Properties = strReturnVal
End Function
This works for me. It might need some adjustments - I get several items returned and only one has .Flags > 0
Function GetUserFullName() As String
Dim objWin32NLP As Object
On Error Resume Next
' Win32_NetworkLoginProfile class https://msdn.microsoft.com/en-us/library/aa394221%28v=vs.85%29.aspx
Set objWin32NLP = GetObject("WinMgmts:").InstancesOf("Win32_NetworkLoginProfile")
If Err.Number <> 0 Then
MsgBox "WMI is not installed", vbExclamation, "Windows Management Instrumentation"
Exit Function
End If
For Each objItem In objWin32NLP
If objItem.Flags > 0 Then GetUserFullName = objItem.FullName
Next
End Function
Try this:
How To Call NetUserGetInfo from Visual Basic
(From Microsoft Knowledge Base, article ID 151774)
The NetUserGetInfo function is a Unicode-only Windows NT API. The last parameter of this function is a pointer to a pointer to a structure whose members contain DWORD data and pointers to Unicode strings. In order to call this function correctly from a Visual Basic application, you need to de-reference the pointer returned by the function and then you need to convert the Visual Basic string to a Unicode string and vice versa. This article illustrates these techniques in an example that calls NetUserGetInfo to retrieve a USER_INFO_3 structure from a Visual Basic application.
The example below uses the Win32 RtlMoveMemory function to de-reference the pointer returned by the NetUserGetInfo call.
Step-by-Step Example
Start Visual Basic. If Visual Basic is already running, from the File menu, choose New Project. Form1 is created by default.
Add a Command button, Command1, to Form1.
Add the following code to the General Declarations section of Form1:
' definitions not specifically declared in the article:
' the servername and username params can also be declared as Longs,
' and passed Unicode memory addresses with the StrPtr function.
Private Declare Function NetUserGetInfo Lib "netapi32" _
(ByVal servername As String, _
ByVal username As String, _
ByVal level As Long, _
bufptr As Long) As Long
Const NERR_Success = 0
Private Declare Sub MoveMemory Lib "kernel32" Alias _
"RtlMoveMemory" (pDest As Any, pSource As Any, ByVal dwLength As Long)
Private Declare Function lstrlenW Lib "kernel32" (lpString As Any) As Long
' Converts a Unicode string to an ANSI string
' Specify -1 for cchWideChar and 0 for cchMultiByte to return string length.
Private Declare Function WideCharToMultiByte Lib "kernel32" _
(ByVal codepage As Long, _
ByVal dwFlags As Long, _
lpWideCharStr As Any, _
ByVal cchWideChar As Long, _
lpMultiByteStr As Any, _
ByVal cchMultiByte As Long, _
ByVal lpDefaultChar As String, _
ByVal lpUsedDefaultChar As Long) As Long
Private Declare Function NetApiBufferFree Lib "netapi32" _
(ByVal Buffer As Long) As Long
' CodePage
Const CP_ACP = 0 ' ANSI code page
Private Type USER_INFO_3
usri3_name As Long 'LPWSTR in SDK
usri3_password As Long 'LPWSTR in SDK
usri3_password_age As Long 'DWORD in SDK
usri3_priv As Long 'DWORD in SDK
usri3_home_dir As Long 'LPWSTR in SDK
usri3_comment As Long 'LPWSTR in SDK
usri3_flags As Long 'DWORD in SDK
usri3_script_path As Long 'LPWSTR in SDK
usri3_auth_flags As Long 'DWORD in SDK
usri3_full_name As Long 'LPWSTR in SDK
usri3_usr_comment As Long 'LPWSTR in SDK
usri3_parms As Long 'LPWSTR in SDK
usri3_workstations As Long 'LPWSTR in SDK
usri3_last_logon As Long 'DWORD in SDK
usri3_last_logoff As Long 'DWORD in SDK
usri3_acct_expires As Long 'DWORD in SDK
usri3_max_storage As Long 'DWORD in SDK
usri3_units_per_week As Long 'DWORD in SDK
usri3_logon_hours As Long 'PBYTE in SDK
usri3_bad_pw_count As Long 'DWORD in SDK
usri3_num_logons As Long 'DWORD in SDK
usri3_logon_server As Long 'LPWSTR in SDK
usri3_country_code As Long 'DWORD in SDK
usri3_code_page As Long 'DWORD in SDK
usri3_user_id As Long 'DWORD in SDK
usri3_primary_group_id As Long 'DWORD in SDK
usri3_profile As Long 'LPWSTR in SDK
usri3_home_dir_drive As Long 'LPWSTR in SDK
usri3_password_expired As Long 'DWORD in SDK
End Type
Private Sub Command1_Click()
Dim lpBuf As Long
Dim ui3 As USER_INFO_3
' Replace "Administrator" with a valid Windows NT user name.
If (NetUserGetInfo("", StrConv("Administrator", vbUnicode), 3, _
uf) = NERR_Success) Then
Call MoveMemory(ui3, ByVal lpBuf, Len(ui3))
MsgBox GetStrFromPtrW(ui3.usri3_name)
Call NetApiBufferFree(ByVal lpBuf)
End If
End Sub
' Returns an ANSI string from a pointer to a Unicode string.
Public Function GetStrFromPtrW(lpszW As Long) As String
Dim sRtn As String
sRtn = String$(lstrlenW(ByVal lpszW) * 2, 0) ' 2 bytes/char
' WideCharToMultiByte also returns Unicode string length
' sRtn = String$(WideCharToMultiByte(CP_ACP, 0, ByVal lpszW, -1, 0, 0, 0, 0), 0)
Call WideCharToMultiByte(CP_ACP, 0, ByVal lpszW, -1, ByVal sRtn, Len(sRtn), 0, 0)
GetStrFromPtrW = GetStrFromBufferA(sRtn)
End Function
' Returns the string before first null char encountered (if any) from an ANSI string.
Public Function GetStrFromBufferA(sz As String) As String
If InStr(sz, vbNullChar) Then
GetStrFromBufferA = Left$(sz, InStr(sz, vbNullChar) - 1)
Else
' If sz had no null char, the Left$ function
' above would return a zero length string ("").
GetStrFromBufferA = sz
End If
End Function
I would recommend re-factoring this into a module rather than embedding it in the form itself. I've used this successfully in Access in the past.
I've tried so many things, but I suppose my organization does not allow me to query Active Directory (or I got the structure wrong). I could only get my account name (not full name) or the error "No mapping between account names and security IDs was done"
But after 2 weeks searching, I finally have a working solution that I wanted to share. My final hint can be found here: https://www.mrexcel.com/board/threads/application-username-equivalent-in-ms-access.1143798/page-2#post-5545265
The value does appear in the registry i.e.
"HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\UserName"
Once I realized that, it was easy to access with VBA:
UserName = CreateObject("wscript.shell").RegRead("HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\UserName")
I assume (did not test though) that this is what Application.Username from Excel uses as well. Might not be perfect, but I finally have a solution that works.
I'm trying to adapt the code in either here or here to open the custom colour palette in Excel 2010 64-bit but cannot get it to work. Code on both sites work fine in Excel 2003
One attempt
Option Explicit
Private Type CHOOSECOLOR
lStructSize As Long
hwndOwner As Long
hInstance As Long
rgbResult As Long
lpCustColors As String
flags As Long
lCustData As Long
lpfnHook As Long
lpTemplateName As String
End Type
Private Declare PtrSafe Function ChooseColorAPI Lib "comdlg32.dll" Alias _
"ChooseColorA" (pChoosecolor As CHOOSECOLOR) As Long
Dim CustomColors() As Byte
Private Sub Command1_Click()
Dim cc As CHOOSECOLOR
Dim Custcolor(16) As Long
Dim lReturn As Long
cc.lStructSize = Len(cc)
cc.hwndOwner = Application.Hwnd
cc.hInstance = 0
cc.lpCustColors = StrConv(CustomColors, vbUnicode)
cc.flags = 0
lReturn = ChooseColorAPI(cc)
If lReturn <> 0 Then
Application.Caption = "RGB Value User Chose: " & Str$(cc.rgbResult)
Application.BackColor = cc.rgbResult ' Visual Basic only ****
Application.Section(0).BackColor = cc.rgbResult ' Access only **********
CustomColors = StrConv(cc.lpCustColors, vbFromUnicode)
Else
MsgBox "User chose the Cancel Button"
End If
End Sub
Private Sub Form_Load()
ReDim CustomColors(0 To 16 * 4 - 1) As Byte
Dim i As Integer
For i = LBound(CustomColors) To UBound(CustomColors)
CustomColors(i) = 0
Next i
End Sub
This runs ok but doesn't show the dialog. I've also tried changing some LONG types to LONGPTR with no success. Does anyone know how to get this working on a 64-bit machine; or if it's even possible? Perhaps there's a new library?
Thanks
Edit: Slight rewording with offer of bounty...
How do I access and use this custom colour chooser (image below) in Excel 2010 64-bit (MUST work on 64-bit!) to set cells in Excel 2010 with the colour chosen and store the colour? The image is taken from Excel 2010 64-bit by selecting fill button>more colors>Custom
Valid XHTML http://img851.imageshack.us/img851/2057/unlednvn.png
Two things I would try. First, replace every use of Long with LongPtr.
Private Type CHOOSECOLOR
lStructSize As LongPtr
hwndOwner As LongPtr
hInstance As LongPtr
rgbResult As LongPtr
lpCustColors As String
flags As LongPtr
lCustData As LongPtr
lpfnHook As LongPtr
lpTemplateName As String
End Type
Private Declare PtrSafe Function ChooseColorAPI Lib "comdlg32.dll" Alias _
"ChooseColorA" (pChoosecolor As CHOOSECOLOR) As LongPtr
Second, replace the use of Len with LenB.
Private Sub Command1_Click()
Dim cc As CHOOSECOLOR
Dim Custcolor(16) As LongPtr
Dim lReturn As LongPtr
cc.lStructSize = LenB(cc)
cc.hwndOwner = Application.Hwnd
cc.hInstance = 0
cc.lpCustColors = StrConv(CustomColors, vbUnicode)
cc.flags = 0
lReturn = ChooseColorAPI(cc)
If lReturn <> 0 Then
Application.Caption = "RGB Value User Chose: " & Str$(cc.rgbResult)
Application.BackColor = cc.rgbResult ' Visual Basic only ****
Application.Section(0).BackColor = cc.rgbResult ' Access only **********
CustomColors = StrConv(cc.lpCustColors, vbFromUnicode)
Else
MsgBox "User chose the Cancel Button"
End If
End Sub
Private Sub Form_Load()
ReDim CustomColors(0 To 16 * 4 - 1) As Byte
Dim i As Integer
For i = LBound(CustomColors) To UBound(CustomColors)
CustomColors(i) = 0
Next i
End Sub
More Info
LongPtr Data Type
LenB Function
AFAIK 32-bit dll's cannot be used by a 64-bit application.
Use comdlg64.dll instead (if there is such a dll).
Using google reveals that there a host of viruses floating around on the net by that name.
So if comdlg64.dll is not on your machine don't download it from the net!
(Unless you want to experience zombieness).