Archie OSG Step By Step⑦MFC修改鼠标,制作半透明窗口,视口全屏以及添加背景音乐。

建立osgMFC项目

VS2010新建一空项目osgMFC

将osg示例Samples下的osgViewerMFC文件拷贝到当前项目的osgMFC文件下


项目→添加现有项,把osgMFC文件夹下文件都添加到当前项目。并在使用共享DLL中使用MFC。


然后配置osg的头文件和库文件目录,添加链接器输入。

OpenThreadsd.lib  
osgd.lib  
osgDBd.lib  
osgFXd.lib  
osgGAd.lib  
osgManipulatord.lib  
osgParticled.lib  
osgShadowd.lib  
osgSimd.lib  
osgTerraind.lib  
osgTextd.lib  
osgUtild.lib  
osgViewerd.lib  

出现错误:

“1>LINK : fatal error LNK1561: 必须定义入口点 ”,修改如下

运行,打开一个osg文件,如图

以下见FreeSouth《Step Into OSG》

修改鼠标

修改鼠标分为两种,一种为修改成为 系统自带鼠标,比如在收集点时把鼠标改为十字(cross),在执行非法操作时鼠标改为禁止,遇忙时等待。
另一种最常见的为加载.ANI文件,两种操作异曲同工,需要注意的是需要加载.ANI文件时,需要先把该文件放在res目录或是项目根目录中!
如本例子中StarCraftArrow.ani。ani为动画光标animation

在CMFC_OSG_MDIView.cpp的PreCreateWindow函数中做如下修改:

原代码为

BOOL CMFC_OSG_MDIView::PreCreateWindow(CREATESTRUCT& cs)
{
    return CView::PreCreateWindow(cs);
}


//在使用OSG进行渲染时将取消背景填充色,通过下面的代码重新注册窗口类可以改变当前的鼠标与背景色和窗口风格,还有一种比较麻烦的方法是重新注册WNDCLASS结构体。为了保证是宽字符串,需要在"res/StarCraftArrow.ani"前加上L,或者是TEXT都可以,VS8几乎取消了对窄字符的支持!GetStockObject函数,可以返回一个画刷,字体或PEN,具体参数如下: 

HGDIOBJ GetStockObject( int fnObject); 

/*BLACK_BRUSH 黑色画刷,值为4 

DKGRAY_BRUSH 暗灰色画刷 

GRAY_BRUSH 灰色画刷 

HOLLOW_BRUSH 空画刷,显示为背景 

LTGRAY_BRUSH 亮灰色画刷 

NULL_BRUSH 空画刷,显示为背景 

WHITE_BRUSH 白色画刷 

BLACK_PEN 黑色Pen 

WHITE_PEN 白色pen. 

NULL_PEN 空画笔 

SYSTEM_FONT 得到系统字体,默认情况下中国就是宋体,是在程序中菜单上,对话框等上出现的字体 

DEFAULT_PALETTE 得到系统调色板 */

BOOL CMFC_OSG_MDIView::PreCreateWindow(CREATESTRUCT& cs)
{
    
    if (!CView::PreCreateWindow (cs)) return FALSE ;
    cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,
        LoadCursorFromFile("res/StarCraftArrow.ani"), (HBRUSH)GetStockObject(4)) ; 
    return TRUE;
   
}
重新注册窗口类可以 改变当前的鼠标与背景色和窗口风格
函数: HCURSOR LoadCursorFromFile(LPCTSTR lpFileName); 此函数可以从文件中读入一个鼠标,返回HCURSOR。失败时返回NULL.失败的情况一般为.ANI文件不存在或是做过非法修改! 

HCURSOR LoadCursor( HINSTANCE hInstance, LPCTSTR lpCursorName); 此函数也可以用做取鼠标,不同的是它取的是系统默认的鼠标,第一个参数一般设置为NULL,经常使用的语句是:SetCursor(LoadCursor(NULL, IDC_WAIT));其中第二个参数IDC_WAIT可以是IDC_ARROW:箭头,IDC_UPARROW向上箭头,IDC_CROSS十字架等等!

