新人报道,顺便问个问题

isaacyh 2005-03-01 09:18:52
我在很久很久以前接触过C,在本科时又看了看VC,但啥也没学会。。。
本科完了后脱离了自己的专业,进入了计算机软件的大军,用的是DotNet,C#。。。

但越用C#心里越慌,发现它太上层了,调个API还要什么Pinvoke。。。

所以准备回头学C++,MFC的一套也想了解,请各位大哥多多指导小弟,在此先谢谢了。。。

BTW:现在的项目里有个难题,C#+MSMedia的那套不好解决,如下:

MS的那套录制桌面的东东在有活动的视频流的情况下的确比较好,但是如果我的桌面的录制不是有很多活动的东东,是基于文本的为大多数,有少量的图片的话,MS的那套传输时占的带宽实在是太多了,机器录制时的CPU也是100%,但实际的项目是不允许的,看到有些软件做这种录制传输很快,不知道怎么做的,请各位大侠指点一下,介绍点方向也可以的。。。
...全文
157 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
isaacyh 2005-03-03
  • 打赏
  • 举报
回复
这边人气没有DotNet版的旺呀。。。
是不是大家都很忙???
可惜这边还只能发100分的贴子的说。。。
isaacyh 2005-03-02
  • 打赏
  • 举报
回复
呵呵,现在流行的有两种方式,你可以先看看

http://blog.joycode.com/jiangsheng/archive/2004/01/01/10410.aspx

微软的那套好像是用的内核模式,但太费CPU了,客户端的机器承受不起。。。。
256的项目要求不行的说,现在用的是32位的。。。。




hushuangyan74 2005-03-02
  • 打赏
  • 举报
回复
应该说VC的编的程序的执行速度比C#编的程序的执行速度要快很多,像你这种录制传输桌面的项目用VC是比较合适的。
首先我谈谈我对这个问题的看法:
一.把屏幕上的东西抓下来保存为bmp文件(当然你是传输的话,就不要保存为bmp文件了,直接把图像数据通过UDP等传给客户端。。。。);
1、得到整个屏幕的DC:HDC hDisplay = CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
2、得到屏幕的宽度和高度:int nScreenWidth = GetDeviceCaps(hDisplay, HORZRES);
int nScreenHeight = GetDeviceCaps(hDisplay, VERTRES);
3、创建一个内存中的DC:
HDC hMemDc = CreateCompatibleDC(hDisplay);
4、创建一个内存中的位图:
HBITMAP hBmp = CreateCompatibleBitmap(hDisplay, nScreenWidth, nScreenHeight);
5、把位图和DC绑定在一起:
HBITMAP hOldBmp = (HBITMAP)SelectObject(hMemDc, hBmp);
6、把整个屏幕的内容复制到内存DC中:
BitBlt(hMemDc, 0, 0, nScreenWidth, nScreenHeight, hDisplay, 0, 0, SRCCOPY);
7、再次绑定(例子上这么做,不知道为什么)
hBmp = (HBITMAP)SelectObject(hMemDc, hOldBmp);
8、分配内存(BMP图片文件大小),初始化位图结构体(省略)
9、利用GetDIBits函数得到位图的象素信息:
GetDIBits(hDisplay, hBmp, 0, nScreenHeight,
pBits,
(BITMAPINFO *)pInfoHeader,
DIB_RGB_COLORS);
10、创建文件,保存位图

结果呢!保存成的位图居然是黑白两色的。请教高手,我从在哪里?

这里是源代码:
//复制屏幕
void CopyScreen(const char *pFilePath)
{
//首先得到整个屏幕的句柄
HDC hDisplay = CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
_ASSERT(NULL!=hDisplay);
//得到屏幕的大小
int nScreenWidth = GetDeviceCaps(hDisplay, HORZRES);
int nScreenHeight = GetDeviceCaps(hDisplay, VERTRES);
//创建内存DC
HDC hMemDc = CreateCompatibleDC(hDisplay);
_ASSERT(NULL != hMemDc);
//创建位图
HBITMAP hBmp = CreateCompatibleBitmap(hDisplay, nScreenWidth, nScreenHeight);
_ASSERT(NULL != hBmp);
//选择位图
HBITMAP hOldBmp = (HBITMAP)SelectObject(hMemDc, hBmp);
_ASSERT(NULL != (DWORD)hOldBmp || GDI_ERROR != (DWORD)hOldBmp);
//复制图形
BOOL blnReturnValue = BitBlt(hMemDc, 0, 0, nScreenWidth, nScreenHeight, hDisplay, 0, 0, SRCCOPY);
_ASSERT(0 != blnReturnValue);
//再次选择
hBmp = (HBITMAP)SelectObject(hMemDc, hOldBmp);
_ASSERT(NULL != (DWORD)hBmp || GDI_ERROR != (DWORD)hBmp);
DeleteDC(hMemDc);
hMemDc = NULL;
int nBits = GetDeviceCaps(hDisplay, BITSPIXEL); //每个象素的位数
DWORD dwLineBits = 0; //每行字节数
switch (nBits)
{
case 16:
dwLineBits = nScreenWidth*2;
break;
case 24:
dwLineBits = (nScreenWidth+1)*3-((nScreenWidth+1)*3)%4;
break;
case 32:
dwLineBits = nScreenWidth*4;
break;
default:
//其他情况(这里产生资源泄漏,只是例子,所以没管)
MessageBox(NULL, _T("不支持该格式!"), _T("不支持!"), MB_OK);
break;
}
//下面分配内存
DWORD dwBitsCount = dwLineBits * nScreenHeight;
DWORD dwFileSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwBitsCount;
BYTE * pMem = (BYTE *)GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, dwFileSize);
if (NULL == pMem)
{
MessageBox(hWnd, _T("分配内存失败!"), _T("错误!"), MB_OK);
return;
}
BITMAPFILEHEADER* pBMPHeader = (BITMAPFILEHEADER*)pMem;
BITMAPINFOHEADER* pInfoHeader = (BITMAPINFOHEADER*)((BYTE *)pBMPHeader + sizeof(BITMAPFILEHEADER));
BYTE* pBits = (BYTE*)pInfoHeader + sizeof(BITMAPINFOHEADER);
//下面初始化
pBMPHeader->bfType = ('M'<<8) | 'B';
pBMPHeader->bfSize = dwFileSize;
pBMPHeader->bfReserved1 = 0;
pBMPHeader->bfReserved2 = 0;
pBMPHeader->bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

