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