为啥鼠标没变呢?

透明对话框

在OSG中,在场景中可能会经常用到无模式的对话框,以便显示建筑信息等等。这里就需要用到透明对话框的制做。在这里首先介绍一下物体透明的原理。
各种设计透明物体的方法在经过实践的选择以后,alpha混合技术成为主导。它的原理是如果一个物体需要对它后面的物体透明,这就需要将透明物的颜色和其后面物体的颜色进行混合。与每个象素相关联的有一个RGB颜色值和一个Z缓冲器深度值,另外一个成份就是alpha值,可以根据需要生成并存储,可以使用alpha描述给定象素处物体的透明程度(Archie注:更确切的说是不透明程度),alpha为1表示不透明,为0表示全透明。
通常有些文件格式为RGBA,其中最后一个A就代表alpha通道,它的意义为:如果C1代表遮挡物体颜色,C2代表被挡物体颜色,则挡住区域最终的颜色值为:
C = alpha*C1 + (1-alpha)*C2 .

在VS中为我们提供了一个函数,专门用来计算层叠窗口的透明度与不透明度!

BOOL SetLayeredWindowAttributes( HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags);
下面我们把上个例子中的关于对话框做成透明的:
示例二:透明对话框的制做
第一步:在CAboutDlg类上右键,属性,在属性面板的重写按钮下拉菜单中选中添加OnInitDialog() 或者右键,类向导,重写虚函数。
第二步:在MFC_OSG_MDI..cpp中对重写的OnInitDialog进行填充,首先要弄明白的是OnInitDialog()是在窗口初始化时调用的函数,所以在 窗口未产生之前就会调用该函数。
BOOL CAboutDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    // TODO:  在此添加额外的初始化
    //在窗口样式中添加WS_EX_LAYERED
    SetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE,GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE)^WS_EX_LAYERED);
    //需要装入User32.DLL 
    HINSTANCE hInst = LoadLibrary("User32.DLL"); 
    if(hInst) 
    { 
        typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD); 
        MYFUNC fun = NULL; //取得SetLayeredWindowAttributes函数指针 
        CHAR str[] = "SetLayeredWindowAttributes" ; 
        fun=(MYFUNC)GetProcAddress(hInst, str); 
        if(fun)
            fun(this->GetSafeHwnd(),0,128,2); 
        FreeLibrary(hInst); 
    }

    return TRUE;  // return TRUE unless you set the focus to a control
    // 异常: OCX 属性页应返回 FALSE
}

在VS中为我们提供了一个函数,专门用来计算层叠窗口的透明度与不透明度! 下面来看一下这个函数:

函数:

    

BOOL SetLayeredWindowAttributes( HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags); 
    参数:
    HWND hWnd :指的是需要透明的窗口的句柄,需要指明的是该窗口必须具有WS_EX_LAYERED的扩展风格才能具备透明度,可以使用SetWindowLong来对扩展风格进行处理,这是个极常用的函数,等一会儿详细介绍。 
    COLORREF crKey:顾明思义,这里指的是要透明的颜色,使用的是RGB宏(0~255) 
    BYTE bAlpha:指的是透明度。0指全透明,255指不透明。 
    DWORD dwFlags:指定一种行为,可以是以下两值: LWA_COLORKEY 把crKey 当作透明色 LWA_ALPHA 使用bAlpha来指定不透明度

函数: LONG SetWindowLong( HWND hWnd, int nIndex, LONG dwNewLong); 
功能:设置窗口风格 
参数:
  HWND hWnd:一般指要修改的窗口的句柄 
  Int nIndex:要设置的风格类型,一般取下列值之一: 
      GWL_EXSTYLE :设置扩展风格  
      GWL_STYLE :设置新的风格 
      GWL_ID :给窗口设置一个新的ID 
      GWL_USERDATA :给窗口重新定义一个32位长的数字,一般窗口都有一个唯一32位长的数字来描述其各种属性 
  LONG dwNewLong:给窗口设置新值(风格),一般是通过GetWindowLong取得同样值后与需要的值取位与运算,或是位且取反运算来去掉该值!GetWindowLong只有前两个参数,返回值为风格(LONG)
