VBA - Office 365 x64 bit - Completely crashing
up vote
1
down vote
favorite
This is my first time asking for any help on stack overflow, let alone commenting so please be gentle with me :)
I am at a loss with this one, I will give as much information as possible.
Issue
I would like to preface, this code does not cause any crashes on the latest update of 0365, only on Version 1807 & earlier. It also does not crash on the 32 bit version at all which makes me think it's a 64 bit issue. My client cannot update from this version either so simply asking them to update is not going to be able to happen.
I have narrowed the crashing down to this particular section.
Public Function GetSpecialFolder(CSIDL As Long) As String
'*******************************************************************************
'* Function: GetSpecialFolder
'* Purpose: Wraps the apis to retrieve folders such as My Docs etc.
'*******************************************************************************
Dim idlstr As Long
Dim sPath As String
Dim IDL As ITEMIDLIST
Const MAX_LENGTH = 260
'Fill the IDL structure with the specified folder item.
On Error GoTo GetSpecialFolder_Error
idlstr = SHGetSpecialFolderLocation _
(0, CSIDL, IDL)
If idlstr = 0 Then
'Get the path from the IDL list, and return the folder adding final "".
sPath = Space$(MAX_LENGTH)
**idlstr = SHGetPathFromIDList(ByVal IDL.mkid.cb, ByVal sPath)**
If idlstr Then
GetSpecialFolder = Left$(sPath, InStr(sPath, Chr$(0)) _
- 1) & ""
End If
End If
procExit:
On Error Resume Next
Exit Function
GetSpecialFolder_Error:
CommonErrorHandler lngErrNum:=Err.Number, strErrDesc:=Err.Description, _
strProc:="GetSpecialFolder", strModule:="modWinAPI", lngLineNum:=Erl
Resume procExit
End Function
And here is the declaration
'File system
Public Declare PtrSafe Function SHGetSpecialFolderLocation Lib "shell32.dll" _
(ByVal hwndOwner As Long, ByVal nFolder As Long, pidl As ITEMIDLIST) As Long
Public Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" _
Alias "SHGetPathFromIDListA" (ByVal pidl As Long, ByVal pszPath As String) As Long
Private Declare PtrSafe Function GetTempPath Lib "kernel32" _
Alias "GetTempPathA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Private Declare PtrSafe Function ShellExecute Lib "shell32.dll" _
Alias "ShellExecuteA" (ByVal hwnd As LongPtr, ByVal lpOperation As String, _
ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, _
ByVal nShowCmd As Long) As LongPtr
Private Type ITEMIDLIST
mkid As ShortItemId
End Type
Private Type ShortItemId
cb As Long
abID As Byte
End Type
I have tried adding LongPtr as suggested in documents I've found online but it hasn't helped.
Can anyone help me?
Thanks!
vba ms-office
add a comment |
up vote
1
down vote
favorite
This is my first time asking for any help on stack overflow, let alone commenting so please be gentle with me :)
I am at a loss with this one, I will give as much information as possible.
Issue
I would like to preface, this code does not cause any crashes on the latest update of 0365, only on Version 1807 & earlier. It also does not crash on the 32 bit version at all which makes me think it's a 64 bit issue. My client cannot update from this version either so simply asking them to update is not going to be able to happen.
I have narrowed the crashing down to this particular section.
Public Function GetSpecialFolder(CSIDL As Long) As String
'*******************************************************************************
'* Function: GetSpecialFolder
'* Purpose: Wraps the apis to retrieve folders such as My Docs etc.
'*******************************************************************************
Dim idlstr As Long
Dim sPath As String
Dim IDL As ITEMIDLIST
Const MAX_LENGTH = 260
'Fill the IDL structure with the specified folder item.
On Error GoTo GetSpecialFolder_Error
idlstr = SHGetSpecialFolderLocation _
(0, CSIDL, IDL)
If idlstr = 0 Then
'Get the path from the IDL list, and return the folder adding final "".
sPath = Space$(MAX_LENGTH)
**idlstr = SHGetPathFromIDList(ByVal IDL.mkid.cb, ByVal sPath)**
If idlstr Then
GetSpecialFolder = Left$(sPath, InStr(sPath, Chr$(0)) _
- 1) & ""
End If
End If
procExit:
On Error Resume Next
Exit Function
GetSpecialFolder_Error:
CommonErrorHandler lngErrNum:=Err.Number, strErrDesc:=Err.Description, _
strProc:="GetSpecialFolder", strModule:="modWinAPI", lngLineNum:=Erl
Resume procExit
End Function
And here is the declaration
'File system
Public Declare PtrSafe Function SHGetSpecialFolderLocation Lib "shell32.dll" _
(ByVal hwndOwner As Long, ByVal nFolder As Long, pidl As ITEMIDLIST) As Long
Public Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" _
Alias "SHGetPathFromIDListA" (ByVal pidl As Long, ByVal pszPath As String) As Long
Private Declare PtrSafe Function GetTempPath Lib "kernel32" _
Alias "GetTempPathA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Private Declare PtrSafe Function ShellExecute Lib "shell32.dll" _
Alias "ShellExecuteA" (ByVal hwnd As LongPtr, ByVal lpOperation As String, _
ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, _
ByVal nShowCmd As Long) As LongPtr
Private Type ITEMIDLIST
mkid As ShortItemId
End Type
Private Type ShortItemId
cb As Long
abID As Byte
End Type
I have tried adding LongPtr as suggested in documents I've found online but it hasn't helped.
Can anyone help me?
Thanks!
vba ms-office
Comments are not for extended discussion; this conversation has been moved to chat.
– Samuel Liew♦
Nov 12 at 4:58
add a comment |
up vote
1
down vote
favorite
up vote
1
down vote
favorite
This is my first time asking for any help on stack overflow, let alone commenting so please be gentle with me :)
I am at a loss with this one, I will give as much information as possible.
Issue
I would like to preface, this code does not cause any crashes on the latest update of 0365, only on Version 1807 & earlier. It also does not crash on the 32 bit version at all which makes me think it's a 64 bit issue. My client cannot update from this version either so simply asking them to update is not going to be able to happen.
I have narrowed the crashing down to this particular section.
Public Function GetSpecialFolder(CSIDL As Long) As String
'*******************************************************************************
'* Function: GetSpecialFolder
'* Purpose: Wraps the apis to retrieve folders such as My Docs etc.
'*******************************************************************************
Dim idlstr As Long
Dim sPath As String
Dim IDL As ITEMIDLIST
Const MAX_LENGTH = 260
'Fill the IDL structure with the specified folder item.
On Error GoTo GetSpecialFolder_Error
idlstr = SHGetSpecialFolderLocation _
(0, CSIDL, IDL)
If idlstr = 0 Then
'Get the path from the IDL list, and return the folder adding final "".
sPath = Space$(MAX_LENGTH)
**idlstr = SHGetPathFromIDList(ByVal IDL.mkid.cb, ByVal sPath)**
If idlstr Then
GetSpecialFolder = Left$(sPath, InStr(sPath, Chr$(0)) _
- 1) & ""
End If
End If
procExit:
On Error Resume Next
Exit Function
GetSpecialFolder_Error:
CommonErrorHandler lngErrNum:=Err.Number, strErrDesc:=Err.Description, _
strProc:="GetSpecialFolder", strModule:="modWinAPI", lngLineNum:=Erl
Resume procExit
End Function
And here is the declaration
'File system
Public Declare PtrSafe Function SHGetSpecialFolderLocation Lib "shell32.dll" _
(ByVal hwndOwner As Long, ByVal nFolder As Long, pidl As ITEMIDLIST) As Long
Public Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" _
Alias "SHGetPathFromIDListA" (ByVal pidl As Long, ByVal pszPath As String) As Long
Private Declare PtrSafe Function GetTempPath Lib "kernel32" _
Alias "GetTempPathA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Private Declare PtrSafe Function ShellExecute Lib "shell32.dll" _
Alias "ShellExecuteA" (ByVal hwnd As LongPtr, ByVal lpOperation As String, _
ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, _
ByVal nShowCmd As Long) As LongPtr
Private Type ITEMIDLIST
mkid As ShortItemId
End Type
Private Type ShortItemId
cb As Long
abID As Byte
End Type
I have tried adding LongPtr as suggested in documents I've found online but it hasn't helped.
Can anyone help me?
Thanks!
vba ms-office
This is my first time asking for any help on stack overflow, let alone commenting so please be gentle with me :)
I am at a loss with this one, I will give as much information as possible.
Issue
I would like to preface, this code does not cause any crashes on the latest update of 0365, only on Version 1807 & earlier. It also does not crash on the 32 bit version at all which makes me think it's a 64 bit issue. My client cannot update from this version either so simply asking them to update is not going to be able to happen.
I have narrowed the crashing down to this particular section.
Public Function GetSpecialFolder(CSIDL As Long) As String
'*******************************************************************************
'* Function: GetSpecialFolder
'* Purpose: Wraps the apis to retrieve folders such as My Docs etc.
'*******************************************************************************
Dim idlstr As Long
Dim sPath As String
Dim IDL As ITEMIDLIST
Const MAX_LENGTH = 260
'Fill the IDL structure with the specified folder item.
On Error GoTo GetSpecialFolder_Error
idlstr = SHGetSpecialFolderLocation _
(0, CSIDL, IDL)
If idlstr = 0 Then
'Get the path from the IDL list, and return the folder adding final "".
sPath = Space$(MAX_LENGTH)
**idlstr = SHGetPathFromIDList(ByVal IDL.mkid.cb, ByVal sPath)**
If idlstr Then
GetSpecialFolder = Left$(sPath, InStr(sPath, Chr$(0)) _
- 1) & ""
End If
End If
procExit:
On Error Resume Next
Exit Function
GetSpecialFolder_Error:
CommonErrorHandler lngErrNum:=Err.Number, strErrDesc:=Err.Description, _
strProc:="GetSpecialFolder", strModule:="modWinAPI", lngLineNum:=Erl
Resume procExit
End Function
And here is the declaration
'File system
Public Declare PtrSafe Function SHGetSpecialFolderLocation Lib "shell32.dll" _
(ByVal hwndOwner As Long, ByVal nFolder As Long, pidl As ITEMIDLIST) As Long
Public Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" _
Alias "SHGetPathFromIDListA" (ByVal pidl As Long, ByVal pszPath As String) As Long
Private Declare PtrSafe Function GetTempPath Lib "kernel32" _
Alias "GetTempPathA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Private Declare PtrSafe Function ShellExecute Lib "shell32.dll" _
Alias "ShellExecuteA" (ByVal hwnd As LongPtr, ByVal lpOperation As String, _
ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, _
ByVal nShowCmd As Long) As LongPtr
Private Type ITEMIDLIST
mkid As ShortItemId
End Type
Private Type ShortItemId
cb As Long
abID As Byte
End Type
I have tried adding LongPtr as suggested in documents I've found online but it hasn't helped.
Can anyone help me?
Thanks!
vba ms-office
vba ms-office
edited Nov 12 at 1:43
asked Nov 12 at 0:22
RCW05
84
84
Comments are not for extended discussion; this conversation has been moved to chat.
– Samuel Liew♦
Nov 12 at 4:58
add a comment |
Comments are not for extended discussion; this conversation has been moved to chat.
– Samuel Liew♦
Nov 12 at 4:58
Comments are not for extended discussion; this conversation has been moved to chat.
– Samuel Liew♦
Nov 12 at 4:58
Comments are not for extended discussion; this conversation has been moved to chat.
– Samuel Liew♦
Nov 12 at 4:58
add a comment |
2 Answers
2
active
oldest
votes
up vote
1
down vote
accepted
SHGetSpecialFolderLocation
does not fill in the memory you allocate for ITEMIDLIST
like Declare
d function usually do, it allocates a new piece of memory that you are later required to free with CoTaskMemFree
. That makes it pointless to declare ITEMIDLIST
as a structure in VBA to begin with (and your declaration is wrong anyway, cb
must be Integer
, and abID
is a variable-length byte array, not a single byte).
If you needed to do something with individual members of a structure allocated in this way, you would have to copy them out of the returned pointer with CopyMemory
. Luckily, you don't need to do any of that because SHGetSpecialFolderLocation
returns a pointer to PIDLIST_ABSOLUTE
, and SHGetPathFromIDList
accepts PCIDLIST_ABSOLUTE
:
Public Declare PtrSafe Function SHGetSpecialFolderLocation Lib "shell32.dll" _
(ByVal hwndOwner As LongPtr, ByVal nFolder As Long, ByRef pIdl As LongPtr) As Long
Public Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" _
Alias "SHGetPathFromIDListA" (ByVal pIdl As LongPtr, ByVal pszPath As String) As Long
Public Declare PtrSafe Sub CoTaskMemFree Lib "ole32.dll" (pv As Any)
Public Function GetSpecialFolder(ByVal CSIDL As Long) As String
Dim retval As Long
Dim pIdl As LongPtr
Dim sPath As String
Const MAX_LENGTH = 260
retval = SHGetSpecialFolderLocation(0, CSIDL, pIdl)
If retval = 0 Then
sPath = Space$(MAX_LENGTH)
retval = SHGetPathFromIDList(pIdl, sPath)
If retval <> 0 Then
GetSpecialFolder = Left$(sPath, InStr(sPath, Chr$(0)) - 1) & ""
End If
CoTaskMemFree ByVal pIdl
End If
End Function
Note that it's pointless to have an On Error Goto
in such function because Windows API generally do not raise exceptions, they return error codes. It would make sense if you used Err.Raise ...
after finding out a return value indicates an error.
Yeah, that's pretty much it. +1.SHGetPathFromIDList
returns a bool though.
– Comintern
Nov 12 at 2:25
@CominternLen(bool)
is 2 in VBA, so like withhWnd
, I'm keen on keeping the size correct ;)
– GSerg
Nov 12 at 2:26
Fair enough - I personally let the marshaller handle that so I can retain the VBA semantics.
– Comintern
Nov 12 at 2:29
@Comintern You got me wondering about that marshalling, so I've done a little test and nope, it truncates without actually marshalling. If you declare the function and theretval
variableAs Boolean
, the bits that end up in theretval
variable on VBA side are0x0001
, which is "truthy", but does not actually equalTrue
. They would be0xFFFF
if there was actually marshalling. Which means that doingretval_bool = SHGetPathFromIDList(pIdl, sPath)
and thenIf retval_bool Then
will execute theIf
, butIf retval_bool = True Then
will not. (I have tested, it does not= True
).
– GSerg
Nov 12 at 2:44
1
@RCW05 Yes, and you should not have differentDeclare
s for 32 and 64 bits. That is why there isLongPtr
to begin with. The only reason to have two declarations would be if you still support Office 2003 and below where you don't havePtrSafe
andLongPtr
, but then you need to branch on#If VBA7 Then
, not on#If Win64 Then
.
– GSerg
Nov 13 at 12:17
|
show 10 more comments
up vote
1
down vote
TBH, I have no clue how this was functioning correctly on a 32 bit build. The declarations for the two structures are incorrect. This one...
Private Type ShortItemId
cb As Long
abID As Byte
End Type
...is defined in the MS documentation as this:
typedef struct _SHITEMID {
USHORT cb;
BYTE abID[1];
} SHITEMID;
Note that abID
is an array, and cb
is an unsigned short (you can use an Integer
for that in VBA, but it definitely is not a Long
).
In addition, this structure (wrapped in the ITEMIDLIST) is not even supposed to be allocated by the caller, but must be freed by the caller:
It is the responsibility of the calling application to free the returned IDList by using CoTaskMemFree.
Re the pointers, the only pointers (that aren't being marshaled from String
) are the
pidl
parameter of SHGetSpecialFolderLocation
and the pointer to ppidl
in SHGetPathFromIDList
. Note that you can't use a VBA defined struct, because you need to free the memory when you're done. Something like this will work:
Private Declare PtrSafe Function SHGetSpecialFolderLocation Lib "shell32.dll" _
(ByVal hwndOwner As Long, ByVal nFolder As Long, pidl As LongPtr) As Long
Private Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" _
Alias "SHGetPathFromIDListA" (ByVal pidl As LongPtr, ByVal pszPath As String) As Boolean
Private Declare PtrSafe Sub CoTaskMemFree Lib "ole32.dll" (ByVal pv As LongPtr)
Private Const S_OK As Long = 0
Private Const MAX_LENGTH = 260
Public Function GetSpecialFolder(ByVal CSIDL As Integer) As String
Dim result As Long
Dim path As String
Dim idl_ptr As LongPtr
'Fill the IDL structure with the specified folder item.
result = SHGetSpecialFolderLocation(0, CSIDL, idl_ptr)
If result = S_OK Then
'Get the path from the IDL list, and return the folder adding final "".
path = Space$(MAX_LENGTH)
If SHGetPathFromIDList(idl_ptr, path) Then
GetSpecialFolder = Left$(path, InStr(path, vbNullChar) - 1) & ""
End If
CoTaskMemFree idl_ptr
End If
End Function
Note that per the discussion in the comments, you could technically declare hwndOwner
as LongPtr
as well, but it shouldn't make any difference.
When trying this I'm getting an idl_ptr ByRef argument type Mismatch.. any idea why?
– RCW05
Nov 12 at 3:09
@RCW05 That's odd, works just fine for me. Which line gives you the error? Note thatpidl As LongPtr
is not declaredByVal
, so it's implicitlyByRef
in the declaration.
– Comintern
Nov 12 at 3:12
@RCW05 - Ahhh... I changed the function signature toCSIDL As Integer
because, well, CSIDL is not aLong
. Make that explicitlyByVal
(see the edit).
– Comintern
Nov 12 at 3:16
I'm not sure what I'm doing wrong here. Even this code is now giving me ByRef argument type mismatch when copy and pasted?
– RCW05
Nov 13 at 12:03
Please ignore this sorry - I had another version declared and didn't realise it would conflict .... DOH!
– RCW05
Nov 13 at 12:19
|
show 1 more comment
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
SHGetSpecialFolderLocation
does not fill in the memory you allocate for ITEMIDLIST
like Declare
d function usually do, it allocates a new piece of memory that you are later required to free with CoTaskMemFree
. That makes it pointless to declare ITEMIDLIST
as a structure in VBA to begin with (and your declaration is wrong anyway, cb
must be Integer
, and abID
is a variable-length byte array, not a single byte).
If you needed to do something with individual members of a structure allocated in this way, you would have to copy them out of the returned pointer with CopyMemory
. Luckily, you don't need to do any of that because SHGetSpecialFolderLocation
returns a pointer to PIDLIST_ABSOLUTE
, and SHGetPathFromIDList
accepts PCIDLIST_ABSOLUTE
:
Public Declare PtrSafe Function SHGetSpecialFolderLocation Lib "shell32.dll" _
(ByVal hwndOwner As LongPtr, ByVal nFolder As Long, ByRef pIdl As LongPtr) As Long
Public Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" _
Alias "SHGetPathFromIDListA" (ByVal pIdl As LongPtr, ByVal pszPath As String) As Long
Public Declare PtrSafe Sub CoTaskMemFree Lib "ole32.dll" (pv As Any)
Public Function GetSpecialFolder(ByVal CSIDL As Long) As String
Dim retval As Long
Dim pIdl As LongPtr
Dim sPath As String
Const MAX_LENGTH = 260
retval = SHGetSpecialFolderLocation(0, CSIDL, pIdl)
If retval = 0 Then
sPath = Space$(MAX_LENGTH)
retval = SHGetPathFromIDList(pIdl, sPath)
If retval <> 0 Then
GetSpecialFolder = Left$(sPath, InStr(sPath, Chr$(0)) - 1) & ""
End If
CoTaskMemFree ByVal pIdl
End If
End Function
Note that it's pointless to have an On Error Goto
in such function because Windows API generally do not raise exceptions, they return error codes. It would make sense if you used Err.Raise ...
after finding out a return value indicates an error.
Yeah, that's pretty much it. +1.SHGetPathFromIDList
returns a bool though.
– Comintern
Nov 12 at 2:25
@CominternLen(bool)
is 2 in VBA, so like withhWnd
, I'm keen on keeping the size correct ;)
– GSerg
Nov 12 at 2:26
Fair enough - I personally let the marshaller handle that so I can retain the VBA semantics.
– Comintern
Nov 12 at 2:29
@Comintern You got me wondering about that marshalling, so I've done a little test and nope, it truncates without actually marshalling. If you declare the function and theretval
variableAs Boolean
, the bits that end up in theretval
variable on VBA side are0x0001
, which is "truthy", but does not actually equalTrue
. They would be0xFFFF
if there was actually marshalling. Which means that doingretval_bool = SHGetPathFromIDList(pIdl, sPath)
and thenIf retval_bool Then
will execute theIf
, butIf retval_bool = True Then
will not. (I have tested, it does not= True
).
– GSerg
Nov 12 at 2:44
1
@RCW05 Yes, and you should not have differentDeclare
s for 32 and 64 bits. That is why there isLongPtr
to begin with. The only reason to have two declarations would be if you still support Office 2003 and below where you don't havePtrSafe
andLongPtr
, but then you need to branch on#If VBA7 Then
, not on#If Win64 Then
.
– GSerg
Nov 13 at 12:17
|
show 10 more comments
up vote
1
down vote
accepted
SHGetSpecialFolderLocation
does not fill in the memory you allocate for ITEMIDLIST
like Declare
d function usually do, it allocates a new piece of memory that you are later required to free with CoTaskMemFree
. That makes it pointless to declare ITEMIDLIST
as a structure in VBA to begin with (and your declaration is wrong anyway, cb
must be Integer
, and abID
is a variable-length byte array, not a single byte).
If you needed to do something with individual members of a structure allocated in this way, you would have to copy them out of the returned pointer with CopyMemory
. Luckily, you don't need to do any of that because SHGetSpecialFolderLocation
returns a pointer to PIDLIST_ABSOLUTE
, and SHGetPathFromIDList
accepts PCIDLIST_ABSOLUTE
:
Public Declare PtrSafe Function SHGetSpecialFolderLocation Lib "shell32.dll" _
(ByVal hwndOwner As LongPtr, ByVal nFolder As Long, ByRef pIdl As LongPtr) As Long
Public Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" _
Alias "SHGetPathFromIDListA" (ByVal pIdl As LongPtr, ByVal pszPath As String) As Long
Public Declare PtrSafe Sub CoTaskMemFree Lib "ole32.dll" (pv As Any)
Public Function GetSpecialFolder(ByVal CSIDL As Long) As String
Dim retval As Long
Dim pIdl As LongPtr
Dim sPath As String
Const MAX_LENGTH = 260
retval = SHGetSpecialFolderLocation(0, CSIDL, pIdl)
If retval = 0 Then
sPath = Space$(MAX_LENGTH)
retval = SHGetPathFromIDList(pIdl, sPath)
If retval <> 0 Then
GetSpecialFolder = Left$(sPath, InStr(sPath, Chr$(0)) - 1) & ""
End If
CoTaskMemFree ByVal pIdl
End If
End Function
Note that it's pointless to have an On Error Goto
in such function because Windows API generally do not raise exceptions, they return error codes. It would make sense if you used Err.Raise ...
after finding out a return value indicates an error.
Yeah, that's pretty much it. +1.SHGetPathFromIDList
returns a bool though.
– Comintern
Nov 12 at 2:25
@CominternLen(bool)
is 2 in VBA, so like withhWnd
, I'm keen on keeping the size correct ;)
– GSerg
Nov 12 at 2:26
Fair enough - I personally let the marshaller handle that so I can retain the VBA semantics.
– Comintern
Nov 12 at 2:29
@Comintern You got me wondering about that marshalling, so I've done a little test and nope, it truncates without actually marshalling. If you declare the function and theretval
variableAs Boolean
, the bits that end up in theretval
variable on VBA side are0x0001
, which is "truthy", but does not actually equalTrue
. They would be0xFFFF
if there was actually marshalling. Which means that doingretval_bool = SHGetPathFromIDList(pIdl, sPath)
and thenIf retval_bool Then
will execute theIf
, butIf retval_bool = True Then
will not. (I have tested, it does not= True
).
– GSerg
Nov 12 at 2:44
1
@RCW05 Yes, and you should not have differentDeclare
s for 32 and 64 bits. That is why there isLongPtr
to begin with. The only reason to have two declarations would be if you still support Office 2003 and below where you don't havePtrSafe
andLongPtr
, but then you need to branch on#If VBA7 Then
, not on#If Win64 Then
.
– GSerg
Nov 13 at 12:17
|
show 10 more comments
up vote
1
down vote
accepted
up vote
1
down vote
accepted
SHGetSpecialFolderLocation
does not fill in the memory you allocate for ITEMIDLIST
like Declare
d function usually do, it allocates a new piece of memory that you are later required to free with CoTaskMemFree
. That makes it pointless to declare ITEMIDLIST
as a structure in VBA to begin with (and your declaration is wrong anyway, cb
must be Integer
, and abID
is a variable-length byte array, not a single byte).
If you needed to do something with individual members of a structure allocated in this way, you would have to copy them out of the returned pointer with CopyMemory
. Luckily, you don't need to do any of that because SHGetSpecialFolderLocation
returns a pointer to PIDLIST_ABSOLUTE
, and SHGetPathFromIDList
accepts PCIDLIST_ABSOLUTE
:
Public Declare PtrSafe Function SHGetSpecialFolderLocation Lib "shell32.dll" _
(ByVal hwndOwner As LongPtr, ByVal nFolder As Long, ByRef pIdl As LongPtr) As Long
Public Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" _
Alias "SHGetPathFromIDListA" (ByVal pIdl As LongPtr, ByVal pszPath As String) As Long
Public Declare PtrSafe Sub CoTaskMemFree Lib "ole32.dll" (pv As Any)
Public Function GetSpecialFolder(ByVal CSIDL As Long) As String
Dim retval As Long
Dim pIdl As LongPtr
Dim sPath As String
Const MAX_LENGTH = 260
retval = SHGetSpecialFolderLocation(0, CSIDL, pIdl)
If retval = 0 Then
sPath = Space$(MAX_LENGTH)
retval = SHGetPathFromIDList(pIdl, sPath)
If retval <> 0 Then
GetSpecialFolder = Left$(sPath, InStr(sPath, Chr$(0)) - 1) & ""
End If
CoTaskMemFree ByVal pIdl
End If
End Function
Note that it's pointless to have an On Error Goto
in such function because Windows API generally do not raise exceptions, they return error codes. It would make sense if you used Err.Raise ...
after finding out a return value indicates an error.
SHGetSpecialFolderLocation
does not fill in the memory you allocate for ITEMIDLIST
like Declare
d function usually do, it allocates a new piece of memory that you are later required to free with CoTaskMemFree
. That makes it pointless to declare ITEMIDLIST
as a structure in VBA to begin with (and your declaration is wrong anyway, cb
must be Integer
, and abID
is a variable-length byte array, not a single byte).
If you needed to do something with individual members of a structure allocated in this way, you would have to copy them out of the returned pointer with CopyMemory
. Luckily, you don't need to do any of that because SHGetSpecialFolderLocation
returns a pointer to PIDLIST_ABSOLUTE
, and SHGetPathFromIDList
accepts PCIDLIST_ABSOLUTE
:
Public Declare PtrSafe Function SHGetSpecialFolderLocation Lib "shell32.dll" _
(ByVal hwndOwner As LongPtr, ByVal nFolder As Long, ByRef pIdl As LongPtr) As Long
Public Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" _
Alias "SHGetPathFromIDListA" (ByVal pIdl As LongPtr, ByVal pszPath As String) As Long
Public Declare PtrSafe Sub CoTaskMemFree Lib "ole32.dll" (pv As Any)
Public Function GetSpecialFolder(ByVal CSIDL As Long) As String
Dim retval As Long
Dim pIdl As LongPtr
Dim sPath As String
Const MAX_LENGTH = 260
retval = SHGetSpecialFolderLocation(0, CSIDL, pIdl)
If retval = 0 Then
sPath = Space$(MAX_LENGTH)
retval = SHGetPathFromIDList(pIdl, sPath)
If retval <> 0 Then
GetSpecialFolder = Left$(sPath, InStr(sPath, Chr$(0)) - 1) & ""
End If
CoTaskMemFree ByVal pIdl
End If
End Function
Note that it's pointless to have an On Error Goto
in such function because Windows API generally do not raise exceptions, they return error codes. It would make sense if you used Err.Raise ...
after finding out a return value indicates an error.
edited Nov 12 at 8:27
answered Nov 12 at 2:21
GSerg
58.6k14100217
58.6k14100217
Yeah, that's pretty much it. +1.SHGetPathFromIDList
returns a bool though.
– Comintern
Nov 12 at 2:25
@CominternLen(bool)
is 2 in VBA, so like withhWnd
, I'm keen on keeping the size correct ;)
– GSerg
Nov 12 at 2:26
Fair enough - I personally let the marshaller handle that so I can retain the VBA semantics.
– Comintern
Nov 12 at 2:29
@Comintern You got me wondering about that marshalling, so I've done a little test and nope, it truncates without actually marshalling. If you declare the function and theretval
variableAs Boolean
, the bits that end up in theretval
variable on VBA side are0x0001
, which is "truthy", but does not actually equalTrue
. They would be0xFFFF
if there was actually marshalling. Which means that doingretval_bool = SHGetPathFromIDList(pIdl, sPath)
and thenIf retval_bool Then
will execute theIf
, butIf retval_bool = True Then
will not. (I have tested, it does not= True
).
– GSerg
Nov 12 at 2:44
1
@RCW05 Yes, and you should not have differentDeclare
s for 32 and 64 bits. That is why there isLongPtr
to begin with. The only reason to have two declarations would be if you still support Office 2003 and below where you don't havePtrSafe
andLongPtr
, but then you need to branch on#If VBA7 Then
, not on#If Win64 Then
.
– GSerg
Nov 13 at 12:17
|
show 10 more comments
Yeah, that's pretty much it. +1.SHGetPathFromIDList
returns a bool though.
– Comintern
Nov 12 at 2:25
@CominternLen(bool)
is 2 in VBA, so like withhWnd
, I'm keen on keeping the size correct ;)
– GSerg
Nov 12 at 2:26
Fair enough - I personally let the marshaller handle that so I can retain the VBA semantics.
– Comintern
Nov 12 at 2:29
@Comintern You got me wondering about that marshalling, so I've done a little test and nope, it truncates without actually marshalling. If you declare the function and theretval
variableAs Boolean
, the bits that end up in theretval
variable on VBA side are0x0001
, which is "truthy", but does not actually equalTrue
. They would be0xFFFF
if there was actually marshalling. Which means that doingretval_bool = SHGetPathFromIDList(pIdl, sPath)
and thenIf retval_bool Then
will execute theIf
, butIf retval_bool = True Then
will not. (I have tested, it does not= True
).
– GSerg
Nov 12 at 2:44
1
@RCW05 Yes, and you should not have differentDeclare
s for 32 and 64 bits. That is why there isLongPtr
to begin with. The only reason to have two declarations would be if you still support Office 2003 and below where you don't havePtrSafe
andLongPtr
, but then you need to branch on#If VBA7 Then
, not on#If Win64 Then
.
– GSerg
Nov 13 at 12:17
Yeah, that's pretty much it. +1.
SHGetPathFromIDList
returns a bool though.– Comintern
Nov 12 at 2:25
Yeah, that's pretty much it. +1.
SHGetPathFromIDList
returns a bool though.– Comintern
Nov 12 at 2:25
@Comintern
Len(bool)
is 2 in VBA, so like with hWnd
, I'm keen on keeping the size correct ;)– GSerg
Nov 12 at 2:26
@Comintern
Len(bool)
is 2 in VBA, so like with hWnd
, I'm keen on keeping the size correct ;)– GSerg
Nov 12 at 2:26
Fair enough - I personally let the marshaller handle that so I can retain the VBA semantics.
– Comintern
Nov 12 at 2:29
Fair enough - I personally let the marshaller handle that so I can retain the VBA semantics.
– Comintern
Nov 12 at 2:29
@Comintern You got me wondering about that marshalling, so I've done a little test and nope, it truncates without actually marshalling. If you declare the function and the
retval
variable As Boolean
, the bits that end up in the retval
variable on VBA side are 0x0001
, which is "truthy", but does not actually equal True
. They would be 0xFFFF
if there was actually marshalling. Which means that doing retval_bool = SHGetPathFromIDList(pIdl, sPath)
and then If retval_bool Then
will execute the If
, but If retval_bool = True Then
will not. (I have tested, it does not = True
).– GSerg
Nov 12 at 2:44
@Comintern You got me wondering about that marshalling, so I've done a little test and nope, it truncates without actually marshalling. If you declare the function and the
retval
variable As Boolean
, the bits that end up in the retval
variable on VBA side are 0x0001
, which is "truthy", but does not actually equal True
. They would be 0xFFFF
if there was actually marshalling. Which means that doing retval_bool = SHGetPathFromIDList(pIdl, sPath)
and then If retval_bool Then
will execute the If
, but If retval_bool = True Then
will not. (I have tested, it does not = True
).– GSerg
Nov 12 at 2:44
1
1
@RCW05 Yes, and you should not have different
Declare
s for 32 and 64 bits. That is why there is LongPtr
to begin with. The only reason to have two declarations would be if you still support Office 2003 and below where you don't have PtrSafe
and LongPtr
, but then you need to branch on #If VBA7 Then
, not on #If Win64 Then
.– GSerg
Nov 13 at 12:17
@RCW05 Yes, and you should not have different
Declare
s for 32 and 64 bits. That is why there is LongPtr
to begin with. The only reason to have two declarations would be if you still support Office 2003 and below where you don't have PtrSafe
and LongPtr
, but then you need to branch on #If VBA7 Then
, not on #If Win64 Then
.– GSerg
Nov 13 at 12:17
|
show 10 more comments
up vote
1
down vote
TBH, I have no clue how this was functioning correctly on a 32 bit build. The declarations for the two structures are incorrect. This one...
Private Type ShortItemId
cb As Long
abID As Byte
End Type
...is defined in the MS documentation as this:
typedef struct _SHITEMID {
USHORT cb;
BYTE abID[1];
} SHITEMID;
Note that abID
is an array, and cb
is an unsigned short (you can use an Integer
for that in VBA, but it definitely is not a Long
).
In addition, this structure (wrapped in the ITEMIDLIST) is not even supposed to be allocated by the caller, but must be freed by the caller:
It is the responsibility of the calling application to free the returned IDList by using CoTaskMemFree.
Re the pointers, the only pointers (that aren't being marshaled from String
) are the
pidl
parameter of SHGetSpecialFolderLocation
and the pointer to ppidl
in SHGetPathFromIDList
. Note that you can't use a VBA defined struct, because you need to free the memory when you're done. Something like this will work:
Private Declare PtrSafe Function SHGetSpecialFolderLocation Lib "shell32.dll" _
(ByVal hwndOwner As Long, ByVal nFolder As Long, pidl As LongPtr) As Long
Private Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" _
Alias "SHGetPathFromIDListA" (ByVal pidl As LongPtr, ByVal pszPath As String) As Boolean
Private Declare PtrSafe Sub CoTaskMemFree Lib "ole32.dll" (ByVal pv As LongPtr)
Private Const S_OK As Long = 0
Private Const MAX_LENGTH = 260
Public Function GetSpecialFolder(ByVal CSIDL As Integer) As String
Dim result As Long
Dim path As String
Dim idl_ptr As LongPtr
'Fill the IDL structure with the specified folder item.
result = SHGetSpecialFolderLocation(0, CSIDL, idl_ptr)
If result = S_OK Then
'Get the path from the IDL list, and return the folder adding final "".
path = Space$(MAX_LENGTH)
If SHGetPathFromIDList(idl_ptr, path) Then
GetSpecialFolder = Left$(path, InStr(path, vbNullChar) - 1) & ""
End If
CoTaskMemFree idl_ptr
End If
End Function
Note that per the discussion in the comments, you could technically declare hwndOwner
as LongPtr
as well, but it shouldn't make any difference.
When trying this I'm getting an idl_ptr ByRef argument type Mismatch.. any idea why?
– RCW05
Nov 12 at 3:09
@RCW05 That's odd, works just fine for me. Which line gives you the error? Note thatpidl As LongPtr
is not declaredByVal
, so it's implicitlyByRef
in the declaration.
– Comintern
Nov 12 at 3:12
@RCW05 - Ahhh... I changed the function signature toCSIDL As Integer
because, well, CSIDL is not aLong
. Make that explicitlyByVal
(see the edit).
– Comintern
Nov 12 at 3:16
I'm not sure what I'm doing wrong here. Even this code is now giving me ByRef argument type mismatch when copy and pasted?
– RCW05
Nov 13 at 12:03
Please ignore this sorry - I had another version declared and didn't realise it would conflict .... DOH!
– RCW05
Nov 13 at 12:19
|
show 1 more comment
up vote
1
down vote
TBH, I have no clue how this was functioning correctly on a 32 bit build. The declarations for the two structures are incorrect. This one...
Private Type ShortItemId
cb As Long
abID As Byte
End Type
...is defined in the MS documentation as this:
typedef struct _SHITEMID {
USHORT cb;
BYTE abID[1];
} SHITEMID;
Note that abID
is an array, and cb
is an unsigned short (you can use an Integer
for that in VBA, but it definitely is not a Long
).
In addition, this structure (wrapped in the ITEMIDLIST) is not even supposed to be allocated by the caller, but must be freed by the caller:
It is the responsibility of the calling application to free the returned IDList by using CoTaskMemFree.
Re the pointers, the only pointers (that aren't being marshaled from String
) are the
pidl
parameter of SHGetSpecialFolderLocation
and the pointer to ppidl
in SHGetPathFromIDList
. Note that you can't use a VBA defined struct, because you need to free the memory when you're done. Something like this will work:
Private Declare PtrSafe Function SHGetSpecialFolderLocation Lib "shell32.dll" _
(ByVal hwndOwner As Long, ByVal nFolder As Long, pidl As LongPtr) As Long
Private Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" _
Alias "SHGetPathFromIDListA" (ByVal pidl As LongPtr, ByVal pszPath As String) As Boolean
Private Declare PtrSafe Sub CoTaskMemFree Lib "ole32.dll" (ByVal pv As LongPtr)
Private Const S_OK As Long = 0
Private Const MAX_LENGTH = 260
Public Function GetSpecialFolder(ByVal CSIDL As Integer) As String
Dim result As Long
Dim path As String
Dim idl_ptr As LongPtr
'Fill the IDL structure with the specified folder item.
result = SHGetSpecialFolderLocation(0, CSIDL, idl_ptr)
If result = S_OK Then
'Get the path from the IDL list, and return the folder adding final "".
path = Space$(MAX_LENGTH)
If SHGetPathFromIDList(idl_ptr, path) Then
GetSpecialFolder = Left$(path, InStr(path, vbNullChar) - 1) & ""
End If
CoTaskMemFree idl_ptr
End If
End Function
Note that per the discussion in the comments, you could technically declare hwndOwner
as LongPtr
as well, but it shouldn't make any difference.
When trying this I'm getting an idl_ptr ByRef argument type Mismatch.. any idea why?
– RCW05
Nov 12 at 3:09
@RCW05 That's odd, works just fine for me. Which line gives you the error? Note thatpidl As LongPtr
is not declaredByVal
, so it's implicitlyByRef
in the declaration.
– Comintern
Nov 12 at 3:12
@RCW05 - Ahhh... I changed the function signature toCSIDL As Integer
because, well, CSIDL is not aLong
. Make that explicitlyByVal
(see the edit).
– Comintern
Nov 12 at 3:16
I'm not sure what I'm doing wrong here. Even this code is now giving me ByRef argument type mismatch when copy and pasted?
– RCW05
Nov 13 at 12:03
Please ignore this sorry - I had another version declared and didn't realise it would conflict .... DOH!
– RCW05
Nov 13 at 12:19
|
show 1 more comment
up vote
1
down vote
up vote
1
down vote
TBH, I have no clue how this was functioning correctly on a 32 bit build. The declarations for the two structures are incorrect. This one...
Private Type ShortItemId
cb As Long
abID As Byte
End Type
...is defined in the MS documentation as this:
typedef struct _SHITEMID {
USHORT cb;
BYTE abID[1];
} SHITEMID;
Note that abID
is an array, and cb
is an unsigned short (you can use an Integer
for that in VBA, but it definitely is not a Long
).
In addition, this structure (wrapped in the ITEMIDLIST) is not even supposed to be allocated by the caller, but must be freed by the caller:
It is the responsibility of the calling application to free the returned IDList by using CoTaskMemFree.
Re the pointers, the only pointers (that aren't being marshaled from String
) are the
pidl
parameter of SHGetSpecialFolderLocation
and the pointer to ppidl
in SHGetPathFromIDList
. Note that you can't use a VBA defined struct, because you need to free the memory when you're done. Something like this will work:
Private Declare PtrSafe Function SHGetSpecialFolderLocation Lib "shell32.dll" _
(ByVal hwndOwner As Long, ByVal nFolder As Long, pidl As LongPtr) As Long
Private Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" _
Alias "SHGetPathFromIDListA" (ByVal pidl As LongPtr, ByVal pszPath As String) As Boolean
Private Declare PtrSafe Sub CoTaskMemFree Lib "ole32.dll" (ByVal pv As LongPtr)
Private Const S_OK As Long = 0
Private Const MAX_LENGTH = 260
Public Function GetSpecialFolder(ByVal CSIDL As Integer) As String
Dim result As Long
Dim path As String
Dim idl_ptr As LongPtr
'Fill the IDL structure with the specified folder item.
result = SHGetSpecialFolderLocation(0, CSIDL, idl_ptr)
If result = S_OK Then
'Get the path from the IDL list, and return the folder adding final "".
path = Space$(MAX_LENGTH)
If SHGetPathFromIDList(idl_ptr, path) Then
GetSpecialFolder = Left$(path, InStr(path, vbNullChar) - 1) & ""
End If
CoTaskMemFree idl_ptr
End If
End Function
Note that per the discussion in the comments, you could technically declare hwndOwner
as LongPtr
as well, but it shouldn't make any difference.
TBH, I have no clue how this was functioning correctly on a 32 bit build. The declarations for the two structures are incorrect. This one...
Private Type ShortItemId
cb As Long
abID As Byte
End Type
...is defined in the MS documentation as this:
typedef struct _SHITEMID {
USHORT cb;
BYTE abID[1];
} SHITEMID;
Note that abID
is an array, and cb
is an unsigned short (you can use an Integer
for that in VBA, but it definitely is not a Long
).
In addition, this structure (wrapped in the ITEMIDLIST) is not even supposed to be allocated by the caller, but must be freed by the caller:
It is the responsibility of the calling application to free the returned IDList by using CoTaskMemFree.
Re the pointers, the only pointers (that aren't being marshaled from String
) are the
pidl
parameter of SHGetSpecialFolderLocation
and the pointer to ppidl
in SHGetPathFromIDList
. Note that you can't use a VBA defined struct, because you need to free the memory when you're done. Something like this will work:
Private Declare PtrSafe Function SHGetSpecialFolderLocation Lib "shell32.dll" _
(ByVal hwndOwner As Long, ByVal nFolder As Long, pidl As LongPtr) As Long
Private Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" _
Alias "SHGetPathFromIDListA" (ByVal pidl As LongPtr, ByVal pszPath As String) As Boolean
Private Declare PtrSafe Sub CoTaskMemFree Lib "ole32.dll" (ByVal pv As LongPtr)
Private Const S_OK As Long = 0
Private Const MAX_LENGTH = 260
Public Function GetSpecialFolder(ByVal CSIDL As Integer) As String
Dim result As Long
Dim path As String
Dim idl_ptr As LongPtr
'Fill the IDL structure with the specified folder item.
result = SHGetSpecialFolderLocation(0, CSIDL, idl_ptr)
If result = S_OK Then
'Get the path from the IDL list, and return the folder adding final "".
path = Space$(MAX_LENGTH)
If SHGetPathFromIDList(idl_ptr, path) Then
GetSpecialFolder = Left$(path, InStr(path, vbNullChar) - 1) & ""
End If
CoTaskMemFree idl_ptr
End If
End Function
Note that per the discussion in the comments, you could technically declare hwndOwner
as LongPtr
as well, but it shouldn't make any difference.
edited Nov 12 at 3:16
answered Nov 12 at 2:23
Comintern
17.9k42354
17.9k42354
When trying this I'm getting an idl_ptr ByRef argument type Mismatch.. any idea why?
– RCW05
Nov 12 at 3:09
@RCW05 That's odd, works just fine for me. Which line gives you the error? Note thatpidl As LongPtr
is not declaredByVal
, so it's implicitlyByRef
in the declaration.
– Comintern
Nov 12 at 3:12
@RCW05 - Ahhh... I changed the function signature toCSIDL As Integer
because, well, CSIDL is not aLong
. Make that explicitlyByVal
(see the edit).
– Comintern
Nov 12 at 3:16
I'm not sure what I'm doing wrong here. Even this code is now giving me ByRef argument type mismatch when copy and pasted?
– RCW05
Nov 13 at 12:03
Please ignore this sorry - I had another version declared and didn't realise it would conflict .... DOH!
– RCW05
Nov 13 at 12:19
|
show 1 more comment
When trying this I'm getting an idl_ptr ByRef argument type Mismatch.. any idea why?
– RCW05
Nov 12 at 3:09
@RCW05 That's odd, works just fine for me. Which line gives you the error? Note thatpidl As LongPtr
is not declaredByVal
, so it's implicitlyByRef
in the declaration.
– Comintern
Nov 12 at 3:12
@RCW05 - Ahhh... I changed the function signature toCSIDL As Integer
because, well, CSIDL is not aLong
. Make that explicitlyByVal
(see the edit).
– Comintern
Nov 12 at 3:16
I'm not sure what I'm doing wrong here. Even this code is now giving me ByRef argument type mismatch when copy and pasted?
– RCW05
Nov 13 at 12:03
Please ignore this sorry - I had another version declared and didn't realise it would conflict .... DOH!
– RCW05
Nov 13 at 12:19
When trying this I'm getting an idl_ptr ByRef argument type Mismatch.. any idea why?
– RCW05
Nov 12 at 3:09
When trying this I'm getting an idl_ptr ByRef argument type Mismatch.. any idea why?
– RCW05
Nov 12 at 3:09
@RCW05 That's odd, works just fine for me. Which line gives you the error? Note that
pidl As LongPtr
is not declared ByVal
, so it's implicitly ByRef
in the declaration.– Comintern
Nov 12 at 3:12
@RCW05 That's odd, works just fine for me. Which line gives you the error? Note that
pidl As LongPtr
is not declared ByVal
, so it's implicitly ByRef
in the declaration.– Comintern
Nov 12 at 3:12
@RCW05 - Ahhh... I changed the function signature to
CSIDL As Integer
because, well, CSIDL is not a Long
. Make that explicitly ByVal
(see the edit).– Comintern
Nov 12 at 3:16
@RCW05 - Ahhh... I changed the function signature to
CSIDL As Integer
because, well, CSIDL is not a Long
. Make that explicitly ByVal
(see the edit).– Comintern
Nov 12 at 3:16
I'm not sure what I'm doing wrong here. Even this code is now giving me ByRef argument type mismatch when copy and pasted?
– RCW05
Nov 13 at 12:03
I'm not sure what I'm doing wrong here. Even this code is now giving me ByRef argument type mismatch when copy and pasted?
– RCW05
Nov 13 at 12:03
Please ignore this sorry - I had another version declared and didn't realise it would conflict .... DOH!
– RCW05
Nov 13 at 12:19
Please ignore this sorry - I had another version declared and didn't realise it would conflict .... DOH!
– RCW05
Nov 13 at 12:19
|
show 1 more comment
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53254577%2fvba-office-365-x64-bit-completely-crashing%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Comments are not for extended discussion; this conversation has been moved to chat.
– Samuel Liew♦
Nov 12 at 4:58