VC多媒体编程

2020年05月25日 阅读数:189
这篇文章主要向大家介绍VC多媒体编程,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

 

--  VC多媒体编程本文来自http://study.feloo.com/ css


--  做者:admin --  发布时间:2006-8-11 16:05:00c++

 --  Visual C++中基于多文档视窗模型的重叠图象拼接技术摘要   程序员

图象拼接是在全景视频系统、地理信息系统等应用中常常遇到的一个问题,本文基于网格匹配的方法对边界部分有重叠的图象提出了一种行之有效的对准算法,并经过平滑因子对图象实现了无缝拼接。并应用文档视窗模型实现了该算法,并完成了位图文件的显示、存储等操做,具备必定的广泛意义。 算法

关键词:     图象拼接,算法,重叠图象,文档视窗,位图文件,图象显示 sql

文章正文 数据库

1、      多文档视窗模型概述 MFCAppWizard能够生成三种类型的应用程序:基于对话框的应用、单文档应用(SDI)和多文档应用(MDI)。三种应用中,以多文档应用(MDI)最为复杂,其功能也最强大。当咱们用AppWizard生成一个多文档应用时,系统由CMultiDocTemplate自动生成了一个从Cdocument类继承的文档类,一个从Cview类继承的视窗类,一个从CMDIChildWnd类继承的框架类。当咱们每次创建一个新的文档时,程序根据文档模板生成一个新实例,这些咱们都可不用关心AppWizard已经自动生成了代码。但若是咱们要在程序中使用多个不一样的文档类时,则需本身创建文档模板并控制文档实例的创建。假设咱们要向一基于多文档的工程MDI中增长一Test的文档。编程

具体步骤以下: windows

1、用Clazard创建一个框架类CTestFrame基类选CMDIChildWnd api

2、用Clazard创建一个文档类CTestDoc基类选CDocument 数组

3、用Clazard创建一个文档类CTestView基类选CView

4、将三个类的头文件加入应用类CMDIApp中。

5、建立新文档模板,在CMDIApp::InitInstance()函数中加入以下代码  

  CMultiDocTemplate* pDocTemplate;     

pDocTemplate = new CMultiDocTemplate(        IDR_TESTTYPE,       

RUNTIME_CLASS(CTestDoc),       

 RUNTIME_CLASS(CTestFrame),       

 RUNTIME_CLASS(CTestView));     

AddDocTemplate(pDocTemplate);

 6、定义一菜单项ID号为ID_NEWTEST,利用Clazard将其处理函数加入应用类(或主框架类),在其处理函数CMDIApp::OnNewtest()函数中加入以下代码     

POSITION curTemplatePos = GetFirstDocTemplatePosition();     

while(curTemplatePos != NULL)     

{        //取下一个文档模板指针       

 CDocTemplate* curTemplate =GetNextDocTemplate(curTemplatePos);       

 CString str;       

curTemplate->GetDocString(str, CDocTemplate::docName);  

//取文档名称       

 if(str == _T("Test"))  

 //判断当前文档文档是否Test       

 {           

curTemplate->OpenDocumentFile(NULL);

//建立新的文档实例           

 return;

}       

 }     

这样咱们就创建了一个新的文档类。注意在5中建立文档模板时咱们用到了一文档类型资源IDR_TESTTYPE,该资源ID在资源文件中定义以下(未包括图标和菜单的定义)

STRINGTABLE PRELOAD DISCARDABLE BEGIN     ……….    

 IDR_TESTTYPE      //nTest//nTest//n//n//nMDI.Document//nTest Document

END   

文档类型标识包括七个子串,包括窗口标题、文档名称、文件扩展名等。

6curTemplate->GetDocString(str, CDocTemplate::docName);取的就是第二个子串,文档名称。

文档创建以后咱们就能够对其进行操做了。固然文档类和视窗类,文档类和主窗口类,以及不一样文档类之间进行通讯也是较为复杂的,并不是几句话就能说清楚,如不熟悉文档视窗的读者请参看其它有关资料。

2、      重叠图象拼接技术

1.算法思想

在实现全景视频(Panoramic Video)系统、地理信息系统(GIS)及其它一些应用的过程当中,咱们一般会碰到这样的一个问题,就是要把几幅小的图象拼接成一幅大的图象。为了能让计算机自动对准图象咱们要求待拼接的图象边界有部分重叠,计算机正是利用这些信息进行匹配对准。匹配算法的整体思想是既要保证对准的精度,又要保证运算量不至过大。这里算法利用了图象的自身特性,既在通常图象中,相邻的象素点的灰度值相差不大。所以,可在第二幅图象的边界取一个网格,而后将网格在第一幅图象上移动,计算全部网格点的两幅图象对应象素点的RGB值的差的平方和。记录最小的值的网格位置,即认为是最佳匹配位置。(如图1)为了减少运算量,咱们将匹配分为两个步骤,第一步是粗略匹配,在该阶段网格每次水平或垂直移动一个网格间距。在完成粗略匹配以后,咱们在当前最佳匹配点处进行精确匹配,在该阶段以当前最佳匹配点为中心,网格向上下、左右各移动一个小步长。初始步长为粗略拼接时移动步长的一半,即为半个网格间距。不断的与当前最小平方和进行比较,若是比当前值优,就替换当前最佳匹配点。循环进行这个过程每次步长减半,直到水平步长和垂直步长均为0为止。

2.算法描述

 procedure ImageMatching {    

 输入FirstImage;     

输入SecondImage;    

 //得到两幅图象的大小     

Height1=GetImageHeight(FirstImage);     

Height2=GetImageHeight(SecondImage);     

Width1=GetImageWidth(FirstImage);     

Width2=GetImageWidth(SecondImage);

// 从第二幅图象取网格匹配模板     

SecondImageGrid = GetSecondImageGrid(SecondImage);

// 粗略匹配,网格在第一幅图象中先从左向右移动,再从下到上移动,每次移动一个网格间距,Step_Width Step_Height,当网格移出重叠区域后结束

y=Heitht1-GridHeight; MinValue = MaxInteger;

While ( y<Height1-OverlapNumber)

//当网格移出重叠部分后结束

{       

 x=Grid_Width/2;

//当网格位于第一幅图象的最左边时,A点的横坐标。       

While ( x<(Width1-Grid_Width/2) ) {           

 FirstImageGrid=GetImgaeGrid(FirstImgaeGrid, x, y);        

 differ=CaculateDiff(FirstImgaeGrid, SecondImageGrid);

//计算象素值差的平                               

//方和           

 if (differ<MinValue)           

 {              

 BestMatch_x=x;               

BestMatch_y=y;              

 MinValue = differ;           

}       

x= x+Step_width;       

 }       

y=y-Step_Height; }  

//精确匹配

Step_Width= Step_Width/2;

Step_Height= Step_Height/2;

 While ( Step_Height>0 & Step_Width>0)

//当水平步长和垂直步长均减为零时结束

{     if(Step_Height==0)

//当仅有垂直步长减为零时,将其置为1       

Step_Height=1;    

 If(Step_Width==0)

//当仅有水平步长减为零时,将其置为1       

Step_Width=1; temp_x = BestMatch_x; temp_y = BestMatch_y;    

 for ( i= -1; i<1; i++)       

 for( j= -1; j<1; j++)       

 {          

  if ((i=0&j!=0)|(i!=0&j=0))           

 {              

 FirstImageGrid=GetImgaeGrid(FirstImgaeGrid, temp_x+i*Step_Width, temp_y +j*Step_Height);           

differ=CaculateDiff(FirstImgaeGrid, SecondImageGrid);       

 if (differ<MinValue)              

 {                   

BestMatch_x=x;                   

BestMatch_y=y;                 

  MinValue = differ;           

}            }           }       

Step_Height = Step_Height /2;       

 Step_Width = Step_Width/2;     } }  

 3、      基于多文挡视窗模型的重叠图象拼接技术 程序在Visual C++实现过程当中有以下一些技术问题须要注意。

 1 位图文件的读取和显示 位图文件是一种最简单的图象文件,屏幕图象的每一点对应位图文件的几位数据。现有的标准有1位、4位、8位、24位。24位位图不含颜色表,每一个象素用3个字节表示,依次表示RGB空间里的蓝、绿、红的灰度值。每种位图文件都由两部分组成,一部分是文件头和位图信息头,另外一部分是图象的位数组。所以要想显示一个位图文件首先要声明一个CFile类实例将文件读入内存,而后根据文件头和位图信息头得到图象的相关信息和位数组的起始地址。调用SetDIBitsToDevice()函数便可把图象显示在屏幕上。

2 位图文件中任意象素点颜色值的获取 要实现图象的处理,访问任意象素点的象素值是必需的操做。在访问位图文件时有两点须要注意,一是图象位数组的存储是按从下到上进行的。也就是说,图象的最底行的数据存在位数组的最开始位置。另外一个特色是,图象的每行象素所占的空间是双字的整数倍,不足的用零填充。每行象素的实际存储大小可由如下公式加以计算。  

 WidthBytes=(((biWidth*biBitCount)+31)&~31)>>3            

1   假设位数组的起始指针为lpStartBits屏幕坐标(x,y)在的象素值的指针可用下式计算。

 lpBits=lpStartBits + (WidthBytes*(Height-y-1) + x*biBitCount);            

(2)   其中WidthBytes为(1)式计算的值,Height为图象的高度。

3 不一样文档类之间的数据交换的实现 不一样文档类之间的数据交换咱们能够经过应用程序类或主窗口类做为媒介进行。在文档类或视窗类可经过AfxGetApp()AfxGetMainWnd()得到应用类和主窗口类的指针,在应用类和主窗口类则能够经过得到文档模板来得到文档类的指针来访问文档类的数据。这样咱们能够经过应用类或主窗口类的成员变量进行数据交换了。

 4 图象的平滑链接 当找到最佳匹配点后,随后的工做将是把两幅图象合成一幅图象。对于重叠部分,咱们若是只是简单的取第一幅图象或第二幅图象的数据,会形成图象的模糊和明显的边界,这是不能容忍的。即便取两幅图象的平均值,效果也不能使人满意。为了能使拼接区域平滑,保证图象质量,咱们采用了渐入渐出的方法,即在重叠部分由第一幅图象慢慢过渡到第二幅图象,很天然咱们能够想到设一渐变因子为0<d<1,对应的先后两幅图象为image1image2,结果为image3,则image3=d*image1+(1-d)*imge2其中d的值由1渐变到0,它与该点距重叠边界的距离有关。

 4、      多文挡视窗模型的重叠图象拼接程序框架

1 程序构成 程序除应用类、主窗口类之外,还包括CFristImageDoc, CSecondImageDoc, CThirdImageDoc类用来保存第一幅、第二副以及拼接后图象的数据。还有与其相连的文档类和框架类。

2 程序流程 程序的主要工做在应用类中完成,首先打开第一幅图象,图象的显示等操做由CFirstImageDoc 类和与其相关的视窗类及框架类完成,并将图象的位数组指针和图象大小传给应用类成员变量。再打开第二幅图象一样完成显示等操做,也将位数组指针和图象大小传给应用类成员变量。在应用类中完成图象的匹配对准工做,最后实现图象的合成。将合成后的图象传给CThirdImageDoc类进行显示当用户对拼接结果基本满意后,能够选择平滑链接将两幅图象平滑的链接起来。用户可将最后的结果保存成bmp文件。

5、      总结

图象拼接中,图象对准是前提和关键,程序基于网格匹配的方法实现了图象对准,应用了交互技术让用户能够对网格点的多少,网格间距大小,都可调整,还容许用户输入重叠范围使拼接过程有的放矢,缺省是较小图象高度的1/3。该程序实现了对位图图象文件的各类操做,具备广泛意义,还引入了不一样文档类型的多文档视窗模型,并在不一样文档类间实现了数据交换,具备必定的实用价值。为了使程序简单易用,只实现了对24位位图的拼接,也未提供垂直方向的拼接,只提供了水平方向的拼接。如要对不符合条件的图象进行拼接咱们只需在Windows提供的画笔中将图象转化一下便可


--  做者:admin --  发布时间:2006-8-11 16:06:00

--  VC下显示JPEGGIF格式图像的一种简便方法

