2010-05-21 15 views
3

Je tente d'utiliser Redmon http://www.winimage.com/misc/redmon/ pour envoyer des tâches d'impression vers une application C# personnalisée. Redmon "s'exécute" (en fait le spouleur d'impression) en tant que SYSTEM mais a une option à exécuter en tant qu'utilisateur pour permettre à votre application de s'exécuter sous l'utilisateur qui a imprimé le travail. Le problème est qu'il ne semble pas charger l'environnement de l'utilisateur. Ainsi, appeler des fonctions comme Path.GetTempPath() pointe vers \ windows \ temp au lieu de celui de l'utilisateur. Également lors de la tentative d'exécution d'Outlook 2007+ via des appels MAPI (pour ajouter des pièces jointes), il signale des erreurs de formulaire en raison, je pense, de l'emplacement du dossier temporaire.Redmon's Run As User ne charge pas les variables d'environnement de l'utilisateur

Existe-t-il un moyen de "recharger" un profil ou d'au moins obtenir des variables d'environnement dans l'application Impersonated? Les seules idées que j'ai eues jusqu'ici sont de reconstruire les vars directement à partir du registre, mais je veux éviter cela puisque c'est un bidouillage (en évitant les détails d'implémentation et tout ça). Ou créer un programme de remplacement que Redmon appelle, puis exécuter correctement en tant qu'utilisateur avec le profil complet de l'application personnalisée.

D'autres articles ou astuces?

Répondre

7

J'ai fini par trouver un moyen de charger le EnvironmentBlock de l'utilisateur, extraire chaque variable et les charger dans mon environnement existant. Basé sur le code et les idées de plusieurs pages:

Excuse mon code C#, tout tweaks apprécié:

[DllImport("userenv.dll", SetLastError = true)] 
private static extern bool CreateEnvironmentBlock(ref IntPtr lpEnvironment, IntPtr hToken, bool bInherit); 

[DllImport("advapi32.dll", SetLastError = true)] 
private static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, ref IntPtr TokenHandle); 
private const uint TOKEN_QUERY = 0x0008; 

[DllImport("kernel32.dll")] 
static extern IntPtr GetCurrentProcess(); 

[DllImport("kernel32.dll", SetLastError = true)] 
private static extern bool CloseHandle(IntPtr hObject); 

private static void ReloadEnviroVars() 
{ 
    IntPtr hToken = IntPtr.Zero; 
    IntPtr envBlock = IntPtr.Zero; 

    //Load this user's environment variables 
    OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, ref hToken); 
    bool retVal = CreateEnvironmentBlock(ref envBlock, hToken, false); 

    //Extract each environment variable from the envroblock and add it to 
    // our running program's environment vars 
    int offset = 0; 
    while (true) { 
    //EnviroBlock is an array of null-terminated unicode strings 
    IntPtr ptr = new IntPtr(envBlock.ToInt64() + offset); 
    string Enviro = Marshal.PtrToStringUni(ptr); 
    offset += Encoding.Unicode.GetByteCount(Enviro) + 2; 
    if (string.IsNullOrEmpty(Enviro)) 
     break; 
    string EnviroKey = Enviro.Substring(0, Enviro.IndexOf("=")); 
    string EnviroValue = Enviro.Substring(Enviro.IndexOf("=") + 1, Enviro.Length - 1 - Enviro.IndexOf("=")); 
    Environment.SetEnvironmentVariable(EnviroKey, EnviroValue); 
    } 

    CloseHandle(hToken); 
} 
+0

code mis à jour à utiliser ToInt64 au lieu de ToInt32 pour les systèmes 64 bits (avec plus de 4gig ram?). http://stackoverflow.com/a/1866268 signale qu'il utiliserait simplement plus de frais généraux sur les systèmes 32 bits mais fonctionnerait. – Halfdone