串口选择窗口DLL制作,以非模态窗口选择之后,怎么给调用DLL的程序EXE发送消息说已经选择完毕了

串口选择窗口DLL制作,以非模态窗口选择之后,如何给调用DLL的程序EXE发送消息说已经选择完毕了?
由于工作缘故,经常要与串口使用打交道,但每次新建一个工程,都得重新创建一个关于串口的对话框,
如此多次之后,甚为繁琐,所以最近打算琢磨如何将其制作成DLL以重复使用,研究了许久,进展甚慢。。。
-----------------------------------------------------------
DLL使用regular MFC dll方式,并且自己添加了对话框并生成该类,以下是主要代码

// CPortDlg dialog
INT_PTR GetSerialPort(CStringArray &arrCom)
{
arrCom.RemoveAll();
HKEY hkey;
LONG32 lRes = RegOpenKeyEx(HKEY_LOCAL_MACHINE,_T("HARDWARE\\DEVICEMAP\\SERIALCOMM"),
NULL,KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS|KEY_READ,&hkey);
if (lRes == ERROR_SUCCESS)
{
TCHAR tchKey[MAX_PATH];
TCHAR tchValue[20];
DWORD dwIndex = 0;
DWORD dwType = REG_SZ;
while (lRes ==ERROR_SUCCESS)
{
DWORD dwCnt = MAX_PATH;
DWORD dwVCount = 20;
lRes = RegEnumValue(hkey,dwIndex++,tchKey,&dwCnt,NULL,&dwType,(LPBYTE)tchValue,
&dwVCount);
if (lRes == ERROR_SUCCESS)
{
if ((dwVCount>0)&&(dwCnt>0))
{
arrCom.Add(tchValue);
}
}
}
}
RegCloseKey(hkey);
return arrCom.GetSize();
}

// CPortDlg message handlers
void CPortDlg::ScanPort(UINT nID)
{
((CComboBox*)GetDlgItem(nID))->ResetContent();
CStringArray arrayStrCom;
for (int i=0;i<GetSerialPort(arrayStrCom);i++)
{
((CComboBox*)GetDlgItem(nID))->AddString(arrayStrCom.GetAt(i));
}
int nIndex = 0;//((CComboBox*)GetDlgItem(IDC_CMB_COM_NO))->FindStringExact(-1,strComm);
((CComboBox*)GetDlgItem(nID))->SetCurSel(nIndex);
}
void CPortDlg::OnDropdownComboPort() 
{
// TODO: Add your control notification handler code here
ScanPort(IDC_COMBO_PORT);

}

void CPortDlg::OnSelchangeComboPort() 
{
// TODO: Add your control notification handler code here
int nSel = ((CComboBox*)GetDlgItem(IDC_COMBO_PORT))->GetCurSel();
CString str;
((CComboBox*)GetDlgItem(IDC_COMBO_PORT))->GetLBText(nSel,str);
str = str.Right(str.GetLength() - 3 );
m_nPort = _ttoi(str.GetBuffer(str.GetLength()));
str.ReleaseBuffer();
}
int CPortDlg::GetSelectedPort()
{
return m_nPort;
}

BOOL CPortDlg::OnInitDialog() 
{
CDialog::OnInitDialog();

// TODO: Add extra initialization here

return TRUE;  // return TRUE unless you set the focus to a control
              // EXCEPTION: OCX Property Pages should return FALSE
}

void CPortDlg::OnClose() 
{
// TODO: Add your message handler code here and/or call default
theApp.DecreseRef();
CDialog::OnClose();
}

void CPortDlg::OnOK() 
{
// TODO: Add extra validation here
theApp.DecreseRef();
  CDialog::OnOK();
}

...
class CMFCDlgDll1App : public CWinApp
{
public:
CMFCDlgDll1App();
int GetRef(){ return m_nRef; }//获取引用计数器
void AddRef(){ m_nRef++; }//递增
void DecreseRef(){ if(m_nRef>0)m_nRef--;}//递减
CPortDlg* GetDlg(){ return m_pDlg; }
BOOL IsDlgNull(){ if(m_pDlg == NULL)return TRUE;else return FALSE; }
void DestroyDlg(){ m_pDlg->DestroyWindow();delete m_pDlg;m_pDlg = NULL;}
void CreateDlg(){ m_pDlg = new CPortDlg; m_pDlg->Create(IDD_DLG_PORT); }
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMFCDlgDll1App)
//}}AFX_VIRTUAL

//{{AFX_MSG(CMFCDlgDll1App)
// NOTE - the ClassWizard will add and remove member functions here.
//    DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
int m_nRef;//引用计数器
CPortDlg* m_pDlg;
};

以下是2张效果图,简陋为之
串口选择窗口DLL制作,以非模态窗口选择之后,怎么给调用DLL的程序EXE发送消息说已经选择完毕了串口选择窗口DLL制作,以非模态窗口选择之后,怎么给调用DLL的程序EXE发送消息说已经选择完毕了
 然后接下来是导出函数

CMFCDlgDll1App::CMFCDlgDll1App()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
m_nRef = 0;
m_pDlg =  NULL;
}

int ShowDlg()
{
//此处创建后dlg为0
//使用模态对话框无法成功
//只能使用非模态进行显示
AFX_MANAGE_STATE(AfxGetStaticModuleState());
int i = 0; 
if (theApp.GetRef()>=1)//已经创建了
{
i = -1;
}
else
{
   if(theApp.IsDlgNull()==TRUE)
{
theApp.CreateDlg();
}
theApp.GetDlg() ->CenterWindow();
theApp.GetDlg() ->ShowWindow(SW_SHOWNORMAL);

theApp.AddRef();
i = 0;
}
return i;
}
int GetPortNum()
{    //切换资源使用
AFX_MANAGE_STATE(AfxGetStaticModuleState());