0

我使用我编写的添加修改的应用程序(假设是应用程序 A)。

应用程序 A 具有允许脚本调用类库或 exe 文件的功能。它通过获取应用程序 A 创建的参数对象并将其传递到类库(我们称之为应用程序 B)来工作

应用程序 A 几乎是一个黑盒子,我不知道代码是什么样子或做了什么。我有一个脚本格式,它从应用程序 A 获取参数对象(包含有关调用程序的相关信息,例如:当前用户、用户语言、项目应用程序 B 是从等启动的)并将其传递给应用程序 B。此脚本功能使用作为应用程序 A 一部分的管理员面板进行设置。

启动器脚本必须使用form.Show()而不是form.ShowDialog()打开应用程序 B,因为用户必须能够在应用程序 B 打开时访问应用程序 A(数据检查等)。

现在我希望能够尽可能地防止应用程序 B 多次打开,因为它已经使用form.Show()而不是启动,form.ShowDialog()但是我似乎找不到合适的方法来执行此操作。

我首先尝试检查当前进程,但发现应用程序 B 未在此处列出,因为它是由应用程序 A 启动的。

  1. M3 销售自动化是应用程序 A
  2. 新客户是应用程序 B

这可以从我的任务管理器的以下屏幕截图中看出:

任务管理器(应用程序选项卡) 任务管理器(进程选项卡) M3 销售自动化和新客户都列在应用程序部分,但只有 M3 销售自动化列在流程部分。

最初我尝试访问这些进程,但发现由于它实际上没有在那里列出,所以我无法检查它,不得不更深入地查看。现在我做了更多检查,发现 NewCustomer.dll 列在当前进程的 ProcessModules 中。

我在启动器脚本中使用了以下代码来获取信息:

        public void GetProcessModules()
        {
            ProcessModuleCollection modules = Process.GetCurrentProcess().Modules;
            string modulesOutput = string.Empty;
            foreach (ProcessModule pm in processModuleCollection)
            {
                modulesOutput += pm.ModuleName + ";\r\n";
            }

            MessageBox.Show(modulesOutput, "Modules");
        }

这输出了一长串属于应用程序 A 的 dll。现在我想我可以看看是否多次列出 NewCustomer.dll,如果发生这种情况,则阻止启动应用程序,因为它已经打开. 然而情况并非如此,NewCustomer.dll 无论打开多少次都只会列出一次。

所以现在我的下一个想法是看看我是否可以访问任务管理器应用程序选项卡中显示的内容。如果我的程序在那里列出,那么我想阻止它再次打开。

有谁知道如何实现这一目标?

我什至不确定我应该搜索什么,因为每次我尝试搜索时,我都会得到关于在此处不相关的流程中查找的答案。

4

2 回答 2

1

在 Windows 任务管理器的应用程序选项卡中,您会看到系统中打开的窗口列表,但只有一个进程(1 个应用程序)在 2 个窗口上。

此代码用于在系统中搜索窗口。也许对您有用,因为您可以按“新客户”标题搜索,或者这可能是您未来研究的良好开端。

using System.Runtime.InteropServices;
using System.Text;

public class WndSearcher
{
    public static IntPtr SearchForWindow(string wndclass, string title)
    {
        SearchData sd = new SearchData { Wndclass=wndclass, Title=title };
        EnumWindows(new EnumWindowsProc(EnumProc), ref sd);
        return sd.hWnd;
    }

    public static bool EnumProc(IntPtr hWnd, ref SearchData data)
    {
        // Check classname and title 
        // This is different from FindWindow() in that the code below allows partial matches
        StringBuilder sb = new StringBuilder(1024);
        GetClassName(hWnd, sb, sb.Capacity);
        if (sb.ToString().StartsWith(data.Wndclass))
        {
            sb = new StringBuilder(1024);
            GetWindowText(hWnd, sb, sb.Capacity);
            if (sb.ToString().StartsWith(data.Title))
            {
                data.hWnd = hWnd;
                return false;    // Found the wnd, halt enumeration
            }
        }
        return true;
    }

    public class SearchData
    {
        // You can put any dicks or Doms in here...
        public string Wndclass;
        public string Title;
        public IntPtr hWnd;
    } 

    private delegate bool EnumWindowsProc(IntPtr hWnd, ref SearchData data);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, ref SearchData data);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
}