效果如下
 

这里再对动态链接库进行一下简单介绍。(Archie)

动态链接库(dynamics link library,DLL)是一个包含了若干个导出函数的可执行文件。与静态链接库(static link library,SLL)不同主要是连接时机不同。SLL是在编译、链接应用程序时就同程序相链接,链接由LINK完成,称为“静态链接”;而DLL则在程序运行时才同程序链接,由Windows操作系统来完成,称为“动态链接”。

      使用静态链接库,必须执行Tool|Options命令,在Directories页面设置Library files静态链接库文件所在的路径。

      使用DLL有隐式链接和显示链接,隐式链接是指在程序运行时,由Windows操作系统将要使用的DLL自动加载到应用程序,显示链接是指应用程序在执行的过程中,程序自己通过专门的函数(如LoadLibrary)调用来动态加载DLL。

       采用隐式链接时,除DLL,还需提供DLL的导入库文件(即LIB文件),并且需要在VC开发环境中设置Project有关选项,在Project|Settings命令,Link页面Object/library modules输入库的路径和文件名。

       采用显示链接,不需要LIB文件,DLL中的导出函数必须在模块定义文件(DEF文件)中进行EXPORTS说明。在程序中通过函数调用动态加载和卸载DLL,并通过函数指针调用导出函数。

Archie注:VC6 中 只要加入这段代码在顶部 就可以使用SetLayeredWindowAttributes了 
#define WS_EX_LAYERED 0x00080000
#define LWA_COLORKEY 0x00000001
#define LWA_ALPHA 0x00000002
typedef BOOL (FAR WINAPI *LAYERFUNC)(HWND,COLORREF,BYTE,DWORD);
BOOL SetLayeredWindowAttributes(HWND hwnd,COLORREF crKey,BYTE bAlpha,DWORD dwFlags)
{
	LAYERFUNC SetLayer;
	HMODULE hmod = LoadLibrary("user32.dll");
	SetLayer=(LAYERFUNC)GetProcAddress(hmod,"SetLayeredWindowAttributes");
	BOOL bReturn = SetLayer(hwnd,crKey,bAlpha,dwFlags);
	FreeLibrary(hmod);
	return bReturn;
}

 

这也是一个显示使用DLL的例子。

typedef BOOL (FAR WINAPI *LAYERFUNC)(HWND,COLORREF,BYTE,DWORD);关于typedef此句理解

声明一个指向函数的指针类型,返回值为BOOL。

这句使用了typedef也就是说为声明重新定义了一个别名LAYERFUNC。

LAYERFUNC SetLayer;//声明一个指向函数的指针变量

SetLayer=(LAYERFUNC)GetProcAddress(hmod,"SetLayeredWindowAttributes");

获取函数的地址GetProcAddress函数检索指定的动态链接库(DLL)中的输出库函数地址。

函数原型:

FARPROC GetProcAddress(

HMODULE hModule, // DLL模块句柄

LPCSTR lpProcName // 函数名

);

函数参数类型分别为HWND,COLORREF,BYTE,DWORD

HMODULE可以用HINSTANCE替换HMODULE 是代表应用程序载入的模块,win32系统下通常是被载入模块的线性地址

HINSTANCE 在win32下与HMODULE是相同的东西,在Win32下还存在主要是因为win16
程序使用HINSTANCE来区别task。

在头文件中HMODULE定义如下:
typedef HINSTANCE HMODULE;
再看看HINSTANCE定义,
typedef HANDLE HINSTANCE;
再看看HANDLE定义,
typedef PVOID HANDLE;
再看看PVOID定义,typedef void *PVOID;

 

函数指针

指针变量也可以指向一个函数。一个函数在编译时被分配给一个入口地址。这个函数入口地址就称为函数的指针。可以用一个指针变量指向函数,然后通过该指针变量调用此函数。

指向函数的指针变量的一般定义形式为

