I have the following directory structure:
D:\LinkTest
├─Links
│ ├─LinkToTargetDirectory.lnk
│ └─LinkToTargetFile.lnk
└─Targets
├─TargetFile.txt
└─TargetDirectory
└─FileInTargetDirectory.txt
.lnk files are symbolic links.
They show up in Windows Explorer without the .lnk extension, with the respective target's icon, and double-clicking LinkToTargetDirectory shows the contents of D:\LinkTest\Targets\TargetDirectory, and double-clicking LinkToTargetFile opens the file D:\LinkTest\Targets\TargetFile.txt in notepad.
.txt files are text files.
Everything else are directories.
I would like to use the following code taken from this answer to get the path of the file/directory pointed to:
public static class NativeMethods
{
private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
private const uint FILE_READ_EA = 0x0008;
private const uint FILE_FLAG_BACKUP_SEMANTICS = 0x2000000;
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint GetFinalPathNameByHandle(IntPtr hFile, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpszFilePath, uint cchFilePath, uint dwFlags);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CreateFile(
[MarshalAs(UnmanagedType.LPTStr)] string filename,
[MarshalAs(UnmanagedType.U4)] uint access,
[MarshalAs(UnmanagedType.U4)] FileShare share,
IntPtr securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero
[MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
[MarshalAs(UnmanagedType.U4)] uint flagsAndAttributes,
IntPtr templateFile);
public static string GetFinalPathName(string path)
{
var h = CreateFile(path,
FILE_READ_EA,
FileShare.ReadWrite | FileShare.Delete,
IntPtr.Zero,
FileMode.Open,
FILE_FLAG_BACKUP_SEMANTICS,
IntPtr.Zero);
if (h == INVALID_HANDLE_VALUE)
throw new Win32Exception();
try
{
var sb = new StringBuilder(1024);
var res = GetFinalPathNameByHandle(h, sb, 1024, 0);
if (res == 0)
throw new Win32Exception();
return sb.ToString();
}
finally
{
CloseHandle(h);
}
}
}
What should happen:
Console.WriteLine(NativeMethods.GetFinalPathName(#"D:\LinkTest\Links\LinkToTargetDirectory.lnk"));
should print \\?\D:\LinkTest\Targets\TargetDirectory
Console.WriteLine(NativeMethods.GetFinalPathName(#"D:\LinkTest\Links\LinkToTargetFile.lnk"));
should print \\?\D:\LinkTest\Targets\TargetFile.txt
What actually happens:
Console.WriteLine(NativeMethods.GetFinalPathName(#"D:\LinkTest\Links\LinkToTargetDirectory.lnk"));
prints \\?\D:\LinkTest\Links\LinkToTargetDirectory.lnk
Console.WriteLine(NativeMethods.GetFinalPathName(#"D:\LinkTest\Links\LinkToTargetFile.lnk"));
prints \\?\D:\LinkTest\Links\LinkToTargetFile.lnk
So instead of getting the target's path, it just returns the path of the link file.
What is wrong with this code and how can I fix it?
I already found this: https://social.msdn.microsoft.com/forums/windowsdesktop/en-US/d8a26a7f-6661-48ce-b183-8e476dfffecd/am-i-using-getfinalpathnamebyhandle-incorrectly?forum=windowsgeneraldevelopmentissues
Passing 8 instead of 0 as the last argument to GetFinalPathNameByHandle seems to help that user, but it does not change the behavior for me.
I'm trying to configure a device's TCP/IP settings via registries but i can't seem to get it to work without a soft reboot.
I've been scouring Google for an answer and found that the way to do it is to pinvoke DeviceIoControl().
I've looked at the registries and they are definitely changing to the ones i want, I can't get DeviceIoControl() to return anything except 0 (fail) and I'm not sure what I'm doing wrong.
[DllImport("coredll.dll", EntryPoint = "CreateFile", SetLastError = true)]
private static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFLagsAndAttributes, IntPtr hTemplateFile);
[DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
private static extern int DeviceIoControl(IntPtr hDevice, uint dwIoControlCode, ref string lpInBuffer, int nInBufferSize, out string lpOutBuffer, int nOutBufferSize, ref int lpBytesReturned, IntPtr lpOverlapped);
[DllImport("coredll.dll", EntryPoint = "CloseHandle", SetLastError = true)]
private static extern bool CloseHandle(IntPtr hObject);
public static void SetTCPIP()
{
RegistryKey baseKey = Registry.LocalMachine;
string subKey = #"Comm\FEC1\Parms\TcpIp";
string enableDhcpKey = "EnableDHCP";
string gatewayKey = "DefaultGateway";
string ipAddressKey = "IpAddress";
string subnetMaskKey = "Subnetmask";
string ipAddress = "192.168.8.100";
string subnetMask = "255.255.255.0";
string gateway = "192.168.8.1";
WriteReg(baseKey, subKey, enableDhcpKey, 0);
WriteRegMultiString(baseKey, subKey, ipAddressKey, ipAddress);
WriteRegMultiString(baseKey, subKey, gatewayKey, gateway);
WriteRegMultiString(baseKey, subKey, subnetMaskKey, subnetMask);
CommitLocalMachineRegistry(); //RegFlushKey()
BindAdapter();
}
private static void BindAdapter()
{
const uint genericRead = 0x80000000;
const uint genericWrite = 0x40000000;
const int IOCTL_NDIS_REBIND_ADAPTER = 0x17002E;
const int OPEN_EXISTING = 3;
const string NI = #"NDS0:";
//Open the Handle to Rebind the Network Adapter
IntPtr hNdis = CreateFile(NI, genericRead | genericWrite, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
if (hNdis == IntPtr.Zero)
{
Debug.WriteLine("!!!!!!!!!!!!!!!!!"+hNdis);
}
string Adapter = "FEC1\0";
string OutBuffer = "";
int bytesReturned = 0;
//Rebind the Network Adapter
int check = DeviceIoControl(hNdis, IOCTL_NDIS_REBIND_ADAPTER, ref Adapter, Adapter.Length,
out OutBuffer, 0, ref bytesReturned, IntPtr.Zero);
if (check==0)
{
Debug.WriteLine("!!!!!!!!!!!!!!!!!!");
Debug.WriteLine(Marshal.GetLastWin32Error());
}
//Close the Handle
CloseHandle(hNdis);
}
I've tried getting more info on the issue using GetLastWin32Error() but it's returning 0 as well
Edit (couldn't add comment)
i've tried having Adapter = "FEC1\0\0" and I've also tried marshalling as a StringBuilder with no luck
Edit 2
Registries are HIVE based, so changes persist after a reboot.
I have created website project, and am using IIS version 6 as the web server when developing. When I try to debug this method (createfile) bellow in order to read from USB .
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);
const uint OPEN_EXISTING = 3;
const uint GENERIC_WRITE = (0x40000000);
const uint FSCTL_LOCK_VOLUME = 0x00090018;
const uint FSCTL_UNLOCK_VOLUME = 0x0009001c;
const uint FSCTL_DISMOUNT_VOLUME = 0x00090020;
bool success = false;
int intOut;
string deviceId = #"\\.\H:";
long DiskSize = 2056320000;
SafeFileHandle diskHandle = CreateFile(deviceId, GENERIC_WRITE, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
if (diskHandle.IsInvalid)
{
//Console.WriteLine(deviceId + " open error.");
Debug.WriteLine(Marshal.GetLastWin32Error());
return 0;
}
I get this error num (5=access denied), but it works fine in other types of projects like (windows forms , console application , asp project ).
How can this be solved?
thank you in advance
the solution has been found, we just need to give permissions to the application pool by changing the identity property to (Local system)
I need to obtain disk geometry info, but something wrong and DeviceIoControl returning false. Any ideas how to fix it? Or Other examples using C# and kernel32 appreciated.
[DllImport("kernel32.dll")]
public static extern IntPtr CreateFile(
string lpFileName, int dwDesiredAccess, int dwShareMode,
IntPtr lpSecurityAttributes, int dwCreationDisposition,
int dwFlagsAndAttributes, IntPtr hTemplateFile);
private const int FILE_SHARE_READ = 1;
private const int OPEN_ALWAYS = 4;
private const int INVALID_HANDLE_VALUE = -1;
[DllImport("kernel32.dll", ExactSpelling = true)]
internal static extern bool DeviceIoControl(
IntPtr hDevice, int dwIoControlCode, IntPtr lpInBuffer, int nInBufferSize,
IntPtr lpOutBuffer, int nOutBufferSize, ref int lpBytesReturned, IntPtr lpOverlapped);
private const int IOCTL_DISK_GET_MEDIA_TYPES = 0x00070c00;
static void Main(string[] args)
{
IntPtr hflp = CreateFile(#""\\.\C:", 0, FILE_SHARE_READ, IntPtr.Zero, OPEN_ALWAYS, 0, IntPtr.Zero);
if ((int)hflp == INVALID_HANDLE_VALUE)
{ Console.WriteLine("CreateFile failed"); return; }
Type ts = typeof(DISK_GEOMETRY);
int ss = Marshal.SizeOf(ts);
int ssa = ss * 20;
IntPtr mptr = Marshal.AllocHGlobal(ssa);
int byret = 0;
bool ok = DeviceIoControl(hflp, IOCTL_DISK_GET_MEDIA_TYPES, IntPtr.Zero, 0,
mptr, ssa, ref byret, IntPtr.Zero);
if (!ok)
{ Console.WriteLine("DeviceIoControl failed"); return; }
int count = byret / ss;
int run = (int)mptr;
DISK_GEOMETRY gem;
for (int i = 0; i < count; i++)
{
gem = (DISK_GEOMETRY)Marshal.PtrToStructure((IntPtr)run, ts);
Console.WriteLine("MediaType={0} SectorsPerTrack={1}", gem.MediaType, gem.SectorsPerTrack);
run += ss;
}
Marshal.FreeHGlobal(mptr);
}
P.S I've already read msdn help on this.
IOCTL_DISK_GET_MEDIA_TYPES appears to be legacy and no longer supported. At least that's the case on my OS (Win7 x64). Attempting to call DeviceIoControl with IOCTL_DISK_GET_MEDIA_TYPES results in error code 1, ERROR_INVALID_FUNCTION.
I believe that you will need to use IOCTL_STORAGE_GET_MEDIA_TYPES_EX instead.
My advice in this situation is to attempt to call the API functions from C++ first. That way you don't have to struggle with p/invoke and you know that all the structures and function prototypes are correct. Once you have worked out how to call the particular API function then translate into p/invoke.
As an aside, you should be a little more careful about your p/invokes. Take care to use uint to match DWORD, and make sure you use SetLastError=true so that you can query the error code with Marshal.GetLastWin32Error().
Something like this:
[DllImport("kernel32.dll", SetLastError=true)]
public static extern IntPtr CreateFile(
string lpFileName, uint dwDesiredAccess, uint dwShareMode,
IntPtr lpSecurityAttributes, uint dwCreationDisposition,
uint dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError=true)]
internal static extern bool DeviceIoControl(
IntPtr hDevice, uint dwIoControlCode, IntPtr lpInBuffer,
uint nInBufferSize, IntPtr lpOutBuffer, uint nOutBufferSize,
ref uint lpBytesReturned, IntPtr lpOverlapped);
I am trying to start another process with Process.Start running under different credentials with the UAC turned on. I get the following error:
System.ComponentModel.Win32Exception:
Logon failure: user account
restriction. Possible reasons are
blank passwords not allowed, logon
hour restrictions, or a policy
restriction has been enforced at
System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo
startInfo) at
System.Diagnostics.Process.Start()
at
System.Diagnostics.Process.Start(ProcessStartInfo
startInfo)
If I turn off UAC, it works fine. If I start the process without specifying username and password, it works fine. Below is a copy of the code:
ProcessStartInfo processInfo = new ProcessStartInfo();
processInfo.Verb = "runas";
processInfo.FileName = command;
processInfo.Arguments = parameters;
processInfo.UserName = txtUserName.Text;
processInfo.Password = password;
processInfo.Domain = "myDomain";
processInfo.UseShellExecute = false;
processInfo.LoadUserProfile = true;
Process.Start(processInfo);
I believe this has something to do with the desktop session, but am not sure why it works when UAC is off.
Any ideas on how to get this to work without turning off UAC, modifying the registry, or changing local/group policies would greatly be appreciated.
Thanks
EDIT
The Process that has the code above is started as an admin:
static void Main(string[] args)
{
//make sure we are running with admin privileges
if (VerifyIsAdmin())
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyApp(args));
}
}
private static bool VerifyIsAdmin()
{
WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
bool isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator);
if (!isAdmin)
{
ProcessStartInfo processInfo = new ProcessStartInfo();
processInfo.Verb = "runas";
processInfo.FileName = Application.ExecutablePath;
Process.Start(processInfo);
}
return isAdmin;
}
EDIT
Tried CreateProcessWithLogonW ... Had same problem.
After further searching, looks like it is a problem with the Group Policy requiring smart card logon (scforceoption). That being said, I still don't understand why it works when UAC is off. It should still require smart card on logon.
It doesn't look like I am going to be able to get around this. Any insight/advice would be appreciated.
You have to do following things:
1. Get who is logged in and in this user has an active desktop
2. Get process' handle started by this user
3. "Steal" credentials from this process
4. Start process with those credentials
Following code should do the trick:
using System;
using System.Text;
using System.Security;
using System.Management;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Win32
{
public class Win32API
{
#region WMI Constants
private const String cstrScope = "root\\CIMV2";
private const String cstrLoggenInUser = "SELECT * FROM Win32_ComputerSystem";
#endregion
#region Win32 API routines
[StructLayout(LayoutKind.Sequential)]
struct SECURITY_ATTRIBUTES
{
public Int32 Length;
public IntPtr lpSecurityDescriptor;
public Boolean bInheritHandle;
}
enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation = 2
}
enum TOKEN_INFORMATION_CLASS
{
TokenUser = 1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId,
TokenGroupsAndPrivileges,
TokenSessionReference,
TokenSandBoxInert,
TokenAuditPolicy,
TokenOrigin,
MaxTokenInfoClass // MaxTokenInfoClass should always be the last enum
}
[StructLayout(LayoutKind.Sequential)]
struct STARTUPINFO
{
public Int32 cb;
public String lpReserved;
public String lpDesktop;
public String lpTitle;
public UInt32 dwX;
public UInt32 dwY;
public UInt32 dwXSize;
public UInt32 dwYSize;
public UInt32 dwXCountChars;
public UInt32 dwYCountChars;
public UInt32 dwFillAttribute;
public UInt32 dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public UInt32 dwProcessId;
public UInt32 dwThreadId;
}
enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3,
}
[StructLayout(LayoutKind.Sequential)]
struct LUID
{
public Int32 LowPart;
public Int32 HighPart;
}
[StructLayout(LayoutKind.Sequential)]
struct LUID_AND_ATRIBUTES
{
LUID Luid;
Int32 Attributes;
}
[StructLayout(LayoutKind.Sequential)]
struct TOKEN_PRIVILEGES
{
public Int32 PrivilegeCount;
//LUID_AND_ATRIBUTES
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public Int32[] Privileges;
}
const Int32 READ_CONTROL = 0x00020000;
const Int32 STANDARD_RIGHTS_REQUIRED = 0x000F0000;
const Int32 STANDARD_RIGHTS_READ = READ_CONTROL;
const Int32 STANDARD_RIGHTS_WRITE = READ_CONTROL;
const Int32 STANDARD_RIGHTS_EXECUTE = READ_CONTROL;
const Int32 STANDARD_RIGHTS_ALL = 0x001F0000;
const Int32 SPECIFIC_RIGHTS_ALL = 0x0000FFFF;
const Int32 TOKEN_ASSIGN_PRIMARY = 0x0001;
const Int32 TOKEN_DUPLICATE = 0x0002;
const Int32 TOKEN_IMPERSONATE = 0x0004;
const Int32 TOKEN_QUERY = 0x0008;
const Int32 TOKEN_QUERY_SOURCE = 0x0010;
const Int32 TOKEN_ADJUST_PRIVILEGES = 0x0020;
const Int32 TOKEN_ADJUST_GROUPS = 0x0040;
const Int32 TOKEN_ADJUST_DEFAULT = 0x0080;
const Int32 TOKEN_ADJUST_SESSIONID = 0x0100;
const Int32 TOKEN_ALL_ACCESS_P = (
STANDARD_RIGHTS_REQUIRED |
TOKEN_ASSIGN_PRIMARY |
TOKEN_DUPLICATE |
TOKEN_IMPERSONATE |
TOKEN_QUERY |
TOKEN_QUERY_SOURCE |
TOKEN_ADJUST_PRIVILEGES |
TOKEN_ADJUST_GROUPS |
TOKEN_ADJUST_DEFAULT);
const Int32 TOKEN_ALL_ACCESS = TOKEN_ALL_ACCESS_P | TOKEN_ADJUST_SESSIONID;
const Int32 TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY;
const Int32 TOKEN_WRITE = STANDARD_RIGHTS_WRITE |
TOKEN_ADJUST_PRIVILEGES |
TOKEN_ADJUST_GROUPS |
TOKEN_ADJUST_DEFAULT;
const Int32 TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE;
const UInt32 MAXIMUM_ALLOWED = 0x2000000;
const Int32 CREATE_NEW_PROCESS_GROUP = 0x00000200;
const Int32 CREATE_UNICODE_ENVIRONMENT = 0x00000400;
const Int32 IDLE_PRIORITY_CLASS = 0x40;
const Int32 NORMAL_PRIORITY_CLASS = 0x20;
const Int32 HIGH_PRIORITY_CLASS = 0x80;
const Int32 REALTIME_PRIORITY_CLASS = 0x100;
const Int32 CREATE_NEW_CONSOLE = 0x00000010;
const string SE_DEBUG_NAME = "SeDebugPrivilege";
const string SE_RESTORE_NAME = "SeRestorePrivilege";
const string SE_BACKUP_NAME = "SeBackupPrivilege";
const Int32 SE_PRIVILEGE_ENABLED = 0x0002;
const Int32 ERROR_NOT_ALL_ASSIGNED = 1300;
[StructLayout(LayoutKind.Sequential)]
struct PROCESSENTRY32
{
UInt32 dwSize;
UInt32 cntUsage;
UInt32 th32ProcessID;
IntPtr th32DefaultHeapID;
UInt32 th32ModuleID;
UInt32 cntThreads;
UInt32 th32ParentProcessID;
Int32 pcPriClassBase;
UInt32 dwFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
string szExeFile;
}
const UInt32 TH32CS_SNAPPROCESS = 0x00000002;
const Int32 INVALID_HANDLE_VALUE = -1;
[DllImport("kernel32.dll", SetLastError = true)]
static extern Boolean CloseHandle(IntPtr hSnapshot);
[DllImport("kernel32.dll")]
public static extern UInt32 WTSGetActiveConsoleSessionId();
[DllImport("Wtsapi32.dll")]
static extern UInt32 WTSQueryUserToken(UInt32 SessionId, ref IntPtr phToken);
[DllImport("advapi32.dll", SetLastError = true)]
static extern Boolean LookupPrivilegeValue(IntPtr lpSystemName, string lpname, [MarshalAs(UnmanagedType.Struct)] ref LUID lpLuid);
[DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
extern static Boolean CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes, Boolean bInheritHandle, Int32 dwCreationFlags, IntPtr lpEnvironment,
String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
[DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
extern static Boolean DuplicateTokenEx(IntPtr ExistingTokenHandle, UInt32 dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes, Int32 TokenType,
Int32 ImpersonationLevel, ref IntPtr DuplicateTokenHandle);
[DllImport("kernel32.dll")]
static extern IntPtr OpenProcess(UInt32 dwDesiredAccess, Boolean bInheritHandle, UInt32 dwProcessId);
[DllImport("advapi32", SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
static extern Boolean OpenProcessToken(IntPtr ProcessHandle, // handle to process
Int32 DesiredAccess, // desired access to process
ref IntPtr TokenHandle); // handle to open access token
[DllImport("advapi32.dll", SetLastError = true)]
static extern Boolean AdjustTokenPrivileges(IntPtr TokenHandle, Boolean DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, Int32 BufferLength, IntPtr PreviousState, IntPtr ReturnLength);
[DllImport("advapi32.dll", SetLastError = true)]
static extern Boolean SetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, ref UInt32 TokenInformation, UInt32 TokenInformationLength);
[DllImport("userenv.dll", SetLastError = true)]
static extern Boolean CreateEnvironmentBlock(ref IntPtr lpEnvironment, IntPtr hToken, Boolean bInherit);
#endregion
#region Methods
/// <summary>
/// Method returns name of the user that logged in on workstation
/// </summary>
public static String GetLoggedInUserName()
{
String userName = String.Empty;
try
{
ManagementObjectSearcher searcher =
new ManagementObjectSearcher(cstrScope, cstrLoggenInUser);
foreach (ManagementObject queryObj in searcher.Get())
{
userName = queryObj["UserName"].ToString();
break;
}
}
catch
{
userName = String.Empty;
}
return userName;
}
/// <summary>
/// Creates the process in the interactive desktop with credentials of the logged in user.
/// </summary>
public static Boolean CreateProcessAsUser(String commandLine,
String workingDirectory,
String userAppName,
out StringBuilder output)
{
Boolean processStarted = false;
output = new StringBuilder();
try
{
UInt32 dwSessionId = WTSGetActiveConsoleSessionId();
output.AppendLine(String.Format("Active console session Id: {0}", dwSessionId));
IntPtr hUserToken = IntPtr.Zero;
WTSQueryUserToken(dwSessionId, ref hUserToken);
if (hUserToken != IntPtr.Zero)
{
output.AppendLine(String.Format("WTSQueryUserToken() OK (hUserToken:{0})", hUserToken));
Process[] processes = Process.GetProcessesByName(userAppName);
if (processes.Length == 0)
{
output.AppendLine(String.Format("Application '{0}' can not be found in the running processes", userAppName));
return false;
}
Int32 userAppProcessId = -1;
for (Int32 k = 0; k < processes.Length; k++)
{
output.AppendLine(String.Format("Process: '{0}', PID: {1}, Handle: {2}, Session: {3}",
processes[k].ProcessName, processes[k].Id, processes[k].Handle, processes[k].SessionId));
if ((UInt32)processes[k].SessionId == dwSessionId)
{
userAppProcessId = processes[k].Id;
}
}
if (userAppProcessId == -1)
{
output.AppendLine(String.Format("Application '{0}' is not found in the processes of the current session", userAppName));
return false;
}
IntPtr hProcess = OpenProcess((Int32)MAXIMUM_ALLOWED, false, (UInt32)userAppProcessId);
IntPtr hPToken = IntPtr.Zero;
OpenProcessToken(hProcess,
TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
| TOKEN_DUPLICATE
| TOKEN_ASSIGN_PRIMARY
| TOKEN_ADJUST_SESSIONID
| TOKEN_READ
| TOKEN_WRITE,
ref hPToken);
if (hPToken != IntPtr.Zero)
{
output.AppendLine(String.Format("OpenProcessToken() OK (Token: {0})", hPToken));
LUID luid = new LUID();
if (LookupPrivilegeValue(IntPtr.Zero, SE_DEBUG_NAME, ref luid))
{
output.AppendLine(String.Format("LookupPrivilegeValue() OK (High: {0}, Low: {1})", luid.HighPart, luid.LowPart));
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.Length = Marshal.SizeOf(sa);
IntPtr hUserTokenDup = IntPtr.Zero;
DuplicateTokenEx(hPToken,
(Int32)MAXIMUM_ALLOWED,
ref sa,
(Int32)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
(Int32)TOKEN_TYPE.TokenPrimary,
ref hUserTokenDup);
if (hUserTokenDup != IntPtr.Zero)
{
output.AppendLine(String.Format("DuplicateTokenEx() OK (hToken: {0})", hUserTokenDup));
TOKEN_PRIVILEGES tp = new TOKEN_PRIVILEGES
{
PrivilegeCount = 1,
Privileges = new Int32[3]
};
tp.Privileges[1] = luid.HighPart;
tp.Privileges[0] = luid.LowPart;
tp.Privileges[2] = SE_PRIVILEGE_ENABLED;
//Adjust Token privilege
if (SetTokenInformation(hUserTokenDup,
TOKEN_INFORMATION_CLASS.TokenSessionId,
ref dwSessionId,
(UInt32)IntPtr.Size))
{
output.AppendLine(String.Format("SetTokenInformation() OK"));
if (AdjustTokenPrivileges(hUserTokenDup,
false, ref tp, Marshal.SizeOf(tp),
IntPtr.Zero, IntPtr.Zero))
{
output.AppendLine("AdjustTokenPrivileges() OK");
Int32 dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
IntPtr pEnv = IntPtr.Zero;
if (CreateEnvironmentBlock(ref pEnv, hUserTokenDup, true))
{
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
}
else
{
output.AppendLine(String.Format("CreateEnvironmentBlock() FAILED (Last Error: {0})", Marshal.GetLastWin32Error()));
pEnv = IntPtr.Zero;
}
// Launch the process in the client's logon session.
PROCESS_INFORMATION pi;
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = "winsta0\\default";
output.AppendLine(String.Format("CreateProcess (Path:{0}, CurrDir:{1})", commandLine, workingDirectory));
if (CreateProcessAsUser(hUserTokenDup, // client's access token
null, // file to execute
commandLine, // command line
ref sa, // pointer to process SECURITY_ATTRIBUTES
ref sa, // pointer to thread SECURITY_ATTRIBUTES
false, // handles are not inheritable
dwCreationFlags, // creation flags
pEnv, // pointer to new environment block
workingDirectory, // name of current directory
ref si, // pointer to STARTUPINFO structure
out pi // receives information about new process
))
{
processStarted = true;
output.AppendLine(String.Format("CreateProcessAsUser() OK (PID: {0})", pi.dwProcessId));
}
else
{
output.AppendLine(String.Format("CreateProcessAsUser() failed (Last Error: {0})", Marshal.GetLastWin32Error()));
}
}
else
{
output.AppendLine(String.Format("AdjustTokenPrivileges() failed (Last Error: {0})", Marshal.GetLastWin32Error()));
}
}
else
{
output.AppendLine(String.Format("SetTokenInformation() failed (Last Error: {0})", Marshal.GetLastWin32Error()));
}
CloseHandle(hUserTokenDup);
}
else
{
output.AppendLine(String.Format("DuplicateTokenEx() failed (Last Error: {0})", Marshal.GetLastWin32Error()));
}
}
else
{
output.AppendLine(String.Format("LookupPrivilegeValue() failed (Last Error: {0})", Marshal.GetLastWin32Error()));
}
CloseHandle(hPToken);
}
else
{
output.AppendLine(String.Format("OpenProcessToken() failed (Last Error: {0})", Marshal.GetLastWin32Error()));
}
CloseHandle(hUserToken);
}
else
{
output.AppendLine(String.Format("WTSQueryUserToken failed: {0}", Marshal.GetLastWin32Error()));
}
}
catch (Exception ex)
{
output.AppendLine("Exception occurred: " + ex.Message);
}
return processStarted;
}
#endregion
}
}
Usage:
try
{
StringBuilder output = new StringBuilder();
if (!Win32API.CreateProcessAsUser("C:\\WINDOWS\\notepad.exe", "C:\\WINDOWS\\", "winlogon", out output))
throw new Win32Exception(output.ToString());
else
throw new Win32Exception("Process RUN!!!");
}
catch (Win32Exception ex)
{
File.WriteAllText("c:\\hello!.txt", ex.Message + " " + ex.ErrorCode.ToString());
}
Credits for the code goes to Forcas from rsdn.ru
I found some old project where I used code below and it worked at the time (looks similar to yours), maybe it won't help but still it's worth a try :
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.UseShellExecute = true;
startInfo.WorkingDirectory = Environment.CurrentDirectory;
startInfo.FileName = Application.ExecutablePath;
startInfo.Verb = "runas";
try
{
Process p = Process.Start(startInfo);
}
catch(System.ComponentModel.Win32Exception ex)
{
return;
}
It looks like you aren't alone with this issue, and it may not be possible as you are trying to do:
http://www.icodefactory.com/lab/post/UAC-Revealed-7e-elevation-of-rights-from-NET-as-commonly-misunderstood.aspx
It's just a guess, but maybe you can request admin privileges and then impersonate the user and then finally then start the process while impersonating?
Edit: You can also try PInvoke which based on a comment on this page is working for starting a process under a different user:
http://blogs.msdn.com/thottams/archive/2006/08/11/696013.aspx
Try adding manifest file for that other process that you want to start.
Windows will analyze manifest file and present you with UAC dialog before process start.
Here is the info how to embed manifest file link1 and link2
HTH