我想创建一个使用 ClickOnce 进行安装并注册文件关联的程序,并且始终只启动一个实例,这样如果再次单击该文件扩展名的文件,它将被发送到第一个(已经打开的)程序.
有人知道如何做到这一点的好代码示例吗?
请记住 ClickOnce 部分 - 因为这会改变处理 SingleInstance 位的方式。
我想创建一个使用 ClickOnce 进行安装并注册文件关联的程序,并且始终只启动一个实例,这样如果再次单击该文件扩展名的文件,它将被发送到第一个(已经打开的)程序.
有人知道如何做到这一点的好代码示例吗?
请记住 ClickOnce 部分 - 因为这会改变处理 SingleInstance 位的方式。
您应该使用 Mutex 来检查您的应用程序是否正在运行:
static void Main()
{
bool createdNew;
using (Mutex mutex = new Mutex(true, Application.ProductName, out createdNew))
{
mutex.ReleaseMutex();
if (createdNew)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FormMain());
}
else
{
using (Process currentProcess = Process.GetCurrentProcess())
{
foreach (Process process in Process.GetProcessesByName(currentProcess.ProcessName))
{
if (process.Id != currentProcess.Id)
{
User32.SetForegroundWindow(process.MainWindowHandle);
break;
}
}
}
}
}
}
设置前景窗口:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
同样的问题在这里:如何使用 Click Once 构建单实例应用程序?
试试这个: http: //northhorizon.net/2010/single-instance-clickonce/
我制作了一个以这种方式工作的应用程序。它使用 Windows 消息进行通信。所以在第二个实例中,您只需要第一个实例中的 MainForm 的句柄。我将此句柄保存在名为 hwnd 的 ClickOnce 设置中。
using ProjectApplicationTemplate.Properties;
using System;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.Hosting;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
namespace ProjectApplicationTemplate
{
static class Program
{
static Mutex mutex = new Mutex(true, guid());
static string guid()
{
// http://stackoverflow.com/questions/502303/how-do-i-programmatically-get-the-guid-of-an-application-in-net2-0
Assembly assembly = Assembly.GetExecutingAssembly();
var attribute = (GuidAttribute)assembly.GetCustomAttributes(typeof(GuidAttribute), true)[0];
return attribute.Value;
}
static int MainWindowHandle
{
get
{
Settings.Default.Reload();
return Settings.Default.hwnd;
}
set
{
Settings sett = Settings.Default;
sett.hwnd = value;
sett.Save();
}
}
public static string GetFileName()
{
ActivationArguments a = AppDomain.CurrentDomain.SetupInformation.ActivationArguments;
// aangeklikt bestand achterhalen
string[] args = a == null ? null : a.ActivationData;
return args == null ? "" : args[0];
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
if (mutex.WaitOne(TimeSpan.Zero, true))
{
#region standaard
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
#endregion
MainForm frm = new MainForm();
MainWindowHandle = (int)frm.Handle;
Application.Run(frm);
MainWindowHandle = 0;
mutex.ReleaseMutex();
}
else
{
int hwnd = 0;
while (hwnd == 0)
{
Thread.Sleep(5);
hwnd = MainWindowHandle;
}
Win32.CopyDataStruct cds = new Win32.CopyDataStruct();
try
{
string data = GetFileName();
cds.cbData = (data.Length + 1) * 2; // number of bytes
cds.lpData = Win32.LocalAlloc(0x40, cds.cbData); // known local-pointer in RAM
Marshal.Copy(data.ToCharArray(), 0, cds.lpData, data.Length); // Copy data to preserved local-pointer
cds.dwData = (IntPtr)1;
Win32.SendMessage((IntPtr)hwnd, Win32.WM_COPYDATA, IntPtr.Zero, ref cds);
}
finally
{
cds.Dispose();
}
}
}
}
}
在你的 MainForm
using System;
using System.Data;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Windows.Forms;
namespace ProjectApplicationTemplate
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
OpenFile(Program.GetFileName());
}
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case Win32.WM_COPYDATA:
Win32.CopyDataStruct st = (Win32.CopyDataStruct)Marshal.PtrToStructure(m.LParam, typeof(Win32.CopyDataStruct));
string strData = Marshal.PtrToStringUni(st.lpData);
OpenFile(strData);
Activate();
break;
default:
// let the base class deal with it
base.WndProc(ref m);
break;
}
}
void OpenFile(string filename)
{
if (filename == "") return;
if (!File.Exists(filename)) return;
IDocument[] vensters = MdiChildren.Select(T => (IDocument)T).Where(T => T.CurrentFileName == filename).ToArray();
if (vensters.Length == 0)
{
ChildForm frm = new ChildForm();
frm.OpenFile(filename);
frm.MdiParent = this;
frm.Show();
}
else
{
vensters[0].Activate();
}
}
private void fileMenu_DropDownOpening(object sender, EventArgs e)
{
IDocument active = (IDocument)ActiveMdiChild;
if (active == null)
{
saveToolStripMenuItem.Enabled = false;
saveAsToolStripMenuItem.Enabled = false;
printToolStripMenuItem.Enabled = false;
printSetupToolStripMenuItem.Enabled = false;
printPreviewToolStripMenuItem.Enabled = false;
}
else
{
saveToolStripMenuItem.Enabled = active.Changed;
saveAsToolStripMenuItem.Enabled = true;
printToolStripMenuItem.Enabled = active.CanPrint;
printSetupToolStripMenuItem.Enabled = active.CanPrint;
printPreviewToolStripMenuItem.Enabled = active.CanPrint;
}
// fill the MRU-list
tmiOnlangsGeopend.DropDownItems.Clear();
string RecentFolder = Environment.GetFolderPath(Environment.SpecialFolder.Recent);
string[] bestanden = Directory.GetFiles(RecentFolder).Where(T => T.EndsWith(".text.lnk")).ToArray();
if (bestanden.Length == 0)
{
tmiOnlangsGeopend.DropDownItems.Add(new ToolStripMenuItem(Properties.Resources.NoRecent) { Enabled = false });
}
else
{
foreach (string bestand in bestanden.OrderBy(T => File.GetLastWriteTime(T)).Reverse())
{
ToolStripMenuItem tmi = new ToolStripMenuItem(Path.GetFileNameWithoutExtension(bestand.Substring(0, bestand.Length - 4)));
tmi.Click += delegate { OpenFile(ResolveShortCut(bestand)); };
tmiOnlangsGeopend.DropDownItems.Add(tmi);
}
}
}
string ResolveShortCut(string shc)
{
// Add Reference -> COM -> Windows Script Host Object Model
if (File.Exists(shc))
{
IWshRuntimeLibrary.WshShell shell = new IWshRuntimeLibrary.WshShell();
IWshRuntimeLibrary.IWshShortcut link = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(shc);
return link.TargetPath;
}
else
{
return "";
}
}
}
}
Win32.cs
using System;
using System.Runtime.InteropServices;
namespace ProjectApplicationTemplate
{
public partial class Win32
{
public const int WM_COPYDATA = 0x004A;
public struct CopyDataStruct : IDisposable
{
public IntPtr dwData;
public int cbData;
public IntPtr lpData;
public void Dispose()
{
if (this.lpData != IntPtr.Zero)
{
LocalFree(this.lpData);
this.lpData = IntPtr.Zero;
}
}
}
/// <summary>
/// The SendMessage API
/// </summary>
/// <param name="hWnd">handle to the required window</param>
/// <param name="Msg">the system/Custom message to send</param>
/// <param name="wParam">first message parameter</param>
/// <param name="lParam">second message parameter</param>
/// <returns></returns>
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref CopyDataStruct lParam);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LocalAlloc(int flag, int size);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LocalFree(IntPtr p);
}
}
如果有人想了解更多信息: http ://pieterjan.pro/?a=Projecten_csharp_DrawIt.php
而这个是 ac# 模板,包含大量内容: - 具有文件关联的单实例应用程序 - 本地化(在运行时也是如此) - MDI 和用于遍历用户命令的界面 - 检查更新 - 最近使用的列表
http://pieterjan.pro/Projecten/csharp/ProjectApplicationTemplate.zip
你可以做类似这样的事情:
using System.Diagnostics;
namespace Foo
{
class Bar
{
static void Main(string[] args)
{
Process p = Process.GetCurrentProcess();
Process [] processSearch = Process.GetProcessesByName(p.ProcessName);
if (processSearch.Length > 1)
{
return;
}
}
}
}