Comic Coder
Comic Coder

Reputation: 549

Check if dll launched from another application is already open

I work with an application (lets say application A) that I write add on modifications for.

The application A has functionality to allow scripts to call class librarys or exe files. It works by taking a parameter object created by the application A and passes it into the class library (lets call it Application B)

Application A is pretty much a black box that I have no idea what the code looks like or does. I have a script format that takes a parameter object from application A (containing relevant information about the calling program, for example: current user, user language, item application B was launched from etc etc) and passes it into application B. This script functionality is set up using a Administrator panel that is part of application A.

The launcher script must use form.Show() and not form.ShowDialog() to open application B as the user must be able to access application A while application B is open (Data checking and so forth).

Now I want to be able to prevent application B from opening multiple times as is currently possible, because it has been launched using form.Show() and not form.ShowDialog() however I can't seem to find a suitable way to do this.

I firstly tried checking the current processes but have found that application B is not listed here as it is launched by the application A.

  1. M3 Sales Automation is Application A
  2. New Customer is Application B

This can be seen from the following screen shots from my task manager:

Task Manager (Applications Tab) Task Manager (Processes Tab) Both M3 Sales Automation and New Customer are listed in the applications section, but only M3 Sales Automation is listed in the processes section.

Initially I tried accessing the processes but found that as its not actually listed there I can't check that and had to look a little deeper. Now I did some more checking and found that the NewCustomer.dll is listed in the ProcessModules for the current process.

I used the following code in the launcher script to get the information:

        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");
        }

This outputted a long list of dll's that are part of application A. Now I thought that I could perphaps look to see if the NewCustomer.dll was listed more than once and if this occurred then prevent launch of the application as it would already be open. This was not the case however and the NewCustomer.dll is only listed once no matter how many times it is open.

So now my next thought is to look and see if I can access what is shown in the Task Manager Applications Tab. If my program is listed there then I want to prevent it opening again.

Does anyone have any Idea how to acheive this?

I'm not even sure what I should be searching for as everytime I try to search I get answers talking about looking in the Processes which is not relevant here.

Upvotes: 0

Views: 928

Answers (2)

Comic Coder
Comic Coder

Reputation: 549

Actually after looking at the code jlvaquero posted above I found the following on the same site

EnumDesktopWindows (user32)

I added the following using statements to my laucher script:

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

I then added the following class to my launcher script

    /// <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);
}

I then added the following function in my launch script to call the new class and do the processing to discover the active windows

/// <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;
    }

And finally I modified my launch function to include the check for the active windows

/// <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);
        }
    }

Hope this helps anyone else with the same problem

Regards,

Comic Coder

Upvotes: 1

jlvaquero
jlvaquero

Reputation: 8785

In Application tab in Windows Task Manager you see the list of windows opened in the system, but there is only one process (1 application) wich onws the 2 windows.

This code is for search a window in the system. Maybe is useful for you because you can search by "New Customer" title or maybe it's a good start for your future research.

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);
}

Then you'd call:

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

Code from pinvoke.net.

Upvotes: 1

Related Questions