上一篇文章定制IE浏览器弹窗中的外部窗口就是一个不规则窗口,这篇文章介绍下其是如何实现的。思路是根据这张图片创建一个不规则区域,然后将窗口的区域设置为该不规则区域。

第一步,在资源文件rc中设置对话框的属性

阅读全文

使用CWebBrowser2定制IE浏览器窗口

发布在 MFC

在客户端程序中嵌入浏览器,有两种方式,一种是使用微软的IE控件,一种是使用CEF。这里介绍的是使用CWebBrowser2类(在MFC程序中插入IE的Active控件生成),定制内嵌浏览器窗口的一些经验。

本文的经验积累于实现逆战退出游戏时候的广告弹窗的过程中,下面Show一下这个自带萌妹子的弹窗吧。

阅读全文

CMFCToolBar上添加组合框的bug

发布在 MFC

说实话,这几天为了CMFCToolBarComboBoxButton上的莫名其妙自动切换选择的bug烦死了,浪费了很多时间。也是过其它替代方法,发现都实现不了需要的界面效果。
我也不知道为什么自己对界面效果这么纠结。伤不起啊。本来我就没用过vs2008更新版本的MFC,也没打算用这个。由于上一次做的东西用到了切分视图,但是发现FormView自适应控件大小的实现非常麻烦,老是出现些不爽的bug,而且添加新的控件还得编辑界面,非常不爽。所以,打算使用新版本MFC里面的属性窗口。
刚好发现vs2010的项目导航可以生成这样的工程,果断试验之。虽然过程无比艰辛,总算可以使用这些自适应的DockPane窗口了。而且还发现这样的结构非常合适添加子窗口,以后的项目都可以采用这样的界面了,只要平台在windows下。
但是,美中最不足的是CFrameWndEx(使用CDockablePane必须使用扩展的框架窗口),只能使用恶心的CMFCToolBar,因为CFrameWndEx的菜单和工具栏都是可以DockPane的子类。我只能说CMFCToolBar的使用太TMD的讲究了,一个不注意效果就不对。因为使用这个东西的人少,网上资料也很少。只能一直google,还有查看类定义的源码,慢慢尝试了。
现在,我这里说的只是添加组合框。
首先,在资源编辑器中新建工具栏IDR_BUILD,留下一个空位,如ID_BUILD_CHOOSE。如下图,第二个就是我预留的ID_BUILD_CHOOSE的空位。
然后,在CMainFrame::OnCreate中创建两个工具栏,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
   if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER
| CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC)
|| !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("未能创建工具栏\n");
return -1; // 未能创建
}

if (!m_wndToolBarBuild.Create(this, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_TOOLTIPS | CBRS_FLYBY
| CBRS_HIDE_INPLACE | CBRS_SIZE_DYNAMIC| CBRS_GRIPPER | CBRS_BORDER_3D, IDC_MFCTOOLBAR_BUILD)
|| !m_wndToolBarBuild.LoadToolBar(IDR_BUILD))
{
TRACE0("未能创建build工具栏\n");
return -1; // 未能创建
}

if (!m_wndStatusBar.Create(this))
{
TRACE0("未能创建状态栏\n");
return -1; // 未能创建
}
m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT));

m_wndMenuBar.EnableDocking(CBRS_ALIGN_ANY);
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
m_wndToolBarBuild.EnableDocking(CBRS_ALIGN_ANY);

EnableDocking(CBRS_ALIGN_ANY);
DockPane(m_wndMenuBar);
DockPane(m_wndToolBarBuild);
DockPaneLeftOf(m_wndToolBar, m_wndToolBarBuild);
阅读全文

使用GDI+和CListCtrl实现缩略图控件

发布在 MFC

