Win32 プログラミング

[このトピックは解決済みです]

フォーラムルール
フォーラムルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Name: 駆け出し
[URL]
上級者(18,248 ポイント)
Date: 2017年1月02日(月) 22:16
No: 1
(OFFLINE)

 Win32 プログラミング

こんばんは。今、自分でWindowsMediaPlayerもどきを作っています。CunstomDrawを使い、すでに再生されたエリアは青く塗るようにしたいのですが、塗られないままで、そのままです。(画像を添付します。)
どこが間違っているかを、ご教示していただけないでしょうか。(音源は、ネット上に公開されている著作権フリーのものを利用しております) MFP【Marron Fields Production】

こちらのソースは最新のものではありません。

CustomDraw部分
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include "strdef.h"
 
LRESULT CustomDrawProc(HWND hWnd, InternalData indata,WPARAM wp, LPARAM lp)
{
    LPNMHDR lpNotify = (LPNMHDR)lp;
    LPNMCUSTOMDRAW lpDraw;
    HBRUSH brush, oldBrush;
    int Pos, max, pos_x;
    RECT rc;
 
    switch (lpNotify->code)
    {
        case NM_CUSTOMDRAW:
        if (lpNotify->hwndFrom == indata.hTrack)
        {
            lpDraw = (LPNMCUSTOMDRAW)lpNotify;
            switch (lpDraw->dwDrawStage)
            {
            case CDDS_PREPAINT:
                return CDRF_NOTIFYITEMDRAW;
            case CDDS_ITEMPREPAINT:
                switch (lpDraw->dwItemSpec)
                {
                case TBCD_CHANNEL:
                    //再生が終わった場所は青く塗る
                    //現在位置の取得
                    Pos = SendMessage(indata.hTrack, TBM_GETPOS, 0, 0);
                    //最大数の取得
                    max = indata.maxSrc;
                    if (!max)
                        max++;
                    //比計算
                    //max : rc.right-rc.left = pos : x
                    pos_x = (lpDraw->rc.right - lpDraw->rc.left)*Pos / max;
                    //とりあえず真っ白に塗り込む
                    FillRect(lpDraw->hdc, &lpDraw->rc, (HBRUSH)GetStockObject(WHITE_BRUSH));
                    //左側
                    rc = lpDraw->rc;
                    rc.right =(LONG)pos_x;
//                  rc.left = 0;
                    brush = CreateSolidBrush(RGB(0, 0, 255));
                    oldBrush = (HBRUSH)SelectObject(lpDraw->hdc, brush);
                    FillRect(lpDraw->hdc, &rc, brush);
                    SelectObject(lpDraw->hdc, oldBrush);
                    DeleteObject(brush);
                    return CDRF_SKIPDEFAULT;
                case TBCD_THUMB:
                    brush = CreateSolidBrush(RGB(255, 255, 255));
                    oldBrush = (HBRUSH)SelectObject(lpDraw->hdc, brush);
                    Ellipse(lpDraw->hdc, lpDraw->rc.left, lpDraw->rc.top, lpDraw->rc.right, lpDraw->rc.bottom);
                    SelectObject(lpDraw->hdc, oldBrush);
                    DeleteObject(brush);
                    return CDRF_SKIPDEFAULT;
                }
                break;
            }
            break;
        }
    }
 
    return FORWARD_WM_NOTIFY(hWnd, wp, lp, DefWindowProc);
}

ウィンドウプロシージャ-
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
    static InternalData indata;
    static MCI_PLAY_PARMS play;
    static MCI_STATUS_PARMS mciStatus;
    static HWND hMCI;
    RECT rc;
 
    switch (msg) {
    case WM_DESTROY:
        mciSendCommandW(indata.open.wDeviceID, MCI_CLOSE, 0, 0);
 
        PostQuitMessage(0);
        return 0;
 
    case WM_CREATE:
        InitCommonControls();
        InitSoundStruct(L"C:\\Games\\Minecraft\\testsound.mp3", L"MPEGVideo", &indata.open);
 
        SetTimer(hwnd, 1, 999, NULL);
        play.dwCallback = (DWORD)hwnd;
        //トラックバー作成
        indata.hTrack = CreateTrackbar(hwnd);
 
        return 0;
    case WM_TIMER:
        if (indata.Status)
        {
            DWORD dwSrc, dwMin, dwSrc_all, dwMin_all;
            WCHAR Temp[512];
            mciStatus.dwItem = MCI_STATUS_POSITION;
            mciSendCommandW(indata.open.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus);
            //秒と分を取得(今は使っていない)
            dwSrc = mciStatus.dwReturn / 1000; //msrc->src
            dwMin = dwSrc / 60;
            dwSrc %= 60;
           
            dwSrc_all = indata.maxSrc % 60;
            dwMin_all = indata.maxSrc / 60;
 
            swprintf_s(Temp, L"%02d:%02d", dwMin, dwSrc);
 
            SendMessageW(indata.hTrack, TBM_SETPOS, TRUE, mciStatus.dwReturn / 1000);
 
            SetWindowTextW(hwnd, Temp);
 
        }
        return 0;
    case WM_LBUTTONDOWN:
        mciSendCommandW(indata.open.wDeviceID, MCI_PLAY, MCI_NOTIFY, (DWORD_PTR)& play);
        //長さを取得
        //とりあえず戻り値は'm'srcにする
        mciStatus.dwItem = MCI_FORMAT_MILLISECONDS;
        mciSendCommandW(indata.open.wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)&mciStatus);
               //局の長さを取得
        mciStatus.dwItem = MCI_STATUS_LENGTH;
        mciSendCommandW(indata.open.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus);
        indata.Status = TRUE;
        indata.maxSrc = mciStatus.dwReturn / 1000;
 
        //トラックバーに関する設定(最後まで再生したときにつまみが一番右側にいるようにする)
        SendMessageW(indata.hTrack, TBM_SETRANGE, TRUE, MAKELPARAM(0, indata.maxSrc));
 
        return 0;
    case WM_SIZE:
        GetClientRect(hwnd, &rc);
        MoveWindow(indata.hTrack, 0, rc.bottom - 25, LOWORD(lp), HIWORD(lp), TRUE);
        return 0;
    case WM_NOTIFY:
        return  CustomDrawProc(hwnd, indata, wp, lp);
    case MM_MCINOTIFY:
        if (lp == indata.open.wDeviceID) {
 
            if (wp == MCI_NOTIFY_SUCCESSFUL) {
                //シークバーを先頭に戻す
                mciSendCommandW(indata.open.wDeviceID, MCI_SEEK, MCI_SEEK_TO_START, 0);
                //再生終了
                indata.Status = FALSE;
            }
            return 0;
        }
        break;
    }
    return DefWindowProcW(hwnd, msg, wp, lp);
}


MP3ファイル読み込み部分
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
int InitSoundStruct(LPCWSTR lpFilePath,LPCWSTR lpstrDeviceType,MCI_OPEN_PARMSW *retTemp)
{
    MCI_OPEN_PARMSW MPEGStruct;
    MCIERROR result;
    TCHAR MsgBuf[1024];
 
    ZeroMemory(&MPEGStruct, sizeof(MCI_OPEN_PARMSW));
 
    MPEGStruct.lpstrDeviceType = lpstrDeviceType;
    MPEGStruct.lpstrElementName = lpFilePath;
 
    result = mciSendCommandW(
        0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,
        (DWORD_PTR)&MPEGStruct
    );
    if (result)
    {
        mciGetErrorStringW(result, MsgBuf, sizeof(MsgBuf));
 
        OutputDebugStringEx(L"%s\n",MsgBuf);
        *retTemp = MPEGStruct;
        return
            create_temp_file(lpFilePath, lpstrDeviceType, retTemp);
    }
 
    *retTemp = MPEGStruct;
 
    return TRUE;
}
 
//synchsafeを10新数に変換
int unsynchsafe(char size[4])
{
    int ToRet = 0;
 
    if ((size[0] & 0x0F) || ((size[0] | size[1] | size[2] | size[3]) & 0x80))
    {
    }
    else {
        int Footer = size[0] & 0x10;
        ToRet = size[0] << 21;
        ToRet += size[1] << 14;
        ToRet += size[2] << 7;
        ToRet += size[3];
        ToRet += 10;
        if (Footer)
            ToRet += 10;
    }
    return ToRet;
}
 