1、 引言 JPEG图像压缩标准随然是一种有损图像压缩标准,但因为人眼视觉的不敏感,经压缩后的画质基本没有发生变化,很快便以较高的压缩率获得了普遍的承认。GIF格式虽然仅支持256色但它对于颜色较少的图像有着很高的压缩率,甚至超过JPEG标准,也获得了普遍的认同。但做为众多程序员的一个重要的开发工具--Microsoft Visual C++ 6.0MFC库却仅对没有通过任何压缩的BMP位图文件有着良好的支持,能够读取、显示、存储甚至在内存中建立一块内存位图。因为BMP格式的图像没有通过任何的压缩,不管是做为程序的外部文件,仍是做为程序的内部资源都要占据大量的空间,尤为是后者会大大增长可执行文件的长度。能够看出,若是能用通过压缩、具备较好的压缩率的JPEGGIF格式的图像来取代BMP文件在VC中的应用,无疑仍是颇有吸引力的。

 2、 设计思路 虽然有一些操做、处理JPEGGIF等其余格式图像的Active X控件,但总的来讲使用起来并不太方便,笔者通过实验摸索,总结出了一种借助于COM接口的OLE方法来实现上述功能的一种简便方法,现介绍以下以飨广大读者:

下面咱们要使用IPicture COM接口,有必要对该图像接口作些了解:

该接口主要管理图像对象及其属性,图像对象为位图、图标和图元等提供一种与语言无关的抽象。和标准的字体对象同样,系统也提供了对图像对象的标准实现。其主要的接口是IPictureIPictureDisp,后者是由IDispatch接口派生以便经过自动化对图像的属性进行访问。图像对象也支持外部接口IPropertyNotifySink,以便用户能在图像属性发生改变时做出决定。图像对象也支持IPersistStream接口,因此它能从一个IStream接口的实例对象保存、装载本身,而IStream接口也支持对流对象的数据读写。 咱们能够用函数OleLoadPicture从包含有图像数据的流中装载图像。该函数简化了基于流的图像对象的建立过程,能够建立一个新的图像对象而且用流中的内容对它进行初始化。

其函数原型为:

STDAPI OleLoadPicture( IStream * pStream,

//指向包含有图像数据的流的指针LONG lSize, //从流中读取的字节数BOOL fRunmode,

 //图像属性对应的初值REFIID riid,

//涉及到的接口标识,描述要返回的接口指针的类型VOID ppvObj

// rrid中用到的接口指针变量的地址);

3、 具体的实现 在显示图像以前,首先要获取到图像文件的存放路径,这里采用标准的文件打开对话框来选取图像文件,文件名存放在CString型的变量m_sPath中:

CFileDialog dlg(TRUE,"jpg","*.jpg", OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, "JPEG文件(*.jpg)|*.jpg|GIF文件(*.gif)|*.gif||",NULL);

 if(dlg.DoModal()==IDOK)

{ m_sPath=dlg.GetPathName(); Invalidate(); }

为简单计,图形显示的代码直接在视类中的OnDraw中编写,首先打开文件并判断文件的可用性,并把文件内容放到流接口IStream的对象pStm中:

IStream *pStm;

CFileStatus fstatus;

CFile file;

LONG cb; ……

if (file.Open(m_Path,CFile::modeRead)&&file.GetStatus(m_Path,fstatus)&& ((cb = fstatus.m_size) != -1))

{ HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, cb);

LPVOID pvData = NULL;

if (hGlobal != NULL)

{ if ((pvData = GlobalLock(hGlobal)) != NULL)

{ file.ReadHuge(pvData, cb);

GlobalUnlock(hGlobal);

CreateStreamOnHGlobal(hGlobal, TRUE, &pStm); } } }

而后,就直接调用OleLoadPicture函数从流中装载图像:

 IPicture *pPic;

 …… OleLoadPicture(pStm,fstatus.m_size,TRUE,IID_IPicture,(LPVOID*)&pPic));

因为该函数有时会致使失败,因此应当用SUCCEEDED宏来作一些适当的保护工做,只有在数据装载成功的前提下才能继续下面的图像显示工做:

if(SUCCEEDED(OleLoadPicture(pStm,fstatus.m_size,TRUE,IID_IPicture,(LPVOID*)&pPic)))

{

 OLE_XSIZE_HIMETRIC hmWidth;

OLE_YSIZE_HIMETRIC hmHeight;

 pPic->get_Width(&hmWidth);

 pPic->get_Height(&hmHeight);

double fX,fY;

 ……

fX = (double)pDC->GetDeviceCaps(HORZRES)*(double)hmWidth/((double)pDC->GetDeviceCaps(HORZSIZE)*100.0);

fY = (double)pDC->GetDeviceCaps(VERTRES)*(double)hmHeight/((double)pDC->GetDeviceCaps(VERTSIZE)*100.0);

if(FAILED(pPic->Render(*pDC,0,0,(DWORD)fX,(DWORD)fY,0,hmHeight,hmWidth,-hmHeight,NULL)))

 AfxMessageBox("渲染图像失败!");

pPic->Release(); }

else AfxMessageBox("从流中装载图像失败!");

 其中,显示工做主要是由IPicture接口对象的Render函数来完成的,该函数主要用来将图片的指定部分画到指定的设备环境的指定位置。原型以下:

 HRESULT Render( HDC hdc,

//渲染图像用的设备环境句柄 long x,

 //hdc上的水平坐标 long y,

//hdc上的垂直坐标 long cx,

//图像宽度 long cy,

//图像高度 OLE_XPOS_HIMETRIC xSrc,

//在源图像上的水平偏移 OLE_YPOS_HIMETRIC ySrc,

//在源图像上的垂直偏移 OLE_XSIZE_HIMETRIC cxSrc,

//在源图像上水平拷贝的数量 OLE_YSIZE_HIMETRIC cySrc,

//在源图像上垂直拷贝的数量 LPCRECT prcWBounds

//指向目标图元设备环境句柄的指针);

小结:到此为止,经过上述代码已经可以在程序的客户区内显示JPEGGIF等标准的图像了,但对于有多帧图片(即有动画)的GIF格式的图像,目前还只能显示第一帧,如要完整的显示GIF 动画的全过程,还须要外部Active X控件的支持。


--  做者:admin --  发布时间:2006-8-11 16:07:00 --  Visual C++实现Flash动画播放

程序运行效果截图:

摘要: 本文经过在VC中将外格式文件内嵌为VC的内部资源,使其在程序运行过程当中从资源动态释放到临时文件,从而实现VCFlash动画的播放。   

引言   

Flash动画因为能够很方便地把用户的想象经过动画显现出来,使本来只属于专业制做人员的动画制做变的异乎寻常的快捷、方便。因为Flash制做的动画在层次、内容、表现形式等诸多方面均比较出色,所以在网络上获得迅猛的发展,更有很多厂商用Flash在互联网上作起了广告和产品演示,效果丝绝不比视频的差,而体积则要小的多。Flash不只在网络上有普遍的应用,在普通的应用程序中也能够借助Flash实现一些VCDelphi等编程语言所难以实现的特效,好比在一些演示版的程序中彻底能够将程序运行前的闪屏用Flash来制做。本文下面将经过对内嵌资源的动态释放来实现VCFlash动画的播放,并给出了部分实现代码。   

嵌资源的动态释放   

 Flash动画在此是做为程序的一个模块,虽然也能够以文件的形式做为一个外部资源来使用,但为了不因外部模块遗失而形成程序的非正常运行,可将由Flash 5.0预先制做好格式的文件以资源的形式打包到应用程序中去,而在程序运行时再将其从资源恢复到文件,使用完毕再经过程序将其从磁盘删除。   

在导入资源时由格式文件并不是VC的标准资源,因此在导入时须要在"Resource type"栏指定资源类型",特别须要注意的是在此必需要包含引号。加入到资源后能够经过资源视图看到导入资源是以二进制形式保存的,一但加入就不能再经过资源视图对其进行编辑了。     

在使资源前首先要将其动态从应用程序中释放到文件中才可对资源作进一步的使用。可先经过宏MAKEINTRESOURCE()将资源标识号IDR转换成字符串Name,再分别经过FindResource()LoadResource()函数查找、装载该资源到内存:

CString Type="

HRSRC res=FindResource (NULL,Name,Type);

HGLOBAL gl=LoadResource (NULL,res);   

当资源加载到内存后,还要经过对资源内存的锁定来返回指向资源内存的地址的指针,并籍此实现资源从内存到磁盘的保存,至于存盘的操做则由文件函数CreateFile()、和WriteFile()来完成:

 LPVOID lp=LockResource(gl);

//返回指向资源内存的地址的指针。

 CString filename="Temp"

 //保存的临时文件名

 // CREATE_ALWAYS为无论文件存不存在都产生新文件。

fp= CreateFile(filename ,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL);

DWORD a;

//sizeofResource 获得资源文件的大小

if (!WriteFile (fp,lp,SizeofResource (NULL,res),&a,NULL))

return false;

 CloseHandle (fp);

//关闭句柄

 FreeResource (gl);

//释放内存   

 经过上述代码,可资源从应用程序中提取并释放到临时文件Temp中,在此后只对此临时文件操做,与程序内嵌资源无关。   

Flash动画的播放   

格式的Flash动画一般主要应用在网页上,也就是说IE浏览器自己能够支持Flash动画的播放。这样就没必要再单独编写用于播文件的代码,从而大大减小编程的工做量。在VC ++ 6.0中新增了一个从CView派生的、用于处理网页的视类CHtmlView,因为该类是以Internet Explorer为后台支持,所以在建立工程时只需在最后一步指定视类从CHtmlView派生就能够使程序不编一行代码而具有IE浏览器的网页显示能力。   

程序刚生成的时候缺省的链接主页是为微软公司的主页,须要对此修改,使程序在执行时当即显示刚才提取出来的Flash临时文件Temp

显示缺省主页的代码是在视类的初始化函数中进行的:

void CEmbedModuleView::OnInitialUpdate()

{ CHtmlView::OnInitialUpdate();

 Navigate2(_T("http://www.microsoft.com"),NULL,NULL); }   

 

 显然要将Navigate2()函数的第一个参数改为Temp的存放路径。刚才在释放资源到文件时并无指定绝对路径,所以释放出来的资源文件应当和应用程序处于同一目录。可是在此处若是不写明绝对路径是没法显示该临时文件的。获取该临时文件的绝对路径可用以下方法实现:先获取应用程序自己的绝对路径,而后去处应用程序全名(程序名和扩展名)此时获得的是应用程序和临时文件所处文件夹的路径,最后只需在此基础上加上临时文件的文件名Temp便可获得临时文件的全路径。下面是实现的主要代码:

 //获取应用程序的全路径

 

char exeFullPath[MAX_PATH];

 GetModuleFileName(NULL,exeFullPath,MAX_PATH);

//将其格式化为字符串

m_TempFile.Format("%s",exeFullPath);

//去掉应用程序的全名(15为应用程序文件全名的长度)

 exeFullPath[m_TempFile.GetLength()-15]=/'/';

//获得应用程序所在路径

m_TempFile.Format("%s",exeFullPath);

 //获得临时文件的全路径

m_TempFile+="Temp";   

最后将获得的临时文件的全路径m_TempFile做为参数传递给Navigate2()便可在程序运行时把Flash动画做为主页而显示(如上图所示)。   

因为临时文件Temp是在程序运行过程当中从应用程序的资源中提取出来的,所以在程序退出以前须要将其删除。通常是在消息WM_DESTORY的响应函数里经过DeleteFile()函数来加以实现的。   

小结   

本文经过对CHtmlView和内嵌资源的动态释放实现了Flash动画在VC程序中的播放,并对资源的动态释放做了较为清晰的描述。经过相似的方法,能够将动态连接库、HTML文件等程序模块做为资源嵌入其中,在使用时再动态释放到临时文件,这样可有效避免文件模块过多时的杂乱以及程序模块丢失致使程序非正常运行等状况的发生。本文所述程序在Windows 98下,由Microsoft Visual C++ 6.0编译经过。Flash动画由 Macromedia Flash 5.0制做,所需浏览器支持为Internet Explorer 6.0


--  做者:admin --  发布时间:2006-8-11 16:08:00 --  RealPlayer控件制做的播放器

下载本文所附源代码 程序运行效果截图:

本文介绍如何插入RealPlay控件实现媒体文件的播放,代码运行效果图如左:

下面简要介绍一下具体实现步骤:

1、创建基于对话框的程序

2、在对话框内添加RealPlayer G2 controlActiveX控件 (工程->添加工程->compontent and controls->registed ActiveX controls )

3、在对话框内添加源程序内所示的按钮和静态文本 分别用于控制打开播放等控制及显示歌曲信息 ID号如源程序

4、用MFC映射各按钮消息

void CSunapplerealplayerDlg::OnOpen()

{

char szFileFilter[]=     "RM File(*.rm)|*.rm|"         "Mp3 File(*.mp3)|*.mp3|"         "MPEG File(*.mpeg)|*.mpeg|"         "Media File(*.asf)|*.asf|"         "Video File(*.dat)|*.dat|"         "MPGA File(*.mpga)|*.mpga|"         "Wave File(*.wav)|*.wav|"         "AVI File(*.avi)|*.avi|"         "Movie File(*.mov)|*.mov|"         "Mid File(*.mid;*,rmi)|*.mid;*.rmi|"         "Wma File(*.wma)|*.wma|"         "All File(*.*)|*.*||";     

CFileDialog dlg(TRUE,NULL,NULL,OFN_HIDEREADONLY,szFileFilter);     

if(dlg.DoModal()==IDOK){         

CString PathName=dlg.GetPathName();        

PathName.MakeUpper();         

m_player->SetSource(PathName);        

 m_player->DoPlay();         

SetDlgItemText(IDC_STATIC1,m_player->GetAuthor());       

SetDlgItemText(IDC_STATIC2,m_player->GetTitle());       

SetDlgItemText(IDC_COPYRIGHT,m_player->GetCopyright());       

SetDlgItemText(IDC_SOURCE,m_player->GetSource());     }     }

 

void CSunapplerealplayerDlg::OnPlay() {       

SetDlgItemText(IDC_STATIC1,m_player->GetAuthor());    

 SetDlgItemText(IDC_STATIC2,m_player->GetTitle());     

SetDlgItemText(IDC_COPYRIGHT,m_player->GetCopyright());    

 SetDlgItemText(IDC_SOURCE,m_player->GetSource());

  m_player->DoPlay();          

UpdateData(false);    

 SetTimer(1,20,NULL); }

 

void CSunapplerealplayerDlg::OnTimer(UINT nIDEvent) {  

 if(0&&isRepeat)         

m_player->DoPlay();  

CDialog::OnTimer(nIDEvent); }

 

void CSunapplerealplayerDlg::OnClose() {    

 ///////添加此代码时不要忘了在stdafx.h开头处添加前两行    

 AnimateWindow(GetSafeHwnd(),1000,AW_HIDE|AW_BLEND);     

KillTimer(0);

//////////////////////////////////// //此处采用DestroyWindow关闭窗口

//多谢杜修杏 老师指点 ///////////////////////////////////    

 this->DestroyWindow();      }

void CSunapplerealplayerDlg::OnFullscreen() {     

 m_player->DoPause();    

  m_player->SetFullScreen();    

  m_player->DoPlay(); }

void CSunapplerealplayerDlg::OnMp3down() {    

 ShellExecute(NULL,_T("open"),"http://sunapple.51.net",NULL,NULL,TRUE);     

 }

 

 void CSunapplerealplayerDlg::OnPause() {   

  m_player->DoPause(); }

void CSunapplerealplayerDlg::OnStop() {    

 m_player->DoStop();    

 KillTimer(0); }

 

void CSunapplerealplayerDlg::OnRepeat() {    

 m_player->SetLoop(true);    

 if(isRepeat){       

  isRepeat=FALSE;         

SetDlgItemText(IDC_REPEAT,"循环");   }

  else   {      

 isRepeat=TRUE;       

SetDlgItemText(IDC_REPEAT,"正常");  

 } }

 

void CSunapplerealplayerDlg::OnLower() {    

 // TOD Add your control notification handler code here     

short volume=m_player->GetVolume();     

m_player->DoPause();     

m_player->SetVolume(volume-100);    

 m_player->DoPlay(); }

 

void CSunapplerealplayerDlg::OnUpper() {    

 // TOD Add your control notification handler code here    

 short volume=m_player->GetVolume();     

m_player->DoPause();     

m_player->SetVolume(volume+100);    

 m_player->DoPlay(); }

 

void CSunapplerealplayerDlg::OnFloat() {     

//  TOD Add your command handler code here     

ShellExecute(NULL,_T("open"),"http://sunapple.51.net",NULL,NULL,TRUE); }

 

void CSunapplerealplayerDlg::OnPetroleum() {   

  // TOD Add your command handler code here     

ShellExecute(NULL,_T("open"),"http://www.hdpu.edu.cn",NULL,NULL,TRUE); }

 

5、映射WM_CTLCOLOR消息,用于控制文本显示的颜色

 HBRUSH CSunapplerealplayerDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {    

 HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);       

 if(nCtlColor==CTLCOLOR_STATIC)       

  if(pWnd.GetDlgCtrlID()==IDC_VOLUME)         

{            

 pDC.SetTextColor(RGB(165,182,222));            

 pDC.SetBkMode(TRANSPARENT);            

 return (HBRUSH) m_brush.GetSafeHandle();         }        

 if(pWnd.GetDlgCtrlID()==IDC_STATIC1||pWnd.GetDlgCtrlID()==IDC_STATIC2         ||pWnd.GetDlgCtrlID()==IDC_SOURCE||pWnd.GetDlgCtrlID()==IDC_COPYRIGHT)         

{            

 pDC.SetTextColor(RGB(0,0,255));            

 pDC.SetBkMode(TRANSPARENT);            

 return (HBRUSH) m_brush.GetSafeHandle();         }         

if(pWnd.GetDlgCtrlID()==IDC_STATIC||pWnd.GetDlgCtrlID()==IDC_INFO)        

 {      pDC.SetTextColor(RGB(255,0,0));             

pDC.SetBkMode(TRANSPARENT);            

 return (HBRUSH) m_brush.GetSafeHandle();        

 }    

 // TOD Return a different brush if the default is not desired     

return hbr; }

