In a Winform application I have an array of this format:
float[][,]
I need to copy it via the clipboard to another Winform app.
How could I achieve this?
Thanks
Short answer: Using the System.Windows.Forms.Clipboard is simple.
Use Clipboard.SetData("CustomDataName", nonStandardData); to put your custom data on the clipboard and use var clipboardData = (float[][,])Clipboard.GetData("CustomDataName"); to get your custom data off the clipboard. You should check if the data is available on the clipboard using Clipboard.ContainsData("CustomDataName")
Note: By default the Windows clipboard only contains one entry at
a time be it an "image", "text" or "custom data". By putting your
custom data on the clipboard the previous data contained on the
clipboard will be gone.
The clipboard is best used for sharing more universal data between
unrelated programs, such as an image which can be pasted into a web browser or image editor. A grid of csv values which can be pasted into different data capturing and spreadsheet programs. float[][,] on the other hand has no real meaning other than to your software.
Long Answer (Here is an example):
// A Format/"Type" name for your clipboard data
static readonly string JOE_SOAP_DATA_V1 =
"JOE_SOAP_DATA_V1 {F1193E97-0B29-4ACD-935C-835A8EDFBB9D}";
// Some dummy data used to demonstrate
private readonly float[][,] JoeSoapData = new float[3][,]
{
new float[,]{{54,90},{34,56}},
new float[,]
{
{
// random values to create some variation
// will be different each time program is started
(float)new Random().NextDouble() * 2,
(float)new Random().NextDouble() * 6
},
{
(float)new Random().NextDouble() * 4,
(float)new Random().NextDouble() * 7
},
{
(float)new Random().NextDouble() * 4,
(float)new Random().NextDouble() * 7
}
},
new float[,]{{54,90},{34,56}}
};
private string JoeSoapDataToString(float[][,] data)
{
var sb = new StringBuilder();
foreach(var x in data)
{
foreach (var y in x)
sb.Append(y).Append(", ");
sb.Append('\n');
}
return sb.ToString();
}
private void BtnCopyToClipboard_Click(object sender, EventArgs e)
{
// On button click add the dummy data to the clipboard
Clipboard.SetData(JOE_SOAP_DATA_V1, JoeSoapData);
}
private void BtnPasteFromClipboard_Click(object sender, EventArgs e)
{
// Check if the clipboard contains our unique Format and notify the user if it does not
if (!Clipboard.ContainsData(JOE_SOAP_DATA_V1))
{
MessageBox.Show($"No {nameof(JOE_SOAP_DATA_V1)} clipboard data found :(");
return;
}
// extract the clipboard data and show the user
var clipboardData = (float[][,])Clipboard.GetData(JOE_SOAP_DATA_V1);
// show the copied data
LblFromClipboard.Text = "Data from clipboard\n" + JoeSoapDataToString(clipboardData);
}
private void Form1_Load(object sender, EventArgs e)
{
LblDataToCopy.Text = "Data that will be copied to the clipboard\n"
+ JoeSoapDataToString(JoeSoapData);
}
You can use AddClipboardFormatListener (for listening the clipboard update message) combined with Clipboard class to copy the data.
Receiver app:
public partial class ReceiverAppMainForm : Form
{
public ReceiverAppMainForm()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
ClipboardWrapper.AddClipboardFormatListener(Handle);
base.OnLoad(e);
}
protected override void OnClosing(CancelEventArgs e)
{
ClipboardWrapper.RemoveClipboardFormatListener(Handle);
base.OnClosing(e);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == ClipboardWrapper.WM_CLIPBOARDUPDATE)
{
var data = Clipboard.GetDataObject();
if (data != null && data.GetDataPresent("clipboard-demoapp-data"))
{
var array = (float[][,])data.GetData("clipboard-demoapp-data");
// TODO: use the shared data
}
}
}
internal static class ClipboardWrapper
{
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool AddClipboardFormatListener(IntPtr hwnd);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool RemoveClipboardFormatListener(IntPtr hwnd);
internal const int WM_CLIPBOARDUPDATE = 0x031D;
}
}
Sender app:
public partial class SenderAppMainForm : Form
{
// ... ignored for brevity
private static void CopyAppDataToClipboard(float[][,] data)
{
// variant #1 (to avoid duplication)
var dataObject = new DataObject();
dataObject.SetData("clipboard-demoapp-data", data);
Clipboard.SetDataObject(dataObject, false, 10, 100);
// variant #2 (the event is sending twice on my computer running Win10)
//Clipboard.SetData("cliboard-demoapp-data", data);
}
}
Okay so I'm making this simple screenshot program using bitmaps and such, but when i try to make a hotkey like f12, for instance, nothing happens, i coded it just to show a message box, but it doesn't even do that. So i set it back to do both message box and take a screenshot but still doesn't work.
private static NotifyIcon notifyIcon;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
// We need to dispose here, or the icon will not remove until the
// system tray is updated.
System.Windows.Forms.Application.ApplicationExit += delegate
{
notifyIcon.Dispose();
};
CreateNotifyIcon();
System.Windows.Forms.Application.Run();
}
/// <summary>
/// Creates the icon that sits in the system tray.
/// </summary>
///
static void Program_KeyDown(object sender, KeyEventArgs e)
{
if(e.KeyCode == Keys.F12)
{
MessageBox.Show("ScreenShot Taken");
TakeFullScreenShot();
}
else if(e.KeyCode == Keys.F11)
{
Application.Exit();
}
}
private static void CreateNotifyIcon()
{
notifyIcon = new NotifyIcon
{
Icon = Resources.AppIcon, ContextMenu = GetContextMenu()
};
notifyIcon.Visible = true;
}
private static ContextMenu GetContextMenu()
{
string myPath = System.AppDomain.CurrentDomain.BaseDirectory.ToString();
System.Diagnostics.Process prc = new System.Diagnostics.Process();
prc.StartInfo.FileName = myPath;
ContextMenu menu = new ContextMenu();
menu.MenuItems.Add("Take Screenshot (F12)", delegate { TakeFullScreenShot(); });
menu.MenuItems.Add("Open Folder", delegate { prc.Start(); });
menu.MenuItems.Add("Exit", delegate { System.Windows.Forms.Application.Exit(); });
return menu;
}
private static void TakeFullScreenShot()
{
int width = Screen.PrimaryScreen.Bounds.Width;
int height = Screen.PrimaryScreen.Bounds.Height;
using (Bitmap screenshot = new Bitmap(width, height, PixelFormat.Format32bppArgb))
{
using (Graphics graphics = Graphics.FromImage(screenshot))
{
Point origin = new Point(0, 0);
Size screenSize = Screen.PrimaryScreen.Bounds.Size;
//Copy Entire screen to entire bitmap.
graphics.CopyFromScreen(origin, origin, screenSize);
}
//Check to see if the file exists, if it does, append.
int append = 1;
while (File.Exists($"Screenshot{append}.jpg"))
append++;
string fileName = $"Screenshot{append}.jpg";
screenshot.Save(fileName, ImageFormat.Jpeg);
}
}
You may not need all of that but its just to make sure i didn't mess anything up when trying to build it. Also, this program has no form to it, its just a icon in your taskbar, if you right click on it and click Take Screenshot(F12) It will take the screenshot with out problem. Thank you!
The hotkey will not work unless the program has focus. The Key events are only sent to your application when it has focus.
I want to perform action on button click that debugging should be stopped when the button is clicked:
private void button3_Click(object sender, EventArgs e)
{
//write code here to stop debugging
}
How do you mean 'stop debugging' you can use the Detach option in Visual Studio, but that isn't in code. To exit the application while debugging use this (windows forms code):
if (Debugger.IsAttached)
{
Application.Exit();
}
If you are after programmatically detaching debugger, you need to get a reference to the currently running EnvDTE80.DTE2 object. Once you have that, you could try:
var dte = ...
dte.Debugger.DetachAll()
To get a reference to EnvDTE80.DTE2, adabyron's approach seems to work:
Get the reference of the DTE2 object in Visual C# 2010
You can wrap it all in some class like so:
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using EnvDTE80;
class DetachDebugger
{
[DllImport("ole32.dll")]
private static extern void CreateBindCtx(int reserved, out IBindCtx ppbc);
[DllImport("ole32.dll")]
private static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot);
public static void Detach()
{
var dte = GetCurrent();
dte.Debugger.DetachAll();
}
/// <summary>
/// Gets the current visual studio's solution DTE2
/// </summary>
private static DTE2 GetCurrent()
{
List<DTE2> dte2s = new List<DTE2>();
IRunningObjectTable rot;
GetRunningObjectTable(0, out rot);
IEnumMoniker enumMoniker;
rot.EnumRunning(out enumMoniker);
enumMoniker.Reset();
IntPtr fetched = IntPtr.Zero;
IMoniker[] moniker = new IMoniker[1];
while (enumMoniker.Next(1, moniker, fetched) == 0)
{
IBindCtx bindCtx;
CreateBindCtx(0, out bindCtx);
string displayName;
moniker[0].GetDisplayName(bindCtx, null, out displayName);
// add all VisualStudio ROT entries to list
if (displayName.StartsWith("!VisualStudio"))
{
object comObject;
rot.GetObject(moniker[0], out comObject);
dte2s.Add((DTE2)comObject);
}
}
// get path of the executing assembly (assembly that holds this code) - you may need to adapt that to your setup
string thisPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
// compare dte solution paths to find best match
KeyValuePair<DTE2, int> maxMatch = new KeyValuePair<DTE2, int>(null, 0);
foreach (DTE2 dte2 in dte2s)
{
int matching = GetMatchingCharsFromStart(thisPath, dte2.Solution.FullName);
if (matching > maxMatch.Value)
maxMatch = new KeyValuePair<DTE2, int>(dte2, matching);
}
return (DTE2)maxMatch.Key;
}
/// <summary>
/// Gets index of first non-equal char for two strings
/// Not case sensitive.
/// </summary>
private static int GetMatchingCharsFromStart(string a, string b)
{
a = (a ?? string.Empty).ToLower();
b = (b ?? string.Empty).ToLower();
int matching = 0;
for (int i = 0; i < Math.Min(a.Length, b.Length); i++)
{
if (!char.Equals(a[i], b[i]))
break;
matching++;
}
return matching;
}
}
Then, using your event handler:
private void button3_Click(object sender, EventArgs e)
{
//write code here to stop debugging
DetachDebugger.Detach();
}
Let me give you the background.
We have an Application(medium sized) that is using MessageBox.Show (....) at various places (in hundreds).
These message boxes are part of workflow and being used for informing,warning or taking input from an user. Application is supposed to automatically log off after certain time if there is no activity. We have a requirement that while logging out the application, just to clean the session data , to clear views and to hide itself so that in next launch, it won't have to execute the startup process which is costly in terms of time.
Everything is working fine but in a scenario when there is some message box on the screen and user left the machine without responding to message box and then due to no activity to make the application to log out. Problem is Message box won't disappear.
How I can close the opened messagebox, if any, while hiding the application?
Here is a piece of code based on UIAutomation (a cool but still not very used API) that attempts to close all modal windows (including the one opened with MessageBox) of the current process:
/// <summary>
/// Attempt to close modal windows if there are any.
/// </summary>
public static void CloseModalWindows()
{
// get the main window
AutomationElement root = AutomationElement.FromHandle(Process.GetCurrentProcess().MainWindowHandle);
if (root == null)
return;
// it should implement the Window pattern
object pattern;
if (!root.TryGetCurrentPattern(WindowPattern.Pattern, out pattern))
return;
WindowPattern window = (WindowPattern)pattern;
if (window.Current.WindowInteractionState != WindowInteractionState.ReadyForUserInteraction)
{
// get sub windows
foreach (AutomationElement element in root.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window)))
{
// hmmm... is it really a window?
if (element.TryGetCurrentPattern(WindowPattern.Pattern, out pattern))
{
// if it's ready, try to close it
WindowPattern childWindow = (WindowPattern)pattern;
if (childWindow.Current.WindowInteractionState == WindowInteractionState.ReadyForUserInteraction)
{
childWindow.Close();
}
}
}
}
}
For example, if you have a WinForms application that pops up a MessageBox when you press some button1, you will still be able to close the app using Windows "Close Window" menu (right click in the task bar):
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("Don't click me. I want to be closed automatically!");
}
protected override void WndProc(ref System.Windows.Forms.Message m)
{
const int WM_SYSCOMMAND = 0x0112;
const int SC_CLOSE = 0xF060;
if (m.Msg == WM_SYSCOMMAND) // this is sent even if a modal MessageBox is shown
{
if ((int)m.WParam == SC_CLOSE)
{
CloseModalWindows();
Close();
}
}
base.WndProc(ref m);
}
You could use CloseModalWindows somewhere else in your code of course, this is just a sample.
This link on MSDN forums shows how to close a message box by using FindWindow and sending a WM_CLOSE message. Although the question was asked for .NET/WindowsCE, it might solve your problem, its worth a look
Refer to DmitryG post in "Close a MessageBox after several seconds"
Auto-Close MessageBox after timeout reach
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
public class AutoClosingMessageBox
{
System.Threading.Timer _timeoutTimer;
string _caption;
AutoClosingMessageBox(string text, string caption, int timeout)
{
_caption = caption;
_timeoutTimer = new System.Threading.Timer(OnTimerElapsed,
null, timeout, System.Threading.Timeout.Infinite);
MessageBox.Show(text, caption);
}
public static void Show(string text, string caption, int timeout)
{
new AutoClosingMessageBox(text, caption, timeout);
}
void OnTimerElapsed(object state)
{
IntPtr mbWnd = FindWindow(null, _caption);
if (mbWnd != IntPtr.Zero)
SendMessage(mbWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
_timeoutTimer.Dispose();
}
const int WM_CLOSE = 0x0010;
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
}
and Call it via
AutoClosingMessageBox.Show("Content", "Title", TimeOut);
First a Question: If messages boxes are used as part of workflow, won't programatically closing message box cause the flow to change/continue?
I think you have three options
Create your own version of the messagebox class that opens a dialog window that looks like a messagebox with added functionality so it closed automatically after a period of time.
Implement something like this in c# to close message boxes programtically.
http://www.codeproject.com/KB/dialog/AutoCloseMessageBox.aspx
Get rid of the message boxes from interupting the workflow. This is probably the best solution as from the sound of it closing a message box programatically will cause workflow to continue/change, and perhaps even cause another messagebox to show which may not be desirable. But obviously fixing the root problem might be best, but isn't always the easiest.
1 and 2 would need to be done from a separate thread, so you will need to think about the implications of that as showing the messagebox will be blocking.
Heres my example with SendKeys - tested and working:
lets say we have backgroundworker and button in form. After button was click - start worker and show message box. In workers DoWork event sleep for 5s and then send enter key - messsage box closed.
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
MessageBox.Show("Close this message!");
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(5000);
SendKeys.SendWait("{Enter}");//or Esc
}
This topic has been abundantly covered in other SO questions but since this particular one has several answers about using UI automation/window lookup techniques (which I don't particularly like) and generic suggestions about creating own dialog without provided code, I decided post my own solution. One can create an instantiable MessageBox like class as it follows:
using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Text.RegularExpressions;
namespace Common
{
// Loosely based on: https://www.codeproject.com/Articles/17253/A-Custom-Message-Box
class MsgBox : Form
{
private Panel _plHeader = new Panel();
private Panel _plFooter = new Panel();
private Panel _plIcon = new Panel();
private PictureBox _picIcon = new PictureBox();
private FlowLayoutPanel _flpButtons = new FlowLayoutPanel();
private Label _lblMessage;
private MsgBox()
{
FormBorderStyle = FormBorderStyle.FixedDialog;
BackColor = Color.White;
StartPosition = FormStartPosition.CenterScreen;
MinimizeBox = false;
MaximizeBox = false;
ShowIcon = false;
Width = 400;
_lblMessage = new Label();
_lblMessage.Font = new Font("Segoe UI", 10);
_lblMessage.Dock = DockStyle.Fill;
_lblMessage.TextAlign = ContentAlignment.MiddleLeft;
_flpButtons.FlowDirection = FlowDirection.RightToLeft;
_flpButtons.Dock = DockStyle.Fill;
//_plHeader.FlowDirection = FlowDirection.TopDown;
_plHeader.Dock = DockStyle.Fill;
_plHeader.Padding = new Padding(20);
_plHeader.Controls.Add(_lblMessage);
_plFooter.Dock = DockStyle.Bottom;
_plFooter.BackColor = Color.FromArgb(240, 240, 240);
_plFooter.Padding = new Padding(10);
_plFooter.Height = 60;
_plFooter.Controls.Add(_flpButtons);
_picIcon.Location = new Point(30, 50);
_plIcon.Dock = DockStyle.Left;
_plIcon.Padding = new Padding(20);
_plIcon.Width = 70;
_plIcon.Controls.Add(_picIcon);
Controls.Add(_plHeader);
Controls.Add(_plIcon);
Controls.Add(_plFooter);
}
public static DialogResult Show(IWin32Window owner, string message, string title = null, MessageBoxButtons? buttons = MessageBoxButtons.OK, MessageBoxIcon icon = MessageBoxIcon.Information)
{
var msgBox = Create(message, title, buttons, icon);
return msgBox.ShowDialog(owner);
}
public static DialogResult Show(string message, string title = null, MessageBoxButtons? buttons = MessageBoxButtons.OK, MessageBoxIcon icon = MessageBoxIcon.Information)
{
var msgBox = Create(message, title, buttons, icon);
return msgBox.ShowDialog();
}
public static MsgBox Create(string message, string title = null, MessageBoxButtons? buttons = MessageBoxButtons.OK, MessageBoxIcon icon = MessageBoxIcon.Information)
{
var msgBox = new MsgBox();
msgBox.Init(message, title, buttons, icon);
return msgBox;
}
void Init(string message, string title, MessageBoxButtons? buttons, MessageBoxIcon icon)
{
_lblMessage.Text = message;
Text = title;
InitButtons(buttons);
InitIcon(icon);
Size = MessageSize(message);
}
void InitButtons(MessageBoxButtons? buttons)
{
if (!buttons.HasValue)
return;
switch (buttons)
{
case MessageBoxButtons.AbortRetryIgnore:
AddButton("Ignore");
AddButton("Retry");
AddButton("Abort");
break;
case MessageBoxButtons.OK:
AddButton("OK");
break;
case MessageBoxButtons.OKCancel:
AddButton("Cancel");
AddButton("OK");
break;
case MessageBoxButtons.RetryCancel:
AddButton("Cancel");
AddButton("Retry");
break;
case MessageBoxButtons.YesNo:
AddButton("No");
AddButton("Yes");
break;
case MessageBoxButtons.YesNoCancel:
AddButton("Cancel");
AddButton("No");
AddButton("Yes");
break;
}
}
void InitIcon(MessageBoxIcon icon)
{
switch (icon)
{
case MessageBoxIcon.None:
_picIcon.Hide();
break;
case MessageBoxIcon.Exclamation:
_picIcon.Image = SystemIcons.Exclamation.ToBitmap();
break;
case MessageBoxIcon.Error:
_picIcon.Image = SystemIcons.Error.ToBitmap();
break;
case MessageBoxIcon.Information:
_picIcon.Image = SystemIcons.Information.ToBitmap();
break;
case MessageBoxIcon.Question:
_picIcon.Image = SystemIcons.Question.ToBitmap();
break;
}
_picIcon.Width = _picIcon.Image.Width;
_picIcon.Height = _picIcon.Image.Height;
}
private void ButtonClick(object sender, EventArgs e)
{
Button btn = (Button)sender;
switch (btn.Text)
{
case "Abort":
DialogResult = DialogResult.Abort;
break;
case "Retry":
DialogResult = DialogResult.Retry;
break;
case "Ignore":
DialogResult = DialogResult.Ignore;
break;
case "OK":
DialogResult = DialogResult.OK;
break;
case "Cancel":
DialogResult = DialogResult.Cancel;
break;
case "Yes":
DialogResult = DialogResult.Yes;
break;
case "No":
DialogResult = DialogResult.No;
break;
}
Close();
}
private static Size MessageSize(string message)
{
int width=350;
int height = 230;
SizeF size = TextRenderer.MeasureText(message, new Font("Segoe UI", 10));
if (message.Length < 150)
{
if ((int)size.Width > 350)
{
width = (int)size.Width;
}
}
else
{
string[] groups = (from Match m in Regex.Matches(message, ".{1,180}") select m.Value).ToArray();
int lines = groups.Length+1;
width = 700;
height += (int)(size.Height+10) * lines;
}
return new Size(width, height);
}
private void AddButton(string caption)
{
var btn = new Button();
btn.Text = caption;
btn.Font = new Font("Segoe UI", 8);
btn.BackColor = Color.FromArgb(225, 225, 225);
btn.Padding = new Padding(3);
btn.Height = 30;
btn.Click += ButtonClick;
_flpButtons.Controls.Add(btn);
}
}
}
One can then just keep the reference of the dialog in a class scope, show the dialog and get the result, or just close it in an application exit event handler.
MsgBox _msgBox;
void eventHandler1(object sender, EventArgs e)
{
_msgBox = MsgBox.Create("Do you want to continue", "Inquiry", MessageBoxButtons.YesNo);
var result = _msgBox.ShowDialog();
// do something with result
}
void applicationExitHandler(object sender, EventArgs e)
{
if (_msgBox != null)
_msgBox.Close();
}
I think the cleanest way would be to implement you own message box form like
class MyMessageBox : Form {
private MyMessageBox currentForm; // The currently active message box
public static Show(....) { // same as MessageBox.Show
// ...
}
public static Show(...) { // define additional overloads
}
public static CloseCurrent() {
if (currentForm != null)
currentForm.Close();
}
// ...
}
In some of my larger projects, I found this approach useful also for other purposes (such as automatic logging of error messages etc.)
The second idea I have would be to use GetTopWindow() (or maybe some other WIN32 function) to get the current top-level window of your application and send a WM_CLOSE message to it.
Taking as an assumption that you can edit the code that's calling the
MessageBox.Show() method, I would recommend not use
MessageBox. Instead, just use your own custom form, calling ShowDialog()
on it to do basically the same thing as the MessageBox class. Then, you
have the instance of the form itself, and you can call Close() on that
instance to close it.
A good example is here.
I used .net 2 and two approaches with the same trick.
Open the MessageBox from stub-Form with MessageBox.Show(this,"message")
When the form is not visible or doesn't has really UI.
Keep the form handler and close it with:
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
or
holding the form as class parameter and using FormX.Close().
Since the Form is the owner of the MessageBox, Closing it will close the MessageBox.
The easiest solution is to create a form that will close on timer_tick
private int interval = 0;
private string message = "";
public msgBox(string msg = "", int i = 0)
{
InitializeComponent();
interval = i;
message = msg;
}
private void MsgBox_Load(object sender, EventArgs e)
{
if (interval > 0)
timer1.Interval = interval;
lblMessage.Text = message;
lblMessage.Width = panel1.Width - 20;
lblMessage.Left = 10;
}
private void Timer1_Tick(object sender, EventArgs e)
{
this.Close();
}
private void Panel1_Paint(object sender, PaintEventArgs e)
{
ControlPaint.DrawBorder(e.Graphics, this.panel1.ClientRectangle, Color.DarkBlue, ButtonBorderStyle.Solid);
}
Method to use in main form
private void showMessage(string msg, int interval = 0)
{
msgBox mb = new msgBox(msg, interval);
mb.ShowDialog(this);
}
Call it
showMessage("File saved");
Create your own control for this and implement behavior you like to have there. As an option there may be a timer to close this MessageBox.
a program of mine uses AxShockwaveFlash component used as stream player.
The problem is that my code works with most stream-providers (livestream, ustream, own3d.tv) but Justin.TV's player is somewhat problematic.
Before moving on the actual problem let me summarize my code;
Inherited FlashControl - this allows me to override the flashplayer's built-in menu:
public class FlashPlayer : AxShockwaveFlashObjects.AxShockwaveFlash // Customized Flash Player.
{
private const int WM_MOUSEMOVE = 0x0200;
private const int WM_MOUSEWHEEL = 0x020A;
private const int WM_LBUTTONDOWN = 0x0201;
private const int WM_LBUTTONUP = 0x0202;
private const int WM_LBUTTONDBLCLK = 0x0203;
private const int WM_RBUTTONDOWN = 0x0204;
private const int WM_RBUTTONUP = 0x0205;
public new event MouseEventHandler DoubleClick;
public new event MouseEventHandler MouseDown;
public new event MouseEventHandler MouseUp;
public new event MouseEventHandler MouseMove;
public FlashPlayer():base()
{
this.HandleCreated += FlashPlayer_HandleCreated;
}
void FlashPlayer_HandleCreated(object sender, EventArgs e)
{
this.AllowFullScreen = "true";
this.AllowNetworking = "all";
this.AllowScriptAccess = "always";
}
protected override void WndProc(ref Message m) // Override's the WndProc and disables Flash activex's default right-click menu and if exists shows the attached ContextMenuStrip.
{
if (m.Msg == WM_LBUTTONDOWN)
{
if (this.MouseDown != null) this.MouseDown(this, new MouseEventArgs(System.Windows.Forms.MouseButtons.Left, 1, Cursor.Position.X, Cursor.Position.Y, 0));
}
else if (m.Msg == WM_LBUTTONUP)
{
if (this.MouseUp != null) this.MouseUp(this, new MouseEventArgs(System.Windows.Forms.MouseButtons.None, 0, Cursor.Position.X, Cursor.Position.Y, 0));
}
else if (m.Msg == WM_MOUSEMOVE)
{
if (this.MouseMove != null) this.MouseMove(this, new MouseEventArgs(System.Windows.Forms.MouseButtons.None, 0, Cursor.Position.X, Cursor.Position.Y, 0));
}
else if (m.Msg == WM_RBUTTONDOWN)
{
if (this.ContextMenuStrip != null) this.ContextMenuStrip.Show(Cursor.Position.X, Cursor.Position.Y);
m.Result = IntPtr.Zero;
return;
}
else if (m.Msg == WM_LBUTTONDBLCLK)
{
if (this.DoubleClick != null) this.DoubleClick(this, new MouseEventArgs(System.Windows.Forms.MouseButtons.Left, 2, Cursor.Position.X, Cursor.Position.Y, 0));
m.Result = IntPtr.Zero;
return;
}
base.WndProc(ref m);
}
}
Player window code: (Player is an instance of FlashPlayer)
private void Player_Load(object sender, EventArgs e)
{
try
{
this.Text = string.Format("Stream: {0}", this._stream.Name); // set the window title.
this.Player.LoadMovie(0, this._stream.Movie); // load the movie.
if (this._stream.ChatAvailable && Settings.Instance.AutomaticallyOpenChat) this.OpenChatWindow();
}
catch (Exception exc)
{
// log stuff.
}
}
So this works great for livestream.com, ustream.com, own3d.tv but when it come's to justin.tv's player i'm getting a 1337 error (invalid embed code). So i tried to ask them for support but could't get a valid answer.
_stream.movie variable actually holds a valid URL for the stream source like;
http://cdn.livestream.com/grid/LSPlayer.swf?channel=%slug%&autoPlay=true (livestream sample)
or
http://www.justin.tv/widgets/live_embed_player.swf?channel=%slug%&auto_play=true&start_volume=100 (justin.tv sample)
Tried to urlencode the 'channel=%slug%&auto_play=true&start_volume=100' part for justin.tv but that did not work also.
So i started trying some work-arounds which at first place i thought setting flashVars variable of the control.
But i've a strange problem there, whenever i try to set flashVars variable it never get's set. I found a sample screenshot on the issue;
So if i was able to set the flashVariables may be i could work-around the justin.tv player's error. Btw, i also tried setting variables using Player.SetVariable(key,value) - that didn't work also.
Notes:
I'm running on .net 4.0 client profile.
Using the Flash10l.ocx.
Have generated the AxShockwaveFlashObjects.dll, ShockwaveFlashObjects.dll wrappers using "aximp.exe –source "C:\WINDOWS\system32\Macromed\Flash\Flash10l.ocx"
I recently had an issue with making justin.tv work, but in the end it was as simple as
axShockwaveFlash1.FlashVars = "auto_play=true&channel=adventuretimed&start_volume=25";
axShockwaveFlash1.Movie = "http://www.justin.tv/widgets/live_embed_player.swf";
and it works perfectly