//ID3タグがあるとき、(少なくとも自分の環境では)MCIは読み込んでくれないのでとりあえずtempファイルに書き出し、それを読み込ませる
int create_temp_file(LPCWSTR lpFilePath,LPCWSTR lpstrDeviceType,MCI_OPEN_PARMSW *retTemp)
{
    FILE *fp,*wfp;
    ID3V2HEADER head; //ID3プロファイルがあるかどうか
    DWORD size = 0;
    char mp3head[3] = { 0 }, temp[16] = { 0 };
//  char _size[32];
 
    _wfopen_s(&fp, lpFilePath, L"rb");
 
    if (!fp)
    {
        OutputDebugStringEx(
            L"%s:ファイル\"%s\"\nの読み込みに失敗しました。\n",
            __FUNCSIG__, lpFilePath
        );
 
        return 0;
    }
 
    ZeroMemory(&head, sizeof(head));
    fread(&head, sizeof(head), 1, fp);
 
       //strcmpだと比較できない(\0がないため)
    if (head.tag[0] != 'I' ||
        head.tag[1] != 'D' ||
        head.tag[2] != '3'
    )
    {
        OutputDebugStringW(L"ID3 header not found\n");
        fclose(fp);
 
        return 0;
    }
 
    //
    //
    //syncfaceを普通の10進数に変換
    size = unsynchsafe(head.size);
 
    //headerはとりあえず読み飛ばす
    long file_size;
    char *buffer;
 
    //ファイルサイズを取得する
    //戦闘に移動
    fseek(fp, 0, SEEK_SET);
 
    if (fseek(fp, 0, SEEK_END) != 0) {
        /* エラー処理 */
        goto err;
    }
 
    file_size = ftell(fp);
    if (file_size == -1) {
        /* エラー処理 */
        goto err;
    }
 
    buffer = (char*)malloc(file_size - size);
    if (buffer == NULL) {
        /* エラー処理 */
        goto err;
    }
 
    //mp3の先頭に移動
    fseek(fp, size, SEEK_SET);
   
    //本体読み込み
    fread(buffer, file_size - size, 1, fp);
   
    _wfopen_s(&wfp, TEMP_FILE_NAME, L"wb");
    if (!wfp)
        goto err;
    fwrite(buffer, file_size - size, 1, wfp);
    fclose(fp);
    fclose(wfp);
    free(buffer);
 
    {
        MCI_OPEN_PARMSW MPEGStruct;
        MCIERROR result;
        TCHAR MsgBuf[1024];
 
        ZeroMemory(&MPEGStruct, sizeof(MCI_OPEN_PARMSW));
 
        MPEGStruct.lpstrDeviceType = lpstrDeviceType;
        MPEGStruct.lpstrElementName = TEMP_FILE_NAME;
 
        result = mciSendCommandW(
            0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,
            (DWORD_PTR)&MPEGStruct
        );
        if (result)
        {
            mciGetErrorStringW(result, MsgBuf, sizeof(MsgBuf));
 
            OutputDebugStringEx(L"%s",MsgBuf);
 
 
            *retTemp = MPEGStruct;
 
            goto Err;
        }
 
        *retTemp = MPEGStruct;
 
        return TRUE;
    }
 
 
    return TRUE;
 
err:
    fclose(fp);
 
    return FALSE;
}


strdef.h
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
include <windows.h>
#include <stdio.h>
#include <string.h>
#include <mmsystem.h>
#include <windows.h>
#include <vfw.h>
#include <commctrl.h>
#include <stdio.h>
#include <assert.h>
#include <tchar.h>
#include <shlwapi.h>
#include <windowsx.h>
 
#pragma comment( lib, "shlwapi.lib" )
#pragma comment(lib,"msvfw32.lib")
#pragma comment(lib,"winmm.lib")
#pragma comment(lib, "comctl32.lib")
 
#define TEMP_FILE_NAME                     L"soundfile.mp3"
 
 
typedef struct tagID3V2HEADER
{
    char        tag[3];
    char        version[2];
    char        flags;
    char       size[4]; //syncface
} ID3V2HEADER;
 
typedef struct tagInternalData
{
    //現在再生しているデータに関するもの
    DWORD maxSrc;     //現在再生しているものの、長さ(単位:src)
    MCI_OPEN_PARMS open;
    BOOL  Status;        //現在再生しているかどうか
 
    //トラックバーコントロール
    HWND hTrack;
 
}InternalData;
 
int InitSoundStruct(LPCWSTR lpFilePath, LPCWSTR lpstrDeviceType, MCI_OPEN_PARMSW *retTemp);
//ID3ヘッダに関する処理
int create_temp_file(LPCWSTR lpFilePath, LPCWSTR lpstrDeviceType, MCI_OPEN_PARMSW *retTemp);
 
HWND CreateTrackbar(HWND hWnd);
 
LRESULT CustomDrawProc(HWND hWnd, InternalData indata , WPARAM wp, LPARAM lp);
//OutputDebugStringWの改良版
int OutputDebugStringEx(LPCWSTR lpOutputString, ...);
添付ファイル
スクリーンショット (41).png
スクリーンショット (41).png (298.18 KiB) 表示数: 1299 回
最後に編集したユーザー 駆け出し [ 2017年1月08日(日) 08:57 ], 累計 1 回

Name: Math
[URL]
Date: 2017年1月04日(水) 09:00
No: 2
(OFFLINE)

 Re: Win32 プログラミング

VS2015上で再現してみようと思ったけどこれだけでは出来なさそうなので。”Debug"をされているようですが、switch (lpDraw->dwDrawStage)にブレークポイントを設定して[F11]でステップ実行されたらわかるのではありませんか?

Name: 駆け出し
[URL]
上級者(18,248 ポイント)
Date: 2017年1月05日(木) 01:10
No: 3
(OFFLINE)

 Re: Win32 プログラミング

こんばんは。Debugをして、いくつか試行錯誤してみたのですが、関数:FillRectの戻り値は常に1なのです...
FillRect関数(MSDN)
また、いくつか試行錯誤した結果、余計に自分でもわからなくなってきてしまいました。(CustomDraw.cppの抜粋を見ていただけると助かります)
デタッチ(?)していないので結果が反映されないよ、ということは読んだのですが、c++かつ無償版のVC2015にはついていない機能を使っていたもので...

また、検証用に現在私が書いたソースコードすべて(ヘッダ、リソース含む)を置いておきます(バグあるかもです...)。
ヘッダファイルとソースファイルのパスを分けておいているので、一部修正しないと検証できないかもしれないです。お手数をおかけしますが、よろしくお願いします。

[追記]
いくつかのファイルにバグがあることと、処理を変更したので、新しい書き込みから、そちらに上がっているファイルはコピペしてください。
Zipを置いておきましたので、そちらからDownloadよろしくお願いします。
また、こちらのコードは最新のものではありません。
res.rc
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
#include "H\rc.h"
#include <windows.h>
 
SOUNDPLAYER MENU
{
    POPUP "ファイル(&F)"
    {
        MENUITEM "SoundPlayerの終了(&E)", IDM_EXIT
        MENUITEM SEPARATOR
        MENUITEM "開く(&O)",IDM_OPEN
        MENUITEM "再生(&P)",IDM_PLAY
    }
}


strdef.h
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <mmsystem.h>
#include <windows.h>
#include <vfw.h>
#include <commctrl.h>
#include <stdio.h>
#include <assert.h>
#include <tchar.h>
#include <shlwapi.h>
#include <windowsx.h>
 
 
#pragma comment( lib, "shlwapi.lib" )
#pragma comment(lib,"msvfw32.lib")
#pragma comment(lib,"winmm.lib")
#pragma comment(lib, "comctl32.lib")
 
 
#define TEMP_FILE_NAME                     L"soundfile.mp3"
 
 
typedef struct tagID3V2HEADER
{
    char        tag[3];
    char        version[2];
    char        flags;
    char       size[4]; //syncface
} ID3V2HEADER;
 
typedef struct tagInternalData
{
    //現在再生しているデータに関するもの
    DWORD maxSrc;
    MCI_OPEN_PARMS open;
    MCI_PLAY_PARMS play;
    BOOL  Status;        //現在再生しているかどうか
 
    int NowPlay;         //現在再生してるファイルのアドレス
    int MaxPlay;         //減殺再生しているファイル軍の総数
 
    WCHAR *ParentDir;    //親ディレクトリ
    WCHAR **File;        //これから再生するファイル名
 
    //トラックバーコントロール
    HWND hTrack;
 
}InternalData;
 
//
//MCIを使い、サウンドファイルを読み込む
//lpFilePath...読み込ませたいファイル名
//lpstrDeviceType...そのファイルのタイプ(今のところはmp3のみを考える)
//rettemp...作成された構造体の情報
//callflag...読み込み失敗時に、create_temp_fileを呼び出すかどうか
//
//return TRUE...成功 / FALSE...失敗
//
int InitSoundStruct(LPCWSTR lpFilePath, LPCWSTR lpstrDeviceType, MCI_OPEN_PARMSW *retTemp, int callflag = TRUE);
 
//
//ID3タグがあるとき、それがない状態のmp3を作成する
//lpFilePath...ID3タグがあるかもしれないファイルパス
//lpstrDeviceType...そのファイルのタイプ(今のところはmp3のみを考える)
//rettemp...作成された構造体の情報
//
//return TRUE...成功 / FALSE...失敗
//
int create_temp_file(LPCWSTR lpFilePath, LPCWSTR lpstrDeviceType, MCI_OPEN_PARMSW *retTemp);
 
//
//トラックバーの作成
//hWnd...メインウィンドウのハンドル
//
//return 作成されたトラックバーのハンドル (失敗時はNULL)
//
HWND CreateTrackbar(HWND hWnd);
 
