通过进程协作显示图像-C#

发布于:2024-07-31 ⋅ 阅读:(126) ⋅ 点赞:(0)

前言

如果一个软件比较复杂或者某些情况下需要拆解,可以考试将软件分解成两个或多个进程,但常规的消息传递又不能完全够用,使用消息+共享内存,实现图像传递,当然性能这个方面我并没有测试,仅是一种解决思路吧。

一、效果展示

1、调用方

2、被调用方

二、实现代码

1、主调打开调用进程

主要是为了拿到Handle,为发送消息函数提供操作句柄。

2、创建共享内存

        /// <summary>
        /// 创建共享内存
        /// </summary>
        /// <returns>0=创建成功;1=创建共享体失败;2=打开失败;3=印射失败; 4=共享内存命名错误</returns>
        public int CreateMemory()
        {
            if (MemSize <= 0) MemSize = 0x00800000;
            if (ShareName.Length > 0)
            {
                //创建内存共享体(INVALID_HANDLE_VALUE)
                m_hSharedMemoryFile = CreateFileMapping(INVALID_HANDLE_VALUE, IntPtr.Zero, (uint)PAGE_READWRITE, 0, (uint)MemSize, ShareName);
                if (m_hSharedMemoryFile == IntPtr.Zero)
                {
                    m_bAlreadyExist = false;
                    m_bInit = false;
                    MemPtr = IntPtr.Zero;
                    return 1; //创建共享体失败
                }
                else
                {
                    if (GetLastError() == ERROR_ALREADY_EXISTS) //已经创建
                    {
                        m_bAlreadyExist = true;
                        CloseHandle(m_hSharedMemoryFile);
                        m_hSharedMemoryFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, ShareName);
                        if (m_hSharedMemoryFile == null)
                        {
                            MemPtr = IntPtr.Zero;
                            return 2;//打开共享内存失败
                        }
                    }
                    else                                         //新创建
                    {
                        m_bAlreadyExist = false;
                    }
                }
                //创建内存映射
                m_rwData = MapViewOfFile(m_hSharedMemoryFile, FILE_MAP_ALL_ACCESS, 0, 0, (uint)MemSize);
                if (m_rwData == IntPtr.Zero)
                {
                    m_bInit = false;
                    CloseHandle(m_hSharedMemoryFile);
                    MemPtr = IntPtr.Zero;
                    return 3; //创建内存映射失败
                }
                else
                {
                    m_bInit = true;
                    MemPtr = m_rwData;
                }
            }
            else
            {
                return 4; //参数错误
            }
            return 0;     //创建成功
        }

3、读取本地图像并写图像数据到共享内存中

 MyAlgoProcessNet.HImage hImage = new MyAlgoProcessNet.HImage(fileName);

 IntPtr prt = hImage.GetImagePointer1(out string type, out imageData.Widht, out imageData.Height);
 imageData.dataLength = imageData.Widht * imageData.Height;
 byte[] datas = new byte[imageData.dataLength];
 Marshal.Copy(prt, datas, 0, imageData.dataLength);
 int pos = Marshal.SizeOf(imageData);
 share1.WriteToMemory(imageData);

 //写共享内存
 if (share1.WriteBytes(datas, pos + 1) == 0)
 {
     WriteMsg("share1写入共享内存成功");
 }
 else
 {
     WriteMsg("share1写入共享内存失败!!");
 }



   public int WriteBytes(byte[] datas, int pos = -1)
   {
       if (IntPtr.Zero == MemPtr)
       {
           return -1;
       }
       if (pos == -1)
       {
           Marshal.Copy(datas, 0, MemPtr, datas.Length);
       }
       else
       {
           IntPtr offPtr = IntPtr.Add(MemPtr, pos);
           Marshal.Copy(datas, 0, offPtr, datas.Length);
       }

       return 0;
   }

4、通知读取数据

private void SendMsg2(string msg)
{
    // 获取目标进程句柄

    IntPtr hWnd = process.MainWindowHandle;

    // 封装消息

    byte[] sarr = System.Text.Encoding.Default.GetBytes(msg);

    int len = sarr.Length;

    COPYDATASTRUCT cds2;

    cds2.dwData = (IntPtr)0;

    cds2.cbData = len + 1;

    cds2.lpData = msg;

    // 发送消息
    WriteMsg(msg + " Start");
    SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, ref cds2);
    WriteMsg(msg + " End");
}

