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

 

posted @ 2012-08-27 19:02  markro  阅读(1062)  评论(0)    收藏  举报