//
//ウィンドウのカスタムドローを一括して行う
//hWnd...メインウィンドウのハンドル
//indata...アプリが一括して管理するデータの構造体
//wp,lp...ウィンドウプロシージャから受け取った値
//
//return 様々な値
//
LRESULT CustomDrawProc(HWND hWnd, InternalData indata, WPARAM wp, LPARAM lp);
 
//
//音声を再生する
//indata...変更されるべきデータを持った構造体
//
//return 常にTRUE
//
int StartPlaySound(InternalData *indata);
 
//
//OutputDebugStringの改造版
//(lpOutputString,...)...出力される文字列
//
//return 成功...TRUE / 失敗...FALSE
//
int OutputDebugStringEx(LPCWSTR lpOutputString, ...);
 
//
//Userに開かれるべきファイルを訪ねる
//hWnd...親ウィンドのハンドル
//temp...情報を受け取ることができる構造体
//
//return TRUE...成功 /FALSE...失敗
//
int GetFileNames(HWND hWnd, InternalData *temp);
 
//
//作成されたファイルパスデータをすべて削除する
//indata...削除されるべきデータを持った構造体
//
//return ... 常にTRUE
//
int DeleteInternalData_indata(InternalData *indata);
 
//
//作成されたMCIデータをすべて削除する
//indata...削除されるべきデータを持った構造体
//
//return ... 常にTRUE
//
int DeleteInternalData_MCI(InternalData *indata);
 
//
//作成されたファイルパス、MCIデータといったデータをすべて削除する
//indata...削除されるべきデータを持った構造体
//
//return ... 常にTRUE
//
int DeleteInternalData(InternalData *indata);


rc.h
コード[C++]: 全て選択
1
2
3
4
5
#define DF_IDC_TRACKBAR                (101211)
 
#define IDM_EXIT                       (1001)
#define IDM_OPEN                       (1002)
#define IDM_PLAY                       (1003)


BaseFunc.cpp
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include "strdef.h"
 
//
//OutputDebugStringの改造版
//(lpOutputString,...)...出力される文字列
//
//return 成功...TRUE / 失敗...FALSE
//
int OutputDebugStringEx(LPCWSTR lpOutputString, ...)
{
    WCHAR *Str;
    va_list val;
    size_t len;
 
    va_start(val, lpOutputString);
 
    __try {
        len = _vscwprintf(lpOutputString, val) + sizeof(WCHAR)/*NULL*/;
    }
    __except (1)
    {
        //OutputDebugStringEx("%s%s");みたいな感じだとここに来る
        va_end(val);
        return 0;
    }
 
    if ((
        Str = (WCHAR*)malloc(len * sizeof(WCHAR))
        ) == NULL)
    {
        va_end(val);
        return 0;
    }
 
    vswprintf_s(Str, len, lpOutputString, val);
 
    OutputDebugStringW(Str);
 
    va_end(val);
    free(Str);
 
    return 1;
}


CustomDraw.cppより
//
//今回質問させていただいている場所
//
//[蛇足]
//現在、トラックバーには現在再生している曲の秒数分のRANGEが作成されています。
//一秒ごとにWM_TIMERを使い、つまみの位置を移動させる処理をしています。
//このとき、ほとんどの場合つまみの位置(x,y)と、実際の座標(xr,yr)が同じではないのです(y=yrは多分成り立ちますが...)
//(それは、トラックバーの横幅と、RANGEの数がたいてい異なるから)
//そこで、現在すでに再生されてた分(1RANGE/秒)進んでいるつまみの位置を座標に変換しなければならないと考えました。
//ex) n秒の長さの曲を読み込み、現在k秒(n>1,0<k<n,n,kは0以上の整数)経過したとき
//|RANGE |1|2|3|4|5|6|....|k |.... |n-1|n |曲の終わり|
//|つまみの位置| ... |ここ |.... |ここまでくる |曲の終わり|
//|実際の座標 | ... |pos_x|.... |lpDraw->right|曲の終わり|
//そこで次の比例式をかんがえました。
//lpDraw->rc.right : indata.maxSrc = pos_x : Pos;
//⇔pos_x = (lpDraw->rc.right * Pos) / indata.maxSrc(=max) (ただしindata.maxSrc≠0だが、すでに0は回避している)
pos_x = (int)((lpDraw->rc.right * Pos) / max);
//ところが。うまくいかないのです...
//また、なぜか次のようにすると、トラックバーをダブルクリックするまでは、つまみがすでに進んだところは青くなります
pos_x = (int)(lpDraw->rc.right * Pos);


CustomDraw.cpp
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include "strdef.h"
 
//
//ウィンドウのカスタムドローを一括して行う
//hWnd...メインウィンドウのハンドル
//indata...アプリが一括して管理するデータの構造体
//wp,lp...ウィンドウプロシージャから受け取った値
//
//return 様々な値
//
LRESULT CustomDrawProc(HWND hWnd, InternalData indata,WPARAM wp, LPARAM lp)
{
    LPNMHDR lpNotify = (LPNMHDR)lp;
    LPNMCUSTOMDRAW lpDraw;
    static HBRUSH bbrush,wbrush, oldBrush;
    int Pos, max, pos_x, ret;
    RECT rc;
 
    //ブラシが作成されていないようなら作成
    if (!wbrush)
    {
        wbrush = CreateSolidBrush(RGB(255, 255, 255));
        bbrush = CreateSolidBrush(RGB(0, 0, 255));
    }
 
    switch (lpNotify->code)
    {
        case NM_CUSTOMDRAW:
        //トラックバーに関する処理だったとき
        if (lpNotify->hwndFrom == indata.hTrack)
        {
            lpDraw = (LPNMCUSTOMDRAW)lpNotify;
            switch (lpDraw->dwDrawStage)
            {
            case CDDS_PREPAINT:
                return CDRF_NOTIFYITEMDRAW;
            case CDDS_ITEMPREPAINT:
                switch (lpDraw->dwItemSpec)
                {
                case TBCD_CHANNEL:
//                  return CDRF_DODEFAULT;
                case TBCD_TICS:
                    //再生が終わった場所は青く塗る
                    //現在位置の取得
                    Pos = SendMessage(indata.hTrack, TBM_GETPOS, 0, 0);
                    //最大数の取得
                    max = indata.maxSrc;
                    if (!max)
                        max++; // /0 を回避
 
                    //とりあえず真っ白に塗り込む
                    oldBrush = (HBRUSH)SelectObject(lpDraw->hdc, wbrush);
                    FillRect(lpDraw->hdc, &lpDraw->rc, wbrush);
                    SelectObject(lpDraw->hdc, oldBrush);
 
                    //左側
 
                    //
                    //今回質問させていただいている場所
                    //
                    //[蛇足]
                    //現在、トラックバーには現在再生している曲の秒数分のRANGEが作成されています。
                    //一秒ごとにWM_TIMERを使い、つまみの位置を移動させる処理をしています。
                    //このとき、ほとんどの場合つまみの位置(x,y)と、実際の座標(xr,yr)が同じではないのです(y=yrは多分成り立ちますが...)
                    //(それは、トラックバーの横幅と、RANGEの数がたいてい異なるから)
                    //そこで、現在すでに再生されてた分(1RANGE/秒)進んでいるつまみの位置を座標に変換しなければならないと考えました。
                    //ex) n秒の長さの曲を読み込み、現在k秒(n>1,0<k<n,n,kは0以上の整数)経過したとき
                    //|RANGE |1|2|3|4|5|6|....|k    |.... |n-1|n        |曲の終わり|
                    //|つまみの位置|   ...    |ここ |.... |ここまでくる |曲の終わり|
                    //|実際の座標  |   ...    |pos_x|.... |lpDraw->right|曲の終わり|
                    //そこで次の比例式をかんがえました。
                    //lpDraw->rc.right : indata.maxSrc = pos_x : Pos;
                    //⇔pos_x = (lpDraw->rc.right * Pos) / indata.maxSrc(=max) (ただしindata.maxSrc≠0だが、すでに0は回避している)
                    pos_x = (int)((lpDraw->rc.right * Pos) / max);
                    //ところが。うまくいかないのです...
                    //また、なぜか次のようにすると、トラックバーをダブルクリックするまでは、つまみがすでに進んだところは青くなります
                    pos_x = (int)(lpDraw->rc.right * Pos);
 
                    rc = lpDraw->rc;
                    rc.right = (LONG)pos_x;
                    rc.left = 0;
                    oldBrush = (HBRUSH)SelectObject(lpDraw->hdc, bbrush);
                    ret = FillRect(lpDraw->hdc, &rc, bbrush);
                    SelectObject(lpDraw->hdc, oldBrush);
 
                    OutputDebugStringEx(L"(%d,%d),", ret, pos_x);
 
                    return CDRF_SKIPDEFAULT;
                case TBCD_THUMB:
                    //つまみを描画(今回は楕円)
                    oldBrush = (HBRUSH)SelectObject(lpDraw->hdc, wbrush);
                    Ellipse(lpDraw->hdc, lpDraw->rc.left, lpDraw->rc.top, lpDraw->rc.right, lpDraw->rc.bottom);
                    SelectObject(lpDraw->hdc, oldBrush);
                    return CDRF_SKIPDEFAULT;
                default:
                    return CDRF_DODEFAULT;
                }
                break;
            }
            break;
        }
    }
 
    //終了
    return DefWindowProcW(hWnd, WM_NOTIFY, wp, lp);
}