6、在APP类里的initInstance()里添加下面函数改变对话框背景。 SetDialogBkColor(RGB(206,227,99));

7、为了美观咱们的外形可引入CButtonXP,将个按钮类型设置为CButtonXP 好了,应该大功告成了!调试一下吧! 本程序在调试过程当中要多谢杜修杏老师的指点


--  做者:admin --  发布时间:2006-8-11 16:09:00

--  Visual C++编程控制鼠标鼠标是如今计算机的标准配置,不少软件都有控制鼠标的功能,好比,有的保密软件能够使鼠标移动限制在必定范围之内,有的能够模拟鼠标的点击,有的能够使鼠标本身移动。要实现以上的功能,必须使用WindowsAPI函数。   

 咱们如下面的程序例子,来讲明如何控制鼠标。咱们使用Visual C++6.0来写这个程序。打开Visual C++6.0,使用MFC AppWizard新建1个基于对话框的工程,工程名为Mouse,在对话框上加上2button控件,一个标题为"控制鼠标移动范围",另外1个的标题是"释放鼠标"MFC Clazard中添加两个当咱们使用鼠标单击这两个控件时响应的函数,标题为"控制鼠标移动范围"的控件的响应函数代码为:

//首先使用GetWindowRect得到这个程序窗口的范围

CRect rect this->GetWindowRect&rect

 //而后使用ClipCursor函数把鼠标控制在这个范围之内,这个函数的功能就是控制鼠标的范围。

ClipCursor&rect   

 标题为"释放鼠标"的控件的响应函数代码为:

ClipCursorNULL   

 这行代码很是简单,就是使鼠标能够自由移动,不受限制。   

 把以上程序编译好了之后运行,点下"控制鼠标移动范围"按钮,鼠标就只能在这个窗口的范围之内活动,离不开这个窗口了,点下"释放鼠标"按钮,鼠标就恢复正常了。   

 知道了如何控制鼠标范围,该讲讲如何移动鼠标了。移动鼠标很是简单,只须要一个API函数SetCursorPos,这个函数有2个参数,1个参数是屏幕的x坐标,2个参数是屏幕的y坐标,它能够把鼠标移动到指定的坐标上去。   

 模拟鼠标的点击功能也很是简单,好比模拟点鼠标右键,能够使用下面两行代码:

 mouse_eventMOUSEEVENTF_RIGHTDOWN0000

mouse_eventMOUSEEVENTF_RIGHTUP0000   

mouse_even

t函数的功能就是模拟鼠标点击,1行代码是模拟按下鼠标右键,2行代码是模拟鼠标右键弹起,这两行代码就模拟了1次点击鼠标右键的操做,若是想模拟点鼠标左键的操做,只要以上两行代码中的MOUSEEVENTF_RIGHTDOWNMOUSEEVENTF_RIGHTUP参数换成MOUSEEVENTF_LEFTDOWNMOUSEEVENTF_LEFTUP就能够了。   

 鼠标的模拟操做讲完了。以上的程序在Windows98,使用Visual V++6.0编译成功,调试正常。 本期知识点:控制鼠标的API函数。


--  做者:admin --  发布时间:2006-8-11 16:11:00

--  VC实现图象渐显和渐隐摘 图象的渐显/渐隐被普遍运用与图象处理和多媒提娱乐软件。本文基于windows的调色板动画和时间码技术设计了通用的图象渐显和渐隐算法,并实现了其visual c++程序编码。 关键词 渐显、渐隐、调色板、调色板动画、时间码 图象的渐显/渐隐是十分重要的图象效果,普遍运用于图象处理和多媒提娱乐软件。渐显/渐隐算法设计的最大困难是速度控制,包括定时和快速改变图象中各象素的颜色。如采用普通的全图扫描算法,则速度较慢,很难真正体现渐显/渐隐效果。

利用windows3.x.95/98/nt)操做系统特殊的调色板管理和时间码定时机制能设计出有效的图象渐显/渐隐算法。windows提供一种被称为调色板动画(palette animation)的颜色处理技术,它经过快速改变颜色调色板中所选取的表项中的颜色能模拟颜色的变化。设置时间码,定时调用该技术使图象颜色渐变就能实现图象的渐显和渐隐。

1、调色板动画 visual c++中实现调色板动画依赖于mfc类库提供的cpalette类和cdc类中的若干成员函数,其基本步骤以下: 调用cpalette::createpalette(lplogpalette lplogpalette)函数建立逻辑调色板,注意将参数lplogpalette所指向的各颜色表项结构的peflags域设置为pc_reserved,以防止其它窗口同该调色板匹配颜色。; 调用cdc::selectpalettecdc::realizepalette函数选择和实现所建立的逻辑调色板; 调用cpalette::animatepalette函数改变颜色,实现调色板动画; 动画完成后应恢复系统调色板。 cpalette::animatepalette是其中最关键的函数,其原型以下:

 void animatepalette( uint nstartindex,

// 起始的表项号

 uint nnumentries,

// 变化的表项数

 lppaletteentry lppalettecolors );

 // 逻辑调色板表项指针

lppalettecolors为指向paletteentry结构的指针,其中存储着逻辑调色板将要更新的颜色信息。paletteentry结构定义以下:

 typedef struct tagpaletteentry {

// pe

byte pered;

byte pegreen;

 byte peblue;

 byte peflags; } paletteentry;

 peredpegreenpeblue分别表示逻辑调色板项的rgb颜色份量值。peflags 应被置为pc_reserved nstartindexlppalettecolors中将变化的起始表项号,nnumentries lppalettecolors中将变化的表项数。

2、时间码定时 cwnd::settimer函数可设置一个系统时间码,并指定每通过必定的时间间隔使windows系统发送一个wm_timer消息到窗口的消息队列中。窗口在每当接收到相应的wm_timer消息时作必定的处理,便实现了定时处理。 一般应在窗口的消息循环中接受和处理wm_timer消息,这样将很难编制通用的定时操做。通用的定时操做应将定时处理封装在一个函数中,而不与其它的代码纠缠在一块儿。笔者实现这一技术的技巧是,在循环操做中截获窗口消息,如消息为指定的时间码消息,则进行定时处理;不然分发消息给窗口消息处理机制。若是定时操做已结束,则修改循环标志,退出循环。具体的代码以下:

……………………………… // 设置时间码,pwnd为处理定时操做的窗口对象指针

 pwnd->settimer(0x100, utimeout, null);

 // 屏蔽鼠标操做,使定时操做不受影响

pwnd->setcapture();

 // 开始定时操做

 bool bdone = false;

 msg msg;

