winmm.libの使い方について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
parapara

winmm.libの使い方について

#1

投稿記事 by parapara » 13年前

winmm.libの使い方について、「猫でも」の第二版(第4版ももっています)をやっているのですがwinmm.libをvisualstudio2010の追加の依存ファイルに設定しても、MMTIME構造体の宣言で、定義されてない識別子みたいなエラーがでるのですが、本のプログラムに#include<mmsystem.h>を追加しないといけないんでしょうか?よろしくお願いします。他にスマートなやりかたあればよろしくおねがいします。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: winmm.libの使い方について

#2

投稿記事 by softya(ソフト屋) » 13年前

winmm.libはリンク時に使うものでコンパイル済みのライブラリです(実際にはDLLの参照解決用のライブラリ)。
これはコンパイルに関係しません。

#include<mmsystem.h>はソースにインクルードされるのでコンパイルに関係します。

コンパイルとリンクの違いを理解して貰うのが早道かと思います。
「ビルドは何をしている? [VC++の使い方]」
http://www.nitoyon.com/vc/tutorial/proj ... detail.htm

>他にスマートなやりかたあればよろしくおねがいします。
特にないですが、VC++などに著しく限定して良いのなら#pragmaを使えばソースコードにwinmm.libを記述できます。
こうすると追加の依存ファイルに設定する必要はありません。ただし、gccなどでは通用しません。

#pragma comment(lib, "winmm.lib")
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: winmm.libの使い方について

#3

投稿記事 by ISLe » 13年前

MMTIME構造体は、mmsystem.hで定義される。
mmsystem.hはwindows.hといっしょにインクルードされる。
とMSDNには書いてありますが。

winmm.libを使うプログラムのソースファイルで、mmsystem.hをインクルードするだけで解決するならそれがいちばんスマートだと思います。

paraparaさんが書いたソースを見ないとそれ以上は何とも言えません。

parapara

Re: winmm.libの使い方について

#4

投稿記事 by parapara » 13年前

ソフト屋様ISLE様ありがとうございます。以前Isle様は直感的なプログラミング言語を教えてもらい参考になりました。CLI系の本がココ何年かで増え良かったです。まだ、やってませんが、COMをある程度理解したら、DirectXも中身の想像がある程度分かるような気がします。ダイレクトXの最初のインスタンスを作る時にCOMの初期化(アパートメント)もやっているのでしょうか?
仰るとおりwindows.hをインクルードしても、駄目なんですよ、mmsystem.hをインクルードすると解決するんですが。

コード:

// タイピング01ver01Project.cpp : アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"
#include "タイピング01ver01Project.h"

#define MAX_LOADSTRING 100
#define TIMER_ID 100
// グローバル変数:
HINSTANCE hInst;								// 現在のインターフェイス
TCHAR szTitle[MAX_LOADSTRING];					// タイトル バーのテキスト
TCHAR szWindowClass[MAX_LOADSTRING];			// メイン ウィンドウ クラス名

// このコード モジュールに含まれる関数の宣言を転送します:
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

 	// TODO: ここにコードを挿入してください。
	MSG msg;
	HACCEL hAccelTable;

	// グローバル文字列を初期化しています。
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_MY01VER01PROJECT, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// アプリケーションの初期化を実行します:
	if (!InitInstance (hInstance, nCmdShow))
	{
		return FALSE;
	}

	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MY01VER01PROJECT));

	// メイン メッセージ ループ:
	while (GetMessage(&msg, NULL, 0, 0))
	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	return (int) msg.wParam;
}



//
//  関数: MyRegisterClass()
//
//  目的: ウィンドウ クラスを登録します。
//
//  コメント:
//
//    この関数および使い方は、'RegisterClassEx' 関数が追加された
//    Windows 95 より前の Win32 システムと互換させる場合にのみ必要です。
//    アプリケーションが、関連付けられた
//    正しい形式の小さいアイコンを取得できるようにするには、
//    この関数を呼び出してください。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MY01VER01PROJECT));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_MY01VER01PROJECT);
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassEx(&wcex);
}