函数类型  (*指针变量名p)(函数形参表);

在定义指向函数的指针变量p时(*p)两侧的括号不可省略()优先级高于*,表示p先于*结合,它是指针变量,然后再与后面的()结合,表示此指针变量指向函数,这个函数值(即函数返回的值)为函数类型。

求函数地址时,只需将函数名赋给函数指针即可,不能带参数形式。函数名代表函数入口地址,而带参数则是函数调用。比如求两个数最大值原型

int max(int x,int y);

定义函数指针

int (*p)(int, int);

int a,b,m;

p=max;    //函数名代表函数入口地址,入口地址赋给指针变量p

cin>>a>>b;

m=p(a,b);

此句和m=max(a, b)等价。

4、客户区全屏

一般来讲对客户区全屏需要以下几个步骤:
去掉边框、系统菜单、最大化最小化按钮,菜单(可去可不去),把客户区充斥到整个屏慕。这样就达到目的了。
 通过这个例子我们来深入理解一下MFC框架。 
下面我们在上一个程序的基础上来通过菜单响应来控制建立一个全屏的程序:

单文档全屏

第一步:定位到资源视图的菜单中,在原菜单的最后一项上添加视图根菜单,全屏子菜单:
第二步:对全屏菜单右击,选择添加事件处理程序,类列表选择CMainFrame。
选择添加编辑: 此时要想使用菜单控制全屏与非全屏,必须得知道当前程序是否处于全屏之中,因此需要在CMainFrame中添加一变量m_bFullScreen,添加变量有多种方法,最简单的是用手直接添,用手添的坏处是容易忘记初始化,好处是灵活性大,想怎么添怎么添,想添哪添哪,一般根据个人习惯不同,我习惯人工处理。
而后再添加一个为void FullScreen(bool )的函数,添加函数也可以通过向导,但是手工添感觉更好。当你对程序的整个条理比较清析的时候,无论怎样操作都不会出错,或是不会出什么大错。
下面是通过向导添加的变量,可以看到自动添加了变量初始化:m_bFullScreen(false)
CMainFrame::CMainFrame()
    : m_bFullScreen(false)
{
    m_bAutoMenuEnable = false;
}
在OnCreate中添加FullScreen(false);与初始化一致
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
        return -1;
    
    ……
     FullScreen(false) ;
    return 0;
}

void CMainFrame::FullScreen(BOOL)
{
    LONG style = ::GetWindowLong(this->m_hWnd,GWL_STYLE);
    //得到当前wnd
    CWnd *pWnd = AfxGetMainWnd();
    if (m_bFullScreen) // 全屏显示
    {
        pWnd->DrawMenuBar();
        // 去掉边框
        style&=~(WS_DLGFRAME | WS_THICKFRAME);
        SetWindowLong(this->m_hWnd,GWL_STYLE,style);
        // 最大化视窗
        this->ShowWindow(SW_SHOWMAXIMIZED);
        CRect rect;
        //得到当前视窗口并稍做移动,保证彻底全屏,可能有的机器不同,会保留任务栏,大多数都 会全屏
        this->GetWindowRect(&rect); 
        ::SetWindowPos(this->m_hWnd,HWND_TOPMOST,rect.left, rect.top, rect.right-rect.left + 3, rect.bottom-rect.top + 3, SWP_FRAMECHANGED);
    }
    else//窗口显示 
    { 
        //得到菜单 
        CMenu menu; 
        //取菜单 
        menu.LoadMenu(IDR_MAINFRAME); 
        //设置菜单 
        pWnd->SetMenu(&menu); 
        pWnd->DrawMenuBar(); 
        menu.Detach(); 
        style |= WS_DLGFRAME | WS_THICKFRAME; 
        SetWindowLong(this->m_hWnd, GWL_STYLE, style); 
        this->ShowWindow(SW_SHOWNORMAL); 
    } ;
}

多文档全屏

添加一个全局变量m_bFullScreen,添加一RECT变量 m_rcOldWnd;

先在构造函数中初始化m_bFullScreen:

