I'm very new to c# and I want to do a code that will logoff all users that logged to the pc.
I tried to do this:
System.Diagnostics.Process("shutdown", "/l");
But this didn't logged off all the users, this logged off only the user that I was running from it.
So how can I do this?
Use the WTSDisconnectSession() Windows API. See article here.
using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
class Program
{
[DllImport("wtsapi32.dll", SetLastError = true)]
static extern bool WTSDisconnectSession(IntPtr hServer, int sessionId, bool bWait);
const int WTS_CURRENT_SESSION = -1;
static readonly IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
static void Main(string[] args)
{
if (!WTSDisconnectSession(WTS_CURRENT_SERVER_HANDLE,
WTS_CURRENT_SESSION, false))
throw new Win32Exception();
}
}
Related
Why is SetThreadAffinityMask ignored?
I'm trying to write a program that sets the Affinity of each process thread according to the value of IdealProcessor.
But SetThreadAffinityMask is ignored.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace ThreadAffinity
{
class Program
{
[DllImport("kernel32.dll")]
static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
[DllImport("kernel32.dll")]
static extern bool SetThreadAffinityMask(IntPtr hThread, IntPtr dwThreadAffinityMask);
[DllImport("kernel32.dll")]
static extern bool GetThreadIdealProcessorEx(IntPtr hThread, ref PROCESSOR_NUMBER lpIdealProcessor);
[DllImport("kernel32.dll")]
static extern bool CloseHandle(IntPtr hObject);
[StructLayout(LayoutKind.Sequential)]
public struct PROCESSOR_NUMBER
{
public ushort Group;
public byte Number;
public byte Reserved;
}
[Flags]
public enum ThreadAccess : int
{
TERMINATE = (0x0001),
SUSPEND_RESUME = (0x0002),
GET_CONTEXT = (0x0008),
SET_CONTEXT = (0x0010),
SET_INFORMATION = (0x0020),
QUERY_INFORMATION = (0x0040),
SET_THREAD_TOKEN = (0x0080),
IMPERSONATE = (0x0100),
DIRECT_IMPERSONATION = (0x0200),
THREAD_ALL_ACCESS = (0x1F03FF)
}
static void Main(string[] args)
{
Console.WriteLine("Enter process id:");
int processId = Convert.ToInt32(Console.ReadLine());
Process process = Process.GetProcessById(processId);
foreach (ProcessThread thread in process.Threads)
{
IntPtr hThread = OpenThread(ThreadAccess.QUERY_INFORMATION, false, (uint)thread.Id);
PROCESSOR_NUMBER processorNumber = new PROCESSOR_NUMBER();
GetThreadIdealProcessorEx(hThread, ref processorNumber);
Console.WriteLine("Thread {0} ideal processor is {1}", thread.Id, processorNumber.Number);
SetThreadAffinityMask(hThread, (IntPtr)(1 << processorNumber.Number));
CloseHandle(hThread);
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
}
I can't deny that with 99% probability I'm an idiot, that's why I came here to ask for your help.
upd1: The program properly detects idealprocessor, but doesn't set affinity to the thread.
As #RaymondChen said
Per documentation: This handle must have the THREAD_SET_INFORMATION or
THREAD_SET_LIMITED_INFORMATION access right and the
THREAD_QUERY_INFORMATION or THREAD_QUERY_LIMITED_INFORMATION access
right.
Let's say I have multiple chrome windows open (not tabs),
how can I check the browser title?
I tried the following:
Process[] p = Process.GetProcessesByName("chrome");
foreach (Process item in p)
{
Console.WriteLine(item.MainWindowTitle);
}
but it return me only the last open window name and all other are blanks..
I had to do something like this, but it was amazingly fiddly involving calling Windows API functions. The problem was that Chrome seems to use a single process for multiple windows or some other weirdness that meant the simple approach didn't work for me.
Anyway, try this and see if it works. Basically it uses the Chrome window class name (which might be Chrome_WidgetWin_0 or Chrome_WidgetWin_1) to enumerate all windows with that class name, and returns the window titles for those which are not blank.
Note that this also always returns a windows title called "Chrome App Launcher" for some reason, so you might need to filter that out.
Note: you can also do this for Firefox by using "MozillaWindowClass" and for IE by using "IEFrame" (although any of those are likely to change with different versions).
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
namespace Demo
{
class WindowsByClassFinder
{
public delegate bool EnumWindowsDelegate(IntPtr hWnd, IntPtr lparam);
[SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage"), SuppressUnmanagedCodeSecurity]
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage"), SuppressUnmanagedCodeSecurity]
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public extern static bool EnumWindows(EnumWindowsDelegate lpEnumFunc, IntPtr lparam);
[SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage"), SuppressUnmanagedCodeSecurity]
[DllImport("User32", CharSet=CharSet.Auto, SetLastError=true)]
public static extern int GetWindowText(IntPtr windowHandle, StringBuilder stringBuilder, int nMaxCount);
[DllImport("user32.dll", EntryPoint = "GetWindowTextLength", SetLastError = true)]
internal static extern int GetWindowTextLength(IntPtr hwnd);
/// <summary>Find the windows matching the specified class name.</summary>
public static IEnumerable<IntPtr> WindowsMatching(string className)
{
return new WindowsByClassFinder(className)._result;
}
private WindowsByClassFinder(string className)
{
_className = className;
EnumWindows(callback, IntPtr.Zero);
}
private bool callback(IntPtr hWnd, IntPtr lparam)
{
if (GetClassName(hWnd, _apiResult, _apiResult.Capacity) != 0)
{
if (string.CompareOrdinal(_apiResult.ToString(), _className) == 0)
{
_result.Add(hWnd);
}
}
return true; // Keep enumerating.
}
public static IEnumerable<string> WindowTitlesForClass(string className)
{
foreach (var windowHandle in WindowsMatchingClassName(className))
{
int length = GetWindowTextLength(windowHandle);
StringBuilder sb = new StringBuilder(length + 1);
GetWindowText(windowHandle, sb, sb.Capacity);
yield return sb.ToString();
}
}
public static IEnumerable<IntPtr> WindowsMatchingClassName(string className)
{
if (string.IsNullOrWhiteSpace(className))
throw new ArgumentOutOfRangeException("className", className, "className can't be null or blank.");
return WindowsMatching(className);
}
private readonly string _className;
private readonly List<IntPtr> _result = new List<IntPtr>();
private readonly StringBuilder _apiResult = new StringBuilder(1024);
}
class Program
{
void run()
{
ChromeWindowTitles().Print();
}
public IEnumerable<string> ChromeWindowTitles()
{
foreach (var title in WindowsByClassFinder.WindowTitlesForClass("Chrome_WidgetWin_0"))
if (!string.IsNullOrWhiteSpace(title))
yield return title;
foreach (var title in WindowsByClassFinder.WindowTitlesForClass("Chrome_WidgetWin_1"))
if (!string.IsNullOrWhiteSpace(title))
yield return title;
}
static void Main()
{
new Program().run();
}
}
static class DemoUtil
{
public static void Print(this object self)
{
Console.WriteLine(self);
}
public static void Print(this string self)
{
Console.WriteLine(self);
}
public static void Print<T>(this IEnumerable<T> self)
{
foreach (var item in self)
Console.WriteLine(item);
}
}
}
I know this is already answered, but I also have made a solution, which enumerates all Windows within a thread.
It was built from Matthew Watson's solution, hence some similarities.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Chrome_Windows
{
class Program
{
[DllImport("user32.dll")]
private static extern bool EnumThreadWindows(uint dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("User32", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowText(IntPtr windowHandle, StringBuilder stringBuilder, int nMaxCount);
[DllImport("user32.dll", EntryPoint = "GetWindowTextLength", SetLastError = true)]
internal static extern int GetWindowTextLength(IntPtr hwnd);
private static List<IntPtr> windowList;
private static string _className;
private static StringBuilder apiResult = new StringBuilder(256); //256 Is max class name length.
private delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);
static void Main(string[] args)
{
List<IntPtr> ChromeWindows = WindowsFinder("Chrome_WidgetWin_1", "chrome");
foreach (IntPtr windowHandle in ChromeWindows)
{
int length = GetWindowTextLength(windowHandle);
StringBuilder sb = new StringBuilder(length + 1);
GetWindowText(windowHandle, sb, sb.Capacity);
Console.WriteLine(sb.ToString());
}
}
private static List<IntPtr> WindowsFinder(string className, string process)
{
_className = className;
windowList = new List<IntPtr>();
Process[] chromeList = Process.GetProcessesByName(process);
if (chromeList.Length > 0)
{
foreach (Process chrome in chromeList)
{
if (chrome.MainWindowHandle != IntPtr.Zero)
{
foreach (ProcessThread thread in chrome.Threads)
{
EnumThreadWindows((uint)thread.Id, new EnumThreadDelegate(EnumThreadCallback), IntPtr.Zero);
}
}
}
}
return windowList;
}
static bool EnumThreadCallback(IntPtr hWnd, IntPtr lParam)
{
if (GetClassName(hWnd, apiResult, apiResult.Capacity) != 0)
{
if (string.CompareOrdinal(apiResult.ToString(), _className) == 0)
{
windowList.Add(hWnd);
}
}
return true;
}
}
}
I know this is an old thread, but I have found the answer to this, at least for my use case anyway. I wanted to find all the open chrome windows/tabs by title as well, but in my case I wanted to close the ones I found containing x Title. After reading icbytes and dor-cohen's post above I realized I could achieve what I needed by calling Process.GetProcessesByName() more than once. When making this call you do get an array of all the running chrome processes, but only one instance will contain a value for MainWindowTitle. This is a bit annoying for several reasons. You can have multiple chrome sessions open with and "active" "displayed tab", but still the call only ever returns an array of chrome proc's with just one instance in that array having an value for MainWindowTitle. Again, my solution is not necessarily the OP's intention as he states just wanting to list the titles. My solution wants to close each found title.
What I have done is as follows:
Once I find the first chrome process with the title I am looking for I call CloseMainWindow() on that process. Do not call Kill() as it will crash the browser altogether. I am just closing the active or top level window here. I am posting my code below. I hope this will help someone else! Thanks!
bool foundAll = false;
do
{
bool foundOne = false;
procs = Process.GetProcessesByName("chrome");
foreach (Process p in procs)
{
if (p.MainWindowTitle.Length > 0)
{
string t = p.MainWindowTitle.Replace(" - Google Chrome", "");
if (t.ToLower().Contains(this.BrowserTabText.ToLower()))
{
foundOne = true;
this.WriteEventLogEntry($"Found Tab Title: {this.BrowserTabText} with PID: {p.Id}. \r\nWe will close it.", EventLogEntryType.Information);
p.CloseMainWindow();
break;
}
}
}
if (!foundOne)
{
foundAll = true;
}
} while (!foundAll);
You must get a list of processes.
Iterate through the list and only where name is "chrome".
This will allow You to get all titles.
Because if You have more then one chrome process , Your call will give You only one, because You call it only once.
Which it returns is perhaps another question. In Your case it is the last.
The problem:
I have windows service that uses impersonation to check the service status on a separate server, however it was noted during testing that when the user supplied a local machine address and an invalid local machine account the check would proceed to open the service control manager and retrieve the status successfully. We aim to have it only work with a valid local machine account.
The Code:
Impersonation namespace (contains method (SoddingNetworkAuth) used to set up the impersonation:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.Principal;
namespace Impersonation
{
public class Network
{
public class SoddingNetworkAuth : IDisposable
{
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);
[DllImport("kernel32", SetLastError = true)]
private static extern bool CloseHandle(IntPtr hObject);
private IntPtr userHandle = IntPtr.Zero;
private WindowsImpersonationContext impersonationContext;
public SoddingNetworkAuth(string user, string domain, string password)
{
if (!string.IsNullOrEmpty(user))
{
// Call LogonUser to get a token for the user
bool loggedOn = LogonUser(user, domain, password,
9 /*(int)LogonType.LOGON32_LOGON_NEW_CREDENTIALS*/,
3 /*(int)LogonProvider.LOGON32_PROVIDER_WINNT50*/,
out userHandle);
if (!loggedOn)
throw new Win32Exception(Marshal.GetLastWin32Error());
// Begin impersonating the user
impersonationContext = WindowsIdentity.Impersonate(userHandle);
}
}
public void Dispose()
{
if (userHandle != IntPtr.Zero)
CloseHandle(userHandle);
if (impersonationContext != null)
impersonationContext.Undo();
}
}
}
}
A console app I wrote for the test:
using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceProcess;
namespace NetworkAuthIssue
{
class Program
{
static void Main(string[] args)
{
string result;
try
{
using (new Impersonation.Network.SoddingNetworkAuth("Invalid User", "localhost", "InvalidPassword"))
{
var serviceController = new ServiceController("Power", "localhost");
if (serviceController.Status == ServiceControllerStatus.Running)
{
result = "Authenticated, service running";
}
else
{
result = "Authenticated, service not running";
}
}
}
catch (Exception e)
{
result = "Authentication Failed";
}
Console.WriteLine(result);
Console.Read();
}
}
}
I am running Windows 8.1
It's because you're using LOGON32_LOGON_NEW_CREDENTIALS.
From https://msdn.microsoft.com/en-us/library/windows/desktop/aa378184%28v=vs.85%29.aspx (emphasis mine):
This logon type allows the caller to clone its current token and specify new credentials for outbound connections. The new logon session has the same local identifier but uses different credentials for other network connections.
The "outbound connections" part is important. It means that for local connections, the provided credentials aren't used at all. The current identity gets used for local connections.
I can't check things right now but I had similar issues like you and this was caused by the selected LogonType/LogonProvider values in the Logon method. You should try them out in a console app and use the combination which works for your scenario.
See also the msdn documentation for this method: https://msdn.microsoft.com/en-us/library/windows/desktop/aa378184(v=vs.85).aspx
I want to write a program in C# that recognize now computer connected to internet or not by C#.
Would you help me how to do that, I have no idea about it,because I didnt work network in C#.
one more question,how I can run a program from c# and sent argument also?
Use Microsoft's InternetGetConnectedState function.
You can call it with P/Invoke:
using System;
using System.Runtime.InteropServices;
namespace ConnectionState
{
internal class Program
{
[DllImport("wininet.dll", SetLastError = true)]
private static extern bool InternetGetConnectedState(out int lpdwFlags, int dwReserved);
private static void Main(string[] args)
{
int flags;
bool isConnected = InternetGetConnectedState(out flags, 0);
Console.WriteLine(string.Format("Is connected: {0} Flags:{1}", isConnected, flags));
Console.Read();
}
}
}
My ASP.NET 4.0 Web App is unable to access Network Printers, while debugging on VS 2010. It can access local printers. Seems like it may be a permissions issue. Since VS2010 Debugging runs on ASP.NET Development Server, it must be running under the account I used to log into Windows, right? Does that user need to be added as an Admin in that printers users? Is there any account that I can impersonate to get this working?
You are correct, debugging through Visual Studio means all of your code runs with the same rights as the user logged in to windows. On the server, you will need to setup impersonation and/or setup your Application Pool to run as a user who has access to print on these printers.
I recommend you setup a dedicated domain account (like domain\yourapp-impers-user) and either set the Application Pool to use that, or setup impersonation in your web.config. Then on the print server, you simply grant that user account the necessary permissions.
Here is an example of impersonation
using System;
using System.Collections.Generic;
using System.Web.Security;
using System.Security.Principal;
using System.Runtime.InteropServices;
using System.Linq;
using System.Web;
using System.IO;
public partial class Main : PageBase
{
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_PROVIDER_DEFAULT = 0;
WindowsImpersonationContext impersonationContext;
[DllImport("advapi32.dll")]
public static extern int LogonUserA(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DuplicateToken(IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
protected void Page_Load(object sender, EventArgs e)
{
if (Page.IsPostBack == false)
{
if (impersonateValidUser("Username", "Domain", "Password"))
{
//Your code under a specific user here.
}
}
}
private bool impersonateValidUser(String userName, String domain, String password)
{
WindowsIdentity tempWindowsIdentity;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
if (RevertToSelf())
{
if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, ref token) != 0)
{
if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
if (impersonationContext != null)
{
CloseHandle(token);
CloseHandle(tokenDuplicate);
return true;
}
}
}
}
if (token != IntPtr.Zero)
CloseHandle(token);
if (tokenDuplicate != IntPtr.Zero)
CloseHandle(tokenDuplicate);
return false;
}
private void undoImpersonation()
{
impersonationContext.Undo();
}
Good luck !
without knowing for sure, you can try to impersonate the Network Service, or of course your own domain account which should always work.