I'm writing an add-in for a fujitsu scanner in C#. Documents are scanned to a local directory, and I wanted to copy them to a pc on the network. I keep getting System.IO.IOException: Logon failure: unknown user name or bad password though. I tried copying them to a public directory (at least I think its public), and I still get the same result.
Any ideas for stuff I could try? I don't think my code here is the issue, but here it is anyway.
private bool moveTheFile(String source, String destination)
{
System.DirectoryServices.DirectoryEntry dntry = null;
try
{
//System.IO.File.Move(source, destination);
System.IO.File.Copy(source, destination);
System.IO.File.Delete(source);
if (System.IO.File.Exists(destination))
{
return true;
}
else
{
return false;
}
}
catch (Exception err)
{
_host.WriteSystemLog(LogType.Information, "E1000099", "File.Move Error " + err.ToString());
return false;
}
}
Your problem is due to the fact that the machine is using a LOCAL SERVICE account or something that does not have access even to the shared public folder. You need to impersonate a different account I believe. I found the following code on a different site to do this:
public WindowsImpersonationContext
ImpersonateUser(string sUsername, string sDomain, string sPassword)
{
// initialize tokens
IntPtr pExistingTokenHandle = new IntPtr(0);
IntPtr pDuplicateTokenHandle = new IntPtr(0);
pExistingTokenHandle = IntPtr.Zero;
pDuplicateTokenHandle = IntPtr.Zero;
// if domain name was blank, assume local machine
if (sDomain == "")
sDomain = System.Environment.MachineName;
try
{
string sResult = null;
const int LOGON32_PROVIDER_DEFAULT = 0;
// create token
const int LOGON32_LOGON_INTERACTIVE = 2;
//const int SecurityImpersonation = 2;
// get handle to token
bool bImpersonated = LogonUser(sUsername, sDomain, sPassword,
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
ref pExistingTokenHandle);
// did impersonation fail?
if (false == bImpersonated)
{
int nErrorCode = Marshal.GetLastWin32Error();
sResult = "LogonUser() failed with error code: " +
nErrorCode + "\r\n";
// show the reason why LogonUser failed
MessageBox.Show(this, sResult, "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
// Get identity before impersonation
sResult += "Before impersonation: " +
WindowsIdentity.GetCurrent().Name + "\r\n";
bool bRetVal = DuplicateToken(pExistingTokenHandle,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
ref pDuplicateTokenHandle);
// did DuplicateToken fail?
if (false == bRetVal)
{
int nErrorCode = Marshal.GetLastWin32Error();
// close existing handle
CloseHandle(pExistingTokenHandle);
sResult += "DuplicateToken() failed with error code: "
+ nErrorCode + "\r\n";
// show the reason why DuplicateToken failed
MessageBox.Show(this, sResult, "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return null;
}
else
{
// create new identity using new primary token
WindowsIdentity newId = new WindowsIdentity
(pDuplicateTokenHandle);
WindowsImpersonationContext impersonatedUser =
newId.Impersonate();
// check the identity after impersonation
sResult += "After impersonation: " +
WindowsIdentity.GetCurrent().Name + "\r\n";
MessageBox.Show(this, sResult, "Success",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return impersonatedUser;
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
// close handle(s)
if (pExistingTokenHandle != IntPtr.Zero)
CloseHandle(pExistingTokenHandle);
if (pDuplicateTokenHandle != IntPtr.Zero)
CloseHandle(pDuplicateTokenHandle);
}
}
Here are the supporting methods:
[DllImport("advapi32.dll", SetLastError=true)]
public static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword,
int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
// closes open handes returned by LogonUser
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);
// creates duplicate token handle
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
// group type enum
public enum SECURITY_IMPERSONATION_LEVEL : int
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3
}
Related
I have created a program that can also be ran as a service and it will allow me to debug it as well using the following in the Program.cs startup file.
using System;
using System.Linq;
using System.Windows.Forms;
using System.ServiceProcess;
using System.Reflection;
using System.Threading;
using crs.Includes;
using crs.Service;
using System.IO;
namespace crs
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
//Convert all arguments to lower
args = Array.ConvertAll(args, e => e.ToLower());
//Create the container object for the settings to be stored
Settings.Bag = new SettingsBag();
//Check if we want to run this as a service
bool runAsService = args.Contains("-service");
//Check if debugging
bool debug = Environment.UserInteractive;
//Catch all unhandled exceptions as well
if (!debug || debug)
{
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
if (runAsService)
{
//Create service array
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new CRSService()
};
//Run services in interactive mode if needed
if (debug)
RunInteractive(ServicesToRun);
else
ServiceBase.Run(ServicesToRun);
}
else
{
//Start the main gui
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainGUI());
}
}
#region Functions
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception ex = e.ExceptionObject as Exception;
string stackTrace = ex.Message + "/n";
while (ex.InnerException != null)
{
ex = ex.InnerException;
stackTrace += ex.Message + "/n";
}
stackTrace = stackTrace.Substring(0, stackTrace.Length - 2);
string msg = "UNHANDLED EXCEPTION!/n/n" + stackTrace;
//Write all log messages to a debug log
try
{
string currentDate = DateTime.Now.ToString("yyyy-MM-dd");
string debugFilePath = AppDomain.CurrentDomain.BaseDirectory + #"debugLogs\";
string debugFilename = Application.ProductName + "-debug-" + currentDate + ".log";
if (!Directory.Exists(debugFilePath))
{
//Create the debug log files directory
Directory.CreateDirectory(debugFilePath);
}
if (!File.Exists(debugFilePath + debugFilename))
{
//Create the new file
using (StreamWriter w = File.CreateText(debugFilePath + debugFilename))
{
w.WriteLine("Debug log file for " + Application.ProductName + ".");
w.WriteLine("Created on " + currentDate + ".");
w.WriteLine("");
}
}
//Write the log message to the file
using (StreamWriter w = File.AppendText(debugFilePath + debugFilename))
{
w.WriteLine(DateTime.Now.ToString() + " :: " + msg);
}
}
catch
{ }
}
private static void RunInteractive(ServiceBase[] servicesToRun)
{
Console.WriteLine("Services running in interactive mode.");
Console.WriteLine();
MethodInfo onStartMethod = typeof(ServiceBase).GetMethod("OnStart", BindingFlags.Instance | BindingFlags.NonPublic);
foreach (ServiceBase service in servicesToRun)
{
Console.Write("Starting {0}...", service.ServiceName);
onStartMethod.Invoke(service, new object[] { new string[] { } });
Console.Write("Started");
}
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("Press any key to stop the services and end the process...");
Console.ReadKey();
Console.WriteLine();
MethodInfo onStopMethod = typeof(ServiceBase).GetMethod("OnStop", BindingFlags.Instance | BindingFlags.NonPublic);
foreach (ServiceBase service in servicesToRun)
{
Console.Write("Stopping {0}...", service.ServiceName);
onStopMethod.Invoke(service, null);
Console.WriteLine("Stopped");
}
//Keep the console alive for a second to allow the user to see the message.
Console.WriteLine("All services stopped.");
Thread.Sleep(1000);
}
#endregion
}
}
Everything works as expected except for the line Console.ReadKey(); under the RunInteractive() method. If I was to try and run this service manually in a console window I would have no issues what so ever, it runs great and waits for me to hit enter to start the service stopping process. However, when running it in the IDE it's spitting everything out to the DEBUG window and there is nothing for it to grab a ReadKey on.
How can I go about getting around this when debugging in the IDE? Is it possible to somehow force it to run in a command window when debugging in the IDE?
After some digging around I came up with a new class to suit my needs. Thanks for the post by Pavlo I was able to actually get text to read and write to the new console window I needed to create when one was not present.
My altered RunInteractive function from my original question:
private static void RunInteractive(ServiceBase[] servicesToRun)
{
//Account for running this application without a console window (debugging in IDE)
if (!ConsoleWindow.Exists() && !ConsoleWindow.Create())
return;
Console.WriteLine("Services running in interactive mode.");
Console.WriteLine();
MethodInfo onStartMethod = typeof(ServiceBase).GetMethod("OnStart", BindingFlags.Instance | BindingFlags.NonPublic);
foreach (ServiceBase service in servicesToRun)
{
Console.Write("Starting {0}...", service.ServiceName);
onStartMethod.Invoke(service, new object[] { new string[] { } });
Console.Write("Started");
}
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("Press any key to stop the services and end the process...");
Console.ReadKey();
Console.WriteLine();
MethodInfo onStopMethod = typeof(ServiceBase).GetMethod("OnStop", BindingFlags.Instance | BindingFlags.NonPublic);
foreach (ServiceBase service in servicesToRun)
{
Console.Write("Stopping {0}...", service.ServiceName);
onStopMethod.Invoke(service, null);
Console.WriteLine("Stopped");
}
//Keep the console alive for a second to allow the user to see the message.
Console.WriteLine("All services stopped.");
Thread.Sleep(1000);
}
Note: The only thing that was added here was this little bit at the top of the function.
//Account for running this application without a console window (debugging in IDE)
if (!ConsoleWindow.Exists() && !ConsoleWindow.Create())
return;
My new ConsoleWindow class:
using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace crs.Includes
{
public class ConsoleWindow
{
#region Constants
private const UInt32 GENERIC_WRITE = 0x40000000;
private const UInt32 GENERIC_READ = 0x80000000;
private const UInt32 FILE_SHARE_READ = 0x00000001;
private const UInt32 FILE_SHARE_WRITE = 0x00000002;
private const UInt32 OPEN_EXISTING = 0x00000003;
private const UInt32 FILE_ATTRIBUTE_NORMAL = 0x80;
#endregion
#region WinAPI external functions
[DllImport("kernel32.dll")]
private static extern IntPtr GetConsoleWindow();
[DllImport(
"kernel32.dll",
SetLastError = true
)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FreeConsole();
[DllImport(
"kernel32.dll",
SetLastError = true
)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool AllocConsole();
[DllImport(
"kernel32.dll",
EntryPoint = "CreateFileW",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall
)]
private static extern IntPtr CreateFileW(
string lpFileName,
UInt32 dwDesiredAccess,
UInt32 dwShareMode,
IntPtr lpSecurityAttributes,
UInt32 dwCreationDisposition,
UInt32 dwFlagsAndAttributes,
IntPtr hTemplateFil
);
#endregion
#region Public class methods
public static bool Exists()
{
if (GetConsoleWindow() == IntPtr.Zero)
return false;
else
return true;
}
public static bool Create()
{
try
{
if (!AllocConsole())
throw new Exception("Error! Could not get a lock on a console window and could not create one.");
InitializeOutStream();
InitializeInStream();
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return false;
}
#endregion
#region Functions
private static void InitializeOutStream()
{
FileStream fs = CreateFileStream("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, FileAccess.Write);
if (fs != null)
{
StreamWriter writer = new StreamWriter(fs) { AutoFlush = true };
Console.SetOut(writer);
Console.SetError(writer);
}
}
private static void InitializeInStream()
{
FileStream fs = CreateFileStream("CONIN$", GENERIC_READ, FILE_SHARE_READ, FileAccess.Read);
if (fs != null)
Console.SetIn(new StreamReader(fs));
}
private static FileStream CreateFileStream(string name, uint win32DesiredAccess, uint win32ShareMode, FileAccess dotNetFileAccess)
{
SafeFileHandle file = new SafeFileHandle(CreateFileW(name, win32DesiredAccess, win32ShareMode, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero), true);
if (!file.IsInvalid)
{
FileStream fs = new FileStream(file, dotNetFileAccess);
return fs;
}
return null;
}
#endregion
}
}
Instead of console.write, you can create a log file in which you can log the status of the program. I recommend using the log4net nuget package.
i am trying to run a process but want it to be hidden - so i guess, i want to run it in a different desktop.
public static void LaunchCommand2(string strCommand)
{
// Variables
PROCESS_INFORMATION processInfo = new PROCESS_INFORMATION();
STARTUPINFO startInfo = new STARTUPINFO();
Boolean bResult = false;
IntPtr hToken = IntPtr.Zero;
UInt32 uiResultWait = WAIT_FAILED;
IntPtr desktop = CreateDesktop("temp", IntPtr.Zero, IntPtr.Zero, 0, (long)DESKTOP_ACCESS_MASK.GENERIC_ALL, IntPtr.Zero);
startInfo.lpDesktop = "temp";
try
{
startInfo.cb = Marshal.SizeOf(startInfo);
startInfo.dwFlags = STARTF_USESHOWWINDOW;
startInfo.wShowWindow = 0;
unsafe
{
WTSQueryUserToken(WTSGetActiveConsoleSessionId(),out hToken);
}
bResult = Win32.CreateProcessAsUser(
hToken,
null,
strCommand,
IntPtr.Zero,
IntPtr.Zero,
false,
0,
IntPtr.Zero,
null,
ref startInfo,
out processInfo
);
if (!bResult) { throw new Exception("CreateProcessAsUser error #" + Marshal.GetLastWin32Error()); }
// Wait for process to end
uiResultWait = WaitForSingleObject(processInfo.hProcess, INFINITE);
if (uiResultWait == WAIT_FAILED) { throw new Exception("WaitForSingleObject error #" + Marshal.GetLastWin32Error()); }
}
finally
{
// Close all handles
CloseHandle(hToken);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
}
but it does not work. i dont know if i am setting new desktop to a startInfo correctly. Thanks in advance.
I'm attempting to launch a service using CreateProcessAsUser but for some reason multiple (30+) instances of the EXE are being created when debugging. The processes begin to spawn on this line of code:
ret = CreateProcessAsUser(DupedToken, Path, null, ref sa, ref sa, false, 0, (IntPtr)0, "c:\\", ref si, out pi);
I used code from this example - http://support.microsoft.com/default.aspx?scid=kb;EN-US;889251.
[StructLayout(LayoutKind.Sequential)]
public struct STARTUPINFO
{
public int cb;
public String lpReserved;
public String lpDesktop;
public String lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int Length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
[DllImport("kernel32.dll", EntryPoint = "CloseHandle", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public extern static bool CloseHandle(IntPtr handle);
[DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public extern static bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment,
String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
[DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
public extern static bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType,
int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);
string curFile2 = AppDomain.CurrentDomain.BaseDirectory + "OnStart.txt";
public void createProcessAsUser()
{
IntPtr Token = new IntPtr(0);
IntPtr DupedToken = new IntPtr(0);
bool ret;
//Label2.Text+=WindowsIdentity.GetCurrent().Name.ToString();
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.bInheritHandle = false;
sa.Length = Marshal.SizeOf(sa);
sa.lpSecurityDescriptor = (IntPtr)0;
Token = WindowsIdentity.GetCurrent().Token;
const uint GENERIC_ALL = 0x10000000;
const int SecurityImpersonation = 2;
const int TokenType = 1;
ret = DuplicateTokenEx(Token, GENERIC_ALL, ref sa, SecurityImpersonation, TokenType, ref DupedToken);
if (ret == false)
File.AppendAllText(curFile2, "DuplicateTokenEx failed with " + Marshal.GetLastWin32Error());
else
File.AppendAllText(curFile2, "DuplicateTokenEx SUCCESS");
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = "";
string Path;
Path = #"C:\myEXEpath";
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
ret = CreateProcessAsUser(DupedToken, Path, null, ref sa, ref sa, false, 0, (IntPtr)0, "c:\\", ref si, out pi);
if (ret == false)
File.AppendAllText(curFile2, "CreateProcessAsUser failed with " + Marshal.GetLastWin32Error());
else
{
File.AppendAllText(curFile2, "CreateProcessAsUser SUCCESS. The child PID is" + pi.dwProcessId);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
ret = CloseHandle(DupedToken);
if (ret == false)
File.AppendAllText(curFile2, Marshal.GetLastWin32Error().ToString() );
else
File.AppendAllText(curFile2, "CloseHandle SUCCESS");
}
The steps you outlined above will generate one process per execution of the method createProcessAsUser(). Now this method does not contain any code to terminate or kill the process so repeatidly calling this method will generate more than one process. As your code is displayed the method will inface generate only one process.
I think the real answer is how are you calling this method. As you stated in the comment
I'm trying to launch the .exe in the user session
I can only assume you may be calling this process from the Session start, Application_BeginRequest or another method that may be executed multiple times depending on how your application is designed (the calling code for this method would be great as an edit).
As I stated earlier the exe is being executed every time the method is called and not terminated. If you only ever want one instance of the application running you will have to examine the process tree to identify if the process is already running. Now if you should have one process running per user you will need to do the above but also maintain a reference the process ID that was created the first time the application started.
Review the code below for the changes (simplified)
public void createProcessAsUser()
{
//one process per session
object sessionPID = Session["_servicePID"];
if (sessionPID != null && sessionPID is int && Process.GetProcessById((int)sessionPID) != null)
return; //<-- Return process already running for session
else
Session.Remove("_servicePID");
//one process per application
object applicationPID = Application["_applicationPID"];
if (applicationPID != null && applicationPID is int && Process.GetProcessById((int)applicationPID) != null)
return; //<-- Process running for application
else
Application.Remove("_applicationPID");
//omitted starting code
if (ret == false)
// omitted log failed
else
{
// omitted log started
//for one process per session
Session["_servicePID"] = Convert.ToInt32(pi.dwProcessId);
//for one process per application
Application["_applicationPID"] = Convert.ToInt32(pi.dwProcessId);
//close handles
}
// omitted the rest of the method
}
This simple saves a reference to the Process ID that was created for the application into either the Session state for one process per user or the Application state for one process per application instance.
Now if this is the intended result you may also want to look at Terminating the process either when the application shutdown (gracefully) or the session ends. That would be very similar to our first check but can be done as seen below. *note this doesn't take into account the worker process shutting down without calling the session \ application end events those should be handled as well possibly in the application start.
//session end
void Session_End(object sender, EventArgs e)
{
object sessionPID = Session["_servicePID"];
if (sessionPID != null && sessionPID is int)
{
Process runningProcess = Process.GetProcessById((int)sessionPID);
if (runningProcess != null)
runningProcess.Kill();
}
}
//application end
void Application_End(object sender, EventArgs e)
{
object applicationPID = Application["_applicationPID"];
if (applicationPID != null && applicationPID is int && Process.GetProcessById((int)applicationPID) != null)
{
Process runningProcess = Process.GetProcessById((int)applicationPID);
if (runningProcess != null)
runningProcess.Kill();
}
}
Again, back to the original question how do you stop the multiple instances. The answer is simply stop the ability to spawn multiple instances by examining how you start the instances (I.e. the calling code to the method createProcessAsUser()) and adjust your method accordingly to avoid multiple calls.
Please post an edit if this inst helpful with details on how the createProcessAsUser() method is called.
Update 1:
Session \ Application does not exist in the context. This will happen if the method createProcessUser() is in a different class than an ASPX page (as it is on the tutorial).
Because of this you will need to change for the existance of an HttpContext this can simply done by calling
HttpContext.Currrent
I have adapted the method above to include checks to the HttpContext
public void createProcessAsUser()
{
//find the http context
var ctx = HttpContext.Current;
if (ctx == null)
throw new Exception("No Http Context");
//use the following code for 1 process per user session
object sessionPID = ctx.Session["_servicePID"];
if (sessionPID != null && sessionPID is int && Process.GetProcessById((int)sessionPID) != null)
return; //<-- Return process already running for session
else
ctx.Session.Remove("_servicePID");
//use the following code for 1 process per application instance
object applicationPID = ctx.Application["_applicationPID"];
if (applicationPID != null && applicationPID is int && Process.GetProcessById((int)sessionPID) != null)
return; //<-- Process running for application
else
ctx.Application.Remove("_applicationPID");
// omitted code
if (ret == false)
{
//omitted logging
}
else
{
//omitted logging
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
//for one process per session
ctx.Session["_servicePID"] = Convert.ToInt32(pi.dwProcessId);
//for one process per application
ctx.Application["_applicationPID"] = Convert.ToInt32(pi.dwProcessId);
}
//omitted the rest
}
You will not the changes are in the first few lines where it gets the current HttpContext (you must add using System.Web) by calling var ctx = HttpContext.Current
Next we just check that the ctx variable is not null. If it is null I am throwing an exception, however you can handle this anyway you wish.
From there instead of directly calling Session and Application I have changed the references to ctx.Session... and ctx.Application...
Update 2:
This is a Windows Application calling the method above. Now this changes the ball game as the code above is really meant to start a process as the impersonated windows identity. Now Impersonation is typcially done in WebApplications not WinForms (can be done though).
If you are not impersonating a different user than the user who is running the application. Meaning the user logged in is the user that is running the application. If this is so then your code becomes ALOT easier.
Below is an example of how this can be achieved.
/// <summary>
/// static process ID value
/// </summary>
static int? processID = null;
public void startProcess()
{
//check if the processID has a value and if the process ID is active
if (processID.HasValue && Process.GetProcessById(processID.Value) != null)
return;
//start a new process
var process = new Process();
var processStartInfo = new ProcessStartInfo(#"C:\myProg.exe");
processStartInfo.CreateNoWindow = true;
processStartInfo.UseShellExecute = false;
process.StartInfo = processStartInfo;
process.Start();
//set the process id
processID = process.Id;
}
Again as this is a Win Forms application you can use the Process object to launch a process, this windows application will run as the user running the Windows Forms application. In this example we also hold a static reference to the processID and check the if the processID (if found) is already running.
I have made an application to log all websites visited by current PC user. This is not for a malicious use. I am making this feature for my employee monitoring software which will be licensed under proper laws.
Coming on main point, Whenever I am fetching URL from any browser such as IE. I am only getting its URL for all opened tabs. I am unable to get any tab handle for IE7+ , because of which I am unable to maintain a list of tabs for which I have already logged URL's for same tab.
Below is my code (Take a Look on Commented Code First):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace WebsiteLoggerConsole
{
public class WebLogger
{
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr hwndParent,
IntPtr hwndChildAfter,
string lpszClass,
string lpszWindow);
System.Threading.Timer log;
public void StartLoggin()
{
try
{
TimerCallback logcallback = new TimerCallback(LogTick);
log = new System.Threading.Timer(logcallback, null, 0, 2000);
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(ex.Message);
}
}
public void StopLogging()
{
try
{
log.Dispose();
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(ex.Message);
}
}
public void LogTick(Object stateInfo)
{
CreateLog();
}
void CreateLog()
{
try
{
SHDocVw.ShellWindows shellWindows = new SHDocVw.ShellWindows();
string filename;
foreach (SHDocVw.InternetExplorer ie in shellWindows)
{
filename = Path.GetFileNameWithoutExtension(ie.FullName).ToLower();
if (filename.Equals("iexplore"))
{
int val = ie.HWND;
IntPtr hwnd = new IntPtr(val);
IntPtr uihwnd = GetDirectUIHWND(hwnd);
string ddd = (ie.LocationURL) + " :::: " + (uihwnd.ToString());
Console.WriteLine(ddd);
}
}
//SHDocVw.ShellWindows shellWindows = new SHDocVw.ShellWindows();
//string filename;
//foreach (SHDocVw.InternetExplorer ie in shellWindows)
//{
// filename = Path.GetFileNameWithoutExtension(ie.FullName).ToLower();
// if (filename.Equals("iexplore"))
// {
// int val = ie.HWND;
// IntPtr hwnd = new IntPtr(val);
// IntPtr uihwnd = GetDirectUIHWND(hwnd);
// IntPtr tabhwnd = GetDirectUIHWND(uihwnd);
// string ddd = (ie.LocationURL) + " :::: " + (tabhwnd.ToString());
// Console.WriteLine(ddd);
// }
//}
//Process[] processlist = Process.GetProcesses();
//foreach (Process theprocess in processlist)
//{
// if (theprocess.ProcessName == "iexplore")
// {
// Console.WriteLine("Process: {0}, ID: {1}, Handle: {3}, Window name: {2}",
// theprocess.ProcessName, theprocess.Id, theprocess.MainWindowTitle, theprocess.SessionId.ToString()
// );
// }
//}
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(ex.Message);
}
}
private static IntPtr GetDirectUIHWND(IntPtr ieFrame)
{
// try IE 9 first:
IntPtr intptr = FindWindowEx(ieFrame, IntPtr.Zero, "WorkerW", null);
if (intptr == IntPtr.Zero)
{
// IE8 and IE7
intptr = FindWindowEx(ieFrame, IntPtr.Zero, "CommandBarClass", null);
}
intptr = FindWindowEx(intptr, IntPtr.Zero, "ReBarWindow32", null);
//intptr = FindWindowEx(intptr, IntPtr.Zero, "TabBandClass", null);
//intptr = FindWindowEx(intptr, IntPtr.Zero, "DirectUIHWND", null);
return intptr;
}
}
}
I provided a solution on this topic: How to write a standalone URL logger for Windows?
There I used Java, but you can do the same by using C#. I am almost sure there is a lot of good libpcap wrappers for C#.
There is a project called pcapDotNet and you can use it.
Adjusting one example:
using System;
using System.Collections.Generic;
using PcapDotNet.Core;
using PcapDotNet.Packets;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.Transport;
namespace InterpretingThePackets
{
class Program
{
static void Main(string[] args)
{
// Retrieve the device list from the local machine
IList<LivePacketDevice> allDevices = LivePacketDevice.AllLocalMachine;
if (allDevices.Count == 0)
{
Console.WriteLine("No interfaces found! Make sure WinPcap is installed.");
return;
}
// Print the list
for (int i = 0; i != allDevices.Count; ++i)
{
LivePacketDevice device = allDevices[i];
Console.Write((i + 1) + ". " + device.Name);
if (device.Description != null)
Console.WriteLine(" (" + device.Description + ")");
else
Console.WriteLine(" (No description available)");
}
int deviceIndex = 0;
do
{
Console.WriteLine("Enter the interface number (1-" + allDevices.Count + "):");
string deviceIndexString = Console.ReadLine();
if (!int.TryParse(deviceIndexString, out deviceIndex) ||
deviceIndex < 1 || deviceIndex > allDevices.Count)
{
deviceIndex = 0;
}
} while (deviceIndex == 0);
// Take the selected adapter
PacketDevice selectedDevice = allDevices[deviceIndex - 1];
// Open the device
using (PacketCommunicator communicator =
selectedDevice.Open(65536, // portion of the packet to capture
// 65536 guarantees that the whole packet will be captured on all the link layers
PacketDeviceOpenAttributes.Promiscuous, // promiscuous mode
1000)) // read timeout
{
// Check the link layer. We support only Ethernet for simplicity.
if (communicator.DataLink.Kind != DataLinkKind.Ethernet)
{
Console.WriteLine("This program works only on Ethernet networks.");
return;
}
// Compile the filter
using (BerkeleyPacketFilter filter = communicator.CreateFilter("ip and tcp"))
{
// Set the filter
communicator.SetFilter(filter);
}
Console.WriteLine("Listening on " + selectedDevice.Description + "...");
// start the capture
communicator.ReceivePackets(0, PacketHandler);
}
}
// Callback function invoked by libpcap for every incoming packet
private static void PacketHandler(Packet packet)
{
// print timestamp and length of the packet
Console.WriteLine(packet.Timestamp.ToString("yyyy-MM-dd hh:mm:ss.fff") + " length:" + packet.Length);
IpV4Datagram ip = packet.Ethernet.IpV4;
//Do your magic here using HttpRequestDatagram
}
}
}
Why Register a DLL?
I have a lot of basic doubts on DLLs and i have tried to put them in a listed Questions form as below:
Why do we need to register a DLL?
What happens when we register a DLL?
When i use a "LoadLibrary" in my C# code, i do not do any registration.
Whats the connection/difference between the two?
(Registering a DLL and Loading a DLL)
Can i register all the DLLs? or are there some DLLs which cannot be registered and why?
If anyone can recommend some online articles for clarifying my doubts it would be big help!
otherwise snippet code.
im using this code but it doesnt give exactly what i need, thats why i asked here....
its working fine in 32-bit machine but it gives denied path error in 64 bit machine
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Security;
using System.Management;
using System.IO;
using CCC_DLLRegistar.LoadLibrary;
using System.Security.Principal;
using System.Diagnostics;
namespace CCC_DLLRegistar
{
public partial class Form1 : Form
{
#region Is64BitOperatingSystem (IsWow64Process)
public static bool Is64BitOperatingSystem()
{
if (IntPtr.Size == 8) // 64-bit programs run only on Win64
{
return true;
}
else // 32-bit programs run on both 32-bit and 64-bit Windows
{
// Detect whether the current process is a 32-bit process
// running on a 64-bit system.
bool flag;
return ((DoesWin32MethodExist("kernel32.dll", "IsWow64Process") &&
IsWow64Process(GetCurrentProcess(), out flag)) && flag);
}
}
static bool DoesWin32MethodExist(string moduleName, string methodName)
{
IntPtr moduleHandle = GetModuleHandle(moduleName);
if (moduleHandle == IntPtr.Zero)
{
return false;
}
return (GetProcAddress(moduleHandle, methodName) != IntPtr.Zero);
}
[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentProcess();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
static extern IntPtr GetModuleHandle(string moduleName);
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule,
[MarshalAs(UnmanagedType.LPStr)]string procName);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsWow64Process(IntPtr hProcess, out bool wow64Process);
#endregion
#region Is64BitOperatingSystem (WMI)
public static bool Is64BitOperatingSystem(string machineName,
string domain, string userName, string password)
{
ConnectionOptions options = null;
if (!string.IsNullOrEmpty(userName))
{
options = new ConnectionOptions();
options.Username = userName;
options.Password = password;
options.Authority = "NTLMDOMAIN:" + domain;
}
// Else the connection will use the currently logged-on user
// Make a connection to the target computer.
ManagementScope scope = new ManagementScope("\\\\" +
(string.IsNullOrEmpty(machineName) ? "." : machineName) +
"\\root\\cimv2", options);
scope.Connect();
ObjectQuery query = new ObjectQuery(
"SELECT AddressWidth FROM Win32_Processor");
// Perform the query and get the result.
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection queryCollection = searcher.Get();
foreach (ManagementObject queryObj in queryCollection)
{
if (queryObj["AddressWidth"].ToString() == "64")
{
return true;
}
}
return false;
}
#endregion
public Form1()
{
InitializeComponent();
}
private string _RootPath = string.Empty;
private string _path = string.Empty;
private List<string> _Regfiles;
DLLHelper obj;
public string path
{
get { return _path; }
set { _path = value; }
}
public string RootPath
{
get { return _RootPath; }
set { _RootPath = value; }
}
private void Form1_Load(object sender, EventArgs e)
{
// Solution 1. Is64BitOperatingSystem (IsWow64Process)
// Determine whether the current operating system is a 64 bit
// operating system.
bool f64bitOS = Is64BitOperatingSystem();
//Console.WriteLine("The current operating system {0} 64-bit.",
// f64bitOS ? "is" : "is not");
// Solution 2. Is64BitOperatingSystem (WMI)
// Determine whether the current operating system is a 64 bit
// operating system through WMI. The function is also able to
// query the bitness of OS on a remote machine.
try
{
f64bitOS = Is64BitOperatingSystem(".", null, null, null);
//Console.WriteLine("The current operating system {0} 64-bit.",
// f64bitOS ? "is" : "is not");
if (f64bitOS == true)
{
RootPath = "C:\\windows\\SysWow64\\";
}
else
{
RootPath = "C:\\Windows\\System32\\";
}
bool isAdmin = new WindowsPrincipal(WindowsIdentity.GetCurrent())
.IsInRole(WindowsBuiltInRole.Administrator) ? true : false;
if (isAdmin)
{
MessageBox.Show("you are an administrator");
}
else
{
MessageBox.Show("You are not an administrator");
}
path = Application.StartupPath + "\\CCC DLL\\";
List<string> regsvr = new List<string>();
foreach (string s in Directory.GetFiles(path, "*.*").Select(Path.GetFileName))
{
regsvr.Add(Application.StartupPath + "\\CCC DLL\\" + s);
}
foreach (string filepath in regsvr)
{
Registar_Dlls(filepath);
}
_Regfiles=new List<string>();
foreach (string s in Directory.GetFiles(path, "*.dll").Select(Path.GetFileName))
{
_Regfiles.Add(Application.StartupPath + "\\CCC DLL\\" + s);
if (DLLHelper.UnmanagedDllIs64Bit(Application.StartupPath + "\\CCC DLL\\" + s) == true)
{
MessageBox.Show("62 bit");
}
else
{
MessageBox.Show("32 bit");
}
}
foreach (string s in Directory.GetFiles(path, "*.ocx").Select(Path.GetFileName))
_Regfiles.Add(Application.StartupPath + "\\CCC DLL\\" + s);
foreach (string filepath in _Regfiles)
{
obj = new DLLHelper(filepath);
obj.DumpToFile(RootPath + obj.GetDLLName());
}
MessageBox.Show("Register Colmpleted");
}
catch (Exception ex)
{
//Console.WriteLine("Is64BitOperatingSystem throws the exception: {0}",
// ex.Message);
MessageBox.Show(ex.Message.ToString());
}
}
public void Registar_Dlls(string filePath)
{
try
{
//'/s' : Specifies regsvr32 to run silently and to not display any message boxes.
//string arg_fileinfo = "/s" + " " + "\"" + filePath + "\"";
string arg_fileinfo = RootPath +"\regsvr32.exe"+" "+ "/s" + " " + "\"" + filePath;
Process reg = new Process();
//This file registers .dll files as command components in the registry.
reg.StartInfo.FileName = "cmd.exe"; //"regsvr32.exe";
reg.StartInfo.Arguments = arg_fileinfo;
reg.StartInfo.UseShellExecute = false;
reg.StartInfo.CreateNoWindow = true;
reg.StartInfo.RedirectStandardOutput = true;
if (System.Environment.OSVersion.Version.Major >= 6)
{
reg.StartInfo.Verb = "runas";
}
reg.Start();
reg.WaitForExit();
reg.Close();
// MessageBox.Show("Successfully Registered your Ocx files");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}