CMainFrame::CMainFrame():m_bFullScreen( false){...}

PreCreateWindow()和OnCreate()函数可以不修改,用默认的.

void CMainFrame::FullScreen(BOOL)
{
   

    if (m_bFullScreen) // 全屏显示
    {  //保存旧窗口坐标位置
        GetWindowRect( &m_rcOldWnd);
        //隐藏菜单栏,状态栏等,以便全屏
        m_wndStatusBar.ShowWindow( SW_HIDE); 
        m_wndToolBar.ShowWindow( SW_HIDE); 

   //     SetMenu(NULL);//设置菜单为空   如果有此句,全屏时将看不到菜单栏

        ModifyStyle( 0 ,WS_POPUP );
        ModifyStyle(  WS_CAPTION, 0);
        ModifyStyle(WS_BORDER,0);
        ModifyStyle(WS_THICKFRAME,0);

        //将窗口大小设为全屏,
        MoveWindow( 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));

        MDIGetActive()->ShowWindow( SW_SHOWMAXIMIZED);//将视图区占满整个客户区

    }
    else//窗口显示 
    { 
        //显示菜单栏,状态栏等 
        m_wndStatusBar.ShowWindow( SW_SHOW); 
        m_wndToolBar.ShowWindow( SW_SHOW); 


        //恢复到旧位置
        MoveWindow( &m_rcOldWnd);  

        ModifyStyle( 0, WS_CAPTION );
        ModifyStyle( 0, WS_BORDER);
        ModifyStyle( 0, WS_THICKFRAME );

        //注意,此处不能用WS_MAXIMIZE,否则位置会变为第一次窗口的位置
        ModifyStyle( 0, WS_OVERLAPPED |  FWS_ADDTOTITLE |WS_MINIMIZEBOX | WS_MAXIMIZEBOX /* |WS_MAXIMIZE*/   );

        //重新加载菜单  当菜单栏也需要隐藏和显示时,在恢复菜单时加上此句,比如用键盘控制全屏
        SetMenu( CMenu::FromHandle( ::LoadMenu( ::AfxGetApp()->m_hInstance ,MAKEINTRESOURCE( IDR_MFC_OSG_MDITYPE))));

        //修改子窗口属性
        MDIGetActive()->ModifyStyle( 0, WS_CHILD | WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU
            | FWS_ADDTOTITLE /*| WS_THICKFRAME*/ | WS_MINIMIZEBOX | WS_MAXIMIZEBOX /*| WS_MAXIMIZE*/);

        MDIGetActive()->ShowWindow(  SW_SHOWNORMAL);//将子窗口视图区正常显示   

        ShowWindow(SW_SHOWNORMAL);//显示正常的主窗口


    } ;
}

接着,在子窗口的ChildFrame.cpp里设置窗口属性:

BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
{
    // TODO: Modify the Window class or styles here by modifying the CREATESTRUCT cs
    if( !CMDIChildWnd::PreCreateWindow(cs) )
        return FALSE;
    //注意,要全屏千万不能有WS_THICKFRAME
    cs.style = WS_CHILD | WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU
        | FWS_ADDTOTITLE /*| WS_THICKFRAME */| WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_MAXIMIZE;

    return TRUE;
}

总结:要实现全屏效果,可隐藏标题,菜单和工具,状态栏等,然后把子窗口最大化即可.本文还有一些缺陷,如没有考虑到滚动条等.

键盘控制全屏

由于视图类处理键盘和鼠标消息更为方便,我们把处理函数放在View类中,有几种处理方式

第一种比如按键F等字母键,直接在OnKeyDown消息中处理,这里全屏去掉了菜单项

#include "MainFrm.h"

void CMFC_OSG_MDIView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    // Pass Key Presses into OSG
    mOSG->getViewer()->getEventQueue()->keyPress(nChar);
    switch(nChar)  
    {  
    case VK_ESCAPE:  
        {
            GetParent()->SendMessage(WM_CLOSE);
        break;
        }   
    case 'F':  //全屏控制
        {  
            ((CMainFrame*)::AfxGetMainWnd())->OnFullscreen();
            break;  
        }  

    }    
}

