timeSetEventとtimeKillEventの使用について

このQ&Aのポイント
  • timeSetEvent関数を調査していた際、timeKillEvent関数の使用について疑問が生じました。
  • timeSetEvent関数の戻り値を保存し、必要な時にtimeKillEvent関数を使用するサンプルは見つかったが、これを内部で使用しても問題はないのか疑問です。
  • 実験した限りでは問題はなく、正常に動作しているように見えますが、内部的に問題が発生する可能性があるか心配です。
回答を見る
  • ベストアンサー

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などの関数を付加して実験してみた結果だけだと、問題なく動いているように見えるのですが、実はすぐには分からないような問題が内部的に発生してる可能性はありますか?)

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

  • ベストアンサー
  • rinkun
  • ベストアンサー率44% (706/1571)
回答No.1

多分大丈夫でしょう。 timeSetEventのコールバックについての情報ではありませんが、同じマルチメディア系のMidiOutProcコールバック関数について > アプリケーションでは、EnterCriticalSection、LeaveCriticalSection、 > midiOutLongMsg、midiOutShortMsg, OutputDebugString、PostMessage、 > PostThreadMessage、SetEvent、timeGetSystemTime、timeGetTime、 > timeKillEvent および timeSetEvent を除き、コールバック関数内から > システム定義関数を呼び出さないようにします。ほかのウェーブ関数を > 呼び出すと、デッドロックの原因となります。 という解説があります。(MSDN) 逆にいうと記載のtimeKillEvent等は大丈夫ということでしょう。 ただしtimeKillEventを実行したら二度とこのコールバック関数が呼ばれないということは保証できないようです。既にイベントがキューイングされている可能性があるのでそれについては対処しましょう。

LongSecret
質問者

お礼

お、ほんとだ MidiOutProcの解説にそういう文章がありますね♪ ありがとうございます! 別の実験で 上記のように使い捨て的な判定するのではなくしておいて 別個に配列にIDを確保しておくようにして、timeSetEventをたくさん連続で呼んだり timeSetEvent→timeKillEvent→timeSetEvent→timeKillEvent といったことも試してみて問題はないようなので (ただ、連続で呼ぶほうはなぜか同じコールバック関数に対して一定の回数以上はできない・・・?というような現象が出ましたが、そんなに何回も呼ぶような設計はそもそもCPUへの影響とかタイミングのとりやすさも含めてあまりやらないで済むほうがいいと思うので) おそらく、むしろ単発で好きな時に走らせて、用がすんだらすぐに止めるようにしつつ、何度でも呼べることを前提にした設計の方が汎用性があっていいかもしれませんね。 (てかそういうことならスレッドのほうが意味的にあってるかもしれませんw) 作戦はいろいろ考えられますが、いずれにせよありがとうございます。