Main.cpp
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include "strdef.h"
#include "rc.h"
 
//ウィンドウハンドル
HWND hwnd;
//インスタンスハンドル
HINSTANCE hinst;
 
//ウィンドウ横幅
#define WIDTH 500
#define HEIGHT 300
 
 
 
 
LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
    static InternalData indata;
    static MCI_STATUS_PARMS mciStatus;
    RECT rc;
    WCHAR Temp[MAX_PATH * 2];
 
    switch (msg) {
    case WM_DESTROY:
        mciSendCommandW(indata.open.wDeviceID, MCI_CLOSE, 0, 0);
 
        PostQuitMessage(0);
        return 0;
 
    case WM_CREATE:
        InitCommonControls();
 
        SetTimer(hwnd, 1, 1000, NULL);
        indata.play.dwCallback = (DWORD)hwnd;
        //トラックバー作成
        indata.hTrack = CreateTrackbar(hwnd);
 
        return 0;
    case WM_TIMER:
        if (indata.Status)
        {
            DWORD dwSrc, dwMin, dwSrc_all, dwMin_all;
            WCHAR Temp[512];
            mciStatus.dwItem = MCI_STATUS_POSITION;
            mciSendCommandW(indata.open.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus);
            //秒と分を取得
            dwSrc = mciStatus.dwReturn / 1000; //msrc->src
            dwMin = dwSrc / 60;
            dwSrc %= 60;
           
            dwSrc_all = indata.maxSrc % 60;
            dwMin_all = indata.maxSrc / 60;
 
            swprintf_s(Temp, L"%02d:%02d", dwMin, dwSrc);
 
            SendMessageW(indata.hTrack, TBM_SETPOS, TRUE, mciStatus.dwReturn / 1000);
            UpdateWindow(indata.hTrack);
 
            SetWindowTextW(hwnd, Temp);
 
        }
        return 0;
    case WM_SIZE:
        GetClientRect(hwnd, &rc);
        MoveWindow(indata.hTrack, 0, rc.bottom - 25, LOWORD(lp), HIWORD(lp), TRUE);
        return 0;
    case WM_NOTIFY:
        return  CustomDrawProc(hwnd, indata, wp, lp);
    case MM_MCINOTIFY:
        if (lp == indata.open.wDeviceID)
        {
 
            if (wp == MCI_NOTIFY_SUCCESSFUL)
            {
                //シークバーを先頭に戻す
                //再生するファイルに関する処理
                mciSendCommandW(indata.open.wDeviceID, MCI_SEEK, MCI_SEEK_TO_START, 0);
                if (indata.NowPlay == indata.MaxPlay)
                    indata.NowPlay = 0;
                else
                    indata.NowPlay++;
                //次のファイルの再生
                DeleteInternalData_MCI(&indata);
                swprintf_s(Temp, L"%s\\%s", indata.ParentDir, indata.File[indata.NowPlay]);
                InitSoundStruct(Temp, L"MPEGVideo", &indata.open);
                StartPlaySound(&indata);
            }
            return 0;
        }
        break;
    case WM_COMMAND:
        switch (LOWORD(wp))
        {
        case IDM_EXIT:
            SendMessageW(hwnd, WM_DESTROY, 0, 0);
            break;
        case IDM_PLAY:
//          StartPlaySound(&indata);
            break;
        case IDM_OPEN:
            //もし再生していたら、削除
            DeleteInternalData(&indata);
            if (GetFileNames(hwnd, &indata))
            {
                swprintf_s(Temp, L"%s\\%s", indata.ParentDir, indata.File[0]);
                InitSoundStruct(Temp, L"MPEGVideo", &indata.open);
                StartPlaySound(&indata);
            }
 
            break;
        }
    }
    return DefWindowProcW(hwnd, msg, wp, lp);
}
 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    MSG msg;
    WNDCLASS wc;
 
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WinProc;
    wc.cbClsExtra = wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hCursor = wc.hIcon = NULL;
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wc.lpszClassName = L"MainWindow";
    wc.lpszMenuName = L"SOUNDPLAYER";
 
    if (!RegisterClassW(&wc)) {
        assert(FALSE);
        return -1;
    }
 
 
    //インスタンスハンドル
    hinst = hInstance;
 
    hwnd = CreateWindowW(wc.lpszClassName, L"MainWindow", WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
        0, 0, 400, 400, NULL, NULL, hInstance, NULL);
 
 
    if (hwnd == NULL) {
        assert(FALSE);
        return -1;
    }
 
 
 
    //GetMessageは0か-1のときエラー
    while (GetMessage(&msg, NULL, 0, 0) > 0)
    {  
        DispatchMessage(&msg);
    }
 
    //クラス解放
    UnregisterClass(L"test", hinst);
 
    return msg.wParam;
 
}


SoundAPI.cpp
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
#include "strdef.h"
 
//
//MCIを使い、サウンドファイルを読み込む
//lpFilePath...読み込ませたいファイル名
//lpstrDeviceType...そのファイルのタイプ(今のところはmp3のみを考える)
//rettemp...作成された構造体の情報
//callflag...読み込み失敗時に、create_temp_fileを呼び出すかどうか
//
//return TRUE...成功 / FALSE...失敗
//
int InitSoundStruct(LPCWSTR lpFilePath,LPCWSTR lpstrDeviceType,MCI_OPEN_PARMSW *retTemp,int callflag)
{
    MCIERROR result;
    WCHAR MsgBuf[1024];
    MCI_OPEN_PARMSW MPEGStruct = { 0 };
 
    if (!retTemp)
        return FALSE;
 
    MPEGStruct.lpstrDeviceType = lpstrDeviceType;
    MPEGStruct.lpstrElementName = lpFilePath;
 
    result = mciSendCommandW(
        0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,
        (DWORD_PTR)&MPEGStruct
    );
    if (result)
    {
        //失敗
        mciGetErrorStringW(result, MsgBuf, sizeof(MsgBuf));
 
        OutputDebugStringW(MsgBuf);
        *retTemp = MPEGStruct;
        //callflagで判断
        return callflag == 1 ?
            create_temp_file(lpFilePath, lpstrDeviceType, retTemp) : FALSE;
    }
 
    *retTemp = MPEGStruct;
 
    return TRUE;
}
 
//
//syncheface数(7bit)を普通の8bit数に変換
//size[4]...synchface数
//
//return 普通の8bit数(4byte)
//
int unsynchsafe(char size[4])
{
    int ToRet = 0;
 
    if ((size[0] & 0x0F) || ((size[0] | size[1] | size[2] | size[3]) & 0x80))
    {
    }
    else {
        int Footer = size[0] & 0x10;
        ToRet = size[0] << 21;
        ToRet += size[1] << 14;
        ToRet += size[2] << 7;
        ToRet += size[3];
        ToRet += 10;
        if (Footer)
            ToRet += 10;
    }
    return ToRet;
}
 
//
//ID3タグがあるとき、それがない状態のmp3を作成する
//lpFilePath...ID3タグがあるかもしれないファイルパス
//lpstrDeviceType...そのファイルのタイプ(今のところはmp3のみを考える)
//rettemp...作成された構造体の情報
//
//return TRUE...成功 / FALSE...失敗
//
int create_temp_file(LPCWSTR lpFilePath,LPCWSTR lpstrDeviceType,MCI_OPEN_PARMSW *retTemp)
{
    FILE *fp,*wfp;
    ID3V2HEADER head; //ID3プロファイルがあるかどうか
    DWORD size = 0;
//  char _size[32];
 
    _wfopen_s(&fp, lpFilePath, L"rb");
 
    if (!fp)
    {
        OutputDebugStringEx(
            L"%s:ファイル\"%s\"\nの読み込みに失敗しました。\n",
            __FUNCSIG__, lpFilePath
        );
 
        return 0;
    }
 
    ZeroMemory(&head, sizeof(head));
    fread(&head, sizeof(head), 1, fp);
 
 
    if (head.tag[0] != 'I' ||
        head.tag[1] != 'D' ||
        head.tag[2] != '3'
    )
    {
        OutputDebugStringW(L"ID3 header not found\n");
        goto err;
    }
 
    //
    //ID3を持たないmp3ファイルを書き出す
    //
    //
 
    //syncfaceを普通の8bit数に変換
    size = unsynchsafe(head.size);
 
    //headerはとりあえず読み飛ばす
    long file_size;
    char *buffer;
 
    //ファイルサイズを取得する
    //戦闘に移動
    fseek(fp, 0, SEEK_SET);
 
    if (fseek(fp, 0, SEEK_END) != 0) {
        /* エラー処理 */
        goto err;
    }
 
    file_size = ftell(fp);
    if (file_size == -1) {
        /* エラー処理 */
        goto err;
    }
 
    buffer = (char*)malloc(file_size - size);
    if (buffer == NULL) {
        /* エラー処理 */
        goto err;
    }
 
    //mp3の先頭に移動
    fseek(fp, size, SEEK_SET);
   
    //本体読み込み
    fread(buffer, file_size - size, 1, fp);
   
    _wfopen_s(&wfp, TEMP_FILE_NAME, L"wb");
    if (!wfp)
        goto err;
    fwrite(buffer, file_size - size, 1, wfp);
    fclose(fp);
    fclose(wfp);
    free(buffer);
 
    //再読み込みを試みる
    return InitSoundStruct(
        TEMP_FILE_NAME,
        lpstrDeviceType,
        retTemp,
        FALSE);
 
err:
    fclose(fp);
 
    return 0;
}
 
