Below is my attempt to turn a System.Diagnostics.Process into an IConnectableObservable.
This solution has a problem: I'd like to listen to the standard output and error continiously and use the event Process.Exited as trigger for OnCompleted. Unfortunately I found out that Process.Exited is raised before output buffers are empty. This means that without my ugly workaround with a thread sleep I can reproduce situations where the output is not served via OnNext statements.
Q1: Do you see any workaround for this issue?
Q2: With regard to System.Reactive: What could I have done better in my solution?
regards,
Markus
public static class RxProcessUtilities
{
/// <summary>
/// Creates a connectable observable for a process.
/// </summary>
/// <remarks>Must be a connectable observable in order to hinder multiple
/// subscriptions to call the process multiple times.</remarks>
/// <param name="process">The process.</param>
/// <returns></returns>
public static IConnectableObservable<string> CreateConnectableObservableProcess
(string filename, string arguments, IObservable<string> input = null)
{
var observable = Observable.Using(() =>
{
Process process = new Process();
// process configuration
process.StartInfo.FileName = filename;
process.StartInfo.Arguments = arguments;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.EnableRaisingEvents = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
if (null != input)
{
process.StartInfo.RedirectStandardInput = true;
input.Subscribe(s =>
{
if (!process.HasExited)
{
process.StandardInput.Write(s);
}
});
}
return process;
},
process =>
{
return Observable.Create<string>(
(IObserver<string> observer) =>
{
// listen to stdout and stderr
var stdOut = RxProcessUtilities.CreateStandardOutputObservable(process);
var stdErr = RxProcessUtilities.CreateStandardErrorObservable(process);
var stdOutSubscription = stdOut.Subscribe(observer);
var stdErrSubscription = stdErr.Subscribe(observer);
var processExited = Observable.FromEventPattern
(h => process.Exited += h, h => process.Exited -= h);
var processError = processExited.Subscribe(args =>
{
// Here is my problem: process sends exited event *before* all
// *DataReceived events have been raised
// My ugly workaround for process exit before stdout and stderr buffers are empty.
Thread.Sleep(2000);
// Also: AFAICS we cannot read synchronously what is left in the buffer,
// since we started asynchronously. This will throw:
// string restOfStdOut = process.StandardOutput.ReadToEnd();
// string restOfStdErr = process.StandardError.ReadToEnd();
if (process.ExitCode != 0)
{
observer.OnError(new Exception
(String.Format("Process '{0}' terminated with error code {1}",
process.StartInfo.FileName, process.ExitCode)));
}
else
{
observer.OnCompleted();
}
});
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
return new CompositeDisposable
(stdOutSubscription,
stdErrSubscription,
processError);
});
});
return observable.Publish();
}
/// <summary>
/// Creates an IObservable<string> for the standard error of a process.
/// </summary>
/// <param name="process">The process.</param>
/// <returns></returns>
public static IObservable<string> CreateStandardErrorObservable(Process process)
{
// var processExited = Observable.FromEventPattern
// (h => process.Exited += h, h => process.Exited -= h);
var receivedStdErr =
Observable.FromEventPattern<DataReceivedEventHandler, DataReceivedEventArgs>
(h => process.ErrorDataReceived += h,
h => process.ErrorDataReceived -= h)
//.TakeUntil(processExited)
// cannot be used here, since process exited event might be raised
// before all stderr and stdout events occurred.
.Select(e => e.EventArgs.Data);
return Observable.Create<string>(observer =>
{
var cancel = Disposable.Create(process.CancelErrorRead);
return new CompositeDisposable(cancel, receivedStdErr.Subscribe(observer));
});
}
/// <summary>
/// Creates an IObservable<string> for the standard output of a process.
/// </summary>
/// <param name="process">The process.</param>
/// <returns></returns>
public static IObservable<string> CreateStandardOutputObservable(Process process)
{
var receivedStdOut =
Observable.FromEventPattern<DataReceivedEventHandler, DataReceivedEventArgs>
(h => process.OutputDataReceived += h,
h => process.OutputDataReceived -= h)
.Select(e => e.EventArgs.Data);
return Observable.Create<string>(observer =>
{
var cancel = Disposable.Create(process.CancelOutputRead);
return new CompositeDisposable(cancel, receivedStdOut.Subscribe(observer));
});
}
}
The trick is
process.WaitForExit();
See http://msdn.microsoft.com/en-us/library/fb4aw7b8.aspx: "This overload [WaitForExit()] ensures that all processing has been completed, including the handling of asynchronous events for redirected standard output. You should use this overload after a call to the WaitForExit(Int32) overload when standard output has been redirected to asynchronous event handlers."
Here is the complete solution:
/// <summary>
/// Creates a connectable observable for a process.
/// </summary>
/// <remarks>Must be a connectable observable in order to hinder multiple subscriptions to call the process multiple times.</remarks>
/// <param name="process">The process.</param>
/// <returns></returns>
public static IConnectableObservable<string> CreateConnectableObservableProcess(string filename, string arguments, IObservable<string> input = null)
{
var observable = Observable.Using(() =>
{
Process process = new Process();
// process configuration
process.StartInfo.FileName = filename;
process.StartInfo.Arguments = arguments;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.EnableRaisingEvents = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
if (null != input)
{
process.StartInfo.RedirectStandardInput = true;
input.Subscribe(s =>
{
if (!process.HasExited)
{
process.StandardInput.Write(s);
}
});
}
return process;
},
process =>
{
return Observable.Create<string>(
(IObserver<string> observer) =>
{
// listen to stdout and stderr
var stdOut = RxProcessUtilities.CreateStandardOutputObservable(process);
var stdErr = RxProcessUtilities.CreateStandardErrorObservable(process);
var stdOutSubscription = stdOut.Subscribe(observer);
var stdErrSubscription = stdErr.Subscribe(observer);
var processExited = Observable.FromEventPattern(h => process.Exited += h, h => process.Exited -= h);
var processError = processExited.Subscribe(args =>
{
process.WaitForExit();
try
{
if (process.ExitCode != 0)
{
observer.OnError(new Exception(String.Format("Process '{0}' terminated with error code {1}",
process.StartInfo.FileName, process.ExitCode)));
}
else
{
observer.OnCompleted();
}
}
finally
{
process.Close();
}
});
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
return new CompositeDisposable(stdOutSubscription,
stdErrSubscription,
processError);
});
});
return observable.Publish();
}
Related
I've installed filepicker control from Nuget and added tried adding reference from MonoTouch10 folder and later from github to my xamarin.ios project.
FileData file = await CrossFilePicker.Current.PickFile();
if (file != null) { }
this is the code i added to my browse button, after selecting a file from iCloud drive, control never comes to "if condition".
and again when i click on browse button for second time, app crashes saying "only one operation can be active at a time".
Modifying the source code of the FilePickerImplementation plugin for the iOS platform worked, in this way:
using Foundation;
using MobileCoreServices;
using Plugin.FilePicker.Abstractions;
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using UIKit;
using System.Diagnostics;
namespace Plugin.FilePicker
{
/// <summary>
/// Implementation for FilePicker
/// </summary>
public class FilePickerImplementation : NSObject, IUIDocumentMenuDelegate, IFilePicker
{
private int _requestId;
private TaskCompletionSource<FileData> _completionSource;
/// <summary>
/// Event which is invoked when a file was picked
/// </summary>
public EventHandler<FilePickerEventArgs> Handler
{
get;
set;
}
private void OnFilePicked(FilePickerEventArgs e)
{
Handler?.Invoke(null, e);
}
public void DidPickDocumentPicker(UIDocumentMenuViewController documentMenu, UIDocumentPickerViewController documentPicker)
{
documentPicker.DidPickDocument += DocumentPicker_DidPickDocument;
documentPicker.WasCancelled += DocumentPicker_WasCancelled;
documentPicker.DidPickDocumentAtUrls += DocumentPicker_DidPickDocumentAtUrls;
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(documentPicker, true, null);
}
private void DocumentPicker_DidPickDocumentAtUrls(object sender, UIDocumentPickedAtUrlsEventArgs e)
{
var control = (UIDocumentPickerViewController)sender;
foreach (var url in e.Urls)
DocumentPicker_DidPickDocument(control, new UIDocumentPickedEventArgs(url));
control.Dispose();
}
private void DocumentPicker_DidPickDocument(object sender, UIDocumentPickedEventArgs e)
{
var securityEnabled = e.Url.StartAccessingSecurityScopedResource();
var doc = new UIDocument(e.Url);
var data = NSData.FromUrl(e.Url);
var dataBytes = new byte[data.Length];
System.Runtime.InteropServices.Marshal.Copy(data.Bytes, dataBytes, 0, Convert.ToInt32(data.Length));
string filename = doc.LocalizedName;
string pathname = doc.FileUrl?.ToString();
// iCloud drive can return null for LocalizedName.
if (filename == null)
{
// Retrieve actual filename by taking the last entry after / in FileURL.
// e.g. /path/to/file.ext -> file.ext
// filesplit is either:
// 0 (pathname is null, or last / is at position 0)
// -1 (no / in pathname)
// positive int (last occurence of / in string)
var filesplit = pathname?.LastIndexOf('/') ?? 0;
filename = pathname?.Substring(filesplit + 1);
}
OnFilePicked(new FilePickerEventArgs(dataBytes, filename, pathname));
}
/// <summary>
/// Handles when the file picker was cancelled. Either in the
/// popup menu or later on.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void DocumentPicker_WasCancelled(object sender, EventArgs e)
{
{
var tcs = Interlocked.Exchange(ref _completionSource, null);
tcs.SetResult(null);
}
}
/// <summary>
/// Lets the user pick a file with the systems default file picker
/// For iOS iCloud drive needs to be configured
/// </summary>
/// <returns></returns>
public async Task<FileData> PickFile()
{
var media = await TakeMediaAsync();
return media;
}
private Task<FileData> TakeMediaAsync()
{
var id = GetRequestId();
var ntcs = new TaskCompletionSource<FileData>(id);
if (Interlocked.CompareExchange(ref _completionSource, ntcs, null) != null)
throw new InvalidOperationException("Only one operation can be active at a time");
var allowedUtis = new string[] {
UTType.UTF8PlainText,
UTType.PlainText,
UTType.RTF,
UTType.PNG,
UTType.Text,
UTType.PDF,
UTType.Image,
UTType.UTF16PlainText,
UTType.FileURL
};
var importMenu =
new UIDocumentMenuViewController(allowedUtis, UIDocumentPickerMode.Import)
{
Delegate = this,
ModalPresentationStyle = UIModalPresentationStyle.Popover
};
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(importMenu, true, null);
var presPopover = importMenu.PopoverPresentationController;
if (presPopover != null)
{
presPopover.SourceView = UIApplication.SharedApplication.KeyWindow.RootViewController.View;
presPopover.PermittedArrowDirections = UIPopoverArrowDirection.Down;
}
Handler = null;
Handler = (s, e) => {
var tcs = Interlocked.Exchange(ref _completionSource, null);
tcs?.SetResult(new FileData(e.FilePath, e.FileName, () => { var url = new Foundation.NSUrl(e.FilePath); return new FileStream(url.Path, FileMode.Open, FileAccess.Read); }));
};
return _completionSource.Task;
}
public void WasCancelled(UIDocumentMenuViewController documentMenu)
{
var tcs = Interlocked.Exchange(ref _completionSource, null);
tcs?.SetResult(null);
}
private int GetRequestId()
{
var id = _requestId;
if (_requestId == int.MaxValue)
_requestId = 0;
else
_requestId++;
return id;
}
public async Task<bool> SaveFile(FileData fileToSave)
{
try
{
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var fileName = Path.Combine(documents, fileToSave.FileName);
File.WriteAllBytes(fileName, fileToSave.DataArray);
return true;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
return false;
}
}
public void OpenFile(NSUrl fileUrl)
{
var docControl = UIDocumentInteractionController.FromUrl(fileUrl);
var window = UIApplication.SharedApplication.KeyWindow;
var subViews = window.Subviews;
var lastView = subViews.Last();
var frame = lastView.Frame;
docControl.PresentOpenInMenu(frame, lastView, true);
}
public void OpenFile(string fileToOpen)
{
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var fileName = Path.Combine(documents, fileToOpen);
if (NSFileManager.DefaultManager.FileExists(fileName))
{
var url = new NSUrl(fileName, true);
OpenFile(url);
}
}
public async void OpenFile(FileData fileToOpen)
{
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var fileName = Path.Combine(documents, fileToOpen.FileName);
if (NSFileManager.DefaultManager.FileExists(fileName))
{
var url = new NSUrl(fileName, true);
OpenFile(url);
}
else
{
await SaveFile(fileToOpen);
OpenFile(fileToOpen);
}
}
}
}
To answer my own question, i customized in plugin, like
Used DocumentPicker_DidPickDocumentAtUrls event instead of DocumentPicker_DidPickDocument.
while returning selected file used
new FileData(e.FilePath, e.FileName, () =>
{
var url = new Foundation.NSUrl(e.FilePath);
return new FileStream(url.Path, FileMode.Open, FileAccess.Read);
})
This solved my issue. Thanks.
There are several forks of the FilePicker Xamarin plugin. I recommend the following project, since it's the most actively maintained one:
https://github.com/jfversluis/FilePicker-Plugin-for-Xamarin-and-Windows (note: I'm one of the contributors to the project).
With this version of the plugin file picking should work. The example code from sandeep's answer was already incorporated into the latest version of the plugin. Be sure to read the README.md's Troubleshooting page in case you're getting problems.
I've building a windows app for browsing web pages using cefSharp.
I need to implement some short cut keys into that application, can any one tell me how can i achieve this functionality.
Ex.
ctrl + tab = move to next tab
I'm able to track if user presses any single key, but unable to track multi key pressing.
IKeyboardHandler
public class KeyboardHandler : IKeyboardHandler
{
public bool OnKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey)
{
bool result = false;
Debug.WriteLine(String.Format("OnKeyEvent: KeyType: {0} 0x{1:X} Modifiers: {2}", type, windowsKeyCode, modifiers));
// TODO: Handle MessageNeeded cases here somehow.
return result;
}
public bool OnPreKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut)
{
const int WM_SYSKEYDOWN = 0x104;
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
const int WM_SYSKEYUP = 0x105;
const int WM_CHAR = 0x102;
const int WM_SYSCHAR = 0x106;
const int VK_TAB = 0x9;
bool result = false;
isKeyboardShortcut = false;
// Don't deal with TABs by default:
// TODO: Are there any additional ones we need to be careful of?
// i.e. Escape, Return, etc...?
if (windowsKeyCode == VK_TAB)
{
return result;
}
Control control = browserControl as Control;
int msgType = 0;
switch (type)
{
case KeyType.RawKeyDown:
if (isSystemKey)
{
msgType = WM_SYSKEYDOWN;
}
else
{
msgType = WM_KEYDOWN;
}
break;
case KeyType.KeyUp:
if (isSystemKey)
{
msgType = WM_SYSKEYUP;
}
else
{
msgType = WM_KEYUP;
}
break;
case KeyType.Char:
if (isSystemKey)
{
msgType = WM_SYSCHAR;
}
else
{
msgType = WM_CHAR;
}
break;
default:
Trace.Assert(false);
break;
}
// We have to adapt from CEF's UI thread message loop to our fronting WinForm control here.
// So, we have to make some calls that Application.Run usually ends up handling for us:
PreProcessControlState state = PreProcessControlState.MessageNotNeeded;
// We can't use BeginInvoke here, because we need the results for the return value
// and isKeyboardShortcut. In theory this shouldn't deadlock, because
// atm this is the only synchronous operation between the two threads.
control.Invoke(new Action(() =>
{
Message msg = new Message() { HWnd = control.Handle, Msg = msgType, WParam = new IntPtr(windowsKeyCode), LParam = new IntPtr(nativeKeyCode) };
// First comes Application.AddMessageFilter related processing:
// 99.9% of the time in WinForms this doesn't do anything interesting.
bool processed = Application.FilterMessage(ref msg);
if (processed)
{
state = PreProcessControlState.MessageProcessed;
}
else
{
// Next we see if our control (or one of its parents)
// wants first crack at the message via several possible Control methods.
// This includes things like Mnemonics/Accelerators/Menu Shortcuts/etc...
state = control.PreProcessControlMessage(ref msg);
}
}));
if (state == PreProcessControlState.MessageNeeded)
{
// TODO: Determine how to track MessageNeeded for OnKeyEvent.
isKeyboardShortcut = true;
}
else if (state == PreProcessControlState.MessageProcessed)
{
// Most of the interesting cases get processed by PreProcessControlMessage.
result = true;
}
Debug.WriteLine(String.Format("OnPreKeyEvent: KeyType: {0} 0x{1:X} Modifiers: {2}", type, windowsKeyCode, modifiers));
Debug.WriteLine(String.Format("OnPreKeyEvent PreProcessControlState: {0}", state));
return result;
}
Finally got an alternative to implement shortcut functionality without implementing IKeyboardHandler.
Here i used Global Keyboard Hook to implement this.
GlobalKeyboardHook
public class GlobalKeyboardHook
{
#region Variables and dll import
#region For key capturing
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr hhk, int code, int wParam, ref keyBoardHookStruct lParam);
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, LLKeyboardHook callback, IntPtr hInstance, uint theardID);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
public delegate int LLKeyboardHook(int Code, int wParam, ref keyBoardHookStruct lParam);
public struct keyBoardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x0100;
const int WM_KEYUP = 0x0101;
const int WM_SYSKEYDOWN = 0x0104;
const int WM_SYSKEYUP = 0x0105;
LLKeyboardHook llkh;
public List<Keys> HookedKeys = new List<Keys>();
IntPtr Hook = IntPtr.Zero;
public event KeyEventHandler KeyDown;
public event KeyEventHandler KeyUp;
#endregion
#region For modifier capturing
/// <summary>
/// Gets the state of modifier keys for a given keycode.
/// </summary>
/// <param name="keyCode">The keyCode</param>
/// <returns></returns>
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
public static extern short GetKeyState(int keyCode);
//Modifier key vkCode constants
private const int VK_SHIFT = 0x10;
private const int VK_CONTROL = 0x11;
private const int VK_MENU = 0x12;
private const int VK_CAPITAL = 0x14;
#endregion
#endregion
#region Constructor
// This is the Constructor. This is the code that runs every time you create a new GlobalKeyboardHook object
public GlobalKeyboardHook()
{
llkh = new LLKeyboardHook(HookProc);
// This starts the hook. You can leave this as comment and you have to start it manually
// Or delete the comment mark and your hook will start automatically when your program starts (because a new GlobalKeyboardHook object is created)
// That's why there are duplicates, because you start it twice! I'm sorry, I haven't noticed this...
// hook(); <-- Choose!
}
~GlobalKeyboardHook()
{ unhook(); }
#endregion
#region Functions and implementation
/// <summary>
/// Hook (Start listening keybord events)
/// </summary>
public void hook()
{
IntPtr hInstance = LoadLibrary("User32");
Hook = SetWindowsHookEx(WH_KEYBOARD_LL, llkh, hInstance, 0);
}
/// <summary>
/// Unhook (Stop listening keybord events)
/// </summary>
public void unhook()
{
UnhookWindowsHookEx(Hook);
}
/// <summary>
/// Pass key into event
/// </summary>
/// <param name="Code">Key code</param>
/// <param name="wParam">int event type (keydown/keyup)</param>
/// <param name="lParam">keyBoardHookStruct enum for detecting key</param>
/// <returns>next hook call</returns>
public int HookProc(int Code, int wParam, ref keyBoardHookStruct lParam)
{
if (Code >= 0)
{
Keys key = (Keys)lParam.vkCode;
if (HookedKeys.Contains(key))
{
//Get modifiers
key = AddModifiers(key);
KeyEventArgs kArg = new KeyEventArgs(key);
if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && (KeyDown != null))
{
KeyDown(this, kArg);
}
else if ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && (KeyUp != null))
{
KeyUp(this, kArg);
}
if (kArg.Handled)
return 1;
}
}
return CallNextHookEx(Hook, Code, wParam, ref lParam);
}
/// <summary>
/// Checks whether Alt, Shift, Control or CapsLock
/// is pressed at the same time as the hooked key.
/// Modifies the keyCode to include the pressed keys.
/// </summary>
private Keys AddModifiers(Keys key)
{
//CapsLock
if ((GetKeyState(VK_CAPITAL) & 0x0001) != 0) key = key | Keys.CapsLock;
//Shift
if ((GetKeyState(VK_SHIFT) & 0x8000) != 0) key = key | Keys.Shift;
//Ctrl
if ((GetKeyState(VK_CONTROL) & 0x8000) != 0) key = key | Keys.Control;
//Alt
if ((GetKeyState(VK_MENU) & 0x8000) != 0) key = key | Keys.Alt;
return key;
}
#endregion
}
Start hook
To start hook add below code to form load or application start
//Start listening keybord events
gHook = new GlobalKeyboardHook();
gHook.KeyDown += new KeyEventHandler(gHook_KeyDown);
foreach (Keys key in Enum.GetValues(typeof(Keys)))
{
gHook.HookedKeys.Add(key);
}
gHook.hook();
Stop hook
Add this code on application exit(form closing event)
//Stop listening keybord events
gHook.unhook();
Handel key down event for shortcut implementation
public void gHook_KeyDown(object sender, KeyEventArgs e)
{
if (this.ContainsFocus)
{
if (e.KeyData.ToString().ToUpper().IndexOf("ALT".ToUpper()) >= 0
&& e.KeyValue == 66)//B = 66
{
//ALT + B
new Thread(() =>
{
// execute this on the gui thread. (winforms)
this.Invoke(new Action(delegate
{
tosBrowserBtnBack_Click(this, new EventArgs());
}));
}).Start();
}
else if (e.KeyData.ToString().ToUpper().IndexOf("ALT".ToUpper()) >= 0
&& e.KeyValue == 70)//F = 70
{
//ALT + F
new Thread(() =>
{
// execute this on the gui thread. (winforms)
this.Invoke(new Action(delegate
{
tosBrowserBtnFor_Click(this, new EventArgs());
}));
}).Start();
}
}
Global hook works for every keystroke whether your application has focus or not, so here I've used this.ContainsFocus to check current form has focus or not, if has then handle shortcut events. If you need to implementation shortcut on hole application then you need to check if application has focus or not.
For that you need to create a new class
ApplicationFocus
public class ApplicationFocus
{
/// <summary>Returns true if the current application has focus, false otherwise</summary>
public static bool ApplicationIsActivated()
{
var activatedHandle = GetForegroundWindow();
if (activatedHandle == IntPtr.Zero)
{
return false; // No window is currently activated
}
var procId = Process.GetCurrentProcess().Id;
int activeProcId;
GetWindowThreadProcessId(activatedHandle, out activeProcId);
return activeProcId == procId;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);
}
Then replace if (this.ContainsFocus) with ApplicationFocus.ApplicationIsActivated() in gHook_KeyDown event.
This is worked for me.
Attempting to jump into the Windows Server ServiceBus 1.1 code-base along with adopting the new TPL async methods. But I could not find an easy way to just spin up N number of handlers for message sessions (might have 100 or so concurrent sessions). So it would be great to get some feedback on the following code, any suggestions on an easier way would be great... note tried to keep code sample simple for the questions purpose.
///example usage
SubscriptionClient subClient = SubscriptionClient.Create(TopicName, SubscriptionName);
subClient.HandleSessions(5, msg =>
{
Console.WriteLine(string.Format("Processing recived Message: SessionId = {0}, Body = {1}",
msg.SessionId,
msg.GetBody<string>()));
msg.Complete();
});
public static class SubscriptionClientExtensions
{
public static void HandleSessions (this SubscriptionClient sc, Int32 numberOfSessions, Action<BrokeredMessage> handler)
{
Action<Task<MessageSession>> sessionAction = null;
Action<Task<BrokeredMessage>> msgHandler = null;
sessionAction = new Action<Task<MessageSession>>(tMS =>
{
if (tMS.IsFaulted) // session timed out - repeat
{
sc.AcceptMessageSessionAsync().ContinueWith(sessionAction);
return;
}
MessageSession msgSession = null;
try
{
msgSession = tMS.Result;
}
catch (Exception)
{
return; // task cancelation exception
}
msgHandler = new Action<Task<BrokeredMessage>>(taskBM =>
{
if (taskBM.IsFaulted)
return;
BrokeredMessage bMsg = null;
try
{
bMsg = taskBM.Result;
}
catch (Exception)
{
return; // task cancelation exception
}
if (bMsg == null)
{
sc.AcceptMessageSessionAsync().ContinueWith(sessionAction); // session is dead
return;
}
handler(bMsg); // client code to handle the message
msgSession.ReceiveAsync(TimeSpan.FromSeconds(5)).ContinueWith(msgHandler); // repeat
});
msgSession.ReceiveAsync(TimeSpan.FromSeconds(5)).ContinueWith(msgHandler); // start listening
});
for (Int32 nIndex = 0; nIndex < numberOfSessions; nIndex++)
{
sc.AcceptMessageSessionAsync().ContinueWith(sessionAction);
}
}
}
In my project with six laser particle counters, when I send the commands, always return extraneous characters. And sometimes the string received in the form this incomplete. Below is a snippet of code: Who know fix this?
/// <summary>
/// Class to keep track of string and color for lines in output window.
/// </summary>
private class Line
{
public string Str;
public Color ForeColor;
public Line(string str, Color color)
{
Str = str;
ForeColor = color;
}
}
ArrayList lines = new ArrayList();
Font origFont;
Font monoFont;
public Form1()
{
InitializeComponent();
outputList_Initialize();
Settings.Read();
TopMost = Settings.Option.StayOnTop;
CommPort com = CommPort.Instance;
com.StatusChanged += OnStatusChanged;
com.DataReceived += OnDataReceived;
com.Open();
}
#region Event handling - data received and status changed
/// <summary>
/// Prepare a string for output by converting non-printable characters.
/// </summary>
/// <param name="StringIn">input string to prepare.</param>
/// <returns>output string.</returns>
private String PrepareData(String StringIn)
{
// The names of the first 32 characters
string[] charNames = {
// "NUL", "SOH", "STX", "ETX", "EOT",
//"ENQ", "ACK", "BEL", "BS", "TAB", "LF", "VT", "FF", "CR", "SO", "SI",
//"DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", "CAN", "EM", "SUB",
//"ESC", "FS", "GS", "RS", "US", "Space"
};
string StringOut = "";
foreach (char c in StringIn)
{
if (Settings.Option.HexOutput)
{
StringOut = StringOut + String.Format("{0:X2} ", (int)c);
}
else if (c < 32 && c != 9)
{
StringOut = StringOut + "";// +"<"+charNames[c]+">";
//Uglier "Termite" style
//StringOut = StringOut + String.Format("[{0:X2}]", (int)c);
}
else
{
StringOut = StringOut + c;
}
}
return StringOut;
}
/// <summary>
/// Partial line for AddData().
/// </summary>
private Line partialLine = null;
/// <summary>
/// Add data to the output.
/// </summary>
/// <param name="StringIn"></param>
/// <returns></returns>
private Line AddData(String StringIn)
{
String StringOut = PrepareData(StringIn);
// if we have a partial line, add to it.
if (partialLine != null)
{
// tack it on
partialLine.Str = partialLine.Str + StringOut;
outputList_Update(partialLine);
return partialLine;
}
return outputList_Add(StringOut, receivedColor);
}
// delegate used for Invoke
internal delegate void StringDelegate(string data);
/// <summary>
/// Handle data received event from serial port.
/// </summary>
/// <param name="data">incoming data</param>
public void OnDataReceived(string dataIn)
{
//Handle multi-threading
if (InvokeRequired)
{
Invoke(new StringDelegate(OnDataReceived), new object[] { dataIn });
return;
}
// pause scrolling to speed up output of multiple lines
bool saveScrolling = scrolling;
scrolling = false;
// if we detect a line terminator, add line to output
int index;
while (dataIn.Length > 0 &&
((index = dataIn.IndexOf("\r")) != -1 ||
(index = dataIn.IndexOf("\n")) != -1))
{
String StringIn = dataIn.Substring(0, index);
dataIn = dataIn.Remove(0, index + 1);
logFile_writeLine(AddData(StringIn).Str);
logFile_writeLine1(AddData(StringIn).Str);
partialLine = null; // terminate partial line
}
// if we have data remaining, add a partial line
if (dataIn.Length > 0)
{
partialLine = AddData(dataIn);
}
// restore scrolling
scrolling = saveScrolling;
outputList_Scroll();
listBox1_Scroll();
}
/// <summary>
/// Update the connection status
/// </summary>
public void OnStatusChanged(string status)
{
//Handle multi-threading
if (InvokeRequired)
{
Invoke(new StringDelegate(OnStatusChanged), new object[] { status });
return;
}
textBox1.Text = status;
}
#endregion
Could it be bit (or byte) stuffing ?
Is there any MOSS out of the box web service which takes the URL of a SharePoint site and tells us if that URL is pointing to a file (document)? For example, we have a list of SharePoint URLs and we need to find out which URLs are pointing to a file and not a document library or a list?
I would seriously consider going with propfind (webdav). I can't give you an exact answer on how to check for file or document library or list, but I can post a function that can serve as a base for something you might implement... here it is....
/// <summary>
/// Checks if MOSS resource exists.
/// </summary>
/// <param name="url">
/// The url to the resource.
/// </param>
/// <returns>
/// True or false.
/// </returns>
/// <exception cref="Exception">
/// </exception>
private bool MossResourceExists(string url)
{
// Create the web request object
var oReq = (HttpWebRequest) WebRequest.Create(url);
// Set the needed properties
oReq.Method = "PROPFIND";
oReq.Credentials = wsLists.Credentials; // Use same credentials as wsLists.
oReq.AllowAutoRedirect = true;
oReq.UserAgent = "Microsoft-WebDAV-MiniRedir/6.1.7600";
try
{
// Enumerate through top level only, increasing the depth will find children.
oReq.Headers["Depth"] = "0";
oReq.Headers["translate"] = "f";
var oRequest = new StreamWriter(oReq.GetRequestStream());
oRequest.WriteLine();
oRequest.Close();
oReq.GetResponse();
////done with the webclient stuff, check the results
//var oMyDoc = new XmlDocument();
//oMyDoc.LoadXml(sResponse);
//var oNsMgr = new XmlNamespaceManager(oMyDoc.NameTable);
//oNsMgr.AddNamespace("D", "DAV:");
//XmlNodeList oAllResponses = oMyDoc.SelectNodes(".//D:multistatus/D:response", oNsMgr);
//foreach (XmlNode oNode in oAllResponses)
//{
// if ()
// string oNodeURL = oNode.SelectSingleNode("./D:href", oNsMgr).InnerText.ToLower()
// Console.WriteLine("Name: " +
// oNode.SelectSingleNode("./D:propstat/D:prop/D:displayname",
// oNsMgr).InnerText);
// if (oNode.SelectNodes("./D:propstat/D:prop/D:isFolder", oNsMgr).Count > 0)
// {
// Console.WriteLine("Is folder: " +
// oNode.SelectSingleNode("./D:propstat/D:prop/D:isFolder",
// oNsMgr).InnerText);
// }
// else
// {
// Console.WriteLine("Is folder: f");
// }
// Console.WriteLine();
//}
}
catch (WebException ex)
{
var errorResponse = ex.Response as HttpWebResponse;
if (errorResponse != null)
if (errorResponse.StatusCode == HttpStatusCode.NotFound)
{
return false;
}
else
{
throw new Exception("Error checking if URL exists:" + url + ";Status Code:" +
errorResponse.StatusCode + ";Error Message:" + ex.Message);
}
}
return true;
}