関連するQ&A

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

    お世話になります、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 です。宜しくお願い致します。

  • FPSについて

    一つ質問なのですが、FPSの計測したいのですが、以下のソースでやるとFPSが57になってしまうのですが。 どうしたらFPSを60にすることが出来るのでしょうか? 多分ここら辺だろうなというところを載せます。 void FPSCount(void){ static DWORD before_time = timeGetTime(); // 以前の時間 DWORD now_time = timeGetTime(); // 現在の時間 static DWORD fps_ctr = 0; TCHAR buff[80]; // 文字列表示用バッファ if(now_time - before_time >= 1000){ // 初期化 before_time = now_time; *fps = fps_ctr;     wsprintf(buff,_T("%d\n"),fps_ctr);     OutputDebugString(buff);     fps_ctr = 0; } fps_ctr++; } // エントリポイント int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )      ・      ・      ・ // メッセージループ while(true) { if (PeekMessage(&msg, NULL, 0,0,PM_REMOVE)) { if (msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); } else { // 同期処理 if (timeGetTime() - dwStart >= 1000.0/FPS) { FPSCount(); // 時間更新 dwStart = timeGetTime(); fps=0; // 描画処理 Draw(); } } Sleep(1); } timeEndPeriod(1); // 終了処理 Cleanup(); // 戻り値を返します。 return (int)msg.wParam; } } です。 環境はVC+2005です。

  • [C#] DeviceIoControlの変数の型

    Visual C# 2008でDeviceIoControlを利用して USBを操作しようとしているのですが、 DLLImportの時に指定する変数の型がわからないのです。 BOOL DeviceIoControl( HANDLE hDevice, // デバイス、ファイル、ディレクトリいずれかのハンドル DWORD dwIoControlCode, // 実行する動作の制御コード LPVOID lpInBuffer, // 入力データを供給するバッファへのポインタ DWORD nInBufferSize, // 入力バッファのバイト単位のサイズ LPVOID lpOutBuffer, // 出力データを受け取るバッファへのポインタ DWORD nOutBufferSize, // 出力バッファのバイト単位のサイズ LPDWORD lpBytesReturned, // バイト数を受け取る変数へのポインタ LPOVERLAPPED lpOverlapped // 非同期動作を表す構造体へのポインタ ); と、MSDNに載っていて [DllImport("kernel32", SetLastError = true)] private static extern bool DeviceIoControl( IntPtr hDevice, // デバイス、ファイル、ディレクトリいずれかのハンドル uint dwIoControlCode, // 実行する動作の制御コード ref byte[] lpInBuffer, uint nInBufferSize, // 入力バッファのバイト単位のサイズ ref byte[] lpOutBuffer, uint nOutBufferSize, // 出力バッファのバイト単位のサイズ ref int lpBytesReturned, // バイト数を受け取る変数へのポインタ int Overlapped // overlapped buffer ); と、して Bool ret = DeviceIoControl(hDevice,123456,null,0,null,0,0); と、しても戻り値がfalseにしかなりません。 具体的には byte配列で{ 0x01, 0x23, 0x45, 0x67, 0,89}のような値を入力データにして byte bytes = new byte[10]; で、確保したbytesに出力データを受け取りたいのです。 どのようにすればよいでしょうか?

  • ビットマップ表示とSetTimer関数を同居させる方法

    ビットマップ表示とSetTimer関数を同居させる方法 現在、vc++2005を使用して、簡易的なGUIアプリケーションを作成しようとしているのですが、自分では解決ができない問題が発生してしまったので、質問させていただきます。 それはビットマップ表示とSetTimer関数を同居させる方法についてです。 ビットマップを読み込んで表示させる機能を追加してから、SetTimer関数が反応しなくなってしまい困っています。 ちなみにビットマップ表示の機能を追加する前まではSetTimer関数が正常に機能していました。 ウィンドウのハンドルhWndが何か関係しているのかと思ったのですが、解決方法がわからず・・・・・・ ご存知の方がいらっしゃましたら御教授いただけると幸いです。 ↓ ソースの一部です case WM_CREATE: //ビットマップファイル読み込み + 表示の準備 static HBITMAP hbitmap,prebitmap; static HDC hDC, hcomDC;      hbitmap = (HBITMAP)LoadImage(NULL,_T("kouen.bmp"),IMAGE_BITMAP,0,0, LR_LOADFROMFILE); if( hbitmap == NULL ) { MessageBox(hWnd, _T("ビットマップのロードに失敗しました"), _T("エラー"),MB_OK | MB_ICONWARNING); return 0; } hDC =GetDC(hWnd); hcomDC =CreateCompatibleDC(hDC); prebitmap= (HBITMAP)SelectObject(hcomDC,hbitmap);            (中略) break;                     case WM_LBUTTONDOWN: //2連続のシングルクリック防止 EnableWindow(hWnd,FALSE); SetTimer(hWnd, ID_TIMER1, 500, NULL); ← これが機能していない          (中略) break; case WM_PAINT: BitBlt( hDC, 0, 0, 1024, 690, hcomDC, 0, 0, SRCCOPY ); break; case WM_TIMER://機能しなくなってしまった部分 if(wParam==ID_TIMER1){ KillTimer(hWnd,ID_TIMER1); EnableWindow(hWnd,TRUE); }

  • ボタンのアイコン表示

    開発環境:Vista Visual Studio2012 C言語 CreateWindowで作成したボタンを、アイコン表示にしたいのですけれど上手くいきません。 どこが悪いのでしょうか? HWND CreatePushButton(HWND hwnd, int x, int y, int w, int h, LPCTSTR caption, int id) {     return CreateWindow(         _T("BUTTON"),         caption,         WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_ICON ;         x, y,         w, h,         hwnd,         (HMENU)(INT_PTR)id,         G_hInst,         NULL         ); } LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {    static HWND     hButton;    static HICON     m_hIcon;    switch (uMsg) {      case WM_CREATE: //ウィンドウが作られたとき         hButtonREC = CreatePushButton( hwnd,                               20, 20,                               80, 40,                                _T("テスト"),                               ID_BUTTON  );         m_hIcon = LoadIcon( NULL , IDI_ERROR );         SendDlgItemMessage( hButtonREC,                       ID_BUTTON_RCE,                       BM_SETIMAGE,                       IMAGE_ICON,                       (LPARAM)m_hIcon); }

  • Cのソースファイルにすると警告が出る理由

    wavファイルを再生するプログラムを勉強中なのですが、下のプログラムをビルドすると error C2055: 型リストではなく、仮パラメーター リストが必要です。 warning C4047: '関数' : 間接参照のレベルが 'MCIDEVICEID' と 'void *' で異なっています。 warning C4024: 'mciSendCommandW' : の型が 1 の仮引数および実引数と異なります。 という警告が出ます。 いろいろ試した結果、ソースファイルの拡張子をcからcppに変更したら警告が消えたのですがどうして拡張子がCのソースファイルでビルドすると警告がでるのか理由が全く分かりません。 拡張子を変更しないで警告を出さないようにするにはどこを直せばいいのでしょうか? --- 実行環境 --- Microsoft Visual C++ 2010 Express WIN32 ユニコードビルド C言語 #include<Windows.h> #include "resource.h" #include<MMSystem.h> #pragma comment(lib,"winmm.lib") HINSTANCE hinst; INT_PTR CALLBACK dlgproc(HWND,UINT,WPARAM,LPARAM); int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE,LPSTR,int nCmdShow) { hinst=hInstance; DialogBox(hinst,TEXT("mydlg"),NULL,dlgproc); return 0; } INT_PTR CALLBACK dlgproc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp) { static MCI_OPEN_PARMS mop; static MCI_PLAY_PARMS play; switch(msg) { case WM_INITDIALOG: mop.lpstrDeviceType=TEXT("WaveAudio"); mop.lpstrElementName=TEXT("C:\\Users\\test.wav"); mciSendCommand(NULL,MCI_OPEN,MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,(DWORD_PTR)&mop); mciSendCommand(mop.wDeviceID,MCI_PLAY,NULL,(DWORD_PTR)&play); return (INT_PTR)TRUE; case WM_CLOSE: EndDialog(hwnd,LOWORD(wp)); return (INT_PTR)TRUE; break; } return(INT_PTR)FALSE; }

  • 「外部シンボルが未解決」について教えてください

    BCCを使ってます。windowsのプログラムで、『外部シンボル 'MyCreateFontが未解決』と言うメッセージが出たのですが、リンクエラーなのでしょうか? また、『外部シンボル○○が未解決』と表示された場合、どのような処置をすればいいですか。アドバイスをお願いします。 D:\borland\bcc55\lesson>bcc32 -W -w-8057 timer.cpp Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland timer.cpp: Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland Error: 外部シンボル 'MyCreateFont(int, unsigned long, const char *)' が未解決(D:\BORLAND\BCC55\LESSON\TIMER.OBJ が参照 ) こちらが、宣言の部分です。 #include <windows.h> #define ID_MYTIMER 100 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); HFONT MyCreateFont(int, DWORD, LPCTSTR); char szClassName[] = "clock"; //ウィンドウクラス int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow)

  • WM_CLOSEで閉じれないウィンドウを閉じるには?

    以下にソースを張ります。 #include <stdio.h> #include <windows.h> BOOL CALLBACK EnumWindowProc(HWND hwnd, LPARAM lp) { static bool is_first = true; DWORD style = ::GetWindowLong(hwnd, GWL_STYLE); DWORD dwPID; if ( ::IsWindow(hwnd) && ::IsWindowVisible(hwnd) && (style&WS_CAPTION) && !(style&WS_POPUP) ) { char buf[65536]; ::GetWindowText(hwnd, buf, 65535); GetWindowThreadProcessId( hwnd, &dwPID ); if ( buf[0] != '\0' ) { if ( is_first ) is_first = false; else //printf("%c\n", 1); printf("%s%d\n", buf,hwnd); } } return TRUE; } int main (void){ ::EnumWindows(EnumWindowProc, 0); HWND hWnd; printf("プロセスIDを入力:\n"); scanf("%d",&hWnd); if( hWnd != NULL ){ printf( "終了します。-- pause --\n" ); getchar(); PostMessage( hWnd, WM_CLOSE, 0, 0 ); }else{ printf( "起動してないウインドウズです。\n" ); } return 0; } これですとたとえばメモ帳を編集していたときに WM_CLOSE メッセージを送ったときに「変更を保存しますか?」のようなダイアログが出る アプリがあります。これをダイアログが出ずに強制終了するには どうしたらよいでしょか?よろしくお願いします。

  • コールバック関数が動きません。【音処理】

    当方、音に関するプログラミングをしています。 その中で、解決できない問題が発生しましたので、ご助言・ご協力頂ければ、と思い質問させていただきます。 尚、ソフトは、Microsoft Visual C++ 2010 Express を使用しております。 言語は、C/C++です。 作成したのは、音を再生する、というだけのプログラムです。 初めに、Win32プロジェクトを使い、一部、次のようにプログラムを作成しました。 ~~~~~~ HWND hWnd=CreateWindow(~) ~~仮の適当なウインドウを作成する~~ ~~~~~ MMRESULT ret = waveOutOpen( ~~音をオープンする処理~~ &m_hWaveOut, uDevID, &m_wfxWaveForm, (DWORD)hWnd, 0, CALLBACK_WINDOW); } ~~~~~ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { ~~ 再生に関する処理 ~~ } 音データは大きいので、分割して再生し、一つの分割データが再生し終わると、WndProcが呼ばれて 次の再生データを入れ… というような処理です。 大事なのは、コールバック関数を使っているところです。 このプログラムは無事動きました。 しかし、ここから問題が起きました。 ちゃんとしたGUIを実装する為にWindowsフォームアプリケーション、にてプログラムを作成し直した場合、 なぜかコールバック関数の部分だけが動かなくなってしまうのです。 他の部分は問題なく、動きます。 ウインドウから送られてくるメッセージが「Windowsフォームアプリケーション」の場合だけ 違ったりするのでしょうか? 何かわかる方いらっしゃいましたら、ご助言・ご協力お願いいたします。

  • コールバック関数 再び

    またまた、お世話になります。前回、御回答頂き動作するようにはなったのですが、コールバックに入力があった時に、アプリケーションが終了してしまう現象がおきています。御教授お願いします。 C++で作られたDLLを利用。 装置との通信を行なう物で初期設定用と通信開始用の 関数があり、コールバック関数で、装置からの送信もある。このDLLを使った、他のアプリで動作確認は取れているのでDLL自体には問題ないと思われる。 関数説明 【初期設定用】  initial(DWORD ip,LPNOTIFICATIONFUNC notificationFunc); ip=相手先のipアドレス notificationFunc=コールバック関数へのポインタ コールバック関数 WINAPI *PNOTIFICATIONFUNC(  DWORD id,  BYTE bySet1,  BYTE bySet2,  BYTE *data,  DWORD datasize); 以上の説明があり、現在下記のように宣言して使っています。 【初期設定用】 Declare Function MT_INITIALIZE Lib "TEST.dll" Alias "Initial" _  (ByVal ip As Integer, ByVal notificationFunc As CallBack) As Boolean Public Delegate Sub CallBack( _  ByVal id As Integer, _ ByVal byset1 As Byte, _ ByVal byset2 As Byte, _ ByVal data As IntPtr, _ ByVal dataSize As Integer) 【コールバック関数】 Public Shared Sub notificationFunc( _  ByVal id As Integer, _ ByVal byset1 As Byte, _ ByVal byset2 As Byte, _ ByVal data As IntPtr, _ ByVal dataSize As Integer )   //データのバッファ処理 End Sub