//
//音声を再生する
//indata...変更されるべきデータを持った構造体
//
//return 常にTRUE
//
int StartPlaySound(InternalData *indata)
{
    MCI_STATUS_PARMS mciStatus;
 
    //再生が終了したときに、通知を受け取る
    mciSendCommandW(indata->open.wDeviceID, MCI_PLAY, MCI_NOTIFY, (DWORD_PTR)&indata->play);
 
    //
    //曲の長さを取得
    //
 
    //とりあえず戻り値は'm'srcにする
    mciStatus.dwItem = MCI_FORMAT_MILLISECONDS;
    mciSendCommandW(indata->open.wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)&mciStatus);
 
    mciStatus.dwItem = MCI_STATUS_LENGTH;
    mciSendCommandW(indata->open.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus);
    indata->Status = TRUE;
    indata->maxSrc = mciStatus.dwReturn / 1000;
 
    //トラックバーに関する設定
    SendMessageW(indata->hTrack, TBM_SETRANGE, TRUE, MAKELPARAM(0, indata->maxSrc));
 
    return TRUE;
}
 
//
//作成されたファイルパスデータをすべて削除する
//indata...削除されるべきデータを持った構造体
//
//return ... 常にTRUE
//
int DeleteInternalData_indata(InternalData *indata)
{
    int i;
 
    //データがない場合何もしない
    if (!indata->Status)
        return TRUE;
 
    //削除
    for (i = 0; i < indata->MaxPlay; i++)
        free(indata->File[i]);
 
    free(indata->File);
    free(indata->ParentDir);
 
    return TRUE;
}
 
//
//作成されたMCIデータをすべて削除する
//indata...削除されるべきデータを持った構造体
//
//return ... 常にTRUE
//
int DeleteInternalData_MCI(InternalData *indata)
{
    //データがない場合何もしない
    if (!indata->Status)
        return TRUE;
 
    //MCIの終了
    mciSendCommandW(indata->open.wDeviceID, MCI_CLOSE, 0, 0);
 
    return TRUE;
}
 
//
//作成されたファイルパス、MCIデータといったデータをすべて削除する
//indata...削除されるべきデータを持った構造体
//
//return ... 常にTRUE
//
int DeleteInternalData(InternalData *indata)
{
    DeleteInternalData_indata(indata);
    DeleteInternalData_MCI(indata);
 
    return TRUE;
}


UserInerface.cpp
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include "strdef.h"
#include "rc.h"
 
//
//トラックバーの作成
//hWnd...メインウィンドウのハンドル
//
//return 作成されたトラックバーのハンドル (失敗時はNULL)
//
HWND CreateTrackbar(HWND hWnd)
{
    long  lMin = 0;
    long  lMax = 20;
    long  lFirstPosition = 0;
    long  lPageSize = 5;
    HWND hTrackbar;
 
    /* コモンコントロールの初期化 */
    InitCommonControls();
 
    /* トラックバーコントロールの作成 */
    hTrackbar = CreateWindowEx(
        0, TRACKBAR_CLASS, NULL,
        WS_CHILD | WS_VISIBLE |
        TBS_NOTICKS | TBS_TOOLTIPS,
        0, 0, 200, 30,
        hWnd, (HMENU)DF_IDC_TRACKBAR, (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE), NULL);
 
    if (!hTrackbar)
        return NULL;
 
    /* 範囲のセット */
    SendMessageW(hTrackbar, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(lMin, lMax));
 
    /* 1ページのサイズのセット */
    SendMessageW(hTrackbar, TBM_SETPAGESIZE, 0, (LPARAM)lPageSize);
 
    /* 初期値のセット */
    SendMessageW(hTrackbar, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)lFirstPosition);
 
    /* フォーカスのセット */
//  SetFocus(hTrackbar);
 
 
    return hTrackbar;
}
 
//
//Userに開かれるべきファイルを訪ねる
//hWnd...親ウィンドのハンドル
//temp...情報を受け取ることができる構造体
//
//return TRUE...成功 /FALSE...失敗
//
int GetFileNames(HWND hWnd, InternalData *temp)
{
    const long MAXFILELENGTH = MAX_PATH * 5;
 
    OPENFILENAMEW ofn;
    WCHAR fileName[MAXFILELENGTH] = { 0 };
    int iCnt = 0, nPos;
    size_t Dirlen;
 
    ZeroMemory(&ofn, sizeof(ofn));
    ofn.lStructSize = sizeof(ofn);
    ofn.Flags = OFN_ALLOWMULTISELECT | OFN_EXPLORER | OFN_HIDEREADONLY;
    ofn.lpstrFile = fileName;
    ofn.nMaxFile = sizeof(fileName);
    ofn.lpstrFilter = L"全てのファイル(*.*)\0*.*\0";
    ofn.lpstrDefExt = L"*.*";
    ofn.nFilterIndex = 1;
 
    if (GetOpenFileNameW(&ofn))
    {
        nPos = lstrlen(fileName) + 1;
 
        //とりあえずディレクトリを割り出す
        Dirlen = wcslen(fileName) + 1;
        if ((temp->ParentDir = (WCHAR*)malloc(Dirlen * sizeof(WCHAR))) == NULL)
            return FALSE;
        //残りメモリも確保しておく(多くても損はしない)
        if ((temp->File = (WCHAR**)malloc(MAXFILELENGTH * sizeof(WCHAR))) == NULL)
        {
            free(temp->ParentDir);
            return FALSE;
        }
 
        ZeroMemory(temp->File, MAXFILELENGTH * sizeof(WCHAR));
 
        //データをコピー
        //(strcpy_sだとメモリをよこせと言ってくるので)
        memcpy(temp->ParentDir, fileName, Dirlen * sizeof(WCHAR));
 
        if (fileName[nPos])
        {
            // 複数ファイルが選択された
            do {
                // パスをコピー
                if (fileName[nPos]) temp->File[iCnt] = (WCHAR*)malloc((wcslen(&fileName[nPos]) + 1) * sizeof(WCHAR));
                else break;
                if (!temp->File[iCnt])
                {
                    //leak
                    free(temp->File);
                    free(temp->ParentDir);
 
                    return FALSE;
                }
                wcscpy_s(temp->File[iCnt], (wcslen(&fileName[nPos]) + 1), &fileName[nPos]);
                OutputDebugStringEx(L"%s\n", temp->File[iCnt]);
                iCnt++;
                nPos += (wcslen(&fileName[nPos]) + 1);
            } while (fileName[nPos]);
        }
        else {
            temp->File[0] = (WCHAR*)malloc((wcslen(PathFindFileNameW(fileName)) + 1) * sizeof(WCHAR));
            if (!temp->File[0])
            {
                free(temp->File);
                free(temp->ParentDir);
                return FALSE;
            }
            // 1つだけ選択された
            lstrcpy(temp->File[0], fileName);
            iCnt = 1;
        }
    }
    else
        return FALSE;
    //準備
    temp->NowPlay = 0;
    temp->MaxPlay = iCnt;
    return TRUE;
}
最後に編集したユーザー 駆け出し [ 2017年1月08日(日) 08:52 ], 累計 2 回

Name: 駆け出し
[URL]
上級者(18,248 ポイント)
Date: 2017年1月06日(金) 00:07
No: 4
(OFFLINE)

 Re: Win32 プログラミング

こんばんは。連投失礼します。
まず、検証用に置かせていただいたソースコードですが、バグがありました。申し訳ないです。

UserInterface.cppのGetUserFilesの、一つのファイルのみが選択されたときの処理を完全にDebugするのを忘れてました。(複数のほうのみチェックして油断してました。)つきましては、UserInerface.cppは次のようになります。また、新たに関数を追加しています。

こちらのコードは最新のものではありません。

UserInerface.cpp,strdef.h,Main.cpp,CunstomDraw.cpp
UserInterface.cpp
[spoil]
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include "strdef.h"
#include "rc.h"
 
//
//トラックバーの作成
//hWnd...メインウィンドウのハンドル
//
//return 作成されたトラックバーのハンドル (失敗時はNULL)
//
HWND CreateTrackbar(HWND hWnd)
{
    long  lMin = 0;
    long  lMax = 20;
    long  lFirstPosition = 0;
    long  lPageSize = 5;
    HWND hTrackbar;
 
    /* コモンコントロールの初期化 */
    InitCommonControls();
 
    /* トラックバーコントロールの作成 */
    hTrackbar = CreateWindowEx(
        0, TRACKBAR_CLASS, NULL,
        WS_CHILD | WS_VISIBLE |
        TBS_NOTICKS | TBS_TOOLTIPS,
        0, 0, 200, 30,
        hWnd, (HMENU)DF_IDC_TRACKBAR, (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE), NULL);
 
    if (!hTrackbar)
        return NULL;
 
    /* 範囲のセット */
    SendMessageW(hTrackbar, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(lMin, lMax));
 
    /* 1ページのサイズのセット */
    SendMessageW(hTrackbar, TBM_SETPAGESIZE, 0, (LPARAM)lPageSize);
 
    /* 初期値のセット */
    SendMessageW(hTrackbar, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)lFirstPosition);
 
    /* フォーカスのセット */
