▣ Vista에서는 보안 기능(UAC)이 강화됨에 따라 일반 사용자 계정에서 접근(Writable) 가능한 폴더가 제한적으로 바뀌었습니다. Vista 이전에는 SHGetFolderPath() 함수를 이용해서 특수 폴더의 경로를 구할 수 있었는데, Vista에서는 쓰기 가능한 폴더를 구할 수 있는 SHGetKnownFolderPath() 함수가 추가되었습니다.
VC, Delphi 등의 언어에서 SHGetKnownFolderPath() 함수 사용에 대한 소스는 구글링을 통해 쉽게 찾을 수 있었지만 VB6 에 대한 예제는 찾을 수 없어 만들어봅니다.
▣ API 선언
'-------------------------------------------------------------------------------
' IID
Private Const FOLDERID_LocalAppDataLow As String = "{A520A1A4-1780-4FF6-BD18-167343C5AF16}"
'-------------------------------------------------------------------------------
' SHGetKnownFolderPath
Private Declare Function SHGetKnownFolderPathA Lib "shell32" Alias "SHGetKnownFolderPath" (ByRef rfid As GUID, ByVal dwFlags As Long, ByVal hToken As Long, ByRef ppszPath As Long) As Long
' IID
Private Const FOLDERID_LocalAppDataLow As String = "{A520A1A4-1780-4FF6-BD18-167343C5AF16}"
'-------------------------------------------------------------------------------
' SHGetKnownFolderPath
Private Declare Function SHGetKnownFolderPathA Lib "shell32" Alias "SHGetKnownFolderPath" (ByRef rfid As GUID, ByVal dwFlags As Long, ByVal hToken As Long, ByRef ppszPath As Long) As Long
▣ VB에서 SHGetKnownFolderPath() API 사용 예제 (Vista 이상에서만 정상 실행됨)
'===============================================================================
' 함 수 명 : SHGetKnownFolderPath()
' 설 명 : Vista에서 쓰기 가능한 폴더 구하기
' 입 력 값 :
' 결 과 값 :
' 작 성 일 : 2007.04.06
' 작 성 자 : 제용재(182cm@korea.com)
'===============================================================================
Public Function SHGetKnownFolderPath() As String
Dim hr As Long
Dim pPath As Long
Dim rfid As GUID
Dim strPath As String
Call CLSIDFromString(StrPtr(FOLDERID_LocalAppDataLow), rfid)
hr = SHGetKnownFolderPathA(rfid, 0&, 0&, pPath)
If hr <> 0 Then
Err.Raise hr, , FormatMessage(hr)
Exit Function
End If
Call StringFromPointer(pPath, strPath)
' FOLDERID_LocalAppDataLow => C:\Users\<user account>\AppData\LocalLow
SHGetKnownFolderPath = strPath
Exit Function
End Function
' 함 수 명 : SHGetKnownFolderPath()
' 설 명 : Vista에서 쓰기 가능한 폴더 구하기
' 입 력 값 :
' 결 과 값 :
' 작 성 일 : 2007.04.06
' 작 성 자 : 제용재(182cm@korea.com)
'===============================================================================
Public Function SHGetKnownFolderPath() As String
Dim hr As Long
Dim pPath As Long
Dim rfid As GUID
Dim strPath As String
Call CLSIDFromString(StrPtr(FOLDERID_LocalAppDataLow), rfid)
hr = SHGetKnownFolderPathA(rfid, 0&, 0&, pPath)
If hr <> 0 Then
Err.Raise hr, , FormatMessage(hr)
Exit Function
End If
Call StringFromPointer(pPath, strPath)
' FOLDERID_LocalAppDataLow => C:\Users\<user account>\AppData\LocalLow
SHGetKnownFolderPath = strPath
Exit Function
End Function
▣ API에서 리턴받은 UNICODE 문자열 처리
'===============================================================================
' 함 수 명 : StringFromPointer()
' 설 명 : String Pinter로부터 String 데이터 구함
' 입 력 값 :
' 결 과 값 :
' 참 고 : http://support.microsoft.com/kb/183544
' 작 성 일 : 2007.04.06
' 작 성 자 : 제용재(182cm@korea.com)
'===============================================================================
Private Sub StringFromPointer(pOLESTR As Long, strOut As String)
Dim ByteArray(255) As Byte
Dim intTemp As Integer
Dim intCount As Integer
Dim i As Integer
intTemp = 1
'Walk the string and retrieve the first byte of each WORD.
While intTemp <> 0
CopyMemory intTemp, ByVal pOLESTR + i, 2
ByteArray(intCount) = intTemp
intCount = intCount + 1
i = i + 2
Wend
'Copy the byte array to our string.
strOut = String(intCount, Chr$(0))
CopyMemory ByVal strOut, ByteArray(0), intCount
If InStr(1, strOut, Chr$(0)) > 0 Then
strOut = Left(strOut, InStr(1, strOut, Chr$(0)) - 1)
End If
End Sub
' 함 수 명 : StringFromPointer()
' 설 명 : String Pinter로부터 String 데이터 구함
' 입 력 값 :
' 결 과 값 :
' 참 고 : http://support.microsoft.com/kb/183544
' 작 성 일 : 2007.04.06
' 작 성 자 : 제용재(182cm@korea.com)
'===============================================================================
Private Sub StringFromPointer(pOLESTR As Long, strOut As String)
Dim ByteArray(255) As Byte
Dim intTemp As Integer
Dim intCount As Integer
Dim i As Integer
intTemp = 1
'Walk the string and retrieve the first byte of each WORD.
While intTemp <> 0
CopyMemory intTemp, ByVal pOLESTR + i, 2
ByteArray(intCount) = intTemp
intCount = intCount + 1
i = i + 2
Wend
'Copy the byte array to our string.
strOut = String(intCount, Chr$(0))
CopyMemory ByVal strOut, ByteArray(0), intCount
If InStr(1, strOut, Chr$(0)) > 0 Then
strOut = Left(strOut, InStr(1, strOut, Chr$(0)) - 1)
End If
End Sub
▣ Vista 이전 버전에서 실행하면 에러 발생

▣ FOLDERID_LocalAppDataLow => C:\Users\<user account>\AppData\LocalLow

☞ 본문 출처 : http://www.enjoydev.com/blog/113
☞ 본인의 글 입니다. 이 글을 다른 곳에 게재하는 경우 본문 출처를 밝혀주시기 바랍니다.
SHGetKnownFolderPath.exe
SHGetKnownFolderPath.zip
댓글을 달아 주세요
이 코드 이용해서 도움 많이 됐습니다 ^^
근데 StringFromPointer에서 유저명이 한글인 경우 한글 문자열 처리하면서 ByteArray가 오버플로되는 버그가 있네요.
이 부분만 Byte에서 변환하는 것이 아니라 ChrW 함수 이용하는 방식으로 한글 처리 했습니다.
이 코드 에러나는 다른 분들 참고하세요.
한글유저 에러나는 부분 때문에 헤메고 있습니다.
혹시 수정하신 걸 볼 수 있을지요...