A프로그램에서 B프로그램에게 요청하여 동작을 할 일이 있었습니다.

B프로그램은 초기화 되며 열려있는 창들이 닫혀야 했는데 이 부분에 대한 구현이 필요했습니다.

 

ex)

Program (B) 기능 -> OpenFileDialog (윈도우 API) Custom Form (사용자Form)

 

Program (B) 가 ShowDialog 로 잡혀있는 상황입니다.

윈도우API 종료는 SendMessage 를 사용해야 하고, Form은 Close를 통해 종료해 줄 수 있습니다.

 

(NamedPipe를 사용하였고, BlockingCollection Queue 를 사용하여 순서유지를 보장하였습니다.

코드가 좀 길어졌지만.. 남겨봅니다!

 

ShowDialog() 종료하는 프로그램

 

A프로그램 (명령 내리는 코드)

using System;
using System.IO;
using System.IO.Pipes;
using System.Windows.Forms;

namespace WindowsFormsApp6
{
    public partial class Form2 : Form
    {
        private const string targetName = "A_Pipe";

        public Form2()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            SendNamedPipe("CloseAPI");
        }

        private void button2_Click(object sender, EventArgs e)
        {
            SendNamedPipe("CloseSubForm");
        }

        private void SendNamedPipe(string message)
        {
            try
            {
                NamedPipeClientStream namedPipeClientStream = new NamedPipeClientStream(".", targetName, PipeDirection.InOut);
                namedPipeClientStream.Connect(10000); //10초

                StreamWriter streamWriter = new StreamWriter(namedPipeClientStream);

                streamWriter.WriteLine(message);
                streamWriter.Flush();

                streamWriter.Close();
                namedPipeClientStream.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
    }
}

 

 

B프로그램 (ShowDialog 하는 프로그램)

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form3 : Form
    {
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        private const uint WM_CLOSE = 0x0010;
        private const string myName = "A_Pipe"; //이름만 바꿔서 사용 가능

        private BlockingCollection<string> queue = new BlockingCollection<string>();
        private int queueCount = 0;

        private void ProcessQueue()
        {
            //내부적으로 monitor lock 걸려있어 순서 및 단일 실행 보장
            foreach (string message in queue.GetConsumingEnumerable())
            {
                if (message == "CloseAPI")
                {
                    CloseAPI();
                }
                else if (message == "CloseSubForm")
                {
                    CloseSubForm();
                }

                Invoke((MethodInvoker)delegate
                {
                    queueCount++;
                    listBox1.Items.Add(string.Format("{0}_{1}", queueCount, message));
                });
            }
        }

        public Form3()
        {
            InitializeComponent();

            //큐에서 관리
            Task.Run(() =>
            {
                ProcessQueue();
            });

            //네임드파이프 통신
            Task.Run(() =>
            {
                Receive();
            });
        }

        private void Receive()
        {
            while (true)
            {
                try
                {
                    NamedPipeServerStream namedPipeServerStream = new NamedPipeServerStream(myName, PipeDirection.InOut, 10);
                    namedPipeServerStream.WaitForConnection(); //데이터 받을때까지 기다립니다.

                    StreamReader streamReader = new StreamReader(namedPipeServerStream);
                    string message = streamReader.ReadLine();

                    queue.Add(message); //큐에 데이터 쌓아주기

                    streamReader.Close();
                    namedPipeServerStream.Close();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Title = "불러오기 테스트";

            //테스트하기 위해 띄워주기만 함.
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                //정상 OK 눌렀을 때 실행
            }
            else
            {
                //강제 종료시 이 곳을 실행.
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            //테스트용으로 단순 띄워주기만 진행
            new Form1().ShowDialog();
        }

        private void CloseAPI()
        {
            IntPtr hWnd = FindWindow(null, "불러오기 테스트"); //타이틀명으로 찾기
            if (hWnd != IntPtr.Zero)
            {
                SendMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero); //종료 메시지 보내기
            }
        }

        private void CloseSubForm()
        {
            List<Form> formList = new List<Form>();

            foreach (Form form in Application.OpenForms)
            {
                // 메인폼 제외
                if (form is Form3 == false)
                {
                    formList.Add(form);
                }
            }

            foreach (Form form in formList)
            {
                Invoke((MethodInvoker)delegate
                {
                    form.Close();
                });
            }
        }
    }
}

+ Recent posts