//  SetFocus(hTrackbar);
 
 
    return hTrackbar;
}
 
//
//トラックバーに関する設定を行う
//indata...設定されるべきトラックバーのハンドル
//
void SetTrackbarStatus(InternalData indata)
{
    /* 範囲のセット */
    SendMessageW(indata.hTrack, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, indata.maxSrc));
 
    /* 1ページのサイズのセット */
    SendMessageW(indata.hTrack, TBM_SETPAGESIZE, 0, (LPARAM)indata.maxSrc);
}
 
 
//
//Userに開かれるべきファイルを訪ねる
//hWnd...親ウィンドのハンドル
//temp...情報を受け取ることができる構造体
//
//return TRUE...成功 /FALSE...失敗
//
int GetFileNames(HWND hWnd, InternalData *temp)
{
    const long MAXFILELENGTH = MAX_PATH * 5;
 
    OPENFILENAMEW ofn;
    WCHAR fileName[MAXFILELENGTH] = { 0 };
    int iCnt = 0, nPos;
    size_t Dirlen;
 
    ZeroMemory(&ofn, sizeof(ofn));
    ofn.lStructSize = sizeof(ofn);
    ofn.Flags = OFN_ALLOWMULTISELECT | OFN_EXPLORER | OFN_HIDEREADONLY;
    ofn.lpstrFile = fileName;
    ofn.nMaxFile = sizeof(fileName);
    ofn.lpstrFilter = L"全てのファイル(*.*)\0*.*\0";
    ofn.lpstrDefExt = L"*.*";
    ofn.nFilterIndex = 1;
 
    if (GetOpenFileNameW(&ofn))
    {
        nPos = lstrlen(fileName) + 1;
 
        //とりあえずディレクトリを割り出す
        Dirlen = wcslen(fileName) + 1;
        if ((temp->ParentDir = (WCHAR*)malloc(Dirlen * sizeof(WCHAR))) == NULL)
            return FALSE;
        //残りメモリも確保しておく(多くても損はしない)
        if ((temp->File = (WCHAR**)malloc(MAXFILELENGTH * sizeof(WCHAR))) == NULL)
        {
            free(temp->ParentDir);
            return FALSE;
        }
 
        ZeroMemory(temp->File, MAXFILELENGTH * sizeof(WCHAR));
 
        //データをコピー
        //(strcpy_sだとメモリをよこせと言ってくるので)
        memcpy(temp->ParentDir, fileName, Dirlen * sizeof(WCHAR));
 
        if (fileName[nPos])
        {
            // 複数ファイルが選択された
            do {
                // パスをコピー
                if (fileName[nPos]) temp->File[iCnt] = (WCHAR*)malloc((wcslen(&fileName[nPos]) + 1) * sizeof(WCHAR));
                else break;
                if (!temp->File[iCnt])
                {
                    //leak
                    free(temp->File);
                    free(temp->ParentDir);
 
                    return FALSE;
                }
                wcscpy_s(temp->File[iCnt], (wcslen(&fileName[nPos]) + 1), &fileName[nPos]);
                OutputDebugStringEx(L"%s\n", temp->File[iCnt]);
                iCnt++;
                nPos += (wcslen(&fileName[nPos]) + 1);
            } while (fileName[nPos]);
        }
        else {
            //親ディレクトリおよびファイルに関するメモリを確保しなおす
            ZeroMemory(temp->ParentDir + (Dirlen - wcslen(PathFindFileNameW(fileName)) -2/*NULL + \\*/), wcslen(PathFindFileNameW(fileName)) * sizeof(WCHAR));
            //親ディレクトリ名だけを確保
            temp->File[0] = (WCHAR*)malloc((wcslen(PathFindFileNameW(fileName) + 1) * sizeof(WCHAR)));
            if (!temp->File[0])
                return FALSE;
            wcscpy_s(temp->File[0], wcslen(PathFindFileNameW(fileName)) + 1, PathFindFileNameW(fileName));
            iCnt = 1;
        }
    }
    else
        return FALSE;
    //準備
    temp->NowPlay = 0;
    temp->MaxPlay = iCnt;
    return TRUE;
}

strdef.h
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <mmsystem.h>
#include <windows.h>
#include <vfw.h>
#include <commctrl.h>
#include <stdio.h>
#include <assert.h>
#include <tchar.h>
#include <shlwapi.h>
#include <windowsx.h>
 
 
#pragma comment( lib, "shlwapi.lib" )
#pragma comment(lib,"msvfw32.lib")
#pragma comment(lib,"winmm.lib")
#pragma comment(lib, "comctl32.lib")
 
 
#define TEMP_FILE_NAME                     L"soundfile.mp3"
 
 
typedef struct tagID3V2HEADER
{
    char        tag[3];
    char        version[2];
    char        flags;
    char       size[4]; //syncface
} ID3V2HEADER;
 
typedef struct tagInternalData
{
    //現在再生しているデータに関するもの
    DWORD maxSrc;
    MCI_OPEN_PARMS open;
    MCI_PLAY_PARMS play;
    BOOL  Status;        //現在再生しているかどうか
 
    int NowPlay;         //現在再生してるファイルのアドレス
    int MaxPlay;         //減殺再生しているファイル軍の総数
 
    WCHAR *ParentDir;    //親ディレクトリ
    WCHAR **File;        //これから再生するファイル名
 
    //トラックバーコントロール
    HWND hTrack;
 
}InternalData;
 
//
//MCIを使い、サウンドファイルを読み込む
//lpFilePath...読み込ませたいファイル名
//lpstrDeviceType...そのファイルのタイプ(今のところはmp3のみを考える)
//rettemp...作成された構造体の情報
//callflag...読み込み失敗時に、create_temp_fileを呼び出すかどうか
//
//return TRUE...成功 / FALSE...失敗
//
int InitSoundStruct(LPCWSTR lpFilePath, LPCWSTR lpstrDeviceType, MCI_OPEN_PARMSW *retTemp, int callflag = TRUE);
 
//
//ID3タグがあるとき、それがない状態のmp3を作成する
//lpFilePath...ID3タグがあるかもしれないファイルパス
//lpstrDeviceType...そのファイルのタイプ(今のところはmp3のみを考える)
//rettemp...作成された構造体の情報
//
//return TRUE...成功 / FALSE...失敗
//
int create_temp_file(LPCWSTR lpFilePath, LPCWSTR lpstrDeviceType, MCI_OPEN_PARMSW *retTemp);
 
//
//トラックバーの作成
//hWnd...メインウィンドウのハンドル
//
//return 作成されたトラックバーのハンドル (失敗時はNULL)
//
HWND CreateTrackbar(HWND hWnd);
 
//
//トラックバーに関する設定を行う
//indata...設定されるべきトラックバーのハンドル
//
void SetTrackbarStatus(InternalData indata);
 
//
//ウィンドウのカスタムドローを一括して行う
//hWnd...メインウィンドウのハンドル
//indata...アプリが一括して管理するデータの構造体
//wp,lp...ウィンドウプロシージャから受け取った値
//
//return 様々な値
//
LRESULT CustomDrawProc(HWND hWnd, InternalData indata, WPARAM wp, LPARAM lp);
 
//
//音声を再生する
//indata...変更されるべきデータを持った構造体
//
//return 常にTRUE
//
int StartPlaySound(InternalData *indata);
 
//
//OutputDebugStringの改造版
//(lpOutputString,...)...出力される文字列
//
//return 成功...TRUE / 失敗...FALSE
//
int OutputDebugStringEx(LPCWSTR lpOutputString, ...);
 
//
//Userに開かれるべきファイルを訪ねる
//hWnd...親ウィンドのハンドル
//temp...情報を受け取ることができる構造体
//
//return TRUE...成功 /FALSE...失敗
//
int GetFileNames(HWND hWnd, InternalData *temp);
 
//
//作成されたファイルパスデータをすべて削除する
//indata...削除されるべきデータを持った構造体
//
//return ... 常にTRUE
//
int DeleteInternalData_indata(InternalData *indata);
 
//
//作成されたMCIデータをすべて削除する
//indata...削除されるべきデータを持った構造体
//
//return ... 常にTRUE
//
int DeleteInternalData_MCI(InternalData *indata);
 
//
//作成されたファイルパス、MCIデータといったデータをすべて削除する
//indata...削除されるべきデータを持った構造体
//
//return ... 常にTRUE
//
int DeleteInternalData(InternalData *indata);


Main.cpp
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include "strdef.h"
#include "rc.h"
 
//ウィンドウハンドル
HWND hwnd;
//インスタンスハンドル
HINSTANCE hinst;
 
