dll与exe的通信,也可用于两进程间通信(WM_COPYDATA)
这两天在写一个的小工具。需要用到dll与exe通信,dll中去发WM_COPYDATA消息,exe中接受并处理。这个问题在写的时候断断续续弄了两天。后来干脆写个demo记录一下。以便给方便别人查阅和自己观看。
首先定义需要发送的数据,我这里用结构体表示。到时候将结构体发送过去就是了。
1 /* 2 *CopyDataDll.h 3 */ 4 5 #ifdef COPYDATADLL_EXPORTS 6 #define COPYDATADLL_API __declspec(dllexport) 7 #else 8 #define COPYDATADLL_API __declspec(dllimport) 9 #endif 10 11 //顾名思义 12 struct STPROCINFO 13 { 14 char ProcessName[256]; 15 int nPID; 16 int nTID; 17 char ProcessPath[MAX_PATH]; 18 }; 19 20 //导出一个函数 21 extern "C" COPYDATADLL_API void GetInfoForDll();
而cpp中,我们直接给它值。这部分自由发挥。
// CopyDataDll.cpp : 定义 DLL 应用程序的入口点。 // #include "stdafx.h" #include "CopyDataDll.h" extern "C" BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } extern "C" COPYDATADLL_API void GetInfoForDll() { /* *查找窗口 */ HWND g_hwmd = FindWindow(NULL, "CopyData"); if (g_hwmd == NULL) { MessageBox(NULL, "Can't find CopyData Form!", "Error", MB_ICONERROR|MB_OK); return; } /* *结构体要传些什么数据就自由发挥了 */ STPROCINFO stProcessInfo; strncpy(stProcessInfo.ProcessName, "Bin.exe", strlen("Bin.exe")+1); stProcessInfo.nPID = 1010; stProcessInfo.nTID = 2020; strncpy(stProcessInfo.ProcessPath, "C:\\Bin.exe", strlen("C:\\Bin.exe")+1); strncat(stProcessInfo.ProcessName, "\0", 1); strncat(stProcessInfo.ProcessPath, "\0", 1); COPYDATASTRUCT cpd; cpd.cbData = 0; //自定义数据 cpd.dwData = sizeof(stProcessInfo); //结构体大小 cpd.lpData = (PVOID)&stProcessInfo; //指向你的数据 //发送,注意窗口 SendMessage(g_hwmd, WM_COPYDATA, 0, (LPARAM)&cpd); return; }
编译之后,看一下导出表.

