マルチメディアタイマーの使用方法

このQ&Aのポイント
  • マルチメディアタイマーのプログラムの使用方法について
  • コードを作成して、マルチメディアタイマーを動作させたいが処理が固まる
  • timeSetEvent()を呼び出した後にプログラムの動作が止まる原因は何か
回答を見る
  • ベストアンサー

マルチメディアタイマーの使用方法

お世話になります、fujitomoです。 今回お聞きしたいのはマルチメディアタイマーのプログラムの使用方法についてです。現在下記のようなコードを作成して、マルチメディアタイマーを動作させたいと思っていますが、なぜか処理が固まってしまいます。 プログラムはVisual Studio2005のVisual C++のダイアログベースのプログラムで、CStatic派生クラスをメインダイアログクラスにてサブクラス化した際の動作を示しています。 //CStatic派生のクラスCSampleクラスのヘッダーファイル //CSample.h class CSample : public CStatic { static void CALLBACK TimerProc(UINT uTimerID,UINT uMsg,DWORD dwUser,DWORD dw1,DWORD dw2); static UINT TimerID; } //CSample.cpp void CSample::PreSubclassWindow() { TIMECAPS timercaps; MMRESULT mmresult; //分解能を取得 mmresult = timeGetDevCaps(&timercaps,sizeof(TIMECAPS)); if(mmresult != TIMERR_NOERROR){ AfxMessageBox(_T("分解能取得失敗")); return; } else period = timercaps.wPeriodMin; //最小タイマー分解能の設定 mmresult = timeBeginPeriod(period); if(mmresult != TIMERR_NOERROR){ AfxMessageBox(_T("分解能設定失敗")); return; } //タイマー処理の呼び出しの設定と開始 mmresult = ::timeSetEvent(500,period,TimerProc,0,TIME_PERIODIC|TIME_CALLBACK_FUNCTION); if(mmresult == NULL){ AfxMessageBox(_T("タイマー処理失敗")); return; } else TimerID = (UINT)mmresult; } void CALLBACK CSample::TimeProc(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) { if(uTimerID == TimerID){ ; } } というコードです。自分の予想ではTimerProcにブレークポイントを置いて、デバックを開始すると500msecでTimerProcにとぶと思っているのですが、実際はtimeSetEvent()を呼び出した後にプログラムの動作が止まってしまいます。 これは何が原因なのかわかりますでしょうか? timesetEvent()を使用するのが初めてで、なかなか使い方が分からず初歩的な質問なのかもしれませんが、どうかご意見を宜しくお願い致します。 尚、開発環境は Visual Studio 2005 Windows CE 6.0 です。宜しくお願い致します。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

 こんにちは。  試してみましたが、正常に動いています。サブクラスの掛け方に失敗しているのではないでしょうか。 //CTestDlg.cpp // BOOL CTestDlg::OnInitDialog() { CDialog::OnInitDialog(); // "バージョン情報..." メニューをシステム メニューに追加します。 // IDM_ABOUTBOX は、システム コマンドの範囲内になければなりません。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // このダイアログのアイコンを設定します。アプリケーションのメイン ウィンドウがダイアログでない場合、 // Framework は、この設定を自動的に行います。 SetIcon(m_hIcon, TRUE); // 大きいアイコンの設定 SetIcon(m_hIcon, FALSE); // 小さいアイコンの設定 // TODO: 初期化をここに追加します。 //スタティックコントロールのサブクラス化 m_sample.SubclassDlgItem(IDC_STATIC1, this); return TRUE; // フォーカスをコントロールに設定した場合を除き、TRUE を返します。 } // Sample.cpp : 実装ファイル // #include "stdafx.h" #include "listview.h" #include "Sample.h" #include<mmsystem.h> #pragma comment(lib, "winmm.lib") // CSample IMPLEMENT_DYNAMIC(CSample, CStatic) //staticメンバ変数 UINT CSample::TimerID = 0; //staticメンバ関数 void CALLBACK CSample::TimerProc(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) { //取り敢えずコールバック回数をスタティックテキストにカウント表示 static int sCount = 0; CSample* pSample = reinterpret_cast<CSample*>(dwUser); CWnd* pParent = pSample->GetParent(); pParent->SetDlgItemInt(IDC_STATIC1, sCount++); } CSample::CSample() { } CSample::~CSample() { } BEGIN_MESSAGE_MAP(CSample, CStatic) END_MESSAGE_MAP() // CSample メッセージ ハンドラ void CSample::PreSubclassWindow() { // TODO: ここに特定なコードを追加するか、もしくは基本クラスを呼び出してください。 TIMECAPS timercaps; MMRESULT mmresult; //分解能を取得 mmresult = timeGetDevCaps(&timercaps,sizeof(TIMECAPS)); if(mmresult != TIMERR_NOERROR) { AfxMessageBox(_T("分解能取得失敗")); return; } //最小タイマー分解能の設定 mmresult = timeBeginPeriod(timercaps.wPeriodMin); if(mmresult != TIMERR_NOERROR) { AfxMessageBox(_T("分解能設定失敗")); return; } //タイマー処理の呼び出しの設定と開始 mmresult = ::timeSetEvent(500, timercaps.wPeriodMin, TimerProc, reinterpret_cast<DWORD_PTR>(this), TIME_PERIODIC | TIME_CALLBACK_FUNCTION); if(mmresult == NULL) { AfxMessageBox(_T("タイマー処理失敗")); return; } //staticに代入 TimerID = (UINT)mmresult; //スーパークラスに渡す CStatic::PreSubclassWindow(); }