5、被调用方关联消息处理函数

        protected override void OnSourceInitialized(EventArgs e)
        {
            base.OnSourceInitialized(e);
            HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
            if (hwndSource != null)
            {
                IntPtr handle = hwndSource.Handle;
                hwndSource.AddHook(new HwndSourceHook(WndProc));
            }
        }

6、被调用方处理图像数据

        private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (msg == WM_COPYDATA)
            {
                WriteInfo(1, "WndProc Start");
                COPYDATASTRUCT cds = (COPYDATASTRUCT)Marshal.PtrToStructure(lParam,
                typeof(COPYDATASTRUCT)); // 接收封装的消息
                string rece = cds.lpData; // 获取消息内容
                                          // 自定义行为
                                          //  Console.WriteLine(rece);

                if (rece == "Read")
                {
                    Task.Run(() =>
                    {
                        //读共享内存
                        // datastruct = (MemoryClass)shareMemory.ReadFromMemory(typeof(MemoryClass));
                        // WriteInfo(1, $"读取数据:{datastruct.bianliang1},{datastruct.bianliang2},{datastruct.bianliang3}");

                        imageData = (ImageData)shareMemory.ReadFromMemory(typeof(ImageData));

                        int ShareSize = Marshal.SizeOf(imageData);
                        byte[] datas = shareMemory.ReadByteFromMemory(imageData.dataLength, ShareSize + 1);
                        HImage hImage = new HImage();
                        using (PinnedObject pinnedObject = new PinnedObject(datas))
                        {
                            hImage.GenImage1("byte", imageData.Widht, imageData.Height, pinnedObject.Pointer);
                        }
                        // hImage.GenImage1(imageData.DataType, imageData.Widht, imageData.Height, imageData.dataPrt);
                        ImgControl.HalconWindow.AttachBackgroundToWindow(hImage);
                        WriteInfo(1, "图像处理完成");
                    });
                }
                // Thread.Sleep(2000);
                WriteInfo(2, rece);
                if (rece.Equals("Close"))
                {
                    this.Close();
                }
            }
            return hwnd;
        }