while (! bdone) {

if (::peekmessage(&msg, null, 0, 0, pm_remove))

{

if (msg.message == wm_timer && msg. wparam == 0x100)

{ ………………….. 定时操做代码 …………………..

// 如定时操做完成,则设置循环标志,结束操做

if (定时操做完成) bdone = true; }

::translatemessage(&msg); ::dispatchmessage(&msg); } }

// 释放鼠标

::releasecapture();

 // 删除时间码

pwnd->killtimer(0x100);

…………………………..

函数peekmessage截获窗口消息,translatemessagedispatchmessage函数解释和分发除指定时间码消息以外的全部消息,以免丢失消息。

 3、渐显 渐显就是将显示颜色由黑色(rgb(0, 0, 0))逐渐变化为图象各象素的颜色的过程。开始时调用cpalette::getpaletteentries函数保存图象调色板的各逻辑表项信息,而后调用cpalette::setpaletteentries函数将逻辑调色板中各逻辑表项的peredpegreenpeblue置为0,定时调用cpalette::animatepalette,每次将各逻辑表项的peredpegreenpeblue值增长一个变化量,直到它们分别等于图象逻辑调色板中各逻辑表项的peredpegreenpeblue值。

下面的函数fadein经过对调色板颜色表项中的各颜色份量值先设为0,而后进行递增,直到全部颜色值都恢复成原调色板中颜色值来实现渐显。

// 图象渐显效果

// 参数:

 // pwnd – 显示图象的窗口

 // ppal – 调色板指针

// ndeta – 各颜色份量的减少量

// utimeout – 时间的变化量

void fadein(cwnd *pwnd, cpalette *ppal, int ndeta, uint utimeout) {

// 保留原来的调色板颜色表项

int ntotalcolors = ppal->getentrycount();

paletteentry palettecolors0[256];

 ppal->getpaletteentries(0, ntotalcolors, palettecolors0);

 // 先将调色板表项中各颜色份量置为0

 paletteentry palettecolors1[256];

for (int i=0; i<ntotalcolors; ++i)

{

palettecolors1[i].pered = 0;

palettecolors1[i].pegreen = 0;

 palettecolors1[i].peblue = 0;

palettecolors1[i].peflags = pc_reserved; }

 ppal->setpaletteentries(0, ntotalcolors, palettecolors1);

ppal->animatepalette(0, ntotalcolors, palettecolors1);

// 设置时间码

 pwnd->settimer(0x100, utimeout, null);

// 开始渐显

pwnd->setcapture();

 bool bdone = false; msg msg; while (! bdone)

{

 if (::peekmessage(&msg, null, 0, 0, pm_remove))

{

if (msg.message == wm_timer && msg.wparam == 0x100)

{

cclientdc dc(pwnd);

cpalette *poldpal = dc.selectpalette(ppal, false);

dc.realizepalette();

 // 递增各颜色份量

paletteentry palettecolors[256];

 ppal->getpaletteentries(0, ntotalcolors, palettecolors);

bool bredzero=false

 bool bgreenzero=false;

 bool bbluezero=false;

 for (int i=0; i<ntotalcolors; ++i)

 {

if (palettecolors[i].pered + ndeta < palettecolors0[i].pered)

 { palettecolors[i].pered += ndeta; bredzero = false; }

 else if (palettecolors[i].pered + 1 < palettecolors0[i].pered)

 { palettecolors[i].pered++; bredzero = false; }

Else

 bredzero = true;

if (palettecolors[i].pegreen + ndeta < palettecolors0[i].pegreen)

{ palettecolors[i].pegreen += ndeta;

 bgreenzero = false; }

else if (palettecolors[i].pegreen + 1 < palettecolors0[i].pegreen)

 { palettecolors[i].pegreen++; bgreenzero = false; }

Else

 bgreenzero = true;

 if (palettecolors[i].peblue + ndeta < palettecolors0[i].peblue)

{ palettecolors[i].peblue += ndeta; bbluezero = false; }

 else if (palettecolors[i].peblue +1 < palettecolors0[i].peblue)

 { palettecolors[i].peblue++; bbluezero = false; }

else bbluezero = true; }

// 直到恢复原始值结束

 bdone = bredzero && bgreenzero && bbluezero;

 // 使系统改变调色板

 ppal->animatepalette(0, ntotalcolors, palettecolors);

}

 ::translatemessage(&msg); ::dispatchmessage(&msg); } }

 ::releasecapture(); pwnd->killtimer(0x100);

// 恢复原始调色板

ppal->setpaletteentries(0, ntotalcolors, palettecolors0);

 ppal->animatepalette(0, ntotalcolors, palettecolors0); }

 4、渐隐 渐隐就是将显示颜色由图象各象素的颜色逐渐变化为黑色(rgb(0, 0, 0))的过程,即定时调用cpalette::animatepalette,每次将各逻辑表项的peredpegreenpeblue值减少一个变化量,直到它们都为0

下面的函数fadeout经过对调色板颜色表项中的各颜色份量值进行递减,直到全部颜色值都变成0(即黑色)来实现渐隐。

 // 图象渐隐效果

 // 参数:

// pwnd – 显示图象的窗口

 // ppal – 调色板指针

 // ndeta – 各颜色份量的减少量

 // utimeout – 时间的变化量

 void fadeout(cwnd *pwnd, cpalette *ppal, int ndeta, uint utimeout) {

 // 保留原来的调色板颜色表项

int ntotalcolors = ppal->getentrycount();

paletteentry palettecolors0[256];

 ppal->getpaletteentries(0, ntotalcolors, palettecolors0);

// 设置时间码

pwnd->settimer(0x100, utimeout, null);

 // 开始渐隐

pwnd->setcapture();

bool bdone = false;

msg msg;

 while (! bdone) {

 if (::peekmessage(&msg, null, 0, 0, pm_remove))

{ if (msg.message == wm_timer && msg.wparam == 0x100)

{ cclientdc dc(pwnd);

cpalette *poldpal = dc.selectpalette(ppal, false);

dc.realizepalette();

paletteentry palettecolors[256];

ppal->getpaletteentries(0, ntotalcolors, palettecolors);

bool bredzero=false

bool bgreenzero=false;

 bool bbluezero=false;

// 递减颜色份量

for (int i=0; i<ntotalcolors; ++i)

{ if (palettecolors[i].pered > ndeta)

{ palettecolors[i].pered -= ndeta;

bredzero = false; }

 else if (palettecolors[i].pered > 1)

{ palettecolors[i].pered--;

bredzero = false; }

 else

bredzero = true;

if (palettecolors[i].pegreen > ndeta)

{ palettecolors[i].pegreen -= ndeta;

 bgreenzero = false; }

else if (palettecolors[i].pegreen > 1)

{ palettecolors[i].pegreen--;

 bgreenzero = false; }

else

bgreenzero = true;

if (palettecolors[i].peblue > ndeta) {

 palettecolors[i].peblue -= ndeta;

 bbluezero = false; }

 else if (palettecolors[i].peblue > 1)

{ palettecolors[i].peblue--;

 bbluezero = false; }

else

bbluezero = true; }

 // 如全部颜色份量都为0,则结束渐隐

bdone = bredzero && bgreenzero && bbluezero;

// 使系统改变调色板

 ppal->animatepalette(0, ntotalcolors, palettecolors); }

::translatemessage(&msg);

::dispatchmessage(&msg); } }

::releasecapture(); pwnd->killtimer(0x100);

 // 恢复原始调色板

ppal->setpaletteentries(0, ntotalcolors, palettecolors0);

ppal->animatepalette(0, ntotalcolors, palettecolors0);


n        做者:admin --  发布时间:2006-8-11 16:11:00

n        --  VC进行屏幕截取编程

n        ---- 屏幕截取是使人比较感兴趣的事情.虽然如今有很多应用程序如HYPERSNAP等能够用来截取你所喜欢的屏幕画面,可是若是能把这个功能加到本身的程序中,就更能利用它强大的做用.

n        ---- 下面用VC来逐步介绍在Windows95下的实现过程.首先咱们要肯定屏幕截取的区域,LPRECT结构来定义.能够截取一个窗口,或整个屏幕.如下代码把选定的屏幕区域拷贝到位图中.

n         HBITMAP CopyScreenToBitmap(LPRECT lpRect)

n         //lpRect 表明选定区域 { HDC hScrDC, hMemDC;

n         // 屏幕和内存设备描述表 HBITMAP hBitmap, hOldBitmap;

n        // 位图句柄 int nX, nY, nX2, nY2;

n        // 选定区域坐标 int nWidth, nHeight;

n        // 位图宽度和高度 int xScrn, yScrn;

n        // 屏幕分辨率

n        // 确保选定区域不为空矩形

n        if (IsRectEmpty(lpRect)) return NULL;

n        //为屏幕建立设备描述表

n         hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);

n        //为屏幕设备描述表建立兼容的内存设备描述表

n        hMemDC = CreateCompatibleDC(hScrDC);

n         // 得到选定区域坐标

n         nX = lpRect- >left;

n        nY = lpRect- >top;

n        nX2 = lpRect- >right;

n        nY2 = lpRect- >bottom;

n         // 得到屏幕分辨率

n         xScrn = GetDeviceCaps(hScrDC, HORZRES);

n         yScrn = GetDeviceCaps(hScrDC, VERTRES);

n         //确保选定区域是可见的

n        if (nX 0) nX = 0;

n         if (nY 0)

n         nY = 0;

n         if (nX2 > xScrn)

n        nX2 = xScrn;

n         if (nY2 > yScrn)

n        nY2 = yScrn;

n         nWidth = nX2 - nX;

n         nHeight = nY2 - nY;

n        // 建立一个与屏幕设备描述表兼容的位图

n        hBitmap = CreateCompatibleBitmap (hScrDC, nWidth, nHeight);

n        // 把新位图选到内存设备描述表中

n        hOldBitmap = SelectObject(hMemDC, hBitmap);

n         // 把屏幕设备描述表拷贝到内存设备描述表中

n        BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY);

n         //获得屏幕位图的句柄

n        hBitmap = SelectObject(hMemDC, hOldBitmap);

n        //清除 DeleteDC(hScrDC); DeleteDC(hMemDC);

n         // 返回位图句柄

n        return hBitmap; }

n        获得屏幕位图句柄之后,咱们 能够把屏幕内容粘贴到剪贴板上.

n        if (OpenClipboard(hWnd))

n        //hWnd为程序窗口句柄

n        {

n        //清空剪贴板

n        EmptyClipboard();

n        //把屏幕内容粘贴到剪贴板上, hBitmap 为刚才的屏幕位图句柄

n        SetClipboardData(CF_BITMAP, hBitmap);

n        //关闭剪贴板

n         CloseClipboard(); }

n         咱们也能够把屏幕内容以位图格式存到磁盘文件上.

n         int SaveBitmapToFile(HBITMAP hBitmap , LPSTR lpFileName)

n        //hBitmap 为刚才的屏幕位图句柄

n        {

n        //lpFileName 为位图文件名

n        HDC hDC;

n        //设备描述表

n        int iBits;

n        //当前显示分辨率下每一个像素所占字节数

n        WORD wBitCount;

n        //位图中每一个像素所占字节数

n        //定义调色板大小, 位图中像素字节大小 位图文件大小 写入文件字节数

n        DWORD dwPaletteSize=0, dwBmBitsSize, dwDIBSize, dwWritten;

n        BITMAP Bitmap;

n         //位图属性结构

n        BITMAPFILEHEADER bmfHdr;

n        //位图文件头结构

n         BITMAPINFOHEADER bi;

n         //位图信息头结构

n         LPBITMAPINFOHEADER lpbi;

n        //指向位图信息头结构

n        HANDLE fh, hDib, hPal,hOldPal=NULL;

n        //定义文件,分配内存句柄,调色板句柄 //计算位图文件每一个像素所占字节数

n        hDC = CreateDC("DISPLAY",NULL,NULL,NULL);

n         iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);

n         DeleteDC(hDC);

n         if (iBits = 1) wBitCount = 1;

n        else if (iBits = 4)

n        wBitCount = 4;

n        else if (iBits = 8) wBitCount = 8;

n        else if (iBits = 24) wBitCount = 24;

n         //计算调色板大小

n        if (wBitCount = 8)

n        dwPaletteSize = (1 wBitCount) * sizeof(RGBQUAD);

n        //设置位图信息头结构

n         GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap);

n         bi.biSize = sizeof(BITMAPINFOHEADER);

n         bi.biWidth = Bitmap.bmWidth;

n        bi.biHeight = Bitmap.bmHeight;

