记录Windows_SDK编程–弹钢琴项目及遇到的问题
首先是代码的前缀模板部分,均相同,故单独放置,使用时复制粘贴即可
#include <Windows.h>
#include <tchar.h>
#include <mmsystem.h>
#pragma comment(lib, "WINMM.LIB")
HINSTANCE g_hInstance = 0;
LRESULT CALLBACK WndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lPara);
int APIENTRY _tWinMain(
HINSTANCE hInstance, //本程序的实例句柄
HINSTANCE hPreInstance,
PTCHAR pStr,
int nCmd
)
{
g_hInstance = hInstance;
//1 设计一个窗口类
//UINT style;
//WNDPROC lpfnWndProc;
//int cbClsExtra;
//int cbWndExtra;
//HINSTANCE hInstance;
//HICON hIcon; 图标
//HCURSOR hCursor; 光标
//HBRUSH hbrBackground;
//LPCWSTR lpszMenuName;
//LPCWSTR lpszClassName;
WNDCLASS wnd = { 0 };
wnd.style = CS_VREDRAW | CS_HREDRAW;//风格
wnd.lpfnWndProc = WndProc; //非常重要,消息处理回调函数的指针
wnd.hInstance = hInstance; //本程序的实例句柄,将窗口类注册到自己的程序中
wnd.hbrBackground = (HBRUSH)COLOR_WINDOW;//背景颜色
wnd.lpszClassName = _T("Piano"); //非常重要,窗口类名,是一个标识
//---------------------------------------------------------------
wnd.hCursor = 0;
wnd.hIcon = 0;
wnd.lpszMenuName = 0;
//2 注册窗口类
RegisterClass(&wnd);
//3 创建窗口
// 返回值,就是窗口的句柄
// 我们要想操作窗口,API一定会要求我们提供句柄
HWND hWnd = CreateWindow(
_T("Piano"), //窗口类名,必须和之前注册的一致
_T("Piano"),//窗口名,随便起的名字
WS_OVERLAPPEDWINDOW,//窗口风格,这里是重叠窗口(最常见的普通窗口)
10, 10, 500, 300, //窗口的左上角x,y坐标,宽度和高度
NULL, //父窗口句柄
NULL, //菜单的句柄
hInstance, //实例句柄,代表这个窗口属于本程序
NULL //传递WM_CREATE消息的时候,一个附加的参数
);
//4 更新显示窗口
//窗口刚被创建的时候,是隐藏起来的,需要使用
//ShowWindow显示出来
ShowWindow(hWnd, SW_SHOW);
//它会产生第一个WM_PAINT消息,让窗口有机会自我绘制
UpdateWindow(hWnd);
//5 消息循环(消息泵)
MSG msg = {};
//GetMessageW(
// _Out_ LPMSG lpMsg,
// _In_opt_ HWND hWnd, 我只接收某一个窗口的消息
// _In_ UINT wMsgFilterMin, 获取消息的最小值
// _In_ UINT wMsgFilterMax);获取消息的最大值
// 5.1获取消息
//当获取到WM_QUIT消息的时候,返回0
//while结束整个程序结束
while (GetMessage(&msg, 0, 0, 0))
{
// 5.2翻译消息
TranslateMessage(&msg);
// 5.3转发到消息回调函数
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WndProc(
HWND hWnd, //哪一个窗口产生了消息
UINT Message, //产生的消息是什么
WPARAM wParam,//消息的附加信息
LPARAM lParam //也是消息的附加信息
)
- 第一次根据钢琴需求写出的代码为响应A~Z26个按键,播放对应按键的音效(很长,很LOW)
case 0x(XX) 为16进制的A~Z
(用PlaySound也可以)
反正都是无效打工…
{
switch (Message)
{
case WM_KEYDOWN:
switch (wParam)
{
case 0x41:
mciSendString(TEXT("close G://Sound_A.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_A.wav"), NULL, 0, NULL);
break;
case 0x42:
mciSendString(TEXT("close G://Sound_B.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_B.wav"), NULL, 0, NULL);
break;
case 0x43:
mciSendString(TEXT("close G://Sound_C.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_C.wav"), NULL, 0, NULL);
break;
case 0x44:
mciSendString(TEXT("close G://Sound_D.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_D.wav"), NULL, 0, NULL);
break;
case 0x45:
mciSendString(TEXT("close G://Sound_E.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_E.wav"), NULL, 0, NULL);
break;
case 0x46:
mciSendString(TEXT("close G://Sound_F.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_F.wav"), NULL, 0, NULL);
break;
case 0x47:
mciSendString(TEXT("close G://Sound_G.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_G.wav"), NULL, 0, NULL);
break;
case 0x48:
mciSendString(TEXT("close G://Sound_H.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_H.wav"), NULL, 0, NULL);
break;
case 0x49:
mciSendString(TEXT("close G://Sound_I.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_I.wav"), NULL, 0, NULL);
break;
case 0x4A:
mciSendString(TEXT("close G://Sound_J.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_J.wav"), NULL, 0, NULL);
break;
case 0x4B:
mciSendString(TEXT("close G://Sound_K.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_K.wav"), NULL, 0, NULL);
break;
case 0x4C:
mciSendString(TEXT("close G://Sound_L.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_L.wav"), NULL, 0, NULL);
break;
case 0x4D:
mciSendString(TEXT("close G://Sound_M.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_M.wav"), NULL, 0, NULL);
break;
case 0x4E:
mciSendString(TEXT("close G://Sound_N.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_N.wav"), NULL, 0, NULL);
break;
case 0x4F:
mciSendString(TEXT("close G://Sound_O.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_O.wav"), NULL, 0, NULL);
break;
case 0x50:
mciSendString(TEXT("close G://Sound_P.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_P.wav"), NULL, 0, NULL);
break;
case 0x51:
mciSendString(TEXT("close G://Sound_Q.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_Q.wav"), NULL, 0, NULL);
break;
case 0x52:
mciSendString(TEXT("close G://Sound_R.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_R.wav"), NULL, 0, NULL);
break;
case 0x53:
mciSendString(TEXT("close G://Sound_S.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_S.wav"), NULL, 0, NULL);
break;
case 0x54:
mciSendString(TEXT("close G://Sound_T.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_T.wav"), NULL, 0, NULL);
break;
case 0x55:
mciSendString(TEXT("close G://Sound_U.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_U.wav"), NULL, 0, NULL);
break;
case 0x56:
mciSendString(TEXT("close G://Sound_V.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_V.wav"), NULL, 0, NULL);
break;
case 0x57:
mciSendString(TEXT("close G://Sound_W.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_W.wav"), NULL, 0, NULL);
break;
case 0x58:
mciSendString(TEXT("close G://Sound_X.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_X.wav"), NULL, 0, NULL);
break;
case 0x59:
mciSendString(TEXT("close G://Sound_Y.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_Y.wav"), NULL, 0, NULL);
break;
case 0x5A:
mciSendString(TEXT("close G://Sound_Z.wav"), NULL, 0, NULL);
mciSendString(TEXT("play G://Sound_Z.wav"), NULL, 0, NULL);
break;
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hWnd, Message, wParam, lParam);
break;
}
return 0;
//所有不处理的消息,都可以由DefWindowProc默认处理
}
反正就…通俗易懂…
--------------------------------------------------------------------------------------------------------------------------------------------------------
- 因为按键音频的wav文件都是大致一致的Sound_(X).wav格式,故修改为如下版本(从这里有点小坑,导致后面做自动弹琴的辅助时出现问题)
{
switch (Message)
{
case WM_KEYDOWN:
{
TCHAR szFullPath[MAX_PATH];
_stprintf_s(szFullPath, MAX_PATH, _T("G://Sound_%C.wav"), wParam);
PlaySound(szFullPath, NULL, SND_ASYNC | SND_NOWAIT);//PlaySound不支持混音
}break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hWnd, Message, wParam, lParam);
break;
}
return 0;
//所有不处理的消息,都可以由DefWindowProc默认处理
}
(到这里其实不考虑自动弹琴辅助的问题是可以正常使用的)
- 接下来是自动弹琴辅助
读取曲谱文件,并输出打印即可
#include<stdio.h>
#include<Windows.h>
void GetDate(char*& data, int& len)
{
FILE* fp;
fopen_s(&fp, "G:\\Sound.txt", "r");
fseek(fp, 0, SEEK_END);
len = ftell(fp);
data = new char[len];
fseek(fp, 0, SEEK_SET);
fread(data, len, 1, fp);
fclose(fp);
}
int main()
{
HWND hWnd = FindWindow(NULL, L"Piano");
char* data = NULL;
int len = 0;
GetDate(data, len);
for (int i = 0; i < len; i++)
{
printf(" %c", data[i]);
if (data[i] != '\n' && data[i] != ' ')
{
SendMessage(hWnd, WM_CHAR, data[i], 0);
Sleep(400);
}
}
return 0;
}
然后这里就出现问题了,程序倒是跑起来了,自嗨模拟按键也感觉妥妥的,但是就是没有声音…
实现了吗?实现了。有影响吗?没有影响。有人在乎吗?没有人在乎。
其实就是之前自己挖的小坑…
之前想的是钢琴,那就是我按下按键,你发出声音,逻辑没毛病,单独看也没毛病,但放在一起就不行了。
这里也很好解决,其实就是把WM_KEYDOWN换成WM_CHAR就可以了,再贴一遍代码,毕竟我看别人代码也看不懂。
{
switch (Message)
{
//case WM_KEYDOWN:
case WM_CHAR:
{
TCHAR szFullPath[MAX_PATH];
_stprintf_s(szFullPath, MAX_PATH, _T("G:\\Sound_%C.wav"), wParam);
PlaySound(szFullPath, NULL, SND_ASYNC | SND_NOWAIT);//PlaySound不支持混音
}break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hWnd, Message, wParam, lParam);
break;
}
return 0;
//所有不处理的消息,都可以由DefWindowProc默认处理
}
注:WM_CHAR消息是俘获某一个字符的消息,WM_KEYDOWN消息是俘获某一个键按下的消息
如果光是弹琴可以是获取字符消息也可以是获取按键消息,但是由于自动弹琴是通过读取字符实现的,故此处需使用WM_CHAR。
- 最后先运行钢琴程序,再运行自动弹琴辅助程序就可以实现自动弹琴了。