接来下就新建一个MFC工程,重载一下OnCopyData消息。 调用GetInfoForDll。就可以了。具体实现如下
1 // CopyDataDlg.cpp : 实现文件 2 // 3 4 #include "stdafx.h" 5 #include "CopyData.h" 6 #include "CopyDataDlg.h" 7 #include ".\copydatadlg.h" 8 9 #ifdef _DEBUG 10 #define new DEBUG_NEW 11 #endif 12 13 struct STPROCINFO 14 { 15 char ProcessName[256]; 16 int nPID; 17 int nTID; 18 char ProcessPath[MAX_PATH]; 19 }; 20 // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 21 22 class CAboutDlg : public CDialog 23 { 24 public: 25 CAboutDlg(); 26 27 // 对话框数据 28 enum { IDD = IDD_ABOUTBOX }; 29 30 protected: 31 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 32 33 // 实现 34 protected: 35 DECLARE_MESSAGE_MAP() 36 }; 37 38 CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) 39 { 40 } 41 42 void CAboutDlg::DoDataExchange(CDataExchange* pDX) 43 { 44 CDialog::DoDataExchange(pDX); 45 } 46 47 BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) 48 END_MESSAGE_MAP() 49 50 51 // CCopyDataDlg 对话框 52 53 54 55 CCopyDataDlg::CCopyDataDlg(CWnd* pParent /*=NULL*/) 56 : CDialog(CCopyDataDlg::IDD, pParent) 57 { 58 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 59 } 60 61 void CCopyDataDlg::DoDataExchange(CDataExchange* pDX) 62 { 63 CDialog::DoDataExchange(pDX); 64 DDX_Control(pDX, IDC_MAINLIST, m_ListCtrl); 65 } 66 67 BEGIN_MESSAGE_MAP(CCopyDataDlg, CDialog) 68 ON_WM_SYSCOMMAND() 69 ON_WM_PAINT() 70 ON_WM_QUERYDRAGICON() 71 //}}AFX_MSG_MAP 72 ON_WM_SHOWWINDOW() 73 ON_WM_COPYDATA() 74 ON_COMMAND(ID_GETDATA, OnGetdata) 75 END_MESSAGE_MAP() 76 77 78 // CCopyDataDlg 消息处理程序 79 80 BOOL CCopyDataDlg::OnInitDialog() 81 { 82 CDialog::OnInitDialog(); 83 84 // 将\“关于...\”菜单项添加到系统菜单中。 85 86 // IDM_ABOUTBOX 必须在系统命令范围内。 87 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 88 ASSERT(IDM_ABOUTBOX < 0xF000); 89 90 CMenu* pSysMenu = GetSystemMenu(FALSE); 91 if (pSysMenu != NULL) 92 { 93 CString strAboutMenu; 94 strAboutMenu.LoadString(IDS_ABOUTBOX); 95 if (!strAboutMenu.IsEmpty()) 96 { 97 pSysMenu->AppendMenu(MF_SEPARATOR); 98 pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); 99 } 100 } 101 102 // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 103 // 执行此操作 104 SetIcon(m_hIcon, TRUE); // 设置大图标 105 SetIcon(m_hIcon, FALSE); // 设置小图标 106 107 // TODO: 在此添加额外的初始化代码 108 InitGUI(); 109 InitBack(); 110 111 return TRUE; // 除非设置了控件的焦点,否则返回 TRUE 112 } 113 114 void CCopyDataDlg::OnSysCommand(UINT nID, LPARAM lParam) 115 { 116 if ((nID & 0xFFF0) == IDM_ABOUTBOX) 117 { 118 CAboutDlg dlgAbout; 119 dlgAbout.DoModal(); 120 } 121 else 122 { 123 CDialog::OnSysCommand(nID, lParam); 124 } 125 } 126 127 // 如果向对话框添加最小化按钮,则需要下面的代码 128 // 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, 129 // 这将由框架自动完成。 130 131 void CCopyDataDlg::OnPaint() 132 { 133 if (IsIconic()) 134 { 135 CPaintDC dc(this); // 用于绘制的设备上下文 136 137 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); 138 139 // 使图标在工作矩形中居中 140 int cxIcon = GetSystemMetrics(SM_CXICON); 141 int cyIcon = GetSystemMetrics(SM_CYICON); 142 CRect rect; 143 GetClientRect(&rect); 144 int x = (rect.Width() - cxIcon + 1) / 2; 145 int y = (rect.Height() - cyIcon + 1) / 2; 146 147 // 绘制图标 148 dc.DrawIcon(x, y, m_hIcon); 149 } 150 else 151 { 152 CDialog::OnPaint(); 153 } 154 } 155 156 //当用户拖动最小化窗口时系统调用此函数取得光标显示。 157 HCURSOR CCopyDataDlg::OnQueryDragIcon() 158 { 159 return static_cast<HCURSOR>(m_hIcon); 160 } 161 162 // 初使化 163 void CCopyDataDlg::InitGUI(void) 164 { 165 m_ListCtrl.InsertColumn(0, "ProcessName"); 166 m_ListCtrl.InsertColumn(1, "PID"); 167 m_ListCtrl.InsertColumn(2, "TID"); 168 m_ListCtrl.InsertColumn(3, "Path"); 169 m_ListCtrl.SetExtendedStyle(m_ListCtrl.GetExtendedStyle()|LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES); 170 } 171 172 void CCopyDataDlg::OnShowWindow(BOOL bShow, UINT nStatus) 173 { 174 CDialog::OnShowWindow(bShow, nStatus); 175 176 // TODO: 在此处添加消息处理程序代码 177 m_ListCtrl.SetColumnWidth(0, LVSCW_AUTOSIZE_USEHEADER); 178 m_ListCtrl.SetColumnWidth(1,LVSCW_AUTOSIZE_USEHEADER); 179 m_ListCtrl.SetColumnWidth(2,LVSCW_AUTOSIZE_USEHEADER); 180 m_ListCtrl.SetColumnWidth(3,LVSCW_AUTOSIZE_USEHEADER); 181 182 } 183 184 void CCopyDataDlg::InitBack(void) 185 { 186 187 } 188 189 //重载一下这个消息就可以了 190 BOOL CCopyDataDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct) 191 { 192 // TODO: 在此添加消息处理程序代码和/或调用默认值 193 194 STPROCINFO* pstCopyData; 195 196 //pCopyDataStruct->lpData保存的就是dll发过来的数据的地址 197 pstCopyData = (STPROCINFO*)(pCopyDataStruct->lpData); 198 199 m_ListCtrl.InsertItem(0, pstCopyData->ProcessName); 200 201 char tmp[256]; 202 wsprintf(tmp, "%d", pstCopyData->nPID); 203 m_ListCtrl.SetItemText(0, 1, tmp); 204 205 wsprintf(tmp, "%d", pstCopyData->nTID); 206 m_ListCtrl.SetItemText(0, 2, tmp); 207 208 wsprintf(tmp, "%s", pstCopyData->ProcessPath); 209 m_ListCtrl.SetItemText(0, 3, tmp); 210 211 return CDialog::OnCopyData(pWnd, pCopyDataStruct); 212 } 213 214 //Getdata是文件->GetData菜单。也可以换成按钮的 215 void CCopyDataDlg::OnGetdata() 216 { 217 // TODO: 在此添加命令处理程序代码 218 HMODULE hCopyDataDll = LoadLibrary("CopyDataDll.dll"); 219 if (hCopyDataDll == NULL) 220 { 221 AfxMessageBox("Can't load CopyDataDll.dll"); 222 return; 223 } 224 225 //用来保存GetInfoForDll的地址 226 typedef void (*pFunMR)(void); 227 pFunMR Funaddress= NULL; 228 229 Funaddress = (pFunMR)GetProcAddress(hCopyDataDll, "GetInfoForDll"); 230 if (Funaddress) 231 { 232 Funaddress(); //执行之 233 AfxMessageBox("OK"); 234 } 235 FreeLibrary(hCopyDataDll); 236 return; 237 }
将CopyDataDll.dll与CopyData.exe放到同一目录。最后执行效果如下:

打全收工。
争取每天更新博客。写一份代码。量不在多,坚持就行。
2012-08-27

浙公网安备 33010602011771号