C# 不同进程间通讯实例源码下载(SendMessage方式)
在.NET中基于Windows消息的IPC实现 一、什么是IPC IPC(Inter process Communication)就是“进程间通讯”。我们都知道,在windows系统中,各个应用程序(进程)之间常常需要交换、传递数据,这就要解决进程间的数据通信问题。在最初的16位Windows3.x系统中,所有Windows应用程序共享单一地址,任何进程都能够对这一共享地址空间的数据进行读写操作。 随着Windwos98、Windows NT、Windows2000等32位的操作系统的出现,每个进程都有自己的地址空间,一个Windows进程不能存取另一个进程的私有数据,也就是说,虽然两个进程可以用具有相同值的指针寻址,但所读写的只是它们各自的数据,这样就减少了进程之间的相互干扰。 二、如何实现IPC 那么在windows当前系统下,如何实现进程通讯呢?其实有很多方法,如: 1、 剪贴板Clipboard 2、 DDE(动态数据交换) 3、 内存映像 4、 消息管道 5、 邮件槽 6、 Socket 7、 RPC 8、 串行/并行通信(Serial/Parallel Communication) 9、 COM/DCOM 10、Windows消息 三、基于Windows消息的IPC 现在让我们进入今天我们要讲的主题:“基于Windows消息的IPC实现”。 在这里,我假定大家对Windows消息机制都有很好的理解,所以我就不在这上面费太多的墨水了。我们直接看看Windows消息是怎么样实现进程间通讯的。我们首先看看Windows的消息常数: WM_COPYDATA=0x004A// 当一个应用程序传递数据给另一个应用程序时发送此消息。 这就是我们要的。下面我们来看看如何利用它来实现IPC。 让我们先看看几个API函数,没有它们,我们没有办法将数据发送出去。 1、 PostMessage 函数功能:该函数将一个消息放入(寄送)到与指定窗口创建的线程相联系消息队列里,不等待线程处理消息就返回。消息队列里的消息通过调用GetMessage和PeekMessage取得。 函数原型:B00L PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); 参数 hWnd:其窗口程序接收消息的窗口的句柄。可取有特定含义的两个值: HWND.BROADCAST:消息被寄送到系统的所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口。消息不被寄送到子窗口。 NULL:此函数的操作和调用参数dwThread设置为当前线程的标识符PostThreadMessage函数一样。 Msg:指定被寄送的消息。 wParam:指定附加的消息特定的信息。 IParam:指定附加的消息特定的信息。 返回值:如果函数调用成功,返回非零值:如果函数调用失败,返回值是零。若想获得更多的错误信息,请调用GetLastError函数。 2、 SendMessage 函数功能:该函数将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回。而函数PostMessage不同,将一个消息寄送到一个线程的消息队列后立即返回。 函数原型:LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam); 参数: hWnd:其窗口程序将接收消息的窗口的句柄。如果此参数为HWND_BROADCAST,则消息将被发送到系统中所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口,但消息不被发送到子窗口。 Msg:指定被发送的消息。 wParam:指定附加的消息指定信息。 IParam:指定附加的消息指定信息。 返回值:返回值指定消息处理的结果,依赖于所发送的消息。 3、 RegisterWindowMessage 函数功能:RegisterWindowMessage函数定义一个新的窗口消息,该消息保证在整个系统范围内是唯一的。调用SendMessage或PostMessage函数时可以使用该函数返回的消息值。 函数原型:UINT RegisterWindowMessage(lpsz) 参数: lpsz指向一个以NULL结束的字符串,该字符串指定待登记的消息。 返回值:若成功地登记了消息,返回值是一个消息标识符。该标识符值的范围在0XC000到0XFFFF之间,否则,返回值为0。 我们现在在C#中声明这些API函数: [DllImport("user32")] internal static extern int RegisterWindowMessage(string lpString); [DllImport("user32")] internal static extern int PostMessage(IntPtr hWnd, int Msg, int wParam, int lParam); [DllImport("user32")] internal static extern int PostMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam); [DllImport("user32")] internal static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref COPYDATASTRUCT lParam); 然后定义一些我们需要的常数: internal const int WM_COPYDATA = 0x004A; //当一个应用程序传递数据给另一个应用程序时发送此消息 internal const int WM_DESTROY = 0x0002; //窗体被销毁 internal const int WM_CREATE = 0x0001; //应用程序创建一个窗口 internal const int WM_QUERYENDSESSION = 0x0011; //当用户选择结束对话框或程序自己调用ExitWindows函数 internal static readonly IntPtr HWND_BROADCAST = new IntPtr(0xFFFF); 我们还需要一个传送数据的结构: /// ///发送WM_COPYDATA消息的数据结构 /// internal struct COPYDATASTRUCT { /// ///用户自定义数据 /// internal IntPtr dwData; /// ///数据长度 /// internal int cbData; /// ///数据首地址指针 /// internal IntPtr lpData; } 现在我们来看看具体如何实现: 1、 我们首先创建一个类,让它从Form类继承,因为我们需要一个窗体,然后对它的消息进行处理: internal class WinMsg : Form{ private string _messageString; private List _windowList; private int _message; private int _intHandler; private bool _isConnected;} 2、 然后定义构造函数,在构造函数里注册一个消息通道值,并发出一个广播通知其它在这个通道的窗口。 internal WinMsg(string messageString) { _messageString = messageString; _isConnected = false; _intHandler = Handle.ToInt32(); _windowList = new List(); _message = Win32.RegisterWindowMessage(_messageString);//注册一个消息通道 int errCode = Win32.PostMessage(Win32.HWND_BROADCAST, _message, Win32.CONNECTION, _intHandler);//向此通道内所有的窗口广播自己的句柄 if (errCode == 0) { throw new Win32Exception(errCode);//发生错误,抛出异常 } else { _isConnected = true; } } 3、 重写基类的WndProc函数,处理接收到的消息: protected override void WndProc(ref Message m) { if (m.Msg == _message)//接收到广播消息,进行处理 { int LParam = m.LParam.ToInt32(); int WParam = m.WParam.ToInt32(); if (LParam != 0 && LParam != _intHandler) { if (WParam == Win32.DISCONNECTION) { _windowList.Remove(m.WParam);//将对方窗口的句柄从列表中删除 } else { if (WParam==Win32.CONNECTION) { Win32.PostMessage(m.LParam, _message, Win32.REVERSION, _intHandler); } _windowList.Add(m.LParam);//将对方窗口的句柄存入列表中 } } return; } switch (m.Msg) { case Win32.WM_COPYDATA://接收到其它窗口发送过来的数据 { COPYDATASTRUCT data = new COPYDATASTRUCT(); data = (COPYDATASTRUCT)m.GetLParam(data.GetType()); byte[] message = new byte[data.cbData]; Marshal.Copy(data.lpData, message, 0, data.cbData);//从非托管内存中将数据复制到我们的byte数组中。 Anyzler(m.WParam, message);//在这里处理接收到的数据。 } break; case Win32.WM_DESTROY: case Win32.WM_QUERYENDSESSION://窗口被关闭,向其它窗口广播通知从队列中删除自己 Win32.PostMessage(Win32.HWND_BROADCAST, _message, Win32.DISCONNECTION, _intHandler); base.WndProc(ref m);//调用基类的消息处理函数。 break; default: base.WndProc(ref m); //调用基类的消息处理函数。 break; } }4、 定义发送消息的函数: internal void Send(byte[] message) { if (_isConnected) { int length = message.Length; IntPtr ptr = Marshal.AllocHGlobal(length);//申请一块非托管内存 Marshal.Copy(message, 0, ptr, length);//将要发送的数据封送到非托管内存 COPYDATASTRUCT data = new COPYDATASTRUCT(); data.dwData = IntPtr.Zero;//这里可以随意定义。 data.cbData = length;//传递要发送的数据的长度 data.lpData = ptr;//传递要发送的数据的地址指针 //向其它所有窗口发送数据,这里不能发广播消息。必须一个一个发送。 foreach (IntPtr window in _windowList) { Win32.SendMessage(window, Win32.WM_COPYDATA, this.Handle, ref data); } Marshal.FreeHGlobal(ptr);//释放这块非托管内存,这行一定要写上,不然会内存泄漏。 } }好了,主要代码就是这些了!
- 2013-09-14下载
- 积分:1
c++ 邮件群发 例子源码
#include "stdafx.h" #include #include #include "Resource.h" #include "TabDlg1.h" #include "winsock2.h"#include "stdafx.h"#include #include #include "Resource.h"#include "MainDlg.h" #include "TabDlg1.h" #include "TabDlg2.h" #include "TabDlg3.h" #include "winsock2.h"#define WM_CLICKBIT (WM_USER 1) //最小化,消息定义NOTIFYICONDATA nid;RECT RectForm; //广告窗口坐标 HFONT hFontURLNotVisit;//字体HFONT hFontURLVisited;extern TCHAR tcRunPath[MAX_PATH]; //程序当前路径目录HINSTANCE hInst; static HWND Child1hWnd,Child2hWnd,Child3hWnd; //TAB Control 3个子窗口句柄int initDialog(HWND hwnd)//初始化TAB CTR控件{ //TCHAR szWebSite[100]="http://returnc.com/archives/300.html"; //ShellExecute(hwnd,TEXT("open"),szWebSite,TEXT(""),NULL,SW_SHOWMAXIMIZED); HWND hwndTab = GetDlgItem(hwnd, IDC_TAB1); InitCommonControls(); TCITEM ItemStruct;//定义TAB的参数的结构体 ItemStruct.mask = TCIF_TEXT;//标签 ItemStruct.iImage = 0;//图像 ItemStruct.lParam = 0; ItemStruct.pszText = "SMTP设置";//选项的字符 ItemStruct.cchTextMax = 10; SendMessage(hwndTab, TCM_INSERTITEM, 0, (LPARAM)&ItemStruct);//不用SendMessage用 //TabCtrl_InsertItem(hwndTab,0,&ItemStruct);是一样一样的。 ItemStruct.pszText = "邮件内容";//同上,就是重新定义一下选项的字符 SendMessage(hwndTab, TCM_INSERTITEM, 1, (LPARAM)&ItemStruct); ItemStruct.pszText = "收件箱"; SendMessage(hwndTab, TCM_INSERTITEM, 2, (LPARAM)&ItemStruct); //Child1hWnd = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hwndTab, (DLGPROC)NULL, 0); //网上出现的是上面这个版本,我一开始用这个,给折腾到死都没得到子窗口控件,得不到控件就没法设置了 //因为后面的(DLGPROC)被置空了。这里置空,TAB只能当摆设,所以改成你自己建好的TAB1.CPP中的PROC函数就好了 Child1hWnd = CreateDialogParam((HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE),MAKEINTRESOURCE(IDD_DIALOG1),hwndTab,(DLGPROC)TAB1_Proc,0);//创建子窗口 Child2hWnd = CreateDialogParam((HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE),MAKEINTRESOURCE(IDD_DIALOG2),hwndTab,(DLGPROC)TAB2_Proc,0); Child3hWnd = CreateDialogParam((HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE),MAKEINTRESOURCE(IDD_DIALOG3),hwndTab,(DLGPROC)TAB3_Proc,0); ShowWindow(Child1hWnd, SW_SHOWDEFAULT); //默认显示一下第一个窗口 return 0; } BOOL WINAPI Main_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ HWND hwndTab = GetDlgItem(hWnd, IDC_TAB1);//TAB Control句柄 HWND hwnd_Link=GetDlgItem(hWnd,IDC_SYSLINK1);//Syslink Control 文字链接——版权句柄 switch(uMsg) { HANDLE_MSG(hWnd, WM_INITDIALOG, Main_OnInitDialog); HANDLE_MSG(hWnd, WM_COMMAND, Main_OnCommand); HANDLE_MSG(hWnd,WM_CLOSE, Main_OnClose); HANDLE_MSG(hWnd, WM_SYSCOMMAND, Main_OnSysCommand); //最小化到托盘 HANDLE_MSG(hWnd,WM_LBUTTONDOWN,Main_OnLButtonDown);//左键点击 HANDLE_MSG(hWnd,WM_MOUSEMOVE, Main_OnMouseMove); //鼠标移动范围 HANDLE_MSG(hWnd,WM_PAINT, Main_OnPaint); //点击后显示网站 //HANDLE_MSG(hwnd,WM_CTLCOLORSTATIC, Main_OnCtlColor); case WM_CLICKBIT://最小化后,点击图标 { if(wParam == IDI_ICON1) { switch(lParam) { case WM_LBUTTONDBLCLK://左键双击事件 { ShowWindow(hWnd, SW_SHOWNORMAL); //显示窗口 Shell_NotifyIcon(NIM_DELETE, &nid);//删除托盘图标 SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);//设置窗口坐标 } break; case WM_RBUTTONUP://右键起来时弹出快捷菜单,待完善” { MessageBox(hWnd,TEXT("作者比较懒,右键功能还没添加,双击左键恢复主窗口"),TEXT("憨笑"),MB_OK); } break; default: // ShowWindow(hWnd, SW_HIDE); break; } return TRUE; } else { return FALSE; } } break; case WM_NOTIFY: { /* switch (((LPNMHDR)lParam)->code)//文字链接部分 //TAB CONTROL 控件选择操作&文字链接 **********这一段经百次测试,10分之一左右的概率出现内存读取错误,疑似(LPNMHDR)lParam)->code读取问题 { case NM_CLICK ://点击 //case NM_RETURN ://回车键都可以打开链接 { PNMLINK pNMLink = (PNMLINK)lParam; LITEM item = pNMLink->item; NMHDR hdr = pNMLink->hdr; if ((hdr.hwndFrom == hwnd_Link) && (item.iLink == 0)) { ShellExecute(hWnd,TEXT("open"),"http://www.bachengxie.com/?p=300",TEXT(""),NULL,SW_SHOWMAXIMIZED);//打开网站 return TRUE; } else { return FALSE; } } break; default: break; } */ if ( *(LPDWORD)((LPBYTE)lParam 8)==TCN_SELCHANGE ) //子窗口选择 { int i = TabCtrl_GetCurSel(hwndTab);//返回TAB CTR选择页编号,显示对应窗口数据 switch (i) { case 0: { ShowWindow(Child1hWnd,SW_SHOWDEFAULT); ShowWindow(Child2hWnd,SW_HIDE); ShowWindow(Child3hWnd,SW_HIDE); } break; case 1: { ShowWindow(Child2hWnd,SW_SHOWDEFAULT); ShowWindow(Child1hWnd,SW_HIDE); ShowWindow(Child3hWnd,SW_HIDE); } break; case 2: { ShowWindow(Child3hWnd,SW_SHOWDEFAULT); ShowWindow(Child1hWnd,SW_HIDE); ShowWindow(Child2hWnd,SW_HIDE); } break; default: break; } return TRUE; } else { return FALSE; } } break; default: break; } return FALSE; }BOOL Main_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam){ SkinH_AttachEx(("skins/china.she"), NULL); //载入皮肤 initDialog(hwnd); //初始化TAB控件 hFontURLNotVisit=CreateFont(15,6,0,0,0,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE,"黑体");//设置TAB控件字体大小 //SendDlgItemMessage(hwnd,IDC_TAB1,WM_SETFONT,(WPARAM)hFontURLNotVisit,0); //设置TAB字体 return TRUE;}void Main_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify){ switch(id) { case IDC_TOTRAY: { ToTray(hwnd); //最小化到系统托盘 } break; case ID_HELP: { ShellExecute(NULL,"open","ReadMe.txt",NULL,NULL,SW_SHOWNORMAL); //打开ReadMe文本。 } break; default: break; }}void Main_OnClose(HWND hwnd){ SkinH_Detach(); //释放窗口皮肤 EndDialog(hwnd, 0);}void Main_OnPaint(HWND hwnd) //设置起始点及图片大小{ GetClientRect(hwnd,&RectForm); MoveWindow(GetDlgItem(hwnd,IDC_STATIC_AD),RectForm.left 20,RectForm.top 20,523,80,TRUE); //X,Y分别为30和20的顶点坐标,长为430,宽为90,自我理解} void Main_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags){ GetClientRect(hwnd,&RectForm); if(x>=RectForm.left 20 && x=RectForm.top 20 && y=RectForm.left 20 && x=RectForm.top 20 && y
- 2014-12-15下载
- 积分:1