n        bi.biPlanes = 1;

n        bi.biBitCount = wBitCount;

n        bi.biCompression = BI_RGB;

n        bi.biSizeImage = 0;

n        bi.biXPelsPerMeter = 0;

n         bi.biYPelsPerMeter = 0;

n        bi.biClrUsed = 0;

n         bi.biClrImportant = 0;

n         dwBmBitsSize = ((Bitmap.bmWidth * wBitCount+31)/32)* 4 *Bitmap.bmHeight ;

n        //为位图内容分配内存

n        hDib = GlobalAlloc(GHND,dwBmBitsSize+ dwPaletteSize+sizeof(BITMAPINFOHEADER));

n        lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);

n         *lpbi = bi;

n         // 处理调色板

n         hPal = GetStockObject(DEFAULT_PALETTE);

n         if (hPal) {

n        hDC = GetDC(NULL);

n        hOldPal = SelectPalette(hDC, hPal, FALSE); RealizePalette(hDC);

n        }

n        // 获取该调色板下新的像素值

n         GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER) +dwPaletteSize, (BITMAPINFOHEADER *) lpbi, DIB_RGB_COLORS);

n         //恢复调色板

n        if (hOldPal) {

n        SelectPalette(hDC, hOldPal, TRUE);

n         RealizePalette(hDC);

n         ReleaseDC(NULL, hDC); }

n         //建立位图文件

n         fh = CreateFile(lpFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_ FLAG_SEQUENTIAL_SCAN, NULL);

n         if (fh == INVALID_HANDLE_VALUE)

n        return FALSE;

n         // 设置位图文件头

n         bmfHdr.bfType = 0x4D42;

n        // "BM"

n        dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize;

n         bmfHdr.bfSize = dwDIBSize;

n         bmfHdr.bfReserved1 = 0;

n        bmfHdr.bfReserved2 = 0;

n         bmfHdr.bfOffBits = (DWORD)sizeof (BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize;

n        // 写入位图文件头

n         WriteFile(fh, (LPSTR)&bmfHdr, sizeof (BITMAPFILEHEADER), &dwWritten, NULL);

n        // 写入位图文件其他内容

n        WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);

n        //清除

n        GlobalUnlock(hDib);

n         GlobalFree(hDib);

n        CloseHandle(fh);


--  做者:admin

 --  发布时间:2006-8-11 16:12:00

--  VC制做图片屏幕保护程序 VC++可谓神通广大,若是学到家了,或者就掌握了那么一点MFC,你也会感到它的方便快捷,固然最重要的是功能强大。不是吗,从最基本的应用程序.EXE到动态链接库DLL,再由风靡网上的ActiveX控件到Internet Server API,固然,还有数据库应用程序……瞧,我都用它来作屏幕保护程序了。通常的屏幕保护程序都是以SCR做为扩展名,而且要放在c://windows 目录或 c://windows//system 目录下,由Windows 98内部程序调用(Windows NT 是在 c://windows//system32 目录下)。怎么调用?不用说了,这谁不知道。   

好了,咱们来做一个简单的。选择MFC AppWizard(exe)Project Name MyScreensaver[NEXT],对话框,再后面随你了。打开菜单ProjectSettings,在Debug页、Executable for debug session项,以及Link页中Output file name项改成c://windows//MyScreensaver.scr,这样,你能够调试完后,直接在VC中运行(CtrlF5),即可看到结果。固然,这样作的惟一缺点是你必须手动清除Windows 目录下的垃圾文件(固然是在看到满意结果后;还有,你可借助SafeClean 这个小东东来帮你清除,除非你的硬盘大的让你感到无所谓……快快快回来,看我跑到那里去了)。接下来用Class Wizard生成CMyWnd类,其基类为CWnd(Base Class 中为generic CWnd)。这个类是咱们所要重点研究的。建立满屏窗口、计时器,隐藏鼠标,展现图片,响应键盘、鼠标等等,这家伙全包了。至于MyScreensaverDlg.hMyScreensaverDlg.cpp文件咱们暂时无论。打开MyScreensaver.cpp,修改InitInstance()函数:   

 

BOOL CMyScreensaverApp::InitInstance()   

{   

AfxEnableControlContainer();   

ifdef _AFXDLL   

 Enable3dControls();

 // Call this when using MFC in a shared DLL  

 #else   

 Enable3dControlsStatic();

// Call this when linking to MFC statically  

 #endif   

 CMyWnd pWnd = new CMyWnd;   

pWnd>Create();   

 m_pMainWnd = pWnd;  

  return TRUE;   

}  

 固然,再这以前得先 include “MyWnd.h" 。后面要作的都在MyWnd.h MyWnd.cpp 两文件中了。   

下面给出CMyWnd 的说明:   

class CMyWnd : public CWnd   {

public:    CMyWnd();  

 static LPCSTR lpszClassName;

//注册类名   

public:   

 BOOL Create();  

 public:   

// Clazard generated virtual function overrides   

 //

{{AFX_VIRTUAL(CMyWnd)   

 protected:   

 virtual void PostNcDestroy();   

 //

}}AFX_VIRTUAL  

 public:   

 virtual CMyWnd();   

protected:   

CPoint m_prePoint;

//检测鼠标移动   

void DrawBitmap(CDC dc, int nIndexBit);   

 //

{{AFX_MSG(CMyWnd)   

afx_msg void OnPaint();   

 afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);   

afx_msg void OnLButtonDown(UINT nFlags, CPoint point);   

afx_msg void OnMButtonDown(UINT nFlags, CPoint point);   

afx_msg void OnMouseMove(UINT nFlags, CPoint point);   

afx_msg void OnRButtonDown(UINT nFlags, CPoint point);   

afx_msg void OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);   

afx_msg void OnDestroy();   

 afx_msg void OnTimer(UINT nIDEvent);   

afx_msg void OnActivate(UINT nState, CWnd pWndOther, BOOL bMinimized);   

 afx_msg void OnActivateApp(BOOL bActive, HTASK hTask);   

//

}}AFX_MSG   

 DECLARE_MESSAGE_MAP()   

};   

MyWnd.cpp 文件:  

 ……   

CMyWnd::CMyWnd()   

{   

 m_prePoint=CPoint(1, 1);   

}   

LPCSTR CMyWnd::lpszClassName=NULL;  

 BOOL CMyWnd::Create()   

{   

 if(lpszClassName==NULL)   

 {   

 lpszClassName=AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW,   

::LoadCursor(AfxGetResourceHandle(),MAKEINTRESOURCE(IDC_NOCURSOR)));  

 //注册类;IDC_NOCURSOR为新建光标的ID,这个光标没有任何图案   

}   

 CRect rect(0, 0, ::GetSystemMetrics(SM_CXSCREEN),  

  ::GetSystemMetrics(SM_CYSCREEN));   

 CreateEx(WS_EX_TOPMOST, lpszClassName, _T(“”), WS_VISIBLE|WS_POPUP,    rect.left, rect.top, rect.right rect.left, rect.bottom rect.top,    GetSafeHwnd(), NULL, NULL);

//建立一个全屏窗口   

SetTimer(ID_TIMER, 500, NULL);

//计时器,ID_TIMER别忘了定义   

 return TRUE;   }   

为了防止同时运行两个相同的程序,下面两个函数是必需的:   

void CMyWnd::OnActivate(UINT nState, CWnd pWndOther, BOOL bMinimized)  

 {   

 CWnd::OnActivate(nState,pWndOther,bMinimized);   

 if (nState==WA_INACTIVE)   

 PostMessage(WM_CLOSE);  

 }   

 

void CMyWnd::OnActivateApp(BOOL bActive, HTASK hTask)   {   

 CWnd::OnActivateApp(bActive, hTask);   

 if (!bActive)

//is being deactivated   

 PostMessage(WM_CLOSE);  

 }   