fujtomo
質問者

お礼

machongola様、御回答ありがとうございます。 どうやら、Widows CE環境ですと、動作が正常にいかないようです。 私もXPで同じコードで作成して、実行してみたところ動作しました。 確認不足だったようです。。 動作確認をしていただき、ありがとうございました。

関連するQ&A

  • マルチメディアタイマー

    初めて質問させていただきます。 Visual C++ 6.0でMFCのダイアログベースでマルチメディアタイマーを使おうとしてるのですが、 class CTimeCounter { public: LPTIMECALLBACK lpTimeCallback; UINT TimerID; UINT uPeriod; UINT uDelay; void GetPeriod(); void AttachAD(LPTIMECALLBACK lpProc); CTimeCounter(); virtual ~CTimeCounter(); }; void CTimeCounter::AttachAD(LPTIMECALLBACK lpProc) { TimerID = uPeriod = NULL; GetPeriod(); //最小分解能を取得し、uPeriodに代入 this->uDelay = uPeriod; this->lpTimeCallback = lpProc; } としてCTimeCounter ctcを宣言したのですが、OnInitDialogのTODOの箇所でコールバック関数のアドレスを取得しようとして ctc.AttachAD(this->TimerProc); とすると error C2664: 'AttachAD' : 1 番目の引数を 'void (unsigned int,unsigned int,unsigned long,unsigned long,unsigned long)' から 'void (__stdcall *)(unsigned int,unsigned int,unsign ed long,unsigned long,unsigned long)' に変換できません。 というエラーを返されます。これはどう対処すればいいのでしょうか? よろしくお願いします。

  • timeSetEventに対するtimeKillEventについて

    SetTimerとの比較も兼ねてtimeSetEvent関連を調べていたのですが CALLBACKの外部で timeSetEventの戻り値を保存しておき、必要な時にそのIDを基に timeKillEventするサンプルは簡単に見つかったのですが timeKillEventは内部で使ってもいいのでしょうか? なるべく端折って書くとたとえば timeBeginPeriod( 8 ); timeSetEvent( 40, 8, TimerProc, 0, TIME_PERIODIC ); とでもした場合に timeSetEventの重ねがけをしない(するならもうちょっと変更) という前提で void CALLBACK TimerProc( UINT ID, UINT, DWORD User, DWORD , DWORD ){ static int d(11); if ( !--d ){ timeKillEvent(ID); timeEndPeriod(8); } } 的なことをしても問題ないのでしょうか? (出力やtimeGetTimeなどの関数を付加して実験してみた結果だけだと、問題なく動いているように見えるのですが、実はすぐには分からないような問題が内部的に発生してる可能性はありますか?)

  • _beginthread()の使用について

    元々スレッドの生成を CreateThread(NULL, 0, ThreadFunc, (LPVOID)&param, 0, &dwID); としていたのですが、 生成したスレッドがC言語のライブラリを利用する場合、 CreateThread()ではなく_beginthread()を使うとMSDNに記載されていました。 そこでプログラムを_beginthread()に書き換えたのですが、 『error C2440: '関数' : 'DWORD (__stdcall *)(LPVOID)' から 'void (__cdecl *)(void *)' に変換できません。』 『warning C4024: '_beginthread' : の型が 1 の仮引数および実引数と異なります。』 とのエラーが表示されてしまいます。 アドバイスをよろしくお願いします。 #include <windows.h> #include <process.h> #define APP_NAME TEXT("Sample_MainWindow") typedef struct _ThreadParam {   HWND owner;   POINT point; } ThreadParam; DWORD WINAPI ThreadFunc(LPVOID vdParam) {      ・     (省略)      ・ } LRESULT CALLBACK WindowProc(   HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {   ThreadParam param;   switch(uMsg) {     case WM_LBUTTONDOWN:       param.owner = hWnd;       param.point.x = LOWORD(lParam);       param.point.y = HIWORD(lParam);       _beginthread(ThreadFunc, 0, &param);       return 0;     }   return DefWindowProc(hWnd, uMsg, wParam, lParam); }

  • EditBoxのサブクラス化

    いつもお世話になっております。 現在、EditBoxのサブクラス化についてやっておりまして、詰まってしまったのでお聞きしたいです。 EditBoxにおいてENTERとESCAPEを押下されたときにある処理をしようとしてサブクラス化をしたのですが、その結果その他のキーが受け付けられなくなってしまいました。 defaultで何かすればいいかと思いいろいろやってみましたがよくわからなかったのでアドバイスお願いします。 現在のソースは以下のとおりです。 LRESULT CALLBACK EditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {  switch (uMsg)  {   case WM_KEYUP:   {    if (wParam == VK_RETURN)    {     // 処理    }    else if (wParam == VK_ESCAPE)    {     // 処理    }   }  break;  }  return false; } ここでENTERとESC以外は普通に入力したいのですがどのようにすれば実現できるかアドバイスお願いします。 環境は WindowsXP SP3 Visual Studio6.0 です。よろしくお願いします。

  • キィーボードをフックしません、何故ですか???

    パソコンを現在人間が実際に操作中であるか否かを判定しながら進めるアプリを作っています 簡易的にキィーボードを操作していれば操作中と判断します(マウス操作も含めますが話を簡単にするため今はキィーだけとします) グローバルフックでKEY_DOWNをフックする為に以下のDLL(主要部分のみ)を作りました キィーが押されるとMW_KEYDOWN_DLLというメッセージをアプリに送ります EXPORT LRESULT CALLBACK HookProc( int nCode, WPARAM wParam, LPARAM lParam) { if(nCode == HC_ACTION) { CWPSTRUCT *pcwp = (CWPSTRUCT *)lParam; if(pcwp->message == WM_KEYDOWN) { SendMessage(g_hWnd, WM_KEYDOWN_DLL, pcwp->wParam, pcwp->lParam); ←(1) } } return (CallNextHookEx(g_hHook, nCode, wParam, lParam)); } MW_KEYDOWN_DLLメッセージを受けたアプリは操作中フラグを立てます(主要部分のみ) LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_KEYDOWN_DLL: ここで操作中フラグを立てます ←(2)  このフラグは一定時間後にタイマーが倒します break; default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } return (0L); } 実行してみると(1)に来ません、当然(2)のフラグは立ちません WM_KEYDOWNの代わりにWM_CREATE、WM_CLOSEだときちんとフックします WM_CHAR、MW_KEYUPなどのキィーボード系のメッセージだとフックしません なぜでしょうか??? 多分きわめて初歩的な知識の欠如によるものでしょうが分かりません 宜しくご指導願います

  • C++ WIN32 ウィドウの表示

    プログラミング初心者です。 WIN32APIの勉強を始めたばかりの状態です。 本を見ながら、ウィンドウを表示させるだけのプログラムを書いてみたのですが、エラーになってしまいます。 #include <windows.h> //ウィンドウ・クラス名 #define MYWNDCLSNAME "MyWindowClass" LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) { WNDCLASS wndcls; HWND hWnd; MSG msg; //ウィンドウ・クラスを登録 ZeroMemory(&wndcls, sizeof(wndcls)); wndcls.lpfnWndProc = WndProc; wndcls.hInstance = hInst; wndcls.hIcon = LoadIcon(0, IDI_APPLICATION); wndcls.hCursor = LoadCursor(0, IDC_ARROW); wndcls.hbrBackground = (HBRUSH)COLOR_BACKGROUND; wndcls.lpszClassName = MYWNDCLSNAME; if(RegisterClass(&wndcls) == 0) return -1; //メイン・ウィンドウを作成 hWnd = CreateWindow(MYWNDCLSNAME, "My Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInst, NULL); if(hWnd == 0) return -2; //ウィンドウの表示状態を指定する ShowWindow(hWnd,nCmdShow); UpdateWindow(hWnd); //メッセージループ while(GetMessage(&msg, 0, 0, 0)){ DispatchMessage(&msg); } //WM_QUITメッセージのwParamを終了コードにする return msg.wParam; } LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg){ case WM_DESTROY: PostQuitMessage(0); return 0; } //自分で処理しないメッセージはWindowsに任せる return DefWindowProc(hWnd, uMsg, wParam, lParam); } 本を読み直しても原因がよくわかりません。 どこがいけないのかご指摘いただけるとうれしいです。お願いします。 エラーの内容は error C2440: '=' : 'const char [14]' から 'LPCWSTR' に変換できません。 error C2664: 'CreateWindowExW' : 2 番目の引数を 'const char [14]' から 'LPCWSTR' に変換できません。 です。

  • GetModuleFileNameでエラーが出てしまう。

    #include<windows.h> #include<string.h> // 関数のプロトタイプ宣言 VOID CALLBACK TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime); BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam); // エントリポイント int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; EnumWindows((WNDENUMPROC)EnumWindowsProc,NULL); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam) { char Caption[201]; char FileName[1024]=""; char FindList[1][80]={"Microsoft Internet Explorer"}; GetWindowText(hwnd, Caption, 200); for(int i=0;i<=0;i++) if(NULL!=strstr(Caption,FindList[i])) { HINSTANCE hInst; hInst = (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE); if(GetModuleFileName(hInst, FileName, 1023)!=0) { // ファイル名取得成功したときの動作 MessageBox(NULL,Caption,FileName,MB_OK|MB_SETFOREGROUND); }else{ MessageBox(NULL,Caption,"Error",MB_OK|MB_SETFOREGROUND); } } return true; } 実行するとIEが起動されてたらそのウインドウのキャプションとプログラム名を表示される予定なのですが、 GetModuleFileNameでエラーが返されます。 何が原因なのでしょう?

  • MFCのタイマーのつかい方を教えてください

    タイマーのつかい方が今ひとつ分かりません。 MFCでタイピングのゲームを作成しているのですが、 25問を解き、正解だった場合もしくは制限時間を超えてしまった場合、次の問題を表示したいと思っております。 下記がプログラム内容です。 void CProgramView::Loop1(CDC* pDC) { CProgramDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if((m_nRight<26)|(0<m_nRight)) { m_nRight=0; //正解数 m_nQuestion=1; //問題数 } Haikei(pDC); //問題表示領域の枠表示 Tokei(pDC); //時計の秒針が表示される枠表示 Moji(pDC); //問題文表示 OnChar(ch, count,flags); //入力 if(m_fTimer==FALSE) { SetTimer(123,250,NULL); //タイマーをセット if(m_nQuestion<26) //25問以上問題を解いていないケース { m_fTimer = FALSE; } else m_fTimer = TRUE; //全問解いた場合 } Loop0(pDC); //秒針の描画クラス if(m_nx==715) //タイムアウトだった場合 { KillTimer(123); NGPaper(pDC); m_nQuestion++; //問題をカウント m_sAnser.Empty(); //回答文字列をクリア pDoc->GetNextSet(); //次の問題を取得する InvalidateRect(NULL); } if(m_nQuestion<m_nCount) //正解だった場合 { KillTimer(123); //タイマーを切る Tokei(pDC); //秒針の画像を消すために時計の画面を再描画 Right(pDC); //正解した場合の画像を描画 Haikei(pDC); //問題文・回答を消すために問題表示領域の枠を再描画 PartsPaper1(pDC); //正解した場合の壁紙を表示 m_nQuestion++; //問題数をカウント m_sAnser.Empty(); //回答文字列をクリアする pDoc->GetNextSet(); //次の問題を取得する InvalidateRect(NULL); } } そして、この動作を25問、解くまでループさせる関数として以下の関数を作成しました。 void CProgramView::Loop2(CDC* pDC) { if(m_fTimer==FALSE) { Loop1(pDC); } } //タイマーの内容 void CProgramView::OnTimer(UINT nIDEvent) { // TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフォルトの処理を呼び出してください if(nIDEvent == 123) { InvalidateRect(NULL); } CView::OnTimer(nIDEvent); } しかし、実際にこのプログラムを実行すると入力し、正解する間は次の問題が表示されるのですが、タイマーが切れません。 そして、制限時間になるとそこまで解いていた問題から凄い勢いで描画が始まり、止まりません。 おそらくタイマーが正常に使えていないという可能性が考えられるのですが・・・。 希望としては、25問を順次解き、解き終わった後は画像を描画し、次の問題を表示したいのですが、どうしたら良いか教えてください。

  • ソースを見てください。お願いします

    始めまして、Missing0001と申します。 ウィンドウズプログラムをしていて、 他のところは正常に動いているのにMoveWindow関数の場所だけ思うように動きません。 どなたかソースの間違っているところを指摘していただけないでしょうか? したいことはButtonのマウスでの移動です。 BtProc・・・サブクラス(Button)のプロシージャ DrawRect・・・Buttonのサイズの四角形を描いたり消したりするもの LRESULT CALLBACK BtProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { static BOOL Btn_Flag = false; static POINTS end,old_end; char Str[512]; switch(uMsg) { case WM_LBUTTONDOWN: Btn_Flag = true; old_end = MAKEPOINTS(lParam); DrawRect(hWnd,old_end); break; case WM_MOUSEMOVE: if(Btn_Flag) { end = MAKEPOINTS(lParam); DrawRect(hWnd,old_end); DrawRect(hWnd,end); old_end = end; } else { return CallWindowProc(fnBtProc,hWnd,uMsg,wParam,lParam); } break; case WM_LBUTTONUP: if(Btn_Flag) { DrawRect(hWnd,end); MoveWindow(hWnd,end.x,end.y,50,30,true); ←ここがうまくいかない Btn_Flag = false; } else { return CallWindowProc(fnBtProc,hWnd,uMsg,wParam,lParam); } } return CallWindowProc(fnBtProc,hWnd,uMsg,wParam,lParam); }

  • DrawTextでの描画

    お世話になります。 現在開発中のアプリケーションにて行き詰ってしまった箇所が あったためご質問させていただきました。 Visual Studio2005にてダイアログベースのアプリケーションを作成しており、オリジナルのCStatic派生のクラスCSampleStaticクラスを作成します。 このCSampleStaticクラスはメインダイアログでのサブクラスにした際に PreSubclassWindow() ないでタイマーイベントを発生させます。タイマーイベントの内容は1秒ごとにタイマーを呼び、ランダムの値をそのCStaticの値に代入し、ダイアログ上に表示させる動作をします。 その際の処理のプログラムは以下のように作成しています CString str;//メンバー変数 //メインダイアログにてサブクラス化した際に呼ばれる CSampleStatic::PreSubclassWindow() { SetTimer(1,1000,NULL);//1秒毎に } CSampleStatic::OnTimer(UINT_PTR nIDEvent) { str.Format(_T("%d"),rand()%200); //1~199の乱数をstrに代入  Invalidate();           //OnPaint()を呼ぶ  CStatic::OnTimer(nIDEvent); } CSampleStatic::OnPaint() { CPaintDC dc(this); CFont MyFont; MyFont.CreateFont(-----); //フォント設定 CDC* myDC = GetDC(); CRect Myrect; GetClientRect(&Myrect); myDC->SelectObject(&Myrect); myDC->DrawText(str,-1,&Myrect,DT_CENTER); //strを表示 ReleaseDC(myDC); MyFont.DeleteObject(); } というプログラムを作成しているのですが、この方法でのダイアログへの文字の表示では、たとえば90が表示され、次に100が表示されるのであればいいのですが、100のあとに90が表示された時に100の上にそのまま90が表示されてしまい、うまく表示できません。 再描画のときに、上書きではなく、前回の数値を消去してから新たな数値を表示できればいいとは思うのですが、やり方がわからず、ご意見をいただければと思い質問させていただきました。 どうか宜しくお願いいたします。 開発環境は Windows CE 6.0 Visual Studio 2005 です。

専門家に質問してみよう