VBA - Office 365 x64 bit - Completely crashing












1














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!










share|improve this question
























  • Comments are not for extended discussion; this conversation has been moved to chat.
    – Samuel Liew
    Nov 12 at 4:58
















1














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!










share|improve this question
























  • Comments are not for extended discussion; this conversation has been moved to chat.
    – Samuel Liew
    Nov 12 at 4:58














1












1








1







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!










share|improve this question















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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


















  • 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












2 Answers
2






active

oldest

votes


















1














SHGetSpecialFolderLocation does not fill in the memory you allocate for ITEMIDLIST like Declared 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.






share|improve this answer























  • 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










  • 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








  • 1




    @RCW05 Yes, and you should not have different Declares 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



















1














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.






share|improve this answer























  • 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 - 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










  • Please ignore this sorry - I had another version declared and didn't realise it would conflict .... DOH!
    – RCW05
    Nov 13 at 12:19











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















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

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














SHGetSpecialFolderLocation does not fill in the memory you allocate for ITEMIDLIST like Declared 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.






share|improve this answer























  • 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










  • 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








  • 1




    @RCW05 Yes, and you should not have different Declares 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
















1














SHGetSpecialFolderLocation does not fill in the memory you allocate for ITEMIDLIST like Declared 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.






share|improve this answer























  • 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










  • 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








  • 1




    @RCW05 Yes, and you should not have different Declares 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














1












1








1






SHGetSpecialFolderLocation does not fill in the memory you allocate for ITEMIDLIST like Declared 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.






share|improve this answer














SHGetSpecialFolderLocation does not fill in the memory you allocate for ITEMIDLIST like Declared 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.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 12 at 8:27

























answered Nov 12 at 2:21









GSerg

58.7k14100218




58.7k14100218












  • 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










  • 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








  • 1




    @RCW05 Yes, and you should not have different Declares 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


















  • 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










  • 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








  • 1




    @RCW05 Yes, and you should not have different Declares 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
















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 Declares 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 Declares 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













1














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.






share|improve this answer























  • 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 - 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










  • Please ignore this sorry - I had another version declared and didn't realise it would conflict .... DOH!
    – RCW05
    Nov 13 at 12:19
















1














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.






share|improve this answer























  • 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 - 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










  • Please ignore this sorry - I had another version declared and didn't realise it would conflict .... DOH!
    – RCW05
    Nov 13 at 12:19














1












1








1






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.






share|improve this answer














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.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 12 at 3:16

























answered Nov 12 at 2:23









Comintern

18k42354




18k42354












  • 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 - 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










  • 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










  • @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










  • 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


















draft saved

draft discarded




















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

Florida Star v. B. J. F.

Danny Elfman

Lugert, Oklahoma