第二种在PreTranslateMessage()中处理链接
或在OnChar等中处理

 音乐播放

音乐播放最好放在CMainFrame中,因为菜单频繁的控制VIEWER类,有几率可能会使音乐中断且在框类中调用

在程序开始创建时便开始播放音乐,并不是在打开模型后或是在打开模型时,在换场景等等对VIEWER类的操作中,不会使音乐受到任何影响,有时候需要重新加载VIEWER类来释放内存,那么音乐将会中断,而在CMainFrame中将不会出现这种情况!

---------------------------

Archie注:关于MCI可以参考利用MCI制作音乐播放器
MCI ( Media Control Interface ) ,即媒体控制接口,向基于Windows操作系统的应用程序提供了高层次的控制媒体设备接口的能力。

对于程序员来说,可以把MCI理解为设备面板上的一排按键,通过选择不同的按键(发送不同的MCI命令)可以让设备完成各种功能,而不必关心设备内部如何实现。比如,对于play,视盘机和CD机有不同的反应(一个是播放视频,一个播放音频),而对用户来说却只需要按同一按钮。
应用程序通过MCI发送相应的命令来控制媒体设备。MCI分为命令字符串和命令消息两种,两者具有类似的功能。命令字符串具有使用简单的特点,但是它的执行效率略低于命令消息。

相关程序

所有的MCI命令字符串都是通过 多媒体API函数mciSendString传递给MCI的,该函数的声明为:
MCIERROR mciSendString(
	LPCTSTR lpszCommand, //MCI命令字符串
	LPTSTR lpszReturnString, //存放反馈信息的缓冲区
	UINT cchReturn, //缓冲区的长度
	HANDLE hwndCallback //回调窗口的句柄,一般为NULL
	); //若成功则返回0,否则返回错误码。

该函数返回的错误码可以用mciGetErrorString函数进行分析,该函数的声明为:
BOOL mciGetErrorString(
	DWORD fdwError, //函数mciSendString或mciSendCommand返回的错误码
	LPTSTR lpszErrorText, //接收描述错误的字符串的缓冲区
	UINT cchErrorText //缓冲区的长度
	);


下面是使用mciSendString函数的一个简单例子:

 	char buf[50];
	MCIERROR mciError;
	mciError=mciSendString(“open cdaudio”,NULL,0,NULL);
	if(mciError)
	{
		mciGetErrorString(mciError,buf,sizeof(buf));
		AfxMessageBox(buf);
		return;
	}
"open cdaudio"命令会打开CD播放器,如果出错(如驱动器内没有CD)则返回错误码,此时可以用mciGetErrorString函数取得错误信息字符串。open是MCI的“打开设备”命令,cdaudio是MCI中约定的设备名。

----------------------------------
下面来介绍本节中使用的“发声函数”,在MCI中,往往会创立一个窗口,我们不需要此窗口,故而需要把窗口来隐藏掉:


函数: HWND MCIWndCreate( HWND hwndParent, HINSTANCE hInstance, DWORD dwStyle, LPSTR szFile);
功能:该函数创建MCI窗口 ,(MCI:Media Control Interface). 
参数:
hwndParent:父窗口句柄,将被挂名在此窗口下 
hInstance:创建一个实例与MCIWindow相关! 
dwStyle:指定风格,类似与CreateWindowEx的功能,也可以用之实现,该标识一般取下列值: 
  MCIWNDF_NOAUTOSIZEWINDOW MCI:具有此风格窗口的大小将不会改变。 
  MCIWNDF_NOAUTOSIZEMOVIE :同上。 
  MCIWNDF_NOERRORDLG :继承ERROR对话框给USER MCIWNDF_NOMENU :隐藏菜单,一般丢失的菜单上的选项可以在系统菜单上找到     MCIWNDF_NOOPEN :在面板上隐藏打开菜单,将从系统菜单上增加打开选项 
  MCIWNDF_NOPLAYBAR :隐藏工具栏 
  MCIWNDF_NOTIFYANSI :在向父窗口发送设置参数修改消息时,让MCIWnd使用ANSI字符替换Unicode字符只能与        MCIWNDF_NOTIFYMODE 配合使用在NT及2000以上的系统之上。 
  MCIWNDF_NOTIFYMODE 向系统发送MCIWNDM_NOTIFYMODE 消息,无论当前在进行什么操作,且在lparam中指定新值如  MCI_MODE_STOP。 MCIWNDF_NOTIFYPOS 当对播放器指定回放操作时将会发生此消息且记下当前回放位置 
  MCIWNDF_NOTIFYMEDIA当打开文件时会发送该消息,lparam中存有新文件之路径串 
  MCIWNDF_NOTIFYSIZE 当窗口大小改变时会发送此消息 
  MCIWNDF_NOTIFYERROR 向主窗口发送错误消息 
  MCIWNDF_NOTIFYALL 使所有的NODIFY风格被使用
  MCIWNDF_RECORD 在面板上增加Record键以完成其功能 
   MCIWNDF_SHOWALL 使所有的MCIWNDF_SHOW 风格被使用 
    MCIWNDF_SHOWMODE 当前配置模式被显示在WINDOWS标题栏中,当前模式可以通过MCIWndGetMode宏得到 
    MCIWNDF_SHOWNAME 在MCIWindow的标题栏中显示当前文件名
    MCIWNDF_SHOWPOS 在MCIWindow的标题栏中显示当前播放进度 LPSTR szFile:指定要播放的文件名字串,为平凡字串(意思为非宽字符)
 
函数: BOOL ShowWindow( HWND hWnd, int nCmdShow); 
功能:隐藏或显示指定窗口 
参数:
HWND hWnd:指定要隐藏或要显示的窗口 
Int nCmdShow: 参数一般习惯为取TRUE|true|1为显示,取FALSE|false|0为隐藏,而实际上01只是它们的前两个值,一般它可以取下列值: 
SW_HIDE :隐藏窗口,同时激活其它窗口 
SW_SHOW :显示窗口且激活其在当前位置 
SW_SHOWNA:显示窗口正常如果在激活仍旧在激活,一般不使用这个 
SW_SHOWNORMAL :正常显示窗口,如果在最小化之中将会被赋以焦点从而以正常尺寸在当前位置显示,这个一般在第一次创建窗口时使用, 关于MCI的更多内容请查阅MSDN: 

下面我们来播放音乐,在上一章例子的基础上做一些改动:

 

第一步

把要播放的音乐(建议使用.MP3,.WAV过大)拷至文件根目录下,否则需要在播放文件名前加路径,在调试程序编译运行时的根目录指的是放有很多.CPP,.H的这个当前目录,而独立运行指的是可执行程序所在目录。

第二步

点击菜单:项目属性页,在弹出的对话框中,配置项默认为对当前活动Debug进行配置,如果不调试,而发布Release则需要对Release进行配置,一般来讲Debug版本中包含更多的信息,但是Release适合发布,一般文件比较小。
点击下面列表中的链接器,按如图配置: 
在附加选项中添加vfw32.lib这是链接文件,在OSG中最经常使用与制做的功能模块便是WIN32 DLL,更加方便的复用,ActriveX控件适合做成品的功能模块,而DLL更适合某些具体的功能模块,如某DLL可到处实现对任何OSG程序任何场景的漫游,只需要添加不多的几行代码,而ActriveX更适合已经做成的小漫游场景用在VS的其它类型的程序框中,最经常见到的是VB与WEB。 
下面的配置也可以使用另一种方法,可以在属性页(如下图)的链接器输入右边面板的附加依赖项中添加vfw32.lib这样的话所加内容将会出现在如图示的右边所有选项的灰色框中,读者可自己下去试一下。


也可以通过语句添加,在stdafx.h中加入如下语句#pragma comment(lib, "vfw32.lib")便可动态的加入vfw32.lib文件。

 
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值