//ウィンドウ横幅
#define WIDTH 500
#define HEIGHT 300
 
 
 
 
LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
    static InternalData indata;
    static MCI_STATUS_PARMS mciStatus;
    RECT rc;
    WCHAR Temp[MAX_PATH * 2];
 
    switch (msg) {
    case WM_DESTROY:
        mciSendCommandW(indata.open.wDeviceID, MCI_CLOSE, 0, 0);
 
        PostQuitMessage(0);
        return 0;
 
    case WM_CREATE:
        InitCommonControls();
 
        SetTimer(hwnd, 1, 1000, NULL);
        indata.play.dwCallback = (DWORD)hwnd;
        //トラックバー作成
        indata.hTrack = CreateTrackbar(hwnd);
 
        return 0;
    case WM_TIMER:
        if (indata.Status)
        {
            DWORD dwSrc, dwMin, dwSrc_all, dwMin_all;
            WCHAR Temp[512];
            mciStatus.dwItem = MCI_STATUS_POSITION;
            mciSendCommandW(indata.open.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus);
            //秒と分を取得
            dwSrc = mciStatus.dwReturn / 1000; //msrc->src
            dwMin = dwSrc / 60;
            dwSrc %= 60;
           
            dwSrc_all = indata.maxSrc % 60;
            dwMin_all = indata.maxSrc / 60;
 
            swprintf_s(Temp, L"%02d:%02d", dwMin, dwSrc);
 
            SendMessageW(indata.hTrack, TBM_SETPOS, TRUE, mciStatus.dwReturn / 1000);
           
            SetTrackbarStatus(indata);
 
            SetWindowTextW(hwnd, Temp);
 
        }
        return 0;
    case WM_SIZE:
        GetClientRect(hwnd, &rc);
        MoveWindow(indata.hTrack, 0, rc.bottom - 25, LOWORD(lp), HIWORD(lp), TRUE);
        return 0;
    case WM_NOTIFY:
        return  CustomDrawProc(hwnd, indata, wp, lp);
    case MM_MCINOTIFY:
        if (lp == indata.open.wDeviceID)
        {
 
            if (wp == MCI_NOTIFY_SUCCESSFUL)
            {
                //シークバーを先頭に戻す
                //再生するファイルに関する処理
                mciSendCommandW(indata.open.wDeviceID, MCI_SEEK, MCI_SEEK_TO_START, 0);
                if (indata.NowPlay == indata.MaxPlay)
                    indata.NowPlay = 0;
                else
                    indata.NowPlay++;
                //次のファイルの再生
                DeleteInternalData_MCI(&indata);
                swprintf_s(Temp, L"%s\\%s", indata.ParentDir, indata.File[indata.NowPlay]);
                InitSoundStruct(Temp, L"MPEGVideo", &indata.open);
                StartPlaySound(&indata);
            }
            return 0;
        }
        break;
    case WM_COMMAND:
        switch (LOWORD(wp))
        {
        case IDM_EXIT:
            SendMessageW(hwnd, WM_DESTROY, 0, 0);
            break;
        case IDM_PLAY:
//          StartPlaySound(&indata);
            break;
        case IDM_OPEN:
            //もし再生していたら、削除
            DeleteInternalData(&indata);
            if (GetFileNames(hwnd, &indata))
            {
                swprintf_s(Temp, L"%s\\%s", indata.ParentDir, indata.File[0]);
                InitSoundStruct(Temp, L"MPEGVideo", &indata.open);
                StartPlaySound(&indata);
            }
 
            break;
        }
    }
    return DefWindowProcW(hwnd, msg, wp, lp);
}
 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    MSG msg;
    WNDCLASS wc;
 
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WinProc;
    wc.cbClsExtra = wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hCursor = wc.hIcon = NULL;
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wc.lpszClassName = L"MainWindow";
    wc.lpszMenuName = L"SOUNDPLAYER";
 
    if (!RegisterClassW(&wc)) {
        assert(FALSE);
        return -1;
    }
 
 
    //インスタンスハンドル
    hinst = hInstance;
 
    hwnd = CreateWindowW(wc.lpszClassName, L"MainWindow", WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
        0, 0, 400, 400, NULL, NULL, hInstance, NULL);
 
 
    if (hwnd == NULL) {
        assert(FALSE);
        return -1;
    }
 
 
 
    //GetMessageは0か-1のときエラー
    while (GetMessage(&msg, NULL, 0, 0) > 0)
    {  
        DispatchMessage(&msg);
    }
 
    //クラス解放
    UnregisterClass(L"test", hinst);
 
    return msg.wParam;
 
}

CustomDraw.cpp
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include "strdef.h"
 
//
//ウィンドウのカスタムドローを一括して行う
//hWnd...メインウィンドウのハンドル
//indata...アプリが一括して管理するデータの構造体
//wp,lp...ウィンドウプロシージャから受け取った値
//
//return 様々な値
//
LRESULT CustomDrawProc(HWND hWnd, InternalData indata,WPARAM wp, LPARAM lp)
{
    LPNMHDR lpNotify = (LPNMHDR)lp;
    LPNMCUSTOMDRAW lpDraw;
    static HBRUSH bbrush,wbrush, oldBrush;
    int Pos, max, pos_x, ret;
    RECT rc;
 
    //ブラシが作成されていないようなら作成
    if (!wbrush)
    {
        wbrush = CreateSolidBrush(RGB(255, 255, 255));
        bbrush = CreateSolidBrush(RGB(0, 0, 255));
    }
 
    switch (lpNotify->code)
    {
        case NM_CUSTOMDRAW:
        //トラックバーに関する処理だったとき
        if (lpNotify->hwndFrom == indata.hTrack)
        {
            lpDraw = (LPNMCUSTOMDRAW)lpNotify;
            switch (lpDraw->dwDrawStage)
            {
            case CDDS_PREPAINT:
                return CDRF_NOTIFYITEMDRAW;
            case CDDS_ITEMPREPAINT:
                switch (lpDraw->dwItemSpec)
                {
                case TBCD_CHANNEL:
//                  return CDRF_DODEFAULT;
                case TBCD_TICS:
                    //再生が終わった場所は青く塗る
                    //現在位置の取得
                    Pos = SendMessage(indata.hTrack, TBM_GETPOS, 0, 0);
                    //最大数の取得
                    max = indata.maxSrc;
                    if (!max)
                        max++; // /0 を回避
 
                    //とりあえず真っ白に塗り込む
                    oldBrush = (HBRUSH)SelectObject(lpDraw->hdc, wbrush);
                    FillRect(lpDraw->hdc, &lpDraw->rc, wbrush);
                    SelectObject(lpDraw->hdc, oldBrush);
 
                    //左側
 
                    //
                    //今回質問させていただいている場所
                    //
                    //[蛇足]
                    //現在、トラックバーには現在再生している曲の秒数分のRANGEが作成されています。
                    //一秒ごとにWM_TIMERを使い、つまみの位置を移動させる処理をしています。
                    //このとき、ほとんどの場合つまみの位置(x,y)と、実際の座標(xr,yr)が同じではないのです(y=yrは多分成り立ちますが...)
                    //(それは、トラックバーの横幅と、RANGEの数がたいてい異なるから)
                    //そこで、現在すでに再生されてた分(1RANGE/秒)進んでいるつまみの位置を座標に変換しなければならないと考えました。
                    //ex) n秒
                    //|RANGE |1|2|3|4|5|6|....|k    |.... |n-1|n        |曲の終わり|
                    //|つまみの位置|   ...    |ここ |.... |ここまでくる |曲の終わり|
                    //|実際の座標  |   ...    |pos_x|.... |lpDraw->right|曲の終わり|
                    //そこで次の比例式をかんがえました。
                    //lpDraw->rc.right : indata.maxSrc = pos_x : Pos;
                    //⇔pos_x = (lpDraw->rc.right * Pos) / indata.maxSrc(=max) (ただしindata.maxSrc≠0だが、すでに0は回避している)
                    pos_x = (int)(((lpDraw->rc.right + lpDraw->rc.left) * Pos) / max)+lpDraw->rc.left; //初期位置
 
                    rc = lpDraw->rc;
                    rc.right = (LONG)pos_x;
                    oldBrush = (HBRUSH)SelectObject(lpDraw->hdc, bbrush);
                    ret = FillRect(lpDraw->hdc, &rc, bbrush);
                    SelectObject(lpDraw->hdc, oldBrush);
 
                                 
                    OutputDebugStringEx(
                        L"RECT(x){left,right},ret=(%d){%d,%d},%d\n",
                        rc.right-rc.left,rc.left,rc.right,ret
                    );
 
                    return CDRF_SKIPDEFAULT;
                case TBCD_THUMB:
                    //つまみを描画(今回は楕円)
                    oldBrush = (HBRUSH)SelectObject(lpDraw->hdc, wbrush);
                    Ellipse(lpDraw->hdc, lpDraw->rc.left, lpDraw->rc.top, lpDraw->rc.right, lpDraw->rc.bottom);
                    SelectObject(lpDraw->hdc, oldBrush);
                    return CDRF_SKIPDEFAULT;
                default:
                    return CDRF_DODEFAULT;
                }
                break;
            }
            break;
        }
    }
 
    //終了
    return DefWindowProcW(hWnd, WM_NOTIFY, wp, lp);
}