本来这个东西我是用CxImage加载了多种格式的图片,结果今天发现在vs2010的debug模型下有内存溢出,调试了半天才找到是它的原因,所以非常不爽,换了GDI+的实现方法。该控件支持加载多种格式的图片,并且在增加的项内部存储的图片路径。重要的一点是必须在控件的OnDestroy里面释放申请的ItemData,否则退出程序时候还是能检测到内存泄露。这个也是找了半天才找到的。郁闷之。
关于该控件类的具体实现过程,有点复杂。使用到是比较简单,绑定到CListCtrl控件上。用InitCtrl初始化,用AddImage添加。
该类还支持多选和全选,以及删除所有的选择。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#pragma once
// CImageListCtrl

class CImageListCtrl : public CListCtrl
{
DECLARE_DYNAMIC(CImageListCtrl)

public:
CImageListCtrl();
virtual ~CImageListCtrl();
CImageList m_ImageList;
WCHAR m_char16ImgName[MAX_PATH];

protected:
DECLARE_MESSAGE_MAP()

public:
// 添加图片
int AddImage(CString imgPath);
void DelImage(CString imgPath);
void RemoveAllImg(void);
// 获得当前显示所有图片的路径
void GetImgPathList(CStringList strListPath);
BOOL InitCtrl(int nX, int nY);
void DeleteSelItem(void);

private:
int m_nX;
int m_nY;
int m_nNum;

public:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDestroy();
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
};
阅读全文

这应该是用vc在程序中添加视频音频播放器最方便的方法了。但是,你如果只是用vs2010或者其它版本工具插入activex控件,然后生成代码,那就不一定能够得到你想要的全部功能。
wmplayer貌似还有个对应的wm sdk。这个可以用com接口的形式更加底层的控制播放器。但是,如果我们能够得到相关的实现播放器功能的代码,我们也能够得到相同程度的控制。前段时间,在网上找了很久,终于找到一大堆有个wmplayer的类代码。用其中的CWMPPlayer4类绑定播放器就能够得到很强大的控制了,用这个类的成员函数可以得到其他控制和设置类的接口等。
用这个东西最大的缺陷是无法播放内存数据,如果是内存数据,必须生成临时文件。最大的优点是简单方便,功能强大,还可以在不同版本的windows平台兼容,只要上面有默认的wmplayer播放器。这个东西还可以播放网络数据,因为文件其实是通过url索引的。因此,在要求简单的时候,还可以用这个东西快速实现一个网络播放器
下面提供wmplayer相关类的代码,WMP

屏蔽右键和全屏都可以在PreTranslateMessage这个虚函数里面处理,比如if (pMsg->message == WM_LBUTTONDBLCLK)
return TRUE;返回TRUE就不会对这个消息进行处理了。屏蔽右键也可以通过调用m_mediaPlayer.put_enableContextMenu(FALSE);处理。
最奇葩的是屏蔽当前播放的是哪个文件的信息,居然有人奇葩到提出这样的需求。找来找去都没有这样的接口,我都直接看wmsdk的文档了,最后想出了个奇葩的办法,就是用一个static控件遮住。
到现在觉得,最好的操作wmplayer的方式是下载微软的wmsdk,从而直接用接口操作,可以提供最大限度的控制。

阅读全文

vc内嵌浏览器

发布在 MFC