pInfoHeader->biSize = sizeof(BITMAPINFOHEADER);
pInfoHeader->biWidth = nScreenWidth;
pInfoHeader->biHeight = nScreenHeight;
pInfoHeader->biPlanes = GetDeviceCaps(hDisplay, PLANES); //调色板数
pInfoHeader->biBitCount = nBits;
pInfoHeader->biCompression = BI_RGB;
pInfoHeader->biSizeImage = dwBitsCount;
pInfoHeader->biXPelsPerMeter = GetDeviceCaps(hDisplay, LOGPIXELSX);
pInfoHeader->biYPelsPerMeter = GetDeviceCaps(hDisplay, LOGPIXELSY);
pInfoHeader->biClrUsed = 0;
pInfoHeader->biClrImportant = 0;

//下面得到数据
int nLines = GetDIBits(hDisplay, hBmp, 0, nScreenHeight,
pBits,
(BITMAPINFO *)pInfoHeader,
DIB_RGB_COLORS);
if (0 == nLines)
{
DWORD errno = GetLastError();
MessageBox(hWnd, _T("复制位图数据失败"), _T("错误!"), MB_OK);
return;
}
DeleteDC(hDisplay);
hDisplay = NULL;
DeleteObject(hBmp);
hBmp = NULL;
DeleteObject(hOldBmp);
hOldBmp = NULL;
//下面保存文件
HANDLE hFile = CreateFile(pFilePath, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
if (NULL == hFile || INVALID_HANDLE_VALUE == hFile)
{
MessageBox(hWnd, _T("文件已经存在!"), _T("错误!"), MB_OK);
return;
}
//写入
DWORD dwWriteCount = 0;
if (!WriteFile(hFile, (void *)pBMPHeader, dwFileSize, &dwWriteCount, NULL))
{
MessageBox(NULL, _T("写入文件失败!"), _T("错误"), MB_OK | MB_ICONEXCLAMATION);
CloseHandle(hFile);
return;
}
//关闭文件
CloseHandle(hFile);
GlobalFree((void *)pBMPHeader);
}
你可以把数据pBits传给客户端,并在客户端用于显示。这样显示一帧效果可以,但是要把屏幕实时的传输给客户端显示,必须得把图像数据压缩之后再传输给客户端,客户端接收到视频流(差不多吧)再解码显示。所以你这个问题的解决办法可以从两方面来解决:
a.选用好的压缩视频的算法,如用H.231,MPEG4等这个比较蛮烦,我不讲了。
b.这个方法要实现也不容易:
就是根据你的屏幕的内容,来分为几个部分,如文字部分,图标部分,窗口部分,及图像部分等,
然后对所有的部分都只用256色(或者16色,效果差一些),图像的效果不会下降很多,然后分别对各个部分进行压缩传输和解压显示,如文字比较单调,可以用一种颜色表示,图标用16色来表示,窗口部分都是很标准的,可以用固定的几种颜色表示,对于图像可以用256色来表示,其它的步骤跟上面差不多,不过这种方法很麻烦,要用到很多的图像分割、分类、压缩知识,我也在研究这些,可能知识梦想吧!请楼主和各位参看!!!
isaacyh 2005-03-01
  • 打赏
  • 举报
回复
TO huanyun(无妻徒刑)

谢谢你的回答先,但这样做的话其实在差异比较时会耗费大量的CPU资源,机器的相应是很慢的。。。还有这样的话其实还是调BitBlt来做的,对于我的少量的视频就不行了。。。

To jintiger()

这很正常呀,它们不是同一个东西呀,个人感觉C++比C#更底层。。。
jintiger 2005-03-01
  • 打赏
  • 举报
回复
我就不明白,你学会了从c#,怎么连从c++都不董呢。
huanyun 2005-03-01
  • 打赏
  • 举报
回复
本地缓存:取图于本地前一次缓存做差异比较,直传输有差异的部分,带宽可大幅度减小.

19,468

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