总结前段时间在VC6下使用MFC开发视频监控控件过程中遇到的一些问题.
1.获取控件当前所在路径,用于读取该目录下的INI配置文件
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
2.获取当前运行控件的电脑上的固定盘符列表,用于本地录像文件存放
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
char m_cHardDriver[26]; // 盘符数组
int m_iDriverNum; // 盘符个数
BOOL F_GetSystemInfo(); // 获取固定盘符列表的函数
// 获取当前运行控件的电脑上的固定盘符列表
BOOL CWebPlayerApp::F_GetSystemInfo()
{
DWORD dw=GetLogicalDriveStrings(0, NULL);
LPTSTR pAllDrivers=new char[dw];
::GetLogicalDriveStrings(dw, pAllDrivers);
LPTSTR pDriver=pAllDrivers;
char tempDriver[26];
DWORD DriverNum=0;
while(pDriver[0] != 0)
{
tempDriver[DriverNum++] = *pDriver;
pDriver = _tcschr(pDriver,0) + 1; //定位到下一个盘符
}
//volume information
TCHAR lpVolumeNameBuffer[200];
DWORD dwVolumeSerialNumber, dwMaxComLength;
DWORD dwFileSystemFlags;
TCHAR lpFileSystemNameBuffer[50];
DWORD HardNum=0;
for(DWORD num=0; num < DriverNum; num++)
{
CString csRootPath;
csRootPath.Format("%c%s", tempDriver[num], ":\\");
if(GetDriveType(csRootPath) == DRIVE_FIXED)
{
if(GetVolumeInformation(csRootPath,lpVolumeNameBuffer, sizeof(lpVolumeNameBuffer), &dwVolumeSerialNumber,
&dwMaxComLength, &dwFileSystemFlags, lpFileSystemNameBuffer, sizeof(lpFileSystemNameBuffer)))
{
this->m_cHardDriver[HardNum++]=tempDriver[num];
}
}
}
m_iDriverNum=HardNum;
delete[] pAllDrivers;
return TRUE;
}
3.视频1,4,9,16路画面切换显示
较简单地实现,在窗体上拖16个STATIC控件(定义数组为panels),动态调整它们的位置大小即可,然后定义一个类如CPlayStatic去继承CStatic,每一个STATIC控件就由CPlayStatic管理;因为我们要在Static控件上添加鼠标,键盘事件处理,鼠标单击事件,选中该一播放面板时绘制绿色边框,可以很明显地看出当前是选中那一路视频播放窗体,同时恢复上一路选中边框为默认灰色边框;鼠标双击事件,实现视频浏览窗口的全屏功能(按多路预览-->单屏预览-->全屏-->单路浏览-->多路预览);右击菜单,对当前画面进行操作,如本地录像,语音对讲,抓图等操作;键盘事件处理,如该窗体当前正在预览按F2/F键进入全屏模式,按Esc退出全屏,恢复普通模式(需让该窗体获得焦点,处理KeyDown事件)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
void CRealPlayDlg::ArrangeWindow()
{
//channelNum当前需要的视频路数
int i=0, j=0, k=-1;
switch (channelNum)
{
case 1://DVR只有1个视频通道时候 只显示播放窗口1
//show=GetDlgItem(IDC_S01);
//show->MoveWindow(0,0,640,520);
panels[0]->SetWindowPos(NULL,0,0,640,520,SWP_NOZORDER);
panels[0]->ShowWindow(SW_SHOW);
//隐藏其他通道播放面板
for (i=1; i<16; i++)
{
panels[i]->ShowWindow(SW_HIDE);
}
m_Expanded = true;
break;
case 4://DVR有4个视频通道
panels[0]->MoveWindow(0,0,319,259);
panels[0]->ShowWindow(SW_SHOW);
panels[1]->MoveWindow(320,0,320,259);
panels[1]->ShowWindow(SW_SHOW);
panels[2]->MoveWindow(0,260,319,260);
panels[2]->ShowWindow(SW_SHOW);
panels[3]->MoveWindow(320,260,320,260);
panels[3]->ShowWindow(SW_SHOW);
for (i=4; i<16; i++)
{
panels[i]->ShowWindow(SW_HIDE);
}
m_Expanded=false;
break;
case 9://DVR有9个视频通道
for (i=0; i<10; i++)
{
j = i % 3;
if (j == 0)
{
k++;
}
panels[i]->SetWindowPos(NULL,j * 214,k * 174,213,173,SWP_NOZORDER);
panels[i]->ShowWindow(SW_SHOW);
}
for (i=9; i<16; i++)
{
panels[i]->ShowWindow(SW_HIDE);
}
m_Expanded=false;
break;
case 16://DVR有16个视频通道
for (i=0; i<16; i++)
{
j=i % 4;
if (j == 0)
{
k++;
}
panels[i]->SetWindowPos(NULL,j * 160,k * 130,159,129,SWP_NOZORDER);
panels[i]->ShowWindow(SW_SHOW);
}
m_Expanded=false;
break;
}
Invalidate();//立即重绘窗体,显示效果
}
4.画面全屏显示 需注意播放窗口全屏后,就不能够通过GetDlgItem(int ctrlid)获取到该STATIC控件句柄了
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
private:
int ActiveCtrlHandle; // 当前活动播放面板的会话标识值(选中视频通道的控制句柄)
CPlayStatic *panels[16];
bool m_Expanded; // 播放面板是否单路浏览
bool m_enterFull; // 是否进入全屏模式
BOOL m_bFullScreen; // 全屏标记
WINDOWPLACEMENT _temppl; // 全屏时保存原窗口信息,用来恢复窗口 window's placement
//处理用户鼠标双击面板事件
void CRealPlayDlg::DoDbClick(CWnd *current)
{
//如果已经全屏,则退出全屏模式
if (m_bFullScreen)
{
//还原风格
current->SetParent(this);
current->ModifyStyle(WS_POPUP, WS_CHILD);
::SetWindowPos(current->GetSafeHwnd(), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
//current->ModifyStyle(WS_CHILD, WS_CLIPSIBLINGS);//WS_CLIPCHILDREN
//::SetWindowLong(current->m_hWnd, GWL_STYLE, style);
//还原位置
current->SetWindowPlacement(&_temppl);
m_bFullScreen = FALSE;
}
else
{
//如果窗体已经进入单屏显示模式,则进入全屏模式
if (m_Expanded)
{
//如果当前窗口已经打开了视频,则全屏;否则切换回到多屏显示模式
if (ActiveCtrlHandle != -1)
{
if (m_enterFull)
{
//全屏
//得到显示器分辨率
int cx=GetSystemMetrics(SM_CXSCREEN);
int cy=GetSystemMetrics(SM_CYSCREEN);
//保存位置信息
current->GetWindowPlacement(&_temppl);
current->SetParent(NULL); // GetDesktopWindow()
current->SetFocus();
//修改风格
current->SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | WS_EX_TOPMOST);
current->ModifyStyle(WS_CHILD, WS_POPUP);
//移动窗口
current->MoveWindow(0, 0, cx, cy);
m_bFullScreen = TRUE;
}
else
{
ArrangeWindow();
}
m_enterFull = !m_enterFull;
}
else
{
ArrangeWindow();
}
}
else
{
//如果是多屏显示模式,则切换当前选中面板到单屏显示
for (int i=0; i<16; i++)
{
if (i != currentSel)
{
panels[i]->ShowWindow(SW_HIDE);
}
else
{
panels[i]->MoveWindow(0,0,640,520);
m_Expanded=true;
}
}
}
}
Invalidate();
}
5.如果ActiveX控件要使用其它第三方的ActiveX,需在InitInstance()方法中添加AfxEnableControlContainer(); 否则会造成第三方控件无法显示,控件创建出错
6.ActiveX在网页中使用
需使用object标签,其classid具体值可在odl文件中找到,一般在文件最后,不要弄错,否则将会造成控件无法成功创建; odl文件中包含了控件的所有属性,方法以及事件;使用如下
<object id="ocx1" height="520" width="640"
classid="clsid:D55EFD59-8482-4486-9FDE-669EFAC4221B">
</object>
若JavaScript想调用控件的方法,可以这样ocx1.RealPlay();调用控件的RealPlay方法
7.相关参考文章
javascript脚本中定义的参数数组,如何在VC++中访问