然后你会打电话:

// If you're viewing this page with IE, this *should* return the hwnd of the browser
IntPtr hWnd = WndSearcher.SearchForWindow("IEFrame", "pinvoke.net: EnumWindows");

来自pinvoke.net的代码。

于 2012-11-15T12:31:34.617 回答
1

实际上,在查看了上面发布的 jlvaquero 代码后,我在同一个站点上发现了以下内容

EnumDesktopWindows (user32)

我在我的 laucher 脚本中添加了以下 using 语句:

  1. using System.Text;
  2. using System.Runtime.InteropServices;

然后我将以下类添加到我的启动器脚本中

    /// <summary>
/// EnumDesktopWindows Demo - shows the caption of all desktop windows.
/// Authors: Svetlin Nakov, Martin Kulov 
/// Bulgarian Association of Software Developers - http://www.devbg.org/en/
/// </summary>
public class user32
{
    /// <summary>
    /// filter function
    /// </summary>
    /// <param name="hWnd"></param>
    /// <param name="lParam"></param>
    /// <returns></returns>
    public delegate bool EnumDelegate(IntPtr hWnd, int lParam);

    /// <summary>
    /// check if windows visible
    /// </summary>
    /// <param name="hWnd"></param>
    /// <returns></returns>
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool IsWindowVisible(IntPtr hWnd);

    /// <summary>
    /// return windows text
    /// </summary>
    /// <param name="hWnd"></param>
    /// <param name="lpWindowText"></param>
    /// <param name="nMaxCount"></param>
    /// <returns></returns>
    [DllImport("user32.dll", EntryPoint = "GetWindowText",
    ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
    public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpWindowText, int nMaxCount);

    /// <summary>
    /// enumarator on all desktop windows
    /// </summary>
    /// <param name="hDesktop"></param>
    /// <param name="lpEnumCallbackFunction"></param>
    /// <param name="lParam"></param>
    /// <returns></returns>
    [DllImport("user32.dll", EntryPoint = "EnumDesktopWindows",
    ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumDelegate lpEnumCallbackFunction, IntPtr lParam);
}

然后我在我的启动脚本中添加了以下函数来调用新类并进行处理以发现活动窗口

/// <summary>
    /// Checks if application window open.
    /// </summary>
    /// <returns></returns>
    private static bool IfApplicationWindowOpen(string windowName)
    {
        List<string> collection = new List<string>();
        user32.EnumDelegate filter = delegate(IntPtr hWnd, int lParam)
        {
            StringBuilder strbTitle = new StringBuilder(255);
            int nLength = user32.GetWindowText(hWnd, strbTitle, strbTitle.Capacity + 1);
            string strTitle = strbTitle.ToString();

            if (user32.IsWindowVisible(hWnd) && string.IsNullOrEmpty(strTitle) == false)
            {
                collection.Add(strTitle);
            }
            return true;
        };

        if (user32.EnumDesktopWindows(IntPtr.Zero, filter, IntPtr.Zero))
        {
            foreach (string item in collection)
            {
                if (item.ToString().Equals(windowName))
                {
                    return true;
                    break;
                }
            }
        }
        return false;
    }

最后我修改了我的启动功能以包括对活动窗口的检查

/// <summary>
    /// Starts the new customer.
    /// </summary>
    /// <param name="param">The param.</param>
    public static void StartNewCustomer(Parameter param)
    {
        string windowName = "New Customer";
        if (!IfApplicationWindowOpen(windowName))
        {

            GlobalFactory globalfactory = param.GlobalFactory;

            try
            {
                Generic objNewCustomer = new Generic();
                objNewCustomer.StartNewCustomerFromCustomer(param);
            }
            catch (TypeInitializationException tx)
            {
                globalfactory.ErrorHandler.Log(tx, (int)msmsError.ErrorSeverity.Major | (int)msmsError.ErrorSeverity.User);
            }
            catch (Exception ex)
            {
                globalfactory.ErrorHandler.Log(ex, (int)msmsError.ErrorSeverity.Major | (int)msmsError.ErrorSeverity.User);
            }
        }
        else
        {
            MessageBox.Show("The application " + windowName + " is already open", windowName + ": Launch Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }

希望这可以帮助其他有同样问题的人

问候,

漫画编码器

于 2012-11-15T16:09:00.040 回答