//
//   関数: InitInstance(HINSTANCE, int)
//
//   目的: インスタンス ハンドルを保存して、メイン ウィンドウを作成します。
//
//   コメント:
//
//        この関数で、グローバル変数でインスタンス ハンドルを保存し、
//        メイン プログラム ウィンドウを作成および表示します。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // グローバル変数にインスタンス処理を格納します。

   hWnd = CreateWindow(szWindowClass, "猫でも分かるキー入力", WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  関数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的:  メイン ウィンドウのメッセージを処理します。
//
//  WM_COMMAND	- アプリケーション メニューの処理
//  WM_PAINT	- メイン ウィンドウの描画
//  WM_DESTROY	- 中止メッセージを表示して戻る
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;
	static MMTIME mt;
	static int ch1=-1,ch2=-1;
	char szBuf[256];
	RECT rect;
	static UINT start_time,end_time,interval_time,start_flag=FALSE,answer=FALSE;

	switch (message)
	{
	case WM_CREATE:
		SetTimer(hWnd,TIMER_ID,500,NULL);
		srand((unsigned int)time(NULL));
		mt.wType=TIME_MS;
		break;
	case WM_TIMER:
		if(start_flag==FALSE||wParam!=TIMER_ID)return DefWindowProc(hWnd,message,wParam,lParam);
		timeGetSystemTime(&mt,sizeof(MMTIME));
		interval_time=mt.u.ms;
		InvalidateRect(hWnd,NULL,TRUE);
		break;
	case WM_CHAR:
		if(VK_SPACE==wParam){
			start_flag=TRUE;
			timeGetSystemTime(&mt,sizeof(MMTIME));
			start_time=mt.u.ms;
			ch2='A'+rand()%(26+26);
			InvalidateRect(hWnd,NULL,TRUE);
		}else if(VK_ESCAPE==wParam){
			start_flag=FALSE;
			ch1=-1;ch2=-1;
			InvalidateRect(hWnd,NULL,TRUE);
		}else{
			ch1=wParam;
			if(ch1==ch2){//正解
				timeGetSystemTime(&mt,sizeof(MMTIME));
				end_time=mt.u.ms-start_time;
				answer=TRUE;
				SendMessage(hWnd,WM_CHAR,VK_SPACE,0);
			}
			else{answer=FALSE;}//不正解
		}
		break;
	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// 選択されたメニューの解析:
		switch (wmId)
		{
		case IDM_ABOUT:
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
			break;
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
	case WM_PAINT:
		if(start_flag==FALSE)return(DefWindowProc(hWnd,message,wParam,lParam));
		GetClientRect(hWnd,&rect);
		hdc = BeginPaint(hWnd, &ps);
		if(ch2!=-1){
			wsprintf(szBuf,"問題文字\"%c\"をタイプしてください。",ch2);
			rect.left=10;rect.top=10;
			DrawText(hdc,szBuf,-1,&rect,DT_CENTER);
		}
		if(ch1!=-1){
			wsprintf(szBuf,"あなたがタイプした文字:\"%c\"",ch1);
			rect.left=10;rect.top=30;
			DrawText(hdc,szBuf,-1,&rect,DT_CENTER);
		}
		if(answer){//正解
			wsprintf(szBuf,"正解です。\n反応時間:%d(ms)",end_time);
			rect.left=10;rect.top=50;
			DrawText(hdc,szBuf,-1,&rect,DT_CENTER);
		}else if(ch1!=-1){//不正解
			wsprintf(szBuf,"不正解です。\n経過時間:%d(ms)",interval_time-start_time);
			rect.left=10;rect.top=50;
			DrawText(hdc,szBuf,-1,&rect,DT_CENTER);
		}
		EndPaint(hWnd, &ps);
		break;
	case WM_CLOSE:
		KillTimer(hWnd,TIMER_ID);
		return DefWindowProc(hWnd, message, wParam, lParam);
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

// バージョン情報ボックスのメッセージ ハンドラーです。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);
	switch (message)
	{
	case WM_INITDIALOG:
		return (INT_PTR)TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hDlg, LOWORD(wParam));
			return (INT_PTR)TRUE;
		}
		break;
	}
	return (INT_PTR)FALSE;
}

parapara

Re: winmm.libの使い方について

#5

投稿記事 by parapara » 13年前

書き方間違えました。
すいません、まだやってませんが、はCLI系です。
COMはやりました。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: winmm.libの使い方について

#6

投稿記事 by softya(ソフト屋) » 13年前

C++/CLIのCLRフォーム(GUI)はVisualStudio2012で裏技的なことしないと新規作成できなくなりました。
なので、マイクロソフト的にはC++/CLIでのGUIは非推奨な方向に進んでいますので使わないほうが良いと思います。
.NetFrameWork体系の中でGUIを作成するのならC#をオススメします(C++もまだならC#を先に勉強するのもひとつの方法です)。
GUIを作るならC/C++ならWin32APIやGTK+、C++ならQtとかMFCもありますので、C++/CLIのCLRフォーム(GUI)に拘るかどうかはparaparaさんがよく考えて下さい。
時代は移り変わりますので、ひとつの技術に固執するのはあまり良い選択肢ではありません。

【追記】
Windows8のストアアプリ(METRO UI)はWinRTとC++/CXとう別物になっていますので、Win32APIでも無くCLRでもありません。MFCやQtも使えません。
これも時代は移り変わるという例です。
parapara さんが書きました:仰るとおりwindows.hをインクルードしても、駄目なんですよ、mmsystem.hをインクルードすると解決するんですが。
その理由は納得できたのでしょうか?
結構C言語の根本理解に関わる問題なのですが。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: winmm.libの使い方について

#7

投稿記事 by ISLe » 13年前

よくあることですが、プリコンパイル済みヘッダが悪さしているのではないでしょうか。

こちらでプリコンパイル済みヘッダを使用しない設定でstdafx.hをwindows.hに書き換えてコンパイルしたところMMTIMEに関するエラーは出ませんでした。

プリコンパイル済みヘッダはすべてのソースファイルで同じヘッダをインクルードするなら良いのですが、プログラムを構造化していくと誤動作等で邪魔になるだけなのでわたしは使いません。

parapara

Re: winmm.libの使い方について

#8

投稿記事 by parapara » 13年前

Isle様の言うことは初耳で目から鱗、状態です。
ソフト屋様、グローバルな関数や変数を使うためには、宣言が必要不可欠ということだと思いますけど。
それと、C++をやり、確かC++で作られたようなOSwindowsのwin32APIのインスタンスとかが同じ概念ではないけど、COMとかと一緒で、それに近いものを意味するような感じで納得できて、良かったです。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: winmm.libの使い方について

#9

投稿記事 by softya(ソフト屋) » 13年前

parapara さんが書きました:ソフト屋様、グローバルな関数や変数を使うためには、宣言が必要不可欠ということだと思いますけど。
それと、C++をやり、確かC++で作られたようなOSwindowsのwin32APIのインスタンスとかが同じ概念ではないけど、COMとかと一緒で、それに近いものを意味するような感じで納得できて、良かったです。
何故comとかインスタンスが出てくるのか話の筋道がわかりませんが、winmm.libだけではダメで#include<mmsystem.h>が必要な理由は理解できたと言うことでしょうか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

parapara

Re: winmm.libの使い方について

#10

投稿記事 by parapara » 13年前

ソフト屋様、理解できたと思います。

閉鎖

“C言語何でも質問掲示板” へ戻る