OnPaint()函数将全屏窗口置为黑色:  

 

 void CMyWnd::OnPaint()   {

   CPaintDC dc(this);   

 CBrush brush(RGB(0,0,0));   

 CRect rect;   

 GetClientRect(rect);  

  dc.FillRect(rect, brush);  

 }  

 

 由计数器调用DrawBitmap()函数,切换图片;注意,下面两个函数中的IDB_BITMAP1, dc.BitBlt(0,0,800,600……以及if(nIndexBit>=5)中的有关数据依据你的bmp图片个数、尺寸、位置不一样而不一样,我是选择了5800x600bmp图片。注意,ID值是连续的,IDB_BITMAP1最小。  

 

 void CMyWnd::DrawBitmap(CDC dc, int nIndexBit)  

 {   

 CDC dcmem;  

  dcmem.CreateCompatibleDC(dc);  

  CBitmap m_Bitmap;   

 m_Bitmap.LoadBitmap(IDB_BITMAP1nIndexBit);  

  dcmem.SelectObject(m_Bitmap);   

 dc.BitBlt(0,0,800,600,dcmem,0,0,SRCCOPY);  

 }  

 

 void CMyWnd::OnTimer(UINT nIDEvent)   {  

  CClientDC dc(this);   

 static nIndexBit=0;  

  if(nIndexBit>=5)   

 nIndexBit=0;   

 DrawBitmap(dc, nIndexBit++);  

  CWnd::OnTimer(nIDEvent);   }    

 

 响应键盘、鼠标是屏幕保护程序不可缺乏的,在OnKeyDown() OnLButtonDown() OnMButtonDown()OnRButtonDown()OnSysKeyDown()函数中都加入:

   PostMessage(WM_CLOSE);  

 OnMouseMove()函数比较特殊,它应加的代码为:  

 

  if(m_prePoint == CPoint(1,1))  

  m_prePoint = point;   

 else if(m_prePoint!=point)  

  PostMessage(WM_CLOSE);  

 

 快要完工了。在OnDestroy()函数中删掉计时器:KillTimer(ID_TIMER);

还有啦,在CMyWnd::PostNcDestroy() 中加入:

 delete this;   

哎呀,腰酸背疼,眼球发涩,手背奇麻(不会吧)!不过,相信你必定会火烧眉毛地按下CtrlF5, 看着一幅幅图片在你面前轮番展现,啊,本身的屏幕保护程序!赶快赶快,换上自制的屏保,感受就是不同:图片任你挑,时间间隔任你改,鼠标?键盘?我想响应谁就响应谁……哎呀,谁扔的纸团:(  

 其实,上面的程序还有不少能够改进的地方,好比图片老是单一地显示;bmp 文件太大,致使生成的屏幕保护程序也很大,远没有jpg合算;没有密码,没有可直接控制的界面。因为InitInstance()函数的简单处理(直接调用CMyWnd类),你会发现当你在桌面上右击,选择属性屏幕保护程序页、屏幕保护程序下拉菜单、选中MyScreensaver时,MyScreensaver就直接预览了(或是直接运行了);假设你肯定MyScreensaver做为你的屏幕保护程序,等你第二次进入屏幕保护程序页时,就直接预览。Why? 回头看看InitInstance()函数就明白了。为了让它更听话地工做,可修改InitInstance()函数:   

 LPTSTR lpszArgv = __argv[1];   

 if (lpszArgv[0] ==‘/’)   

 lpszArgv++;   

 if (lstrcmpi(lpszArgv, _T(“s”))==0)   

 {   

CMyWnd pWnd=new CMyWnd;

   pWnd>Create();   

 m_pMainWnd=pWnd;   

return TRUE;   

}   

 return FALSE;   

不过如今你要是再在VC中运行这个程序,该程序执行了非法操做,即将关闭。若是仍有问题,请与我联系(??将会伴随着一超重低音供你欣赏。(啊?)缘由是咱们加了一句return FALSE; 还有,别忘了还有一个CMyScreensaverDlg类没有用上,用它来与你的屏保直接对话再好不过了。例如,为了方便地肯定时间间隔,选取图片,加上一个编辑框和几个按钮就能够了。重申一点,因为生成文件较大,占用的内存也多,若是不能运行,极可能是开的窗口太多了。这时你能够换较小的图片。有任何问题请来信:toxyz@163.net。晚些时候我将在家门口 http://yxz.163.net 放置上述例子的整个项目,有一些新玩意和你们共同探讨。(全文完)


--  做者:admin

--  发布时间:2006-8-11 16:13:00

--  VC中自建操做BMP位图文件类有编程经验的程序员都知道:要使应用程序的界面美观不可避免的要使用大量位图。如今流行的可视化编程工具对位图的使用提供了很好的支持,被称为三大可视化开发工具的VBVCDelphi经过封装位图对象对位图使用提供了很好的支持:VB提供了两个功能很强的对象:PictureBoxImage,经过使用它们,装载、显示位图变得很是容易。Delphi中也提供了一个位图对象:TImage,它的功能与用法与VB中的Image相似。在VC中经过使用设备相关类CDCGDI对象类CBitmap来完成位图的操做。 然而在VC中使用CBitmap类必须将BMP位图装入资源中,而后经过类 CBitmap的成员函数使用它,在经过CDC类的成员函数操做它。这样作有两点缺陷:将位图装入资源致使可执行文件增大,不利于软件发行;只能使用资源中有限的位图,没法选取其它位图。并且BMP位图文件是以DIB(设备无关位图)方式保存,BMP位图装入资源后被转换为DDB(设备相关位图),类CBitmap就是对一系列DDB操做的API函数进行了封装,使用起来有必定的局限性,不如DIB能够独立于平台特性。 要弥补使用资源位图的两点不足,就必须直接使用BMP位图文件。VC的示例中提供了一种方法读取并显示BMP位图文件,但使用起来至关的麻烦。首先使用API函数GlobalAlloc分配内存并建立HDIB位图句柄,全部操做只能直接读写内存,而后经过StrechDIBitsSetDIBsToDevice函数来显示于屏幕上,操做起来费时费力。 所以笔者经过研究类CBitmap的封装与DIB结构,使用Win32中提供的新函数,创建了一个专用于操做BMP文件的类,并且彻底仿照类CBitmap的实现:从类CGdiObject派生,新类的全部接口与类CBitmap 的部分接口彻底相同。这样对于习惯使用CBitmap类接口用法的程序员来讲二者的接口在使用上没有什么分别。 首先咱们先简单介绍一下DIB的结构。DIB位图既能够存在于内存,也能够以文件形式保存在磁盘上(BMP文件)。全部DIB都包含两部分信息:位图信息(BITMAPINFO),包括位图信息头和颜色表;位图数据。对于内存中DIB的只要有上述两部分就行,而对于DIB文件则还要加上位图文件头。 其次,Win32中提供了一个新函数CreateDIBSection,经过它能够建立一个存储DIB位的内存区域,既能够执行相应的GDI操做,又能够直接经过指向DIB位区域的指针方位DIB位区域。这是一个很是有用的函数,经过它咱们能够用DIB替代DDB 在了解了相应的知识后,咱们能够本身由类CGdiObject派生一个操做BMP文件的类:CBitmapFile 在本身编写类时有两点值得注意: BitmapFile.h文件中定义类CBitmapFile,首先必须声明类CBitmapFile是从类CGdiObject中公有派生。而后在类中首先使用宏DECLARE_DYNAMICCBitmapFile)代表新类的最高父类是类CObject,是符合MFC的类库规范。紧接着宏DECLARE_DYNAMIC的是声明静态函数FromHandle,这两个声明必须放在类定义的最前面。 BitmapFile.cpp文件中类的成员函数的实现前加上IMPLEMENT_DYNAMIC(CBitmapFile,CGdiObject);代表类CBitmapFile直接派生于类CGdiObject 在类CBitmapFile的声明中有三个函数与类Cbitmap中的定义稍有不一样: 在类CbitmapFileLoadBitmap函数的参数是LPCTSTR型,保存的是BMP文件的文件名。 在类CbitmapFileCreateBitmap函数的参数中少了参数nPlanes,在函数内部默认为1 在类CbitmapFileCreateBitmapIndirect函数的参数中多了参数lpBits,它指向指定位图DIB位的内存区域。 在成员函数中最重要的是函数CreateBitmapIndirect和函数LoadBitmap 在函数CreateBitmapIndirect中使用函数CreateDIBSection建立了一个以兼容DC为基础的HBITMAP句柄,并用继承自类CGdiObject 的函数Attach把它与类CGdiObject的句柄m_hObject关联起来。而后将指定位图的DIB位图数据拷贝到由函数CreateDIBSection建立的DIB位的内存区域。 在函数LoadBitmap中首先从指定文件名的文件中读取以结构BITMAPFILEHEADER为大小的数据块,而后由文件头标志判断文件是否为BMP位图文件,而后由BITMAPFILEHEADERbfSize保存的文件大小与文件的真实大小比较文件是否有损坏,再由BITMAPFILEHEADERbfOffBitsBITMAPFILEHEADER结构大小相减计算出位图信息头和颜色表一共的大小,动态申请一块空间保存位图信息头和颜色表信息,再由BITMAPFILEHEADERbfSizebfOffBits相减计算出DIB位图数据的大小,动态申请一块空间保存DIB位图数据,最后调用成员函数CreateBitmapIndirect来建立DIB位图。 在应用程序的OnPaint()事件中绘制DIB位图的方法与使用类CBitmap时绘制位图的方法彻底相同,但有一点要注意的是因为CDC类没有提供返回新类CBitmapFile指针类型的将DIB位图选入内存的SelectObject函数,因此在使用SelectObject时要将返回类型强制转换为CbitmapFile *类型。 至此,关于新类CBitmapFile编写中的一些要点和使用时一些要注意的问题就介绍这么多了。

附源文件

 //

// 文件描述:定义类CBitmapFile,此类是用于读取BMP文件,涉及读取、

 // 创建及一系列经常使用的操做。

// 文件名: BitmapFile.h

 // 时间: 1999-2-11

// 做者: 贾暾

// #ifndef _CBITMAPFILE_H_

#define _CBITMAPFILE_H_

class CBitmapFile : public CGdiObject

{

DECLARE_DYNAMIC(CBitmapFile)

public:

static CBitmapFile* PASCAL FromHandle(HBITMAP hBitmap);

 // Constructors CBitmapFile();

BOOL LoadBitmap(LPCTSTR lpszFileName);

BOOL CreateBitmap(int nWidth, int nHeight, UINT nBitCount, const void* lpBits);

 BOOL CreateBitmapIndirect(LPBITMAPINFO lpBitmapInfo, const void* lpBits);

// Attributes operator HBITMAP() const; int GetBitmap(BITMAP* pBitMap);

protected:

// Attributes int GetColorNumber(WORD wBitCount);

public:

// Operations DWORD SetBitmapBits(DWORD dwCount, const void* lpBits);

 DWORD GetBitmapBits(DWORD dwCount, LPVOID lpBits);

 // Implementation

public:

virtual ~CBitmapFile();

};

#endif

//

// 文件描述:类CBitmapFile内成员函数的实现

// 文件名: BitmapFile.cpp

 // 时间: 1999-2-11

// 做者: 贾暾

//

 #include "BitmapFile.h"

#include <memory.h>

 IMPLEMENT_DYNAMIC(CBitmapFile,CGdiObject);

 CBitmapFile* PASCAL CBitmapFile::FromHandle(HBITMAP hBitmap)

 {

return (CBitmapFile*)

CGdiObject::FromHandle(hBitmap);

}

 

CBitmapFile::CBitmapFile() { }

 

 BOOL CBitmapFile::LoadBitmap(LPCTSTR lpszFileName) {

 CFile file;

 if(!file.Open(lpszFileName,CFile::modeRead|CFile::shareDenyWrite))

{ MessageBox(NULL,"BMP file open error!","warning",MB_OK);

 return FALSE; }

 BITMAPFILEHEADER bfhHeader;

file.Read(&bfhHeader,sizeof(BITMAPFILEHEADER));

 if(bfhHeader.bfType!=((WORD) (/'M/'<<8)|/'B/'))

{ MessageBox(NULL,"The file is not a BMP file!","warning",MB_OK);

return FALSE;

 }

 if(bfhHeader.bfSize!=file.GetLength())

{

MessageBox(NULL,"The BMP file header error!","warning",MB_OK);

 return FALSE; }

 UINT uBmpInfoLen=(UINT) bfhHeader.bfOffBits-sizeof(BITMAPFILEHEADER);

 LPBITMAPINFO lpBitmap=(LPBITMAPINFO) new BYTE[uBmpInfoLen];

 file.Read((LPVOID) lpBitmap,uBmpInfoLen);

 if((* (LPDWORD)(lpBitmap))!=sizeof(BITMAPINFOHEADER)) {

 MessageBox(NULL,"The BMP is not Windows 3.0 format!","warning",MB_OK);

return FALSE; }

DWORD dwBitlen=bfhHeader.bfSize - bfhHeader.bfOffBits;

LPVOID lpBits=new BYTE[dwBitlen];

file.ReadHuge(lpBits,dwBitlen);

 file.Close();

 BOOL bSuccess=CreateBitmapIndirect(lpBitmap, lpBits);

 delete lpBitmap; delete lpBits;

 if(!bSuccess)

return FALSE;

 return TRUE; }

 

 BOOL CBitmapFile::CreateBitmap(int nWidth, int nHeight, UINT nBitCount, const void* lpSrcBits) {

ASSERT(nBitCount==1||nBitCount==4||nBitCount==8 ||nBitCount==16||nBitCount==24||nBitCount==32);

LPBITMAPINFO lpBitmap;

 lpBitmap=(BITMAPINFO*) new BYTE[sizeof(BITMAPINFOHEADER) + GetColorNumber(nBitCount) * sizeof(RGBQUAD)];

 lpBitmap->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);

lpBitmap->bmiHeader.biWidth=nWidth;

 lpBitmap->bmiHeader.biHeight=nHeight;

lpBitmap->bmiHeader.biBitCount=nBitCount;

lpBitmap->bmiHeader.biPlanes=1;

 lpBitmap->bmiHeader.biCompression=BI_RGB;

 lpBitmap->bmiHeader.biSizeImage=0;

 lpBitmap->bmiHeader.biClrUsed=0;

 BOOL bSuccess=CreateBitmapIndirect(lpBitmap, lpSrcBits);

delete lpBitmap;

if(!bSuccess)

return FALSE;

 return TRUE; }

 BOOL CBitmapFile::CreateBitmapIndirect(LPBITMAPINFO lpBitmapInfo, const void* lpSrcBits) {

DeleteObject();

LPVOID lpBits;

CDC *dc=new CDC;

dc->CreateCompatibleDC(NULL);

HBITMAP hBitmap=::CreateDIBSection(dc->m_hDC,lpBitmapInfo,DIB_RGB_COLORS, &lpBits,NULL,0);

ASSERT(hBitmap!=NULL);

 delete dc;

Attach(hBitmap);

 BITMAP bmp;

 GetBitmap(&bmp);

 DWORD dwCount=(DWORD) bmp.bmWidthBytes * bmp.bmHeight;

if(SetBitmapBits(dwCount,lpSrcBits)!=dwCount)

{

MessageBox(NULL,"DIB build error!","warning",MB_OK);

return FALSE; }

return TRUE;

}

CBitmapFile::operator HBITMAP() const {

return (HBITMAP)(this == NULL ? NULL : m_hObject);

 }

int CBitmapFile::GetBitmap(BITMAP* pBitMap) {

ASSERT(m_hObject != NULL);

return ::GetObject(m_hObject, sizeof(BITMAP), pBitMap);

}

 

 int CBitmapFile::GetColorNumber(WORD wBitCount)

{

ASSERT(wBitCount==1||wBitCount==4||wBitCount==8 ||wBitCount==16||wBitCount==24||wBitCount==32);

 {

case 1:

 return 2;

case 4:

return 16;

 case 8:

return 256;

 default: return 0;

}

}

 

DWORD CBitmapFile::SetBitmapBits(DWORD dwCount, const void* lpBits)

 {

if(lpBits!=NULL)

{

BITMAP bmp;

 GetBitmap(&bmp);

memcpy(bmp.bmBits,lpBits,dwCount);

 return dwCount;

 } else

return 0; }

 

 DWORD CBitmapFile::GetBitmapBits(DWORD dwCount, LPVOID lpBits) {

if(lpBits!=NULL) {

BITMAP bmp;

GetBitmap(&bmp);

 memcpy(lpBits,bmp.bmBits,dwCount);

 return dwCount;

}

else return 0; }

 

CBitmapFile::~CBitmapFile() { CGdiObject::DeleteObject();


--  做者:admin

--  发布时间:2006-8-11 16:16:00

--  VC实现多格式图像的转换色彩鲜艳漂亮的高品质图像,一个个形象生动的Windows图标,高速运动、活灵活现的三维动画,这些无一不显示出程序设计者的艺术才华。在程序设计中,图像处理已经成为每一个程序员的必修课。 VC中编程显示一幅位图,下列步骤是不可缺乏的: 装入位图、得到位图的大小信息、启用设备环境、位传输等,所需的程序代码通常比较冗长并且复杂。若是想将装入的位图另存为其余格式的图像文件,代码就更长了。这一切都是由于GDI自己的局限性形成的。 GDI+技术 随着Windows 2000的推出,上述状况有了极大的改观: 程序员没必要了解每种图像格式的具体含义,照样能够写出多格式图像浏览或转换程序,这一切全都依赖于Windows 2000及后继版中所使用的GDI+技术。 和传统的GDI不一样,GDI+中引入了对COM(组件对象模型)技术的支持,经过COM技术,GDI+简化了对图像文件的访问(打开、保存)。它是经过调用COM组件来实现的,GDI+扮演的只是指挥者,而非操做员。对于图像文件,GDI+所关心的不是图像文件的文件头信息,不论要打开的文件格式是什么类型,GDI+首先要作的是在注册表中查看该图像格式的编码(或解码)信息是否已经注册(HKEY_CLASSES_ROOT//MIME//Database//Content Type)。若是已经注册,就经过该编码信息调用COM组件,就这么简单。这种技术早就在微软的其余软件中使用了(IE)体验Nimda病毒的朋友可能对“audio/wav”这段代码并不陌生,Nimda就是靠它来假装本身的:让IE认为附件是WAV文件而自动打开可执行程序,这其实也是IE使用COM技术的一个突出表现。 配合GDI+的推出,微软也同时发布了相应的SDK,若是已经安装了最新的Microsoft PlatForm SDK或已经开始使用VS.NETGDI+SDK就已经在系统中了。若是没有的话,能够到http: //noner.top263.net/progtool上去下载GDI+的头文件和库文件。有了GDI+以后,只需简单地建立一个图形对象(Graphics object),而后直接调用该对象的方法(methods)进行绘图便可。图形对象是GDI+中的核心,正如DC之于GDI那样。图形对象和DC有许多类似的地方,在使用上遵循着相同的使用规则,可是二者在本质上已经有很大的区别。一个是基于句柄的GDI,一个是基于组件对象模型的GDI+。使用GDI+SDK编程,必须按照下面的规范来进行:使用GDI+的命名空间(namespace Gdiplus),在使用GDI+函数时必须进行GDI+的初始化,使用完毕要销毁GDI+,这些规范在下面所列的程序中有详细的说明。 访问注册表编码信息 上面说到GDI+是经过在注册表中查看编码信息来访问图像文件的,在GDI+SDK中,编码信息是存储在 ImageCodecInfo类中的,在这个类中,有编码的CLSIDCOM组件的GUID标识码)、编码方式描述等。对于GDI,在注册表中访问编码信息一般使用如下两个函数来实现:

1. 查看系统中可用的图像编码信息(数量及大小)

 Status GetImageEncodersSize( UINT* numEncoders,

//存储编码器数量的地址

UINT* size 

//存储编码信息所需内存大小

);

2. 获得全部的编码信息

Status GetImageEncoders( UINT numEncoders

//可用编码器数量

UINT size

//存储编码器信息所需内存(由ImageCodecInfo类组成的数组的大小)

 ImageCodecInfo* encoders

//编码器信息指针 );

GetImageEncoders函数中,参数numEncoderssize都是由GetImageEncodersSize返回的。下面的代码在注册表中查找具体格式图像的编码方式:

 int GetImageCLSID(const WCHAR* format, CLSID* pCLSID) {

 //获得格式为format的图像文件的编码值,访问该格式图像的COM组件的GUID值保存在pCLSID

UINT num = 0;

UINT size = 0;

ImageCodecInfo* pImageCodecInfo = NULL;

 GetImageEncodersSize(&num, &size);

 if(size == 0) return FALSE;

// 编码信息不可用

//分配内存

pImageCodecInfo = (ImageCodecInfo*)(malloc(size));

 if(pImageCodecInfo == NULL) return FALSE;

// 分配失败

//得到系统中可用的编码方式的全部信息

GetImageEncoders(num, size, pImageCodecInfo);

 //在可用编码信息中查找format格式是否被支持

 for(UINT i = 0; i < num; ++i) {

 //MimeType:编码方式的具体描述

if( wcscmp(pImageCodecInfo[i] .MimeType, format) == 0 )

{

*pCLSID = pImageCodecInfo[i] .Clsid;

free(pImageCodecInfo);

 return TRUE; } }

free(pImageCodecInfo);

 return FALSE;

}

实现多格式的图像浏览和转换 有了前面的知识,实现多格式的图像的浏览与转换就不是什么难事了。

1.  VC中建立一个SDI项目ImageShow,对GDI+声明和初始化及销毁进行代码编制,具体代码以下:

#include “Gdiplus.h”

using namespace Gdiplus;

CImageShowView::CImageShowView() {

 //初始化GDI+

GdiplusStartupInput gdiplusStartupInput;

ULONG_PTR gdiplusToken;

 GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

 }

 CImageShowView::CImageShowView() {

 //销毁GDI+

ULONG_PTR gdiplusToken; GdiplusShutdown(gdiplusToken);

}

 2. 经过类向导(Class Wizard),重载文件菜单中的打开另存为两项。为了编程的简单,本程序只将当前打开的图像文件直接存为BMP文件(实际上保存为其余格式的文件也很简单,只不过是对文件名进行分析而已)。另外,为了在打开和保存文件时进行文件名的传递,还应在CImageShowView类中加入一全局变量“CString strOpenFileName”打开另存为两菜单的对应代码以下:

 WCHAR* ToWChar(char * str) {

//GDI+中,有关字符的参数类型所有都是WCHAR类型

 //该函数是将传统字符串进行转换

static WCHAR buffer[1024];

 wcsset(buffer,0);

 MultiByteToWideChar(CP_ACP,0,str,strlen(str),buffer,1024); return buffer;

}

 

 void CImageShowView::OnFileOpen() {

//本程序可以打开各种常见格式的图像文件 static char szFilter[]=“常见格式图像文件(*.*)|*.*|”; CFileDialog dlgChoseImage(1NULLNULLNULLszFilter); if(dlgChoseImage.DoModal()==IDOK) {

 strOpenFileName=dlgChoseImage .GetPathName();

//打开文件后当即在窗口中显示(重绘客户窗口)

 this->Invalidate(); } }

 

 void CImageShowView::OnFileSaveAs() {

if(strOpenFileName.IsEmpty())

{

AfxMessageBox(“当前没有打开图像文件,不能进行保存!”); return; }

 //创建图形对象

Graphics graphics(GetDC()->m_hDC);

 //装入当前已经打开的图像文件

 Image image(ToWChar(strOpenFileName.GetBuffer(strOpenFileName.GetLength())));

CString strFileSave;

 //将其余格式的图像所有另存为BMP文件

static char szFilter[]=“位图(*.BMP)|*.BMP|”;

 CFileDialog dlgChoseImage(0“BMP”,NULLNULLszFilter);

if(dlgChoseImage.DoModal()==IDOK) {

strFileSave=dlgChoseImage.GetPathName(); CLSID clsid;

 if(GetImageCLSID(L“image/bmp”&clsid)) {

 image.Save(ToWChar(strFileSave.GetBuffer(strFileSave.GetLength())), &clsid, NULL);

 //将保存后的图像进行显示

 strOpenFileName=strFileSave;

this->Invalidate();

} } }

2.  为了浏览图像转换先后的效果,还应该在窗口中分别绘制转换先后的图像,这须要在OnDraw函数中添加绘制代码,以下所示:

 void CImageShowView::OnDraw(CDC* pDC) {

CImageShowDoc* pDoc = GetDocument();

 ASSERT_VALID(pDoc);

//若是没有选择显示图像文件,则不用重绘

 if(strOpenFileName.IsEmpty()) return;

 //显示当前打开的图像文件的全名

this->GetParent()->SetWindowText(strOpenFileName);

 //创建图像对象

Graphics graphics(pDC->m_hDC);

//装入图形文件

 Image image(ToWChar(strOpenFileName.GetBuffer(strOpenFileName.GetLength())));

 Point destPoints[3] = { Point(0, 0), Point(image.GetWidth(), 0), Point(0, image.GetHeight()) };

 Point* pdestPoints = destPoints;

//在指定区域pdestPoints显示图像 graphics.DrawImage(&image, pdestPoints, 3); }

在编译上面的程序以前,应该将Gdiplus.lib文件连编到项目中去,不然将会出现“LINK 2001”编译错误。上述程序在Visual Studio 6.0Windows 2000/XP下调试经过,它可以显示或转换的图像格式有BMPGIFJPEGExifPNGTIFFICONWMFEMF等等。须要说明的是,本文只就GDI+编程的基本原理进行了阐述,事实上,GDI+的应用远不止此。 结束语 若是对本程序进行些改进,还能够编制出功能更增强大的图像处理程序。本文中所提到的程序,在笔者的主页国税之家http://nationaltax.home.chinaren.com)的我的世界中能够下载到。有关GDI+编程的帮助信息,你们能够到微软的MSDN网站去查阅


--  做者:admin

--  发布时间:2006-8-11 16:17:00

--  ado方式访问带密码数据库的方法主要代码:   

CString strSql;   

 TCHAR FileName[MAX_PATH],errMsg[MAX_PATH];   

 ::CoInitialize(NULL); //初始化Com   

 IADORecordBinding *picRs = NULL;  

  _RecordsetPtr pRs("ADODB.Recordset");   

 _ConnectionPtr pConn("ADODB.Connection" );   

 //CFootballTeamRs rsFootballTeam;   

 GetModuleFileName(NULL,FileName,MAX_PATH);   

 (_tcsrchr(FileName,/'/////'))[1] = 0;   

 lstrcat(FileName,_T("pass.mdb"));   

strSql = strSql +

      "Provider=Microsoft.Jet.OLEDB.4.0;" +

   "Data Source = " +

    FileName +

    ";Persist Security Info=False;Jet OLEDB:Database Password=cd;";

   //pConn->ConnectionString = chDataSource;   

//pConn->Provider = _T("Microsoft.Jet.OLEDB.4.0");   

CString sqlSentence = _T("select * from pass");   

 try   

{   

pConn->Open((_bstr_t)strSql, "", "", adModeUnknown);   

pRs->QueryInterface(   

 __uuidof(IADORecordBinding), (LPVOID*)&picRs);   

 pRs->Open( (_variant_t)sqlSentence,

// 查询DemoTable表中全部字段   

 pConn.GetInterfacePtr(),

// 获取库接库的IDispatch指针     

adOpenDynamic,   

adLockOptimistic, adCmdText);   

}   

catch (_com_error &e)   

{   

 sprintf(errMsg,_T("Code meaning = %s//n"), (char*) e.ErrorMessage());   

 AfxMessageBox(errMsg);   

pRs->Close();   

pConn->Close();   

::CoUninitialize();   

 return;   

}   

try   

 {   

 while(!(pRs->EndOfFile))   

{   

CString pass = (LPCTSTR)(_bstr_t)pRs->GetCollect("pass");   

if(pass.IsEmpty()) return;   

SetDlgItemText(IDC_PASS,pass);   

 pRs->MoveNext();   

 //break;   

}   

pRs->Close();   

pConn->Close();   

}   

catch (_com_error &e)   

{   

sprintf(errMsg,_T("Code meaning = %s//n"), (char*) e.ErrorMessage());   

AfxMessageBox(errMsg);   

 pRs->Close();   

 pConn->Close();   

 ::CoUninitialize();     

 return;   

}   

 CoUninitialize();


--  做者:admin

--  发布时间:2006-8-11 16:18:00

--  VC编程实现文本语音转换  

内容简介   

文本语音(Text-to-Speech,如下简称TTS),它的做用就是把经过TTS引擎把文本转化为语音输出。本文不是讲述如何创建本身的TTS引擎,而是简单介绍如何运用Microsoft Speech SDK 创建本身的文本语音转换应用程序。   

 Microsoft Speech SDK简介   

 Microsoft Speech SDK是微软提供的软件开发包,提供的Speech API SAPI)主要包含两大方面:

1 API for Text-to-Speech   

 2 API for Speech Recognition   

 其中API for Text-to-Speech,就是微软TTS引擎的接口,经过它咱们能够很容易地创建功能强大的文本语音程序,金山词霸的单词朗读功能就用到了这写API,而目前几乎全部的文本朗读工具都是用这个SDK开发的。至于API for Speech Recognition就是与TTS相对应的语音识别,语音技术是一种使人振奋的技术,但因为目前语音识别技术准确度和识别速度不太理想,还未达到普遍应用的要求。   

Microsoft Speech SDK能够在微软的网站免费下载,目前的版本是5.1,为了支持中文,还要把附加的语言包(LangPack)一块儿下载。   

为了在VC中使用这SDK,必需在工程中添加SDKincludelib目录,为免每一个工程都添加目录,最好的办法是在VC   

Option-Directoris立加上SDKincludelib目录。   

一个最简单的例子   

 先看一个入门的例子:

 #include sapi.h

 #pragma comment(lib,"ole32.lib")

//CoInitialize CoCreateInstance须要调用ole32.dll #pragma comment(lib,"sapi.lib")

//sapi.libSDKlib目录,必需正确配置

 int main(int argc, char* argv[]) {

ISpVoice * pVoice = NULL;

 //COM初始化:

 if (FAILED(::CoInitialize(NULL)))

return FALSE;

//获取ISpVoice接口:

HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);

if( SUCCEEDED( hr ) )

 {

hr = pVoice-Speak(L"Hello world", 0, NULL);

 pVoice-Release();

 pVoice = NULL; }

//千万不要忘记:

::CoUninitialize();

return TRUE; }   

短短20几行代码就实现了文本语音转换,够神奇吧。SDK提供的SAPI是基于COM封装的,不管你是否熟悉COM,只要循序渐进地用CoInitialize() CoCreateInstance()获取IspVoice接口就够了,须要注意的是初始化COM后,程序结束前必定要用CoUninitialize()释放资源。   

IspVoice接口主要函数   

上述程序的流程是获取IspVoice接口,而后用ISpVoice::Speak()把文本输出为语音,可见,程序的核心就是IspVoice接口。除了SpeakIspVoice接口还有许多成员函数,具体用法请参考SDK的文档。下面择要说一下几个主要函数的用法:

 HRESULT Speak(const WCHAR *pwcs,DWORD dwFlags,ULONG *pulStreamNumber);   功能:就是speak   

 参数:    

*pwcs 输入的文本字符串,必需为Unicode,若是是ansi字符串必需先转换为Unicode    

 dwFlags 用来标志Speak的方式,其中SPF_IS_XML 表示输入文本含有XML标签,这个下文会讲到。     PulStreamNumber 输出,用来获取去当前文本输入的等候播放队列的位置,只有在异步模式才有用。

 HRESULT Pause ( void ); HRESULT Resume ( void );   

功能:一看就知道了。 HRESULT SetRate(long RateAdjust );

 HRESULT GetRate(long *pRateAdjust);   

功能:设置/获取播放速度,范围:-10 to 10

HRESULT SetVolume(USHORT usVolume);

HRESULT GetVolume(USHORT *pusVolume);   

功能:设置/获取播放音量,范围:0 to 100

HRESULT SetSyncSpeakTimeout(ULONG msTimeout);

 HRESULT GetSyncSpeakTimeout(ULONG *pmsTimeout);   

 功能:设置/获取同步超时时间。因为在同步模式中,电泳Speak后程序就会进入阻塞状态等待Speak返回,为免程序长时间没相应,应该设置超时时间,msTimeout单位为毫秒。

 HRESULT SetOutput(IUnknown *pUnkOutput,BOOL fAllowFormatChanges);   

 功能:设置输出,下文会讲到用SetOutputSpeak输出问WAV文件。   

 这些函数的返回类型都是HRESULT,若是成功则返回S_OK,错误有各自不一样的错误码。   

 使用XML   

我的认为这个TTS api功能最强大之处在于可以分析XML标签,经过XML标签设置音量、音调、延长、停顿,几乎能够使输出达到天然语音效果。前面已经提过,把Speak参数dwFlags设为SPF_IS_XML,TTS引擎就会分析XML文本,输入文本并不须要严格遵照W3C的标准,只要含有XML标签就好了,下面举个例子:

 ……

 pVoice-Speak(L"VOICE REQUIRED=/'/'NAME=Microsoft Mary/'/'/volumeVOLUME LEVEL=/'/'100/'/'turn up/VOLUME", SPF_IS_XML, NULL);

…… VOICE REQUIRED=/'/'NAME=Microsoft Mary/'/'/   

 标签把声音设为Microsoft Mary,英文版SDK中一共含有3种声音,另外两种是Microsoft SamMicrosoft Mike

 …… VOLUME LEVEL=/'/'100/'/'   

 把音量设为100,音量范围是0100   

另外:标志音调(-1010): PITCH MIDDLE="10"text/PITCH   

注意:" 号在C/C++中前面要加 // ,不然会出错。    

标志语速(-1010): RATE SPEED="-10"text/RATE    

 逐个字母读: SPELLtext/SPELL    

强调: EMPHtext/EMPH    

停顿200毫秒(最长为65,536毫秒): SILENCE MSEC="200" /    

 控制发音: PRON SYM = /'/'h eh - l ow 1/'/'/   

这个标签的功能比较强,重点讲一下:全部的语言发音都是由基本的音素组成,拿中文发音来讲,拼音是组成发音的最基本的元素,只要知道汉字的拼音,即便不知道怎么写,咱们可知道这个字怎么都,对于TTS引擎来讲,它不必定认识全部字,可是你把拼音对应的符号(SYM)给它,它就必定可以读出来,而英语发音则能够用音标表示,/'/'h eh - l ow 1/'/'就是hello这个单词对应的语素。至于发音与符号SYM具体对应关系请看SDK文档中的Phoneme Table   

再另外,数字、日期、时间的读法也有一套规则,SDK中有详细的说明,这里不说了(懒得翻译了),下面随便抛个例子: context ID = "date_ ymd"1999.12.21/context   

 会读成 "December twenty first nineteen ninety nine"   

XML标签能够嵌套使用,可是必定要遵照XML标准。XML标签确实好用,效果也不错,可是……缺点:一个字―――"",若是给一大段文字加标签,简直痛不欲生。   

 把文本语音输出为WAV文件

#include sapi.h

 #include sphelper.h

 #pragma comment(lib,"ole32.lib")

#pragma comment(lib,"sapi.lib")

int main(int argc, char* argv[]) {

ISpVoice * pVoice = NULL;

if (FAILED(::CoInitialize(NULL)))

return FALSE;

HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);

 if( SUCCEEDED( hr ) ) {

 CComPtrISpStream cpWavStream; CComPtrISpStreamFormat cpOldStream;

 CSpStreamFormat OriginalFmt; pVoice-GetOutputStream( &cpOldStream );

 OriginalFmt.AssignFormat(cpOldStream);

 hr = SPBindToFile( L"D:////output.wav",SPFM_CREATE_ALWAYS, &cpWavStream,&OriginalFmt.FormatId(), OriginalFmt.WaveFormatExPtr() );

if( SUCCEEDED( hr ) ) {

 pVoice-SetOutput(cpWavStream,TRUE);

WCHAR WTX[] = L"VOICE REQUIRED=/'/'NAME=Microsoft Mary/'/'/text to wave"; pVoice-Speak(WTX, SPF_IS_XML, NULL);

 pVoice-Release(); pVoice = NULL; } }

::CoUninitialize(); return TRUE; }   

 SPBindToFile把文件绑定到输出流上,而SetOutput把输出设为绑定文件的流上。   

 最后   

 看完本文后,是否是以为很简单,微软把强大的功能封装的太好了。其实SDK中另一个APISR(语音识别)更有趣,有兴趣不妨试试,你会有意外的收获的


--  做者:admin

--  发布时间:2006-8-11 16:20:00

--  VC++5.0MIDIWAVCD的播放加入音乐是加强应用程序功能的全部方法中最简单的一个。几乎每一个计算机游戏或多 媒体程序都以某种MIDICD音乐为背景。音乐能够使用户心情愉快;在合适的场合播 放恰当的音乐可以使程序员和他的VC++程序焕发光彩。 第一部分 MIDI的播放

---- 乐器数字化接口(MIDI)是由音乐界的一些大公司(包括生产电子音乐合成器的公司) 制订的一项协议,后来被计算机产业所采用并成为多媒体音乐文件的标准格式。MIDI文件 通常较小,对硬件设备的要求高。

---- 1、 原理 ---- 虽然MicroSoft支持MIDI文件,然而Visual C++MFC并无建立任何组件来实现 这种支持,可是MicroSoft API提供了三种不一样的方法来实现MIDI的播放:

 MCIThe Media Control Interface)。这是最基本的方法,本文将详细讨论这种方法。 流缓冲器。这种格式容许应用程序为MIDI数据分配缓冲器。在须要精确控制MIDI播放的时候,流缓冲器将颇有用处。 低级MIDI设备。须要彻底控制MIDI数据的应用程序能够使用这种方法。

---- MCI能够经过mciSendCommand()和mciSendString()来完成,本文仅使用mciSendCommand()函数。

---- 原型:

DWORD mciSendCommandUINT wDeviceIDUINT wMessageDWORD dwParam1DWORD dwParam2);

 参数:

wDeviceID:接受消息的设备

ID wMessageMCI命令消息

dwParam1:命令的标志位

dwParam2:所使用参数块的指针

---- 返值:调用成功,返回零;

不然,返回双字中的低字存放有错误信息。

 MIDI的播放控制

----

1.   打开设备

MCI_OPEN_PARMS OpenParms;

OpenParms.lpstrDeviceType = (LPCSTR) MCI_DEVTYPE_SEQUENCER;

//MIDI类型

OpenParms.lpstrElementName = (LPCSTR) Filename; OpenParms.wDeviceID = 0;

mciSendCommand (NULL, MCI_OPEN, MCI_WAIT | MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID | MCI_OPEN_ELEMENT, (DWORD)(LPVOID) &OpenParms)

 ---- MCI设备ID指明打开了哪一个设备,当发送了MCI_OPEN命令时,这个值在参数块中返回——应被保存备用。

---- 2 关闭设备

mciSendCommand (m_wDeviceID, MCI_CLOSE, NULL, NULL);

