0

私のアプリケーションはサービスとして実行され、ある時点で、システム上の既存のすべてのユーザー アカウントをループし (これは で実行できると考えましたNetUserEnum())、見つかった各ユーザーの %APPDATA% パスの下にある特定のファイルにアクセスする必要があります。問題は、そのユーザー固有のパス (%APPDATA%) を取得する方法がわからないことです。

アプリケーションはサービス (SYSTEM) として実行されるため、環境またはSHGetFolderPath(). 最初は利用できると思ってLogonUser()いましたが、ユーザー、管理者、またはシステムでアプリケーションテストコードを実行しても、常にエラー1326がスローされます。(テスト プラットフォームとしての winxp)。ユーザーのログイン ハンドルを取得する方法があれば、SHGetFolderPath()またはExpandEnvironmentStringsForUser()API で使用できますが、正しいですか?

したがって、これまで LogonUser() で試したコードは次のとおりです(はい、ユーザー名は正しいです):

LogonUser(
    pw->usri1_name,
    L".",
    NULL,
    LOGON32_LOGON_BATCH,
    LOGON32_PROVIDER_DEFAULT,
    &authtoken
)

おそらくパスワードが必要ですが、顧客のマシンでそれを知る方法はありません。クイック検索で見つけたすべての API は、LogonUser() の HANDLE に依存しているようですが、これは明らかに使用できません...

トリッキーでないアイデアやトリッキーなアイデアは大歓迎です!

4

3 に答える 3

0

特別なフォルダを取得するために「ローカル システム」として実行されるサービスまたはアプリケーション

この例ではCSIDL_DESKTOPDIRECTORYを取得し、XP、win7(32,64) で正常に動作します。

DWORD ServiceGetDesktopDirectory(LPWSTR lpUserName, LPWSTR lpPassword,
    LPWSTR lpDomain, LPWSTR lpBuffer)
{

HANDLE hToken;
BOOL bRet;
bRet = LogonUserW(lpUserName,
                 lpDomain,
                 lpPassword,
                 LOGON32_LOGON_INTERACTIVE,
                 LOGON32_PROVIDER_DEFAULT,
                 &hToken);
if (!bRet) {
    error("LogonUser failed, gle = %lu", GetLastError());
    return FILE_ERR_INVALID_USERNAME_OR_PASSWORD;
}


NET_API_STATUS ntStatus;
USER_INFO_4 *pUserInfo;
ntStatus = NetUserGetInfo((LPCWSTR)lpDomain,
                          (LPCWSTR)lpUserName,
                          4,
                          (BYTE**)&pUserInfo);
if (ntStatus != NERR_Success) {
    error("NetUserGetInfo failed, ntStatus 0X%x", ntStatus);
    CloseHandle(hToken);
    return FILE_ERR_SYSTEM_ERROR;
}

PROFILEINFOW profile;
memset(&profile, 0, sizeof(PROFILEINFOW));
profile.dwSize = sizeof(PROFILEINFOW);
profile.lpUserName = lpUserName;
profile.lpProfilePath = pUserInfo->usri4_profile;
bRet = LoadUserProfileW(hToken, &profile);
if (!bRet) {
    error("LoadUserProfile failed, gle = %lu", GetLastError());
    CloseHandle(hToken);
    NetApiBufferFree(pUserInfo);
    return FILE_ERR_SYSTEM_ERROR;
}


HRESULT hr;
hr = SHGetFolderPathW(NULL,
              CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE,
              hToken,
              0,
              lpBuffer);
if (FAILED(hr)) {
    error("SHGetFolderPath failed, hr 0X%x", hr);
    NetApiBufferFree(pUserInfo);
    UnloadUserProfile(hToken, profile.hProfile);
    CloseHandle(hToken);
    return FILE_ERR_SYSTEM_ERROR;
}

NetApiBufferFree(pUserInfo);
UnloadUserProfile(hToken, profile.hProfile);
CloseHandle(hToken);
return FILE_ERR_OK;
}
于 2015-12-04T08:06:54.517 に答える
-1

WTSEnumerateSessions()およびを使用しWTSQueryUserToken()て、各ログイン セッションのトークンを取得できます。

も参照してください。これは、サービスが特定のユーザーのキーLoadUserProfile()にアクセスするために必要です。HKEY_CURRENT_USERユーザーは、必要なユーザー トークンを取得するために、対話型またはプログラムによってログインするか、偽装する必要があります。

もう 1 つのオプションは、HKEY_USERSキーを列挙してユーザー アカウントの SID を取得し、それを使用LookupAccountSid()してユーザー名を取得し、OS のバージョンに基づいて AppData パスを手動でフォーマットすることです。柔軟性はありませんが、ユーザー固有のレジストリ データへの依存度は低くなります。

それ以外の場合は、サービスからユーザー固有のフォルダーに書き込むことを忘れてください。CSIDL_COMMON_APPDATAやのように、代わりに一般的な共有フォルダーに書き込みますFOLDERID_ProgramData

于 2013-10-08T16:57:55.230 に答える