📄 9937.txt
字号:
似,可以播放100K 以上的文件。
低级Wave音频设备。用这些设备可以运行完全控制Wave数据的应用文
件。
---- 二、 WAV文件播放控制
---- 因为同样使用MCI,与上一章相同,只列出不同的部分。
---- 1. 打开设备
---- 将MIDI的MCI_DEVTYPE_SEQUENCER 改为"waveaudio"
---- 2. 录音
MCI_RECORD_PARMS RecordParms;
mciSendCommand (m_wDeviceID, MCI_RECORD,
NULL, (DWORD)(LPVOID)
&RecordParms);
---- 3. 保存录音
MCI_SAVE_PARMS SaveParms;
SaveParms.lpfilename = (LPCSTR) Filename;
mciSendCommand (m_wDeviceID, MCI_SAVE,
MCI_SAVE_FILE | MCI_WAIT,
(DWORD)(LPVOID) &SaveParms);
第三部分 CD的播放
---- CD的独特优势在于,它由作曲家设计,并由音乐厂家生产。不
同的计算机播放MIDI 文件时,声音效果也不一样,但是CD的声音效
果总是相同的。高品质的音频对计算机用户产生的效果会使你感到吃
惊。我们依然采用MCI播放CD,大部分的播放控制与前两部分相同,
只列出不同的部分
---- 1. 开光驱门
mciSendCommand (m_wDeviceID, MCI_SET,
MCI_SET_DOOR_OPEN, NULL);
---- 2. 关光驱门
mciSendCommand (m_wDeviceID, MCI_SET,
MCI_SET_DOOR_CLOSED, NULL);
---- 3. 打开设备
将MIDI的MCI_DEVTYPE_SEQUENCER 改为MCI_DEVTYPE_CD_AUDIO
---- 4. 播放
---- 指定播放起点必须经过MCI_MAKE_TMSF(Track,Minute,Second,
Frame)转化
---- 5. 查询当前信息
MCI_STATUS_CURRENT_TRACK 得到当前曲目
MCI_STATUS_LENGTH 得到CD或指定曲目长度
MCI_STATUS_MODE 得到驱动器的当前状态
MCI_STATUS_NUMBER_OF_TRACKS 得到CD曲目的数目
MCI_STATUS_POSITION 得到当前格式下的位置
MCI_STATUS_READY 检查设备是否就绪
MCI_STATUS_TIME_FORMAT 得到当前时间格式
MCI_STATUS_MEDIA_PRESENT 检查以确认CD是否在驱动器内
MCI_CDA_STATUS_TYPE_TRACK 检查已确认某曲目是否为音频曲目
---- 注意:
使用MCI_STATUS_LENGTH参数查询CD 及曲目长度,返回值通过调用
MCI_MSF_MINUTE(),MCI_MSF_SECOND()转换为分、秒。
MCI_STATUS_POSITION参数返回值调用MCI_TMSF_TRACK(), MCI_TMSF_MINUTE(),
MCI_TMSF_SECOND(),MCI_TMSF_FRAME才能得到当前的位置的道、分、秒、帧。
---- 6. 跳跃
---- 跳转的目标必须经过MCI_MAKE_TMSF(Track,Minute,Second,Frame)
转化最好将上述三种格式分开建类,或做成动态连接库。在
Project-- >Setting-- >Link-- >Object/library modules中加入winmm.lib,
源程序中包含< mmsystem.h >。
---- MCI调用简单,功能强大,可以满足日常多媒体编程的基本需要。但
是,MCI一次只能播放一个文件,使用DirectSound技术可以实现八个以上
WAV文件的同时播放。
****************************************************************
WINDOWS9x的后台进程
上海仙霞路山特公司软件中心 黄飞
---- 1. 后 台 进 程
---- 在WINDOWS NT中有一个功能强大的SERVICE管理器,它管理着一部分实现重要功能的后台进程, 例如FTP.HTTP.RAS. 网络Message等等,这些后台进程被称之为Service, 他们可以在系统启动时就加载,可以运行在较高的优先级,可以说是非常靠近系统核心的设备驱动程序中的一种.在WINDOWS95下,Microsoft没有提供这样一个高度集中化了的管,不过我们通过VC自带的PVIEW可以看到,在桌面背后同样有秘密的后台进程存在, 例如:SysTray,电源管理等.其实, 这些就是WINDOWS95管理的后台进程,WINDOWS95没有提供SERVICE管理器,取而代之是一个简单的登记接口,可以类似的称之为WINDOWS95下的Service(不过严格的讲,WINDOWS95下是没有Service的),同样的,通过这个登记接口,我们可以使自己的程序随系统启动而最先运行,随系统关闭而最后停止,和操作系统结合在一起,实现许多独特的功能.我在实际工作中,仔细的分析了这个Windows95的接口, 并且测试后发现,在WINDOWS97和最新的WINDOWS98中它一样有效.并通过这个机制,成功的实现了WINDOWS95.98下的无人职守监控.下面是关于这个接口的分析结果和一些准备知识.
---- 2. 进 程 数 据 库(PDB) 介 绍
---- 在Windows 的 核 心 数 据 结 构 中, 有 一 个 重 要 的 进
程 管 理 结 构 叫 进 程 数 据 库, 它 位 于Kernel32 的 公 用
内 存 堆 中, 可 以 通 过GetCurrentProcessID(...) 得 到 指
向 该 结 构 的 指 针, 以 下 是 部 分PDB 的 组 成, 与 本 文
直 接 相 关 的 是PDB 偏 移21h 处 的Service 标 志 字 节, 通
过 后 面 的 伪 码 分 析, 我 们 可 以 清 楚 的 看 到 所 谓 登
记 为Windows95 或Windows98 下 的Service 进 程, 只 不 过 是
把 它 相 应 的PDB 中 该 标 志 字 节 置 为1 而 已.
偏移量长度 说明
============================================
+00h DWORD Type // Kernel32对象的类型
+04h DWORD CReference //参考计数
+08h DWORD Un1 //未知
+0ch DWORD pSomeEvent //指向K32OBJ_EVENT指针
+10h DWORD TerminationStatus //活动标志或返回值
+14h DWORD Un2 //未知
....
+21h BYTE Flags1 // Service标记,
// "1"是Service进程,
// "0"普通进程
....
+24h DWORD pPSP // DOS PSP指针
....
============================================
---- 3. 实 现 接 口
---- (1) Windows95 中 提 供 的 简 单 的Service 接 口 是 一 个
32 位 的API: RegisterServiceProcess, 由 于 在VC++ 的Online help
中 得 不 到 关 于 这 个API 的 确 切 解 释, 笔 者 不 得 不 针
对 此API 进 行 了 逆 向 分 析, 以 下 是 在Windows95 的Kernel32.dll
中 该API 的 伪 码. 我 们 可 以 清 楚 的 看 到Window95 内 部 到
底 是 怎 样 做 的, 其 实 处 理 的 非 常 简 单.
BOOL RegisterServiceProcess
( DWORD dwProcessID, DWORD dwType )
{
HANDLE dwPID;
if( dwProcessID == NULL )
dwPID = dwCurrentProcessID;
// Get global kernel32 variable
else
// Call some kernel functions
if( ( dwPID = CheckPID( dwProcessID ) == NULL )
return FALSE;
if( dwType == 1 )
{
*(BYTE *)( dwPID + 0x21 ) | = 0x01;
return TRUE;
}
if( dwType == 0 )
{
*(BYTE *)( dwPID + 0x21 ) & = 0xFE;
return TRUE;
}
return FALSE;
}
以下为函数原形:
BOOL RegisterServiceProcess( DWORD dwPID, DWORD dwType )
参数: dwPID:进程ID, NULL代表当前进程
dwType: RSP_SIMPLE_SERVICE为登记
RSP_UNREGISTER_SERVICE为取消登记
返回值: TRUE: 调用成功
FALSE: 调用失败
---- (2) 另 外, 为 了 让Service 进 程 有 机 会 在BOOT 后 就
启 动,Windows95 的Registry 中 提 供 了 加 载 方 法: 在KEY
" MyComputer \HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
\CurrentVersion \RunServices " 加 入 自 己 的 应 用 程 序 命
令 行, 即 可 实 现 开 机 自 动 加 载. 当 然, 如 果 你 得 机
器 中 没 有 这 个Key, 自 己 建 一 个 也 是 可 以 的.
---- 4. 例 程
---- 下 面 是 实 现 例 程, 所 有 代 码 经 过 了WINDOWS95.
WINDOWS98 BETA3 的 测 试, 可 以 方 便 的 加 入 到 自 己 的 项
目 文 件 中.
---- 头 文 件:
// File: service.h
// The head file of "service.cpp"
// Note: 1. You must use C++ compiler
// 2. The platform is WIN32 (WINNT & WIN95)
#ifndef _SERVICE_H
#define _SERVICE_H
/////////////////////////////////////
////////////// USED FOR WIN95 SERVICE
// Micros
#define RSP_SIMPLE_SERVICE 1
#define RSP_UNREGISTER_SERVICE 0
// Function types for GetProcAddress
#define RegisterServiceProcess_PROFILE
(DWORD (__stdcall *) (DWORD, DWORD))
// Service Fuctions in Win95
BOOL W95ServiceRegister(DWORD dwType);
BOOL W95StartService( DWORD dwType );
#endif
CPP 文 件:
// File: service.cpp --- implement the service
#include "service.h"
/////////////////////////////////////
////////////// USED FOR WIN95 SERVICE
登 记 为Service 子 程 序:
/////////////////////////////////////////
////////////////////////////////////////
// Define: BOOL
W95ServiceRegister(DWORD dwType)
// Parameters: dwType --- Flag to
register or unregister the service
// RSP_SIMPLE_SERVICE means register
// RSP_UNREGISTER_SERVICE means unregister
// Return: TRUE --- call success;
FALSE --- call failer
BOOL W95ServiceRegister( DWORD dwType )
{
// Function address defination
DWORD (__stdcall * hookRegisterServiceProcess)
( DWORD dwProcessId, DWORD dwType );
// Get address of function
hookRegisterServiceProcess =
RegisterServiceProcess_PROFILE
GetProcAddress
(GetModuleHandle("KERNEL32"),
TEXT("RegisterServiceProcess"));
// Register the WIN95 service
if(hookRegisterServiceProcess(NULL,dwType)==0)
return FALSE;
return TRUE;
}
---- 加 入 注 册 表 子 程 序:
#define SERVICE_NAME TEXT("SERVICE")
// Define: BOOL W95StartService( DWORD dwType )
// Parameters: dwType --- Flag to
register or unregister the service
// RSP_SIMPLE_SERVICE means register
// RSP_UNREGISTER_SERVICE means unregister
// Return: TRUE --- call success; FALSE --- call failer
BOOL W95StartService( DWORD dwType )
{
// Local Variables
TCHAR lpszBuff[256];
LPTSTR lpszStr = lpszBuff +128;
LPTSTR lpszName = lpszBuff;
HANDLE hKey = NULL;
DWORD dwStrCb = 0;
DWORD dwValueType = 0;
// Get service name currently
lpszName = GetCommandLine();
for( int i = _tcslen(lpszName)-1; I >=0; i-- )
{
if( ( lpszName[i] != '"' )&&( lpszName[i]!=' ') )
break;
else if( lpszName[i] == '"' )
lpszName[i] = '\0';
}
if( lpszName[0] == '"' )
lpszName = lpszName +1;
// Registe as start up service
if( RegOpenKeyEx (HKEY_LOCAL_MACHINE,
TEXT( "SOFTWARE\\Microsoft\\Windows\\
CurrentVersion\\RunServices"),
0,
KEY_QUERY_VALUE | KEY_SET_VALUE,
&hKey ) != ERROR_SUCCESS )
{
if( RegCreateKey( HKEY_LOCAL_MACHINE,
TEXT( "SOFTWARE\\Microsoft\\
Windows\\CurrentVersion\\RunServices"),
&hKey ) != ERROR_SUCCESS )
{
//DebugOut( "RegCreateKey() error!");
return FALSE;
}
}
dwValueType = REG_SZ;
dwStrCb = 128;
// Take value
if( RegQueryValueEx(hKey,
SERVICE_NAME,
0,
&dwValueType,
(LPBYTE)lpszStr,
&dwStrCb ) == ERROR_SUCCESS )
{
// Find this key value
if( _tcscmp( lpszStr, lpszName )==0 )
{
// Remove the service
if( dwType == RSP_UNREGISTER_SERVICE )
{
if(RegDeleteValue( hKey, SERVICE_NAME )
== ERROR_SUCCESS )
{
RegCloseKey ( hKey );
return TRUE;
}
RegCloseKey( hKey );
return FALSE;
}
// Already exist service
if( dwType == RSP_SIMPLE_SERVICE )
{
//DebugOut("Already registed!");
RegCloseKey( hKey );
return TRUE;
}
}
// Not find it
} // No this value
// Unregiste return
if( dwType == RSP_UNREGISTER_SERVICE )
{
RegCloseKey( hKey );
return TRUE;
}
// No this value then create it
if( dwType == RSP_SIMPLE_SERVICE )
{
dwStrCb = 128;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -