▣ 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


▣ 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


▣ 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


▣ Vista 이전 버전에서 실행하면 에러 발생
사용자 삽입 이미지

▣ FOLDERID_LocalAppDataLow => C:\Users\<user account>\AppData\LocalLow
사용자 삽입 이미지






☞ 본문 출처 : http://www.enjoydev.com/blog/113(새 창으로 열기)

☞ 본인의 글 입니다. 이 글을 다른 곳에 게재하는 경우 본문 출처를 밝혀주시기 바랍니다.

2007/04/09 10:50 2007/04/09 10:50

트랙백 주소 :: http://www.enjoydev.com/blog/trackback/113

댓글을 달아 주세요

  1. 행인1 2009/10/25 19:41  댓글주소  수정/삭제  댓글쓰기

    이 코드 이용해서 도움 많이 됐습니다 ^^
    근데 StringFromPointer에서 유저명이 한글인 경우 한글 문자열 처리하면서 ByteArray가 오버플로되는 버그가 있네요.
    이 부분만 Byte에서 변환하는 것이 아니라 ChrW 함수 이용하는 방식으로 한글 처리 했습니다.
    이 코드 에러나는 다른 분들 참고하세요.