-1

FOLDERID_RoamingAppData で SHGetKnownFolderPath を呼び出すプログラムがあります。

プログラムをダブルクリックして起動すると、問題なく動作します。

プログラムが (現在のユーザー コンテキストで) Windows サービスによって開始された場合、関数はエラー E_ACCESSDENIED (-2147024891) で失敗します。

これは私のコードがどのように見えるかです:

Tstring EasyGetFolderPath(REFKNOWNFOLDERID folderid)
{
    Tstring sPath = _T("");
    PWSTR pszPath = NULL;

    HRESULT hr = SHGetKnownFolderPath(folderid, 0, NULL, &pszPath);

    if (hr == S_OK && pszPath)
    {
        sPath = WStringToTCHAR(pszPath);
        CoTaskMemFree(pszPath);
        return sPath;
    }
    else
    {
        throw HResultException(hr, _T("SHGetKnownFolderPath failed"));
    }
}

Tstring EasyGetUsrAppDataPath()
{
    return EasyGetFolderPath(FOLDERID_RoamingAppData);
}

static TCHAR* WStringToTCHAR(const std::wstring &s)
{
#ifdef UNICODE
    TCHAR *sT = new TCHAR[s.length() + 1];
    _tcscpy_s(sT, s.length() + 1, s.c_str());
    return sT;
#else
    std::string str = WStringToString(s);
    TCHAR *sT = new TCHAR[str.length()+1];
    _tcscpy_s(sT, str.length() + 1, str.c_str());
    return sT;
#endif // UNICODE
}

static std::string WStringToString(const std::wstring& s, bool method = true)
{
    std::string temp;
    temp.assign(s.begin(), s.end());
    return temp;
}

これは、現在のユーザー コンテキストでプロセスを開始するコードです: (詳細を減らすためにエラー処理を削除しました)

void StartProcessInCurrentUserContext(const Tstring &sExeName, const Tstringarr &lstParams, const Tstring &sWorkingDir)
{
    ...

    EnableDebugPrivilege();

    errCode = GetProcessByName(_T("explorer.exe"), hProcess);

    if (!OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hToken))
    {
        ...
    }

    if (hProcess)
        CloseHandle(hProcess);

    Tstring sCmdLine = ...;

    ...

    // Create the child process. 
    bSuccess = CreateProcessAsUser(hToken, NULL,
        (LPTSTR)sCmdLine.c_str(),            // command line 
        NULL,          // process security attributes 
        NULL,          // primary thread security attributes 
        TRUE,          // handles are inherited 
        0,             // creation flags 
        NULL,          // use parent's environment 
        sWorkingDir.length() > 0 ? (LPCTSTR)sWorkingDir.c_str() : NULL,
        &siStartInfo,  // STARTUPINFO pointer 
        &piProcInfo);  // receives PROCESS_INFORMATION 

    CloseHandle(hToken);

    ...
}

問題が何であるかを知っている人はいますか?

4

1 に答える 1

1

SHGetKnownFolderPathのドキュメントには、hTokenパラメータの説明で次のように記載されています。

ユーザーのhTokenを渡すだけでなく、その特定のユーザーのレジストリ ハイブをマウントする必要があります。

CreateProcessAsUserのドキュメントには、

CreateProcessAsUserは、指定されたユーザーのプロファイルをHKEY_USERSレジストリ キーに読み込みません。

これら 2 つのパラグラフを合わせて、コードが機能しない理由を説明します。幸いなことに、 CreateProcessAsUserのドキュメントの次の文で、何をする必要があるかが説明されています。

したがって、HKEY_CURRENT_USERレジストリ キーの情報にアクセスするには、 CreateProcessAsUserを呼び出す前に、LoadUserProfile関数を使用してユーザーのプロファイル情報をHKEY_USERSに読み込む必要があります。新しいプロセスが終了したら、必ずUnloadUserProfileを呼び出してください。

于 2016-05-31T17:05:50.493 に答える