Archive for the ‘Windows’ Category

COM笔记(一)

COM组件对象模型提供了组件之间交互的规范,不依赖于任何特定的语言,它提供了一种规范、标准。

OLE(对象链接和嵌入)以COM规范为基础,继OLE后Microsoft推出的以COM规范为基础的技术统称ActiveX技术。

组件软件的关键是接口,因此,软件组件应遵从统一标准。COM就是一套公用标准,COM标准包括规范和实现两部分,规范定义了组件间的通信规则,实现则是COM库。

接口是一组逻辑上相关的函数(接口成员函数)的集合。

在COM模型中,对象本身对于客户来说是不可见的,只能通过接口请求服务。

每个接口由一个128位的GUID来标识:客户--->GUID--->接口指针--->接口成员函数。

每个对象也由一个GUID来标识,称为CLSID:客户--->CLSID--->对象的某个接口指针。可以从某个接口指针得到该对象的任意其它接口。

COM组件本身是位置透明的,即只需要调用接口,组件的加载,对象的创建由COM库完成。

COM中包容模式是对象1传递调用给对象2;聚合模型是虽然也不知道对象2的存在,但是直接返回对象2的接口给用户使用。

COM对象为什么要使用引用计数?因为客户个数及什么时候请求服务是不确定的,直接delete释放对象是不安全的。

IDL(接口描述语言)提供了一种不依赖于任何语言的接口描述方法。在VC++中使用IDL其实是MIDL工具将.idl文件编译成C/C++兼容的接口描述头文件。

接口只是一种定义,并不包括实现,具体的实现是在COM对象中,因此,接口继承只继承了成员函数的说明。

接口继承只允许单继承,为什么?因为接口的内存模型中只有一个虚指针,多重继承会出现多个!

接口原则中有一点:对于同一个对象的不同接口指针查询到的IUnkown接口必须相同。这是因为一个COM对象实现了多个接口时,其虚指针会有多个,且虚表中的IUnkown(保存其成员函数地址的位置)会有多份!

Dynamic Data Exchange

DDE是一种动态数据交换机制(Dynamic Data Exchange,DDE)。

使用DDE通讯需要两个Windows应用程序,其中一个作为服务器处理信息,另外一个作为客户机从服务器获得信息。客户机应用程序向当前所激活的服务器应用程序发送一条消息请求信息,服务器应用程序根据该信息作出应答,从而实现两个程序之间的数据交换。

DDE(Dynamic data exchange)的工作原理是:
甲方申请一块全局内存,然后把内存指针PostMessage到乙方,乙方根据收到的指针访问那块全局内存。

有几个API函数是做这种事的,你在MSDN里查一下 Dde 打头的函数全都出来了。因为是已经淘汰的技术,连MFC都没对它进行封装。很难保证它同样会出现在以后的Windows API中。

Dynamic Data Exchange

PEParser

PEParser的存档,至于是什么,以后再补文。

PEParser

ListView

list-view controls中一个item代表一行,设置这行的信息通过subitem。

Each item can have one or more subitems. A subitem is a string that, in report view, is displayed in a column separate from the item's icon and label. All items in a list-view control have the same number of subitems. The number of subitems is determined by the number of columns in the list-view control. When you add a column to a list-view control, you specify its associated subitem index. The iItem member is the zero-based index of the item. The iSubItem member is the one-based index of a subitem or zero if the structure contains information about an item. To change the attributes of a list-view item, use the LVM_SETITEM message, specifying the address of an LVITEM structure. The mask member of this structure specifies the item attributes you want to change. For example, to change only the text of an item or subitem, use the LVM_SETITEMTEXT message.

Report (details) view: Each item appears on its own line, with information arranged in columns. The leftmost column is always left justified and contains the small icon and label. Subsequent columns contain subitems as specified by the application.

示例代码:

HWND hWnd = GetDlgItem(hDlg, IDC_LIST1);
ListView_SetExtendedListViewStyle(hWnd, LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES);
LVCOLUMN lvc = {0};
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvc.fmt = LVCFMT_CENTER;
lvc.cx = 20;
lvc.iSubItem = 0;
lvc.pszText = TEXT("");
ListView_InsertColumn(hWnd, 0, &lvc);
lvc.cx = 100;
lvc.iSubItem = 1;
lvc.pszText = TEXT("编号");
ListView_InsertColumn(hWnd, 1, &lvc);
LVITEM lvi = {0};
lvi.mask = LVIF_TEXT;
lvi.iItem = 0;
lvi.iSubItem = 0;
lvi.pszText = TEXT("");
ListView_InsertItem(hWnd, &lvi);
ListView_SetItemText(hWnd, 0, 1, TEXT("1"));
lvi.iItem = 1;
ListView_InsertItem(hWnd, &lvi);
ListView_SetItemText(hWnd, 1, 1, TEXT("2"));

 

 

 

 

 

 

 

 

 

 

参考资料:http://msdn.microsoft.com/en-us/library/bb774737(v=VS.85).aspx

MFC ODBC与Access

今天帮人调试程序,遇到了MFC ODBC与Access数据库相关的问题,记录下。

之前从未真正使用过ODBC与Access数据库,下面是一点理解:ODBC和JDBC一样,是一层统一的封装,由各个数据库厂商提供统一的接口。你可以使用ODBC的统一接口,因为它具有通用性,稍加修改就能移植到不同数据库。当然,你也可以使用数据库厂商提供的单独的库。

与Access数据库连接,本质是与其数据库文件打交道,格式为.mdb。可以通过COM或者MFC本身的ODBC支持来实现连接。

COM实现连接:http://6520874.blog.163.com/blog/static/7258271920113845626128/

MFC项目向导中有对ODBC的支持,首先要在控制面板--->管理工具中配置数据源(ODBC)。

配置时有三种DSN(Data Source Name,数据源名称),需要根据具体情况及其提示进行配置,添加Microsoft Access Driver相关的数据库.mdb文件。

MFC项目向导会自动生成相关的CxxxSet类对ODBC进行支持。

在这里有趣的是,VC6.0的对话框编辑器中提供了相应的ActiveX控件ADODC和DATAGRID对ODBC进行了视图支持,但VS2005中确没有。具体的解决方案是:http://zhidao.baidu.com/question/210849183.html

在调试的过程中,因为项目的具体要求,还遇到了一点问题。该项目的主窗口即m_pMainWnd是含有以上两个控件的View,不是Dlg。现在需要先有登录对话框进行登录后才能出现主窗口。

在InitInstance中进行修改如下:
// The one and only window has been initialized, so show and update it.
//m_pMainWnd->ShowWindow(SW_SHOW);
//m_pMainWnd->UpdateWindow();
CLoginDlg dlg;
dlg.DoModal();
return TRUE;

然后在登录对话框的登录成功处有如下代码:
AfxGetApp()->m_pMainWnd->ShowWindow(SW_SHOW);
AfxGetApp()->m_pMainWnd->UpdateWindow();
CDialog::OnOK();

结果发现主窗口依然出现,并且CLoginDlg的构造函数中AfxOleInit处出现断言错误。注释掉后,断言错误消失。

于是注释掉InitInstance中如下代码:
//// Parse command line for standard shell commands, DDE, file open
//CCommandLineInfo cmdInfo;
//ParseCommandLine(cmdInfo);

//// Dispatch commands specified on the command line
//if (!ProcessShellCommand(cmdInfo))
// return FALSE;

结果发现会在ShowWindow(SW_SHOW)处出现断言错误,具体出现在winocc.cpp ShowWindow中的ASSERT(::IsWindow(m_hWnd) || (m_pCtrlSite != NULL));处。

经过调试发现m_pMainWnd为NULL。也就是说在ProcessShellCommand后m_pMainWnd才会有正确的赋值。参考:http://apps.hi.baidu.com/share/detail/15714628

最终解决方案:相关函数的调用延迟到CLoginDlg的登录处理函数中,如下:
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
AfxGetApp()->ParseCommandLine(cmdInfo);

// Dispatch commands specified on the command line
if (!AfxGetApp()->ProcessShellCommand(cmdInfo))
return ;

// The one and only window has been initialized, so show and update it.
AfxGetApp()->m_pMainWnd->ShowWindow(SW_SHOW);
AfxGetApp()->m_pMainWnd->UpdateWindow();
CDialog::OnOK();

无觅相关文章插件,快速提升流量