7、共享内存操作

  internal class ShareMemory
  {
      [DllImport("user32.dll", CharSet = CharSet.Auto)]
      public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lParam);

      [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
      public static extern IntPtr CreateFileMapping(int hFile, IntPtr lpAttributes, uint flProtect, uint dwMaxSizeHi, uint dwMaxSizeLow, string lpName);

      [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
      public static extern IntPtr OpenFileMapping(int dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, string lpName);

      [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
      public static extern IntPtr MapViewOfFile(IntPtr hFileMapping, uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, uint dwNumberOfBytesToMap);

      [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
      public static extern bool UnmapViewOfFile(IntPtr pvBaseAddress);

      [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
      public static extern bool CloseHandle(IntPtr handle);

      [DllImport("kernel32", EntryPoint = "GetLastError")]
      public static extern int GetLastError();

      private const int INVALID_HANDLE_VALUE = -1;
      private const int ERROR_ALREADY_EXISTS = 0xB7;//183
      private const int PAGE_READWRITE = 0x04;
      private const int FILE_MAP_ALL_ACCESS = 0x0002 | 0x0004;
      private const int FILE_MAP_READ = 0x0004;
      private const int FILE_MAP_WRITE = 0x0002;

      private IntPtr m_hSharedMemoryFile = IntPtr.Zero;
      private IntPtr m_rwData = IntPtr.Zero;
      private bool m_bAlreadyExist = false;
      private bool m_bInit = false;

      private string ShareName { get; set; } //共享内存的名字
      private long MemSize { get; set; }//共享内存大小
      private IntPtr MemPtr { get; set; }//共享内存印射地址

      /// <summary>
      /// 共享内存初始化
      /// </summary>
      /// <param name="MemName">共享内存名字</param>
      /// <param name="MemSize">共享内存大小</param>
      public ShareMemory(string MemName, long Size)
      {
          ShareName = MemName;
          MemSize = Size;
          MemPtr = IntPtr.Zero;
          m_bInit = false;
          m_bAlreadyExist = false;
          m_rwData = IntPtr.Zero;
          m_hSharedMemoryFile = IntPtr.Zero;
      }

      ~ShareMemory()
      {
          ShareMemoryClose();
      }

      /// <summary>
      /// 创建共享内存
      /// </summary>
      /// <returns>0=创建成功;1=创建共享体失败;2=打开失败;3=印射失败; 4=共享内存命名错误</returns>
      public int CreateMemory()
      {
          if (MemSize <= 0) MemSize = 0x00800000;
          if (ShareName.Length > 0)
          {
              //创建内存共享体(INVALID_HANDLE_VALUE)
              m_hSharedMemoryFile = CreateFileMapping(INVALID_HANDLE_VALUE, IntPtr.Zero, (uint)PAGE_READWRITE, 0, (uint)MemSize, ShareName);
              if (m_hSharedMemoryFile == IntPtr.Zero)
              {
                  m_bAlreadyExist = false;
                  m_bInit = false;
                  MemPtr = IntPtr.Zero;
                  return 1; //创建共享体失败
              }
              else
              {
                  if (GetLastError() == ERROR_ALREADY_EXISTS) //已经创建
                  {
                      m_bAlreadyExist = true;
                      CloseHandle(m_hSharedMemoryFile);
                      m_hSharedMemoryFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, ShareName);
                      if (m_hSharedMemoryFile == null)
                      {
                          MemPtr = IntPtr.Zero;
                          return 2;//打开共享内存失败
                      }
                  }
                  else                                         //新创建
                  {
                      m_bAlreadyExist = false;
                  }
              }
              //创建内存映射
              m_rwData = MapViewOfFile(m_hSharedMemoryFile, FILE_MAP_ALL_ACCESS, 0, 0, (uint)MemSize);
              if (m_rwData == IntPtr.Zero)
              {
                  m_bInit = false;
                  CloseHandle(m_hSharedMemoryFile);
                  MemPtr = IntPtr.Zero;
                  return 3; //创建内存映射失败
              }
              else
              {
                  m_bInit = true;
                  MemPtr = m_rwData;
              }
          }
          else
          {
              return 4; //参数错误
          }
          return 0;     //创建成功
      }

      public byte[] ReadByteFromMemory(int dataLength, int pos = -1)
      {
          if (IntPtr.Zero == MemPtr)
          {
              return new byte[0];
          }
          byte[] datas = new byte[dataLength];
          if (pos == -1)
          {
              Marshal.Copy(MemPtr, datas, 0, dataLength);
          }
          else
          {
              IntPtr offPtr = IntPtr.Add(MemPtr, pos);
              Marshal.Copy(offPtr, datas, 0, dataLength);
          }
          return datas;
      }

      /// <summary>
      /// 读取共享内存并返回到类
      /// </summary>
      /// <param name="type">读取的类型</param>
      /// <returns>读取的数据</returns>
      public Object ReadFromMemory(Type type)
      {
          if (IntPtr.Zero == MemPtr)
          {
              return null;
          }

          Object obj = Marshal.PtrToStructure(MemPtr, type);
          return obj;
      }

      /// <summary>
      /// 读取类并写入共享内存
      /// </summary>
      /// <param name="obj">需要读取的类(结构体)</param>
      /// <returns>返回0表示写入成功,返回-1表示写入失败</returns>
      public int WriteToMemory(Object obj)
      {
          if (IntPtr.Zero == MemPtr)
          {
              return -1;
          }

          Marshal.StructureToPtr(obj, MemPtr, false);

          return 0;
      }

      /// <summary>
      /// 关闭共享内存(解除印射,关闭句柄)
      /// </summary>
      public void ShareMemoryClose()
      {
          if (m_bInit)
          {
              UnmapViewOfFile(m_rwData);
              CloseHandle(m_hSharedMemoryFile);
              m_bInit = false;
          }
      }

      /// <summary>
      /// 获取共享内存印射地址
      /// </summary>
      /// <returns></returns>
      public IntPtr GetPtr()
      {
          return MemPtr;
      }

      /// <summary>
      /// 获取文件句柄
      /// </summary>
      /// <returns></returns>
      public IntPtr GetFileMapPtr()
      {
          return m_hSharedMemoryFile;
      }

      /// <summary>
      /// 获取共享内存大小
      /// </summary>
      /// <returns></returns>
      public long GetSize()
      {
          return MemSize;
      }

      /// <summary>
      /// 获取共享内存名字
      /// </summary>
      /// <returns></returns>
      public string GetName()
      {
          return ShareName;
      }
  }


网站公告

今日签到

点亮在社区的每一天
去签到