至于vc内嵌浏览器的方式有很多种,vs2008就可以使用htmldialog了,使用htmlview也行,但是个人觉得还是插入activex控件,然后再绑定变量来的舒服。我就是用插入activex控件再绑定变量的方式的,记得使用vc6就会生产类CWebBrowser2,但是这个类使用起来并不是那么的舒服,所以我对它再进行了一次继承。
注意到,CWebBrowser2继承自CWnd,所以我们继承自CWebBrowser2得类CxExplorer就必须支持mfc里面的动态创建机制,总之这个也很简单,加几句宏就行了,原理其实也不需要弄得太清楚,把mfc的原理弄得太清楚实在太费时间了。。。
我创建的这个浏览器类,除了提供基类的接口外,还提供了几个方便自动填表之类操作的接口。比如,获取text的值,写text的值,点击按钮或者复选框,执行js函数等的功能,由于我基本也就只用过这些功能,所以也就弄了几个这样的接口,也没过多区关注其原理等。
其实,我也没学过太多的com知识,只看过一本com技术内幕的书,更别说com的模板ATL了。所以啊,很多知识也不是很了解。用内嵌浏览器也玩过几次,以前没怎么发掘它的强大应用了。。。
其实,内嵌浏览器很多很好的应用,比如说可以作为客户端,由于内嵌了浏览器,所以不需要实现太多的客户端逻辑,而且服务端直接写web页面就行了,不过速度要求不能太高。还有自动填写表之类的应用,还有写网页游戏的自动玩的功能应该都能发掘出来吧。。。
关于如何判断网页是否加载完成的方法,网上一直说用OnDocumentComplete事件,其实还可能出现网页离线的状态,但是我试了几个方法都检测不出来。所以,最好还是用OnTimer检测和设置你想要的东西。

下面提供这几个类的下载,我用的使用方式是DDX,不使用vs生成的类还可以保持代码的一致性。explorer

阅读全文

如何将内存中的位图数据绘制在DC上

发布在 MFC

假如你定义了一个位图类,里面包含位图头,位图信息头,调色板,位图数据。然后你按照位图的格式将位图文件读入你的类中,现在你知道了位图的全部信息了。主要信息包含在位图信息头里面,数据则在位图数据缓冲里面。现在的问题是,在Windows下面如何将一张位图画出来,而且现在是如何从数据缓存里面绘画出位图。
一般情况,我们都是直接绘制在dc里面,而不是绑定到子控件,让子控件自己绘画,比如picture控件之类的,我觉得提供绘制在dc里面的接口更具有广泛性。

现在我知道两种从内存数据绘制彩色位图的2种方法。第一种麻烦一点,第二种则相当直接。
方法一:
第一步,用CreateCompatibleDC创建跟目标dc的兼容性内存dc。
第二步,用CreateCompatibleBitmap创建跟目标dc的兼容性位图。
第三步,用SelectObject将第二步创建的兼容位图选入第一步创建的兼容dc中。
第四步,用SetDIBits设置兼容位图的数据缓冲
第五步,用BitBlt将数据从兼容内存dc绘制到目标dc。
第六步,删除兼容位图和兼容dc。
代码如下,其中buffer代表位图数据缓冲。

阅读全文

该函数原型如下,
BOOL SetWindowPos(
HWND hWnd, // handle to window
HWND hWndInsertAfter, // placement-order handle
int X, // horizontal position
int Y, // vertical position
int cx, // width
int cy, // height
UINT uFlags // window-positioning options
);

第一个参数是你要修改的窗口局部,第二个参数是用于修改Z order的,可以用这个参数把你的窗口弄成TopMost之类的窗口,后面四个参数很好理解,最后那个参数是一些标志,具体的请查看msdn。
基本上我觉得使用这个函数有些时候达不到你想要的效果原因是不知道这个函数使用的坐标系其实不是桌面坐标系,也不是当前窗口的客户区坐标系,而是父窗口的客户区坐标系。这个点可能在你移动非子窗口的时候没有什么影响,但是你想移动子窗口的时候就会出问题了,老是达不到你想要的效果那是非常烦人的,而你debug进去发现你的数据又都是对的。当你意识到该函数使用的坐标系的时候,对应的问题就都能够解决了。

阅读全文

本文是以OpenGL的代码为例子的。计算机图形学OpenGL版上面的例子都是控制台模式的,如果不进行设置,运行的时候会先出现黑窗口再出现Windows窗口。

其实要去除控制台窗口非常简单,只需要修改工程设置,把子系统改成Windows,程序的入口点改成mainCRTStartup。

阅读全文
作者的图片

远行

孤筏重洋


游戏开发


Guang Zhou