[/spoil]
次に、青い部分の描画ですがWM_TIMERイベントがあるごとにSetTrackbarStatusを呼び出すことにより、更新部分を反映させることに成功しました。

勝手に一人で掲示板を荒らし、申し訳ありませんでした。
最後に編集したユーザー 駆け出し [ 2017年1月08日(日) 08:59 ], 累計 1 回

Name: Math
[URL]
Date: 2017年1月06日(金) 00:30
No: 5
(OFFLINE)

 Re: Win32 プログラミング

>勝手に一人で掲示板を荒らし、申し訳ありませんでした。
掲示板を書くだけで気合いがはいるしプログラムも整理されるし”荒らし”てるわけではないと思います。
時にはすぐ”自己解決しました。”と風の如く去る人も...
"掲示板の効果”はで絶大ですよ。

Name: Math
[URL]
Date: 2017年1月06日(金) 00:40
No: 6
(OFFLINE)

 Re: Win32 プログラミング

>関数:FillRectの戻り値は常に1なのです...
1はもしかしてTRUEでは...

Name: Math
[URL]
Date: 2017年1月06日(金) 08:41
No: 7
(OFFLINE)

 Re: Win32 プログラミング

実際の開発現場ではスタブ (stub)とドライバー(driver)という考え方がある。
https://ja.wikipedia.org/wiki/%E3%82%B9%E3%82%BF%E3%83%96
このようにスタブ毎にテスト出来ないと自分でもわけが分からない"スパゲティ"プログラムになる。基本設計書をまず見せて頂き1ファイル事にテスト可能な設計になっているか検討する必要があります

Name: Math
[URL]
Date: 2017年1月07日(土) 00:21
No: 8
(OFFLINE)

 Re: Win32 プログラミング

描画プログラムをテストするプログラムを考えてみました。
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <windows.h>//////// 検証用プログラム:ドライバー:描画チェッカー
#include <stdio.h>////////// 2017/01/06 Writen by Math
LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {
    HDC hdc;PAINTSTRUCT ps;static INT imode;POINT points[3];static INT ret;
    switch (msg) {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_CREATE:printf("<<<--->>>\n\n");
        imode = MessageBox(
            NULL , TEXT("return値を確認しますか?。") ,
            TEXT("SetPolyFillMode") , MB_YESNO
        );
        if (imode == IDYES) imode = WINDING;
        else imode = ALTERNATE;printf("001--->>>\n\n");
        return 0;
    case WM_PAINT:
        hdc = BeginPaint(hwnd , &ps);/////////////////////////////////////
        SelectObject(hdc , CreateSolidBrush(0xFF));
        SetPolyFillMode(hdc , imode);
       
        ret=Rectangle( hdc, 10, 20, 100, 110 );printf("ret=%d\n",ret);
        ret=Ellipse( hdc, 10, 20, 100, 110);printf("ret=%d\n",ret);
 
        points[0].x = 190; points[0].y =60;
        points[1].x = 120; points[1].y = 140;
        points[2].x = 260; points[2].y = 140;
 
        ret=Polygon( hdc, points, 3 );printf("ret=%d\n",ret);
        ret=TextOut(hdc, 130,10, TEXT("Hello World!"), 12);printf("ret=%d\n",ret);
       
 
        EndPaint(hwnd , &ps);
        DeleteObject(SelectObject(hdc , GetStockObject(WHITE_BRUSH)));
        return 0;
    }
    return DefWindowProc(hwnd , msg , wp , lp);
}
///////////////////////////////////////////////////////////////////////////////
int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
            PSTR lpCmdLine , int nCmdShow ) {////////////
    AllocConsole();///////////コンソール///////////////// ---[Debug Print]---
    FILE* out = 0; freopen_s( &out, "CON", "w", stdout );
    FILE* in = 0; freopen_s( &in, "CON", "r", stdin );
    ///            /////////Class////////////////////////
    HWND hwnd;  MSG msg;    WNDCLASS winc;
    winc.style      = CS_HREDRAW | CS_VREDRAW;
    winc.lpfnWndProc    = WndProc;
    winc.cbClsExtra = winc.cbWndExtra   = 0;
    winc.hInstance      = hInstance;
    winc.hIcon      = LoadIcon(NULL , IDI_APPLICATION);
    winc.hCursor        = LoadCursor(NULL , IDC_ARROW);
    winc.hbrBackground  = (HBRUSH)GetStockObject(WHITE_BRUSH);
    winc.lpszMenuName   = NULL;
    winc.lpszClassName  = TEXT("Form1");/////////Class//////////
    if (!RegisterClass(&winc)) return -1;////////Registe////////
    hwnd = CreateWindow(
            TEXT("Form1") , TEXT("Form1Samp") , WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
            CW_USEDEFAULT , CW_USEDEFAULT , CW_USEDEFAULT , CW_USEDEFAULT ,
            NULL , NULL , hInstance , NULL
    );//////////////////////////////////////////LOOP/////////////
    if (hwnd == NULL) return -1;
    while(GetMessage(&msg , NULL , 0 , 0)) DispatchMessage(&msg);
    //コンソール解放////////////////////////////コンソール/////// ---[Debug Print]---
    fclose( out ); fclose( in ); FreeConsole(); ////Close////////
    return msg.wParam;
}
///

Name: Math
[URL]
Date: 2017年1月07日(土) 08:48
No: 9
(OFFLINE)

 Re: Win32 プログラミング

プロジェクト・ファイルを送って頂けるとコマンドライン・コンパイルができるので大変助かります。よろしくお願い致します。(.vcxprojファイルです)

Name: 駆け出し
[URL]
上級者(18,248 ポイント)
Date: 2017年1月08日(日) 08:42
No: 10
(OFFLINE)

 Re: Win32 プログラミング

おはようございます。
実際の開発現場ではスタブ (stub)とドライバー(driver)という考え方がある。
https://ja.wikipedia.org/wiki/%E3%82%B9 ... F%E3%83%96
このようにスタブ毎にテスト出来ないと自分でもわけが分からない"スパゲティ"プログラムになる。基本設計書をまず見せて頂き1ファイル事にテスト可能な設計になっているか検討する必要があります


といいうことは、ここで○○を実装、あそこで××を実装、といった具合に決めてからコードを書くということでしょうか?

プロジェクト・ファイルを送って頂けるとコマンドライン・コンパイルができるので大変助かります。よろしくお願い致します。(.vcxprojファイルです)


添付しておきます。
コピペさせて申し訳ないです。これからはプロジェクトごと送ります...

.vcxprojは送れないようなので、zipにして送ります。
また、たぶん上にあるソースとは変わっているので、今編集している状態のソースを送ります.

Name: 駆け出し
[URL]
上級者(18,248 ポイント)
Date: 2017年1月08日(日) 08:43
No: 11
(OFFLINE)

 Re: Win32 プログラミング

vcxobj ファイル
添付ファイル
SoundPlayer.vcxproj.zip
(1.44 KiB) ダウンロード数: 7 回

Name: 駆け出し
[URL]
上級者(18,248 ポイント)
Date: 2017年1月08日(日) 08:47
No: 12
(OFFLINE)

 Re: Win32 プログラミング

今現在のソースコード
添付ファイル
SoundPlayer.zip
(19.13 KiB) ダウンロード数: 10 回

Name: Math
[URL]
Date: 2017年1月08日(日) 08:58
No: 13
(OFFLINE)

 Re: Win32 プログラミング

>といいうことは、ここで○○を実装、あそこで××を実装、といった具合に決めてからコードを書くということでしょうか?
そうです。設計書をもとにスケルトンを作らないでいきなりプログラムを書くといずれ破綻します。
>.vcxprojは送れないようなので、zipにして送ります。
他のトピックスでは送ったり、送られたりしてますよ。コンテキストメニューの”送る”からエディタに送ればいいはずです。でも全部をzipで貰う方がありがたいですね。

Name: 駆け出し
[URL]
上級者(18,248 ポイント)
Date: 2017年1月08日(日) 09:03
No: 14
(OFFLINE)

 Re: Win32 プログラミング

>といいうことは、ここで○○を実装、あそこで××を実装、といった具合に決めてからコードを書くということでしょうか?
そうです。設計書をもとにスケルトンを作らないでいきなりプログラムを書くといずれ破綻します。

なるほど、自分これまで何度か破たんしてる(なんでこの処理をしているかわからなくなる)ので、これからは何を実装するか決めてから実装します。

Name: Math
[URL]
Date: 2017年1月08日(日) 11:09
No: 15
(OFFLINE)

 Re: Win32 プログラミング

Windows10,VS2015で正常に動きました。

Name: 駆け出し
[URL]
上級者(18,248 ポイント)
Date: 2017年1月08日(日) 22:13
No: 16
(OFFLINE)

 Re: Win32 プログラミング

[解決!]

こんばんは。
Mathさん、いろいろ教えていただいてありがとうございました。

これにて、解決とさせていただきます。


Return to C言語何でも質問掲示板

オンラインデータ

このフォーラムを閲覧中のユーザー: なし & ゲスト[34人]