Native Window Handles are not garbage collected. So after searching on internet I came to know about SafeProcessHandle below on MSDN article. Tried to implement it but i am receiving 'System.Runtime.InteropServices.SEHException'
https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.safehandle.aspx
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
namespace TestHandle
{
class Program
{
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
static void Main(string[] args)
{
while (true)
{
IntPtr hWnd = GetForegroundWindow();
int processID = 0;
int threadID = GetWindowThreadProcessId(hWnd, out processID);
using (Process p = Process.GetProcessById(processID))
{
StringBuilder text = new StringBuilder(256);
GetWindowText(hWnd, text, 256);
Console.WriteLine(text.ToString());
}
Console.WriteLine(hWnd);
Thread.Sleep(100);
}
char tmp = 'q';
while (Console.Read() != tmp) ;
}
}
}
In order to obtain currently opened window, I am trying to implement it through Timer and also tried through while loop but it increases memory footprint and if i am designing a long running Console Application which works till PC is running then things are getting worse. Can someone help me on this?
GetForegroundWindow returns a window handle that you do not need to tidy up. The code shown in the question do not leak and has no need for safe handles. You use safe handles when you have a requirement to tidy up unmanaged resources. That is not the case here.
If indeed you do have a problem with a leak, it is not related to the code shown which does not need to be modified.
Update
Regarding your update it is pointless to obtain the process ID and a .net Process object. You don't use them. You can request the window text with the window handle, as indeed you do.
Nothing here suggests a leak of any unmanaged resource and nothing here requires safe handles. If process memory use grows then that would be the normal behaviour for a GC based process. Each time round the loop a new StringBuilder object is created.
The code can be much simpler:
StringBuilder text = new StringBuilder(256);
while (true)
{
IntPtr hWnd = GetForegroundWindow();
GetWindowText(hWnd, text, 256);
Console.WriteLine(text.ToString());
Console.WriteLine(hWnd);
Thread.Sleep(100);
}
Note that I am re-using a single StringBuilder object which will at least prevent steady increase of managed memory use.
You should also check return values of API calls for errors but I don't want to go into the detail of how to do that here.
Related
I'm currently trying to make a software that downloads a lot of files from Google Drive. Downloading is currently not a problem.
Nevertheless, I encounter an issue when launching 500+ simultaneous downloads. I use a slightly modified version of this tutorial : https://wiki.qt.io/Download_Data_from_URL.
Here is the .h file :
class FileDownloader : public QObject
{
Q_OBJECT
public:
explicit FileDownloader(QUrl url, QObject *parent = 0, int number = 0);
QByteArray downloadedData() const;
void launchNewDownload(QUrl url);
QByteArray m_DownloadedData;
QNetworkReply* reply;
static QNetworkAccessManager *m_WebCtrl;
signals:
void downloaded();
private slots:
void fileDownloaded(QNetworkReply* pReply);
};
And here is the .cpp file :
QNetworkAccessManager* FileDownloader::m_WebCtrl = nullptr;
FileDownloader::FileDownloader(QUrl url, QObject *parent) :
QObject(parent)
{
if (m_WebCtrl == nullptr) {
m_WebCtrl = new QNetworkAccessManager(this);
}
connect(m_WebCtrl, SIGNAL (finished(QNetworkReply*)),this, SLOT (fileDownloaded(QNetworkReply*)));
launchNewDownload(url);
}
void FileDownloader::launchNewDownload(QUrl url) {
QNetworkRequest request(url);
this->reply = m_WebCtrl->get(request);
}
void FileDownloader::fileDownloaded(QNetworkReply* pReply) {
m_DownloadedData = pReply->readAll();
//emit a signal
pReply->deleteLater();
emit downloaded();
}
QByteArray FileDownloader::downloadedData() const {
return m_DownloadedData;
}
The issue is "QThread::start: Failed to create thread ()" when reaching about the 500th download. I tried to limit the number of downloads which run at the same time - but I always get the same issue. Besides, I tried to delete every downloader when finishing its task - it did nothing else than crashing the program ;)
I think that it is coming from the number of threads allowed for an only process, but I'm not able to solve it !
Does anyone have an idea that could help me ?
Thank you !
QNetworkAccessManager::finished signal is documented to be emitted whenever a pending network reply is finished.
This means that if the QNetworkAccessManager is used to run multiple requests at a time (and this is perfectly normal usage). finished signal will be emitted once for every request. Since you have a shared instance of QNetworkAccessManager between your FileDownloader objects, the finished signal gets emitted for every get call you have made. So, all the FileDownloader objects get a finished signal as soon as the first FileDownloader finishes downloading.
Instead of using QNetworkAccessManager::finished, you can use QNetworkReply::finished to avoid mixing up signals. Here is an example implementation:
#include <QtNetwork>
#include <QtWidgets>
class FileDownloader : public QObject
{
Q_OBJECT
//using constructor injection instead of a static QNetworkAccessManager pointer
//This allows to share the same QNetworkAccessManager
//object with other classes utilizing network access
QNetworkAccessManager* m_nam;
QNetworkReply* m_reply;
QByteArray m_downloadedData;
public:
explicit FileDownloader(QUrl imageUrl, QNetworkAccessManager* nam,
QObject* parent= nullptr)
:QObject(parent), m_nam(nam)
{
QNetworkRequest request(imageUrl);
m_reply = m_nam->get(request);
connect(m_reply, &QNetworkReply::finished, this, &FileDownloader::fileDownloaded);
}
~FileDownloader() = default;
QByteArray downloadedData()const{return m_downloadedData;}
signals:
void downloaded();
private slots:
void fileDownloaded(){
m_downloadedData= m_reply->readAll();
m_reply->deleteLater();
emit downloaded();
}
};
//sample usage
int main(int argc, char* argv[]){
QApplication a(argc, argv);
QNetworkAccessManager nam;
FileDownloader fileDownloader(QUrl("http://i.imgur.com/Rt8fqpt.png"), &nam);
QLabel label;
label.setAlignment(Qt::AlignCenter);
label.setText("Downloading. . .");
label.setMinimumSize(640, 480);
label.show();
QObject::connect(&fileDownloader, &FileDownloader::downloaded, [&]{
QPixmap pixmap;
pixmap.loadFromData(fileDownloader.downloadedData());
label.setPixmap(pixmap);
});
return a.exec();
}
#include "main.moc"
If you are using this method to download large files, consider having a look at this question.
One solution could be to uses a QThreadPool. You simply feed it tasks (QRunnable) and it will handle the number of threads and the task queue for you.
However in your case this is not perfect because you will be limiting the number of simultaneous downloads to the number of threads created by QThreadPool (generally the number of CPU core you have).
To overcome this you will have to handle the QThread yourself and not use QThreadPool. You would create a small number of thread (see QThread::idealThreadCount()) and run multiple FileDownloader on each QThread.
I am trying to integrate the TestFlightSdk into an app I've made using MonoTouch.
I am trying to implement logging in my app in such a way that it is picked up by the TestFlightSdk. It supposedly picks up NSLogged text automatically, but I can't seem to find the right combination of code to add to my own app, written in C#/MonoTouch, that does the same.
What I've tried:
Console.WriteLine("...");
Debug.WriteLine("..."); (but I think this just calls Console.WriteLine)
Implementing support for NSlog, but this crashed my app so apparently I did something wrong (I'll ask a new question if this is the way to go forward.)
Is there anything built into MonoTouch that will write log messages through NSLog, so that I can use it with TestFlightSdk? Or do I have to roll my own wrapper for NSLog?
In order to implement NSLog myself, I added this:
public static class Logger
{
[DllImport("/System/Library/Frameworks/Foundation.framework/Foundation")]
private extern static void NSLog(string format, string arg1);
public static void Log(string message)
{
NSLog("%s", message);
}
}
(I got pieces of the code above from this other SO question: How to I bind to the iOS Foundations function NSLog.)
But this crashes my app with a SIGSEGV fault.
using System;
using System.Runtime.InteropServices;
using Foundation;
public class Logger
{
[DllImport(ObjCRuntime.Constants.FoundationLibrary)]
private extern static void NSLog(IntPtr message);
public static void Log(string msg, params object[] args)
{
using (var nss = new NSString (string.Format (msg, args))) {
NSLog(nss.Handle);
}
}
}
Anuj pointed the way, and this is what I ended up with:
[DllImport(MonoTouch.Constants.FoundationLibrary)]
private extern static void NSLog(IntPtr format, IntPtr arg1);
and calling it:
using (var format = new NSString("%#"))
using (var arg1 = new NSString(message))
NSLog(format.Handle, arg1.Handle);
When I tried just the single parameter, if I had percentage characters in the string, it was interpreted as an attempt to format the string, but since there was no arguments, it crashed.
Console.WriteLine() works as expected (it redirects to NSLog) on current xamarin.ios versions. Even on release builds (used by hockeyapp, etc). No need to use DllImport anymore.
Sorry for big chunk of code, I couldn't explain that with less.Basically I'm trying to write into a file from many tasks.
Can you guys please tell me what I'm doing wrong? _streamWriter.WriteLine() throws the ArgumentOutOfRangeException.
class Program
{
private static LogBuilder _log = new LogBuilder();
static void Main(string[] args)
{
var acts = new List<Func<string>>();
var rnd = new Random();
for (int i = 0; i < 10000; i++)
{
acts.Add(() =>
{
var delay = rnd.Next(300);
Thread.Sleep(delay);
return "act that that lasted "+delay;
});
}
Parallel.ForEach(acts, act =>
{
_log.Log.AppendLine(act.Invoke());
_log.Write();
});
}
}
public class LogBuilder : IDisposable
{
public StringBuilder Log = new StringBuilder();
private FileStream _fileStream;
private StreamWriter _streamWriter;
public LogBuilder()
{
_fileStream = new FileStream("log.txt", FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
_streamWriter = new StreamWriter(_fileStream) { AutoFlush = true };
}
public void Write()
{
lock (Log)
{
if (Log.Length <= 0) return;
_streamWriter.WriteLine(Log.ToString()); //throws here. Although Log.Length is greater than zero
Log.Clear();
}
}
public void Dispose()
{
_streamWriter.Close(); _streamWriter.Dispose(); _fileStream.Close(); fileStream.Dispose();
}
}
This is not a bug in StringBuilder, it's a bug in your code. And the modification you shown in your followup answer (where you replace Log.String with a loop that extracts characters one at a time) doesn't fix it. It won't throw an exception any more, but it won't work properly either.
The problem is that you're using the StringBuilder in two places in your multithreaded code, and one of them does not attempt to lock it, meaning that reading can occur on one thread simultaneously with writing occurring on another. In particular, the problem is this line:
_log.Log.AppendLine(act.Invoke());
You're doing that inside your Parallel.ForEach. You are not making any attempt at synchronization here, even though this will run on multiple threads at once. So you've got two problems:
Multiple calls to AppendLine may be in progress simultaneously on multiple threads
One thread may attempt to be calling Log.ToString at the same time as one or more other threads are calling AppendLine
You'll only get one read at a time because you are using the lock keyword to synchronize those. The problem is that you're not also acquiring the same lock when calling AppendLine.
Your 'fix' isn't really a fix. You've succeeded only in making the problem harder to see. It will now merely go wrong in different and more subtle ways. For example, I'm assuming that your Write method still goes on to call Log.Clear after your for loop completes its final iteration. Well in between completing that final iteration, and making the call to Log.Clear, it's possible that some other thread will have got in another call to AppendLine because there's no synchronization on those calls to AppendLine.
The upshot is that you will sometimes miss stuff. Code will write things into the string builder that then get cleared out without ever being written to the stream writer.
Also, there's a pretty good chance of concurrent AppendLine calls causing problems. If you're lucky they will crash from time to time. (That's good because it makes it clear you have a problem to fix.) If you're unlucky, you'll just get data corruption from time to time - two threads may end up writing into the same place in the StringBuilder resulting either in a mess, or completely lost data.
Again, this is not a bug in StringBuilder. It is not designed to support being used simultaneously from multiple threads. It's your job to make sure that only one thread at a time does anything to any particular instance of StringBuilder. As the documentation for that class says, "Any instance members are not guaranteed to be thread safe."
Obviously you don't want to hold the lock while you call act.Invoke() because that's presumably the very work you want to parallelize. So I'd guess something like this might work better:
string result = act();
lock(_log.Log)
{
_log.Log.AppendLine(result);
}
However, if I left it there, I wouldn't really be helping you, because this looks very wrong to me.
If you ever find yourself locking a field in someone else's object, it's a sign of a design problem in your code. It would probably make more sense to modify the design, so that the LogBuilder.Write method accepts a string. To be honest, I'm not even sure why you're using a StringBuilder here at all, as you seem to use it just as a holding area for a string that you immediately write to a stream writer. What were you hoping the StringBuilder would add here? The following would be simpler and doesn't seem to lose anything (other than the original concurrency bugs):
public class LogBuilder : IDisposable
{
private readonly object _lock = new object();
private FileStream _fileStream;
private StreamWriter _streamWriter;
public LogBuilder()
{
_fileStream = new FileStream("log.txt", FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
_streamWriter = new StreamWriter(_fileStream) { AutoFlush = true };
}
public void Write(string logLine)
{
lock (_lock)
{
_streamWriter.WriteLine(logLine);
}
}
public void Dispose()
{
_streamWriter.Dispose(); fileStream.Dispose();
}
}
I think the cause is because you are accessing the stringBuilder in the Parellel bracket
_log.Log.AppendLine(act.Invoke());
_log.Write();
and inside the LogBuilder you perform lock() to disallow memory allocation on stringBuidler. You are changing the streamwriter to handle the log in every character so would give the parellel process to unlock the memory allocation to stringBuilder.
Segregate the parallel process into distinct action would likely reduce the problem
Parallel.ForEach(acts, act =>
{
_log.Write(act.Invoke());
});
in the LogBuilder class
private readonly object _lock = new object();
public void Write(string logLines)
{
lock (_lock)
{
//_wr.WriteLine(logLines);
Console.WriteLine(logLines);
}
}
An alternate approach is to use TextWriter.Synchronized to wrap StreamWriter.
void Main(string[] args)
{
var rnd = new Random();
var writer = new StreamWriter(#"C:\temp\foo.txt");
var syncedWriter = TextWriter.Synchronized(writer);
var tasks = new List<Func<string>>();
for (int i = 0; i < 1000; i++)
{
int local_i = i; // get a local value, not closure-reference to i
tasks.Add(() =>
{
var delay = rnd.Next(5);
Thread.Sleep(delay);
return local_i.ToString() + " act that that lasted " + delay.ToString();
});
}
Parallel.ForEach(tasks, task =>
{
var value = task();
syncedWriter.WriteLine(value);
});
writer.Dispose();
}
Here are some of the synchronization helper classes
http://referencesource.microsoft.com/#q=Synchronized
System.Collections
static ArrayList Synchronized(ArrayList list)
static IList Synchronized(IList list)
static Hashtable Synchronized(Hashtable table)
static Queue Synchronized(Queue queue)
static SortedList Synchronized(SortedList list)
static Stack Synchronized(Stack stack)
System.Collections.Generic
static IList Synchronized(List list)
System.IO
static Stream Synchronized(Stream stream)
static TextReader Synchronized(TextReader reader)
static TextWriter Synchronized(TextWriter writer)
System.Text.RegularExpressions
static Match Synchronized(Match inner)
static Group Synchronized(Group inner)
It is seems that it isn't problem of Parallelism. It's StringBuilder's problem.
I have replaced:
_streamWriter.WriteLine(Log.ToString());
with:
for (int i = 0; i < Log.Length; i++)
{
_streamWriter.Write(Log[i]);
}
And it worked.
For future reference: http://msdn.microsoft.com/en-us/library/system.text.stringbuilder(v=VS.100).aspx
Memory allocation section.
I'm trying to elevate the process of my application using "runasuser" verb of the ProcessStartInfo class but everytime I run the program, it automatically terminates.
here is my code for the main class:
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Application Events
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
//Check if the current user is a member of the administrator group
WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
bool hasAdministrativeRights = principal.IsInRole(WindowsBuiltInRole.Administrator);
bool createdNew = false;
if (hasAdministrativeRights)
//Creating new mutex for single instance
using (Mutex mutex = new Mutex(true, "CpELabAppCopier", out createdNew))
{
if (createdNew)
Application.Run(new MainForm());
else
Application.Exit();
}
else
//Creating new mutex for single instance
using (Mutex mutex = new Mutex(true, "Elevated_CpELabAppCopier", out createdNew))
{
if (createdNew)
{
//Setting the startinfo
ProcessStartInfo newProcessInfo = new ProcessStartInfo();
newProcessInfo.FileName = Application.ExecutablePath;
newProcessInfo.Verb = "runasuser";
newProcessInfo.UseShellExecute = true;
//Starting new process
Process newProcess = new Process();
newProcess.StartInfo = newProcessInfo;
newProcess.Start();
//The Run As dialog box will show and close immediately.
}
}
}
Are you sure you want "runasuser" and not "runas"?
RunAs will attempt to run as an administrator, where RunAsUser will allow you to start a process as anybody.
If you really do want "runasuser", the problem seems to be that this verb will launch the username/password dialog in the same thread as the current process, but not block for a response. It also returns a null Process object in this case, so you can't query it's Respond/MainModule/... to see when it actually starts.
The only solution I've found is to enum all windows in the current process until you no longer see the username/password prompt dialog. Here's an example class; the only thing you may need/want to adjust is the trailing 500ms delay:
using System;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace TestAsUser
{
public static class testClass
{
public delegate bool EnumThreadDelegate (IntPtr hwnd, IntPtr lParam);
[DllImport("user32.dll")] static extern bool EnumThreadWindows(uint threadId, EnumThreadDelegate lpfn, IntPtr lParam);
[DllImport("user32.dll")] static extern int GetWindowText(IntPtr hwnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll")] static extern int GetWindowTextLength(IntPtr hwnd);
private static bool containsSecurityWindow;
public static void Main(string[] args)
{
ProcessStartInfo psi = new ProcessStartInfo("c:\\windows\\system32\\notepad.exe");
psi.Verb = "runasuser";
Process.Start(psi);
containsSecurityWindow = false;
while(!containsSecurityWindow) // wait for windows to bring up the "Windows Security" dialog
{
CheckSecurityWindow();
Thread.Sleep(25);
}
while(containsSecurityWindow) // while this process contains a "Windows Security" dialog, stay open
{
containsSecurityWindow = false;
CheckSecurityWindow();
Thread.Sleep(50);
}
Thread.Sleep(500); // give some time for windows to complete launching the application after closing the dialog
}
private static void CheckSecurityWindow()
{
ProcessThreadCollection ptc = Process.GetCurrentProcess().Threads;
for(int i=0; i<ptc.Count; i++)
EnumThreadWindows((uint)ptc[i].Id, CheckSecurityThread, IntPtr.Zero);
}
private static bool CheckSecurityThread(IntPtr hwnd, IntPtr lParam)
{
if(GetWindowTitle(hwnd) == "Windows Security")
containsSecurityWindow = true;
return true;
}
private static string GetWindowTitle(IntPtr hwnd)
{
StringBuilder sb = new StringBuilder(GetWindowTextLength(hwnd) + 1);
GetWindowText(hwnd, sb, sb.Capacity);
return sb.ToString();
}
}
}
application_exit and session_ending event in app.xaml cannot help.
Is there any way to achieve this?
The session_ending event is ignored for XBAP applications
However the Exit event is, but I cant see a way to cancel the exit in this event.
Howevere, why not just have your Exit Button call a method to ask for shutdown, and if YES, explicitly shut the app down here, or not
[DllImport("user32", ExactSpelling = true, CharSet = CharSet.Auto)]
private static extern IntPtr GetAncestor(IntPtr hwnd, int flags);
[DllImport("user32", CharSet = CharSet.Auto)]
private static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
private void exitButton_Click(object sender, RoutedEventArgs e)
{
if (MessageBox.Show("Are you Sure you want to Exit?", "Confirm", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
{
// This will Shut entire IE down
WindowInteropHelper wih = new WindowInteropHelper(Application.Current.MainWindow);
IntPtr ieHwnd = GetAncestor(wih.Handle, 2);
PostMessage(ieHwnd, 0x10, IntPtr.Zero, IntPtr.Zero);
// Singularly will just shutdown single tab and leave white screen, however with above aborts the total IE shutdown
// and just shuts the current tab
Application.Current.Shutdown();
}
}
you will also need these
using System.Windows.Interop;
using System.Runtime.InteropServices;