---- 3 播放

MCI_PLAY_PARMS PlayParms; PlayParms.dwFrom = 0;

// 指定从什么地方(时间)播放

 mciSendCommand (m_wDeviceID, MCI_PLAY, MCI_FROM, (DWORD)(LPVOID) &PlayParms))

 ---- 4 暂停

MCI_PLAY_PARMS PlayParms; mciSendCommand (m_wDeviceID, MCI_PAUSE, 0, (DWORD)(LPVOID) &PlayParms)

---- 5 中止

mciSendCommand (m_wDeviceID, MCI_STOP, NULL, NULL);

---- 6 跳跃 * 跳转到任意地方

MCI_SEEK_PARMS SeekParms; SeekParms.dwTo = (nMinute * 60 + nSecond) * 1000; //跳转的目标时间,时间单位为毫秒

 mciSendCommand (m_wDeviceID, MCI_SEEK, MCI_TO | MCI_WAIT,(DWORD)(LPVOID) &SeekParms)

跳到文件头

mciSendCommand (m_wDeviceID, MCI_SEEK, MCI_SEEK_TO_START, NULL);

l        跳到文件尾

mciSendCommand (m_wDeviceID, MCI_SEEK, MCI_SEEK_TO_END, NULL);

---- 7 查询当前信息

 

MCI_STATUS_PARMS StatusParms;

 StatusParms.dwItem = MCI_SEQ_STATUS_DIVTYPE;

 mciSendCommand (m_wDeviceID, MCI_STATUS, MCI_WAIT | MCI_STATUS_ITEM, (DWORD)(LPVOID) &StatusParms)

 返回信息存放于StatusParms.dwReturn中。

MCI_STATUS标志 MCI_STATUS_LENGTH 得到文件长度 MCI_STATUS_MODE 得到文件播放的当前状态 MCI_STATUS_POSITION 得到文件播放的当前位置 MCI_STATUS_TIME_FORMAT 得到当前的时间格式 MCI_SEQ_STATUS_DIVTYPE 判断文件是PPQN类型仍是SMPTE类型 MCI_SEQ_STATUS_TEMPO 得到当前播放速度,PQRN类型, 此值为节拍/分,SMPTE类型,此值为祯/ ---- 8 设置时间格式及播放速度

MCI_SET_PARMS SetParms;