• R/O
  • SSH
  • HTTPS

foo-mixi: Commit


Commit MetaInfo

Revision69 (tree)
Zeit2009-02-17 02:58:58
Autoryoshy

Log Message

yoshy - 0.2.1.0 trunk を stable-0.2 branche に反映

Ändern Zusammenfassung

Diff

--- src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_X/foo_mixi_feat_winamp.cpp (revision 68)
+++ src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_X/foo_mixi_feat_winamp.cpp (nonexistent)
@@ -1,4309 +0,0 @@
1-#define BUILD_UNICODE
2-
3-#if defined(BUILD_UNICODE)
4-#if !defined(UNICODE)
5-#define _UNICODE
6-#define UNICODE
7-#endif
8-#endif
9-
10-#if defined(UNICODE) && !defined(BUILD_UNICODE)
11-#define BUILD_UNICODE
12-#endif
13-
14-#define LONG_PTR_TO_WNDPROC(p) (reinterpret_cast<WNDPROC>(p))
15-#define WNDPROC_TO_LONG_PTR(p) (reinterpret_cast<LONG_PTR>(p))
16-
17-#include <windows.h>
18-#include <lmcons.h>
19-#include <process.h>
20-#include <shlobj.h>
21-
22-#include <string>
23-#include <vector>
24-#include <map>
25-
26-typedef std::vector<std::string> Strings;
27-typedef Strings::iterator StringsIt;
28-typedef Strings::const_iterator StringsCIt;
29-
30-typedef std::map<std::string, std::string> StringMap;
31-typedef StringMap::iterator StringMapIt;
32-typedef StringMap::const_iterator StringMapCIt;
33-
34-typedef std::map<std::string, UINT> UIntMap;
35-typedef UIntMap::iterator UIntMapIt;
36-typedef UIntMap::const_iterator UIntMapCIt;
37-
38-#include "../SDK/foobar2000.h"
39-#include "../helpers/helpers.h"
40-
41-#if 0
42-#include <wx/string.h>
43-#endif
44-
45-#include "GEN.h"
46-#include "wa_ipc.h"
47-
48-#if 0
49-#define ID3LIB_LINKOPTION 3
50-#include <id3/tag.h>
51-#include <id3/misc_support.h>
52-#endif
53-
54-#include "resource.h"
55-
56-#if defined(_FOOBAR2000_UTF8API_H_)
57-# define FB2K_MAJOR_VERSION 8
58-#else
59-# define FB2K_MAJOR_VERSION 9
60-#endif
61-
62-#define IS_FB2K_VER08 (FB2K_MAJOR_VERSION == 8)
63-#define IS_FB2K_VER09 (FB2K_MAJOR_VERSION == 9)
64-
65-#define FB2K_COMPONENTS_DIR _T("components\\")
66-#define GEN_MIXI_FILE_NAME _T("gen_mixi_for_winamp.dll")
67-#define GEN_MIXI_FUNC_NAME_GET_GENERAL_PURPOSE_PLUGIN "winampGetGeneralPurposePlugin"
68-
69-#define DUMMY_MP3_FILE_NAME _T("foo_mixi_feat_winamp.mp3")
70-#define APPDATA_MIXI_STATION_DIR _T("\\mixi\\mixi")
71-#define DEFAULT_WINAMP_TITLE "Winamp"
72-#define DEFAULT_DUMMYAMP_TITLE "DummyAmp"
73-
74-#define CODEC_TYPE_VORBIS "Vorbis"
75-#define CODEC_TYPE_MP3 "MP3"
76-
77-#define IS_SUPPORTED_FORMAT_BY_GEN_MIXI(codec) ( !::lstrcmpA(codec, CODEC_TYPE_VORBIS) || !::lstrcmpA(codec, CODEC_TYPE_MP3))
78-
79-#if !defined(ENABLE_MSN)
80-#define PLUGIN_CAPTION "mixi music plugin for Winamp, bridge component"
81-#define PLUGIN_CAPTION_JP "mixi ミュージック"
82-#else
83-#define PLUGIN_CAPTION "Mixi Music plugin for M2M"
84-#endif
85-
86-#define ADVANCED_SETTINGS_CAPTION "高度な設定"
87-#define DUMMYAMP_FRAME_CAPTION _T("DummyAmp の設定 (動作状態:%s)")
88-#define DUMMYAMP_BEFORE_INIT_MODE _T("初回再生の待機中")
89-#define DUMMYAMP_HOOK_MODE _T("既存 Winamp API Emulator をフック中")
90-#define DUMMYAMP_STANDALONE_MODE _T("単独で Winamp API をエミュレート中")
91-#define DEBUG_SETTINGS_CAPTION "デバッグ用の設定"
92-#define PLUGIN_VERSION "0.2.0.1"
93-
94-#define DEFAULT_DUMMYAMP_TITLE_FORMAT "[%artist% - ]$if(%title%,%title%,%_filename%)"
95-
96-#define URL_FOO_MIXI_HOME "http://foo-mixi.sourceforge.jp/"
97-
98-#define FORMAT_FILEPATH "%_path%"
99-#define FORMAT_FILEPATHRAW "%_path_raw%"
100-#define FORMAT_ARTIST "%artist%"
101-#define FORMAT_TRACKTITLE "%title%"
102-#define FORMAT_ALBUMTITLE "%album%"
103-#define FORMAT_GENRE "%genre%"
104-#define FORMAT_CODEC "%__codec%"
105-
106-#if IS_FB2K_VER08
107-#define FORMAT_LISTINDEX "%_playlist_number%"
108-#elif IS_FB2K_VER09
109-#define FORMAT_LISTINDEX "%list_index%"
110-#endif
111-
112-#define IPC_GETOUTPUTTIME_PositionMSec 0
113-#define IPC_GETOUTPUTTIME_TotalSec 1
114-
115-#define IPC_INTERNAL_REFRESHLISTINFO 0x4000
116-#define IPC_INTERNAL_REFRESHDYNINFO 0x4001
117-
118-#define RESENT_INTERVAL 5000
119-#define FORCE_RESENT_MODE 0
120-//#define DISABLE_KICK_GEN_MIXI_LOOP
121-
122-#define REQUIRED_MINIMUM_TIME 3
123-#define SEND_TIME_RATE_LOWERBOUND 33
124-#define REQUIRED_MAXIMUM_TIME 20
125-
126-#define CONTROL_SEND_TIMING
127-
128-//#define ENABLE_MSN
129-
130-#if IS_FB2K_VER09
131-using namespace pfc;
132-using namespace pfc::stringcvt;
133-#define pfc_string_to_float string_to_float
134-#endif
135-
136-/*
137- foo_mixi_feat_winamp: project dependencies
138-
139- foo_mixi_feat_winamp
140- foobar2000_SDK
141- utf8api(0.8.3)
142- pfc
143- foobar2000_sdk_helpers
144- pfc
145- foobar2000_component_client(0.9.X)
146- id3lib
147- zlib
148-
149- library dependencies: wxbase28.lib, id3lib.lib, ../shared/shared.lib(0.9.X)
150- runtime library: Multi-Thread (DLL) or (Debug,DLL)
151- !! ensure all projects that depended from this project are correctly set to MT DLL !!
152- ignore: LIBCMT [Win32 Release] (or LIBCMTD [Win32 Debug])
153-*/
154-
155-// if wxWidgets are updated, change lib names below and linker libpath option.
156-
157-#if 0
158-#if defined(_DEBUG)
159-#if defined(BUILD_UNICODE)
160-#pragma comment(lib, "wxbase28ud.lib")
161-#else
162-#pragma comment(lib, "wxbase28d.lib")
163-#endif
164-#else
165-#if defined(BUILD_UNICODE)
166-#pragma comment(lib, "wxbase28u.lib")
167-#else
168-#pragma comment(lib, "wxbase28.lib")
169-#endif
170-#endif
171-#endif
172-
173-// now id3lib automatically added to linker target,
174-// because it generated from depended project.
175-//#pragma comment(lib, "id3lib.lib")
176-
177-#if IS_FB2K_VER09
178-#pragma comment(lib, "../shared/shared.lib")
179-#endif
180-
181-typedef std::basic_string<TCHAR> tstring;
182-
183-typedef TCHAR Str64K[65536];
184-typedef char StrDBCS64K[65536];
185-
186-tstring GetErrorMessage(DWORD errCode);
187-void putLogError(LPCTSTR pMethod, LPCTSTR pErrMsg, DWORD dwErrCode);
188-void DebugPrint(int severity, LPCTSTR lpszFormat, ...);
189-void DebugPrintDBCS(int severity, LPCSTR lpszFormat, ...);
190-void DebugPrint8(int severity, LPCSTR lpszFormat, ...);
191-
192-#define LOGLEVEL_NONE 0
193-#define LOGLEVEL_WARNING 1
194-#define LOGLEVEL_ERROR 2
195-
196-#if IS_FB2K_VER09
197-namespace console
198-{
199- enum {
200- SEVERITY_INFO = 0,
201- SEVERITY_WARNING = 1,
202- SEVERITY_CRITICAL = 2
203- };
204-};
205-#endif
206-
207-#define LOG_TRACE(f, ...) if(cfg_enable_debug_log) DebugPrint(console::SEVERITY_INFO, f, __VA_ARGS__)
208-#define LOG_DEBUG(f, ...) if(cfg_enable_debug_log) DebugPrint(console::SEVERITY_INFO, f, __VA_ARGS__)
209-
210-#define LOG_TRACE8(f, ...) if(cfg_enable_debug_log) DebugPrint8(console::SEVERITY_INFO, f, __VA_ARGS__)
211-#define LOG_DEBUG8(f, ...) if(cfg_enable_debug_log) DebugPrint8(console::SEVERITY_INFO, f, __VA_ARGS__)
212-
213-#define LOG_TRACE_ANSI(f, ...) if(cfg_enable_debug_log) DebugPrintDBCS(console::SEVERITY_INFO, f, __VA_ARGS__)
214-#define LOG_DEBUG_ANSI(f, ...) if(cfg_enable_debug_log) DebugPrintDBCS(console::SEVERITY_INFO, f, __VA_ARGS__)
215-
216-#define LOG_INFO(f, ...) DebugPrint(console::SEVERITY_INFO, f, __VA_ARGS__)
217-#define LOG_WARN(f, ...) DebugPrint(console::SEVERITY_WARNING, f, __VA_ARGS__)
218-#define LOG_ERROR(f, ...) DebugPrint(console::SEVERITY_CRITICAL, f, __VA_ARGS__)
219-
220-#if defined(BUILD_UNICODE)
221-#define TRACE_DBCS(f, ...) if(cfg_enable_debug_log) DebugPrintDBCS(console::SEVERITY_INFO, f, __VA_ARGS__)
222-#else
223-#define TRACE_DBCS(f, ...) if(cfg_enable_debug_log) DebugPrint(console::SEVERITY_INFO, f, __VA_ARGS__)
224-#endif
225-
226-#define DEBUG_DUMMYAMP_INIT(f, ...) if(cfg_debug_dummyamp_init >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
227-#define TRACE_DUMMYAMP_INIT(f, ...) if(cfg_debug_dummyamp_init >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
228-
229-#define DEBUG_DUMMYAMP_PROC(f, ...) if(cfg_debug_dummyamp_proc >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
230-#define DEBUG_DUMMYAMP_PROC8(f, ...) if(cfg_debug_dummyamp_proc >= LOGLEVEL_WARNING) LOG_DEBUG8(f, __VA_ARGS__)
231-#define TRACE_DUMMYAMP_PROC(f, ...) if(cfg_debug_dummyamp_proc >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
232-#define TRACE_DUMMYAMP_PROC8(f, ...) if(cfg_debug_dummyamp_proc >= LOGLEVEL_ERROR) LOG_TRACE8(f, __VA_ARGS__)
233-
234-#define DEBUG_TRACK_INFO(f, ...) if(cfg_debug_track_info >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
235-#define DEBUG_TRACK_INFO8(f, ...) if(cfg_debug_track_info >= LOGLEVEL_WARNING) LOG_DEBUG8(f, __VA_ARGS__)
236-#define DEBUG_TRACK_INFO_ANSI(f, ...) if(cfg_debug_track_info >= LOGLEVEL_WARNING) LOG_DEBUG_ANSI(f, __VA_ARGS__)
237-#define TRACE_TRACK_INFO(f, ...) if(cfg_debug_track_info >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
238-#define TRACE_TRACK_INFO8(f, ...) if(cfg_debug_track_info >= LOGLEVEL_ERROR) LOG_TRACE8(f, __VA_ARGS__)
239-#define TRACE_TRACK_INFO_ANSI(f, ...) if(cfg_debug_track_info >= LOGLEVEL_ERROR) LOG_TRACE_ANSI(f, __VA_ARGS__)
240-
241-#define DEBUG_PLUGIN(f, ...) if(cfg_debug_plugin >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
242-#define TRACE_PLUGIN(f, ...) if(cfg_debug_plugin >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
243-
244-#define DEBUG_CALLBACK(f, ...) if(cfg_debug_callback >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
245-#define TRACE_CALLBACK(f, ...) if(cfg_debug_callback >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
246-
247-static string_utf8_from_os g_pluginCaption8(_T(PLUGIN_CAPTION_JP));
248-static string_utf8_from_os g_pluginVersion8(_T(PLUGIN_VERSION));
249-static string_utf8_from_os g_pluginAbout8(
250- _T(PLUGIN_CAPTION_JP) _T(" ") _T(PLUGIN_VERSION) _T("\nCopyright (C) 2006-2008 Yossiepon Oniichan, All Rights Reserved."));
251-
252-DECLARE_COMPONENT_VERSION(g_pluginCaption8, g_pluginVersion8, g_pluginAbout8);
253-
254-static string_utf8_from_os g_advancedSettingsCaption8(_T(ADVANCED_SETTINGS_CAPTION));
255-static string_utf8_from_os g_debugSettingsCaption8(_T(DEBUG_SETTINGS_CAPTION));
256-
257-static string_utf8_from_os g_menu_item(_T("Components/Mixi/mixiミュージック連携を有効にする"));
258-
259-static string_utf8_from_os g_menu_item_title(_T("mixiミュージック連携を有効にする"));
260-static string_utf8_from_os g_menu_item_description(_T("mixiミュージックへの曲情報の送信について、有効/無効を切り替えます"));
261-
262-#if IS_FB2K_VER08
263-static cfg_int cfg_use_plugin("usePlugin", 1);
264-
265-static cfg_string cfg_no_artist_name("NoArtistName", "No Artist");
266-static cfg_string cfg_no_title_name("NoTitleName", "No Title");
267-static cfg_string cfg_no_album_name("NoAlbumName", "No Title");
268-static cfg_string cfg_no_genre_name("NoGenreName", "Other");
269-
270-static cfg_string cfg_send_interval1("SendInterval1", "20");
271-static cfg_string cfg_send_interval2("SendInterval2", "66");
272-static cfg_string cfg_send_interval3("SendInterval3", "300");
273-
274-static cfg_int cfg_disable_duplicate_song("DisableDuplicateSong", 0);
275-static cfg_int cfg_media_library_registered_file_only("MediaLibraryRegisteredFileOnly", 0);
276-static cfg_int cfg_explicitly_tagged_file_only("ExplicitlyTaggedFileOnly", 0);
277-static cfg_int cfg_enable_streaming_file("EnableStreamingFile", 0);
278-
279-static cfg_int cfg_disable_dummy_mp3("DisableDummyMp3", 0);
280-static cfg_int cfg_dummy_mp3_location("DummyMp3Location", 0);
281-
282-static cfg_int cfg_show_dummyamp("ShowDummyAmp", 0);
283-static cfg_string cfg_dummyamp_title_format("DummyAmpTitleFormat", DEFAULT_DUMMYAMP_TITLE_FORMAT);
284-static cfg_string cfg_dummyamp_playlist_format("DummyAmpPlaylistFormat", DEFAULT_DUMMYAMP_TITLE_FORMAT);
285-static cfg_int cfg_disable_ansi_trans("DisableAnsiTrans", 0);
286-static cfg_int cfg_enable_ext_ipc_proc("EnableExtIpcProc", 1);
287-
288-static cfg_int cfg_enable_debug_log("EnableDebugLog", 1);
289-static cfg_int cfg_debug_dummyamp_init("DebugDummyAmpInit", 1);
290-static cfg_int cfg_debug_dummyamp_proc("DebugDummyAmpProc", 1);
291-static cfg_int cfg_debug_track_info("DebugTrackInfo", 1);
292-static cfg_int cfg_debug_plugin("DebugPlugin", 1);
293-static cfg_int cfg_debug_callback("DebugCallback", 1);
294-#elif IS_FB2K_VER09
295-// {DB051102-6DAE-4ff8-B5ED-AA06C2ACFEDE}
296-static const GUID cfg_use_plugin_guid = { 0xdb051102, 0x6dae, 0x4ff8, { 0xb5, 0xed, 0xaa, 0x6, 0xc2, 0xac, 0xfe, 0xde } };
297-static cfg_int cfg_use_plugin(cfg_use_plugin_guid, 1);
298-
299-// {1B27EDEC-A28A-4dac-96D4-1E3B51C92004}
300-static const GUID cfg_no_artist_name_guid = { 0x1b27edec, 0xa28a, 0x4dac, { 0x96, 0xd4, 0x1e, 0x3b, 0x51, 0xc9, 0x20, 0x4 } };
301-static cfg_string cfg_no_artist_name(cfg_no_artist_name_guid, "No Artist");
302-// {A8CFD50C-05EA-447d-AA74-F4C6975E750E}
303-static const GUID cfg_no_title_name_guid = { 0xa8cfd50c, 0x5ea, 0x447d, { 0xaa, 0x74, 0xf4, 0xc6, 0x97, 0x5e, 0x75, 0xe } };
304-static cfg_string cfg_no_title_name(cfg_no_title_name_guid, "No Title");
305-// {A7593537-8B09-4016-9B3C-0EF5516BBFF9}
306-static const GUID cfg_no_album_name_guid = { 0xa7593537, 0x8b09, 0x4016, { 0x9b, 0x3c, 0xe, 0xf5, 0x51, 0x6b, 0xbf, 0xf9 } };
307-static cfg_string cfg_no_album_name(cfg_no_album_name_guid, "No Title");
308-// {15774319-0CBE-45fd-B0E8-52D4728319A3}
309-static const GUID cfg_no_genre_name_guid = { 0x15774319, 0xcbe, 0x45fd, { 0xb0, 0xe8, 0x52, 0xd4, 0x72, 0x83, 0x19, 0xa3 } };
310-static cfg_string cfg_no_genre_name(cfg_no_genre_name_guid, "Other");
311-
312-// {ED0C715A-D06D-4641-A29A-AE4485A0B9EF}
313-static const GUID cfg_send_interval1_guid = { 0xed0c715a, 0xd06d, 0x4641, { 0xa2, 0x9a, 0xae, 0x44, 0x85, 0xa0, 0xb9, 0xef } };
314-static cfg_string cfg_send_interval1(cfg_send_interval1_guid, "20");
315-// {25989711-B458-4624-8A85-7304FCE799A3}
316-static const GUID cfg_send_interval2_guid = { 0x25989711, 0xb458, 0x4624, { 0x8a, 0x85, 0x73, 0x4, 0xfc, 0xe7, 0x99, 0xa3 } };
317-static cfg_string cfg_send_interval2(cfg_send_interval2_guid, "66");
318-// {4287A873-015D-44b5-A31E-34DEE1BF0525}
319-static const GUID cfg_send_interval3_guid = { 0x4287a873, 0x15d, 0x44b5, { 0xa3, 0x1e, 0x34, 0xde, 0xe1, 0xbf, 0x5, 0x25 } };
320-static cfg_string cfg_send_interval3(cfg_send_interval3_guid, "300");
321-
322-// {5C318451-2B6A-405f-814B-2795A764C1DE}
323-static const GUID cfg_disable_duplicate_song_guid = { 0x5c318451, 0x2b6a, 0x405f, { 0x81, 0x4b, 0x27, 0x95, 0xa7, 0x64, 0xc1, 0xde } };
324-static cfg_int cfg_disable_duplicate_song(cfg_disable_duplicate_song_guid, 0);
325-// {56688AED-A76D-4759-A835-A380D39D34D1}
326-static const GUID cfg_media_library_registered_file_only_guid = { 0x56688aed, 0xa76d, 0x4759, { 0xa8, 0x35, 0xa3, 0x80, 0xd3, 0x9d, 0x34, 0xd1 } };
327-static cfg_int cfg_media_library_registered_file_only(cfg_media_library_registered_file_only_guid, 0);
328-// {91E0D3D4-85DD-4c45-ADB5-7FAC6F3360CD}
329-static const GUID cfg_explicitly_tagged_file_only_guid = { 0x91e0d3d4, 0x85dd, 0x4c45, { 0xad, 0xb5, 0x7f, 0xac, 0x6f, 0x33, 0x60, 0xcd } };
330-static cfg_int cfg_explicitly_tagged_file_only(cfg_explicitly_tagged_file_only_guid, 0);
331-// {F4E85669-6EEF-4b75-AFC1-7964AEBE10B0}
332-static const GUID cfg_enable_streaming_file_guid = { 0xf4e85669, 0x6eef, 0x4b75, { 0xaf, 0xc1, 0x79, 0x64, 0xae, 0xbe, 0x10, 0xb0 } };
333-static cfg_int cfg_enable_streaming_file(cfg_enable_streaming_file_guid, 0);
334-
335-// {67341E11-A385-45d8-9DE6-B1FABA35AC62}
336-static const GUID cfg_disable_dummy_mp3_guid = { 0x67341e11, 0xa385, 0x45d8, { 0x9d, 0xe6, 0xb1, 0xfa, 0xba, 0x35, 0xac, 0x62 } };
337-static cfg_int cfg_disable_dummy_mp3(cfg_disable_dummy_mp3_guid, 0);
338-// {87D4D72C-43AB-42ab-8CAC-D689961DA5EA}
339-static const GUID cfg_dummy_mp3_location_guid = { 0x87d4d72c, 0x43ab, 0x42ab, { 0x8c, 0xac, 0xd6, 0x89, 0x96, 0x1d, 0xa5, 0xea } };
340-static cfg_int cfg_dummy_mp3_location(cfg_dummy_mp3_location_guid, 0);
341-
342-// {F9DB10F0-1A01-40dd-A342-486A6CB596E7}
343-static const GUID cfg_show_dummyamp_guid = { 0xf9db10f0, 0x1a01, 0x40dd, { 0xa3, 0x42, 0x48, 0x6a, 0x6c, 0xb5, 0x96, 0xe7 } };
344-static cfg_int cfg_show_dummyamp(cfg_show_dummyamp_guid, 0);
345-// {CC7785CA-B019-4107-9115-161A543B3952}
346-static const GUID cfg_dummyamp_title_format_guid = { 0xcc7785ca, 0xb019, 0x4107, { 0x91, 0x15, 0x16, 0x1a, 0x54, 0x3b, 0x39, 0x52 } };
347-static cfg_string cfg_dummyamp_title_format(cfg_dummyamp_title_format_guid, DEFAULT_DUMMYAMP_TITLE_FORMAT);
348-// {B964EB32-4957-4e7a-81B5-E89B4405AAAD}
349-static const GUID cfg_dummyamp_playlist_format_guid = { 0xb964eb32, 0x4957, 0x4e7a, { 0x81, 0xb5, 0xe8, 0x9b, 0x44, 0x5, 0xaa, 0xad } };
350-static cfg_string cfg_dummyamp_playlist_format(cfg_dummyamp_title_format_guid, DEFAULT_DUMMYAMP_TITLE_FORMAT);
351-
352-// {094571BA-1484-455c-9D6E-E18B13296149}
353-static const GUID cfg_disable_ansi_trans_guid = { 0x94571ba, 0x1484, 0x455c, { 0x9d, 0x6e, 0xe1, 0x8b, 0x13, 0x29, 0x61, 0x49 } };
354-static cfg_int cfg_disable_ansi_trans(cfg_disable_ansi_trans_guid, 0);
355-// {8961A829-F010-461c-9CC8-C06308BFA4A2}
356-static const GUID cfg_enable_ext_ipc_proc_guid = { 0x8961a829, 0xf010, 0x461c, { 0x9c, 0xc8, 0xc0, 0x63, 0x8, 0xbf, 0xa4, 0xa2 } };
357-static cfg_int cfg_enable_ext_ipc_proc(cfg_enable_ext_ipc_proc_guid, 1);
358-
359-// {3B6B73F9-F6AF-4b6c-8015-E73A1B87AD5C}
360-static const GUID cfg_enable_debug_log_guid = { 0x3b6b73f9, 0xf6af, 0x4b6c, { 0x80, 0x15, 0xe7, 0x3a, 0x1b, 0x87, 0xad, 0x5c } };
361-static cfg_int cfg_enable_debug_log(cfg_enable_debug_log_guid, 1); // debug log enabled
362-// {0BF3522F-BC55-4f77-AA95-B02F6E159544}
363-static const GUID cfg_debug_dummyamp_init_guid = { 0xbf3522f, 0xbc55, 0x4f77, { 0xaa, 0x95, 0xb0, 0x2f, 0x6e, 0x15, 0x95, 0x44 } };
364-static cfg_int cfg_debug_dummyamp_init(cfg_debug_dummyamp_init_guid, 1); // debug level
365-// {D1256573-7560-41db-A781-9985AE50CE07}
366-static const GUID cfg_debug_dummyamp_proc_guid = { 0xd1256573, 0x7560, 0x41db, { 0xa7, 0x81, 0x99, 0x85, 0xae, 0x50, 0xce, 0x7 } };
367-static cfg_int cfg_debug_dummyamp_proc(cfg_debug_dummyamp_proc_guid, 1); // debug level
368-// {0A7E2CAE-905F-4ecb-A82D-8DD853FBFFF3}
369-static const GUID cfg_debug_track_info_guid = { 0xa7e2cae, 0x905f, 0x4ecb, { 0xa8, 0x2d, 0x8d, 0xd8, 0x53, 0xfb, 0xff, 0xf3 } };
370-static cfg_int cfg_debug_track_info(cfg_debug_track_info_guid, 1); // debug level
371-// {67A78DB7-3591-4416-84FC-96436082B619}
372-static const GUID cfg_debug_plugin_guid = { 0x67a78db7, 0x3591, 0x4416, { 0x84, 0xfc, 0x96, 0x43, 0x60, 0x82, 0xb6, 0x19 } };
373-static cfg_int cfg_debug_plugin(cfg_debug_plugin_guid, 1); // debug level
374-// {DBED8400-527F-4b98-9227-2C0BA95B3206}
375-static const GUID cfg_debug_callback_guid = { 0xdbed8400, 0x527f, 0x4b98, { 0x92, 0x27, 0x2c, 0xb, 0xa9, 0x5b, 0x32, 0x6 } };
376-static cfg_int cfg_debug_callback(cfg_debug_callback_guid, 1); // debug level
377-#endif
378-
379-class TrackInfo
380-{
381-public:
382- std::string m_nullStr;
383-
384- StringMap m_infoMap8;
385- StringMap m_infoMapAnsi;
386-
387- UIntMap m_infoMapNum;
388-
389- TrackInfo() {
390- }
391-
392- TrackInfo(const TrackInfo &other)
393- : m_infoMap8(other.m_infoMap8)
394- , m_infoMapAnsi(other.m_infoMapAnsi)
395- , m_infoMapNum(other.m_infoMapNum) {
396- }
397-
398- ~TrackInfo() {
399- }
400-
401- TrackInfo &operator =(const TrackInfo &other)
402- {
403- TrackInfo temp(other);
404- swap(temp);
405-
406- return *this;
407- }
408-
409- void show_map(StringMap &map, bool bAnsi = false)
410- {
411- StringMapCIt beginIt(map.begin()), endIt(map.end()), it;
412-
413- for(it = beginIt; it != endIt; it ++) {
414-
415- if(bAnsi) {
416- TRACE_TRACK_INFO_ANSI("show_map_ansi: [%s, %s]", it->first.c_str(), it->second.c_str());
417- } else {
418- TRACE_TRACK_INFO8("show_map8: [%s, %s]", it->first.c_str(), it->second.c_str());
419- }
420- }
421- }
422-
423- void swap(TrackInfo &other)
424- {
425- m_infoMap8.swap(other.m_infoMap8);
426- m_infoMapAnsi.swap(other.m_infoMapAnsi);
427- m_infoMapNum.swap(other.m_infoMapNum);
428- }
429-
430- void clear()
431- {
432- TRACE_TRACK_INFO(_T("TRACK_INFO::clear - called."));
433-
434- m_infoMap8.clear();
435- m_infoMapAnsi.clear();
436- m_infoMapNum.clear();
437- }
438-
439- bool isEmpty() const { return m_infoMap8.empty() & m_infoMapNum.empty(); }
440-
441-public:
442-
443-#if IS_FB2K_VER08
444- void setStrings(const Strings &keys, metadb_handle * track)
445-#elif IS_FB2K_VER09
446- void setStrings(const Strings &keys, metadb_handle_ptr track)
447-#endif
448- {
449- TRACE_TRACK_INFO(_T("TrackInfo::setStrings - called."));
450-
451- StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
452-
453- for(it = beginIt; it != endIt; it ++) {
454-
455- string8 info8;
456-
457-#if IS_FB2K_VER08
458- track->handle_format_title(info8, it->c_str(), 0);
459-#elif IS_FB2K_VER09
460- service_ptr_t<titleformat_object> titleformat;
461-
462- static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
463- track->format_title(NULL, info8, titleformat, 0);
464-#endif
465-// DEBUG_TRACK_INFO8("TrackInfo::setStrings - %s: %s", it->c_str(), (LPCSTR)info8);
466-
467- putString(it->c_str(), (LPCSTR)info8);
468- }
469- }
470-
471- void setDynamicStrings(const Strings &keys)
472- {
473- TRACE_TRACK_INFO(_T("TrackInfo::setDynamicStrings - called."));
474-
475-#if IS_FB2K_VER08
476- metadb_handle *track = play_control::get()->get_now_playing();
477-#elif IS_FB2K_VER09
478- metadb_handle_ptr track;
479- static_api_ptr_t<playback_control>()->get_now_playing(track);
480-#endif
481-
482- StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
483-
484- for(it = beginIt; it != endIt; it ++) {
485-
486- string8 info8;
487-
488-#if IS_FB2K_VER08
489- play_control::get()->playback_format_title_ex(track, info8, it->c_str(), NULL, false, true);
490-#elif IS_FB2K_VER09
491- service_ptr_t<titleformat_object> titleformat;
492-
493- static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
494- static_api_ptr_t<playback_control>()->playback_format_title_ex(track, NULL, info8, titleformat, NULL, play_control::display_level_titles);
495-#endif
496-// DEBUG_TRACK_INFO8("TrackInfo::setDynamicStrings - %s: %s", it->c_str(), (LPCSTR)info8);
497-
498- const std::string &oldValue = getString(*it);
499-
500- if((::lstrcmpA(info8, "?") != 0) || (oldValue.length() == 0))
501- {
502- putString(it->c_str(), (LPCSTR)info8);
503- }
504- }
505-
506-#if IS_FB2K_VER08
507- if(track) {
508- track->handle_release();
509- }
510-#endif
511- }
512-
513- void setPlaylistStrings(const Strings &keys)
514- {
515- TRACE_TRACK_INFO(_T("TrackInfo::setPlaylistStrings - called."));
516-
517-#if IS_FB2K_VER08
518- int track_index;
519- track_index = playlist_oper::get()->get_now_playing();
520-#elif IS_FB2K_VER09
521- t_size playlist_index, track_index;
522- static_api_ptr_t<playlist_manager>()->get_playing_item_location(&playlist_index, &track_index);
523-#endif
524-
525- StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
526-
527- for(it = beginIt; it != endIt; it ++) {
528-
529- string8 info8;
530-
531-#if IS_FB2K_VER08
532- playlist_oper::get()->format_title(track_index, info8, it->c_str(), NULL);
533-#elif IS_FB2K_VER09
534- service_ptr_t<titleformat_object> titleformat;
535-
536- static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
537- static_api_ptr_t<playlist_manager>()->playlist_item_format_title(playlist_index, track_index,
538- NULL, info8, titleformat, NULL, play_control::display_level_titles);
539-#endif
540-// DEBUG_TRACK_INFO8("TrackInfo::setPlaylistStrings - %s: %s", it->c_str(), (LPCSTR)info8);
541-
542- putString(it->c_str(), (LPCSTR)info8);
543- }
544- }
545-
546-#if IS_FB2K_VER08
547- void setNumbers(const Strings &keys, metadb_handle * track)
548-#elif IS_FB2K_VER09
549- void setNumbers(const Strings &keys, metadb_handle_ptr track)
550-#endif
551- {
552- TRACE_TRACK_INFO(_T("TrackInfo::setNumbers - called."));
553-
554- StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
555-
556- for(it = beginIt; it != endIt; it ++) {
557-
558- string8 info8;
559-
560-#if IS_FB2K_VER08
561- track->handle_format_title(info8, it->c_str(), 0);
562-#elif IS_FB2K_VER09
563- service_ptr_t<titleformat_object> titleformat;
564-
565- static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
566- track->format_title(NULL, info8, titleformat, 0);
567-#endif
568-// DEBUG_TRACK_INFO8("TrackInfo::setNumbers - %s: %s", it->c_str(), (LPCSTR)info8);
569-
570- putNumber(it->c_str(), static_cast<UINT>(::atol(info8)) );
571- }
572- }
573-
574- void setDynamicNumbers(const Strings &keys)
575- {
576- TRACE_TRACK_INFO(_T("TrackInfo::setDynamicNumbers - called."));
577-
578-#if IS_FB2K_VER08
579- metadb_handle *track = play_control::get()->get_now_playing();
580-#elif IS_FB2K_VER09
581- metadb_handle_ptr track;
582- static_api_ptr_t<playback_control>()->get_now_playing(track);
583-#endif
584-
585- StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
586-
587- for(it = beginIt; it != endIt; it ++) {
588-
589- string8 info8;
590-
591-#if IS_FB2K_VER08
592- play_control::get()->playback_format_title_ex(track, info8, it->c_str(), NULL, false, true);
593-#elif IS_FB2K_VER09
594- service_ptr_t<titleformat_object> titleformat;
595-
596- static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
597- static_api_ptr_t<playback_control>()->playback_format_title_ex(track, NULL, info8, titleformat, NULL, play_control::display_level_titles);
598-#endif
599-// DEBUG_TRACK_INFO8("TrackInfo::setDynamicNumbers - %s: %s", it->c_str(), (LPCSTR)info8);
600-
601- UINT newValue = static_cast<UINT>(::atol(info8));
602- UINT oldValue = getNumber(*it);
603-
604- if((newValue != 0) || (oldValue == 0)) {
605- putNumber(it->c_str(), newValue);
606- }
607- }
608-
609-#if IS_FB2K_VER08
610- if(track) {
611- track->handle_release();
612- }
613-#endif
614- }
615-
616- void setPlaylistNumbers(const Strings &keys)
617- {
618- TRACE_TRACK_INFO(_T("TrackInfo::setPlaylistNumbers - called."));
619-
620-#if IS_FB2K_VER08
621- int track_index;
622- track_index = playlist_oper::get()->get_now_playing();
623-#elif IS_FB2K_VER09
624- t_size playlist_index, track_index;
625- static_api_ptr_t<playlist_manager>()->get_playing_item_location(&playlist_index, &track_index);
626-#endif
627-
628- StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
629-
630- for(it = beginIt; it != endIt; it ++) {
631-
632- string8 info8;
633-
634-#if IS_FB2K_VER08
635- playlist_oper::get()->format_title(track_index, info8, it->c_str(), NULL);
636-#elif IS_FB2K_VER09
637- service_ptr_t<titleformat_object> titleformat;
638-
639- static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
640- static_api_ptr_t<playlist_manager>()->playlist_item_format_title(playlist_index, track_index,
641- NULL, info8, titleformat, NULL, play_control::display_level_titles);
642-#endif
643-// DEBUG_TRACK_INFO8("TrackInfo::setPlaylistNumbers - %s: %s", it->c_str(), (LPCSTR)info8);
644-
645- putNumber(it->c_str(), static_cast<UINT>(::atol(info8)) );
646- }
647- }
648-
649- void putString(const std::string &key, const std::string &value)
650- {
651- DEBUG_TRACK_INFO8("TrackInfo::putString - %s: %s", key.c_str(), value.c_str());
652-
653- insert(m_infoMap8, key.c_str(), value.c_str());
654-
655- string_ansi_from_utf8 valueAnsi(value.c_str());
656-
657- insert(m_infoMapAnsi, key.c_str(), (LPCSTR)valueAnsi, true);
658- }
659-
660- void putNumber(const std::string &key, UINT value)
661- {
662- DEBUG_TRACK_INFO8("TrackInfo::putNumber - %s: %u", key.c_str(), value);
663-
664- insert(m_infoMapNum, key.c_str(), value);
665- }
666-
667- const std::string &getString(const std::string &key, bool bForceUTF8 = false) const {
668-
669- if((bForceUTF8 == true) || (cfg_disable_ansi_trans == 1))
670- {
671- StringMapCIt it(m_infoMap8.find(key)), endIt(m_infoMap8.end());
672-
673- if(it == endIt) {
674- return m_nullStr;
675- }
676-
677- return it->second;
678- }
679- else
680- {
681- StringMapCIt it(m_infoMapAnsi.find(key)), endIt(m_infoMapAnsi.end());
682-
683- if(it == endIt) {
684- return m_nullStr;
685- }
686-
687- return it->second;
688- }
689- }
690-
691- const UINT getNumber(const std::string &key) const {
692-
693- UIntMapCIt it(m_infoMapNum.find(key)), endIt(m_infoMapNum.end());
694-
695- if(it == endIt) {
696- return 0;
697- }
698-
699- return it->second;
700- }
701-
702- void removeStrings(const Strings &keys)
703- {
704- TRACE_TRACK_INFO(_T("TrackInfo::removeStrings - called."));
705-
706- StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
707-
708- for(it = beginIt; it != endIt; it ++) {
709- removeString(*it);
710- }
711- }
712-
713- void removeString(const std::string &key)
714- {
715- TRACE_TRACK_INFO8("TrackInfo::removeString - %s", key.c_str());
716-
717- m_infoMap8.erase(m_infoMap8.find(key));
718- m_infoMapAnsi.erase(m_infoMapAnsi.find(key));
719- }
720-
721- void removeNumbers(const Strings &keys)
722- {
723- TRACE_TRACK_INFO(_T("TrackInfo::removeNumbers - called."));
724-
725- StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
726-
727- for(it = beginIt; it != endIt; it ++) {
728- removeNumber(*it);
729- }
730- }
731-
732- void removeNumber(const std::string &key)
733- {
734- TRACE_TRACK_INFO8("TrackInfo::removeNumber - %s", key.c_str());
735-
736- m_infoMapNum.erase(m_infoMapNum.find(key));
737- }
738-
739-protected:
740-
741- static void insert(StringMap &map, LPCSTR pKey, LPCSTR pValue, bool bAnsi = false)
742- {
743-#if 0
744- if(bAnsi) {
745- TRACE_TRACK_INFO_ANSI("insertAnsi: [%s, %s]", pKey, pValue);
746- } else {
747- TRACE_TRACK_INFO8("insert8: [%s, %s]", pKey, pValue);
748- }
749-#endif
750-
751- map.insert(std::make_pair(pKey, pValue));
752- }
753-
754- static void insert(UIntMap &map, LPCSTR pKey, UINT value)
755- {
756-// TRACE_TRACK_INFO8("insertNum: [%s, %u]", pKey, value);
757-
758- map.insert(std::make_pair(pKey, value));
759- }
760-};
761-
762-class PathInfo
763-{
764- protected:
765- PathInfo() {
766- }
767-
768- public:
769- static tstring getFB2Kpath()
770- {
771- TCHAR modulePath[_MAX_PATH], moduleDrive[_MAX_DRIVE], moduleDir[_MAX_DIR];
772- TCHAR returnPath[_MAX_PATH];
773-
774- ::GetModuleFileName(NULL, modulePath, _MAX_PATH);
775- ::_tsplitpath_s(modulePath, moduleDrive, _MAX_DRIVE, moduleDir, _MAX_DIR, NULL, 0, NULL, 0);
776- ::_tmakepath_s(returnPath, _MAX_PATH, moduleDrive, moduleDir, NULL, NULL);
777-
778- return tstring(returnPath);
779- }
780-
781- static tstring getFB2KComponentsPath() {
782- return getFB2Kpath() + FB2K_COMPONENTS_DIR;
783- }
784-
785- static std::string getGenMixiDefaultPath()
786- {
787- string_utf8_from_os path(getFB2KComponentsPath().c_str());
788- return (LPCSTR)path;
789- }
790-
791- static tstring getMixiStationAppPath() {
792- return getSpecialFolderPath(CSIDL_APPDATA, FALSE) + APPDATA_MIXI_STATION_DIR;
793- }
794-
795- static tstring getFooMixiPlayInfoPath()
796- {
797- switch(cfg_dummy_mp3_location)
798- {
799- case 1:
800- return getTemporaryFolderPath();
801-
802- case 2:
803- return getFB2KComponentsPath() ;
804-
805- case 0:
806- default:
807- return getMixiStationAppPath() + _T("\\");
808- }
809- }
810-
811- static tstring getDummyPlayInfoMp3Path() {
812- return getFooMixiPlayInfoPath() + DUMMY_MP3_FILE_NAME;
813- }
814-
815- static tstring splitPath(const string8 &srcPath)
816- {
817- string_os_from_utf8 srcPathOs(srcPath);
818- return splitPath(srcPathOs);
819- }
820-
821- static tstring splitPath(LPCTSTR srcPath)
822- {
823- TCHAR drive[_MAX_DRIVE], dir[_MAX_DIR], dstPath[_MAX_PATH];
824- ::_tsplitpath_s(srcPath, drive, _MAX_DRIVE, dir, _MAX_DIR, NULL, 0, NULL, 0);
825- ::_tmakepath_s(dstPath, _MAX_PATH, drive, dir, NULL, NULL);
826- return dstPath;
827- }
828-
829- //! get the special folder path
830- static tstring getSpecialFolderPath(int nFolder, BOOL bCreate)
831- {
832- tstring resStr;
833- HRESULT hr = NO_ERROR;
834-
835- IMalloc *pMalloc = 0;
836- ITEMIDLIST *pItemID = 0;
837- TCHAR folderPath[MAX_PATH];
838-
839- folderPath[0] = _T('\0');
840- hr = SHGetMalloc(&pMalloc);
841-
842- if(hr == NO_ERROR)
843- {
844- hr = SHGetSpecialFolderLocation(0, nFolder, &pItemID);
845-
846- if(hr == NO_ERROR)
847- {
848- if(SHGetPathFromIDList(pItemID, folderPath) == FALSE)
849- hr = GetLastError();
850-
851- pMalloc->Free(pItemID);
852- }
853-
854- pMalloc->Release();
855- }
856-
857- resStr = folderPath;
858-
859- if(hr != NO_ERROR)
860- {
861- return _T("");
862- }
863-
864- return resStr;
865- }
866-
867- //! get the temporary folder path
868- static tstring getTemporaryFolderPath() {
869-
870- TCHAR strTempPath[MAX_PATH];
871- ::GetTempPath(MAX_PATH, strTempPath);
872-
873- return strTempPath;
874- }
875-};
876-
877-#if IS_FB2K_VER08
878-static cfg_string cfg_gen_mixi_path("GenMixiPath", PathInfo::getGenMixiDefaultPath().c_str());
879-#elif IS_FB2K_VER09
880-// {1EC28435-C243-483c-81EC-E0E57A96727E}
881-static const GUID cfg_gen_mixi_path_guid = { 0x1ec28435, 0xc243, 0x483c, { 0x81, 0xec, 0xe0, 0xe5, 0x7a, 0x96, 0x72, 0x7e } };
882-static cfg_string cfg_gen_mixi_path(cfg_gen_mixi_path_guid, PathInfo::getGenMixiDefaultPath().c_str());
883-#endif
884-
885-class PlayInfo
886-{
887- public:
888-
889- enum EPlayStatus
890- {
891- PLAY_STOP = 0,
892- PLAY_START = 1,
893- PLAY_PAUSE = 3
894- };
895-
896- public:
897-
898- PlayInfo() :
899- m_playStatus(PLAY_STOP),
900- m_isResentMode(false),
901- m_playLength(0),
902- m_playPosition(0),
903- m_playCount(0),
904- m_isPlayInfoMp3Available(false),
905- m_resetBasePosition(0) {
906- }
907-
908- public:
909-
910- void setPlayStatusStart() {
911- setPlayStatus(PLAY_START);
912- }
913-
914- void setPlayStatusStop() {
915- setPlayStatus(PLAY_STOP);
916- }
917-
918- void setPlayStatusPause() {
919- setPlayStatus(PLAY_PAUSE);
920- }
921-
922- void clearPlayInfo(bool isResentMode = true)
923- {
924- setPlayStatusStop();
925- m_isResentMode = isResentMode;
926- setPlayPosition(0);
927- setPlayLength(0);
928- setPlayInfoMp3Available(false);
929- m_resetBasePosition = 0;
930- }
931-
932- void setResentMode(bool bIncrementCounter = true)
933- {
934- if(bIncrementCounter) {
935- incrementPlayCount();
936- }
937- m_isResentMode = true;
938- m_resetBasePosition = m_playPosition;
939- }
940-
941- void clearResentMode() {
942- m_isResentMode = false;
943- }
944-
945- void incrementPlayCount() {
946- setPlayCount(getPlayCount() + 1);
947- }
948-
949- public:
950-
951- EPlayStatus getPlayStatus() const
952- {
953- if((m_playStatus == PLAY_START) && m_isResentMode) {
954- return PLAY_STOP;
955- }
956- return m_playStatus;
957- }
958-
959- void setPlayStatus(EPlayStatus status) {
960- m_playStatus = status;
961- }
962-
963- int getPlayPosition() const
964- {
965- if(m_resetBasePosition > 0) {
966- return m_playPosition - m_resetBasePosition;
967- }
968- return m_playPosition;
969- }
970-
971- void setPlayPosition(int pos) {
972- m_playPosition = pos;
973- }
974-
975- int getPlayLength() const
976- {
977-#if FORCE_RESENT_MODE == 0
978- if(m_resetBasePosition > 0) {
979-#else
980- if(true) {
981-#endif
982- return 0;
983- }
984- return m_playLength;
985- }
986-
987- void setPlayLength(int len) {
988- m_playLength = len;
989- }
990-
991- int getPlayCount() const {
992- return m_playCount;
993- }
994-
995- void setPlayCount(int count) {
996- m_playCount = count;
997- }
998-
999- bool isPlayInfoMp3Available() const {
1000- return m_isPlayInfoMp3Available;
1001- }
1002-
1003- void setPlayInfoMp3Available(bool isAvailable) {
1004- m_isPlayInfoMp3Available = isAvailable;
1005- }
1006-
1007- void setPlayInfoMp3Path(LPCSTR path)
1008- {
1009-#if 0
1010- m_playInfoMp3Path = path;
1011-
1012- string_utf8_from_os path8(path);
1013-
1014- if(cfg_disable_ansi_trans == 1)
1015- {
1016-
1017- m_playInfoMp3Path8 = path8;
1018- }
1019- else
1020- {
1021- string_ansi_from_utf8 pathAnsi(path8);
1022-
1023- m_playInfoMp3Path8 = pathAnsi;
1024- }
1025-#else
1026- m_playInfoMp3Path8 = path;
1027-#endif
1028- }
1029-
1030- const string8 &getPlayInfoMp3Path8() const {
1031- return m_playInfoMp3Path8;
1032- }
1033-
1034- bool isResentMode() const {
1035- return m_isResentMode;
1036- }
1037-
1038- protected:
1039-
1040- EPlayStatus m_playStatus;
1041-
1042- int m_playLength;
1043- int m_playPosition;
1044- int m_playCount;
1045-
1046- bool m_isPlayInfoMp3Available;
1047- bool m_isResentMode;
1048- int m_resetBasePosition;
1049-
1050- string8 m_playInfoMp3Path8;
1051-};
1052-
1053-class id3Info
1054-{
1055- public:
1056-
1057- typedef std::vector<UINT16> UInt16Array;
1058-
1059- id3Info(const TrackInfo & info) : m_info(info), m_hMp3File(INVALID_HANDLE_VALUE) {
1060- }
1061-
1062- ~id3Info() {
1063- close();
1064- }
1065-
1066- DWORD write(LPCTSTR path) {
1067-
1068- string_wide_from_utf8 title_utf16(m_info.getString(FORMAT_TRACKTITLE, true).c_str());
1069- string_wide_from_utf8 artist_utf16(m_info.getString(FORMAT_ARTIST, true).c_str());
1070- string_wide_from_utf8 album_utf16(m_info.getString(FORMAT_ALBUMTITLE, true).c_str());
1071- string_wide_from_utf8 genre_utf16(m_info.getString(FORMAT_GENRE, true).c_str());
1072-
1073- DWORD dwErr = S_OK;
1074-
1075- if((dwErr = open(path)) != S_OK) {
1076- return dwErr;
1077- }
1078-
1079- UInt16Array title = makeTextFrame("TIT2", makeUTF16LE(title_utf16));
1080- UInt16Array album = makeTextFrame("TALB", makeUTF16LE(album_utf16));
1081- UInt16Array artist = makeTextFrame("TPE1", makeUTF16LE(artist_utf16));
1082- UInt16Array genre = makeTextFrame("TCON", makeUTF16LE(genre_utf16));
1083-
1084- dwErr = writeHeader(static_cast<UINT32>(
1085- title.size()*2 + album.size()*2 + artist.size()*2 + genre.size()*2 + 4));
1086- // add charset code size (4bytes)
1087-
1088- if(dwErr == S_OK) {
1089- dwErr = writeTextFrame(title);
1090- }
1091-
1092- if(dwErr == S_OK) {
1093- dwErr = writeTextFrame(album);
1094- }
1095-
1096- if(dwErr == S_OK) {
1097- dwErr = writeTextFrame(artist);
1098- }
1099-
1100- if(dwErr == S_OK) {
1101- dwErr = writeTextFrame(genre);
1102- }
1103-
1104- close();
1105-
1106- return dwErr;
1107- }
1108-
1109- protected:
1110-
1111- DWORD open(LPCTSTR path)
1112- {
1113- close();
1114-
1115- // open dummy mp3 file
1116- m_hMp3File = ::CreateFile(
1117- path, GENERIC_WRITE, 0, NULL,
1118- TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
1119- );
1120-
1121- if(m_hMp3File == INVALID_HANDLE_VALUE)
1122- {
1123- return ::GetLastError();
1124- }
1125-
1126- return S_OK;
1127- }
1128-
1129- UInt16Array makeUTF16LE(const string_wide_from_utf8 &str) {
1130-
1131- LPCWSTR pStr = str.get_ptr();
1132- size_t len = ::lstrlenW(pStr);
1133- UInt16Array utf16(len + 2);
1134-
1135- utf16[0] = 0xfeff; // BOM
1136- ::CopyMemory(&utf16[1], str.get_ptr(), len * 2);
1137-
1138- // swap byte order (big endian to little endian);
1139- for(size_t i = 0; i < len + 1; i++) {
1140- utf16[i] = (utf16[i] << 8) | (utf16[i] >> 8);
1141- }
1142-
1143- utf16[len + 1] = 0; // add NULL character
1144-
1145- return utf16;
1146- }
1147-
1148- UInt16Array makeTextFrame(LPCSTR pFrameID, const UInt16Array &data) {
1149-
1150- UInt16Array frame(data.size() + 5);
1151-
1152- UINT32 size = static_cast<UINT32>(data.size() * 2 + 1); // add charset code size (1byte)
1153-
1154- const UCHAR *pUCFrameID = reinterpret_cast<const UCHAR *>(pFrameID);
1155- const UCHAR *pUCSize = reinterpret_cast<const UCHAR *>(&size);
1156-
1157- frame[0] = ((UINT16)pUCFrameID[1]) << 8 | pUCFrameID[0];
1158- frame[1] = ((UINT16)pUCFrameID[3]) << 8 | pUCFrameID[2];
1159-
1160- frame[2] = ((UINT16)pUCSize[2]) << 8 | pUCSize[3];
1161- frame[3] = ((UINT16)pUCSize[0]) << 8 | pUCSize[1];
1162-
1163- frame[4] = 0; // frame flag
1164-
1165- ::CopyMemory(&frame[5], &data[0], data.size() * 2);
1166-
1167- return frame;
1168- }
1169-
1170- void close() {
1171- if(m_hMp3File != INVALID_HANDLE_VALUE) {
1172- ::CloseHandle(m_hMp3File);
1173- m_hMp3File = INVALID_HANDLE_VALUE;
1174- }
1175- }
1176-
1177- DWORD writeHeader(UINT32 size)
1178- {
1179- UInt16Array header(5);
1180-
1181- header[0] = ((UINT16)'D') << 8 | (UCHAR)'I';
1182- header[1] = ((UINT16) 3 ) << 8 | (UCHAR)'3';
1183-
1184- header[2] = 0;
1185-
1186- UInt16Array length = makeLength(size);
1187-
1188- header[3] = length[0];
1189- header[4] = length[1];
1190-
1191- DWORD dwSize;
1192- if(!::WriteFile(m_hMp3File, &header[0], 10, &dwSize, NULL)) {
1193- return ::GetLastError();
1194- }
1195-
1196- return S_OK;
1197- }
1198-
1199- DWORD writeTextFrame(const UInt16Array &packet)
1200- {
1201- DWORD dwErr = S_OK;
1202-
1203- UCHAR charsetCode = 0x01; // UNICODE
1204-
1205- DWORD dwSize;
1206- if(!::WriteFile(m_hMp3File, &packet[0], 10, &dwSize, NULL)) {
1207- return ::GetLastError();
1208- }
1209- if(!::WriteFile(m_hMp3File, &charsetCode, 1, &dwSize, NULL)) {
1210- return ::GetLastError();
1211- }
1212- if(!::WriteFile(m_hMp3File, &packet[5], static_cast<DWORD>(packet.size() * 2 - 10), &dwSize, NULL)) {
1213- return ::GetLastError();
1214- }
1215-
1216- return S_OK;
1217- }
1218-
1219- UInt16Array makeLength(UINT32 size)
1220- {
1221- UInt16Array length(2);
1222- UCHAR sizes[4];
1223-
1224- /*
1225- 00001111111111111111111111111111
1226-
1227- 1111111000000000000000000000
1228- f e 0 0 0 0 0
1229- 111111100000000000000
1230- 1 f c 0 0 0
1231- 11111110000000
1232- 3 f 8 0
1233- 1111111
1234- 7 f
1235- */
1236-
1237- sizes[3] = static_cast<UCHAR>((size & 0x0000007f) >> 0);
1238- sizes[2] = static_cast<UCHAR>((size & 0x00003f80) >> 7);
1239- sizes[1] = static_cast<UCHAR>((size & 0x001fc000) >> 14);
1240- sizes[0] = static_cast<UCHAR>((size & 0x0fe00000) >> 21);
1241-
1242-
1243- length[0] = ((UINT16)sizes[1]) << 8 | sizes[0];
1244- length[1] = ((UINT16)sizes[3]) << 8 | sizes[2];
1245-
1246- return length;
1247- }
1248-
1249- protected:
1250-
1251- TrackInfo m_info;
1252- HANDLE m_hMp3File;
1253-};
1254-
1255-class DummyAmp
1256-{
1257- public:
1258-
1259- DummyAmp()
1260- : m_bReady(false)
1261- , m_hInstGenMixi((HINSTANCE)INVALID_HANDLE_VALUE)
1262- , m_pGenMixi(NULL)
1263- , m_hWinampWnd((HWND)INVALID_HANDLE_VALUE)
1264- , m_GETPLAYLISTFILE_time(0)
1265- , m_hDirChangeNotify((HANDLE)INVALID_HANDLE_VALUE)
1266- , m_isDummyPlayInfoMp3Available(false)
1267- , m_isAnotherWinampWindowAvailable(false)
1268- {
1269-
1270- m_winampTitle = _T("Winamp");
1271- }
1272-
1273- ~DummyAmp()
1274- {
1275- release();
1276- destroyWindow();
1277- closeDirChangeNotifyHandle();
1278- }
1279-
1280- public:
1281-
1282- static DummyAmp *getInstance()
1283- {
1284- if(m_pMe == NULL)
1285- {
1286- m_pMe = new DummyAmp();
1287- }
1288-
1289- return m_pMe;
1290- }
1291-
1292- void load()
1293- {
1294- TRACE_DUMMYAMP_INIT(_T("DummyAmp::load - called."));
1295-
1296- // initialize gen_mixi_for_winamp
1297- initGenMixi();
1298-
1299- // initialize dummy mp3 file, if dummy mp3 is enabled
1300- if(cfg_disable_dummy_mp3 == 0) {
1301- initDummyMp3();
1302- }
1303-
1304- // set ready flag, if initialization successfully done
1305- if( (getGenMixi() != NULL) && ((cfg_disable_dummy_mp3 == 0) || (isDummyPlayInfoMp3Available() == true)) ){
1306- setReady(true);
1307- }
1308- }
1309-
1310- void config()
1311- {
1312- TRACE_DUMMYAMP_INIT(_T("DummyAmp::config - called."));
1313-
1314- if(getGenMixi() != NULL) {
1315- getGenMixi()->config();
1316- }
1317- }
1318-
1319- void release()
1320- {
1321- TRACE_DUMMYAMP_INIT(_T("DummyAmp::release - called."));
1322-
1323- // finalize gen_mixi_for_winamp
1324- finalizeGenMixi();
1325-
1326- // finalize dummy mp3 file, if dummy mp3 is enbaled
1327- if(isDummyPlayInfoMp3Available())
1328- {
1329- finalizeDummyMp3();
1330- }
1331- }
1332-
1333- void clearDummyAmpTitle()
1334- {
1335- uSetWindowText(getWnd(), DEFAULT_DUMMYAMP_TITLE);
1336- }
1337-
1338- void createWindow()
1339- {
1340- TRACE_PLUGIN(_T("DummyAmp::createWindow - called."));
1341-
1342- if(getWnd() == INVALID_HANDLE_VALUE)
1343- {
1344- if(getGenMixi() != NULL)
1345- {
1346- HWND hAnotherWinamp = FindWindowEx(NULL, NULL, _T("Winamp v1.x"), NULL);
1347-
1348- // found another winamp window
1349- if(hAnotherWinamp != NULL)
1350- {
1351- DEBUG_PLUGIN(_T("DummyAmp::createWindow - Winamp のウィンドウを検出しました。ハンドル: %08x"), hAnotherWinamp);
1352-
1353- DWORD dwAnotherWndProcessID;
1354- ::GetWindowThreadProcessId(hAnotherWinamp, &dwAnotherWndProcessID);
1355-
1356- DWORD dwFb2kProcessID = ::GetCurrentProcessId();
1357-
1358- DEBUG_PLUGIN(_T("DummyAmp::createWindow - Winamp ウィンドウが属するプロセスのハンドル: %08x"), dwAnotherWndProcessID);
1359- DEBUG_PLUGIN(_T("DummyAmp::createWindow - 現在実行中の foobar2000 プロセスのハンドル: %08x"), dwFb2kProcessID);
1360-
1361- // another winamp window owned by foobar2000 process
1362- if(dwAnotherWndProcessID == dwFb2kProcessID) {
1363- // subclass it, because it's winamp api simulator plugin's window
1364- setWnd(subclassWinampWindow(hAnotherWinamp));
1365- } else {
1366- LOG_ERROR(
1367- _T("DummyAmp::createWindow - 検出した Winamp ウィンドウが他のプロセスに属しています"));
1368- LOG_ERROR(
1369- _T("DummyAmp::createWindow - Winamp と思われるプログラムが実行されているため、")
1370- _T("mixi station への送信機能は使用できません"));
1371- LOG_ERROR(
1372- _T("DummyAmp::createWindow - 該当のプログラム(プロセスID:%d)を終了し、")
1373- _T("foobar2000 を再起動してください")
1374- , dwAnotherWndProcessID);
1375-
1376- // unset dummyAmp ready flag
1377- setReady(false);
1378- }
1379- }
1380- // create own winamp simulating window
1381- else
1382- {
1383- setWnd(createWinampWindow());
1384- }
1385-
1386- // initialize gen_mixi_for_winamp, if winamp window successfully created or subclassed
1387- if(getWnd() != INVALID_HANDLE_VALUE)
1388- {
1389- getGenMixi()->hwndParent = getWnd();
1390- getGenMixi()->hDllInstance = getHInstance();
1391- getGenMixi()->init();
1392- }
1393- else
1394- {
1395- // unset dummyAmp ready flag
1396- setReady(false);
1397- }
1398- }
1399- }
1400- }
1401-
1402- void refreshAmpInfo()
1403- {
1404-#if !defined(CONTROL_SEND_TIMING)
1405- // increment play counter on dummyamp
1406- getPlayInfo().incrementPlayCount();
1407-
1408- // update dummyamp title
1409- updateDummyAmpTitle();
1410-#endif
1411- // use currently playing mp3 or ogg/vorbis file instead when dummy playinfo mp3 file disabled by user
1412- // (other codec types will be ignored, because they are not supported by gen_mixi_for_winamp)
1413- if(cfg_disable_dummy_mp3 == 1)
1414- {
1415- // set playinfo mp3 file path to dummyAmp
1416- getPlayInfo().setPlayInfoMp3Path(m_trackInfo.getString(FORMAT_FILEPATH).c_str());
1417-
1418- // set playinfo mp3 file available flag to dummyAmp
1419- LPCSTR codec = m_trackInfo.getString(FORMAT_CODEC).c_str();
1420- getPlayInfo().setPlayInfoMp3Available(IS_SUPPORTED_FORMAT_BY_GEN_MIXI(codec));
1421- }
1422- else
1423- {
1424- // check dummy playinfo mp3 exists and writable
1425- if(isDummyPlayInfoMp3Available())
1426- {
1427- // update dummy mp3 file
1428- tstring playInfoMp3Path = PathInfo::getDummyPlayInfoMp3Path();
1429-#if 1
1430- id3Info id3Info(m_trackInfo);
1431- DWORD dwErrCode;
1432-
1433- if(( dwErrCode = id3Info.write(playInfoMp3Path.c_str()) ) == S_OK)
1434- {
1435- string_utf8_from_os dummyMp3Path8(playInfoMp3Path.c_str());
1436-
1437- // set dummy playinfo mp3 file path to dummyAmp
1438- getPlayInfo().setPlayInfoMp3Path(dummyMp3Path8);
1439-
1440- // set playinfo mp3 file available flag to dummyAmp
1441- getPlayInfo().setPlayInfoMp3Available(true);
1442- }
1443- else
1444- {
1445- putLogError(_T("DummyAmp::refreshAmpInfo"), _T("ダミーMP3ファイルの書き込み中にエラーが発生しました"), dwErrCode);
1446- LOG_ERROR(_T("DummyAmp::refreshAmpInfo - ファイルパス: %s"), playInfoMp3Path.c_str());
1447-
1448- // set playinfo mp3 file available flag
1449- getPlayInfo().setPlayInfoMp3Available(false);
1450-
1451- // unset dummyAmp ready flag
1452- setReady(false);
1453- }
1454-#else
1455- // set id3v2 informations
1456-
1457- string_utf8_from_os dummyMp3Path8(playInfoMp3Path.c_str());
1458- string_ansi_from_utf8 dummyMp3PathAnsi(dummyMp3Path8);
1459- ID3_Tag dummySong(dummyMp3PathAnsi);
1460-
1461- string_wide_from_utf8 title_utf16(m_trackInfo.getString(FORMAT_TRACKTITLE, true).c_str());
1462- string_wide_from_utf8 artist_utf16(m_trackInfo.getString(FORMAT_ARTIST, true).c_str());
1463- string_wide_from_utf8 album_utf16(m_trackInfo.getString(FORMAT_ALBUMTITLE, true).c_str());
1464- string_wide_from_utf8 genre_utf16(m_trackInfo.getString(FORMAT_GENRE, true).c_str());
1465-
1466- AddTitle(&dummySong, title_utf16, true);
1467- AddArtist(&dummySong, artist_utf16, true);
1468- AddAlbum(&dummySong, album_utf16, true);
1469- AddGenre(&dummySong, genre_utf16, true);
1470-
1471- // write id3v2 tag
1472- dummySong.SetPadding(false);
1473- dummySong.SetUnsync(false);
1474- if(dummySong.Update(ID3TT_ID3V2) != ID3TT_NONE)
1475- {
1476- // set dummy playinfo mp3 file path to dummyAmp
1477- getPlayInfo().setPlayInfoMp3Path(dummyMp3Path8);
1478-
1479- // set playinfo mp3 file available flag to dummyAmp
1480- getPlayInfo().setPlayInfoMp3Available(true);
1481- }
1482- else
1483- {
1484- LOG_ERROR(_T("DummyAmp::refreshAmpInfo - ID3_Tag::Update(ID3TT_ID3V2) failed."));
1485-
1486- // set playinfo mp3 file available flag
1487- getPlayInfo().setPlayInfoMp3Available(false);
1488-
1489- // unset dummyAmp ready flag
1490- setReady(false);
1491- }
1492-#endif
1493- }
1494- else
1495- {
1496- // reset playinfo mp3 file available flag
1497- getPlayInfo().setPlayInfoMp3Available(false);
1498-
1499- LOG_WARN(_T("DummyAmp::refreshAmpInfo - ダミーMP3ファイルが無効になっているため、送信情報を書き込めません。"));
1500- }
1501- }
1502-
1503-#if !defined(CONTROL_SEND_TIMING)
1504- // set dummyamp status PLAY_START
1505- getPlayInfo().setPlayStatusStart();
1506-#endif
1507- }
1508-
1509- public:
1510-
1511- bool isReady() const {
1512- return m_bReady;
1513- }
1514-
1515- HWND getWnd() const {
1516- return m_hWinampWnd;
1517- }
1518-
1519- const TrackInfo &getTrackInfo() const {
1520- return m_trackInfo;
1521- }
1522-
1523- TrackInfo &getMutableTrackInfo() {
1524- return m_trackInfo;
1525- }
1526-
1527- void setTrackInfo(const TrackInfo &trackInfo) {
1528- m_trackInfo = trackInfo;
1529- }
1530-
1531- PlayInfo &getPlayInfo() {
1532- return m_playInfo;
1533- }
1534-
1535- PlayInfo &getRawPlayInfo() {
1536- return m_rawPlayInfo;
1537- }
1538-
1539-
1540- void setPlaylistTitle(LPCTSTR pTitle) {
1541-
1542- TRACE_PLUGIN(_T("DummyAmp::setPlayListTitle - %s"), pTitle);
1543-
1544- m_playlistTitle = pTitle;
1545-
1546- string_utf8_from_os playListTitle8(pTitle);
1547-
1548- if(cfg_disable_ansi_trans == 1)
1549- {
1550-
1551- m_playlistTitle8 = playListTitle8;
1552- }
1553- else
1554- {
1555- string_ansi_from_utf8 playListTitleAnsi(playListTitle8);
1556-
1557- m_playlistTitle8 = playListTitleAnsi;
1558- }
1559- }
1560-
1561- const tstring &getPlaylistTitle() const {
1562- return m_playlistTitle;
1563- }
1564-
1565- const string8 &getPlaylistTitle8() const {
1566- return m_playlistTitle8;
1567- }
1568-
1569- void setWinampTitle(LPCTSTR pTitle) {
1570-
1571- TRACE_PLUGIN(_T("DummyAmp::setWinampTitle - %s"), pTitle);
1572-
1573- m_winampTitle = pTitle;
1574- }
1575-
1576- const tstring &getWinampTitle() const {
1577- return m_winampTitle;
1578- }
1579-
1580- void setBaseWinampTitle(LPCTSTR pTitle)
1581- {
1582- TRACE_PLUGIN(_T("DummyAmp::setRawWinampTitle - %s"), pTitle);
1583-
1584- m_baseWinampTitle = pTitle;
1585-
1586- updateDummyAmpTitle();
1587- }
1588-
1589- const tstring &getBaseWinampTitle() const {
1590- return m_baseWinampTitle;
1591- }
1592-
1593- const tstring &getDummyPlayInfoMp3Path() const {
1594- return m_dummyPlayInfoMp3Path;
1595- }
1596-
1597- bool isDummyPlayInfoMp3Available() const {
1598- return m_isDummyPlayInfoMp3Available;
1599- }
1600-
1601- bool isAnotherWinampWindowAvailable() const {
1602- return m_isAnotherWinampWindowAvailable;
1603- }
1604-
1605- void showDummyAmpWindow(bool bShow) {
1606- showDummyAmpWindow(getWnd(), bShow);
1607- }
1608-
1609- protected:
1610-
1611- void initGenMixi()
1612- {
1613- string_os_from_utf8 path(cfg_gen_mixi_path);
1614- tstring genMixiPath = path;
1615- genMixiPath += GEN_MIXI_FILE_NAME;
1616-
1617- setHInstance(::LoadLibrary(genMixiPath.c_str()));
1618-
1619- if(getHInstance() == NULL)
1620- {
1621- setHInstance((HINSTANCE)INVALID_HANDLE_VALUE);
1622-
1623- tstring msg;
1624- msg = GEN_MIXI_FILE_NAME _T(" が見つかりません。\n以下のパスにファイルが存在するか確認してください。\n");
1625- msg += genMixiPath;
1626-
1627- string_utf8_from_os uMsg(msg.c_str());
1628-
1629- uMessageBox(NULL, uMsg, PLUGIN_CAPTION, MB_ICONEXCLAMATION | MB_OK);
1630- }
1631- else
1632- {
1633- winampGeneralPurposePluginGetter funcWinampGetGeneralPurposePlugin = NULL;
1634-
1635- funcWinampGetGeneralPurposePlugin = (winampGeneralPurposePluginGetter)
1636- ::GetProcAddress(getHInstance(), GEN_MIXI_FUNC_NAME_GET_GENERAL_PURPOSE_PLUGIN);
1637-
1638- if(funcWinampGetGeneralPurposePlugin != NULL)
1639- {
1640- setGenMixi(funcWinampGetGeneralPurposePlugin());
1641- // create window later.
1642- }
1643- else
1644- {
1645- tstring msg;
1646- msg = _T("関数 ") _T(GEN_MIXI_FUNC_NAME_GET_GENERAL_PURPOSE_PLUGIN) _T("() が見つかりません。\n")
1647- GEN_MIXI_FILE_NAME _T(" が壊れている可能性があります。");
1648-
1649- string_utf8_from_os uMsg(msg.c_str());
1650-
1651- uMessageBox(NULL, uMsg, PLUGIN_CAPTION, MB_ICONEXCLAMATION | MB_OK);
1652- }
1653- }
1654- }
1655-
1656- void initDummyMp3()
1657- {
1658- // if dummy mp3 file not exist
1659- tstring dummyPlayInfoMp3Path = PathInfo::getDummyPlayInfoMp3Path();
1660- DWORD dwAttr = ::GetFileAttributes(dummyPlayInfoMp3Path.c_str());
1661-
1662- if(dwAttr == -1)
1663- {
1664- // create dummy mp3 file
1665- HANDLE hMp3File = ::CreateFile(
1666- dummyPlayInfoMp3Path.c_str(), 0, 0, NULL,
1667- CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL
1668- );
1669-
1670- if(hMp3File == INVALID_HANDLE_VALUE)
1671- {
1672- DWORD dwErrCode = ::GetLastError();
1673- putLogError(_T("DummyAmp::initDummyMp3"), _T("ダミーMP3ファイルの作成中にエラーが発生しました"), dwErrCode);
1674- LOG_ERROR(_T("DummyAmp::initDummyMp3 - ファイルパス: %s"), dummyPlayInfoMp3Path.c_str());
1675-
1676- LOG_ERROR(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルが使用できないため、送信機能は無効になります"));
1677- }
1678- else
1679- {
1680- DEBUG_DUMMYAMP_INIT(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルを [%s] に作成しました"), dummyPlayInfoMp3Path.c_str());
1681-
1682- ::CloseHandle(hMp3File);
1683-
1684- setDummyPlayInfoMp3Path(dummyPlayInfoMp3Path);
1685- setDummyPlayInfoMp3Available(true);
1686- }
1687- }
1688- else if((dwAttr & FILE_ATTRIBUTE_READONLY) != 0)
1689- {
1690- LOG_ERROR(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルがパス [%s] 上に既に存在しますが、")
1691- _T("読み込み専用属性のため書き込みできません"), dummyPlayInfoMp3Path.c_str());
1692-
1693- LOG_ERROR(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルが使用できないため、送信機能は無効になります"));
1694- }
1695- else
1696- {
1697- LOG_WARN(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルがパス [%s] 上に既に存在します"), dummyPlayInfoMp3Path.c_str());
1698- LOG_WARN(_T("DummyAmp::initDummyMp3 - このMP3ファイルは逐次上書きされ、終了時に削除されます"));
1699-
1700- setDummyPlayInfoMp3Path(dummyPlayInfoMp3Path);
1701- setDummyPlayInfoMp3Available(true);
1702- }
1703- }
1704-
1705- void finalizeGenMixi()
1706- {
1707- if(getHInstance() != INVALID_HANDLE_VALUE)
1708- {
1709- if(getGenMixi() != NULL)
1710- {
1711- getGenMixi()->quit();
1712- setGenMixi(NULL);
1713- }
1714- ::FreeLibrary(getHInstance());
1715- setHInstance((HINSTANCE)INVALID_HANDLE_VALUE);
1716- }
1717-
1718- }
1719-
1720- void finalizeDummyMp3()
1721- {
1722- tstring dummyPlayInfoMp3Path = getDummyPlayInfoMp3Path();
1723-
1724- if(::DeleteFile(dummyPlayInfoMp3Path.c_str()) == FALSE)
1725- {
1726- DWORD dwErrCode = ::GetLastError();
1727- putLogError(_T("DummyAmp::finalizeDummyMp3"), _T("ダミーMP3ファイルの削除中にエラーが発生しました"), dwErrCode);
1728- LOG_ERROR(_T("DummyAmp::finalizeDummyMp3 - ファイルパス: %s"), dummyPlayInfoMp3Path.c_str());
1729- }
1730- else
1731- {
1732- DEBUG_DUMMYAMP_INIT(_T("DummyAmp::finalizeDummyMp3 - ダミーMP3ファイル [%s] を削除しました"), dummyPlayInfoMp3Path.c_str());
1733- setDummyPlayInfoMp3Available(false);
1734- }
1735- }
1736-
1737- void updateDummyAmpTitle()
1738- {
1739- bool bDisableDuplicatedSong = (cfg_disable_duplicate_song == 0);
1740- tstring winampTitle = makeDummyAmpTitle(getBaseWinampTitle(), bDisableDuplicatedSong);
1741-
1742- setWinampTitle(winampTitle.c_str());
1743-
1744- if(isAnotherWinampWindowAvailable() == false) {
1745- ::SetWindowText(getWnd(), winampTitle.c_str());
1746- }
1747- }
1748-
1749- protected:
1750-
1751- void setReady(bool bReady) {
1752- m_bReady = bReady;
1753- }
1754-
1755- void setWnd(HWND hWnd) {
1756- m_hWinampWnd = hWnd;
1757- }
1758-
1759- HINSTANCE getHInstance() const {
1760- return m_hInstGenMixi;
1761- }
1762-
1763- void setHInstance(HINSTANCE hInst) {
1764- m_hInstGenMixi = hInst;
1765- }
1766-
1767- winampGeneralPurposePlugin *getGenMixi() const {
1768- return m_pGenMixi;
1769- }
1770-
1771- void setGenMixi(winampGeneralPurposePlugin *pGenMixi) {
1772- m_pGenMixi = pGenMixi;
1773- }
1774-
1775- void setDummyPlayInfoMp3Path(const tstring &path) {
1776- m_dummyPlayInfoMp3Path = path;
1777- }
1778-
1779- void setDummyPlayInfoMp3Available(bool isAvailable) {
1780- m_isDummyPlayInfoMp3Available = isAvailable;
1781- }
1782-
1783- void setAnotherWinampWindowAvailable(bool isAvailable) {
1784- m_isAnotherWinampWindowAvailable = isAvailable;
1785- }
1786-
1787- int getGetPlayListFileTime() const {
1788- return m_GETPLAYLISTFILE_time;
1789- }
1790-
1791- void setGetPlayListFileTime(int time) {
1792- m_GETPLAYLISTFILE_time = time;
1793- }
1794-
1795- HANDLE getDirChangeNotifyHandle() const {
1796- return m_hDirChangeNotify;
1797- }
1798-
1799- void setDirChangeNotifyHandle(HANDLE handle) {
1800- m_hDirChangeNotify = handle;
1801- }
1802-
1803- protected:
1804-
1805- HWND createWinampWindow()
1806- {
1807- TRACE_PLUGIN(_T("DummyAmp::createWinampWindow - called."));
1808-
1809- static bool isInited = false;
1810-
1811-#if IS_FB2K_VER08
1812- static const char class_name[] = "Winamp v1.x";
1813- if (!isInited)
1814- {
1815- isInited = true;
1816- uWNDCLASS wc;
1817- memset(&wc,0,sizeof(wc));
1818- wc.style = 0;
1819- wc.lpfnWndProc = windowproc;
1820- wc.hInstance = core_api::get_my_instance();
1821- wc.hCursor = NULL; //uLoadCursor(0, IDC_ARROW);
1822- wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
1823- wc.lpszClassName = class_name;
1824- uRegisterClass(&wc);
1825- }
1826- HWND hWinampWnd = uCreateWindowEx(
1827- 0, class_name, DEFAULT_DUMMYAMP_TITLE,
1828- WS_OVERLAPPED|WS_CAPTION|WS_SIZEBOX,
1829- CW_USEDEFAULT, CW_USEDEFAULT, 300, 150,
1830-#if 1
1831- core_api::get_main_window(), 0, core_api::get_my_instance(), NULL
1832-#else
1833- NULL, 0, core_api::get_my_instance(), NULL
1834-#endif
1835- );
1836-#elif IS_FB2K_VER09
1837- static const TCHAR class_name[] = _T("Winamp v1.x");
1838- if (!isInited)
1839- {
1840- isInited = true;
1841- WNDCLASS wc;
1842- memset(&wc,0,sizeof(wc));
1843- wc.style = 0;
1844- wc.lpfnWndProc = windowproc;
1845- wc.hInstance = core_api::get_my_instance();
1846- wc.hCursor = NULL; //uLoadCursor(0, IDC_ARROW);
1847- wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
1848- wc.lpszClassName = class_name;
1849- RegisterClass(&wc);
1850- }
1851- HWND hWinampWnd = CreateWindowEx(
1852- 0, class_name, _T(DEFAULT_DUMMYAMP_TITLE),
1853- WS_OVERLAPPED|WS_CAPTION|WS_SIZEBOX,
1854- CW_USEDEFAULT, CW_USEDEFAULT, 300, 150,
1855-#if 1
1856- core_api::get_main_window(), 0, core_api::get_my_instance(), NULL
1857-#else
1858- NULL, 0, core_api::get_my_instance(), NULL
1859-#endif
1860- );
1861-#endif
1862- if (!hWinampWnd)
1863- {
1864- DWORD dwErrCode = ::GetLastError();
1865- putLogError(_T("DummyAmp::createWinampWindow"), _T("DummyAmp ウィンドウの生成に失敗しました"), dwErrCode);
1866-
1867- return NULL;
1868- }
1869-
1870- DEBUG_PLUGIN(_T("DummyAmp::createWinampWindow - DummyAmp ウィンドウを生成しました"));
1871-
1872- showDummyAmpWindow(hWinampWnd, cfg_show_dummyamp == 1);
1873-
1874- return hWinampWnd;
1875- }
1876-
1877- HWND subclassWinampWindow(HWND hAnotherWinampWnd) {
1878- // subclass another dummyamp window
1879- m_pfnOldAnotherWinampProc =
1880- SetWindowLongPtr(hAnotherWinampWnd, GWL_WNDPROC, WNDPROC_TO_LONG_PTR(hookWinampWindowProc));
1881-
1882- if(hAnotherWinampWnd != NULL)
1883- {
1884- DEBUG_PLUGIN(_T("DummyAmp::subclassWinampWindow - API エミュレータと思われる Winamp ウィンドウのプロシージャをフックしました"));
1885- setAnotherWinampWindowAvailable(true);
1886-
1887- return hAnotherWinampWnd;
1888- }
1889- else
1890- {
1891- DWORD dwErrCode = ::GetLastError();
1892- putLogError(_T("DummyAmp::subclassWinampWindow"), _T("Winamp ウィンドウのサブクラス化に失敗しました"), dwErrCode);
1893-
1894- LOG_ERROR(_T("DummyAmp::subclassWinampWindow - Winamp ウィンドウのプロシージャをフックできなかったため、送信機能は無効になります"));
1895- }
1896-
1897- return (HWND)INVALID_HANDLE_VALUE;
1898- }
1899-
1900- void unsubclassWinampWindow() {
1901- SetWindowLongPtr(getWnd(), GWL_WNDPROC, m_pfnOldAnotherWinampProc);
1902- }
1903-
1904- void showDummyAmpWindow(HWND hWinampWnd, bool bShow)
1905- {
1906- if(bShow) {
1907- ShowWindow(hWinampWnd, SW_SHOW);
1908- } else {
1909- ShowWindow(hWinampWnd, SW_HIDE);
1910- }
1911- }
1912-
1913- void destroyWindow()
1914- {
1915- TRACE_PLUGIN(_T("DummyAmp::destroyWindow - called."));
1916-
1917- if(getWnd() != INVALID_HANDLE_VALUE)
1918- {
1919- if(isAnotherWinampWindowAvailable() == false) {
1920- uDestroyWindow(getWnd());
1921- } else {
1922- unsubclassWinampWindow();
1923-
1924- DEBUG_PLUGIN(_T("DummyAmp::destroyWindow - Winamp ウィンドウのサブクラス化を解除しました"));
1925- }
1926-
1927- setWnd((HWND)INVALID_HANDLE_VALUE);
1928- }
1929- }
1930-
1931- void closeDirChangeNotifyHandle()
1932- {
1933- TRACE_PLUGIN(_T("DummyAmp::closeDirChangeNotifyHandle - called."));
1934-
1935- if(m_hDirChangeNotify != INVALID_HANDLE_VALUE)
1936- {
1937- ::FindCloseChangeNotification(m_hDirChangeNotify);
1938- TRACE_PLUGIN(_T("DummyAmp::closeDirChangeNotifyHandle - ディレクトリ変更通知イベントのハンドル (ID:%08x) を閉じました"), m_hDirChangeNotify);
1939-
1940- m_hDirChangeNotify = (HANDLE)INVALID_HANDLE_VALUE;
1941- }
1942- }
1943-
1944- tstring makeDummyAmpTitle(const tstring &rawTitle, bool bCounterReflection)
1945- {
1946- TRACE_PLUGIN(_T("DummyAmp::makeDummyAmpTitle - called."));
1947-
1948- Str64K formatBuf;
1949-
1950- if(bCounterReflection)
1951- {
1952- _stprintf_s(
1953- formatBuf, sizeof(formatBuf) / sizeof(TCHAR),
1954- _T("%d. %s - ") _T(DEFAULT_WINAMP_TITLE),
1955- getPlayInfo().getPlayCount(),
1956- (LPCTSTR)rawTitle.c_str()
1957- );
1958- }
1959- else
1960- {
1961- _stprintf_s(
1962- formatBuf, sizeof(formatBuf) / sizeof(TCHAR),
1963- _T("%d. %s - ") _T(DEFAULT_WINAMP_TITLE),
1964- m_trackInfo.getNumber(FORMAT_LISTINDEX),
1965- (LPCTSTR)rawTitle.c_str()
1966- );
1967- }
1968-
1969- return formatBuf;
1970- }
1971-
1972- void refreshTitle()
1973- {
1974- // get formatted dynamic titles
1975- string8 dummyAmp_title8;
1976- string8 playlist_title8;
1977-#if IS_FB2K_VER08
1978- metadb_handle *track = play_control::get()->get_now_playing();
1979- if(track)
1980- {
1981- play_control::get()->playback_format_title_ex(track, dummyAmp_title8, cfg_dummyamp_title_format, NULL, false, true);
1982- play_control::get()->playback_format_title_ex(track, playlist_title8, cfg_dummyamp_playlist_format, NULL, false, true);
1983- track->handle_release();
1984- }
1985-#elif IS_FB2K_VER09
1986- metadb_handle_ptr track;
1987- static_api_ptr_t<playback_control>()->get_now_playing(track);
1988-
1989- service_ptr_t<titleformat_object> titleformat;
1990-
1991- static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, cfg_dummyamp_title_format);
1992- static_api_ptr_t<playback_control>()->playback_format_title_ex(track, NULL, dummyAmp_title8, titleformat, NULL, play_control::display_level_all);
1993-
1994- static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, cfg_dummyamp_playlist_format);
1995- static_api_ptr_t<playback_control>()->playback_format_title_ex(track, NULL, playlist_title8, titleformat, NULL, play_control::display_level_all);
1996-#endif
1997- // convert utf8 track informations to os charset
1998- string_os_from_utf8 dummyAmp_title(dummyAmp_title8);
1999- string_os_from_utf8 playlist_title(playlist_title8);
2000-
2001- // set base dummyamp title to dummyamp
2002- setBaseWinampTitle(dummyAmp_title);
2003-
2004- // set dummyamp playlist current item title to dummyamp
2005- setPlaylistTitle(playlist_title);
2006- }
2007-
2008-#if 0
2009- private:
2010-
2011- ID3_Frame* AddArtist(ID3_Tag *tag, const wchar_t *text, bool replace)
2012- {
2013- ID3_Frame* frame = NULL;
2014- if (NULL != tag && NULL != text && lstrlen(text) > 0)
2015- {
2016- if (replace)
2017- {
2018- RemoveArtists(tag);
2019- }
2020- if (replace ||
2021- (tag->Find(ID3FID_LEADARTIST) == NULL &&
2022- tag->Find(ID3FID_BAND) == NULL &&
2023- tag->Find(ID3FID_CONDUCTOR) == NULL &&
2024- tag->Find(ID3FID_COMPOSER) == NULL))
2025- {
2026- frame = new ID3_Frame(ID3FID_LEADARTIST);
2027- if (frame)
2028- {
2029- frame->GetField(ID3FN_TEXT)->SetEncoding(ID3TE_UNICODE);
2030- frame->GetField(ID3FN_TEXT)->Set(SwapByteOrder(text));
2031- frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_UNICODE);
2032- tag->AttachFrame(frame);
2033- }
2034- }
2035- }
2036- return frame;
2037- }
2038-
2039- size_t RemoveArtists(ID3_Tag *tag)
2040- {
2041- size_t num_removed = 0;
2042- ID3_Frame *frame = NULL;
2043-
2044- if (NULL == tag)
2045- {
2046- return num_removed;
2047- }
2048-
2049- while ((frame = tag->Find(ID3FID_LEADARTIST)) != NULL)
2050- {
2051- frame = tag->RemoveFrame(frame);
2052- delete frame;
2053- num_removed++;
2054- }
2055- while ((frame = tag->Find(ID3FID_BAND)) != NULL)
2056- {
2057- frame = tag->RemoveFrame(frame);
2058- delete frame;
2059- num_removed++;
2060- }
2061- while ((frame = tag->Find(ID3FID_CONDUCTOR)) != NULL)
2062- {
2063- frame = tag->RemoveFrame(frame);
2064- delete frame;
2065- num_removed++;
2066- }
2067- while ((frame = tag->Find(ID3FID_COMPOSER)) != NULL)
2068- {
2069- frame = tag->RemoveFrame(frame);
2070- delete frame;
2071- num_removed++;
2072- }
2073-
2074- return num_removed;
2075- }
2076-
2077- ID3_Frame* AddAlbum(ID3_Tag *tag, const wchar_t *text, bool replace)
2078- {
2079- ID3_Frame* frame = NULL;
2080- if (NULL != tag && NULL != text && lstrlen(text) > 0)
2081- {
2082- if (replace)
2083- {
2084- RemoveAlbums(tag);
2085- }
2086- if (replace || tag->Find(ID3FID_ALBUM) == NULL)
2087- {
2088- frame = new ID3_Frame(ID3FID_ALBUM);
2089- if (frame)
2090- {
2091- frame->GetField(ID3FN_TEXT)->SetEncoding(ID3TE_UNICODE);
2092- frame->GetField(ID3FN_TEXT)->Set(SwapByteOrder(text));
2093- frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_UNICODE);
2094- tag->AttachFrame(frame);
2095- }
2096- }
2097- }
2098-
2099- return frame;
2100- }
2101-
2102- size_t RemoveAlbums(ID3_Tag *tag)
2103- {
2104- size_t num_removed = 0;
2105- ID3_Frame *frame = NULL;
2106-
2107- if (NULL == tag)
2108- {
2109- return num_removed;
2110- }
2111-
2112- while ((frame = tag->Find(ID3FID_ALBUM)) != NULL)
2113- {
2114- frame = tag->RemoveFrame(frame);
2115- delete frame;
2116- num_removed++;
2117- }
2118-
2119- return num_removed;
2120- }
2121-
2122- ID3_Frame* AddTitle(ID3_Tag *tag, const wchar_t *text, bool replace)
2123- {
2124- ID3_Frame* frame = NULL;
2125- if (NULL != tag && NULL != text && lstrlen(text) > 0)
2126- {
2127- if (replace)
2128- {
2129- RemoveTitles(tag);
2130- }
2131- if (replace || tag->Find(ID3FID_TITLE) == NULL)
2132- {
2133- frame = new ID3_Frame(ID3FID_TITLE);
2134- if (frame)
2135- {
2136- frame->GetField(ID3FN_TEXT)->SetEncoding(ID3TE_UNICODE);
2137- frame->GetField(ID3FN_TEXT)->Set(SwapByteOrder(text));
2138- frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_UNICODE);
2139- tag->AttachFrame(frame);
2140- }
2141- }
2142- }
2143-
2144- return frame;
2145- }
2146-
2147- size_t RemoveTitles(ID3_Tag *tag)
2148- {
2149- size_t num_removed = 0;
2150- ID3_Frame *frame = NULL;
2151-
2152- if (NULL == tag)
2153- {
2154- return num_removed;
2155- }
2156-
2157- while ((frame = tag->Find(ID3FID_TITLE)) != NULL)
2158- {
2159- frame = tag->RemoveFrame(frame);
2160- delete frame;
2161- num_removed++;
2162- }
2163-
2164- return num_removed;
2165- }
2166-
2167- //following routine courtesy of John George
2168- ID3_Frame* AddGenre(ID3_Tag* tag, const wchar_t *genre, bool replace)
2169- {
2170- ID3_Frame* frame = NULL;
2171- if (NULL != tag && NULL != genre && lstrlen(genre) > 0)
2172- {
2173- if (replace)
2174- {
2175- RemoveGenres(tag);
2176- }
2177- if (replace || NULL == tag->Find(ID3FID_CONTENTTYPE))
2178- {
2179- frame = new ID3_Frame(ID3FID_CONTENTTYPE);
2180- if (NULL != frame)
2181- {
2182- frame->GetField(ID3FN_TEXT)->SetEncoding(ID3TE_UNICODE);
2183- frame->GetField(ID3FN_TEXT)->Set(SwapByteOrder(genre));
2184- frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_UNICODE);
2185- tag->AttachFrame(frame);
2186- }
2187- }
2188- }
2189-
2190- return frame;
2191- }
2192-
2193- size_t RemoveGenres(ID3_Tag *tag)
2194- {
2195- size_t num_removed = 0;
2196- ID3_Frame *frame = NULL;
2197-
2198- if (NULL == tag)
2199- {
2200- return num_removed;
2201- }
2202-
2203- while ((frame = tag->Find(ID3FID_CONTENTTYPE)) != NULL)
2204- {
2205- frame = tag->RemoveFrame(frame);
2206- delete frame;
2207- num_removed++;
2208- }
2209-
2210- return num_removed;
2211- }
2212-
2213- const unicode_t *SwapByteOrder(const wchar_t *text)
2214- {
2215- static unicode_t resBuf[65536];
2216- const wchar_t *pText;
2217- unicode_t *pBuf;
2218-
2219- for(pText = text, pBuf = resBuf; *pText != L'\0'; pText ++, pBuf ++)
2220- {
2221- wchar_t srcVal = *pText;
2222- //unicode_t dstVal = srcVal;
2223- unicode_t dstVal = (srcVal << 8) | (srcVal >> 8);
2224- *pBuf = dstVal;
2225- }
2226-
2227- *pBuf = L'\0';
2228-
2229- return resBuf;
2230- }
2231-#endif
2232-
2233- protected:
2234-
2235- static LRESULT WINAPI hookWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp);
2236- static LRESULT WINAPI windowproc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp);
2237- static std::pair<bool, LRESULT> WINAPI innerWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp);
2238- static std::pair<bool, LRESULT> WINAPI outerWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp);
2239-
2240- protected:
2241-
2242- static DummyAmp *m_pMe;
2243-
2244- bool m_bReady;
2245-
2246- HINSTANCE m_hInstGenMixi;
2247- winampGeneralPurposePlugin *m_pGenMixi;
2248-
2249- HWND m_hWinampWnd;
2250- bool m_isAnotherWinampWindowAvailable;
2251-
2252- static LONG_PTR m_pfnOldAnotherWinampProc;
2253-
2254- HANDLE m_hDirChangeNotify;
2255-
2256- PlayInfo m_playInfo;
2257- PlayInfo m_rawPlayInfo;
2258-
2259- TrackInfo m_trackInfo;
2260- int m_GETPLAYLISTFILE_time;
2261-
2262- tstring m_playlistTitle;
2263- string8 m_playlistTitle8;
2264-
2265- tstring m_winampTitle;
2266- tstring m_baseWinampTitle;
2267-
2268- tstring m_dummyPlayInfoMp3Path;
2269- bool m_isDummyPlayInfoMp3Available;
2270-};
2271-
2272-DummyAmp *DummyAmp::m_pMe = NULL;
2273-
2274-LONG_PTR DummyAmp::m_pfnOldAnotherWinampProc = NULL;
2275-
2276-LRESULT CALLBACK DummyAmp::hookWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp)
2277-{
2278- if(InSendMessage() || (msg != WM_WA_IPC))
2279- {
2280- switch(msg)
2281- {
2282- case WM_CLOSE:
2283- DEBUG_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_CLOSE %s"),
2284- InSendMessage() == TRUE ? _T("from other thread") : _T(""));
2285-
2286- DummyAmp::getInstance()->destroyWindow();
2287- break;
2288-
2289- case WM_GETTEXT:
2290- {
2291- // message from same thread
2292- if((InSendMessage() == FALSE) && (DummyAmp::getInstance()->isAnotherWinampWindowAvailable() == true))
2293- {
2294- LPCTSTR pWinampTitle = DummyAmp::getInstance()->getWinampTitle().c_str();
2295- int nLen = ::lstrlen(pWinampTitle);
2296- TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_GETTEXT / window title [%s]."), pWinampTitle);
2297-
2298- ::lstrcpyn(reinterpret_cast<LPTSTR>(lp), pWinampTitle, static_cast<int>(wp));
2299-
2300- return (LRESULT)nLen;
2301- }
2302- }
2303- break;
2304-
2305- case WM_GETTEXTLENGTH:
2306- {
2307- // message from same thread
2308- if((InSendMessage() == FALSE) && (DummyAmp::getInstance()->isAnotherWinampWindowAvailable() == true))
2309- {
2310- LPCTSTR pWinampTitle = DummyAmp::getInstance()->getWinampTitle().c_str();
2311- int nLen = ::lstrlen(pWinampTitle);
2312- TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_GETTEXTLENGTH / window title length %d."), nLen);
2313-
2314- return (LRESULT)nLen;
2315- }
2316- }
2317- break;
2318-
2319- case WM_SETTEXT:
2320- {
2321- // message from same thread
2322- if((InSendMessage() == FALSE) && (DummyAmp::getInstance()->isAnotherWinampWindowAvailable() == true))
2323- {
2324- TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_SETTEXT / window title [%s]."), reinterpret_cast<LPCTSTR>(lp));
2325- }
2326- }
2327- break;
2328-
2329- default:
2330-
2331- if(InSendMessage())
2332- {
2333- if(msg == WM_WA_IPC) {
2334- if(cfg_enable_ext_ipc_proc == 1)
2335- {
2336- std::pair<bool, LRESULT> res = outerWinampWindowProc(wnd, msg, wp, lp);
2337- if(res.first == true) {
2338- return res.second;
2339- }
2340- }
2341-
2342- TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_WA_IPC from other thread / W:%08x, L:%08x"), wp, lp);
2343-
2344- }
2345- else
2346- {
2347- TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - ")
2348- _T("message from other thread / MSG:%04x, W:%08x, L:%08x"), msg, wp, lp);
2349- }
2350- }
2351-
2352- break;
2353- }
2354-
2355- return CallWindowProc(LONG_PTR_TO_WNDPROC(m_pfnOldAnotherWinampProc), wnd, msg, wp, lp);
2356- }
2357- else
2358- {
2359- return CallWindowProc(windowproc, wnd, msg, wp, lp);
2360- }
2361-}
2362-
2363-LRESULT CALLBACK DummyAmp::windowproc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp)
2364-{
2365- switch(msg)
2366- {
2367- case WM_CLOSE:
2368- DEBUG_DUMMYAMP_PROC(_T("DummyAmp::windowproc - WM_CLOSE"));
2369- DummyAmp::getInstance()->destroyWindow();
2370- return 0;
2371-
2372- case WM_WA_IPC:
2373- // message from same thread
2374- if(InSendMessage() == FALSE)
2375- {
2376- std::pair<bool, LRESULT> res = innerWinampWindowProc(wnd, msg, wp, lp);
2377- if(res.first == true) {
2378- return res.second;
2379- }
2380- }
2381- // message from other thread
2382- else
2383- {
2384- std::pair<bool, LRESULT> res = outerWinampWindowProc(wnd, msg, wp, lp);
2385- if(res.first == true) {
2386- return res.second;
2387- }
2388- }
2389- break;
2390- default:
2391- if(InSendMessage()) {
2392- TRACE_DUMMYAMP_PROC(_T("DummyAmp::windowproc - Unknown MSG from other thread / MSG:%04x, W:%08x, L:%08x"), msg, wp, lp);
2393- }
2394- break;
2395- }
2396-
2397- return uDefWindowProc(wnd,msg,wp,lp);
2398-}
2399-
2400-std::pair<bool, LRESULT> WINAPI DummyAmp::innerWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp)
2401-{
2402- switch(msg)
2403- {
2404- case WM_WA_IPC:
2405- {
2406- PlayInfo::EPlayStatus playStatus = DummyAmp::getInstance()->getPlayInfo().getPlayStatus();
2407- int playPosition = DummyAmp::getInstance()->getPlayInfo().getPlayPosition();
2408- int playLength = DummyAmp::getInstance()->getPlayInfo().getPlayLength();
2409- int playCount = DummyAmp::getInstance()->getPlayInfo().getPlayCount();
2410- int getPlayListFileTime = DummyAmp::getInstance()->getGetPlayListFileTime();
2411- bool isPlayInfoMp3Available = DummyAmp::getInstance()->getPlayInfo().isPlayInfoMp3Available();
2412- const string8 &playInfoMp3Path8 = DummyAmp::getInstance()->getPlayInfo().getPlayInfoMp3Path8();
2413-
2414- switch(lp)
2415- {
2416- case IPC_ISPLAYING:
2417- if(cfg_use_plugin == 1)
2418- {
2419- HANDLE hDirChangeNotify = DummyAmp::getInstance()->getDirChangeNotifyHandle();
2420-
2421- TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_ISPLAYING / status %d"), playStatus);
2422-
2423- if(playStatus != PlayInfo::PLAY_START)
2424- {
2425- if(DummyAmp::getInstance()->getPlayInfo().isResentMode()) {
2426- DummyAmp::getInstance()->getPlayInfo().clearResentMode();
2427- }
2428-
2429- if(hDirChangeNotify != INVALID_HANDLE_VALUE)
2430- {
2431- LOG_WARN(_T("DummyAmp::innerWinampWindowProc - ディレクトリ変更通知イベントのハンドルが閉じられていません"));
2432- LOG_WARN(_T("DummyAmp::innerWinampWindowProc - 安全のため、ここで閉じます"));
2433- DummyAmp::getInstance()->closeDirChangeNotifyHandle();
2434- }
2435- }
2436- else
2437- {
2438- if(hDirChangeNotify != INVALID_HANDLE_VALUE)
2439- {
2440- DWORD dwRes = ::WaitForMultipleObjects(1, &hDirChangeNotify, FALSE, 0);
2441-
2442- if(dwRes == WAIT_OBJECT_0)
2443- {
2444- LOG_INFO(_T("mixi station successfully updated."));
2445- DummyAmp::getInstance()->closeDirChangeNotifyHandle();
2446- DummyAmp::getInstance()->getPlayInfo().setPlayStatusStop();
2447- }
2448- else if(playPosition >= getPlayListFileTime + RESENT_INTERVAL)
2449- {
2450- DummyAmp::getInstance()->closeDirChangeNotifyHandle();
2451- LOG_WARN(_T("DummyAmp::innerWinampWindowProc - mixi station ディレクトリの変更通知イベントが待ち時間内に発生しませんでした"));
2452-#if !defined(DISABLE_KICK_GEN_MIXI_LOOP)
2453- LOG_WARN(_T("DummyAmp::innerWinampWindowProc - gen_mixi_for_winamp に曲情報取得要求を再送させます"));
2454- DummyAmp::getInstance()->getPlayInfo().setResentMode();
2455- DummyAmp::getInstance()->updateDummyAmpTitle();
2456-#else
2457- LOG_WARN(_T("DummyAmp::innerWinampWindowProc - 曲情報は破棄されました"));
2458-#endif
2459- }
2460- }
2461- }
2462- return std::make_pair(true, playStatus);
2463- }
2464- return std::make_pair(true, PlayInfo::PLAY_STOP);
2465-
2466- case IPC_GETOUTPUTTIME:
2467- if(cfg_use_plugin == 1)
2468- {
2469- if(playStatus == PlayInfo::PLAY_START)
2470- {
2471- if(wp == IPC_GETOUTPUTTIME_PositionMSec)
2472- {
2473- TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_GETOUTPUTTIME / position %d"), playPosition / 1000);
2474-
2475- return std::make_pair(true, playPosition);
2476- }
2477- else if(wp == IPC_GETOUTPUTTIME_TotalSec)
2478- {
2479- TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_GETOUTPUTTIME / length %d"), playLength);
2480- return std::make_pair(true, playLength);
2481- }
2482- }
2483- }
2484- return std::make_pair(true, -1);
2485-
2486- case IPC_GETLISTPOS:
2487- TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_GETLISTPOS / index %d returned."), playCount);
2488- return std::make_pair(true, playCount);
2489-
2490- case IPC_GETPLAYLISTFILE:
2491- if(cfg_use_plugin == 1)
2492- {
2493- if(isPlayInfoMp3Available == true)
2494- {
2495- DEBUG_DUMMYAMP_PROC8(
2496- "DummyAmp::innerWinampWindowProc - IPC_GETPLAYLISTFILE / #%d - path [%s] returned.",
2497- playCount, (LPCSTR)playInfoMp3Path8);
2498-
2499- DummyAmp::getInstance()->setGetPlayListFileTime(playPosition);
2500-
2501- tstring mixiAppDataPath = PathInfo::getMixiStationAppPath();
2502-
2503- DummyAmp::getInstance()->setDirChangeNotifyHandle(
2504- ::FindFirstChangeNotification(mixiAppDataPath.c_str(), FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE)
2505- );
2506-
2507- return std::make_pair(true, (LRESULT)(LPCSTR)playInfoMp3Path8);
2508- }
2509- else
2510- {
2511- if(cfg_disable_dummy_mp3 == 1)
2512- {
2513- DEBUG_DUMMYAMP_PROC(_T("DummyAm::innerWinampWindowProcp - IPC_GETPLAYLISTFILE / NULL (audio file codec type not supported.)"));
2514- }
2515- else
2516- {
2517- LOG_WARN(_T("DummyAmp::innerWinampWindowProc - IPC_GETPLAYLISTFILE / NULL (dummy mp3 file not enabled.)"));
2518- }
2519- }
2520- }
2521- return std::make_pair(true, NULL);
2522-
2523- case IPC_INTERNAL_REFRESHLISTINFO: // 0x4000
2524- {
2525- TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_INTERNAL_REFRESHLISTINFO / refresh internal playlist informations."));
2526-
2527- // make playlist info formats array
2528- Strings plNumKeys;
2529-
2530- plNumKeys.push_back(FORMAT_LISTINDEX);
2531-
2532- // set current track informations
2533- DummyAmp::getInstance()->getMutableTrackInfo().setPlaylistNumbers(plNumKeys);
2534-
2535- // refresh dummyamp title
2536- DummyAmp::getInstance()->refreshTitle();
2537-
2538- return std::make_pair(true, 0);
2539- }
2540-
2541- case IPC_INTERNAL_REFRESHDYNINFO: // 0x4001
2542- {
2543- TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_INTERNAL_REFRESHDYNINFO / refresh internal dynamic informations."));
2544-
2545- // make dynamic info formats array
2546- Strings dynStrKeys;
2547-
2548- dynStrKeys.push_back(FORMAT_ARTIST);
2549- dynStrKeys.push_back(FORMAT_TRACKTITLE);
2550- dynStrKeys.push_back(FORMAT_ALBUMTITLE);
2551- dynStrKeys.push_back(FORMAT_GENRE);
2552-
2553- // set current track informations
2554- DummyAmp::getInstance()->getMutableTrackInfo().removeStrings(dynStrKeys);
2555- DummyAmp::getInstance()->getMutableTrackInfo().setDynamicStrings(dynStrKeys);
2556-
2557- // refresh dummyamp title
2558- DummyAmp::getInstance()->refreshTitle();
2559-
2560- // when explicitly tagged file only mode and artist or track name not found,
2561- // then skip sending track informations
2562- string8 title_utf8 = DummyAmp::getInstance()->getTrackInfo().getString(FORMAT_TRACKTITLE, true).c_str();
2563- string8 artist_utf8 = DummyAmp::getInstance()->getTrackInfo().getString(FORMAT_ARTIST, true).c_str();
2564- string8 album_utf8 = DummyAmp::getInstance()->getTrackInfo().getString(FORMAT_ALBUMTITLE).c_str();
2565- string8 genre_utf8 = DummyAmp::getInstance()->getTrackInfo().getString(FORMAT_GENRE).c_str();
2566-
2567- if( (cfg_explicitly_tagged_file_only == 1) && (!lstrcmpA(title_utf8, "?") || !lstrcmpA(artist_utf8, "?")) )
2568- {
2569- DEBUG_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_INTERNAL_REFRESHDYNINFO / SKIP this track. (artist or title not found)"));
2570- }
2571- else
2572- {
2573- if(!lstrcmpA(title_utf8, "?"))
2574- {
2575- DummyAmp::getInstance()->getMutableTrackInfo().removeString(FORMAT_TRACKTITLE);
2576- DummyAmp::getInstance()->getMutableTrackInfo().putString(FORMAT_TRACKTITLE, (LPCSTR)cfg_no_title_name);
2577- }
2578-
2579- if(!lstrcmpA(artist_utf8, "?"))
2580- {
2581- DummyAmp::getInstance()->getMutableTrackInfo().removeString(FORMAT_ARTIST);
2582- DummyAmp::getInstance()->getMutableTrackInfo().putString(FORMAT_ARTIST, (LPCSTR)cfg_no_artist_name);
2583- }
2584-
2585- if(!lstrcmpA(album_utf8, "?"))
2586- {
2587- DummyAmp::getInstance()->getMutableTrackInfo().removeString(FORMAT_ALBUMTITLE);
2588- DummyAmp::getInstance()->getMutableTrackInfo().putString(FORMAT_ALBUMTITLE,(LPCSTR) cfg_no_album_name);
2589- }
2590-
2591- if(!lstrcmpA(genre_utf8, "?"))
2592- {
2593- DummyAmp::getInstance()->getMutableTrackInfo().removeString(FORMAT_GENRE);
2594- DummyAmp::getInstance()->getMutableTrackInfo().putString(FORMAT_GENRE, (LPCSTR)cfg_no_genre_name);
2595- }
2596-
2597- // refresh dummyamp info
2598- DummyAmp::getInstance()->refreshAmpInfo();
2599- }
2600-
2601- return std::make_pair(true, 0);
2602- }
2603-
2604- default:
2605- TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - WM_WA_IPC (Unknown IPC command) / W:%08x, L:%08x"), wp, lp);
2606- break;
2607- }
2608-
2609- }
2610- break;
2611- }
2612-
2613- return std::make_pair(false, 0);
2614-}
2615-
2616-std::pair<bool, LRESULT> WINAPI DummyAmp::outerWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp)
2617-{
2618- switch(msg)
2619- {
2620- case WM_WA_IPC:
2621- {
2622- PlayInfo::EPlayStatus rawPlayStatus = DummyAmp::getInstance()->getRawPlayInfo().getPlayStatus();
2623- int rawPlayPosition = DummyAmp::getInstance()->getRawPlayInfo().getPlayPosition();
2624- int rawPlayLength = DummyAmp::getInstance()->getRawPlayInfo().getPlayLength();
2625- int rawPlayCount = DummyAmp::getInstance()->getPlayInfo().getPlayCount();
2626- const string8 &rawPlayInfoMp3Path8 = DummyAmp::getInstance()->getRawPlayInfo().getPlayInfoMp3Path8();
2627- const tstring &playlistTitle = DummyAmp::getInstance()->getPlaylistTitle();
2628- const string8 &playlistTitle8 = DummyAmp::getInstance()->getPlaylistTitle8();
2629-
2630- switch(lp)
2631- {
2632- case IPC_ISPLAYING:
2633- TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_ISPLAYING / status %d"), rawPlayStatus);
2634- return std::make_pair(true, rawPlayStatus);
2635-
2636- case IPC_GETOUTPUTTIME:
2637-
2638- if(rawPlayStatus != PlayInfo::PLAY_START)
2639- {
2640- rawPlayPosition = -1;
2641- rawPlayLength = -1;
2642- }
2643- else if(true)
2644- {
2645-#if IS_FB2K_VER08
2646- rawPlayPosition = static_cast<int>(play_control::get()->get_playback_time() * 1000.0);
2647-#else IS_FB2K_VER09
2648- rawPlayPosition = static_cast<int>(static_api_ptr_t<playback_control>()->playback_get_position() * 1000.0);
2649-#endif
2650- }
2651-
2652- if(wp == IPC_GETOUTPUTTIME_PositionMSec)
2653- {
2654- TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_GETOUTPUTTIME / position %.3f"), rawPlayPosition / 1000.0);
2655- return std::make_pair(true, rawPlayPosition);
2656- }
2657- else if(wp == IPC_GETOUTPUTTIME_TotalSec)
2658- {
2659- TRACE_DUMMYAMP_PROC(_T("DummyAm::outerWinampWindowProcp - IPC_GETOUTPUTTIME / length %d"), rawPlayLength);
2660- return std::make_pair(true, rawPlayLength);
2661- }
2662-
2663- return std::make_pair(true, -1);
2664-
2665- case IPC_GETLISTPOS:
2666- TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_GETLISTPOS / index %d returned."), rawPlayCount);
2667- return std::make_pair(true, rawPlayCount);
2668-
2669- case IPC_GETPLAYLISTFILE:
2670- TRACE_DUMMYAMP_PROC8(
2671- "DummyAmp::outerWinampWindowProc - IPC_GETPLAYLISTFILE / path [%s] returned.", (LPCSTR)rawPlayInfoMp3Path8);
2672- return std::make_pair(true, (LRESULT)(LPCSTR)rawPlayInfoMp3Path8);
2673-
2674- case IPC_GETPLAYLISTTITLE:
2675- TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_GETPLAYLISTTITLE")
2676- _T(" / title [%s] returned."), (LPCTSTR)playlistTitle.c_str());
2677- return std::make_pair(true, (LRESULT)(LPCSTR)playlistTitle8);
2678-
2679- case IPC_JUMPTOTIME:
2680- if(rawPlayStatus == PlayInfo::PLAY_START)
2681- {
2682- double jumpPos = wp / 1000.0;
2683- TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_JUMPTOTIME")
2684- _T(" / jump to %.3f[sec.]"), jumpPos);
2685-
2686- if(jumpPos > rawPlayLength)
2687- {
2688- // eof
2689- return std::make_pair(true, 1);
2690- }
2691- else
2692- {
2693-#if IS_FB2K_VER08
2694- play_control::get()->playback_seek(jumpPos);
2695-#else IS_FB2K_VER09
2696- static_api_ptr_t<playback_control>()->playback_seek(jumpPos);
2697-#endif
2698- return std::make_pair(true, 0);
2699- }
2700-
2701- }
2702- return std::make_pair(true, -1);
2703-
2704- default:
2705- TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - WM_WA_IPC (Unknown IPC command) / W:%08x, L:%08x"), wp, lp);
2706- break;
2707- }
2708- }
2709- break;
2710- }
2711-
2712- return std::make_pair(false, 0);
2713-}
2714-
2715-#if defined(ENABLE_MSN)
2716-class MSNSender
2717-{
2718- public:
2719-
2720- static void SendTrackInfo(const TRACK_INFO_UTF8 &info)
2721- {
2722- string8 msg;
2723- msg += "\\0Music\\01\\0{0} - {1} - {2} - {3}\\0";
2724- msg += info.m_title;
2725- msg += "\\0";
2726- msg += info.m_artist;
2727- msg += "\\0";
2728- msg += info.m_album;
2729- msg += "\\0";
2730- msg += info.m_genre;
2731- msg += "\\0";
2732-
2733- console::info(msg);
2734-
2735- string_wide_from_utf8 tmp(msg);
2736- SendMessage(tmp);
2737- }
2738-
2739- static void SendMessage(LPCWSTR buf)
2740- {
2741- COPYDATASTRUCT copydata;
2742- int nSendBufLen = (::lstrlenW(buf)*2)+2;
2743-
2744- copydata.dwData = 0x0547;
2745- copydata.lpData = (void*)buf;
2746- copydata.cbData = nSendBufLen;
2747-
2748- HWND hMsnUi = NULL;
2749- hMsnUi = FindWindowEx(NULL, hMsnUi, _T("MsnMsgrUIManager"), _T("MSN Messenger式再生通知を受信する窓"));
2750- if ( hMsnUi == NULL )
2751- {
2752- ERROR(_T("MSNSender::SendMessage - M2M not found."));
2753- return ;
2754- }
2755-
2756- ::SendMessage(hMsnUi, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&copydata);
2757- LOG_INFO(_T("MSNSender::SendMessage - send track informations to M2M."));
2758- }
2759-};
2760-#endif
2761-
2762-#if IS_FB2K_VER08
2763-class play_callback_mixi : public play_callback
2764-#elif IS_FB2K_VER09
2765-class play_callback_mixi : public play_callback_static
2766-#endif
2767-{
2768-#if IS_FB2K_VER09
2769- virtual unsigned get_flags() {
2770- return flag_on_playback_all;
2771- }
2772-#endif
2773-
2774-#if IS_FB2K_VER08
2775- virtual void on_playback_starting()
2776-#elif IS_FB2K_VER09
2777- virtual void on_playback_starting(play_control::t_track_command command, bool paused)
2778-#endif
2779- {
2780- TRACE_CALLBACK(_T("play_callback_mixi::on_playback_starting - called."));
2781-
2782- // create my dummyamp window
2783- DummyAmp::getInstance()->createWindow();
2784- }
2785-
2786-#if IS_FB2K_VER08
2787- virtual void on_playback_new_track(metadb_handle * track)
2788-#elif IS_FB2K_VER09
2789- virtual void on_playback_new_track(metadb_handle_ptr track)
2790-#endif
2791- {
2792- TRACE_CALLBACK(_T("play_callback_mixi::on_playback_new_track - called."));
2793-
2794- if(DummyAmp::getInstance()->isReady() == false)
2795- {
2796- LOG_ERROR(_T("play_callback_mixi::on_playback_new_track - mixi station への送信機能はエラーにより無効化されています"));
2797- LOG_ERROR(_T("play_callback_mixi::on_playback_new_track - エラーの原因を取り除いた上で、foobar2000 を再起動してください"));
2798- return;
2799- }
2800-
2801-#if IS_FB2K_VER08
2802- bool isTrackInLibrary = track->handle_is_permcached() == 1;
2803-#elif IS_FB2K_VER09
2804- bool isTrackInLibrary = static_api_ptr_t<library_manager>()->is_item_in_library(track);
2805-#endif
2806- if(cfg_media_library_registered_file_only == 1)
2807- {
2808- if(isTrackInLibrary)
2809- {
2810- DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_new_track - new track found on media library."));
2811- }
2812- else
2813- {
2814- DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_new_track - new track NOT IN media library."));
2815- }
2816- }
2817-
2818- // get currently playbacked track informations
2819- string8 winamp_title_utf8;
2820- string8 playlist_title_utf8;
2821-
2822- // make currently playbacked track information keys
2823- Strings strKeys;
2824-
2825- strKeys.push_back(FORMAT_FILEPATH);
2826- strKeys.push_back(FORMAT_FILEPATHRAW);
2827- strKeys.push_back(FORMAT_ARTIST);
2828- strKeys.push_back(FORMAT_TRACKTITLE);
2829- strKeys.push_back(FORMAT_ALBUMTITLE);
2830- strKeys.push_back(FORMAT_GENRE);
2831- strKeys.push_back(FORMAT_CODEC);
2832-
2833- // set current track informations
2834- TrackInfo &trackInfo(DummyAmp::getInstance()->getMutableTrackInfo());
2835- trackInfo.clear();
2836- trackInfo.setStrings(strKeys, track);
2837-
2838- // set trackinfo to dummyAmp
2839- //DummyAmp::getInstance()->setTrackInfo(trackInfo);
2840-
2841- // set dynamic flag
2842- setDynamic(trackInfo.getString(FORMAT_FILEPATHRAW));
2843-
2844- if(isDynamic())
2845- {
2846- setFirstDynamicCallback(true);
2847-
2848- // set song total length
2849- m_song_total_sec = pfc_string_to_float(cfg_send_interval3) / pfc_string_to_float(cfg_send_interval2) * 100.0;
2850- }
2851- else
2852- {
2853-#if defined(CONTROL_SEND_TIMING)
2854- // reset send timing
2855- resetSendTiming();
2856-#endif
2857-
2858-#if IS_FB2K_VER08
2859- // get song total length
2860- m_song_total_sec = track->handle_get_length();
2861-
2862- // get formatted dummyamp title
2863- track->handle_format_title(winamp_title_utf8, cfg_dummyamp_title_format, 0);
2864-
2865- // get formatted playlist title
2866- track->handle_format_title(playlist_title_utf8, cfg_dummyamp_playlist_format, 0);
2867-
2868-#elif IS_FB2K_VER09
2869- // get song total length
2870- m_song_total_sec = track->get_length();
2871-
2872- service_ptr_t<titleformat_object> titleformat;
2873-
2874- // get formatted dummyamp title
2875- static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, cfg_dummyamp_title_format);
2876- track->format_title(NULL, winamp_title_utf8, titleformat, 0);
2877-
2878- // get formatted playlist title
2879- static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, cfg_dummyamp_playlist_format);
2880- track->format_title(NULL, playlist_title_utf8, titleformat, 0);
2881-
2882-#endif
2883- string_os_from_utf8 winamp_title(winamp_title_utf8);
2884- string_os_from_utf8 playlist_title(playlist_title_utf8);
2885-
2886- // set base winamp title to dummyamp
2887- DummyAmp::getInstance()->setBaseWinampTitle(winamp_title);
2888-
2889- // set winamp playlist current item title to dummyamp
2890- DummyAmp::getInstance()->setPlaylistTitle(playlist_title);
2891-
2892- // clear raw playinfo on dummyamp (no resent mode)
2893- DummyAmp::getInstance()->getRawPlayInfo().clearPlayInfo(false);
2894-
2895- // set playinfo raw mp3 file path to dummyAmp
2896- DummyAmp::getInstance()->getRawPlayInfo().setPlayInfoMp3Path(trackInfo.getString(FORMAT_FILEPATH).c_str());
2897-
2898- // set dummyamp raw status PLAY_START
2899- DummyAmp::getInstance()->getRawPlayInfo().setPlayStatusStart();
2900-
2901- // set raw song total length
2902- DummyAmp::getInstance()->getRawPlayInfo().setPlayLength(static_cast<int>(m_song_total_sec));
2903-
2904- // increment play counter
2905- DummyAmp::getInstance()->getRawPlayInfo().incrementPlayCount();
2906-
2907- // clear playinfo on dummyamp
2908- DummyAmp::getInstance()->getPlayInfo().clearPlayInfo();
2909-
2910- // set song total length
2911- DummyAmp::getInstance()->getPlayInfo().setPlayLength(static_cast<int>(m_song_total_sec));
2912-
2913- // increment play counter on dummyamp
2914- DummyAmp::getInstance()->getPlayInfo().incrementPlayCount();
2915- }
2916-
2917- if(isDynamic())
2918- {
2919- // post IPC_INTERNAL_REFRESHLISTINFO
2920- ::PostMessage(DummyAmp::getInstance()->getWnd(), WM_WA_IPC, 0, IPC_INTERNAL_REFRESHLISTINFO);
2921- DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_new_track - IPC_INTERNAL_REFRESHLISTINFO posted."));
2922- }
2923- else
2924- {
2925- bool bSkip = false;
2926-
2927- string8 title_utf8 = trackInfo.getString(FORMAT_TRACKTITLE).c_str();
2928- string8 artist_utf8 = trackInfo.getString(FORMAT_ARTIST).c_str();
2929- string8 album_utf8 = trackInfo.getString(FORMAT_ALBUMTITLE).c_str();
2930- string8 genre_utf8 = trackInfo.getString(FORMAT_GENRE).c_str();
2931-
2932- // when media library only mode and track not found on media library,
2933- // then skip sending track informations
2934- if((cfg_media_library_registered_file_only == 1) && (isTrackInLibrary == false))
2935- {
2936- DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_new_track - SKIP this track. (not in media library)"));
2937- bSkip = true;
2938- }
2939-
2940- // when explicitly tagged file only mode and artist or track name not found,
2941- // then skip sending track informations
2942- if( (cfg_explicitly_tagged_file_only == 1) && (!lstrcmpA(title_utf8, "?") || !lstrcmpA(artist_utf8, "?")) )
2943- {
2944- DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_new_track - SKIP this track. (artist or title not found)"));
2945- bSkip = true;
2946- }
2947-
2948- if(!lstrcmpA(title_utf8, "?"))
2949- {
2950- trackInfo.removeString(FORMAT_TRACKTITLE);
2951- trackInfo.putString(FORMAT_TRACKTITLE, (LPCSTR)cfg_no_title_name);
2952- }
2953-
2954- if(!lstrcmpA(artist_utf8, "?"))
2955- {
2956- trackInfo.removeString(FORMAT_ARTIST);
2957- trackInfo.putString(FORMAT_ARTIST, (LPCSTR)cfg_no_artist_name);
2958- }
2959-
2960- if(!lstrcmpA(album_utf8, "?"))
2961- {
2962- trackInfo.removeString(FORMAT_ALBUMTITLE);
2963- trackInfo.putString(FORMAT_ALBUMTITLE, (LPCSTR)cfg_no_album_name);
2964- }
2965-
2966- if(!lstrcmpA(genre_utf8, "?"))
2967- {
2968- trackInfo.removeString(FORMAT_GENRE);
2969- trackInfo.putString(FORMAT_GENRE, (LPCSTR)cfg_no_genre_name);
2970- }
2971-
2972- // refresh dummy amp informations when skip flag not set
2973- if(!bSkip) {
2974- DummyAmp::getInstance()->refreshAmpInfo();
2975-
2976- // post IPC_INTERNAL_REFRESHLISTINFO
2977- ::PostMessage(DummyAmp::getInstance()->getWnd(), WM_WA_IPC, 0, IPC_INTERNAL_REFRESHLISTINFO);
2978- DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_new_track - IPC_INTERNAL_REFRESHLISTINFO posted."));
2979- }
2980- }
2981- }
2982-
2983-#if IS_FB2K_VER08
2984- virtual void on_playback_stop(play_control::stop_reason reason)
2985-#elif IS_FB2K_VER09
2986- virtual void on_playback_stop(play_control::t_stop_reason reason)
2987-#endif
2988- {
2989- TRACE_CALLBACK(_T("play_callback_mixi::on_playback_stop - called."));
2990-
2991- // set dummyamp status PLAY_STOP
2992- DummyAmp::getInstance()->getPlayInfo().setPlayStatusStop();
2993-
2994- // set dummyamp raw status PLAY_STOP
2995- DummyAmp::getInstance()->getRawPlayInfo().setPlayStatusStop();
2996-
2997- // clear dummyamp title
2998- DummyAmp::getInstance()->clearDummyAmpTitle();
2999- }
3000-
3001- virtual void on_playback_seek(double time) // time is second.
3002- {
3003- TRACE_CALLBACK(_T("play_callback_mixi::on_playback_seek - called."));
3004-
3005-#if !defined(CONTROL_SEND_TIMING)
3006- // update current position on dummyamp
3007- DummyAmp::getInstance()->getPlayInfo().setPlayPosition((int)(time * 1000));
3008-#else
3009- // update raw current position on dummyamp
3010- DummyAmp::getInstance()->getRawPlayInfo().setPlayPosition((int)(time * 1000));
3011-
3012- // reset send timing
3013- resetSendTiming();
3014-#endif
3015- }
3016-
3017-#if IS_FB2K_VER08
3018- virtual void on_playback_pause(int state)
3019-#elif IS_FB2K_VER09
3020- virtual void on_playback_pause(bool state)
3021-#endif
3022- {
3023- TRACE_CALLBACK(_T("play_callback_mixi::on_playback_pause - called."));
3024-
3025-#if IS_FB2K_VER08
3026- if(state == 1)
3027-#elif IS_FB2K_VER09
3028- if(state == true)
3029-#endif
3030- {
3031- // set dummyamp status PLAY_PAUSE
3032- DummyAmp::getInstance()->getPlayInfo().setPlayStatusPause();
3033-
3034- // set dummyamp raw status PLAY_PAUSE
3035- DummyAmp::getInstance()->getRawPlayInfo().setPlayStatusPause();
3036-
3037- DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_pause - fb2k paused."));
3038- }
3039- else
3040- {
3041-#if !defined(CONTROL_SEND_TIMING)
3042- // set dummyamp status PLAY_START
3043- DummyAmp::getInstance()->getPlayInfo().setPlayStatusStart();
3044-#else
3045- // set dummyamp status PLAY_STOP
3046- DummyAmp::getInstance()->getPlayInfo().setPlayStatusStop();
3047-#endif
3048-
3049- // set dummyamp rawa status PLAY_START
3050- DummyAmp::getInstance()->getRawPlayInfo().setPlayStatusStart();
3051-
3052- DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_pause - fb2k unpaused."));
3053- }
3054- }
3055-
3056-#if IS_FB2K_VER08
3057- virtual void on_playback_edited(metadb_handle * track){}//currently played file got edited
3058-#elif IS_FB2K_VER09
3059- virtual void on_playback_edited(metadb_handle_ptr track){}//currently played file got edited
3060-#endif
3061-
3062-#if IS_FB2K_VER08
3063- virtual void on_playback_dynamic_info(const file_info * info,bool b_track_change)
3064-#elif IS_FB2K_VER09
3065- virtual void on_playback_dynamic_info(const file_info & info)
3066-#endif
3067- {
3068-#if IS_FB2K_VER08
3069- TRACE_CALLBACK(_T("play_callback_mixi::on_playback_dynamic_info - called."));
3070-
3071- if(isDynamic() && b_track_change)
3072- {
3073- refreshDynamicInfo();
3074- }
3075-#endif
3076- }
3077-
3078-#if IS_FB2K_VER09
3079- virtual void on_playback_dynamic_info_track(const file_info & p_info) {
3080-
3081- TRACE_CALLBACK(_T("play_callback_mixi::on_playback_dynamic_info_track - called."));
3082-
3083- if(isDynamic())
3084- {
3085- refreshDynamicInfo();
3086- }
3087- };
3088-#endif
3089-
3090-#if IS_FB2K_VER08
3091- virtual void on_playback_time(metadb_handle * track, double time)//called every second
3092-#elif IS_FB2K_VER09
3093- virtual void on_playback_time(double time)//called every second
3094-#endif
3095- {
3096- TRACE_CALLBACK(_T("play_callback_mixi::on_playback_time - called."));
3097-
3098- // update current raw position on dummyamp
3099- DummyAmp::getInstance()->getRawPlayInfo().setPlayPosition((int)(time * 1000));
3100-
3101- if(DummyAmp::getInstance()->getPlayInfo().isPlayInfoMp3Available() == true)
3102- {
3103-#if !defined(CONTROL_SEND_TIMING)
3104- // update current position on dummyamp
3105- DummyAmp::getInstance()->getPlayInfo().setPlayPosition((int)(time * 1000));
3106-#else
3107-#if !defined(ENABLE_MSN)
3108- if(m_bPassThesholdTime == true) {
3109- // update current position on dummyamp
3110- DummyAmp::getInstance()->getPlayInfo().setPlayPosition((int)(time * 1000));
3111- }
3112-#endif
3113- if(checkSendTiming(time) == true)
3114- {
3115- DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_time - send track informations ..."));
3116-
3117-#if !defined(ENABLE_MSN)
3118- //dummyamp resent mode
3119- DummyAmp::getInstance()->getPlayInfo().setPlayPosition((int)(time * 1000));
3120- DummyAmp::getInstance()->getPlayInfo().setResentMode(false);
3121-
3122-// // update dummyamp title
3123-// DummyAmp::getInstance()->updateDummyAmpTitle();
3124-
3125- // set dummyamp status PLAY_START
3126- DummyAmp::getInstance()->getPlayInfo().setPlayStatusStart();
3127-#else
3128- // send track informations to M2M
3129- MSNSender::SendTrackInfo(m_trackInfoUtf8);
3130-#endif
3131- }
3132-#endif
3133- }
3134- }
3135-
3136-protected:
3137-
3138-#if defined(CONTROL_SEND_TIMING)
3139- void resetSendTiming()
3140- {
3141- TRACE_CALLBACK(_T("play_callback_mixi::resetSendTiming - called."));
3142-
3143- m_previous_sec = -1.0;
3144- m_bPassLowerBoundTime = false;
3145- m_bPassThesholdTime = false;
3146- }
3147-
3148- bool checkSendTiming(double sec)
3149- {
3150- TRACE_CALLBACK(_T("play_callback_mixi::checkSendTiming - called."));
3151-
3152- if(m_bPassThesholdTime == true) return false;
3153-
3154- if(m_previous_sec < 0.0) {
3155- m_previous_sec = sec - 1.0;
3156- }
3157-
3158- double elapsedTime = sec - m_previous_sec;
3159-
3160- double lowerBoundTime = pfc_string_to_float(cfg_send_interval1);
3161- double thresholdTime1 = m_song_total_sec * pfc_string_to_float(cfg_send_interval2) / 100.0;
3162- double thresholdTime2 = pfc_string_to_float(cfg_send_interval3);
3163- double thresholdTime = min(thresholdTime1, thresholdTime2);
3164-
3165-#if 0
3166- if(lowerBoundTime < 10.0) lowerBoundTime = 10.0;
3167-
3168- if(thresholdTime < 10.0) thresholdTime = 10.0;
3169-#endif
3170- if(thresholdTime < lowerBoundTime) thresholdTime = lowerBoundTime;
3171-
3172- if(m_bPassLowerBoundTime == false)
3173- {
3174- TRACE_CALLBACK(_T("play_callback_mixi::checkSendTiming - pos: %5.1f, lowerBound:%5.1f, elapse:%5.1f"),
3175- sec, lowerBoundTime, elapsedTime);
3176-
3177- if(lowerBoundTime <= elapsedTime + 3) // add gen_mixi response time
3178- {
3179- m_bPassLowerBoundTime = true;
3180- }
3181- }
3182-
3183- if((m_bPassLowerBoundTime == true) && (m_bPassThesholdTime == false))
3184- {
3185- TRACE_CALLBACK(_T("play_callback_mixi::checkSendTiming - pos: %5.1f, threshold:%5.1f, elapse:%5.1f"),
3186- sec, thresholdTime, elapsedTime);
3187-
3188- if(thresholdTime <= elapsedTime + 3) // add gen_mixi response time
3189- {
3190- m_bPassThesholdTime = true;
3191- return true;
3192- }
3193- }
3194-
3195- return false;
3196- }
3197-#endif
3198-
3199- void refreshDynamicInfo()
3200- {
3201- if(cfg_enable_streaming_file == 0)
3202- {
3203- DEBUG_CALLBACK(_T("play_callback_mixi::refreshDynamicInfo - SKIP this track. (ストリーミング情報の送信が許可されていません)"));
3204- setFirstDynamicCallback(false);
3205- return ;
3206- }
3207-
3208- if(cfg_disable_dummy_mp3 == 1)
3209- {
3210- DEBUG_CALLBACK(_T("play_callback_mixi::refreshDynamicInfo - SKIP this track. (ストリーミング情報を送信するには、ダミーMP3ファイルが有効にしてください)"));
3211- setFirstDynamicCallback(false);
3212- return ;
3213- }
3214-
3215- // reset send timing
3216- resetSendTiming();
3217-
3218- // clear raw playinfo on dummyamp (no resent mode)
3219- DummyAmp::getInstance()->getRawPlayInfo().clearPlayInfo(false);
3220-
3221- // set playinfo raw mp3 file path to dummyAmp
3222- DummyAmp::getInstance()->getRawPlayInfo().setPlayInfoMp3Path(DummyAmp::getInstance()->getTrackInfo().getString(FORMAT_FILEPATH).c_str());
3223-
3224- // set dummyamp raw status PLAY_START
3225- DummyAmp::getInstance()->getRawPlayInfo().setPlayStatusStart();
3226-
3227- // set raw song total length
3228- DummyAmp::getInstance()->getRawPlayInfo().setPlayLength(static_cast<int>(m_song_total_sec));
3229-
3230- // increment play counter
3231- DummyAmp::getInstance()->getRawPlayInfo().incrementPlayCount();
3232-
3233- // clear playinfo on dummyamp
3234- DummyAmp::getInstance()->getPlayInfo().clearPlayInfo();
3235-
3236- // set song total length
3237- DummyAmp::getInstance()->getPlayInfo().setPlayLength(static_cast<int>(m_song_total_sec));
3238-
3239- // increment play counter on dummyamp
3240- DummyAmp::getInstance()->getPlayInfo().incrementPlayCount();
3241-
3242- DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_dynamic_info_track - IPC_INTERNAL_REFRESHDYNINFO posted."));
3243- ::PostMessage(DummyAmp::getInstance()->getWnd(), WM_WA_IPC, 0, IPC_INTERNAL_REFRESHDYNINFO);
3244- setFirstDynamicCallback(false);
3245- }
3246-
3247-#if IS_FB2K_VER09
3248- // User changed volume settings. Possibly called when not playing.
3249- virtual void on_volume_change(float new_val) {}
3250-#endif
3251-
3252- void setFirstDynamicCallback(bool isFirst) {
3253- m_isFirstDynamicCallback = isFirst;
3254- }
3255-
3256- bool isFirstDynamicCallback() const {
3257- return m_isFirstDynamicCallback;
3258- }
3259-
3260- void setDynamic(const std::string &rawFilePath)
3261- {
3262- bool isFileProtocol = rawFilePath.find("file://") != std::string::npos;
3263- bool isCddaProtocol = rawFilePath.find("cdda://") != std::string::npos;
3264- bool isDriveName = false;
3265-
3266- if(rawFilePath.length() >= 3) {
3267- LPCSTR pRawFilePath = rawFilePath.c_str();
3268- isDriveName = ::isalpha(pRawFilePath[0]) && (pRawFilePath[1] == ':') && (pRawFilePath[2] == '\\');
3269- }
3270-
3271- m_isDynamic = !(isFileProtocol || isCddaProtocol || isDriveName);
3272- }
3273-
3274- bool isDynamic() const {
3275- return m_isDynamic;
3276- }
3277-
3278-protected:
3279-
3280-// TrackInfo m_trackInfo;
3281-
3282- double m_previous_sec;
3283- double m_song_total_sec;
3284-
3285- bool m_bPassLowerBoundTime;
3286- bool m_bPassThesholdTime;
3287-
3288- bool m_isDynamic;
3289- bool m_isFirstDynamicCallback;
3290-};
3291-
3292-
3293-class initquit_mixi : public initquit
3294-{
3295- typedef std::auto_ptr<DummyAmp> DummyAmpAutoPtr;
3296- DummyAmpAutoPtr m_apDummyAmp;
3297-
3298- virtual void on_init()
3299- {
3300- m_apDummyAmp = DummyAmpAutoPtr(DummyAmp::getInstance());
3301- m_apDummyAmp->load();
3302- }
3303-
3304- virtual void on_quit()
3305- {
3306- m_apDummyAmp->release();
3307- {
3308- DummyAmpAutoPtr sink(m_apDummyAmp);
3309- }
3310- }
3311-
3312- virtual void on_system_shutdown()
3313- {
3314- on_quit();
3315- }
3316-};
3317-
3318-#if IS_FB2K_VER08
3319-class menu_item_mixi : public menu_item_main
3320-#elif IS_FB2K_VER09
3321-// {E8BF1F91-9262-4c0b-AD39-00C0B24B4210}
3322-static const GUID menu_item_mixi_guid = { 0xe8bf1f91, 0x9262, 0x4c0b, { 0xad, 0x39, 0x0, 0xc0, 0xb2, 0x4b, 0x42, 0x10 } };
3323-class menu_item_mixi : public mainmenu_commands
3324-#endif
3325-{
3326-#if IS_FB2K_VER08
3327- virtual unsigned get_num_items() {
3328-#elif IS_FB2K_VER09
3329- virtual t_uint32 get_command_count() {
3330-#endif
3331- return 1;
3332- }
3333-
3334-#if IS_FB2K_VER08
3335- virtual void enum_item(unsigned n, string_base & out) {
3336- out = (n==0 ? g_menu_item : "");
3337- }
3338-#elif IS_FB2K_VER09
3339- virtual GUID get_command(t_uint32 p_index)
3340- {
3341- if (p_index == 0) {
3342- return menu_item_mixi_guid;
3343- }
3344-
3345- return pfc::guid_null;
3346- }
3347-
3348- virtual void get_name(t_uint32 p_index, string_base & p_out)
3349- {
3350- if (p_index == 0)
3351- {
3352- p_out = g_menu_item_title;
3353- }
3354- }
3355-
3356- virtual bool get_description(t_uint32 p_index, string_base & p_out)
3357- {
3358- if (p_index == 0)
3359- {
3360- p_out = g_menu_item_description;
3361- }
3362- else
3363- {
3364- return false;
3365- }
3366-
3367- return true;
3368- }
3369-
3370- virtual GUID get_parent() {
3371- return mainmenu_groups::playback_etc;
3372- }
3373-
3374-#endif
3375-
3376-#if IS_FB2K_VER08
3377- virtual bool is_checked(int index)
3378- {
3379- bool flags = false;
3380- static const bool flag_checked = TRUE;
3381-#elif IS_FB2K_VER09
3382- virtual bool get_display(t_uint32 index, pfc::string_base & text, t_uint32 & flags)
3383- {
3384- flags = 0;
3385-#endif
3386- switch (index)
3387- {
3388- case 0:
3389- if (cfg_use_plugin == 1) flags = flag_checked;
3390- break;
3391- }
3392-
3393-#if IS_FB2K_VER08
3394- return flags;
3395-#elif IS_FB2K_VER09
3396- get_name(index, text);
3397- return true;
3398-#endif
3399- }
3400-
3401-#if IS_FB2K_VER08
3402- virtual void perform_command(unsigned index)
3403- {
3404-#elif IS_FB2K_VER09
3405- virtual void execute(t_uint32 index, service_ptr_t<service_base> /* reserved for future use */)
3406- {
3407-#endif
3408- if ((index == 0) && core_api::assert_main_thread())
3409- {
3410- cfg_use_plugin = 1 - cfg_use_plugin;
3411-
3412- if(cfg_use_plugin > 1)
3413- {
3414- cfg_use_plugin = 1;
3415- }
3416- else if(cfg_use_plugin < 0)
3417- {
3418- cfg_use_plugin = 0;
3419- }
3420-
3421- if (cfg_use_plugin == 1)
3422- {
3423- DEBUG_PLUGIN(_T("menu_item_mixi::execute - mixiミュージック連携を有効にしました"));
3424- }
3425- else
3426- {
3427- DEBUG_PLUGIN(_T("menu_item_mixi::execute - mixiミュージック連携を無効にしました"));
3428- }
3429- }
3430- }
3431-};
3432-
3433-#define CLEARTYPE_QUALITY 5
3434-
3435-#if IS_FB2K_VER08
3436-class config_page_mixi : public config
3437-#elif IS_FB2K_VER09
3438-// {976D6C46-31E4-4ab4-8BFF-5FB2E9BFD599}
3439-static const GUID config_page_mixi_guid = { 0x976d6c46, 0x31e4, 0x4ab4, { 0x8b, 0xff, 0x5f, 0xb2, 0xe9, 0xbf, 0xd5, 0x99 } };
3440-class config_page_mixi : public preferences_page
3441-#endif
3442-{
3443- static HFONT hIntervalFont;
3444-
3445- static BOOL CALLBACK ConfigProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
3446- {
3447- HWND hSendInterval1 = uGetDlgItem(wnd, IDC_SEND_INTERVAL_SLIDER_1ST);
3448- HWND hSendInterval2 = uGetDlgItem(wnd, IDC_SEND_INTERVAL_SLIDER_2ND);
3449- HWND hSendInterval3 = uGetDlgItem(wnd, IDC_SEND_INTERVAL_SLIDER_3RD);
3450-
3451- HWND hSendInterval1Text = uGetDlgItem(wnd, IDC_SEND_INTERVAL_1ST);
3452- HWND hSendInterval2Text = uGetDlgItem(wnd, IDC_SEND_INTERVAL_2ND);
3453- HWND hSendInterval3Text = uGetDlgItem(wnd, IDC_SEND_INTERVAL_3RD);
3454-
3455- switch(msg)
3456- {
3457- case WM_INITDIALOG:
3458- {
3459- HDC hWndDC = ::GetWindowDC(wnd);
3460- hIntervalFont = ::CreateFont(
3461- -MulDiv(20, GetDeviceCaps(hWndDC, LOGPIXELSY), 72), 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
3462- ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, FIXED_PITCH, _T("Arial")
3463- );
3464- ::ReleaseDC(wnd, hWndDC);
3465-
3466- uSendMessage(hSendInterval1Text, WM_SETFONT, (WPARAM)hIntervalFont, (LPARAM)FALSE);
3467- uSendMessage(hSendInterval2Text, WM_SETFONT, (WPARAM)hIntervalFont, (LPARAM)FALSE);
3468- uSendMessage(hSendInterval3Text, WM_SETFONT, (WPARAM)hIntervalFont, (LPARAM)FALSE);
3469-
3470- uButton_SetCheck(wnd, IDC_USE_PLUGIN, (cfg_use_plugin == 1) ? true : false);
3471-
3472- uButton_SetCheck(wnd, IDC_DISABLE_DUPLICATE_SONG, (cfg_disable_duplicate_song == 1) ? true : false);
3473- uButton_SetCheck(wnd, IDC_DISABLE_DUMMY_MP3, (cfg_disable_dummy_mp3 == 1) ? true : false);
3474- uButton_SetCheck(wnd, IDC_MEDIA_LIBRARY_REGISTERED_FILE_ONLY, (cfg_media_library_registered_file_only == 1) ? true : false);
3475- uButton_SetCheck(wnd, IDC_EXPLICITLY_TAGGED_FILE_ONLY, (cfg_explicitly_tagged_file_only == 1) ? true : false);
3476-
3477- uSetDlgItemText(wnd, IDC_NO_ARTIST_NAME, cfg_no_artist_name);
3478- uSetDlgItemText(wnd, IDC_NO_TITLE_NAME, cfg_no_title_name);
3479- uSetDlgItemText(wnd, IDC_NO_ALBUM_NAME, cfg_no_album_name);
3480- uSetDlgItemText(wnd, IDC_NO_GENRE_NAME, cfg_no_genre_name);
3481-
3482- EnableNoNames(wnd, (cfg_explicitly_tagged_file_only == 0) ? true : false);
3483-
3484- uButton_SetCheck(wnd, IDC_ENABLE_STREAMING_FILE, (cfg_enable_streaming_file == 1) ? true : false);
3485-
3486- uSetDlgItemText(wnd, IDC_SEND_INTERVAL_1ST, cfg_send_interval1);
3487- uSetDlgItemText(wnd, IDC_SEND_INTERVAL_2ND, cfg_send_interval2);
3488- uSetDlgItemText(wnd, IDC_SEND_INTERVAL_3RD, cfg_send_interval3);
3489-
3490- uSendMessage(hSendInterval1, TBM_SETRANGE, (WPARAM)FALSE, (LPARAM)MAKELONG(REQUIRED_MINIMUM_TIME, 300));
3491- uSendMessage(hSendInterval1, TBM_SETLINESIZE, (WPARAM)0, (LPARAM)1);
3492- uSendMessage(hSendInterval1, TBM_SETPAGESIZE, (WPARAM)0, (LPARAM)20);
3493- uSendMessage(hSendInterval1, TBM_SETTICFREQ, (WPARAM)20, (LPARAM)0);
3494-
3495- double pos1 = pfc_string_to_float(cfg_send_interval1);
3496- uSendMessage(hSendInterval1, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos1);
3497-
3498- uSendMessage(hSendInterval2, TBM_SETRANGE, (WPARAM)FALSE, (LPARAM)MAKELONG(SEND_TIME_RATE_LOWERBOUND, 100));
3499- uSendMessage(hSendInterval2, TBM_SETLINESIZE, (WPARAM)0, (LPARAM)1);
3500- uSendMessage(hSendInterval2, TBM_SETPAGESIZE, (WPARAM)0, (LPARAM)5);
3501- uSendMessage(hSendInterval2, TBM_SETTICFREQ, (WPARAM)5, (LPARAM)0);
3502-
3503- double pos2 = pfc_string_to_float(cfg_send_interval2);
3504- uSendMessage(hSendInterval2, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos2);
3505-
3506- uSendMessage(hSendInterval3, TBM_SETRANGE, (WPARAM)FALSE, (LPARAM)MAKELONG(REQUIRED_MAXIMUM_TIME, 9999));
3507- uSendMessage(hSendInterval3, TBM_SETLINESIZE, (WPARAM)0, (LPARAM)10);
3508- uSendMessage(hSendInterval3, TBM_SETPAGESIZE, (WPARAM)0, (LPARAM)100);
3509- uSendMessage(hSendInterval3, TBM_SETTICFREQ, (WPARAM)1000, (LPARAM)0);
3510-
3511- double pos3 = pfc_string_to_float(cfg_send_interval3);
3512- uSendMessage(hSendInterval3, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos3);
3513-
3514- uSetDlgItemText(wnd, IDC_VERSION, PLUGIN_CAPTION " " PLUGIN_VERSION);
3515- uSetDlgItemText(wnd, IDC_BUILD, "build on " __DATE__ ", " __TIME__);
3516- }
3517- break;
3518-
3519- case WM_COMMAND:
3520- switch(wp)
3521- {
3522- case (BN_CLICKED<<16)|IDC_USE_PLUGIN:
3523- cfg_use_plugin = uButton_GetCheck(wnd, IDC_USE_PLUGIN) ? 1 : 0;
3524- break;
3525-
3526- case (EN_UPDATE<<16)|IDC_NO_ARTIST_NAME:
3527- {
3528- string8 name;
3529- uGetWindowText(reinterpret_cast<HWND>(lp), name);
3530- cfg_no_artist_name = name;
3531- }
3532- break;
3533-
3534- case (EN_UPDATE<<16)|IDC_NO_TITLE_NAME:
3535- {
3536- string8 name;
3537- uGetWindowText(reinterpret_cast<HWND>(lp), name);
3538- cfg_no_title_name = name;
3539- }
3540- break;
3541-
3542- case (EN_UPDATE<<16)|IDC_NO_ALBUM_NAME:
3543- {
3544- string8 name;
3545- uGetWindowText(reinterpret_cast<HWND>(lp), name);
3546- cfg_no_album_name = name;
3547- }
3548- break;
3549-
3550- case (EN_UPDATE<<16)|IDC_NO_GENRE_NAME:
3551- {
3552- string8 name;
3553- uGetWindowText(reinterpret_cast<HWND>(lp), name);
3554- cfg_no_genre_name = name;
3555- }
3556- break;
3557-
3558- case (BN_CLICKED<<16)|IDC_DISABLE_DUPLICATE_SONG:
3559- cfg_disable_duplicate_song = uButton_GetCheck(wnd, IDC_DISABLE_DUPLICATE_SONG) ? 1 : 0;
3560- break;
3561-
3562- case (BN_CLICKED<<16)|IDC_DISABLE_DUMMY_MP3:
3563- cfg_disable_dummy_mp3 = uButton_GetCheck(wnd, IDC_DISABLE_DUMMY_MP3) ? 1 : 0;
3564- break;
3565-
3566- case (BN_CLICKED<<16)|IDC_MEDIA_LIBRARY_REGISTERED_FILE_ONLY:
3567- cfg_media_library_registered_file_only = uButton_GetCheck(wnd, IDC_MEDIA_LIBRARY_REGISTERED_FILE_ONLY) ? 1 : 0;
3568- break;
3569-
3570- case (BN_CLICKED<<16)|IDC_EXPLICITLY_TAGGED_FILE_ONLY:
3571- cfg_explicitly_tagged_file_only = uButton_GetCheck(wnd, IDC_EXPLICITLY_TAGGED_FILE_ONLY) ? 1 : 0;
3572- EnableNoNames(wnd, (cfg_explicitly_tagged_file_only == 0) ? true : false);
3573- break;
3574-
3575- case (BN_CLICKED<<16)|IDC_ENABLE_STREAMING_FILE:
3576- cfg_enable_streaming_file = uButton_GetCheck(wnd, IDC_ENABLE_STREAMING_FILE) ? 1 : 0;
3577- break;
3578-
3579- case (BN_CLICKED<<16)|IDC_CONFIGURE:
3580- DummyAmp::getInstance()->config();
3581- break;
3582- }
3583- break;
3584-
3585- case WM_HSCROLL:
3586- {
3587- HWND hTrackBar = (HWND)lp;
3588-
3589- if((hTrackBar == hSendInterval1)
3590- || (hTrackBar == hSendInterval2)
3591- || (hTrackBar == hSendInterval3))
3592- {
3593- switch(LOWORD(wp))
3594- {
3595- case TB_THUMBPOSITION:
3596- case TB_THUMBTRACK:
3597- case TB_TOP:
3598- case TB_BOTTOM:
3599- case TB_PAGEUP:
3600- case TB_PAGEDOWN:
3601- case TB_LINEUP:
3602- case TB_LINEDOWN:
3603- case TB_ENDTRACK:
3604- {
3605- LRESULT lPos = 0;
3606-
3607- switch(LOWORD(wp))
3608- {
3609- case TB_THUMBPOSITION:
3610- case TB_THUMBTRACK:
3611- lPos = HIWORD(wp);
3612- break;
3613- default:
3614- lPos = uSendMessage(hTrackBar, TBM_GETPOS, 0, 0);
3615- break;
3616- }
3617-
3618- uSendMessage(hTrackBar, TBM_SETPOS, (WPARAM)TRUE, lPos);
3619-
3620- if(hTrackBar == hSendInterval1)
3621- {
3622- setDlgItemFloat(wnd, IDC_SEND_INTERVAL_1ST, (double)lPos);
3623- string8 pos;
3624- float2String(pos, (double)lPos);
3625- cfg_send_interval1 = pos;
3626- }
3627- else if(hTrackBar == hSendInterval2)
3628- {
3629- setDlgItemFloat(wnd, IDC_SEND_INTERVAL_2ND, (double)lPos);
3630- string8 pos;
3631- float2String(pos, (double)lPos);
3632- cfg_send_interval2 = pos;
3633- }
3634- else if(hTrackBar == hSendInterval3)
3635- {
3636- setDlgItemFloat(wnd, IDC_SEND_INTERVAL_3RD, (double)lPos);
3637- string8 pos;
3638- float2String(pos, (double)lPos);
3639- cfg_send_interval3 = pos;
3640- }
3641- }
3642- break;
3643-
3644- default:
3645- break;
3646- }
3647- }
3648- }
3649- break;
3650- case WM_DESTROY:
3651- if(hIntervalFont != INVALID_HANDLE_VALUE) {
3652- ::DeleteObject(hIntervalFont);
3653- }
3654- break;
3655- }
3656-
3657- return 0;
3658- }
3659-
3660- static void setDlgItemFloat(HWND wnd, UINT id, double val)
3661- {
3662- string8 pos;
3663- float2String(pos, val);
3664-
3665- uSetDlgItemText(wnd, id, pos);
3666- }
3667-
3668- static void float2String(string8 &str, double val)
3669- {
3670-#if IS_FB2K_VER08
3671- char *pStr = str.buffer_get(1024);
3672- pfc_float_to_string(pStr, val, 0);
3673- str.buffer_done();
3674-#elif IS_FB2K_VER09
3675- char *pStr = str.lock_buffer(1024);
3676- float_to_string(pStr, 1024, val, 0);
3677- str.unlock_buffer();
3678-#endif
3679- }
3680-
3681- static void EnableNoNames(HWND wnd, bool bNoNameEnabled) {
3682- EnableNoName(wnd, IDC_NO_ARTIST_NAME, bNoNameEnabled);
3683- EnableNoName(wnd, IDC_NO_TITLE_NAME, bNoNameEnabled);
3684- EnableNoName(wnd, IDC_NO_ALBUM_NAME, bNoNameEnabled);
3685- EnableNoName(wnd, IDC_NO_GENRE_NAME, bNoNameEnabled);
3686- }
3687-
3688- static void EnableNoName(HWND wnd, UINT id, bool bEnable) {
3689- HWND hControlWnd = uGetDlgItem(wnd, id);
3690- uEnableWindow(hControlWnd, bEnable);
3691- }
3692-
3693-public:
3694- virtual HWND create(HWND parent)
3695- {
3696- return uCreateDialog(IDD_PREFERENCE, parent, ConfigProc);
3697- }
3698-
3699- virtual const char * get_name() {
3700- return g_pluginCaption8;
3701- }
3702-
3703- virtual const char * get_parent_name() {
3704- return "Components";
3705- }
3706-
3707-#if IS_FB2K_VER09
3708- virtual GUID get_guid() {
3709- return config_page_mixi_guid;
3710- }
3711-
3712- virtual GUID get_parent_guid() {
3713- return guid_tools;
3714- }
3715-
3716- virtual bool reset_query() {
3717- return true;
3718- }
3719-
3720- virtual void reset()
3721- {
3722- cfg_use_plugin = 1;
3723- cfg_disable_duplicate_song = 0;
3724- cfg_media_library_registered_file_only = 0;
3725- cfg_send_interval1 = "20";
3726- cfg_send_interval2 = "66";
3727- cfg_send_interval3 = "300";
3728- }
3729-
3730- virtual bool get_help_url(pfc::string_base & p_out)
3731- {
3732- p_out = URL_FOO_MIXI_HOME;
3733- return true;
3734- }
3735-#endif
3736-};
3737-
3738-HFONT config_page_mixi::hIntervalFont = (HFONT)INVALID_HANDLE_VALUE;
3739-
3740-#if IS_FB2K_VER08
3741-class config_page_mixi_advanced : public config
3742-#elif IS_FB2K_VER09
3743-// {E01262F2-E6BF-4f3e-B0F2-5B8C08E2C2E3}
3744-static const GUID config_page_mixi_advanced_guid = { 0xe01262f2, 0xe6bf, 0x4f3e, { 0xb0, 0xf2, 0x5b, 0x8c, 0x8, 0xe2, 0xc2, 0xe3 } };
3745-class config_page_mixi_advanced : public preferences_page_v2
3746-#endif
3747-{
3748- static int nOldDummyMp3Location;
3749- static string8 oldGenMixiPath;
3750-
3751- static BOOL CALLBACK ConfigProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
3752- {
3753- switch(msg)
3754- {
3755- case WM_INITDIALOG:
3756- {
3757- uSetDlgItemText(wnd, IDC_CAPTION_ADVANCED, g_advancedSettingsCaption8);
3758-
3759- uButton_SetCheck(wnd, IDC_DISABLE_DUMMY_MP3, (cfg_disable_dummy_mp3 == 1) ? true : false);
3760-
3761- uSendDlgItemMessage(wnd, IDC_DUMMY_MP3_LOCATION, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(_T("ダミーMP3ファイルをユーザプロファイルに作成する")));
3762- uSendDlgItemMessage(wnd, IDC_DUMMY_MP3_LOCATION, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(_T("ダミーMP3ファイルを一時フォルダに作成する")));
3763- uSendDlgItemMessage(wnd, IDC_DUMMY_MP3_LOCATION, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(_T("ダミーMP3ファイルを Components フォルダに作成する")));
3764-
3765- uEnableWindow(uGetDlgItem(wnd, IDC_DUMMY_MP3_LOCATION), (cfg_disable_dummy_mp3 == 0) ? true : false);
3766-
3767- uSendDlgItemMessage(wnd, IDC_DUMMY_MP3_LOCATION, CB_SETCURSEL, (int)cfg_dummy_mp3_location, 0);
3768- nOldDummyMp3Location = (int)cfg_dummy_mp3_location;
3769-
3770- uSetDlgItemText(wnd, IDC_GEN_MIXI_PATH, cfg_gen_mixi_path);
3771- oldGenMixiPath = cfg_gen_mixi_path;
3772-
3773- Str64K dummyAmpFrameCaptionBuf;
3774-
3775- _stprintf_s(
3776- dummyAmpFrameCaptionBuf, sizeof(dummyAmpFrameCaptionBuf) / sizeof(TCHAR),
3777- DUMMYAMP_FRAME_CAPTION,
3778- DummyAmp::getInstance()->getWnd() == INVALID_HANDLE_VALUE ? DUMMYAMP_BEFORE_INIT_MODE :
3779- DummyAmp::getInstance()->isAnotherWinampWindowAvailable() ? DUMMYAMP_HOOK_MODE : DUMMYAMP_STANDALONE_MODE
3780- );
3781-
3782- ::SetDlgItemText(wnd, IDC_DUMMYAMP_FRAME, dummyAmpFrameCaptionBuf);
3783-
3784- uButton_SetCheck(wnd, IDC_SHOW_DUMMYAMP, (cfg_show_dummyamp == 1) ? true : false);
3785- if(DummyAmp::getInstance()->getWnd() == INVALID_HANDLE_VALUE) {
3786- HWND hControlWnd = uGetDlgItem(wnd, IDC_SHOW_DUMMYAMP);
3787- uEnableWindow(hControlWnd, false);
3788- }
3789-
3790- uSetDlgItemText(wnd, IDC_DUMMYAMP_TITLE_FORMAT, cfg_dummyamp_title_format);
3791- uSetDlgItemText(wnd, IDC_DUMMYAMP_PLAYLIST_FORMAT, cfg_dummyamp_playlist_format);
3792-
3793- uButton_SetCheck(wnd, IDC_DISABLE_ANSI_TRANS, (cfg_disable_ansi_trans == 1) ? true : false);
3794- uButton_SetCheck(wnd, IDC_ENABLE_EXT_IPC_PROC, (cfg_enable_ext_ipc_proc == 1) ? true : false);
3795- if(DummyAmp::getInstance()->isAnotherWinampWindowAvailable() == false) {
3796- HWND hControlWnd = uGetDlgItem(wnd, IDC_ENABLE_EXT_IPC_PROC);
3797- uEnableWindow(hControlWnd, false);
3798- }
3799-
3800- uSetDlgItemText(wnd, IDC_VERSION_ADVANCED, PLUGIN_CAPTION " " PLUGIN_VERSION);
3801- uSetDlgItemText(wnd, IDC_BUILD_ADVANCED, "build on " __DATE__ ", " __TIME__);
3802- }
3803- break;
3804-
3805- case WM_COMMAND:
3806- switch(wp)
3807- {
3808- case (BN_CLICKED<<16)|IDC_DISABLE_DUMMY_MP3:
3809- {
3810- cfg_disable_dummy_mp3 = uButton_GetCheck(wnd, IDC_DISABLE_DUMMY_MP3) ? 1 : 0;
3811- uEnableWindow(uGetDlgItem(wnd, IDC_DUMMY_MP3_LOCATION), (cfg_disable_dummy_mp3 == 0) ? true : false);
3812- }
3813- break;
3814-
3815- case (CBN_SELCHANGE<<16)|IDC_DUMMY_MP3_LOCATION:
3816- {
3817- int sel = static_cast<int>(uSendMessage(reinterpret_cast<HWND>(lp), CB_GETCURSEL, 0, 0));
3818- cfg_dummy_mp3_location = sel;
3819- }
3820- break;
3821-
3822- case (EN_UPDATE<<16)|IDC_GEN_MIXI_PATH:
3823- {
3824- string8 path;
3825- uGetWindowText(reinterpret_cast<HWND>(lp), path);
3826- cfg_gen_mixi_path = path;
3827- }
3828- break;
3829-
3830- case (BN_CLICKED<<16)|IDC_GEN_MIXI_PATH_REF:
3831- {
3832- string8 path(cfg_gen_mixi_path);
3833-
3834- OPENFILENAME ofn;
3835- TCHAR strFile[MAX_PATH];
3836-
3837- ::ZeroMemory(&ofn, sizeof(OPENFILENAME));
3838- strFile[0] = _T('\0');
3839-
3840- ofn.lStructSize = sizeof(OPENFILENAME);
3841- ofn.hwndOwner = wnd;
3842- ofn.lpstrFilter = _T("gen_mixi_for_winamp.dll\0gen_mixi_for_winamp.dll\0\0");
3843- ofn.nFilterIndex = 0;
3844- ofn.lpstrInitialDir = PathInfo::splitPath(path).c_str();
3845- ofn.lpstrFile = strFile;
3846- ofn.nMaxFile = MAX_PATH;
3847- ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
3848-
3849- if(::GetOpenFileName(&ofn) == TRUE)
3850- {
3851- tstring genMixiPath(PathInfo::splitPath(strFile));
3852- string_utf8_from_os genMixiPath8(genMixiPath.c_str());
3853-
3854- cfg_gen_mixi_path = genMixiPath8;
3855- ::uSetDlgItemText(wnd, IDC_GEN_MIXI_PATH, genMixiPath8);
3856- }
3857- }
3858-
3859- case (BN_CLICKED<<16)|IDC_SHOW_DUMMYAMP:
3860- {
3861- bool bShowDummyAmp = uButton_GetCheck(wnd, IDC_SHOW_DUMMYAMP);
3862- cfg_show_dummyamp = bShowDummyAmp ? 1 : 0;
3863-
3864- DummyAmp::getInstance()->showDummyAmpWindow(bShowDummyAmp);
3865- }
3866- break;
3867-
3868- case (EN_UPDATE<<16)|IDC_DUMMYAMP_TITLE_FORMAT:
3869- {
3870- string8 format;
3871- uGetWindowText(reinterpret_cast<HWND>(lp), format);
3872- cfg_dummyamp_title_format = format;
3873- }
3874- break;
3875-
3876- case (EN_UPDATE<<16)|IDC_DUMMYAMP_PLAYLIST_FORMAT:
3877- {
3878- string8 format;
3879- uGetWindowText(reinterpret_cast<HWND>(lp), format);
3880- cfg_dummyamp_playlist_format = format;
3881- }
3882- break;
3883-
3884- case (BN_CLICKED<<16)|IDC_DISABLE_ANSI_TRANS:
3885- {
3886- cfg_disable_ansi_trans = uButton_GetCheck(wnd, IDC_DISABLE_ANSI_TRANS) ? 1 : 0;
3887- }
3888- break;
3889-
3890- case (BN_CLICKED<<16)|IDC_ENABLE_EXT_IPC_PROC:
3891- {
3892- cfg_enable_ext_ipc_proc = uButton_GetCheck(wnd, IDC_ENABLE_EXT_IPC_PROC) ? 1 : 0;
3893- }
3894- break;
3895-
3896- default:
3897- break;
3898- }
3899- break;
3900- case WM_DESTROY:
3901- {
3902- bool rebootNeeded = false;
3903-
3904- if(nOldDummyMp3Location != -1)
3905- {
3906- if(nOldDummyMp3Location != cfg_dummy_mp3_location)
3907- {
3908- int nRes = ::MessageBox(
3909- NULL, _T("ダミーMP3ファイルの生成場所の変更は、foobar2000本体の再起動後に有効になります。\n\n")
3910- _T("今すぐ、foobar2000をシャットダウンしますか?"),
3911- _T(PLUGIN_CAPTION), MB_YESNO | MB_ICONEXCLAMATION);
3912-
3913- if(nRes == IDYES) {
3914- rebootNeeded = true;
3915- } else {
3916- rebootNeeded = false;
3917- }
3918- }
3919- }
3920-
3921- if(::strcmp(oldGenMixiPath, cfg_gen_mixi_path) != 0)
3922- {
3923- int nRes = ::MessageBox(
3924- NULL, GEN_MIXI_FILE_NAME _T(" の配置場所の変更は、foobar2000本体の再起動後に有効になります。\n\n")
3925- _T("今すぐ、foobar2000をシャットダウンしますか?"),
3926- _T(PLUGIN_CAPTION), MB_YESNO | MB_ICONEXCLAMATION);
3927-
3928- if(nRes == IDYES) {
3929- rebootNeeded = true;
3930- } else {
3931- rebootNeeded = false;
3932- }
3933- }
3934-
3935- nOldDummyMp3Location = (int)cfg_dummy_mp3_location;
3936- oldGenMixiPath = cfg_gen_mixi_path;
3937-
3938- if(rebootNeeded) {
3939- ::PostQuitMessage(0);
3940- }
3941- }
3942- break;
3943- }
3944-
3945- return 0;
3946- }
3947-
3948-public:
3949-
3950- virtual HWND create(HWND parent)
3951- {
3952- return uCreateDialog(IDD_ADVANCED_SETTINGS, parent, ConfigProc);
3953- }
3954-
3955- virtual const char * get_name() {
3956- return g_advancedSettingsCaption8;
3957- }
3958- virtual const char * get_parent_name() {
3959- return g_pluginCaption8;
3960- }
3961-
3962-#if IS_FB2K_VER09
3963- virtual GUID get_guid() {
3964- return config_page_mixi_advanced_guid;
3965- }
3966-
3967- virtual GUID get_parent_guid() {
3968- return config_page_mixi_guid;
3969- }
3970-
3971- virtual double get_sort_priority() {
3972- return 1.0;
3973- }
3974-
3975- virtual bool reset_query() {
3976- return true;
3977- }
3978-
3979- virtual void reset() {
3980- cfg_disable_dummy_mp3 = 0;
3981- cfg_dummy_mp3_location = 0;
3982- cfg_gen_mixi_path = PathInfo::getGenMixiDefaultPath().c_str();
3983-
3984- cfg_show_dummyamp = 0;
3985- cfg_dummyamp_title_format = DEFAULT_DUMMYAMP_TITLE;
3986- cfg_dummyamp_playlist_format = DEFAULT_DUMMYAMP_TITLE;
3987- }
3988-
3989- virtual bool get_help_url(pfc::string_base & p_out) {
3990- p_out = URL_FOO_MIXI_HOME;
3991- return true;
3992- }
3993-#endif
3994-};
3995-
3996-int config_page_mixi_advanced::nOldDummyMp3Location = -1;
3997-string8 config_page_mixi_advanced::oldGenMixiPath;
3998-
3999-#if IS_FB2K_VER08
4000-class config_page_mixi_debug : public config
4001-#elif IS_FB2K_VER09
4002-// {ADD3AC74-B1A7-4d04-BADB-6BEB7D132669}
4003-static const GUID config_page_mixi_debug_guid = { 0xadd3ac74, 0xb1a7, 0x4d04, { 0xba, 0xdb, 0x6b, 0xeb, 0x7d, 0x13, 0x26, 0x69 } };
4004-class config_page_mixi_debug : public preferences_page_v2
4005-#endif
4006-{
4007- static BOOL CALLBACK ConfigProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
4008- {
4009- switch(msg)
4010- {
4011- case WM_INITDIALOG:
4012- {
4013- uSetDlgItemText(wnd, IDC_CAPTION_DEBUG, g_debugSettingsCaption8);
4014-
4015- bool bDebugLogEnabled = (cfg_enable_debug_log == 1) ? true : false;
4016- uButton_SetCheck(wnd, IDC_ENABLE_DEBUG_LOG, bDebugLogEnabled);
4017-
4018- InitDebugLevelList(wnd, IDC_DEBUG_DUMMYAMP_INIT);
4019- InitDebugLevelList(wnd, IDC_DEBUG_DUMMYAMP_PROC);
4020- InitDebugLevelList(wnd, IDC_DEBUG_TRACK_INFO);
4021- InitDebugLevelList(wnd, IDC_DEBUG_PLUGIN);
4022- InitDebugLevelList(wnd, IDC_DEBUG_CALLBACK);
4023-
4024- EnableDebugLevelLists(wnd, bDebugLogEnabled);
4025-
4026- uSendDlgItemMessage(wnd, IDC_DEBUG_DUMMYAMP_INIT, CB_SETCURSEL, (int)cfg_debug_dummyamp_init, 0);
4027- uSendDlgItemMessage(wnd, IDC_DEBUG_DUMMYAMP_PROC, CB_SETCURSEL, (int)cfg_debug_dummyamp_proc, 0);
4028- uSendDlgItemMessage(wnd, IDC_DEBUG_TRACK_INFO, CB_SETCURSEL, (int)cfg_debug_track_info, 0);
4029- uSendDlgItemMessage(wnd, IDC_DEBUG_PLUGIN, CB_SETCURSEL, (int)cfg_debug_plugin, 0);
4030- uSendDlgItemMessage(wnd, IDC_DEBUG_CALLBACK, CB_SETCURSEL, (int)cfg_debug_callback, 0);
4031-
4032- uSetDlgItemText(wnd, IDC_VERSION_DEBUG, PLUGIN_CAPTION " " PLUGIN_VERSION);
4033- uSetDlgItemText(wnd, IDC_BUILD_DEBUG, "build on " __DATE__ ", " __TIME__);
4034- }
4035- break;
4036-
4037- case WM_COMMAND:
4038- switch(wp)
4039- {
4040- case (BN_CLICKED<<16)|IDC_ENABLE_DEBUG_LOG:
4041- {
4042- bool bDebugLogEnabled = uButton_GetCheck(wnd, IDC_ENABLE_DEBUG_LOG);
4043- cfg_enable_debug_log = bDebugLogEnabled ? 1 : 0;
4044-
4045- EnableDebugLevelLists(wnd, bDebugLogEnabled);
4046- }
4047- break;
4048-
4049- case (CBN_SELCHANGE<<16)|IDC_DEBUG_DUMMYAMP_INIT:
4050- {
4051- int sel = static_cast<int>(uSendMessage(reinterpret_cast<HWND>(lp), CB_GETCURSEL, 0, 0));
4052- cfg_debug_dummyamp_init = sel;
4053- }
4054- break;
4055-
4056- case (CBN_SELCHANGE<<16)|IDC_DEBUG_DUMMYAMP_PROC:
4057- {
4058- int sel = static_cast<int>(uSendMessage(reinterpret_cast<HWND>(lp), CB_GETCURSEL, 0, 0));
4059- cfg_debug_dummyamp_proc = sel;
4060- }
4061- break;
4062-
4063- case (CBN_SELCHANGE<<16)|IDC_DEBUG_TRACK_INFO:
4064- {
4065- int sel = static_cast<int>(uSendMessage(reinterpret_cast<HWND>(lp), CB_GETCURSEL, 0, 0));
4066- cfg_debug_track_info = sel;
4067- }
4068- break;
4069-
4070- case (CBN_SELCHANGE<<16)|IDC_DEBUG_PLUGIN:
4071- {
4072- int sel = static_cast<int>(uSendMessage(reinterpret_cast<HWND>(lp), CB_GETCURSEL, 0, 0));
4073- cfg_debug_plugin = sel;
4074- }
4075- break;
4076-
4077- case (CBN_SELCHANGE<<16)|IDC_DEBUG_CALLBACK:
4078- {
4079- int sel = static_cast<int>(uSendMessage(reinterpret_cast<HWND>(lp), CB_GETCURSEL, 0, 0));
4080- cfg_debug_callback = sel;
4081- }
4082- break;
4083-
4084- default:
4085- break;
4086- }
4087- break;
4088-
4089- case WM_DESTROY:
4090- break;
4091- }
4092-
4093- return 0;
4094- }
4095-
4096-protected:
4097-
4098- static void InitDebugLevelList(HWND wnd, UINT id) {
4099- uSendDlgItemMessage(wnd, id, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(_T("なし")));
4100- uSendDlgItemMessage(wnd, id, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(_T("簡易レベル")));
4101- uSendDlgItemMessage(wnd, id, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(_T("詳細レベル")));
4102- }
4103-
4104- static void EnableDebugLevelLists(HWND wnd, bool bDebugLogEnabled) {
4105- EnableDebugLevelList(wnd, IDC_DEBUG_DUMMYAMP_INIT, bDebugLogEnabled);
4106- EnableDebugLevelList(wnd, IDC_DEBUG_DUMMYAMP_PROC, bDebugLogEnabled);
4107- EnableDebugLevelList(wnd, IDC_DEBUG_TRACK_INFO, bDebugLogEnabled);
4108- EnableDebugLevelList(wnd, IDC_DEBUG_PLUGIN, bDebugLogEnabled);
4109- EnableDebugLevelList(wnd, IDC_DEBUG_CALLBACK, bDebugLogEnabled);
4110- }
4111-
4112- static void EnableDebugLevelList(HWND wnd, UINT id, bool bEnable) {
4113- HWND hControlWnd = uGetDlgItem(wnd, id);
4114- uEnableWindow(hControlWnd, bEnable);
4115- }
4116-
4117-public:
4118-
4119- virtual HWND create(HWND parent)
4120- {
4121- return uCreateDialog(IDD_DEBUG_SETTINGS, parent, ConfigProc);
4122- }
4123-
4124- virtual const char * get_name() {
4125- return g_debugSettingsCaption8;
4126- }
4127- virtual const char * get_parent_name() {
4128- return g_pluginCaption8;
4129- }
4130-
4131-#if IS_FB2K_VER09
4132- virtual GUID get_guid() {
4133- return config_page_mixi_debug_guid;
4134- }
4135-
4136- virtual GUID get_parent_guid() {
4137- return config_page_mixi_guid;
4138- }
4139-
4140- virtual bool reset_query() {
4141- return true;
4142- }
4143-
4144- virtual double get_sort_priority() {
4145- return 2.0;
4146- }
4147-
4148- virtual void reset() {
4149- cfg_enable_debug_log = 1;
4150- cfg_debug_dummyamp_init = 1;
4151- cfg_debug_dummyamp_proc = 1;
4152- cfg_debug_track_info = 1;
4153- cfg_debug_plugin = 1;
4154- cfg_debug_callback = 1;
4155- }
4156-
4157- virtual bool get_help_url(pfc::string_base & p_out) {
4158- p_out = URL_FOO_MIXI_HOME;
4159- return true;
4160- }
4161-#endif
4162-};
4163-
4164-#if IS_FB2K_VER08
4165-static service_factory_single_t<play_callback, play_callback_mixi> foo1;
4166-static service_factory_single_t<initquit, initquit_mixi> foo2;
4167-static menu_item_factory<menu_item_mixi> foo3;
4168-static service_factory_single_t<config, config_page_mixi> foo4;
4169-static service_factory_single_t<config, config_page_mixi_advanced> foo5;
4170-static service_factory_single_t<config, config_page_mixi_debug> foo6;
4171-#elif IS_FB2K_VER09
4172-static service_factory_single_t<play_callback_mixi> foo1;
4173-static initquit_factory_t<initquit_mixi> foo2;
4174-static mainmenu_commands_factory_t<menu_item_mixi> foo3;
4175-static preferences_page_factory_t<config_page_mixi> foo4;
4176-static preferences_page_factory_t<config_page_mixi_advanced> foo5;
4177-static preferences_page_factory_t<config_page_mixi_debug> foo6;
4178-#endif
4179-
4180-tstring GetErrorMessage(DWORD errCode)
4181-{
4182-
4183- LPVOID lpMsgBuf;
4184-
4185- FormatMessage(
4186- FORMAT_MESSAGE_ALLOCATE_BUFFER |
4187- FORMAT_MESSAGE_FROM_SYSTEM |
4188- FORMAT_MESSAGE_IGNORE_INSERTS,
4189- NULL,
4190- errCode,
4191- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // デフォルト言語
4192- (LPTSTR) &lpMsgBuf,
4193- 0,
4194- NULL
4195- );
4196-
4197- tstring msg = (LPCTSTR)lpMsgBuf;
4198-
4199- GlobalFree(lpMsgBuf);
4200-
4201- return msg;
4202-}
4203-
4204-void putLogError(LPCTSTR pMethod, LPCTSTR pErrMsg, DWORD dwErrCode)
4205-{
4206- tstring errMsg = GetErrorMessage(dwErrCode);
4207-
4208- LOG_ERROR(_T("%s - %s"), pMethod, pErrMsg);
4209- LOG_ERROR(_T("%s - コード: %08x, 理由: %s"), pMethod, dwErrCode, errMsg.c_str());
4210-}
4211-
4212-void DebugPrint(int severity, LPCTSTR lpszFormat, ...)
4213-{
4214- static Str64K buf;
4215- va_list marker;
4216-
4217- va_start(marker, lpszFormat);
4218- _vstprintf_s(buf, sizeof(Str64K), lpszFormat, marker);
4219- va_end(marker);
4220-
4221- OutputDebugString(buf);
4222- OutputDebugString(_T("\n"));
4223-
4224- string_utf8_from_os tmp(buf);
4225-
4226-#if IS_FB2K_VER08
4227- console::output(severity, tmp);
4228-#else
4229- switch(severity)
4230- {
4231- case console::SEVERITY_INFO:
4232- console::info(tmp);
4233- break;
4234- case console::SEVERITY_WARNING:
4235- console::warning(tmp);
4236- break;
4237- case console::SEVERITY_CRITICAL:
4238- console::error(tmp);
4239- break;
4240- }
4241-#endif
4242-}
4243-
4244-void DebugPrint8(int severity, LPCSTR lpszFormat, ...)
4245-{
4246- static StrDBCS64K buf;
4247-
4248- va_list marker;
4249-
4250- va_start(marker, lpszFormat);
4251- vsprintf_s(buf, sizeof(StrDBCS64K), lpszFormat, marker);
4252- va_end(marker);
4253-
4254-#if IS_FB2K_VER08
4255- console::output(severity, buf);
4256-#else
4257- switch(severity)
4258- {
4259- case console::SEVERITY_INFO:
4260- console::info(buf);
4261- break;
4262- case console::SEVERITY_WARNING:
4263- console::warning(buf);
4264- break;
4265- case console::SEVERITY_CRITICAL:
4266- console::error(buf);
4267- break;
4268- }
4269-#endif
4270-
4271- string_os_from_utf8 tmp(buf);
4272-
4273- OutputDebugString(tmp);
4274- OutputDebugString(_T("\n"));
4275-}
4276-
4277-#if defined(BUILD_UNICODE)
4278-void DebugPrintDBCS(int severity, LPCSTR lpszFormat, ...)
4279-{
4280- static StrDBCS64K buf;
4281- va_list marker;
4282-
4283- va_start(marker, lpszFormat);
4284- vsprintf_s(buf, sizeof(StrDBCS64K), lpszFormat, marker);
4285- va_end(marker);
4286-
4287- string_wide_from_ansi tmp(buf);
4288-
4289- OutputDebugString(tmp);
4290- OutputDebugString(L"\n");
4291-
4292-#if IS_FB2K_VER08
4293- console::output(severity, buf);
4294-#else
4295- switch(severity)
4296- {
4297- case console::SEVERITY_INFO:
4298- console::info(buf);
4299- break;
4300- case console::SEVERITY_WARNING:
4301- console::warning(buf);
4302- break;
4303- case console::SEVERITY_CRITICAL:
4304- console::error(buf);
4305- break;
4306- }
4307-#endif
4308-}
4309-#endif
\ No newline at end of file
--- src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_X/COPYING (revision 68)
+++ src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_X/COPYING (nonexistent)
@@ -1,674 +0,0 @@
1- GNU GENERAL PUBLIC LICENSE
2- Version 3, 29 June 2007
3-
4- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
5- Everyone is permitted to copy and distribute verbatim copies
6- of this license document, but changing it is not allowed.
7-
8- Preamble
9-
10- The GNU General Public License is a free, copyleft license for
11-software and other kinds of works.
12-
13- The licenses for most software and other practical works are designed
14-to take away your freedom to share and change the works. By contrast,
15-the GNU General Public License is intended to guarantee your freedom to
16-share and change all versions of a program--to make sure it remains free
17-software for all its users. We, the Free Software Foundation, use the
18-GNU General Public License for most of our software; it applies also to
19-any other work released this way by its authors. You can apply it to
20-your programs, too.
21-
22- When we speak of free software, we are referring to freedom, not
23-price. Our General Public Licenses are designed to make sure that you
24-have the freedom to distribute copies of free software (and charge for
25-them if you wish), that you receive source code or can get it if you
26-want it, that you can change the software or use pieces of it in new
27-free programs, and that you know you can do these things.
28-
29- To protect your rights, we need to prevent others from denying you
30-these rights or asking you to surrender the rights. Therefore, you have
31-certain responsibilities if you distribute copies of the software, or if
32-you modify it: responsibilities to respect the freedom of others.
33-
34- For example, if you distribute copies of such a program, whether
35-gratis or for a fee, you must pass on to the recipients the same
36-freedoms that you received. You must make sure that they, too, receive
37-or can get the source code. And you must show them these terms so they
38-know their rights.
39-
40- Developers that use the GNU GPL protect your rights with two steps:
41-(1) assert copyright on the software, and (2) offer you this License
42-giving you legal permission to copy, distribute and/or modify it.
43-
44- For the developers' and authors' protection, the GPL clearly explains
45-that there is no warranty for this free software. For both users' and
46-authors' sake, the GPL requires that modified versions be marked as
47-changed, so that their problems will not be attributed erroneously to
48-authors of previous versions.
49-
50- Some devices are designed to deny users access to install or run
51-modified versions of the software inside them, although the manufacturer
52-can do so. This is fundamentally incompatible with the aim of
53-protecting users' freedom to change the software. The systematic
54-pattern of such abuse occurs in the area of products for individuals to
55-use, which is precisely where it is most unacceptable. Therefore, we
56-have designed this version of the GPL to prohibit the practice for those
57-products. If such problems arise substantially in other domains, we
58-stand ready to extend this provision to those domains in future versions
59-of the GPL, as needed to protect the freedom of users.
60-
61- Finally, every program is threatened constantly by software patents.
62-States should not allow patents to restrict development and use of
63-software on general-purpose computers, but in those that do, we wish to
64-avoid the special danger that patents applied to a free program could
65-make it effectively proprietary. To prevent this, the GPL assures that
66-patents cannot be used to render the program non-free.
67-
68- The precise terms and conditions for copying, distribution and
69-modification follow.
70-
71- TERMS AND CONDITIONS
72-
73- 0. Definitions.
74-
75- "This License" refers to version 3 of the GNU General Public License.
76-
77- "Copyright" also means copyright-like laws that apply to other kinds of
78-works, such as semiconductor masks.
79-
80- "The Program" refers to any copyrightable work licensed under this
81-License. Each licensee is addressed as "you". "Licensees" and
82-"recipients" may be individuals or organizations.
83-
84- To "modify" a work means to copy from or adapt all or part of the work
85-in a fashion requiring copyright permission, other than the making of an
86-exact copy. The resulting work is called a "modified version" of the
87-earlier work or a work "based on" the earlier work.
88-
89- A "covered work" means either the unmodified Program or a work based
90-on the Program.
91-
92- To "propagate" a work means to do anything with it that, without
93-permission, would make you directly or secondarily liable for
94-infringement under applicable copyright law, except executing it on a
95-computer or modifying a private copy. Propagation includes copying,
96-distribution (with or without modification), making available to the
97-public, and in some countries other activities as well.
98-
99- To "convey" a work means any kind of propagation that enables other
100-parties to make or receive copies. Mere interaction with a user through
101-a computer network, with no transfer of a copy, is not conveying.
102-
103- An interactive user interface displays "Appropriate Legal Notices"
104-to the extent that it includes a convenient and prominently visible
105-feature that (1) displays an appropriate copyright notice, and (2)
106-tells the user that there is no warranty for the work (except to the
107-extent that warranties are provided), that licensees may convey the
108-work under this License, and how to view a copy of this License. If
109-the interface presents a list of user commands or options, such as a
110-menu, a prominent item in the list meets this criterion.
111-
112- 1. Source Code.
113-
114- The "source code" for a work means the preferred form of the work
115-for making modifications to it. "Object code" means any non-source
116-form of a work.
117-
118- A "Standard Interface" means an interface that either is an official
119-standard defined by a recognized standards body, or, in the case of
120-interfaces specified for a particular programming language, one that
121-is widely used among developers working in that language.
122-
123- The "System Libraries" of an executable work include anything, other
124-than the work as a whole, that (a) is included in the normal form of
125-packaging a Major Component, but which is not part of that Major
126-Component, and (b) serves only to enable use of the work with that
127-Major Component, or to implement a Standard Interface for which an
128-implementation is available to the public in source code form. A
129-"Major Component", in this context, means a major essential component
130-(kernel, window system, and so on) of the specific operating system
131-(if any) on which the executable work runs, or a compiler used to
132-produce the work, or an object code interpreter used to run it.
133-
134- The "Corresponding Source" for a work in object code form means all
135-the source code needed to generate, install, and (for an executable
136-work) run the object code and to modify the work, including scripts to
137-control those activities. However, it does not include the work's
138-System Libraries, or general-purpose tools or generally available free
139-programs which are used unmodified in performing those activities but
140-which are not part of the work. For example, Corresponding Source
141-includes interface definition files associated with source files for
142-the work, and the source code for shared libraries and dynamically
143-linked subprograms that the work is specifically designed to require,
144-such as by intimate data communication or control flow between those
145-subprograms and other parts of the work.
146-
147- The Corresponding Source need not include anything that users
148-can regenerate automatically from other parts of the Corresponding
149-Source.
150-
151- The Corresponding Source for a work in source code form is that
152-same work.
153-
154- 2. Basic Permissions.
155-
156- All rights granted under this License are granted for the term of
157-copyright on the Program, and are irrevocable provided the stated
158-conditions are met. This License explicitly affirms your unlimited
159-permission to run the unmodified Program. The output from running a
160-covered work is covered by this License only if the output, given its
161-content, constitutes a covered work. This License acknowledges your
162-rights of fair use or other equivalent, as provided by copyright law.
163-
164- You may make, run and propagate covered works that you do not
165-convey, without conditions so long as your license otherwise remains
166-in force. You may convey covered works to others for the sole purpose
167-of having them make modifications exclusively for you, or provide you
168-with facilities for running those works, provided that you comply with
169-the terms of this License in conveying all material for which you do
170-not control copyright. Those thus making or running the covered works
171-for you must do so exclusively on your behalf, under your direction
172-and control, on terms that prohibit them from making any copies of
173-your copyrighted material outside their relationship with you.
174-
175- Conveying under any other circumstances is permitted solely under
176-the conditions stated below. Sublicensing is not allowed; section 10
177-makes it unnecessary.
178-
179- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180-
181- No covered work shall be deemed part of an effective technological
182-measure under any applicable law fulfilling obligations under article
183-11 of the WIPO copyright treaty adopted on 20 December 1996, or
184-similar laws prohibiting or restricting circumvention of such
185-measures.
186-
187- When you convey a covered work, you waive any legal power to forbid
188-circumvention of technological measures to the extent such circumvention
189-is effected by exercising rights under this License with respect to
190-the covered work, and you disclaim any intention to limit operation or
191-modification of the work as a means of enforcing, against the work's
192-users, your or third parties' legal rights to forbid circumvention of
193-technological measures.
194-
195- 4. Conveying Verbatim Copies.
196-
197- You may convey verbatim copies of the Program's source code as you
198-receive it, in any medium, provided that you conspicuously and
199-appropriately publish on each copy an appropriate copyright notice;
200-keep intact all notices stating that this License and any
201-non-permissive terms added in accord with section 7 apply to the code;
202-keep intact all notices of the absence of any warranty; and give all
203-recipients a copy of this License along with the Program.
204-
205- You may charge any price or no price for each copy that you convey,
206-and you may offer support or warranty protection for a fee.
207-
208- 5. Conveying Modified Source Versions.
209-
210- You may convey a work based on the Program, or the modifications to
211-produce it from the Program, in the form of source code under the
212-terms of section 4, provided that you also meet all of these conditions:
213-
214- a) The work must carry prominent notices stating that you modified
215- it, and giving a relevant date.
216-
217- b) The work must carry prominent notices stating that it is
218- released under this License and any conditions added under section
219- 7. This requirement modifies the requirement in section 4 to
220- "keep intact all notices".
221-
222- c) You must license the entire work, as a whole, under this
223- License to anyone who comes into possession of a copy. This
224- License will therefore apply, along with any applicable section 7
225- additional terms, to the whole of the work, and all its parts,
226- regardless of how they are packaged. This License gives no
227- permission to license the work in any other way, but it does not
228- invalidate such permission if you have separately received it.
229-
230- d) If the work has interactive user interfaces, each must display
231- Appropriate Legal Notices; however, if the Program has interactive
232- interfaces that do not display Appropriate Legal Notices, your
233- work need not make them do so.
234-
235- A compilation of a covered work with other separate and independent
236-works, which are not by their nature extensions of the covered work,
237-and which are not combined with it such as to form a larger program,
238-in or on a volume of a storage or distribution medium, is called an
239-"aggregate" if the compilation and its resulting copyright are not
240-used to limit the access or legal rights of the compilation's users
241-beyond what the individual works permit. Inclusion of a covered work
242-in an aggregate does not cause this License to apply to the other
243-parts of the aggregate.
244-
245- 6. Conveying Non-Source Forms.
246-
247- You may convey a covered work in object code form under the terms
248-of sections 4 and 5, provided that you also convey the
249-machine-readable Corresponding Source under the terms of this License,
250-in one of these ways:
251-
252- a) Convey the object code in, or embodied in, a physical product
253- (including a physical distribution medium), accompanied by the
254- Corresponding Source fixed on a durable physical medium
255- customarily used for software interchange.
256-
257- b) Convey the object code in, or embodied in, a physical product
258- (including a physical distribution medium), accompanied by a
259- written offer, valid for at least three years and valid for as
260- long as you offer spare parts or customer support for that product
261- model, to give anyone who possesses the object code either (1) a
262- copy of the Corresponding Source for all the software in the
263- product that is covered by this License, on a durable physical
264- medium customarily used for software interchange, for a price no
265- more than your reasonable cost of physically performing this
266- conveying of source, or (2) access to copy the
267- Corresponding Source from a network server at no charge.
268-
269- c) Convey individual copies of the object code with a copy of the
270- written offer to provide the Corresponding Source. This
271- alternative is allowed only occasionally and noncommercially, and
272- only if you received the object code with such an offer, in accord
273- with subsection 6b.
274-
275- d) Convey the object code by offering access from a designated
276- place (gratis or for a charge), and offer equivalent access to the
277- Corresponding Source in the same way through the same place at no
278- further charge. You need not require recipients to copy the
279- Corresponding Source along with the object code. If the place to
280- copy the object code is a network server, the Corresponding Source
281- may be on a different server (operated by you or a third party)
282- that supports equivalent copying facilities, provided you maintain
283- clear directions next to the object code saying where to find the
284- Corresponding Source. Regardless of what server hosts the
285- Corresponding Source, you remain obligated to ensure that it is
286- available for as long as needed to satisfy these requirements.
287-
288- e) Convey the object code using peer-to-peer transmission, provided
289- you inform other peers where the object code and Corresponding
290- Source of the work are being offered to the general public at no
291- charge under subsection 6d.
292-
293- A separable portion of the object code, whose source code is excluded
294-from the Corresponding Source as a System Library, need not be
295-included in conveying the object code work.
296-
297- A "User Product" is either (1) a "consumer product", which means any
298-tangible personal property which is normally used for personal, family,
299-or household purposes, or (2) anything designed or sold for incorporation
300-into a dwelling. In determining whether a product is a consumer product,
301-doubtful cases shall be resolved in favor of coverage. For a particular
302-product received by a particular user, "normally used" refers to a
303-typical or common use of that class of product, regardless of the status
304-of the particular user or of the way in which the particular user
305-actually uses, or expects or is expected to use, the product. A product
306-is a consumer product regardless of whether the product has substantial
307-commercial, industrial or non-consumer uses, unless such uses represent
308-the only significant mode of use of the product.
309-
310- "Installation Information" for a User Product means any methods,
311-procedures, authorization keys, or other information required to install
312-and execute modified versions of a covered work in that User Product from
313-a modified version of its Corresponding Source. The information must
314-suffice to ensure that the continued functioning of the modified object
315-code is in no case prevented or interfered with solely because
316-modification has been made.
317-
318- If you convey an object code work under this section in, or with, or
319-specifically for use in, a User Product, and the conveying occurs as
320-part of a transaction in which the right of possession and use of the
321-User Product is transferred to the recipient in perpetuity or for a
322-fixed term (regardless of how the transaction is characterized), the
323-Corresponding Source conveyed under this section must be accompanied
324-by the Installation Information. But this requirement does not apply
325-if neither you nor any third party retains the ability to install
326-modified object code on the User Product (for example, the work has
327-been installed in ROM).
328-
329- The requirement to provide Installation Information does not include a
330-requirement to continue to provide support service, warranty, or updates
331-for a work that has been modified or installed by the recipient, or for
332-the User Product in which it has been modified or installed. Access to a
333-network may be denied when the modification itself materially and
334-adversely affects the operation of the network or violates the rules and
335-protocols for communication across the network.
336-
337- Corresponding Source conveyed, and Installation Information provided,
338-in accord with this section must be in a format that is publicly
339-documented (and with an implementation available to the public in
340-source code form), and must require no special password or key for
341-unpacking, reading or copying.
342-
343- 7. Additional Terms.
344-
345- "Additional permissions" are terms that supplement the terms of this
346-License by making exceptions from one or more of its conditions.
347-Additional permissions that are applicable to the entire Program shall
348-be treated as though they were included in this License, to the extent
349-that they are valid under applicable law. If additional permissions
350-apply only to part of the Program, that part may be used separately
351-under those permissions, but the entire Program remains governed by
352-this License without regard to the additional permissions.
353-
354- When you convey a copy of a covered work, you may at your option
355-remove any additional permissions from that copy, or from any part of
356-it. (Additional permissions may be written to require their own
357-removal in certain cases when you modify the work.) You may place
358-additional permissions on material, added by you to a covered work,
359-for which you have or can give appropriate copyright permission.
360-
361- Notwithstanding any other provision of this License, for material you
362-add to a covered work, you may (if authorized by the copyright holders of
363-that material) supplement the terms of this License with terms:
364-
365- a) Disclaiming warranty or limiting liability differently from the
366- terms of sections 15 and 16 of this License; or
367-
368- b) Requiring preservation of specified reasonable legal notices or
369- author attributions in that material or in the Appropriate Legal
370- Notices displayed by works containing it; or
371-
372- c) Prohibiting misrepresentation of the origin of that material, or
373- requiring that modified versions of such material be marked in
374- reasonable ways as different from the original version; or
375-
376- d) Limiting the use for publicity purposes of names of licensors or
377- authors of the material; or
378-
379- e) Declining to grant rights under trademark law for use of some
380- trade names, trademarks, or service marks; or
381-
382- f) Requiring indemnification of licensors and authors of that
383- material by anyone who conveys the material (or modified versions of
384- it) with contractual assumptions of liability to the recipient, for
385- any liability that these contractual assumptions directly impose on
386- those licensors and authors.
387-
388- All other non-permissive additional terms are considered "further
389-restrictions" within the meaning of section 10. If the Program as you
390-received it, or any part of it, contains a notice stating that it is
391-governed by this License along with a term that is a further
392-restriction, you may remove that term. If a license document contains
393-a further restriction but permits relicensing or conveying under this
394-License, you may add to a covered work material governed by the terms
395-of that license document, provided that the further restriction does
396-not survive such relicensing or conveying.
397-
398- If you add terms to a covered work in accord with this section, you
399-must place, in the relevant source files, a statement of the
400-additional terms that apply to those files, or a notice indicating
401-where to find the applicable terms.
402-
403- Additional terms, permissive or non-permissive, may be stated in the
404-form of a separately written license, or stated as exceptions;
405-the above requirements apply either way.
406-
407- 8. Termination.
408-
409- You may not propagate or modify a covered work except as expressly
410-provided under this License. Any attempt otherwise to propagate or
411-modify it is void, and will automatically terminate your rights under
412-this License (including any patent licenses granted under the third
413-paragraph of section 11).
414-
415- However, if you cease all violation of this License, then your
416-license from a particular copyright holder is reinstated (a)
417-provisionally, unless and until the copyright holder explicitly and
418-finally terminates your license, and (b) permanently, if the copyright
419-holder fails to notify you of the violation by some reasonable means
420-prior to 60 days after the cessation.
421-
422- Moreover, your license from a particular copyright holder is
423-reinstated permanently if the copyright holder notifies you of the
424-violation by some reasonable means, this is the first time you have
425-received notice of violation of this License (for any work) from that
426-copyright holder, and you cure the violation prior to 30 days after
427-your receipt of the notice.
428-
429- Termination of your rights under this section does not terminate the
430-licenses of parties who have received copies or rights from you under
431-this License. If your rights have been terminated and not permanently
432-reinstated, you do not qualify to receive new licenses for the same
433-material under section 10.
434-
435- 9. Acceptance Not Required for Having Copies.
436-
437- You are not required to accept this License in order to receive or
438-run a copy of the Program. Ancillary propagation of a covered work
439-occurring solely as a consequence of using peer-to-peer transmission
440-to receive a copy likewise does not require acceptance. However,
441-nothing other than this License grants you permission to propagate or
442-modify any covered work. These actions infringe copyright if you do
443-not accept this License. Therefore, by modifying or propagating a
444-covered work, you indicate your acceptance of this License to do so.
445-
446- 10. Automatic Licensing of Downstream Recipients.
447-
448- Each time you convey a covered work, the recipient automatically
449-receives a license from the original licensors, to run, modify and
450-propagate that work, subject to this License. You are not responsible
451-for enforcing compliance by third parties with this License.
452-
453- An "entity transaction" is a transaction transferring control of an
454-organization, or substantially all assets of one, or subdividing an
455-organization, or merging organizations. If propagation of a covered
456-work results from an entity transaction, each party to that
457-transaction who receives a copy of the work also receives whatever
458-licenses to the work the party's predecessor in interest had or could
459-give under the previous paragraph, plus a right to possession of the
460-Corresponding Source of the work from the predecessor in interest, if
461-the predecessor has it or can get it with reasonable efforts.
462-
463- You may not impose any further restrictions on the exercise of the
464-rights granted or affirmed under this License. For example, you may
465-not impose a license fee, royalty, or other charge for exercise of
466-rights granted under this License, and you may not initiate litigation
467-(including a cross-claim or counterclaim in a lawsuit) alleging that
468-any patent claim is infringed by making, using, selling, offering for
469-sale, or importing the Program or any portion of it.
470-
471- 11. Patents.
472-
473- A "contributor" is a copyright holder who authorizes use under this
474-License of the Program or a work on which the Program is based. The
475-work thus licensed is called the contributor's "contributor version".
476-
477- A contributor's "essential patent claims" are all patent claims
478-owned or controlled by the contributor, whether already acquired or
479-hereafter acquired, that would be infringed by some manner, permitted
480-by this License, of making, using, or selling its contributor version,
481-but do not include claims that would be infringed only as a
482-consequence of further modification of the contributor version. For
483-purposes of this definition, "control" includes the right to grant
484-patent sublicenses in a manner consistent with the requirements of
485-this License.
486-
487- Each contributor grants you a non-exclusive, worldwide, royalty-free
488-patent license under the contributor's essential patent claims, to
489-make, use, sell, offer for sale, import and otherwise run, modify and
490-propagate the contents of its contributor version.
491-
492- In the following three paragraphs, a "patent license" is any express
493-agreement or commitment, however denominated, not to enforce a patent
494-(such as an express permission to practice a patent or covenant not to
495-sue for patent infringement). To "grant" such a patent license to a
496-party means to make such an agreement or commitment not to enforce a
497-patent against the party.
498-
499- If you convey a covered work, knowingly relying on a patent license,
500-and the Corresponding Source of the work is not available for anyone
501-to copy, free of charge and under the terms of this License, through a
502-publicly available network server or other readily accessible means,
503-then you must either (1) cause the Corresponding Source to be so
504-available, or (2) arrange to deprive yourself of the benefit of the
505-patent license for this particular work, or (3) arrange, in a manner
506-consistent with the requirements of this License, to extend the patent
507-license to downstream recipients. "Knowingly relying" means you have
508-actual knowledge that, but for the patent license, your conveying the
509-covered work in a country, or your recipient's use of the covered work
510-in a country, would infringe one or more identifiable patents in that
511-country that you have reason to believe are valid.
512-
513- If, pursuant to or in connection with a single transaction or
514-arrangement, you convey, or propagate by procuring conveyance of, a
515-covered work, and grant a patent license to some of the parties
516-receiving the covered work authorizing them to use, propagate, modify
517-or convey a specific copy of the covered work, then the patent license
518-you grant is automatically extended to all recipients of the covered
519-work and works based on it.
520-
521- A patent license is "discriminatory" if it does not include within
522-the scope of its coverage, prohibits the exercise of, or is
523-conditioned on the non-exercise of one or more of the rights that are
524-specifically granted under this License. You may not convey a covered
525-work if you are a party to an arrangement with a third party that is
526-in the business of distributing software, under which you make payment
527-to the third party based on the extent of your activity of conveying
528-the work, and under which the third party grants, to any of the
529-parties who would receive the covered work from you, a discriminatory
530-patent license (a) in connection with copies of the covered work
531-conveyed by you (or copies made from those copies), or (b) primarily
532-for and in connection with specific products or compilations that
533-contain the covered work, unless you entered into that arrangement,
534-or that patent license was granted, prior to 28 March 2007.
535-
536- Nothing in this License shall be construed as excluding or limiting
537-any implied license or other defenses to infringement that may
538-otherwise be available to you under applicable patent law.
539-
540- 12. No Surrender of Others' Freedom.
541-
542- If conditions are imposed on you (whether by court order, agreement or
543-otherwise) that contradict the conditions of this License, they do not
544-excuse you from the conditions of this License. If you cannot convey a
545-covered work so as to satisfy simultaneously your obligations under this
546-License and any other pertinent obligations, then as a consequence you may
547-not convey it at all. For example, if you agree to terms that obligate you
548-to collect a royalty for further conveying from those to whom you convey
549-the Program, the only way you could satisfy both those terms and this
550-License would be to refrain entirely from conveying the Program.
551-
552- 13. Use with the GNU Affero General Public License.
553-
554- Notwithstanding any other provision of this License, you have
555-permission to link or combine any covered work with a work licensed
556-under version 3 of the GNU Affero General Public License into a single
557-combined work, and to convey the resulting work. The terms of this
558-License will continue to apply to the part which is the covered work,
559-but the special requirements of the GNU Affero General Public License,
560-section 13, concerning interaction through a network will apply to the
561-combination as such.
562-
563- 14. Revised Versions of this License.
564-
565- The Free Software Foundation may publish revised and/or new versions of
566-the GNU General Public License from time to time. Such new versions will
567-be similar in spirit to the present version, but may differ in detail to
568-address new problems or concerns.
569-
570- Each version is given a distinguishing version number. If the
571-Program specifies that a certain numbered version of the GNU General
572-Public License "or any later version" applies to it, you have the
573-option of following the terms and conditions either of that numbered
574-version or of any later version published by the Free Software
575-Foundation. If the Program does not specify a version number of the
576-GNU General Public License, you may choose any version ever published
577-by the Free Software Foundation.
578-
579- If the Program specifies that a proxy can decide which future
580-versions of the GNU General Public License can be used, that proxy's
581-public statement of acceptance of a version permanently authorizes you
582-to choose that version for the Program.
583-
584- Later license versions may give you additional or different
585-permissions. However, no additional obligations are imposed on any
586-author or copyright holder as a result of your choosing to follow a
587-later version.
588-
589- 15. Disclaimer of Warranty.
590-
591- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599-
600- 16. Limitation of Liability.
601-
602- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610-SUCH DAMAGES.
611-
612- 17. Interpretation of Sections 15 and 16.
613-
614- If the disclaimer of warranty and limitation of liability provided
615-above cannot be given local legal effect according to their terms,
616-reviewing courts shall apply local law that most closely approximates
617-an absolute waiver of all civil liability in connection with the
618-Program, unless a warranty or assumption of liability accompanies a
619-copy of the Program in return for a fee.
620-
621- END OF TERMS AND CONDITIONS
622-
623- How to Apply These Terms to Your New Programs
624-
625- If you develop a new program, and you want it to be of the greatest
626-possible use to the public, the best way to achieve this is to make it
627-free software which everyone can redistribute and change under these terms.
628-
629- To do so, attach the following notices to the program. It is safest
630-to attach them to the start of each source file to most effectively
631-state the exclusion of warranty; and each file should have at least
632-the "copyright" line and a pointer to where the full notice is found.
633-
634- <one line to give the program's name and a brief idea of what it does.>
635- Copyright (C) <year> <name of author>
636-
637- This program is free software: you can redistribute it and/or modify
638- it under the terms of the GNU General Public License as published by
639- the Free Software Foundation, either version 3 of the License, or
640- (at your option) any later version.
641-
642- This program is distributed in the hope that it will be useful,
643- but WITHOUT ANY WARRANTY; without even the implied warranty of
644- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645- GNU General Public License for more details.
646-
647- You should have received a copy of the GNU General Public License
648- along with this program. If not, see <http://www.gnu.org/licenses/>.
649-
650-Also add information on how to contact you by electronic and paper mail.
651-
652- If the program does terminal interaction, make it output a short
653-notice like this when it starts in an interactive mode:
654-
655- <program> Copyright (C) <year> <name of author>
656- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657- This is free software, and you are welcome to redistribute it
658- under certain conditions; type `show c' for details.
659-
660-The hypothetical commands `show w' and `show c' should show the appropriate
661-parts of the General Public License. Of course, your program's commands
662-might be different; for a GUI interface, you would use an "about box".
663-
664- You should also get your employer (if you work as a programmer) or school,
665-if any, to sign a "copyright disclaimer" for the program, if necessary.
666-For more information on this, and how to apply and follow the GNU GPL, see
667-<http://www.gnu.org/licenses/>.
668-
669- The GNU General Public License does not permit incorporating your program
670-into proprietary programs. If your program is a subroutine library, you
671-may consider it more useful to permit linking proprietary applications with
672-the library. If this is what you want to do, use the GNU Lesser General
673-Public License instead of this License. But first, please read
674-<http://www.gnu.org/philosophy/why-not-lgpl.html>.
--- src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_X/wa_ipc.h (revision 68)
+++ src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_X/wa_ipc.h (nonexistent)
@@ -1,1022 +0,0 @@
1-/*
2-** Copyright (C) 2003 Nullsoft, Inc.
3-**
4-** This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held
5-** liable for any damages arising from the use of this software.
6-**
7-** Permission is granted to anyone to use this software for any purpose, including commercial applications, and to
8-** alter it and redistribute it freely, subject to the following restrictions:
9-**
10-** 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
11-** If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
12-**
13-** 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
14-**
15-** 3. This notice may not be removed or altered from any source distribution.
16-**
17-*/
18-
19-#ifndef _WA_IPC_H_
20-#define _WA_IPC_H_
21-
22-/*
23-** This is the modern replacement for the classic 'frontend.h'. Most of these
24-** updates are designed for in-process use, i.e. from a plugin.
25-**
26-*/
27-
28-/* message used to sent many messages to winamp's main window.
29-** most all of the IPC_* messages involve sending the message in the form of:
30-** result = SendMessage(hwnd_winamp,WM_WA_IPC,(parameter),IPC_*);
31-*/
32-#define WM_WA_IPC WM_USER
33-/* but some of them use WM_COPYDATA. be afraid.
34-*/
35-
36-#define IPC_GETVERSION 0
37-/* int version = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETVERSION);
38-**
39-** Version will be 0x20yx for winamp 2.yx. versions previous to Winamp 2.0
40-** typically (but not always) use 0x1zyx for 1.zx versions. Weird, I know.
41-*/
42-
43-#define IPC_GETREGISTEREDVERSION 770
44-
45-
46-typedef struct {
47- char *filename;
48- char *title;
49- int length;
50-} enqueueFileWithMetaStruct; // send this to a IPC_PLAYFILE in a non WM_COPYDATA,
51-// and you get the nice desired result. if title is NULL, it is treated as a "thing",
52-// otherwise it's assumed to be a file (for speed)
53-
54-#define IPC_PLAYFILE 100 // dont be fooled, this is really the same as enqueufile
55-#define IPC_ENQUEUEFILE 100
56-/* sent as a WM_COPYDATA, with IPC_PLAYFILE as the dwData, and the string to play
57-** as the lpData. Just enqueues, does not clear the playlist or change the playback
58-** state.
59-*/
60-
61-
62-#define IPC_DELETE 101
63-#define IPC_DELETE_INT 1101 // don't use this, it's used internally by winamp when
64- // dealing with some lame explorer issues.
65-/* SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_DELETE);
66-** Use IPC_DELETE to clear Winamp's internal playlist.
67-*/
68-
69-
70-#define IPC_STARTPLAY 102 // starts playback. almost like hitting play in Winamp.
71-#define IPC_STARTPLAY_INT 1102 // used internally, don't bother using it (won't be any fun)
72-
73-
74-#define IPC_CHDIR 103
75-/* sent as a WM_COPYDATA, with IPC_CHDIR as the dwData, and the directory to change to
76-** as the lpData.
77-*/
78-
79-
80-#define IPC_ISPLAYING 104
81-/* int res = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_ISPLAYING);
82-** If it returns 1, it is playing. if it returns 3, it is paused,
83-** if it returns 0, it is not playing.
84-*/
85-
86-
87-#define IPC_GETOUTPUTTIME 105
88-/* int res = SendMessage(hwnd_winamp,WM_WA_IPC,mode,IPC_GETOUTPUTTIME);
89-** returns the position in milliseconds of the current track (mode = 0),
90-** or the track length, in seconds (mode = 1). Returns -1 if not playing or error.
91-*/
92-
93-
94-#define IPC_JUMPTOTIME 106
95-/* (requires Winamp 1.60+)
96-** SendMessage(hwnd_winamp,WM_WA_IPC,ms,IPC_JUMPTOTIME);
97-** IPC_JUMPTOTIME sets the position in milliseconds of the
98-** current song (approximately).
99-** Returns -1 if not playing, 1 on eof, or 0 if successful
100-*/
101-
102-#define IPC_GETMODULENAME 109
103-#define IPC_EX_ISRIGHTEXE 666
104-/* usually shouldnt bother using these, but here goes:
105-** send a WM_COPYDATA with IPC_GETMODULENAME, and an internal
106-** flag gets set, which if you send a normal WM_WA_IPC message with
107-** IPC_EX_ISRIGHTEXE, it returns whether or not that filename
108-** matches. lame, I know.
109-*/
110-
111-#define IPC_WRITEPLAYLIST 120
112-/* (requires Winamp 1.666+)
113-** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_WRITEPLAYLIST);
114-**
115-** IPC_WRITEPLAYLIST writes the current playlist to <winampdir>\\Winamp.m3u,
116-** and returns the current playlist position.
117-** Kinda obsoleted by some of the 2.x new stuff, but still good for when
118-** using a front-end (instead of a plug-in)
119-*/
120-
121-
122-#define IPC_SETPLAYLISTPOS 121
123-/* (requires Winamp 2.0+)
124-** SendMessage(hwnd_winamp,WM_WA_IPC,position,IPC_SETPLAYLISTPOS)
125-** IPC_SETPLAYLISTPOS sets the playlist position to 'position'. It
126-** does not change playback or anything, it just sets position, and
127-** updates the view if necessary
128-*/
129-
130-
131-#define IPC_SETVOLUME 122
132-/* (requires Winamp 2.0+)
133-** SendMessage(hwnd_winamp,WM_WA_IPC,volume,IPC_SETVOLUME);
134-** IPC_SETVOLUME sets the volume of Winamp (from 0-255).
135-*/
136-
137-
138-#define IPC_SETPANNING 123
139-/* (requires Winamp 2.0+)
140-** SendMessage(hwnd_winamp,WM_WA_IPC,panning,IPC_SETPANNING);
141-** IPC_SETPANNING sets the panning of Winamp (from 0 (left) to 255 (right)).
142-*/
143-
144-
145-#define IPC_GETLISTLENGTH 124
146-/* (requires Winamp 2.0+)
147-** int length = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTLENGTH);
148-** IPC_GETLISTLENGTH returns the length of the current playlist, in
149-** tracks.
150-*/
151-
152-
153-#define IPC_GETLISTPOS 125
154-/* (requires Winamp 2.05+)
155-** int pos=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTPOS);
156-** IPC_GETLISTPOS returns the playlist position. A lot like IPC_WRITEPLAYLIST
157-** only faster since it doesn't have to write out the list. Heh, silly me.
158-*/
159-
160-
161-#define IPC_GETINFO 126
162-/* (requires Winamp 2.05+)
163-** int inf=SendMessage(hwnd_winamp,WM_WA_IPC,mode,IPC_GETINFO);
164-** IPC_GETINFO returns info about the current playing song. The value
165-** it returns depends on the value of 'mode'.
166-** Mode Meaning
167-** ------------------
168-** 0 Samplerate (i.e. 44100)
169-** 1 Bitrate (i.e. 128)
170-** 2 Channels (i.e. 2)
171-** 3 (5+) Video LOWORD=w HIWORD=h
172-** 4 (5+) > 65536, string (video description)
173-*/
174-
175-
176-#define IPC_GETEQDATA 127
177-/* (requires Winamp 2.05+)
178-** int data=SendMessage(hwnd_winamp,WM_WA_IPC,pos,IPC_GETEQDATA);
179-** IPC_GETEQDATA queries the status of the EQ.
180-** The value returned depends on what 'pos' is set to:
181-** Value Meaning
182-** ------------------
183-** 0-9 The 10 bands of EQ data. 0-63 (+20db - -20db)
184-** 10 The preamp value. 0-63 (+20db - -20db)
185-** 11 Enabled. zero if disabled, nonzero if enabled.
186-** 12 Autoload. zero if disabled, nonzero if enabled.
187-*/
188-
189-
190-#define IPC_SETEQDATA 128
191-/* (requires Winamp 2.05+)
192-** SendMessage(hwnd_winamp,WM_WA_IPC,pos,IPC_GETEQDATA);
193-** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_SETEQDATA);
194-** IPC_SETEQDATA sets the value of the last position retrieved
195-** by IPC_GETEQDATA. This is pretty lame, and we should provide
196-** an extended version that lets you do a MAKELPARAM(pos,value).
197-** someday...
198-
199- new (2.92+):
200- if the high byte is set to 0xDB, then the third byte specifies
201- which band, and the bottom word specifies the value.
202-*/
203-
204-#define IPC_ADDBOOKMARK 129
205-/* (requires Winamp 2.4+)
206-** Sent as a WM_COPYDATA, using IPC_ADDBOOKMARK, adds the specified
207-** file/url to the Winamp bookmark list.
208-*/
209-/*
210-In winamp 5+, we use this as a normal WM_WA_IPC and the string:
211-
212- "filename\0title\0"
213-
214- to notify the library/bookmark editor that a bookmark
215-was added. Note that using this message in this context does not
216-actually add the bookmark.
217-do not use :)
218-*/
219-
220-
221-#define IPC_INSTALLPLUGIN 130
222-/* not implemented, but if it was you could do a WM_COPYDATA with
223-** a path to a .wpz, and it would install it.
224-*/
225-
226-
227-#define IPC_RESTARTWINAMP 135
228-/* (requires Winamp 2.2+)
229-** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_RESTARTWINAMP);
230-** IPC_RESTARTWINAMP will restart Winamp (isn't that obvious ? :)
231-*/
232-
233-
234-#define IPC_ISFULLSTOP 400
235-/* (requires winamp 2.7+ I think)
236-** ret=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_ISFULLSTOP);
237-** useful for when you're an output plugin, and you want to see
238-** if the stop/close is a full stop, or just between tracks.
239-** returns nonzero if it's full, zero if it's just a new track.
240-*/
241-
242-
243-#define IPC_INETAVAILABLE 242
244-/* (requires Winamp 2.05+)
245-** val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_INETAVAILABLE);
246-** IPC_INETAVAILABLE will return 1 if the Internet connection is available for Winamp.
247-*/
248-
249-
250-#define IPC_UPDTITLE 243
251-/* (requires Winamp 2.2+)
252-** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_UPDTITLE);
253-** IPC_UPDTITLE will ask Winamp to update the informations about the current title.
254-*/
255-
256-
257-#define IPC_REFRESHPLCACHE 247
258-/* (requires Winamp 2.2+)
259-** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_REFRESHPLCACHE);
260-** IPC_REFRESHPLCACHE will flush the playlist cache buffer.
261-** (send this if you want it to go refetch titles for tracks)
262-*/
263-
264-
265-#define IPC_GET_SHUFFLE 250
266-/* (requires Winamp 2.4+)
267-** val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_SHUFFLE);
268-**
269-** IPC_GET_SHUFFLE returns the status of the Shuffle option (1 if set)
270-*/
271-
272-
273-#define IPC_GET_REPEAT 251
274-/* (requires Winamp 2.4+)
275-** val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_REPEAT);
276-**
277-** IPC_GET_REPEAT returns the status of the Repeat option (1 if set)
278-*/
279-
280-
281-#define IPC_SET_SHUFFLE 252
282-/* (requires Winamp 2.4+)
283-** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_SET_SHUFFLE);
284-**
285-** IPC_SET_SHUFFLE sets the status of the Shuffle option (1 to turn it on)
286-*/
287-
288-
289-#define IPC_SET_REPEAT 253
290-/* (requires Winamp 2.4+)
291-** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_SET_REPEAT);
292-**
293-** IPC_SET_REPEAT sets the status of the Repeat option (1 to turn it on)
294-*/
295-
296-
297-#define IPC_ENABLEDISABLE_ALL_WINDOWS 259 // 0xdeadbeef to disable
298-/* (requires Winamp 2.9+)
299-** SendMessage(hwnd_winamp,WM_WA_IPC,enable?0:0xdeadbeef,IPC_MBOPENREAL);
300-** sending with 0xdeadbeef as the param disables all winamp windows,
301-** any other values will enable all winamp windows.
302-*/
303-
304-
305-#define IPC_GETWND 260
306-/* (requires Winamp 2.9+)
307-** HWND h=SendMessage(hwnd_winamp,WM_WA_IPC,IPC_GETWND_xxx,IPC_GETWND);
308-** returns the HWND of the window specified.
309-*/
310- #define IPC_GETWND_EQ 0 // use one of these for the param
311- #define IPC_GETWND_PE 1
312- #define IPC_GETWND_MB 2
313- #define IPC_GETWND_VIDEO 3
314-#define IPC_ISWNDVISIBLE 261 // same param as IPC_GETWND
315-
316-
317-
318-
319-/************************************************************************
320-***************** in-process only (WE LOVE PLUGINS)
321-************************************************************************/
322-
323-
324-#define IPC_SETSKIN 200
325-/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
326-** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)"skinname",IPC_SETSKIN);
327-** IPC_SETSKIN sets the current skin to "skinname". Note that skinname
328-** can be the name of a skin, a skin .zip file, with or without path.
329-** If path isn't specified, the default search path is the winamp skins
330-** directory.
331-*/
332-
333-
334-#define IPC_GETSKIN 201
335-/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
336-** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)skinname_buffer,IPC_GETSKIN);
337-** IPC_GETSKIN puts the directory where skin bitmaps can be found
338-** into skinname_buffer.
339-** skinname_buffer must be MAX_PATH characters in length.
340-** When using a .zip'd skin file, it'll return a temporary directory
341-** where the ZIP was decompressed.
342-*/
343-
344-
345-#define IPC_EXECPLUG 202
346-/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
347-** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)"vis_file.dll",IPC_EXECPLUG);
348-** IPC_EXECPLUG executes a visualization plug-in pointed to by WPARAM.
349-** the format of this string can be:
350-** "vis_whatever.dll"
351-** "vis_whatever.dll,0" // (first mod, file in winamp plug-in dir)
352-** "C:\\dir\\vis_whatever.dll,1"
353-*/
354-
355-
356-#define IPC_GETPLAYLISTFILE 211
357-/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
358-** char *name=SendMessage(hwnd_winamp,WM_WA_IPC,index,IPC_GETPLAYLISTFILE);
359-** IPC_GETPLAYLISTFILE gets the filename of the playlist entry [index].
360-** returns a pointer to it. returns NULL on error.
361-*/
362-
363-
364-#define IPC_GETPLAYLISTTITLE 212
365-/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
366-** char *name=SendMessage(hwnd_winamp,WM_WA_IPC,index,IPC_GETPLAYLISTTITLE);
367-**
368-** IPC_GETPLAYLISTTITLE gets the title of the playlist entry [index].
369-** returns a pointer to it. returns NULL on error.
370-*/
371-
372-
373-#define IPC_GETHTTPGETTER 240
374-/* retrieves a function pointer to a HTTP retrieval function.
375-** if this is unsupported, returns 1 or 0.
376-** the function should be:
377-** int (*httpRetrieveFile)(HWND hwnd, char *url, char *file, char *dlgtitle);
378-** if you call this function, with a parent window, a URL, an output file, and a dialog title,
379-** it will return 0 on successful download, 1 on error.
380-*/
381-
382-
383-#define IPC_MBOPEN 241
384-/* (requires Winamp 2.05+)
385-** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_MBOPEN);
386-** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)url,IPC_MBOPEN);
387-** IPC_MBOPEN will open a new URL in the minibrowser. if url is NULL, it will open the Minibrowser window.
388-*/
389-
390-
391-
392-#define IPC_CHANGECURRENTFILE 245
393-/* (requires Winamp 2.05+)
394-** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)file,IPC_CHANGECURRENTFILE);
395-** IPC_CHANGECURRENTFILE will set the current playlist item.
396-*/
397-
398-
399-#define IPC_GETMBURL 246
400-/* (requires Winamp 2.2+)
401-** char buffer[4096]; // Urls can be VERY long
402-** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)buffer,IPC_GETMBURL);
403-** IPC_GETMBURL will retrieve the current Minibrowser URL into buffer.
404-** buffer must be at least 4096 bytes long.
405-*/
406-
407-
408-#define IPC_MBBLOCK 248
409-/* (requires Winamp 2.4+)
410-** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_MBBLOCK);
411-**
412-** IPC_MBBLOCK will block the Minibrowser from updates if value is set to 1
413-*/
414-
415-#define IPC_MBOPENREAL 249
416-/* (requires Winamp 2.4+)
417-** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)url,IPC_MBOPENREAL);
418-**
419-** IPC_MBOPENREAL works the same as IPC_MBOPEN except that it will works even if
420-** IPC_MBBLOCK has been set to 1
421-*/
422-
423-#define IPC_ADJUST_OPTIONSMENUPOS 280
424-/* (requires Winamp 2.9+)
425-** int newpos=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_OPTIONSMENUPOS);
426-** moves where winamp expects the Options menu in the main menu. Useful if you wish to insert a
427-** menu item above the options/skins/vis menus.
428-*/
429-
430-#define IPC_GET_HMENU 281
431-/* (requires Winamp 2.9+)
432-** HMENU hMenu=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)0,IPC_GET_HMENU);
433-** values for data:
434-** 0 : main popup menu
435-** 1 : main menubar file menu
436-** 2 : main menubar options menu
437-** 3 : main menubar windows menu
438-** 4 : main menubar help menu
439-** other values will return NULL.
440-*/
441-
442-#define IPC_GET_EXTENDED_FILE_INFO 290 //pass a pointer to the following struct in wParam
443-#define IPC_GET_EXTENDED_FILE_INFO_HOOKABLE 296
444-/* (requires Winamp 2.9+)
445-** to use, create an extendedFileInfoStruct, point the values filename and metadata to the
446-** filename and metadata field you wish to query, and ret to a buffer, with retlen to the
447-** length of that buffer, and then SendMessage(hwnd_winamp,WM_WA_IPC,&struct,IPC_GET_EXTENDED_FILE_INFO);
448-** the results should be in the buffer pointed to by ret.
449-** returns 1 if the decoder supports a getExtendedFileInfo method
450-*/
451-typedef struct {
452- char *filename;
453- char *metadata;
454- char *ret;
455- int retlen;
456-} extendedFileInfoStruct;
457-
458-#define IPC_GET_BASIC_FILE_INFO 291 //pass a pointer to the following struct in wParam
459-typedef struct {
460- char *filename;
461-
462- int quickCheck; // set to 0 to always get, 1 for quick, 2 for default (if 2, quickCheck will be set to 0 if quick wasnot used)
463-
464- // filled in by winamp
465- int length;
466- char *title;
467- int titlelen;
468-} basicFileInfoStruct;
469-
470-#define IPC_GET_EXTLIST 292 //returns doublenull delimited. GlobalFree() it when done. if data is 0, returns raw extlist, if 1, returns something suitable for getopenfilename
471-
472-#define IPC_INFOBOX 293
473-typedef struct {
474- HWND parent;
475- char *filename;
476-} infoBoxParam;
477-
478-#define IPC_SET_EXTENDED_FILE_INFO 294 //pass a pointer to the a extendedFileInfoStruct in wParam
479-/* (requires Winamp 2.9+)
480-** to use, create an extendedFileInfoStruct, point the values filename and metadata to the
481-** filename and metadata field you wish to write in ret. (retlen is not used). and then
482-** SendMessage(hwnd_winamp,WM_WA_IPC,&struct,IPC_SET_EXTENDED_FILE_INFO);
483-** returns 1 if the metadata is supported
484-** Call IPC_WRITE_EXTENDED_FILE_INFO once you're done setting all the metadata you want to update
485-*/
486-
487-#define IPC_WRITE_EXTENDED_FILE_INFO 295
488-/* (requires Winamp 2.9+)
489-** writes all the metadata set thru IPC_SET_EXTENDED_FILE_INFO to the file
490-** returns 1 if the file has been successfully updated, 0 if error
491-*/
492-
493-#define IPC_FORMAT_TITLE 297
494-typedef struct
495-{
496- char *spec; // NULL=default winamp spec
497- void *p;
498-
499- char *out;
500- int out_len;
501-
502- char * (*TAGFUNC)(char * tag, void * p); //return 0 if not found
503- void (*TAGFREEFUNC)(char * tag,void * p);
504-} waFormatTitle;
505-
506-#define IPC_GETUNCOMPRESSINTERFACE 331
507-/* returns a function pointer to uncompress().
508-** int (*uncompress)(unsigned char *dest, unsigned long *destLen, const unsigned char *source, unsigned long sourceLen);
509-** right out of zlib, useful for decompressing zlibbed data.
510-** if you pass the parm of 0x10100000, it will return a wa_inflate_struct * to an inflate API.
511-*/
512-
513-typedef struct {
514- int (*inflateReset)(void *strm);
515- int (*inflateInit_)(void *strm,const char *version, int stream_size);
516- int (*inflate)(void *strm, int flush);
517- int (*inflateEnd)(void *strm);
518- unsigned long (*crc32)(unsigned long crc, const unsigned char *buf, unsigned int len);
519-} wa_inflate_struct;
520-
521-
522-#define IPC_ADD_PREFS_DLG 332
523-#define IPC_REMOVE_PREFS_DLG 333
524-/* (requires Winamp 2.9+)
525-** to use, allocate a prefsDlgRec structure (either on the heap or some global
526-** data, but NOT on the stack), initialze the members:
527-** hInst to the DLL instance where the resource is located
528-** dlgID to the ID of the dialog,
529-** proc to the window procedure for the dialog
530-** name to the name of the prefs page in the prefs.
531-** where to 0 (eventually we may add more options)
532-** then, SendMessage(hwnd_winamp,WM_WA_IPC,&prefsRec,IPC_ADD_PREFS_DLG);
533-**
534-** you can also IPC_REMOVE_PREFS_DLG with the address of the same prefsRec,
535-** but you shouldn't really ever have to.
536-**
537-*/
538-#define IPC_OPENPREFSTOPAGE 380 // pass an id of a builtin page, or a &prefsDlgRec of prefs page to open
539-
540-typedef struct _prefsDlgRec {
541- HINSTANCE hInst;
542- int dlgID;
543- void *proc;
544-
545- char *name;
546- int where; // 0 for options, 1 for plugins, 2 for skins, 3 for bookmarks, 4 for prefs
547-
548-
549- int _id;
550- struct _prefsDlgRec *next;
551-} prefsDlgRec;
552-
553-
554-#define IPC_GETINIFILE 334 // returns a pointer to winamp.ini
555-#define IPC_GETINIDIRECTORY 335 // returns a pointer to the directory to put config files in (if you dont want to use winamp.ini)
556-
557-#define IPC_SPAWNBUTTONPOPUP 361 // param =
558-// 0 = eject
559-// 1 = previous
560-// 2 = next
561-// 3 = pause
562-// 4 = play
563-// 5 = stop
564-
565-#define IPC_OPENURLBOX 360 // pass a HWND to a parent, returns a HGLOBAL that needs to be freed with GlobalFree(), if successful
566-#define IPC_OPENFILEBOX 362 // pass a HWND to a parent
567-#define IPC_OPENDIRBOX 363 // pass a HWND to a parent
568-
569-// pass an HWND to a parent. call this if you take over the whole UI so that the dialogs are not appearing on the
570-// bottom right of the screen since the main winamp window is at 3000x3000, call again with NULL to reset
571-#define IPC_SETDIALOGBOXPARENT 364
572-
573-
574-
575-// pass 0 for a copy of the skin HBITMAP
576-// pass 1 for name of font to use for playlist editor likeness
577-// pass 2 for font charset
578-// pass 3 for font size
579-#define IPC_GET_GENSKINBITMAP 503
580-
581-
582-#define IPC_GET_EMBEDIF 505 // pass an embedWindowState
583-// returns an HWND embedWindow(embedWindowState *); if the data is NULL, otherwise returns the HWND directly
584-typedef struct
585-{
586- HWND me; //hwnd of the window
587-
588- int flags;
589-
590- RECT r;
591-
592- void *user_ptr; // for application use
593-
594- int extra_data[64]; // for internal winamp use
595-} embedWindowState;
596-
597-#define EMBED_FLAGS_NORESIZE 1 // set this bit in embedWindowState.flags to keep window from being resizable
598-#define EMBED_FLAGS_NOTRANSPARENCY 2 // set this bit in embedWindowState.flags to make gen_ff turn transparency off for this wnd
599-
600-
601-#define IPC_EMBED_ENUM 532
602-typedef struct embedEnumStruct
603-{
604- int (*enumProc)(embedWindowState *ws, struct embedEnumStruct *param); // return 1 to abort
605- int user_data; // or more :)
606-} embedEnumStruct;
607- // pass
608-
609-#define IPC_EMBED_ISVALID 533
610-
611-#define IPC_CONVERTFILE 506
612-/* (requires Winamp 2.92+)
613-** Converts a given file to a different format (PCM, MP3, etc...)
614-** To use, pass a pointer to a waFileConvertStruct struct
615-** This struct can be either on the heap or some global
616-** data, but NOT on the stack. At least, until the conversion is done.
617-**
618-** eg: SendMessage(hwnd_winamp,WM_WA_IPC,&myConvertStruct,IPC_CONVERTFILE);
619-**
620-** Return value:
621-** 0: Can't start the conversion. Look at myConvertStruct->error for details.
622-** 1: Conversion started. Status messages will be sent to the specified callbackhwnd.
623-** Be sure to call IPC_CONVERTFILE_END when your callback window receives the
624-** IPC_CB_CONVERT_DONE message.
625-*/
626-typedef struct
627-{
628- char *sourcefile; // "c:\\source.mp3"
629- char *destfile; // "c:\\dest.pcm"
630- int destformat[8]; // like 'PCM ',srate,nch,bps
631- HWND callbackhwnd; // window that will receive the IPC_CB_CONVERT notification messages
632-
633- //filled in by winamp.exe
634- char *error; //if IPC_CONVERTFILE returns 0, the reason will be here
635-
636- int bytes_done; //you can look at both of these values for speed statistics
637- int bytes_total;
638- int bytes_out;
639-
640- int killswitch; // don't set it manually, use IPC_CONVERTFILE_END
641- int extra_data[64]; // for internal winamp use
642-} convertFileStruct;
643-
644-#define IPC_CONVERTFILE_END 507
645-/* (requires Winamp 2.92+)
646-** Stop/ends a convert process started from IPC_CONVERTFILE
647-** You need to call this when you receive the IPC_CB_CONVERTDONE message or when you
648-** want to abort a conversion process
649-**
650-** eg: SendMessage(hwnd_winamp,WM_WA_IPC,&myConvertStruct,IPC_CONVERTFILE_END);
651-**
652-** No return value
653-*/
654-
655-typedef struct {
656- HWND hwndParent;
657- int format;
658-
659- //filled in by winamp.exe
660- HWND hwndConfig;
661- int extra_data[8];
662-} convertConfigStruct;
663-#define IPC_CONVERT_CONFIG 508
664-#define IPC_CONVERT_CONFIG_END 509
665-
666-typedef struct
667-{
668- void (*enumProc)(int user_data, const char *desc, int fourcc);
669- int user_data;
670-} converterEnumFmtStruct;
671-#define IPC_CONVERT_CONFIG_ENUMFMTS 510
672-/* (requires Winamp 2.92+)
673-*/
674-
675-
676-typedef struct
677-{
678- char cdletter;
679- char *playlist_file;
680- HWND callback_hwnd;
681-
682- //filled in by winamp.exe
683- char *error;
684-} burnCDStruct;
685-#define IPC_BURN_CD 511
686-/* (requires Winamp 5.0+)
687-*/
688-
689-typedef struct
690-{
691- convertFileStruct *cfs;
692- int priority;
693-} convertSetPriority;
694-#define IPC_CONVERT_SET_PRIORITY 512
695-
696-typedef struct
697-{
698- char *filename;
699- char *title; // 2048 bytes
700- int length;
701- int force_useformatting; // can set this to 1 if you want to force a url to use title formatting shit
702-} waHookTitleStruct;
703-// return TRUE if you hook this
704-#define IPC_HOOK_TITLES 850
705-
706-#define IPC_GETSADATAFUNC 800
707-// 0: returns a char *export_sa_get() that returns 150 bytes of data
708-// 1: returns a export_sa_setreq(int want);
709-
710-#define IPC_ISMAINWNDVISIBLE 900
711-
712-
713-#define IPC_SETPLEDITCOLORS 920
714-typedef struct
715-{
716- int numElems;
717- int *elems;
718- HBITMAP bm; // set if you want to override
719-} waSetPlColorsStruct;
720-
721-
722-// the following IPC use waSpawnMenuParms as parameter
723-#define IPC_SPAWNEQPRESETMENU 933
724-#define IPC_SPAWNFILEMENU 934 //menubar
725-#define IPC_SPAWNOPTIONSMENU 935 //menubar
726-#define IPC_SPAWNWINDOWSMENU 936 //menubar
727-#define IPC_SPAWNHELPMENU 937 //menubar
728-#define IPC_SPAWNPLAYMENU 938 //menubar
729-#define IPC_SPAWNPEFILEMENU 939 //menubar
730-#define IPC_SPAWNPEPLAYLISTMENU 940 //menubar
731-#define IPC_SPAWNPESORTMENU 941 //menubar
732-#define IPC_SPAWNPEHELPMENU 942 //menubar
733-#define IPC_SPAWNMLFILEMENU 943 //menubar
734-#define IPC_SPAWNMLVIEWMENU 944 //menubar
735-#define IPC_SPAWNMLHELPMENU 945 //menubar
736-#define IPC_SPAWNPELISTOFPLAYLISTS 946
737-
738-typedef struct
739-{
740- HWND wnd;
741- int xpos; // in screen coordinates
742- int ypos;
743-} waSpawnMenuParms;
744-
745-// waSpawnMenuParms2 is used by the menubar submenus
746-typedef struct
747-{
748- HWND wnd;
749- int xpos; // in screen coordinates
750- int ypos;
751- int width;
752- int height;
753-} waSpawnMenuParms2;
754-
755-
756-// system tray sends this (you might want to simulate it)
757-#define WM_WA_SYSTRAY WM_USER+1
758-
759-// input plugins send this when they are done playing back
760-#define WM_WA_MPEG_EOF WM_USER+2
761-
762-
763-
764-//// video stuff
765-
766-#define IPC_IS_PLAYING_VIDEO 501 // returns >1 if playing, 0 if not, 1 if old version (so who knows):)
767-#define IPC_GET_IVIDEOOUTPUT 500 // see below for IVideoOutput interface
768-#define VIDEO_MAKETYPE(A,B,C,D) ((A) | ((B)<<8) | ((C)<<16) | ((D)<<24))
769-#define VIDUSER_SET_INFOSTRING 0x1000
770-#define VIDUSER_GET_VIDEOHWND 0x1001
771-#define VIDUSER_SET_VFLIP 0x1002
772-
773-#ifndef NO_IVIDEO_DECLARE
774-#ifdef __cplusplus
775-
776-class VideoOutput;
777-class SubsItem;
778-
779-typedef struct {
780- unsigned char* baseAddr;
781- long rowBytes;
782-} YV12_PLANE;
783-
784-typedef struct {
785- YV12_PLANE y;
786- YV12_PLANE u;
787- YV12_PLANE v;
788-} YV12_PLANES;
789-
790-class IVideoOutput
791-{
792- public:
793- virtual ~IVideoOutput() { }
794- virtual int open(int w, int h, int vflip, double aspectratio, unsigned int fmt)=0;
795- virtual void setcallback(LRESULT (*msgcallback)(void *token, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam), void *token) { }
796- virtual void close()=0;
797- virtual void draw(void *frame)=0;
798- virtual void drawSubtitle(SubsItem *item) { }
799- virtual void showStatusMsg(const char *text) { }
800- virtual int get_latency() { return 0; }
801- virtual void notifyBufferState(int bufferstate) { } /* 0-255*/
802-
803- virtual int extended(int param1, int param2, int param3) { return 0; } // Dispatchable, eat this!
804-};
805-#endif //cplusplus
806-#endif//NO_IVIDEO_DECLARE
807-
808-// these messages are callbacks that you can grab by subclassing the winamp window
809-
810-// wParam =
811-#define IPC_CB_WND_EQ 0 // use one of these for the param
812-#define IPC_CB_WND_PE 1
813-#define IPC_CB_WND_MB 2
814-#define IPC_CB_WND_VIDEO 3
815-#define IPC_CB_WND_MAIN 4
816-
817-#define IPC_CB_ONSHOWWND 600
818-#define IPC_CB_ONHIDEWND 601
819-
820-#define IPC_CB_GETTOOLTIP 602
821-
822-#define IPC_CB_MISC 603
823- #define IPC_CB_MISC_TITLE 0
824- #define IPC_CB_MISC_VOLUME 1 // volume/pan
825- #define IPC_CB_MISC_STATUS 2
826- #define IPC_CB_MISC_EQ 3
827- #define IPC_CB_MISC_INFO 4
828- #define IPC_CB_MISC_VIDEOINFO 5
829-
830-#define IPC_CB_CONVERT_STATUS 604 // param value goes from 0 to 100 (percent)
831-#define IPC_CB_CONVERT_DONE 605
832-
833-#define IPC_ADJUST_FFWINDOWSMENUPOS 606
834-/* (requires Winamp 2.9+)
835-** int newpos=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_FFWINDOWSMENUPOS);
836-** moves where winamp expects the freeform windows in the menubar windows main menu. Useful if you wish to insert a
837-** menu item above extra freeform windows.
838-*/
839-
840-#define IPC_ISDOUBLESIZE 608
841-
842-#define IPC_ADJUST_FFOPTIONSMENUPOS 609
843-/* (requires Winamp 2.9+)
844-** int newpos=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_FFOPTIONSMENUPOS);
845-** moves where winamp expects the freeform preferences item in the menubar windows main menu. Useful if you wish to insert a
846-** menu item above preferences item.
847-*/
848-
849-#define IPC_GETTIMEDISPLAYMODE 610 // returns 0 if displaying elapsed time or 1 if displaying remaining time
850-
851-#define IPC_SETVISWND 611 // param is hwnd, setting this allows you to receive ID_VIS_NEXT/PREVOUS/RANDOM/FS wm_commands
852-#define ID_VIS_NEXT 40382
853-#define ID_VIS_PREV 40383
854-#define ID_VIS_RANDOM 40384
855-#define ID_VIS_FS 40389
856-#define ID_VIS_CFG 40390
857-#define ID_VIS_MENU 40391
858-
859-#define IPC_GETVISWND 612 // returns the vis cmd handler hwnd
860-#define IPC_ISVISRUNNING 613
861-#define IPC_CB_VISRANDOM 628 // param is status of random
862-
863-#define IPC_SETIDEALVIDEOSIZE 614 // sent by winamp to winamp, trap it if you need it. width=HIWORD(param), height=LOWORD(param)
864-
865-#define IPC_GETSTOPONVIDEOCLOSE 615
866-#define IPC_SETSTOPONVIDEOCLOSE 616
867-
868-typedef struct {
869- HWND hwnd;
870- int uMsg;
871- int wParam;
872- int lParam;
873-} transAccelStruct;
874-
875-#define IPC_TRANSLATEACCELERATOR 617
876-
877-typedef struct {
878- int cmd;
879- int x;
880- int y;
881- int align;
882-} windowCommand; // send this as param to an IPC_PLCMD, IPC_MBCMD, IPC_VIDCMD
883-
884-#define IPC_CB_ONTOGGLEAOT 618
885-
886-#define IPC_GETPREFSWND 619
887-
888-#define IPC_SET_PE_WIDTHHEIGHT 620 // data is a pointer to a POINT structure that holds width & height
889-
890-#define IPC_GETLANGUAGEPACKINSTANCE 621
891-
892-#define IPC_CB_PEINFOTEXT 622 // data is a string, ie: "04:21/45:02"
893-
894-#define IPC_CB_OUTPUTCHANGED 623 // output plugin was changed in config
895-
896-#define IPC_GETOUTPUTPLUGIN 625
897-
898-#define IPC_SETDRAWBORDERS 626
899-#define IPC_DISABLESKINCURSORS 627
900-#define IPC_CB_RESETFONT 629
901-
902-#define IPC_IS_FULLSCREEN 630 // returns 1 if video or vis is in fullscreen mode
903-#define IPC_SET_VIS_FS_FLAG 631 // a vis should send this message with 1/as param to notify winamp that it has gone to or has come back from fullscreen mode
904-
905-#define IPC_SHOW_NOTIFICATION 632
906-
907-#define IPC_GETSKININFO 633
908-
909-// >>>>>>>>>>> Next is 634
910-
911-#define IPC_PLCMD 1000
912-
913-#define PLCMD_ADD 0
914-#define PLCMD_REM 1
915-#define PLCMD_SEL 2
916-#define PLCMD_MISC 3
917-#define PLCMD_LIST 4
918-
919-#define IPC_MBCMD 1001
920-
921-#define MBCMD_BACK 0
922-#define MBCMD_FORWARD 1
923-#define MBCMD_STOP 2
924-#define MBCMD_RELOAD 3
925-#define MBCMD_MISC 4
926-
927-#define IPC_VIDCMD 1002
928-
929-#define VIDCMD_FULLSCREEN 0
930-#define VIDCMD_1X 1
931-#define VIDCMD_2X 2
932-#define VIDCMD_LIB 3
933-#define VIDPOPUP_MISC 4
934-
935-#define IPC_MBURL 1003 //sets the URL
936-#define IPC_MBGETCURURL 1004 //copies the current URL into wParam (have a 4096 buffer ready)
937-#define IPC_MBGETDESC 1005 //copies the current URL description into wParam (have a 4096 buffer ready)
938-#define IPC_MBCHECKLOCFILE 1006 //checks that the link file is up to date (otherwise updates it). wParam=parent HWND
939-#define IPC_MBREFRESH 1007 //refreshes the "now playing" view in the library
940-#define IPC_MBGETDEFURL 1008 //copies the default URL into wParam (have a 4096 buffer ready)
941-
942-#define IPC_STATS_LIBRARY_ITEMCNT 1300 // updates library count status
943-
944-// IPC 2000-3000 reserved for freeform messages, see gen_ff/ff_ipc.h
945-#define IPC_FF_FIRST 2000
946-#define IPC_FF_LAST 3000
947-
948-#define IPC_GETDROPTARGET 3001
949-
950-#define IPC_PLAYLIST_MODIFIED 3002 // sent to main wnd whenever the playlist is modified
951-
952-#define IPC_PLAYING_FILE 3003 // sent to main wnd with the file as parm whenever a file is played
953-#define IPC_FILE_TAG_MAY_HAVE_UPDATED 3004 // sent to main wnd with the file as parm whenever a file tag might be updated
954-
955-
956-#define IPC_ALLOW_PLAYTRACKING 3007
957-// send nonzero to allow, zero to disallow
958-
959-#define IPC_HOOK_OKTOQUIT 3010 // return 0 to abort a quit, nonzero if quit is OK
960-
961-#define IPC_WRITECONFIG 3011 // pass 2 to write all, 1 to write playlist + common, 0 to write common+less common
962-
963-// pass a string to be the name to register, and returns a value > 65536, which is a unique value you can use
964-// for custom WM_WA_IPC messages.
965-#define IPC_REGISTER_WINAMP_IPCMESSAGE 65536
966-
967-/**************************************************************************/
968-
969-/*
970-** Finally there are some WM_COMMAND messages that you can use to send
971-** Winamp misc commands.
972-**
973-** To send these, use:
974-**
975-** SendMessage(hwnd_winamp, WM_COMMAND,command_name,0);
976-*/
977-
978-#define WINAMP_OPTIONS_EQ 40036 // toggles the EQ window
979-#define WINAMP_OPTIONS_PLEDIT 40040 // toggles the playlist window
980-#define WINAMP_VOLUMEUP 40058 // turns the volume up a little
981-#define WINAMP_VOLUMEDOWN 40059 // turns the volume down a little
982-#define WINAMP_FFWD5S 40060 // fast forwards 5 seconds
983-#define WINAMP_REW5S 40061 // rewinds 5 seconds
984-
985-// the following are the five main control buttons, with optionally shift
986-// or control pressed
987-// (for the exact functions of each, just try it out)
988-#define WINAMP_BUTTON1 40044
989-#define WINAMP_BUTTON2 40045
990-#define WINAMP_BUTTON3 40046
991-#define WINAMP_BUTTON4 40047
992-#define WINAMP_BUTTON5 40048
993-#define WINAMP_BUTTON1_SHIFT 40144
994-#define WINAMP_BUTTON2_SHIFT 40145
995-#define WINAMP_BUTTON3_SHIFT 40146
996-#define WINAMP_BUTTON4_SHIFT 40147
997-#define WINAMP_BUTTON5_SHIFT 40148
998-#define WINAMP_BUTTON1_CTRL 40154
999-#define WINAMP_BUTTON2_CTRL 40155
1000-#define WINAMP_BUTTON3_CTRL 40156
1001-#define WINAMP_BUTTON4_CTRL 40157
1002-#define WINAMP_BUTTON5_CTRL 40158
1003-
1004-#define WINAMP_FILE_PLAY 40029 // pops up the load file(s) box
1005-#define WINAMP_FILE_DIR 40187 // pops up the load directory box
1006-#define WINAMP_OPTIONS_PREFS 40012 // pops up the preferences
1007-#define WINAMP_OPTIONS_AOT 40019 // toggles always on top
1008-#define WINAMP_HELP_ABOUT 40041 // pops up the about box :)
1009-
1010-#define ID_MAIN_PLAY_AUDIOCD1 40323 // starts playing the audio CD in the first CD reader
1011-#define ID_MAIN_PLAY_AUDIOCD2 40323 // plays the 2nd
1012-#define ID_MAIN_PLAY_AUDIOCD3 40323 // plays the 3nd
1013-#define ID_MAIN_PLAY_AUDIOCD4 40323 // plays the 4nd
1014-
1015-// IDs 42000 to 45000 are reserved for gen_ff
1016-// IDs from 45000 to 57000 are reserved for library
1017-
1018-#endif//_WA_IPC_H_
1019-
1020-/*
1021-** EOF.. Enjoy.
1022-*/
\ No newline at end of file
--- src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_X/README (revision 68)
+++ src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_X/README (nonexistent)
@@ -1,48 +0,0 @@
1-foo_mixi_feat_winamp 0.0.0.7,
2-Mixi Music plugin for Winamp, bridge component.
3-Copyright (C) 2006,2007 Yossiepon Oniichan, All Rights Reserved.
4-
5-
6-* Copying
7-
8- This program is free software: you can redistribute it and/or modify
9- it under the terms of the GNU Lesser General Public License as
10- published by the Free Software Foundation, either version 3 of
11- the License, or (at your option) any later version.
12-
13- This program is distributed in the hope that it will be useful,
14- but WITHOUT ANY WARRANTY; without even the implied warranty of
15- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16- GNU Lesser General Public License for more details.
17-
18- You should have received a copy of the GNU Lesser General Public License
19- along with this program. If not, see <http://www.gnu.org/licenses/>.
20-
21- Please see the file COPYING and COPYING.LESSER in this directory for
22- full copyright information.
23-
24-
25-* Compilation and Installation
26-
27- Please read INSTALL for compilation instructions.
28-
29-
30-* See also
31-
32- The latest version of foo_mixi_feat_winamp can be obtained at
33- http://foo-mixi.sourceforge.net/
34-
35- There are two mailing lists
36- foo-mixi-users@lists.sourceforge.jp
37- foo-mixi-dev@lists.sourceforge.jp
38-
39- please follow the link in
40-
41- http://sourceforge.jp/projects/foo-mixi
42-
43- to subscribe to the lists or to visit the archives.
44-
45-
46-Enjoy,
47-
48-Yossiepon Oniichan (yoshy at users.sourceforge.jp) (06 November 2007)
--- src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_X/resource.h (revision 68)
+++ src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_X/resource.h (nonexistent)
@@ -1,58 +0,0 @@
1-//{{NO_DEPENDENCIES}}
2-// Microsoft Visual C++ generated include file.
3-// Used by foo_mixi_feat_winamp.rc
4-//
5-#define IDD_PREFERENCE 101
6-#define IDD_ADVANCED_SETTINGS 102
7-#define IDD_DEBUG_SETTINGS 103
8-#define IDC_CONFIGURE 1000
9-#define IDC_USE_PLUGIN 1001
10-#define IDC_VERSION 1002
11-#define IDC_BUILD 1003
12-#define IDC_SEND_INTERVAL_1ST 1004
13-#define IDC_SEND_INTERVAL_2ND 1005
14-#define IDC_SEND_INTERVAL_SLIDER_2ND 1006
15-#define IDC_SEND_INTERVAL_SLIDER_1ST 1007
16-#define IDC_DISABLE_DUPLICATE_SONG 1008
17-#define IDC_DISABLE_DUMMY_MP3 1009
18-#define IDC_SEND_INTERVAL_SLIDER_3RD 1010
19-#define IDC_SEND_INTERVAL_3RD 1011
20-#define IDC_CAPTION_ADVANCED 1012
21-#define IDC_DUMMY_MP3_LOCATION 1013
22-#define IDC_VERSION_ADVANCED 1014
23-#define IDC_BUILD_ADVANCED 1015
24-#define IDC_MEDIA_LIBRARY_REGISTERED_FILE_ONLY 1016
25-#define IDC_EXPLICITLY_TAGGED_FILE_ONLY 1017
26-#define IDC_GEN_MIXI_PATH 1018
27-#define IDC_GEN_MIXI_PATH_REF 1019
28-#define IDC_CAPTION_DEBUG 1020
29-#define IDC_ENABLE_DEBUG_LOG 1021
30-#define IDC_DEBUG_DUMMYAMP_INIT 1022
31-#define IDC_DEBUG_DUMMYAMP_PROC 1023
32-#define IDC_DEBUG_TRACK_INFO 1024
33-#define IDC_DEBUG_PLUGIN 1025
34-#define IDC_DEBUG_CALLBACK 1026
35-#define IDC_VERSION_DEBUG 1027
36-#define IDC_BUILD_DEBUG 1028
37-#define IDC_SHOW_DUMMYAMP 1029
38-#define IDC_DUMMYAMP_TITLE_FORMAT 1030
39-#define IDC_DUMMYAMP_PLAYLIST_FORMAT 1031
40-#define IDC_DISABLE_ANSI_TRANS 1032
41-#define IDC_ENABLE_EXT_IPC_PROC 1033
42-#define IDC_DUMMYAMP_FRAME 1034
43-#define IDC_ENABLE_STREAMING_FILE 1035
44-#define IDC_NO_ARTIST_NAME 1036
45-#define IDC_NO_TITLE_NAME 1037
46-#define IDC_NO_ALBUM_NAME 1038
47-#define IDC_NO_GENRE_NAME 1039
48-
49-// Next default values for new objects
50-//
51-#ifdef APSTUDIO_INVOKED
52-#ifndef APSTUDIO_READONLY_SYMBOLS
53-#define _APS_NEXT_RESOURCE_VALUE 104
54-#define _APS_NEXT_COMMAND_VALUE 40001
55-#define _APS_NEXT_CONTROL_VALUE 1040
56-#define _APS_NEXT_SYMED_VALUE 101
57-#endif
58-#endif
--- src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_4_SDK72/foo_mixi_feat_winamp.cpp (nonexistent)
+++ src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_4_SDK72/foo_mixi_feat_winamp.cpp (revision 69)
@@ -0,0 +1,4317 @@
1+#define BUILD_UNICODE
2+
3+#if defined(BUILD_UNICODE)
4+#if !defined(UNICODE)
5+#define _UNICODE
6+#define UNICODE
7+#endif
8+#endif
9+
10+#if defined(UNICODE) && !defined(BUILD_UNICODE)
11+#define BUILD_UNICODE
12+#endif
13+
14+#define LONG_PTR_TO_WNDPROC(p) (reinterpret_cast<WNDPROC>(p))
15+#define WNDPROC_TO_LONG_PTR(p) (reinterpret_cast<LONG_PTR>(p))
16+
17+#include <windows.h>
18+#include <lmcons.h>
19+#include <process.h>
20+#include <shlobj.h>
21+
22+#include <string>
23+#include <vector>
24+#include <map>
25+
26+typedef std::vector<std::string> Strings;
27+typedef Strings::iterator StringsIt;
28+typedef Strings::const_iterator StringsCIt;
29+
30+typedef std::map<std::string, std::string> StringMap;
31+typedef StringMap::iterator StringMapIt;
32+typedef StringMap::const_iterator StringMapCIt;
33+
34+typedef std::map<std::string, UINT> UIntMap;
35+typedef UIntMap::iterator UIntMapIt;
36+typedef UIntMap::const_iterator UIntMapCIt;
37+
38+#include "../SDK/foobar2000.h"
39+#include "../SDK/component.h"
40+#include "../helpers/helpers.h"
41+
42+#if 0
43+#include <wx/string.h>
44+#endif
45+
46+#include "GEN.h"
47+#include "wa_ipc.h"
48+
49+#if 0
50+#define ID3LIB_LINKOPTION 3
51+#include <id3/tag.h>
52+#include <id3/misc_support.h>
53+#endif
54+
55+#include "resource.h"
56+
57+#if defined(_FOOBAR2000_UTF8API_H_)
58+# define FB2K_MAJOR_VERSION 8
59+#else
60+# define FB2K_MAJOR_VERSION 9
61+#endif
62+
63+#define IS_FB2K_VER08 (FB2K_MAJOR_VERSION == 8)
64+#define IS_FB2K_VER09 (FB2K_MAJOR_VERSION == 9)
65+
66+#define FB2K_COMPONENTS_DIR _T("components\\")
67+#define GEN_MIXI_FILE_NAME _T("gen_mixi_for_winamp.dll")
68+#define GEN_MIXI_FUNC_NAME_GET_GENERAL_PURPOSE_PLUGIN "winampGetGeneralPurposePlugin"
69+
70+#define DUMMY_MP3_FILE_NAME _T("foo_mixi_feat_winamp.mp3")
71+#define APPDATA_MIXI_STATION_DIR _T("\\mixi\\mixi")
72+#define DEFAULT_WINAMP_TITLE "Winamp"
73+#define DEFAULT_DUMMYAMP_TITLE "DummyAmp"
74+
75+#define CODEC_TYPE_VORBIS "Vorbis"
76+#define CODEC_TYPE_MP3 "MP3"
77+
78+#define IS_SUPPORTED_FORMAT_BY_GEN_MIXI(codec) (!::lstrcmpA(codec, CODEC_TYPE_VORBIS) || !::lstrcmpA(codec, CODEC_TYPE_MP3))
79+
80+#if !defined(ENABLE_MSN)
81+#define PLUGIN_CAPTION "mixi music plugin for Winamp, bridge component"
82+#define PLUGIN_CAPTION_JP "mixi ミュージック"
83+#else
84+#define PLUGIN_CAPTION "Mixi Music plugin for M2M"
85+#endif
86+
87+#define ADVANCED_SETTINGS_CAPTION "高度な設定"
88+#define DUMMYAMP_FRAME_CAPTION _T("DummyAmp の設定 (動作状態:%s)")
89+#define DUMMYAMP_BEFORE_INIT_MODE _T("初回再生の待機中")
90+#define DUMMYAMP_HOOK_MODE _T("既存 Winamp API Emulator をフック中")
91+#define DUMMYAMP_STANDALONE_MODE _T("単独で Winamp API をエミュレート中")
92+#define DEBUG_SETTINGS_CAPTION "デバッグ用の設定"
93+#define PLUGIN_VERSION "0.2.1.0"
94+
95+#define DEFAULT_DUMMYAMP_TITLE_FORMAT "[%artist% - ]$if(%title%,%title%,%_filename%)"
96+
97+#define URL_FOO_MIXI_HOME "http://foo-mixi.sourceforge.jp/"
98+
99+#define FORMAT_FILEPATH "%_path%"
100+#define FORMAT_FILEPATHRAW "%_path_raw%"
101+#define FORMAT_ARTIST "%artist%"
102+#define FORMAT_TRACKTITLE "%title%"
103+#define FORMAT_ALBUMTITLE "%album%"
104+#define FORMAT_GENRE "%genre%"
105+#define FORMAT_CODEC "%__codec%"
106+
107+#if IS_FB2K_VER08
108+#define FORMAT_LISTINDEX "%_playlist_number%"
109+#elif IS_FB2K_VER09
110+#define FORMAT_LISTINDEX "%list_index%"
111+#endif
112+
113+#define IPC_GETOUTPUTTIME_PositionMSec 0
114+#define IPC_GETOUTPUTTIME_TotalSec 1
115+
116+#define IPC_INTERNAL_REFRESHLISTINFO 0x4000
117+#define IPC_INTERNAL_REFRESHDYNINFO 0x4001
118+
119+#define RESENT_INTERVAL 5000
120+#define FORCE_RESENT_MODE 0
121+//#define DISABLE_KICK_GEN_MIXI_LOOP
122+
123+#define GEN_MIXI_REQUIRED_SECONDS 6
124+#define GEN_MIXI_TRIGGER_SECONDS 6
125+#define GEN_MIXI_MARGIN_SECONDS 0
126+
127+#define REQUIRED_MINIMUM_TIME 8
128+#define SEND_TIME_RATE_LOWERBOUND 0
129+#define REQUIRED_MAXIMUM_TIME 0
130+
131+#define CONTROL_SEND_TIMING
132+
133+//#define ENABLE_MSN
134+
135+#if IS_FB2K_VER09
136+using namespace pfc;
137+using namespace pfc::stringcvt;
138+#define pfc_string_to_float string_to_float
139+#endif
140+
141+/*
142+ foo_mixi_feat_winamp: project dependencies
143+
144+ foo_mixi_feat_winamp
145+ foobar2000_SDK
146+ utf8api(0.8.3)
147+ pfc
148+ foobar2000_sdk_helpers
149+ pfc
150+ foobar2000_component_client(0.9.X)
151+ id3lib
152+ zlib
153+
154+ library dependencies: wxbase28.lib, id3lib.lib, ../shared/shared.lib(0.9.X)
155+ runtime library: Multi-Thread (DLL) or (Debug,DLL)
156+ !! ensure all projects that depended from this project are correctly set to MT DLL !!
157+ ignore: LIBCMT [Win32 Release] (or LIBCMTD [Win32 Debug])
158+*/
159+
160+// if wxWidgets are updated, change lib names below and linker libpath option.
161+
162+#if 0
163+#if defined(_DEBUG)
164+#if defined(BUILD_UNICODE)
165+#pragma comment(lib, "wxbase28ud.lib")
166+#else
167+#pragma comment(lib, "wxbase28d.lib")
168+#endif
169+#else
170+#if defined(BUILD_UNICODE)
171+#pragma comment(lib, "wxbase28u.lib")
172+#else
173+#pragma comment(lib, "wxbase28.lib")
174+#endif
175+#endif
176+#endif
177+
178+// now id3lib automatically added to linker target,
179+// because it generated from depended project.
180+//#pragma comment(lib, "id3lib.lib")
181+
182+#if IS_FB2K_VER09
183+#pragma comment(lib, "../shared/shared.lib")
184+#endif
185+
186+typedef std::basic_string<TCHAR> tstring;
187+
188+typedef TCHAR Str64K[65536];
189+typedef char StrDBCS64K[65536];
190+
191+tstring GetErrorMessage(DWORD errCode);
192+void putLogError(LPCTSTR pMethod, LPCTSTR pErrMsg, DWORD dwErrCode);
193+void setDlgVersionInfo(HWND wnd, UINT idc_version, UINT idc_build);
194+void DebugPrint(int severity, LPCTSTR lpszFormat, ...);
195+void DebugPrintDBCS(int severity, LPCSTR lpszFormat, ...);
196+void DebugPrint8(int severity, LPCSTR lpszFormat, ...);
197+
198+#define LOGLEVEL_NONE 0
199+#define LOGLEVEL_WARNING 1
200+#define LOGLEVEL_ERROR 2
201+
202+#if IS_FB2K_VER09
203+namespace console
204+{
205+ enum {
206+ SEVERITY_INFO = 0,
207+ SEVERITY_WARNING = 1,
208+ SEVERITY_CRITICAL = 2
209+ };
210+};
211+#endif
212+
213+#define LOG_TRACE(f, ...) if(cfg_enable_debug_log) DebugPrint(console::SEVERITY_INFO, f, __VA_ARGS__)
214+#define LOG_DEBUG(f, ...) if(cfg_enable_debug_log) DebugPrint(console::SEVERITY_INFO, f, __VA_ARGS__)
215+
216+#define LOG_TRACE8(f, ...) if(cfg_enable_debug_log) DebugPrint8(console::SEVERITY_INFO, f, __VA_ARGS__)
217+#define LOG_DEBUG8(f, ...) if(cfg_enable_debug_log) DebugPrint8(console::SEVERITY_INFO, f, __VA_ARGS__)
218+
219+#define LOG_TRACE_ANSI(f, ...) if(cfg_enable_debug_log) DebugPrintDBCS(console::SEVERITY_INFO, f, __VA_ARGS__)
220+#define LOG_DEBUG_ANSI(f, ...) if(cfg_enable_debug_log) DebugPrintDBCS(console::SEVERITY_INFO, f, __VA_ARGS__)
221+
222+#define LOG_INFO(f, ...) DebugPrint(console::SEVERITY_INFO, f, __VA_ARGS__)
223+#define LOG_WARN(f, ...) DebugPrint(console::SEVERITY_WARNING, f, __VA_ARGS__)
224+#define LOG_ERROR(f, ...) DebugPrint(console::SEVERITY_CRITICAL, f, __VA_ARGS__)
225+
226+#if defined(BUILD_UNICODE)
227+#define TRACE_DBCS(f, ...) if(cfg_enable_debug_log) DebugPrintDBCS(console::SEVERITY_INFO, f, __VA_ARGS__)
228+#else
229+#define TRACE_DBCS(f, ...) if(cfg_enable_debug_log) DebugPrint(console::SEVERITY_INFO, f, __VA_ARGS__)
230+#endif
231+
232+#define DEBUG_DUMMYAMP_INIT(f, ...) if(cfg_debug_dummyamp_init >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
233+#define TRACE_DUMMYAMP_INIT(f, ...) if(cfg_debug_dummyamp_init >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
234+
235+#define DEBUG_DUMMYAMP_PROC(f, ...) if(cfg_debug_dummyamp_proc >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
236+#define DEBUG_DUMMYAMP_PROC8(f, ...) if(cfg_debug_dummyamp_proc >= LOGLEVEL_WARNING) LOG_DEBUG8(f, __VA_ARGS__)
237+#define TRACE_DUMMYAMP_PROC(f, ...) if(cfg_debug_dummyamp_proc >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
238+#define TRACE_DUMMYAMP_PROC8(f, ...) if(cfg_debug_dummyamp_proc >= LOGLEVEL_ERROR) LOG_TRACE8(f, __VA_ARGS__)
239+
240+#define DEBUG_TRACK_INFO(f, ...) if(cfg_debug_track_info >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
241+#define DEBUG_TRACK_INFO8(f, ...) if(cfg_debug_track_info >= LOGLEVEL_WARNING) LOG_DEBUG8(f, __VA_ARGS__)
242+#define DEBUG_TRACK_INFO_ANSI(f, ...) if(cfg_debug_track_info >= LOGLEVEL_WARNING) LOG_DEBUG_ANSI(f, __VA_ARGS__)
243+#define TRACE_TRACK_INFO(f, ...) if(cfg_debug_track_info >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
244+#define TRACE_TRACK_INFO8(f, ...) if(cfg_debug_track_info >= LOGLEVEL_ERROR) LOG_TRACE8(f, __VA_ARGS__)
245+#define TRACE_TRACK_INFO_ANSI(f, ...) if(cfg_debug_track_info >= LOGLEVEL_ERROR) LOG_TRACE_ANSI(f, __VA_ARGS__)
246+
247+#define DEBUG_PLUGIN(f, ...) if(cfg_debug_plugin >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
248+#define TRACE_PLUGIN(f, ...) if(cfg_debug_plugin >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
249+
250+#define DEBUG_CALLBACK(f, ...) if(cfg_debug_callback >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
251+#define TRACE_CALLBACK(f, ...) if(cfg_debug_callback >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
252+
253+static string_utf8_from_os g_pluginCaption8(_T(PLUGIN_CAPTION_JP));
254+static string_utf8_from_os g_pluginVersion8(_T(PLUGIN_VERSION));
255+static string_utf8_from_os g_pluginAbout8(
256+ _T(PLUGIN_CAPTION_JP) _T(" ") _T(PLUGIN_VERSION) _T("\nCopyright (C) 2006-2009 Yossiepon Oniichan, All Rights Reserved."));
257+
258+DECLARE_COMPONENT_VERSION(g_pluginCaption8, g_pluginVersion8, g_pluginAbout8);
259+
260+static string_utf8_from_os g_advancedSettingsCaption8(_T(ADVANCED_SETTINGS_CAPTION));
261+static string_utf8_from_os g_debugSettingsCaption8(_T(DEBUG_SETTINGS_CAPTION));
262+
263+static string_utf8_from_os g_menu_item(_T("Components/Mixi/mixiミュージック連携を有効にする"));
264+
265+static string_utf8_from_os g_menu_item_title(_T("mixiミュージック連携を有効にする"));
266+static string_utf8_from_os g_menu_item_description(_T("mixiミュージックへの曲情報の送信について、有効/無効を切り替えます"));
267+
268+#if IS_FB2K_VER08
269+static cfg_int cfg_use_plugin("usePlugin", 1);
270+
271+static cfg_string cfg_no_artist_name("NoArtistName", "No Artist");
272+static cfg_string cfg_no_title_name("NoTitleName", "No Title");
273+static cfg_string cfg_no_album_name("NoAlbumName", "No Title");
274+static cfg_string cfg_no_genre_name("NoGenreName", "Other");
275+
276+static cfg_string cfg_send_interval1("SendInterval1", "20");
277+static cfg_string cfg_send_interval2("SendInterval2", "66");
278+static cfg_string cfg_send_interval3("SendInterval3", "300");
279+
280+static cfg_int cfg_disable_duplicate_song("DisableDuplicateSong", 0);
281+static cfg_int cfg_media_library_registered_file_only("MediaLibraryRegisteredFileOnly", 0);
282+static cfg_int cfg_explicitly_tagged_file_only("ExplicitlyTaggedFileOnly", 0);
283+static cfg_int cfg_enable_streaming_file("EnableStreamingFile", 0);
284+
285+static cfg_int cfg_disable_dummy_mp3("DisableDummyMp3", 0);
286+static cfg_int cfg_dummy_mp3_location("DummyMp3Location", 0);
287+
288+static cfg_int cfg_show_dummyamp("ShowDummyAmp", 0);
289+static cfg_string cfg_dummyamp_title_format("DummyAmpTitleFormat", DEFAULT_DUMMYAMP_TITLE_FORMAT);
290+static cfg_string cfg_dummyamp_playlist_format("DummyAmpPlaylistFormat", DEFAULT_DUMMYAMP_TITLE_FORMAT);
291+static cfg_int cfg_disable_ansi_trans("DisableAnsiTrans", 0);
292+static cfg_int cfg_enable_ext_ipc_proc("EnableExtIpcProc", 1);
293+
294+static cfg_int cfg_enable_debug_log("EnableDebugLog", 1);
295+static cfg_int cfg_debug_dummyamp_init("DebugDummyAmpInit", 1);
296+static cfg_int cfg_debug_dummyamp_proc("DebugDummyAmpProc", 1);
297+static cfg_int cfg_debug_track_info("DebugTrackInfo", 1);
298+static cfg_int cfg_debug_plugin("DebugPlugin", 1);
299+static cfg_int cfg_debug_callback("DebugCallback", 1);
300+#elif IS_FB2K_VER09
301+// {DB051102-6DAE-4ff8-B5ED-AA06C2ACFEDE}
302+static const GUID cfg_use_plugin_guid = { 0xdb051102, 0x6dae, 0x4ff8, { 0xb5, 0xed, 0xaa, 0x6, 0xc2, 0xac, 0xfe, 0xde } };
303+static cfg_int cfg_use_plugin(cfg_use_plugin_guid, 1);
304+
305+// {1B27EDEC-A28A-4dac-96D4-1E3B51C92004}
306+static const GUID cfg_no_artist_name_guid = { 0x1b27edec, 0xa28a, 0x4dac, { 0x96, 0xd4, 0x1e, 0x3b, 0x51, 0xc9, 0x20, 0x4 } };
307+static cfg_string cfg_no_artist_name(cfg_no_artist_name_guid, "No Artist");
308+// {A8CFD50C-05EA-447d-AA74-F4C6975E750E}
309+static const GUID cfg_no_title_name_guid = { 0xa8cfd50c, 0x5ea, 0x447d, { 0xaa, 0x74, 0xf4, 0xc6, 0x97, 0x5e, 0x75, 0xe } };
310+static cfg_string cfg_no_title_name(cfg_no_title_name_guid, "No Title");
311+// {A7593537-8B09-4016-9B3C-0EF5516BBFF9}
312+static const GUID cfg_no_album_name_guid = { 0xa7593537, 0x8b09, 0x4016, { 0x9b, 0x3c, 0xe, 0xf5, 0x51, 0x6b, 0xbf, 0xf9 } };
313+static cfg_string cfg_no_album_name(cfg_no_album_name_guid, "No Title");
314+// {15774319-0CBE-45fd-B0E8-52D4728319A3}
315+static const GUID cfg_no_genre_name_guid = { 0x15774319, 0xcbe, 0x45fd, { 0xb0, 0xe8, 0x52, 0xd4, 0x72, 0x83, 0x19, 0xa3 } };
316+static cfg_string cfg_no_genre_name(cfg_no_genre_name_guid, "Other");
317+
318+// {ED0C715A-D06D-4641-A29A-AE4485A0B9EF}
319+static const GUID cfg_send_interval1_guid = { 0xed0c715a, 0xd06d, 0x4641, { 0xa2, 0x9a, 0xae, 0x44, 0x85, 0xa0, 0xb9, 0xef } };
320+static cfg_string cfg_send_interval1(cfg_send_interval1_guid, "20");
321+// {25989711-B458-4624-8A85-7304FCE799A3}
322+static const GUID cfg_send_interval2_guid = { 0x25989711, 0xb458, 0x4624, { 0x8a, 0x85, 0x73, 0x4, 0xfc, 0xe7, 0x99, 0xa3 } };
323+static cfg_string cfg_send_interval2(cfg_send_interval2_guid, "66");
324+// {4287A873-015D-44b5-A31E-34DEE1BF0525}
325+static const GUID cfg_send_interval3_guid = { 0x4287a873, 0x15d, 0x44b5, { 0xa3, 0x1e, 0x34, 0xde, 0xe1, 0xbf, 0x5, 0x25 } };
326+static cfg_string cfg_send_interval3(cfg_send_interval3_guid, "300");
327+
328+// {5C318451-2B6A-405f-814B-2795A764C1DE}
329+static const GUID cfg_disable_duplicate_song_guid = { 0x5c318451, 0x2b6a, 0x405f, { 0x81, 0x4b, 0x27, 0x95, 0xa7, 0x64, 0xc1, 0xde } };
330+static cfg_int cfg_disable_duplicate_song(cfg_disable_duplicate_song_guid, 0);
331+// {56688AED-A76D-4759-A835-A380D39D34D1}
332+static const GUID cfg_media_library_registered_file_only_guid = { 0x56688aed, 0xa76d, 0x4759, { 0xa8, 0x35, 0xa3, 0x80, 0xd3, 0x9d, 0x34, 0xd1 } };
333+static cfg_int cfg_media_library_registered_file_only(cfg_media_library_registered_file_only_guid, 0);
334+// {91E0D3D4-85DD-4c45-ADB5-7FAC6F3360CD}
335+static const GUID cfg_explicitly_tagged_file_only_guid = { 0x91e0d3d4, 0x85dd, 0x4c45, { 0xad, 0xb5, 0x7f, 0xac, 0x6f, 0x33, 0x60, 0xcd } };
336+static cfg_int cfg_explicitly_tagged_file_only(cfg_explicitly_tagged_file_only_guid, 0);
337+// {F4E85669-6EEF-4b75-AFC1-7964AEBE10B0}
338+static const GUID cfg_enable_streaming_file_guid = { 0xf4e85669, 0x6eef, 0x4b75, { 0xaf, 0xc1, 0x79, 0x64, 0xae, 0xbe, 0x10, 0xb0 } };
339+static cfg_int cfg_enable_streaming_file(cfg_enable_streaming_file_guid, 0);
340+
341+// {67341E11-A385-45d8-9DE6-B1FABA35AC62}
342+static const GUID cfg_disable_dummy_mp3_guid = { 0x67341e11, 0xa385, 0x45d8, { 0x9d, 0xe6, 0xb1, 0xfa, 0xba, 0x35, 0xac, 0x62 } };
343+static cfg_int cfg_disable_dummy_mp3(cfg_disable_dummy_mp3_guid, 0);
344+// {87D4D72C-43AB-42ab-8CAC-D689961DA5EA}
345+static const GUID cfg_dummy_mp3_location_guid = { 0x87d4d72c, 0x43ab, 0x42ab, { 0x8c, 0xac, 0xd6, 0x89, 0x96, 0x1d, 0xa5, 0xea } };
346+static cfg_int cfg_dummy_mp3_location(cfg_dummy_mp3_location_guid, 0);
347+
348+// {F9DB10F0-1A01-40dd-A342-486A6CB596E7}
349+static const GUID cfg_show_dummyamp_guid = { 0xf9db10f0, 0x1a01, 0x40dd, { 0xa3, 0x42, 0x48, 0x6a, 0x6c, 0xb5, 0x96, 0xe7 } };
350+static cfg_int cfg_show_dummyamp(cfg_show_dummyamp_guid, 0);
351+// {CC7785CA-B019-4107-9115-161A543B3952}
352+static const GUID cfg_dummyamp_title_format_guid = { 0xcc7785ca, 0xb019, 0x4107, { 0x91, 0x15, 0x16, 0x1a, 0x54, 0x3b, 0x39, 0x52 } };
353+static cfg_string cfg_dummyamp_title_format(cfg_dummyamp_title_format_guid, DEFAULT_DUMMYAMP_TITLE_FORMAT);
354+// {B964EB32-4957-4e7a-81B5-E89B4405AAAD}
355+static const GUID cfg_dummyamp_playlist_format_guid = { 0xb964eb32, 0x4957, 0x4e7a, { 0x81, 0xb5, 0xe8, 0x9b, 0x44, 0x5, 0xaa, 0xad } };
356+static cfg_string cfg_dummyamp_playlist_format(cfg_dummyamp_title_format_guid, DEFAULT_DUMMYAMP_TITLE_FORMAT);
357+
358+// {094571BA-1484-455c-9D6E-E18B13296149}
359+static const GUID cfg_disable_ansi_trans_guid = { 0x94571ba, 0x1484, 0x455c, { 0x9d, 0x6e, 0xe1, 0x8b, 0x13, 0x29, 0x61, 0x49 } };
360+static cfg_int cfg_disable_ansi_trans(cfg_disable_ansi_trans_guid, 0);
361+// {8961A829-F010-461c-9CC8-C06308BFA4A2}
362+static const GUID cfg_enable_ext_ipc_proc_guid = { 0x8961a829, 0xf010, 0x461c, { 0x9c, 0xc8, 0xc0, 0x63, 0x8, 0xbf, 0xa4, 0xa2 } };
363+static cfg_int cfg_enable_ext_ipc_proc(cfg_enable_ext_ipc_proc_guid, 1);
364+
365+// {3B6B73F9-F6AF-4b6c-8015-E73A1B87AD5C}
366+static const GUID cfg_enable_debug_log_guid = { 0x3b6b73f9, 0xf6af, 0x4b6c, { 0x80, 0x15, 0xe7, 0x3a, 0x1b, 0x87, 0xad, 0x5c } };
367+static cfg_int cfg_enable_debug_log(cfg_enable_debug_log_guid, 1); // debug log enabled
368+// {0BF3522F-BC55-4f77-AA95-B02F6E159544}
369+static const GUID cfg_debug_dummyamp_init_guid = { 0xbf3522f, 0xbc55, 0x4f77, { 0xaa, 0x95, 0xb0, 0x2f, 0x6e, 0x15, 0x95, 0x44 } };
370+static cfg_int cfg_debug_dummyamp_init(cfg_debug_dummyamp_init_guid, 1); // debug level
371+// {D1256573-7560-41db-A781-9985AE50CE07}
372+static const GUID cfg_debug_dummyamp_proc_guid = { 0xd1256573, 0x7560, 0x41db, { 0xa7, 0x81, 0x99, 0x85, 0xae, 0x50, 0xce, 0x7 } };
373+static cfg_int cfg_debug_dummyamp_proc(cfg_debug_dummyamp_proc_guid, 1); // debug level
374+// {0A7E2CAE-905F-4ecb-A82D-8DD853FBFFF3}
375+static const GUID cfg_debug_track_info_guid = { 0xa7e2cae, 0x905f, 0x4ecb, { 0xa8, 0x2d, 0x8d, 0xd8, 0x53, 0xfb, 0xff, 0xf3 } };
376+static cfg_int cfg_debug_track_info(cfg_debug_track_info_guid, 1); // debug level
377+// {67A78DB7-3591-4416-84FC-96436082B619}
378+static const GUID cfg_debug_plugin_guid = { 0x67a78db7, 0x3591, 0x4416, { 0x84, 0xfc, 0x96, 0x43, 0x60, 0x82, 0xb6, 0x19 } };
379+static cfg_int cfg_debug_plugin(cfg_debug_plugin_guid, 1); // debug level
380+// {DBED8400-527F-4b98-9227-2C0BA95B3206}
381+static const GUID cfg_debug_callback_guid = { 0xdbed8400, 0x527f, 0x4b98, { 0x92, 0x27, 0x2c, 0xb, 0xa9, 0x5b, 0x32, 0x6 } };
382+static cfg_int cfg_debug_callback(cfg_debug_callback_guid, 1); // debug level
383+#endif
384+
385+class TrackInfo
386+{
387+public:
388+ std::string m_nullStr;
389+
390+ StringMap m_infoMap8;
391+ StringMap m_infoMapAnsi;
392+
393+ UIntMap m_infoMapNum;
394+
395+ TrackInfo() {
396+ }
397+
398+ TrackInfo(const TrackInfo &other)
399+ : m_infoMap8(other.m_infoMap8)
400+ , m_infoMapAnsi(other.m_infoMapAnsi)
401+ , m_infoMapNum(other.m_infoMapNum) {
402+ }
403+
404+ ~TrackInfo() {
405+ }
406+
407+ TrackInfo &operator =(const TrackInfo &other)
408+ {
409+ TrackInfo temp(other);
410+ swap(temp);
411+
412+ return *this;
413+ }
414+
415+ void show_map(StringMap &map, bool bAnsi = false)
416+ {
417+ StringMapCIt beginIt(map.begin()), endIt(map.end()), it;
418+
419+ for(it = beginIt; it != endIt; it ++) {
420+
421+ if(bAnsi) {
422+ TRACE_TRACK_INFO_ANSI("show_map_ansi: [%s, %s]", it->first.c_str(), it->second.c_str());
423+ } else {
424+ TRACE_TRACK_INFO8("show_map8: [%s, %s]", it->first.c_str(), it->second.c_str());
425+ }
426+ }
427+ }
428+
429+ void swap(TrackInfo &other)
430+ {
431+ m_infoMap8.swap(other.m_infoMap8);
432+ m_infoMapAnsi.swap(other.m_infoMapAnsi);
433+ m_infoMapNum.swap(other.m_infoMapNum);
434+ }
435+
436+ void clear()
437+ {
438+ TRACE_TRACK_INFO(_T("TRACK_INFO::clear - called."));
439+
440+ m_infoMap8.clear();
441+ m_infoMapAnsi.clear();
442+ m_infoMapNum.clear();
443+ }
444+
445+ bool isEmpty() const { return m_infoMap8.empty() & m_infoMapNum.empty(); }
446+
447+public:
448+
449+#if IS_FB2K_VER08
450+ void setStrings(const Strings &keys, metadb_handle * track)
451+#elif IS_FB2K_VER09
452+ void setStrings(const Strings &keys, metadb_handle_ptr track)
453+#endif
454+ {
455+ TRACE_TRACK_INFO(_T("TrackInfo::setStrings - called."));
456+
457+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
458+
459+ for(it = beginIt; it != endIt; it ++) {
460+
461+ string8 info8;
462+
463+#if IS_FB2K_VER08
464+ track->handle_format_title(info8, it->c_str(), 0);
465+#elif IS_FB2K_VER09
466+ service_ptr_t<titleformat_object> titleformat;
467+
468+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
469+ track->format_title(NULL, info8, titleformat, 0);
470+#endif
471+// DEBUG_TRACK_INFO8("TrackInfo::setStrings - %s: %s", it->c_str(), (LPCSTR)info8);
472+
473+ putString(it->c_str(), (LPCSTR)info8);
474+ }
475+ }
476+
477+ void setDynamicStrings(const Strings &keys)
478+ {
479+ TRACE_TRACK_INFO(_T("TrackInfo::setDynamicStrings - called."));
480+
481+#if IS_FB2K_VER08
482+ metadb_handle *track = play_control::get()->get_now_playing();
483+#elif IS_FB2K_VER09
484+ metadb_handle_ptr track;
485+ static_api_ptr_t<playback_control>()->get_now_playing(track);
486+#endif
487+
488+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
489+
490+ for(it = beginIt; it != endIt; it ++) {
491+
492+ string8 info8;
493+
494+#if IS_FB2K_VER08
495+ play_control::get()->playback_format_title_ex(track, info8, it->c_str(), NULL, false, true);
496+#elif IS_FB2K_VER09
497+ service_ptr_t<titleformat_object> titleformat;
498+
499+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
500+ static_api_ptr_t<playback_control>()->playback_format_title_ex(track, NULL, info8, titleformat, NULL, play_control::display_level_titles);
501+#endif
502+// DEBUG_TRACK_INFO8("TrackInfo::setDynamicStrings - %s: %s", it->c_str(), (LPCSTR)info8);
503+
504+ const std::string &oldValue = getString(*it);
505+
506+ if((::lstrcmpA(info8, "?") != 0) || (oldValue.length() == 0))
507+ {
508+ putString(it->c_str(), (LPCSTR)info8);
509+ }
510+ }
511+
512+#if IS_FB2K_VER08
513+ if(track) {
514+ track->handle_release();
515+ }
516+#endif
517+ }
518+
519+ void setPlaylistStrings(const Strings &keys)
520+ {
521+ TRACE_TRACK_INFO(_T("TrackInfo::setPlaylistStrings - called."));
522+
523+#if IS_FB2K_VER08
524+ int track_index;
525+ track_index = playlist_oper::get()->get_now_playing();
526+#elif IS_FB2K_VER09
527+ t_size playlist_index, track_index;
528+ static_api_ptr_t<playlist_manager>()->get_playing_item_location(&playlist_index, &track_index);
529+#endif
530+
531+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
532+
533+ for(it = beginIt; it != endIt; it ++) {
534+
535+ string8 info8;
536+
537+#if IS_FB2K_VER08
538+ playlist_oper::get()->format_title(track_index, info8, it->c_str(), NULL);
539+#elif IS_FB2K_VER09
540+ service_ptr_t<titleformat_object> titleformat;
541+
542+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
543+ static_api_ptr_t<playlist_manager>()->playlist_item_format_title(playlist_index, track_index,
544+ NULL, info8, titleformat, NULL, play_control::display_level_titles);
545+#endif
546+// DEBUG_TRACK_INFO8("TrackInfo::setPlaylistStrings - %s: %s", it->c_str(), (LPCSTR)info8);
547+
548+ putString(it->c_str(), (LPCSTR)info8);
549+ }
550+ }
551+
552+#if IS_FB2K_VER08
553+ void setNumbers(const Strings &keys, metadb_handle * track)
554+#elif IS_FB2K_VER09
555+ void setNumbers(const Strings &keys, metadb_handle_ptr track)
556+#endif
557+ {
558+ TRACE_TRACK_INFO(_T("TrackInfo::setNumbers - called."));
559+
560+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
561+
562+ for(it = beginIt; it != endIt; it ++) {
563+
564+ string8 info8;
565+
566+#if IS_FB2K_VER08
567+ track->handle_format_title(info8, it->c_str(), 0);
568+#elif IS_FB2K_VER09
569+ service_ptr_t<titleformat_object> titleformat;
570+
571+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
572+ track->format_title(NULL, info8, titleformat, 0);
573+#endif
574+// DEBUG_TRACK_INFO8("TrackInfo::setNumbers - %s: %s", it->c_str(), (LPCSTR)info8);
575+
576+ putNumber(it->c_str(), static_cast<UINT>(::atol(info8)) );
577+ }
578+ }
579+
580+ void setDynamicNumbers(const Strings &keys)
581+ {
582+ TRACE_TRACK_INFO(_T("TrackInfo::setDynamicNumbers - called."));
583+
584+#if IS_FB2K_VER08
585+ metadb_handle *track = play_control::get()->get_now_playing();
586+#elif IS_FB2K_VER09
587+ metadb_handle_ptr track;
588+ static_api_ptr_t<playback_control>()->get_now_playing(track);
589+#endif
590+
591+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
592+
593+ for(it = beginIt; it != endIt; it ++) {
594+
595+ string8 info8;
596+
597+#if IS_FB2K_VER08
598+ play_control::get()->playback_format_title_ex(track, info8, it->c_str(), NULL, false, true);
599+#elif IS_FB2K_VER09
600+ service_ptr_t<titleformat_object> titleformat;
601+
602+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
603+ static_api_ptr_t<playback_control>()->playback_format_title_ex(track, NULL, info8, titleformat, NULL, play_control::display_level_titles);
604+#endif
605+// DEBUG_TRACK_INFO8("TrackInfo::setDynamicNumbers - %s: %s", it->c_str(), (LPCSTR)info8);
606+
607+ UINT newValue = static_cast<UINT>(::atol(info8));
608+ UINT oldValue = getNumber(*it);
609+
610+ if((newValue != 0) || (oldValue == 0)) {
611+ putNumber(it->c_str(), newValue);
612+ }
613+ }
614+
615+#if IS_FB2K_VER08
616+ if(track) {
617+ track->handle_release();
618+ }
619+#endif
620+ }
621+
622+ void setPlaylistNumbers(const Strings &keys)
623+ {
624+ TRACE_TRACK_INFO(_T("TrackInfo::setPlaylistNumbers - called."));
625+
626+#if IS_FB2K_VER08
627+ int track_index;
628+ track_index = playlist_oper::get()->get_now_playing();
629+#elif IS_FB2K_VER09
630+ t_size playlist_index, track_index;
631+ static_api_ptr_t<playlist_manager>()->get_playing_item_location(&playlist_index, &track_index);
632+#endif
633+
634+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
635+
636+ for(it = beginIt; it != endIt; it ++) {
637+
638+ string8 info8;
639+
640+#if IS_FB2K_VER08
641+ playlist_oper::get()->format_title(track_index, info8, it->c_str(), NULL);
642+#elif IS_FB2K_VER09
643+ service_ptr_t<titleformat_object> titleformat;
644+
645+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
646+ static_api_ptr_t<playlist_manager>()->playlist_item_format_title(playlist_index, track_index,
647+ NULL, info8, titleformat, NULL, play_control::display_level_titles);
648+#endif
649+// DEBUG_TRACK_INFO8("TrackInfo::setPlaylistNumbers - %s: %s", it->c_str(), (LPCSTR)info8);
650+
651+ putNumber(it->c_str(), static_cast<UINT>(::atol(info8)) );
652+ }
653+ }
654+
655+ void putString(const std::string &key, const std::string &value)
656+ {
657+ DEBUG_TRACK_INFO8("TrackInfo::putString - %s: %s", key.c_str(), value.c_str());
658+
659+ insert(m_infoMap8, key.c_str(), value.c_str());
660+
661+ string_ansi_from_utf8 valueAnsi(value.c_str());
662+
663+ insert(m_infoMapAnsi, key.c_str(), (LPCSTR)valueAnsi, true);
664+ }
665+
666+ void putNumber(const std::string &key, UINT value)
667+ {
668+ DEBUG_TRACK_INFO8("TrackInfo::putNumber - %s: %u", key.c_str(), value);
669+
670+ insert(m_infoMapNum, key.c_str(), value);
671+ }
672+
673+ const std::string &getString(const std::string &key, bool bForceUTF8 = false) const {
674+
675+ if((bForceUTF8 == true) || (cfg_disable_ansi_trans == 1))
676+ {
677+ StringMapCIt it(m_infoMap8.find(key)), endIt(m_infoMap8.end());
678+
679+ if(it == endIt) {
680+ return m_nullStr;
681+ }
682+
683+ return it->second;
684+ }
685+ else
686+ {
687+ StringMapCIt it(m_infoMapAnsi.find(key)), endIt(m_infoMapAnsi.end());
688+
689+ if(it == endIt) {
690+ return m_nullStr;
691+ }
692+
693+ return it->second;
694+ }
695+ }
696+
697+ const UINT getNumber(const std::string &key) const {
698+
699+ UIntMapCIt it(m_infoMapNum.find(key)), endIt(m_infoMapNum.end());
700+
701+ if(it == endIt) {
702+ return 0;
703+ }
704+
705+ return it->second;
706+ }
707+
708+ void removeStrings(const Strings &keys)
709+ {
710+ TRACE_TRACK_INFO(_T("TrackInfo::removeStrings - called."));
711+
712+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
713+
714+ for(it = beginIt; it != endIt; it ++) {
715+ removeString(*it);
716+ }
717+ }
718+
719+ void removeString(const std::string &key)
720+ {
721+ TRACE_TRACK_INFO8("TrackInfo::removeString - %s", key.c_str());
722+
723+ m_infoMap8.erase(m_infoMap8.find(key));
724+ m_infoMapAnsi.erase(m_infoMapAnsi.find(key));
725+ }
726+
727+ void removeNumbers(const Strings &keys)
728+ {
729+ TRACE_TRACK_INFO(_T("TrackInfo::removeNumbers - called."));
730+
731+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
732+
733+ for(it = beginIt; it != endIt; it ++) {
734+ removeNumber(*it);
735+ }
736+ }
737+
738+ void removeNumber(const std::string &key)
739+ {
740+ TRACE_TRACK_INFO8("TrackInfo::removeNumber - %s", key.c_str());
741+
742+ m_infoMapNum.erase(m_infoMapNum.find(key));
743+ }
744+
745+protected:
746+
747+ static void insert(StringMap &map, LPCSTR pKey, LPCSTR pValue, bool bAnsi = false)
748+ {
749+#if 0
750+ if(bAnsi) {
751+ TRACE_TRACK_INFO_ANSI("insertAnsi: [%s, %s]", pKey, pValue);
752+ } else {
753+ TRACE_TRACK_INFO8("insert8: [%s, %s]", pKey, pValue);
754+ }
755+#endif
756+
757+ map.insert(std::make_pair(pKey, pValue));
758+ }
759+
760+ static void insert(UIntMap &map, LPCSTR pKey, UINT value)
761+ {
762+// TRACE_TRACK_INFO8("insertNum: [%s, %u]", pKey, value);
763+
764+ map.insert(std::make_pair(pKey, value));
765+ }
766+};
767+
768+class PathInfo
769+{
770+ protected:
771+ PathInfo() {
772+ }
773+
774+ public:
775+ static tstring getFB2Kpath()
776+ {
777+ TCHAR modulePath[_MAX_PATH], moduleDrive[_MAX_DRIVE], moduleDir[_MAX_DIR];
778+ TCHAR returnPath[_MAX_PATH];
779+
780+ ::GetModuleFileName(NULL, modulePath, _MAX_PATH);
781+ ::_tsplitpath_s(modulePath, moduleDrive, _MAX_DRIVE, moduleDir, _MAX_DIR, NULL, 0, NULL, 0);
782+ ::_tmakepath_s(returnPath, _MAX_PATH, moduleDrive, moduleDir, NULL, NULL);
783+
784+ return tstring(returnPath);
785+ }
786+
787+ static tstring getFB2KComponentsPath() {
788+ return getFB2Kpath() + FB2K_COMPONENTS_DIR;
789+ }
790+
791+ static std::string getGenMixiDefaultPath()
792+ {
793+ string_utf8_from_os path(getFB2KComponentsPath().c_str());
794+ return (LPCSTR)path;
795+ }
796+
797+ static tstring getMixiStationAppPath() {
798+ return getSpecialFolderPath(CSIDL_APPDATA, FALSE) + APPDATA_MIXI_STATION_DIR;
799+ }
800+
801+ static tstring getFooMixiPlayInfoPath()
802+ {
803+ switch(cfg_dummy_mp3_location)
804+ {
805+ case 1:
806+ return getTemporaryFolderPath();
807+
808+ case 2:
809+ return getFB2KComponentsPath() ;
810+
811+ case 0:
812+ default:
813+ return getMixiStationAppPath() + _T("\\");
814+ }
815+ }
816+
817+ static tstring getDummyPlayInfoMp3Path() {
818+ return getFooMixiPlayInfoPath() + DUMMY_MP3_FILE_NAME;
819+ }
820+
821+ static tstring splitPath(const string8 &srcPath)
822+ {
823+ string_os_from_utf8 srcPathOs(srcPath);
824+ return splitPath(srcPathOs);
825+ }
826+
827+ static tstring splitPath(LPCTSTR srcPath)
828+ {
829+ TCHAR drive[_MAX_DRIVE], dir[_MAX_DIR], dstPath[_MAX_PATH];
830+ ::_tsplitpath_s(srcPath, drive, _MAX_DRIVE, dir, _MAX_DIR, NULL, 0, NULL, 0);
831+ ::_tmakepath_s(dstPath, _MAX_PATH, drive, dir, NULL, NULL);
832+ return dstPath;
833+ }
834+
835+ //! get the special folder path
836+ static tstring getSpecialFolderPath(int nFolder, BOOL bCreate)
837+ {
838+ tstring resStr;
839+ HRESULT hr = NO_ERROR;
840+
841+ IMalloc *pMalloc = 0;
842+ ITEMIDLIST *pItemID = 0;
843+ TCHAR folderPath[MAX_PATH];
844+
845+ folderPath[0] = _T('\0');
846+ hr = SHGetMalloc(&pMalloc);
847+
848+ if(hr == NO_ERROR)
849+ {
850+ hr = SHGetSpecialFolderLocation(0, nFolder, &pItemID);
851+
852+ if(hr == NO_ERROR)
853+ {
854+ if(SHGetPathFromIDList(pItemID, folderPath) == FALSE)
855+ hr = GetLastError();
856+
857+ pMalloc->Free(pItemID);
858+ }
859+
860+ pMalloc->Release();
861+ }
862+
863+ resStr = folderPath;
864+
865+ if(hr != NO_ERROR)
866+ {
867+ return _T("");
868+ }
869+
870+ return resStr;
871+ }
872+
873+ //! get the temporary folder path
874+ static tstring getTemporaryFolderPath() {
875+
876+ TCHAR strTempPath[MAX_PATH];
877+ ::GetTempPath(MAX_PATH, strTempPath);
878+
879+ return strTempPath;
880+ }
881+};
882+
883+#if IS_FB2K_VER08
884+static cfg_string cfg_gen_mixi_path("GenMixiPath", PathInfo::getGenMixiDefaultPath().c_str());
885+#elif IS_FB2K_VER09
886+// {1EC28435-C243-483c-81EC-E0E57A96727E}
887+static const GUID cfg_gen_mixi_path_guid = { 0x1ec28435, 0xc243, 0x483c, { 0x81, 0xec, 0xe0, 0xe5, 0x7a, 0x96, 0x72, 0x7e } };
888+static cfg_string cfg_gen_mixi_path(cfg_gen_mixi_path_guid, PathInfo::getGenMixiDefaultPath().c_str());
889+#endif
890+
891+class PlayInfo
892+{
893+ public:
894+
895+ enum EPlayStatus
896+ {
897+ PLAY_STOP = 0,
898+ PLAY_START = 1,
899+ PLAY_PAUSE = 3
900+ };
901+
902+ public:
903+
904+ PlayInfo() :
905+ m_playStatus(PLAY_STOP),
906+ m_isResentMode(false),
907+ m_playLength(0),
908+ m_playPosition(0),
909+ m_playCount(0),
910+ m_isPlayInfoMp3Available(false),
911+ m_resetBasePosition(0) {
912+ }
913+
914+ public:
915+
916+ void setPlayStatusStart() {
917+ setPlayStatus(PLAY_START);
918+ }
919+
920+ void setPlayStatusStop() {
921+ setPlayStatus(PLAY_STOP);
922+ }
923+
924+ void setPlayStatusPause() {
925+ setPlayStatus(PLAY_PAUSE);
926+ }
927+
928+ void clearPlayInfo(bool isResentMode = true)
929+ {
930+ setPlayStatusStop();
931+ m_isResentMode = isResentMode;
932+ setPlayPosition(0);
933+ setPlayLength(0);
934+ setPlayInfoMp3Available(false);
935+ m_resetBasePosition = 0;
936+ }
937+
938+ void setResentMode(bool bIncrementCounter = true)
939+ {
940+ if(bIncrementCounter) {
941+ incrementPlayCount();
942+ }
943+ m_isResentMode = true;
944+ m_resetBasePosition = m_playPosition;
945+ }
946+
947+ void clearResentMode() {
948+ m_isResentMode = false;
949+ }
950+
951+ void incrementPlayCount() {
952+ setPlayCount(getPlayCount() + 1);
953+ }
954+
955+ public:
956+
957+ EPlayStatus getPlayStatus() const
958+ {
959+ if((m_playStatus == PLAY_START) && m_isResentMode) {
960+ return PLAY_STOP;
961+ }
962+ return m_playStatus;
963+ }
964+
965+ void setPlayStatus(EPlayStatus status) {
966+ m_playStatus = status;
967+ }
968+
969+ int getPlayPosition() const
970+ {
971+ if(m_resetBasePosition > 0) {
972+ return m_playPosition - m_resetBasePosition;
973+ }
974+ return m_playPosition;
975+ }
976+
977+ void setPlayPosition(int pos) {
978+ m_playPosition = pos;
979+ }
980+
981+ int getPlayLength() const
982+ {
983+#if FORCE_RESENT_MODE == 0
984+ if(m_resetBasePosition > 0) {
985+#else
986+ if(true) {
987+#endif
988+ return GEN_MIXI_REQUIRED_SECONDS;
989+ }
990+ return m_playLength;
991+ }
992+
993+ void setPlayLength(int len) {
994+ m_playLength = len;
995+ }
996+
997+ int getPlayCount() const {
998+ return m_playCount;
999+ }
1000+
1001+ void setPlayCount(int count) {
1002+ m_playCount = count;
1003+ }
1004+
1005+ bool isPlayInfoMp3Available() const {
1006+ return m_isPlayInfoMp3Available;
1007+ }
1008+
1009+ void setPlayInfoMp3Available(bool isAvailable) {
1010+ m_isPlayInfoMp3Available = isAvailable;
1011+ }
1012+
1013+ void setPlayInfoMp3Path(LPCSTR path)
1014+ {
1015+#if 0
1016+ m_playInfoMp3Path = path;
1017+
1018+ string_utf8_from_os path8(path);
1019+
1020+ if(cfg_disable_ansi_trans == 1)
1021+ {
1022+
1023+ m_playInfoMp3Path8 = path8;
1024+ }
1025+ else
1026+ {
1027+ string_ansi_from_utf8 pathAnsi(path8);
1028+
1029+ m_playInfoMp3Path8 = pathAnsi;
1030+ }
1031+#else
1032+ m_playInfoMp3Path8 = path;
1033+#endif
1034+ }
1035+
1036+ const string8 &getPlayInfoMp3Path8() const {
1037+ return m_playInfoMp3Path8;
1038+ }
1039+
1040+ bool isResentMode() const {
1041+ return m_isResentMode;
1042+ }
1043+
1044+ protected:
1045+
1046+ EPlayStatus m_playStatus;
1047+
1048+ int m_playLength;
1049+ int m_playPosition;
1050+ int m_playCount;
1051+
1052+ bool m_isPlayInfoMp3Available;
1053+ bool m_isResentMode;
1054+ int m_resetBasePosition;
1055+
1056+ string8 m_playInfoMp3Path8;
1057+};
1058+
1059+class id3Info
1060+{
1061+ public:
1062+
1063+ typedef std::vector<UINT16> UInt16Array;
1064+
1065+ id3Info(const TrackInfo & info) : m_info(info), m_hMp3File(INVALID_HANDLE_VALUE) {
1066+ }
1067+
1068+ ~id3Info() {
1069+ close();
1070+ }
1071+
1072+ DWORD write(LPCTSTR path) {
1073+
1074+ string_wide_from_utf8 title_utf16(m_info.getString(FORMAT_TRACKTITLE, true).c_str());
1075+ string_wide_from_utf8 artist_utf16(m_info.getString(FORMAT_ARTIST, true).c_str());
1076+ string_wide_from_utf8 album_utf16(m_info.getString(FORMAT_ALBUMTITLE, true).c_str());
1077+ string_wide_from_utf8 genre_utf16(m_info.getString(FORMAT_GENRE, true).c_str());
1078+
1079+ DWORD dwErr = S_OK;
1080+
1081+ if((dwErr = open(path)) != S_OK) {
1082+ return dwErr;
1083+ }
1084+
1085+ UInt16Array title = makeTextFrame("TIT2", makeUTF16LE(title_utf16));
1086+ UInt16Array album = makeTextFrame("TALB", makeUTF16LE(album_utf16));
1087+ UInt16Array artist = makeTextFrame("TPE1", makeUTF16LE(artist_utf16));
1088+ UInt16Array genre = makeTextFrame("TCON", makeUTF16LE(genre_utf16));
1089+
1090+ dwErr = writeHeader(static_cast<UINT32>(
1091+ title.size()*2 + album.size()*2 + artist.size()*2 + genre.size()*2 + 4));
1092+ // add charset code size (4bytes)
1093+
1094+ if(dwErr == S_OK) {
1095+ dwErr = writeTextFrame(title);
1096+ }
1097+
1098+ if(dwErr == S_OK) {
1099+ dwErr = writeTextFrame(album);
1100+ }
1101+
1102+ if(dwErr == S_OK) {
1103+ dwErr = writeTextFrame(artist);
1104+ }
1105+
1106+ if(dwErr == S_OK) {
1107+ dwErr = writeTextFrame(genre);
1108+ }
1109+
1110+ close();
1111+
1112+ return dwErr;
1113+ }
1114+
1115+ protected:
1116+
1117+ DWORD open(LPCTSTR path)
1118+ {
1119+ close();
1120+
1121+ // open dummy mp3 file
1122+ m_hMp3File = ::CreateFile(
1123+ path, GENERIC_WRITE, 0, NULL,
1124+ TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
1125+ );
1126+
1127+ if(m_hMp3File == INVALID_HANDLE_VALUE)
1128+ {
1129+ return ::GetLastError();
1130+ }
1131+
1132+ return S_OK;
1133+ }
1134+
1135+ UInt16Array makeUTF16LE(const string_wide_from_utf8 &str) {
1136+
1137+ LPCWSTR pStr = str.get_ptr();
1138+ size_t len = ::lstrlenW(pStr);
1139+ UInt16Array utf16(len + 2);
1140+
1141+ utf16[0] = 0xfeff; // BOM
1142+ ::CopyMemory(&utf16[1], str.get_ptr(), len * 2);
1143+
1144+ // swap byte order (big endian to little endian);
1145+ for(size_t i = 0; i < len + 1; i++) {
1146+ utf16[i] = (utf16[i] << 8) | (utf16[i] >> 8);
1147+ }
1148+
1149+ utf16[len + 1] = 0; // add NULL character
1150+
1151+ return utf16;
1152+ }
1153+
1154+ UInt16Array makeTextFrame(LPCSTR pFrameID, const UInt16Array &data) {
1155+
1156+ UInt16Array frame(data.size() + 5);
1157+
1158+ UINT32 size = static_cast<UINT32>(data.size() * 2 + 1); // add charset code size (1byte)
1159+
1160+ const UCHAR *pUCFrameID = reinterpret_cast<const UCHAR *>(pFrameID);
1161+ const UCHAR *pUCSize = reinterpret_cast<const UCHAR *>(&size);
1162+
1163+ frame[0] = ((UINT16)pUCFrameID[1]) << 8 | pUCFrameID[0];
1164+ frame[1] = ((UINT16)pUCFrameID[3]) << 8 | pUCFrameID[2];
1165+
1166+ frame[2] = ((UINT16)pUCSize[2]) << 8 | pUCSize[3];
1167+ frame[3] = ((UINT16)pUCSize[0]) << 8 | pUCSize[1];
1168+
1169+ frame[4] = 0; // frame flag
1170+
1171+ ::CopyMemory(&frame[5], &data[0], data.size() * 2);
1172+
1173+ return frame;
1174+ }
1175+
1176+ void close() {
1177+ if(m_hMp3File != INVALID_HANDLE_VALUE) {
1178+ ::CloseHandle(m_hMp3File);
1179+ m_hMp3File = INVALID_HANDLE_VALUE;
1180+ }
1181+ }
1182+
1183+ DWORD writeHeader(UINT32 size)
1184+ {
1185+ UInt16Array header(5);
1186+
1187+ header[0] = ((UINT16)'D') << 8 | (UCHAR)'I';
1188+ header[1] = ((UINT16) 3 ) << 8 | (UCHAR)'3';
1189+
1190+ header[2] = 0;
1191+
1192+ UInt16Array length = makeLength(size);
1193+
1194+ header[3] = length[0];
1195+ header[4] = length[1];
1196+
1197+ DWORD dwSize;
1198+ if(!::WriteFile(m_hMp3File, &header[0], 10, &dwSize, NULL)) {
1199+ return ::GetLastError();
1200+ }
1201+
1202+ return S_OK;
1203+ }
1204+
1205+ DWORD writeTextFrame(const UInt16Array &packet)
1206+ {
1207+ DWORD dwErr = S_OK;
1208+
1209+ UCHAR charsetCode = 0x01; // UNICODE
1210+
1211+ DWORD dwSize;
1212+ if(!::WriteFile(m_hMp3File, &packet[0], 10, &dwSize, NULL)) {
1213+ return ::GetLastError();
1214+ }
1215+ if(!::WriteFile(m_hMp3File, &charsetCode, 1, &dwSize, NULL)) {
1216+ return ::GetLastError();
1217+ }
1218+ if(!::WriteFile(m_hMp3File, &packet[5], static_cast<DWORD>(packet.size() * 2 - 10), &dwSize, NULL)) {
1219+ return ::GetLastError();
1220+ }
1221+
1222+ return S_OK;
1223+ }
1224+
1225+ UInt16Array makeLength(UINT32 size)
1226+ {
1227+ UInt16Array length(2);
1228+ UCHAR sizes[4];
1229+
1230+ /*
1231+ 00001111111111111111111111111111
1232+
1233+ 1111111000000000000000000000
1234+ f e 0 0 0 0 0
1235+ 111111100000000000000
1236+ 1 f c 0 0 0
1237+ 11111110000000
1238+ 3 f 8 0
1239+ 1111111
1240+ 7 f
1241+ */
1242+
1243+ sizes[3] = static_cast<UCHAR>((size & 0x0000007f) >> 0);
1244+ sizes[2] = static_cast<UCHAR>((size & 0x00003f80) >> 7);
1245+ sizes[1] = static_cast<UCHAR>((size & 0x001fc000) >> 14);
1246+ sizes[0] = static_cast<UCHAR>((size & 0x0fe00000) >> 21);
1247+
1248+
1249+ length[0] = ((UINT16)sizes[1]) << 8 | sizes[0];
1250+ length[1] = ((UINT16)sizes[3]) << 8 | sizes[2];
1251+
1252+ return length;
1253+ }
1254+
1255+ protected:
1256+
1257+ TrackInfo m_info;
1258+ HANDLE m_hMp3File;
1259+};
1260+
1261+class DummyAmp
1262+{
1263+ public:
1264+
1265+ DummyAmp()
1266+ : m_bReady(false)
1267+ , m_hInstGenMixi((HINSTANCE)INVALID_HANDLE_VALUE)
1268+ , m_pGenMixi(NULL)
1269+ , m_hWinampWnd((HWND)INVALID_HANDLE_VALUE)
1270+ , m_GETPLAYLISTFILE_time(0)
1271+ , m_hDirChangeNotify((HANDLE)INVALID_HANDLE_VALUE)
1272+ , m_isDummyPlayInfoMp3Available(false)
1273+ , m_isAnotherWinampWindowAvailable(false)
1274+ {
1275+
1276+ m_winampTitle = _T("Winamp");
1277+ }
1278+
1279+ ~DummyAmp()
1280+ {
1281+ release();
1282+ destroyWindow();
1283+ closeDirChangeNotifyHandle();
1284+ }
1285+
1286+ public:
1287+
1288+ static DummyAmp *getInstance()
1289+ {
1290+ if(m_pMe == NULL)
1291+ {
1292+ m_pMe = new DummyAmp();
1293+ }
1294+
1295+ return m_pMe;
1296+ }
1297+
1298+ void load()
1299+ {
1300+ TRACE_DUMMYAMP_INIT(_T("DummyAmp::load - called."));
1301+
1302+ // initialize gen_mixi_for_winamp
1303+ initGenMixi();
1304+
1305+ // initialize dummy mp3 file, if dummy mp3 is enabled
1306+ if(cfg_disable_dummy_mp3 == 0) {
1307+ initDummyMp3();
1308+ }
1309+
1310+ // set ready flag, if initialization successfully done
1311+ if( (getGenMixi() != NULL) && ((cfg_disable_dummy_mp3 == 0) || (isDummyPlayInfoMp3Available() == true)) ){
1312+ setReady(true);
1313+ }
1314+ }
1315+
1316+ void config()
1317+ {
1318+ TRACE_DUMMYAMP_INIT(_T("DummyAmp::config - called."));
1319+
1320+ if(getGenMixi() != NULL) {
1321+ getGenMixi()->config();
1322+ }
1323+ }
1324+
1325+ void release()
1326+ {
1327+ TRACE_DUMMYAMP_INIT(_T("DummyAmp::release - called."));
1328+
1329+ // finalize gen_mixi_for_winamp
1330+ finalizeGenMixi();
1331+
1332+ // finalize dummy mp3 file, if dummy mp3 is enbaled
1333+ if(isDummyPlayInfoMp3Available())
1334+ {
1335+ finalizeDummyMp3();
1336+ }
1337+ }
1338+
1339+ void clearDummyAmpTitle()
1340+ {
1341+ uSetWindowText(getWnd(), DEFAULT_DUMMYAMP_TITLE);
1342+ }
1343+
1344+ void createWindow()
1345+ {
1346+ TRACE_PLUGIN(_T("DummyAmp::createWindow - called."));
1347+
1348+ if(getWnd() == INVALID_HANDLE_VALUE)
1349+ {
1350+ if(getGenMixi() != NULL)
1351+ {
1352+ HWND hAnotherWinamp = FindWindowEx(NULL, NULL, _T("Winamp v1.x"), NULL);
1353+
1354+ // found another winamp window
1355+ if(hAnotherWinamp != NULL)
1356+ {
1357+ DEBUG_PLUGIN(_T("DummyAmp::createWindow - Winamp のウィンドウを検出しました。ハンドル: %08x"), hAnotherWinamp);
1358+
1359+ DWORD dwAnotherWndProcessID;
1360+ ::GetWindowThreadProcessId(hAnotherWinamp, &dwAnotherWndProcessID);
1361+
1362+ DWORD dwFb2kProcessID = ::GetCurrentProcessId();
1363+
1364+ DEBUG_PLUGIN(_T("DummyAmp::createWindow - Winamp ウィンドウが属するプロセスのハンドル: %08x"), dwAnotherWndProcessID);
1365+ DEBUG_PLUGIN(_T("DummyAmp::createWindow - 現在実行中の foobar2000 プロセスのハンドル: %08x"), dwFb2kProcessID);
1366+
1367+ // another winamp window owned by foobar2000 process
1368+ if(dwAnotherWndProcessID == dwFb2kProcessID) {
1369+ // subclass it, because it's winamp api simulator plugin's window
1370+ setWnd(subclassWinampWindow(hAnotherWinamp));
1371+ } else {
1372+ LOG_ERROR(
1373+ _T("DummyAmp::createWindow - 検出した Winamp ウィンドウが他のプロセスに属しています"));
1374+ LOG_ERROR(
1375+ _T("DummyAmp::createWindow - Winamp と思われるプログラムが実行されているため、")
1376+ _T("mixi station への送信機能は使用できません"));
1377+ LOG_ERROR(
1378+ _T("DummyAmp::createWindow - 該当のプログラム(プロセスID:%d)を終了し、")
1379+ _T("foobar2000 を再起動してください")
1380+ , dwAnotherWndProcessID);
1381+
1382+ // unset dummyAmp ready flag
1383+ setReady(false);
1384+ }
1385+ }
1386+ // create own winamp simulating window
1387+ else
1388+ {
1389+ setWnd(createWinampWindow());
1390+ }
1391+
1392+ // initialize gen_mixi_for_winamp, if winamp window successfully created or subclassed
1393+ if(getWnd() != INVALID_HANDLE_VALUE)
1394+ {
1395+ getGenMixi()->hwndParent = getWnd();
1396+ getGenMixi()->hDllInstance = getHInstance();
1397+ getGenMixi()->init();
1398+ }
1399+ else
1400+ {
1401+ // unset dummyAmp ready flag
1402+ setReady(false);
1403+ }
1404+ }
1405+ }
1406+ }
1407+
1408+ void refreshAmpInfo()
1409+ {
1410+#if !defined(CONTROL_SEND_TIMING)
1411+ // increment play counter on dummyamp
1412+ getPlayInfo().incrementPlayCount();
1413+
1414+ // update dummyamp title
1415+ updateDummyAmpTitle();
1416+#endif
1417+ // use currently playing mp3 or ogg/vorbis file instead when dummy playinfo mp3 file disabled by user
1418+ // (other codec types will be ignored, because they are not supported by gen_mixi_for_winamp)
1419+ if(cfg_disable_dummy_mp3 == 1)
1420+ {
1421+ // set playinfo mp3 file path to dummyAmp
1422+ getPlayInfo().setPlayInfoMp3Path(m_trackInfo.getString(FORMAT_FILEPATH).c_str());
1423+
1424+ // set playinfo mp3 file available flag to dummyAmp
1425+ LPCSTR codec = m_trackInfo.getString(FORMAT_CODEC).c_str();
1426+ getPlayInfo().setPlayInfoMp3Available(IS_SUPPORTED_FORMAT_BY_GEN_MIXI(codec));
1427+ }
1428+ else
1429+ {
1430+ // check dummy playinfo mp3 exists and writable
1431+ if(isDummyPlayInfoMp3Available())
1432+ {
1433+ // update dummy mp3 file
1434+ tstring playInfoMp3Path = PathInfo::getDummyPlayInfoMp3Path();
1435+#if 1
1436+ id3Info id3Info(m_trackInfo);
1437+ DWORD dwErrCode;
1438+
1439+ if(( dwErrCode = id3Info.write(playInfoMp3Path.c_str()) ) == S_OK)
1440+ {
1441+ string_utf8_from_os dummyMp3Path8(playInfoMp3Path.c_str());
1442+
1443+ // set dummy playinfo mp3 file path to dummyAmp
1444+ getPlayInfo().setPlayInfoMp3Path(dummyMp3Path8);
1445+
1446+ // set playinfo mp3 file available flag to dummyAmp
1447+ getPlayInfo().setPlayInfoMp3Available(true);
1448+ }
1449+ else
1450+ {
1451+ putLogError(_T("DummyAmp::refreshAmpInfo"), _T("ダミーMP3ファイルの書き込み中にエラーが発生しました"), dwErrCode);
1452+ LOG_ERROR(_T("DummyAmp::refreshAmpInfo - ファイルパス: %s"), playInfoMp3Path.c_str());
1453+
1454+ // set playinfo mp3 file available flag
1455+ getPlayInfo().setPlayInfoMp3Available(false);
1456+
1457+ // unset dummyAmp ready flag
1458+ setReady(false);
1459+ }
1460+#else
1461+ // set id3v2 informations
1462+
1463+ string_utf8_from_os dummyMp3Path8(playInfoMp3Path.c_str());
1464+ string_ansi_from_utf8 dummyMp3PathAnsi(dummyMp3Path8);
1465+ ID3_Tag dummySong(dummyMp3PathAnsi);
1466+
1467+ string_wide_from_utf8 title_utf16(m_trackInfo.getString(FORMAT_TRACKTITLE, true).c_str());
1468+ string_wide_from_utf8 artist_utf16(m_trackInfo.getString(FORMAT_ARTIST, true).c_str());
1469+ string_wide_from_utf8 album_utf16(m_trackInfo.getString(FORMAT_ALBUMTITLE, true).c_str());
1470+ string_wide_from_utf8 genre_utf16(m_trackInfo.getString(FORMAT_GENRE, true).c_str());
1471+
1472+ AddTitle(&dummySong, title_utf16, true);
1473+ AddArtist(&dummySong, artist_utf16, true);
1474+ AddAlbum(&dummySong, album_utf16, true);
1475+ AddGenre(&dummySong, genre_utf16, true);
1476+
1477+ // write id3v2 tag
1478+ dummySong.SetPadding(false);
1479+ dummySong.SetUnsync(false);
1480+ if(dummySong.Update(ID3TT_ID3V2) != ID3TT_NONE)
1481+ {
1482+ // set dummy playinfo mp3 file path to dummyAmp
1483+ getPlayInfo().setPlayInfoMp3Path(dummyMp3Path8);
1484+
1485+ // set playinfo mp3 file available flag to dummyAmp
1486+ getPlayInfo().setPlayInfoMp3Available(true);
1487+ }
1488+ else
1489+ {
1490+ LOG_ERROR(_T("DummyAmp::refreshAmpInfo - ID3_Tag::Update(ID3TT_ID3V2) failed."));
1491+
1492+ // set playinfo mp3 file available flag
1493+ getPlayInfo().setPlayInfoMp3Available(false);
1494+
1495+ // unset dummyAmp ready flag
1496+ setReady(false);
1497+ }
1498+#endif
1499+ }
1500+ else
1501+ {
1502+ // reset playinfo mp3 file available flag
1503+ getPlayInfo().setPlayInfoMp3Available(false);
1504+
1505+ LOG_WARN(_T("DummyAmp::refreshAmpInfo - ダミーMP3ファイルが無効になっているため、送信情報を書き込めません。"));
1506+ }
1507+ }
1508+
1509+#if !defined(CONTROL_SEND_TIMING)
1510+ // set dummyamp status PLAY_START
1511+ getPlayInfo().setPlayStatusStart();
1512+#endif
1513+ }
1514+
1515+ public:
1516+
1517+ bool isReady() const {
1518+ return m_bReady;
1519+ }
1520+
1521+ HWND getWnd() const {
1522+ return m_hWinampWnd;
1523+ }
1524+
1525+ const TrackInfo &getTrackInfo() const {
1526+ return m_trackInfo;
1527+ }
1528+
1529+ TrackInfo &getMutableTrackInfo() {
1530+ return m_trackInfo;
1531+ }
1532+
1533+ void setTrackInfo(const TrackInfo &trackInfo) {
1534+ m_trackInfo = trackInfo;
1535+ }
1536+
1537+ PlayInfo &getPlayInfo() {
1538+ return m_playInfo;
1539+ }
1540+
1541+ PlayInfo &getRawPlayInfo() {
1542+ return m_rawPlayInfo;
1543+ }
1544+
1545+
1546+ void setPlaylistTitle(LPCTSTR pTitle) {
1547+
1548+ TRACE_PLUGIN(_T("DummyAmp::setPlayListTitle - %s"), pTitle);
1549+
1550+ m_playlistTitle = pTitle;
1551+
1552+ string_utf8_from_os playListTitle8(pTitle);
1553+
1554+ if(cfg_disable_ansi_trans == 1)
1555+ {
1556+
1557+ m_playlistTitle8 = playListTitle8;
1558+ }
1559+ else
1560+ {
1561+ string_ansi_from_utf8 playListTitleAnsi(playListTitle8);
1562+
1563+ m_playlistTitle8 = playListTitleAnsi;
1564+ }
1565+ }
1566+
1567+ const tstring &getPlaylistTitle() const {
1568+ return m_playlistTitle;
1569+ }
1570+
1571+ const string8 &getPlaylistTitle8() const {
1572+ return m_playlistTitle8;
1573+ }
1574+
1575+ void setWinampTitle(LPCTSTR pTitle) {
1576+
1577+ TRACE_PLUGIN(_T("DummyAmp::setWinampTitle - %s"), pTitle);
1578+
1579+ m_winampTitle = pTitle;
1580+ }
1581+
1582+ const tstring &getWinampTitle() const {
1583+ return m_winampTitle;
1584+ }
1585+
1586+ void setBaseWinampTitle(LPCTSTR pTitle)
1587+ {
1588+ TRACE_PLUGIN(_T("DummyAmp::setRawWinampTitle - %s"), pTitle);
1589+
1590+ m_baseWinampTitle = pTitle;
1591+
1592+ updateDummyAmpTitle();
1593+ }
1594+
1595+ const tstring &getBaseWinampTitle() const {
1596+ return m_baseWinampTitle;
1597+ }
1598+
1599+ const tstring &getDummyPlayInfoMp3Path() const {
1600+ return m_dummyPlayInfoMp3Path;
1601+ }
1602+
1603+ bool isDummyPlayInfoMp3Available() const {
1604+ return m_isDummyPlayInfoMp3Available;
1605+ }
1606+
1607+ bool isAnotherWinampWindowAvailable() const {
1608+ return m_isAnotherWinampWindowAvailable;
1609+ }
1610+
1611+ void showDummyAmpWindow(bool bShow) {
1612+ showDummyAmpWindow(getWnd(), bShow);
1613+ }
1614+
1615+ protected:
1616+
1617+ void initGenMixi()
1618+ {
1619+ string_os_from_utf8 path(cfg_gen_mixi_path);
1620+ tstring genMixiPath = path;
1621+ genMixiPath += GEN_MIXI_FILE_NAME;
1622+
1623+ setHInstance(::LoadLibrary(genMixiPath.c_str()));
1624+
1625+ if(getHInstance() == NULL)
1626+ {
1627+ setHInstance((HINSTANCE)INVALID_HANDLE_VALUE);
1628+
1629+ tstring msg;
1630+ msg = GEN_MIXI_FILE_NAME _T(" が見つかりません。\n以下のパスにファイルが存在するか確認してください。\n");
1631+ msg += genMixiPath;
1632+
1633+ string_utf8_from_os uMsg(msg.c_str());
1634+
1635+ uMessageBox(NULL, uMsg, PLUGIN_CAPTION, MB_ICONEXCLAMATION | MB_OK);
1636+ }
1637+ else
1638+ {
1639+ winampGeneralPurposePluginGetter funcWinampGetGeneralPurposePlugin = NULL;
1640+
1641+ funcWinampGetGeneralPurposePlugin = (winampGeneralPurposePluginGetter)
1642+ ::GetProcAddress(getHInstance(), GEN_MIXI_FUNC_NAME_GET_GENERAL_PURPOSE_PLUGIN);
1643+
1644+ if(funcWinampGetGeneralPurposePlugin != NULL)
1645+ {
1646+ setGenMixi(funcWinampGetGeneralPurposePlugin());
1647+ // create window later.
1648+ }
1649+ else
1650+ {
1651+ tstring msg;
1652+ msg = _T("関数 ") _T(GEN_MIXI_FUNC_NAME_GET_GENERAL_PURPOSE_PLUGIN) _T("() が見つかりません。\n")
1653+ GEN_MIXI_FILE_NAME _T(" が壊れている可能性があります。");
1654+
1655+ string_utf8_from_os uMsg(msg.c_str());
1656+
1657+ uMessageBox(NULL, uMsg, PLUGIN_CAPTION, MB_ICONEXCLAMATION | MB_OK);
1658+ }
1659+ }
1660+ }
1661+
1662+ void initDummyMp3()
1663+ {
1664+ // if dummy mp3 file not exist
1665+ tstring dummyPlayInfoMp3Path = PathInfo::getDummyPlayInfoMp3Path();
1666+ DWORD dwAttr = ::GetFileAttributes(dummyPlayInfoMp3Path.c_str());
1667+
1668+ if(dwAttr == -1)
1669+ {
1670+ // create dummy mp3 file
1671+ HANDLE hMp3File = ::CreateFile(
1672+ dummyPlayInfoMp3Path.c_str(), 0, 0, NULL,
1673+ CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL
1674+ );
1675+
1676+ if(hMp3File == INVALID_HANDLE_VALUE)
1677+ {
1678+ DWORD dwErrCode = ::GetLastError();
1679+ putLogError(_T("DummyAmp::initDummyMp3"), _T("ダミーMP3ファイルの作成中にエラーが発生しました"), dwErrCode);
1680+ LOG_ERROR(_T("DummyAmp::initDummyMp3 - ファイルパス: %s"), dummyPlayInfoMp3Path.c_str());
1681+
1682+ LOG_ERROR(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルが使用できないため、送信機能は無効になります"));
1683+ }
1684+ else
1685+ {
1686+ DEBUG_DUMMYAMP_INIT(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルを [%s] に作成しました"), dummyPlayInfoMp3Path.c_str());
1687+
1688+ ::CloseHandle(hMp3File);
1689+
1690+ setDummyPlayInfoMp3Path(dummyPlayInfoMp3Path);
1691+ setDummyPlayInfoMp3Available(true);
1692+ }
1693+ }
1694+ else if((dwAttr & FILE_ATTRIBUTE_READONLY) != 0)
1695+ {
1696+ LOG_ERROR(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルがパス [%s] 上に既に存在しますが、")
1697+ _T("読み込み専用属性のため書き込みできません"), dummyPlayInfoMp3Path.c_str());
1698+
1699+ LOG_ERROR(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルが使用できないため、送信機能は無効になります"));
1700+ }
1701+ else
1702+ {
1703+ LOG_WARN(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルがパス [%s] 上に既に存在します"), dummyPlayInfoMp3Path.c_str());
1704+ LOG_WARN(_T("DummyAmp::initDummyMp3 - このMP3ファイルは逐次上書きされ、終了時に削除されます"));
1705+
1706+ setDummyPlayInfoMp3Path(dummyPlayInfoMp3Path);
1707+ setDummyPlayInfoMp3Available(true);
1708+ }
1709+ }
1710+
1711+ void finalizeGenMixi()
1712+ {
1713+ if(getHInstance() != INVALID_HANDLE_VALUE)
1714+ {
1715+ if(getGenMixi() != NULL)
1716+ {
1717+ getGenMixi()->quit();
1718+ setGenMixi(NULL);
1719+ }
1720+ ::FreeLibrary(getHInstance());
1721+ setHInstance((HINSTANCE)INVALID_HANDLE_VALUE);
1722+ }
1723+
1724+ }
1725+
1726+ void finalizeDummyMp3()
1727+ {
1728+ tstring dummyPlayInfoMp3Path = getDummyPlayInfoMp3Path();
1729+
1730+ if(::DeleteFile(dummyPlayInfoMp3Path.c_str()) == FALSE)
1731+ {
1732+ DWORD dwErrCode = ::GetLastError();
1733+ putLogError(_T("DummyAmp::finalizeDummyMp3"), _T("ダミーMP3ファイルの削除中にエラーが発生しました"), dwErrCode);
1734+ LOG_ERROR(_T("DummyAmp::finalizeDummyMp3 - ファイルパス: %s"), dummyPlayInfoMp3Path.c_str());
1735+ }
1736+ else
1737+ {
1738+ DEBUG_DUMMYAMP_INIT(_T("DummyAmp::finalizeDummyMp3 - ダミーMP3ファイル [%s] を削除しました"), dummyPlayInfoMp3Path.c_str());
1739+ setDummyPlayInfoMp3Available(false);
1740+ }
1741+ }
1742+
1743+ void updateDummyAmpTitle()
1744+ {
1745+ bool bDisableDuplicatedSong = (cfg_disable_duplicate_song == 0);
1746+ tstring winampTitle = makeDummyAmpTitle(getBaseWinampTitle(), bDisableDuplicatedSong);
1747+
1748+ setWinampTitle(winampTitle.c_str());
1749+
1750+ if(isAnotherWinampWindowAvailable() == false) {
1751+ ::SetWindowText(getWnd(), winampTitle.c_str());
1752+ }
1753+ }
1754+
1755+ protected:
1756+
1757+ void setReady(bool bReady) {
1758+ m_bReady = bReady;
1759+ }
1760+
1761+ void setWnd(HWND hWnd) {
1762+ m_hWinampWnd = hWnd;
1763+ }
1764+
1765+ HINSTANCE getHInstance() const {
1766+ return m_hInstGenMixi;
1767+ }
1768+
1769+ void setHInstance(HINSTANCE hInst) {
1770+ m_hInstGenMixi = hInst;
1771+ }
1772+
1773+ winampGeneralPurposePlugin *getGenMixi() const {
1774+ return m_pGenMixi;
1775+ }
1776+
1777+ void setGenMixi(winampGeneralPurposePlugin *pGenMixi) {
1778+ m_pGenMixi = pGenMixi;
1779+ }
1780+
1781+ void setDummyPlayInfoMp3Path(const tstring &path) {
1782+ m_dummyPlayInfoMp3Path = path;
1783+ }
1784+
1785+ void setDummyPlayInfoMp3Available(bool isAvailable) {
1786+ m_isDummyPlayInfoMp3Available = isAvailable;
1787+ }
1788+
1789+ void setAnotherWinampWindowAvailable(bool isAvailable) {
1790+ m_isAnotherWinampWindowAvailable = isAvailable;
1791+ }
1792+
1793+ int getGetPlayListFileTime() const {
1794+ return m_GETPLAYLISTFILE_time;
1795+ }
1796+
1797+ void setGetPlayListFileTime(int time) {
1798+ m_GETPLAYLISTFILE_time = time;
1799+ }
1800+
1801+ HANDLE getDirChangeNotifyHandle() const {
1802+ return m_hDirChangeNotify;
1803+ }
1804+
1805+ void setDirChangeNotifyHandle(HANDLE handle) {
1806+ m_hDirChangeNotify = handle;
1807+ }
1808+
1809+ protected:
1810+
1811+ HWND createWinampWindow()
1812+ {
1813+ TRACE_PLUGIN(_T("DummyAmp::createWinampWindow - called."));
1814+
1815+ static bool isInited = false;
1816+
1817+#if IS_FB2K_VER08
1818+ static const char class_name[] = "Winamp v1.x";
1819+ if (!isInited)
1820+ {
1821+ isInited = true;
1822+ uWNDCLASS wc;
1823+ memset(&wc,0,sizeof(wc));
1824+ wc.style = 0;
1825+ wc.lpfnWndProc = windowproc;
1826+ wc.hInstance = core_api::get_my_instance();
1827+ wc.hCursor = NULL; //uLoadCursor(0, IDC_ARROW);
1828+ wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
1829+ wc.lpszClassName = class_name;
1830+ uRegisterClass(&wc);
1831+ }
1832+ HWND hWinampWnd = uCreateWindowEx(
1833+ 0, class_name, DEFAULT_DUMMYAMP_TITLE,
1834+ WS_OVERLAPPED|WS_CAPTION|WS_SIZEBOX,
1835+ CW_USEDEFAULT, CW_USEDEFAULT, 300, 150,
1836+#if 1
1837+ core_api::get_main_window(), 0, core_api::get_my_instance(), NULL
1838+#else
1839+ NULL, 0, core_api::get_my_instance(), NULL
1840+#endif
1841+ );
1842+#elif IS_FB2K_VER09
1843+ static const TCHAR class_name[] = _T("Winamp v1.x");
1844+ if (!isInited)
1845+ {
1846+ isInited = true;
1847+ WNDCLASS wc;
1848+ memset(&wc,0,sizeof(wc));
1849+ wc.style = 0;
1850+ wc.lpfnWndProc = windowproc;
1851+ wc.hInstance = core_api::get_my_instance();
1852+ wc.hCursor = NULL; //uLoadCursor(0, IDC_ARROW);
1853+ wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
1854+ wc.lpszClassName = class_name;
1855+ RegisterClass(&wc);
1856+ }
1857+ HWND hWinampWnd = CreateWindowEx(
1858+ 0, class_name, _T(DEFAULT_DUMMYAMP_TITLE),
1859+ WS_OVERLAPPED|WS_CAPTION|WS_SIZEBOX,
1860+ CW_USEDEFAULT, CW_USEDEFAULT, 300, 150,
1861+#if 1
1862+ core_api::get_main_window(), 0, core_api::get_my_instance(), NULL
1863+#else
1864+ NULL, 0, core_api::get_my_instance(), NULL
1865+#endif
1866+ );
1867+#endif
1868+ if (!hWinampWnd)
1869+ {
1870+ DWORD dwErrCode = ::GetLastError();
1871+ putLogError(_T("DummyAmp::createWinampWindow"), _T("DummyAmp ウィンドウの生成に失敗しました"), dwErrCode);
1872+
1873+ return NULL;
1874+ }
1875+
1876+ DEBUG_PLUGIN(_T("DummyAmp::createWinampWindow - DummyAmp ウィンドウを生成しました"));
1877+
1878+ showDummyAmpWindow(hWinampWnd, cfg_show_dummyamp == 1);
1879+
1880+ return hWinampWnd;
1881+ }
1882+
1883+ HWND subclassWinampWindow(HWND hAnotherWinampWnd) {
1884+ // subclass another dummyamp window
1885+ m_pfnOldAnotherWinampProc =
1886+ SetWindowLongPtr(hAnotherWinampWnd, GWL_WNDPROC, WNDPROC_TO_LONG_PTR(hookWinampWindowProc));
1887+
1888+ if(hAnotherWinampWnd != NULL)
1889+ {
1890+ DEBUG_PLUGIN(_T("DummyAmp::subclassWinampWindow - API エミュレータと思われる Winamp ウィンドウのプロシージャをフックしました"));
1891+ setAnotherWinampWindowAvailable(true);
1892+
1893+ return hAnotherWinampWnd;
1894+ }
1895+ else
1896+ {
1897+ DWORD dwErrCode = ::GetLastError();
1898+ putLogError(_T("DummyAmp::subclassWinampWindow"), _T("Winamp ウィンドウのサブクラス化に失敗しました"), dwErrCode);
1899+
1900+ LOG_ERROR(_T("DummyAmp::subclassWinampWindow - Winamp ウィンドウのプロシージャをフックできなかったため、送信機能は無効になります"));
1901+ }
1902+
1903+ return (HWND)INVALID_HANDLE_VALUE;
1904+ }
1905+
1906+ void unsubclassWinampWindow() {
1907+ SetWindowLongPtr(getWnd(), GWL_WNDPROC, m_pfnOldAnotherWinampProc);
1908+ }
1909+
1910+ void showDummyAmpWindow(HWND hWinampWnd, bool bShow)
1911+ {
1912+ if(bShow) {
1913+ ShowWindow(hWinampWnd, SW_SHOW);
1914+ } else {
1915+ ShowWindow(hWinampWnd, SW_HIDE);
1916+ }
1917+ }
1918+
1919+ void destroyWindow()
1920+ {
1921+ TRACE_PLUGIN(_T("DummyAmp::destroyWindow - called."));
1922+
1923+ if(getWnd() != INVALID_HANDLE_VALUE)
1924+ {
1925+ if(isAnotherWinampWindowAvailable() == false) {
1926+ uDestroyWindow(getWnd());
1927+ } else {
1928+ unsubclassWinampWindow();
1929+
1930+ DEBUG_PLUGIN(_T("DummyAmp::destroyWindow - Winamp ウィンドウのサブクラス化を解除しました"));
1931+ }
1932+
1933+ setWnd((HWND)INVALID_HANDLE_VALUE);
1934+ }
1935+ }
1936+
1937+ void closeDirChangeNotifyHandle()
1938+ {
1939+ TRACE_PLUGIN(_T("DummyAmp::closeDirChangeNotifyHandle - called."));
1940+
1941+ if(m_hDirChangeNotify != INVALID_HANDLE_VALUE)
1942+ {
1943+ ::FindCloseChangeNotification(m_hDirChangeNotify);
1944+ TRACE_PLUGIN(_T("DummyAmp::closeDirChangeNotifyHandle - ディレクトリ変更通知イベントのハンドル (ID:%08x) を閉じました"), m_hDirChangeNotify);
1945+
1946+ m_hDirChangeNotify = (HANDLE)INVALID_HANDLE_VALUE;
1947+ }
1948+ }
1949+
1950+ tstring makeDummyAmpTitle(const tstring &rawTitle, bool bCounterReflection)
1951+ {
1952+ TRACE_PLUGIN(_T("DummyAmp::makeDummyAmpTitle - called."));
1953+
1954+ Str64K formatBuf;
1955+
1956+ if(bCounterReflection)
1957+ {
1958+ _stprintf_s(
1959+ formatBuf, sizeof(formatBuf) / sizeof(TCHAR),
1960+ _T("%d. %s - ") _T(DEFAULT_WINAMP_TITLE),
1961+ getPlayInfo().getPlayCount(),
1962+ (LPCTSTR)rawTitle.c_str()
1963+ );
1964+ }
1965+ else
1966+ {
1967+ _stprintf_s(
1968+ formatBuf, sizeof(formatBuf) / sizeof(TCHAR),
1969+ _T("%d. %s - ") _T(DEFAULT_WINAMP_TITLE),
1970+ m_trackInfo.getNumber(FORMAT_LISTINDEX),
1971+ (LPCTSTR)rawTitle.c_str()
1972+ );
1973+ }
1974+
1975+ return formatBuf;
1976+ }
1977+
1978+ void refreshTitle()
1979+ {
1980+ // get formatted dynamic titles
1981+ string8 dummyAmp_title8;
1982+ string8 playlist_title8;
1983+#if IS_FB2K_VER08
1984+ metadb_handle *track = play_control::get()->get_now_playing();
1985+ if(track)
1986+ {
1987+ play_control::get()->playback_format_title_ex(track, dummyAmp_title8, cfg_dummyamp_title_format, NULL, false, true);
1988+ play_control::get()->playback_format_title_ex(track, playlist_title8, cfg_dummyamp_playlist_format, NULL, false, true);
1989+ track->handle_release();
1990+ }
1991+#elif IS_FB2K_VER09
1992+ metadb_handle_ptr track;
1993+ static_api_ptr_t<playback_control>()->get_now_playing(track);
1994+
1995+ service_ptr_t<titleformat_object> titleformat;
1996+
1997+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, cfg_dummyamp_title_format);
1998+ static_api_ptr_t<playback_control>()->playback_format_title_ex(track, NULL, dummyAmp_title8, titleformat, NULL, play_control::display_level_all);
1999+
2000+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, cfg_dummyamp_playlist_format);
2001+ static_api_ptr_t<playback_control>()->playback_format_title_ex(track, NULL, playlist_title8, titleformat, NULL, play_control::display_level_all);
2002+#endif
2003+ // convert utf8 track informations to os charset
2004+ string_os_from_utf8 dummyAmp_title(dummyAmp_title8);
2005+ string_os_from_utf8 playlist_title(playlist_title8);
2006+
2007+ // set base dummyamp title to dummyamp
2008+ setBaseWinampTitle(dummyAmp_title);
2009+
2010+ // set dummyamp playlist current item title to dummyamp
2011+ setPlaylistTitle(playlist_title);
2012+ }
2013+
2014+#if 0
2015+ private:
2016+
2017+ ID3_Frame* AddArtist(ID3_Tag *tag, const wchar_t *text, bool replace)
2018+ {
2019+ ID3_Frame* frame = NULL;
2020+ if (NULL != tag && NULL != text && lstrlen(text) > 0)
2021+ {
2022+ if (replace)
2023+ {
2024+ RemoveArtists(tag);
2025+ }
2026+ if (replace ||
2027+ (tag->Find(ID3FID_LEADARTIST) == NULL &&
2028+ tag->Find(ID3FID_BAND) == NULL &&
2029+ tag->Find(ID3FID_CONDUCTOR) == NULL &&
2030+ tag->Find(ID3FID_COMPOSER) == NULL))
2031+ {
2032+ frame = new ID3_Frame(ID3FID_LEADARTIST);
2033+ if (frame)
2034+ {
2035+ frame->GetField(ID3FN_TEXT)->SetEncoding(ID3TE_UNICODE);
2036+ frame->GetField(ID3FN_TEXT)->Set(SwapByteOrder(text));
2037+ frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_UNICODE);
2038+ tag->AttachFrame(frame);
2039+ }
2040+ }
2041+ }
2042+ return frame;
2043+ }
2044+
2045+ size_t RemoveArtists(ID3_Tag *tag)
2046+ {
2047+ size_t num_removed = 0;
2048+ ID3_Frame *frame = NULL;
2049+
2050+ if (NULL == tag)
2051+ {
2052+ return num_removed;
2053+ }
2054+
2055+ while ((frame = tag->Find(ID3FID_LEADARTIST)) != NULL)
2056+ {
2057+ frame = tag->RemoveFrame(frame);
2058+ delete frame;
2059+ num_removed++;
2060+ }
2061+ while ((frame = tag->Find(ID3FID_BAND)) != NULL)
2062+ {
2063+ frame = tag->RemoveFrame(frame);
2064+ delete frame;
2065+ num_removed++;
2066+ }
2067+ while ((frame = tag->Find(ID3FID_CONDUCTOR)) != NULL)
2068+ {
2069+ frame = tag->RemoveFrame(frame);
2070+ delete frame;
2071+ num_removed++;
2072+ }
2073+ while ((frame = tag->Find(ID3FID_COMPOSER)) != NULL)
2074+ {
2075+ frame = tag->RemoveFrame(frame);
2076+ delete frame;
2077+ num_removed++;
2078+ }
2079+
2080+ return num_removed;
2081+ }
2082+
2083+ ID3_Frame* AddAlbum(ID3_Tag *tag, const wchar_t *text, bool replace)
2084+ {
2085+ ID3_Frame* frame = NULL;
2086+ if (NULL != tag && NULL != text && lstrlen(text) > 0)
2087+ {
2088+ if (replace)
2089+ {
2090+ RemoveAlbums(tag);
2091+ }
2092+ if (replace || tag->Find(ID3FID_ALBUM) == NULL)
2093+ {
2094+ frame = new ID3_Frame(ID3FID_ALBUM);
2095+ if (frame)
2096+ {
2097+ frame->GetField(ID3FN_TEXT)->SetEncoding(ID3TE_UNICODE);
2098+ frame->GetField(ID3FN_TEXT)->Set(SwapByteOrder(text));
2099+ frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_UNICODE);
2100+ tag->AttachFrame(frame);
2101+ }
2102+ }
2103+ }
2104+
2105+ return frame;
2106+ }
2107+
2108+ size_t RemoveAlbums(ID3_Tag *tag)
2109+ {
2110+ size_t num_removed = 0;
2111+ ID3_Frame *frame = NULL;
2112+
2113+ if (NULL == tag)
2114+ {
2115+ return num_removed;
2116+ }
2117+
2118+ while ((frame = tag->Find(ID3FID_ALBUM)) != NULL)
2119+ {
2120+ frame = tag->RemoveFrame(frame);
2121+ delete frame;
2122+ num_removed++;
2123+ }
2124+
2125+ return num_removed;
2126+ }
2127+
2128+ ID3_Frame* AddTitle(ID3_Tag *tag, const wchar_t *text, bool replace)
2129+ {
2130+ ID3_Frame* frame = NULL;
2131+ if (NULL != tag && NULL != text && lstrlen(text) > 0)
2132+ {
2133+ if (replace)
2134+ {
2135+ RemoveTitles(tag);
2136+ }
2137+ if (replace || tag->Find(ID3FID_TITLE) == NULL)
2138+ {
2139+ frame = new ID3_Frame(ID3FID_TITLE);
2140+ if (frame)
2141+ {
2142+ frame->GetField(ID3FN_TEXT)->SetEncoding(ID3TE_UNICODE);
2143+ frame->GetField(ID3FN_TEXT)->Set(SwapByteOrder(text));
2144+ frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_UNICODE);
2145+ tag->AttachFrame(frame);
2146+ }
2147+ }
2148+ }
2149+
2150+ return frame;
2151+ }
2152+
2153+ size_t RemoveTitles(ID3_Tag *tag)
2154+ {
2155+ size_t num_removed = 0;
2156+ ID3_Frame *frame = NULL;
2157+
2158+ if (NULL == tag)
2159+ {
2160+ return num_removed;
2161+ }
2162+
2163+ while ((frame = tag->Find(ID3FID_TITLE)) != NULL)
2164+ {
2165+ frame = tag->RemoveFrame(frame);
2166+ delete frame;
2167+ num_removed++;
2168+ }
2169+
2170+ return num_removed;
2171+ }
2172+
2173+ //following routine courtesy of John George
2174+ ID3_Frame* AddGenre(ID3_Tag* tag, const wchar_t *genre, bool replace)
2175+ {
2176+ ID3_Frame* frame = NULL;
2177+ if (NULL != tag && NULL != genre && lstrlen(genre) > 0)
2178+ {
2179+ if (replace)
2180+ {
2181+ RemoveGenres(tag);
2182+ }
2183+ if (replace || NULL == tag->Find(ID3FID_CONTENTTYPE))
2184+ {
2185+ frame = new ID3_Frame(ID3FID_CONTENTTYPE);
2186+ if (NULL != frame)
2187+ {
2188+ frame->GetField(ID3FN_TEXT)->SetEncoding(ID3TE_UNICODE);
2189+ frame->GetField(ID3FN_TEXT)->Set(SwapByteOrder(genre));
2190+ frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_UNICODE);
2191+ tag->AttachFrame(frame);
2192+ }
2193+ }
2194+ }
2195+
2196+ return frame;
2197+ }
2198+
2199+ size_t RemoveGenres(ID3_Tag *tag)
2200+ {
2201+ size_t num_removed = 0;
2202+ ID3_Frame *frame = NULL;
2203+
2204+ if (NULL == tag)
2205+ {
2206+ return num_removed;
2207+ }
2208+
2209+ while ((frame = tag->Find(ID3FID_CONTENTTYPE)) != NULL)
2210+ {
2211+ frame = tag->RemoveFrame(frame);
2212+ delete frame;
2213+ num_removed++;
2214+ }
2215+
2216+ return num_removed;
2217+ }
2218+
2219+ const unicode_t *SwapByteOrder(const wchar_t *text)
2220+ {
2221+ static unicode_t resBuf[65536];
2222+ const wchar_t *pText;
2223+ unicode_t *pBuf;
2224+
2225+ for(pText = text, pBuf = resBuf; *pText != L'\0'; pText ++, pBuf ++)
2226+ {
2227+ wchar_t srcVal = *pText;
2228+ //unicode_t dstVal = srcVal;
2229+ unicode_t dstVal = (srcVal << 8) | (srcVal >> 8);
2230+ *pBuf = dstVal;
2231+ }
2232+
2233+ *pBuf = L'\0';
2234+
2235+ return resBuf;
2236+ }
2237+#endif
2238+
2239+ protected:
2240+
2241+ static LRESULT WINAPI hookWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp);
2242+ static LRESULT WINAPI windowproc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp);
2243+ static std::pair<bool, LRESULT> WINAPI innerWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp);
2244+ static std::pair<bool, LRESULT> WINAPI outerWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp);
2245+
2246+ protected:
2247+
2248+ static DummyAmp *m_pMe;
2249+
2250+ bool m_bReady;
2251+
2252+ HINSTANCE m_hInstGenMixi;
2253+ winampGeneralPurposePlugin *m_pGenMixi;
2254+
2255+ HWND m_hWinampWnd;
2256+ bool m_isAnotherWinampWindowAvailable;
2257+
2258+ static LONG_PTR m_pfnOldAnotherWinampProc;
2259+
2260+ HANDLE m_hDirChangeNotify;
2261+
2262+ PlayInfo m_playInfo;
2263+ PlayInfo m_rawPlayInfo;
2264+
2265+ TrackInfo m_trackInfo;
2266+ int m_GETPLAYLISTFILE_time;
2267+
2268+ tstring m_playlistTitle;
2269+ string8 m_playlistTitle8;
2270+
2271+ tstring m_winampTitle;
2272+ tstring m_baseWinampTitle;
2273+
2274+ tstring m_dummyPlayInfoMp3Path;
2275+ bool m_isDummyPlayInfoMp3Available;
2276+};
2277+
2278+DummyAmp *DummyAmp::m_pMe = NULL;
2279+
2280+LONG_PTR DummyAmp::m_pfnOldAnotherWinampProc = NULL;
2281+
2282+LRESULT CALLBACK DummyAmp::hookWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp)
2283+{
2284+ if(InSendMessage() || (msg != WM_WA_IPC))
2285+ {
2286+ switch(msg)
2287+ {
2288+ case WM_CLOSE:
2289+ DEBUG_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_CLOSE %s"),
2290+ InSendMessage() == TRUE ? _T("from other thread") : _T(""));
2291+
2292+ DummyAmp::getInstance()->destroyWindow();
2293+ break;
2294+
2295+ case WM_GETTEXT:
2296+ {
2297+ // message from same thread
2298+ if((InSendMessage() == FALSE) && (DummyAmp::getInstance()->isAnotherWinampWindowAvailable() == true))
2299+ {
2300+ LPCTSTR pWinampTitle = DummyAmp::getInstance()->getWinampTitle().c_str();
2301+ int nLen = ::lstrlen(pWinampTitle);
2302+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_GETTEXT / window title [%s]."), pWinampTitle);
2303+
2304+ ::lstrcpyn(reinterpret_cast<LPTSTR>(lp), pWinampTitle, static_cast<int>(wp));
2305+
2306+ return (LRESULT)nLen;
2307+ }
2308+ }
2309+ break;
2310+
2311+ case WM_GETTEXTLENGTH:
2312+ {
2313+ // message from same thread
2314+ if((InSendMessage() == FALSE) && (DummyAmp::getInstance()->isAnotherWinampWindowAvailable() == true))
2315+ {
2316+ LPCTSTR pWinampTitle = DummyAmp::getInstance()->getWinampTitle().c_str();
2317+ int nLen = ::lstrlen(pWinampTitle);
2318+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_GETTEXTLENGTH / window title length %d."), nLen);
2319+
2320+ return (LRESULT)nLen;
2321+ }
2322+ }
2323+ break;
2324+
2325+ case WM_SETTEXT:
2326+ {
2327+ // message from same thread
2328+ if((InSendMessage() == FALSE) && (DummyAmp::getInstance()->isAnotherWinampWindowAvailable() == true))
2329+ {
2330+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_SETTEXT / window title [%s]."), reinterpret_cast<LPCTSTR>(lp));
2331+ }
2332+ }
2333+ break;
2334+
2335+ default:
2336+
2337+ if(InSendMessage())
2338+ {
2339+ if(msg == WM_WA_IPC) {
2340+ if(cfg_enable_ext_ipc_proc == 1)
2341+ {
2342+ std::pair<bool, LRESULT> res = outerWinampWindowProc(wnd, msg, wp, lp);
2343+ if(res.first == true) {
2344+ return res.second;
2345+ }
2346+ }
2347+
2348+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_WA_IPC from other thread / W:%08x, L:%08x"), wp, lp);
2349+
2350+ }
2351+ else
2352+ {
2353+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - ")
2354+ _T("message from other thread / MSG:%04x, W:%08x, L:%08x"), msg, wp, lp);
2355+ }
2356+ }
2357+
2358+ break;
2359+ }
2360+
2361+ return CallWindowProc(LONG_PTR_TO_WNDPROC(m_pfnOldAnotherWinampProc), wnd, msg, wp, lp);
2362+ }
2363+ else
2364+ {
2365+ return CallWindowProc(windowproc, wnd, msg, wp, lp);
2366+ }
2367+}
2368+
2369+LRESULT CALLBACK DummyAmp::windowproc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp)
2370+{
2371+ switch(msg)
2372+ {
2373+ case WM_CLOSE:
2374+ DEBUG_DUMMYAMP_PROC(_T("DummyAmp::windowproc - WM_CLOSE"));
2375+ DummyAmp::getInstance()->destroyWindow();
2376+ return 0;
2377+
2378+ case WM_WA_IPC:
2379+ // message from same thread
2380+ if(InSendMessage() == FALSE)
2381+ {
2382+ std::pair<bool, LRESULT> res = innerWinampWindowProc(wnd, msg, wp, lp);
2383+ if(res.first == true) {
2384+ return res.second;
2385+ }
2386+ }
2387+ // message from other thread
2388+ else
2389+ {
2390+ std::pair<bool, LRESULT> res = outerWinampWindowProc(wnd, msg, wp, lp);
2391+ if(res.first == true) {
2392+ return res.second;
2393+ }
2394+ }
2395+ break;
2396+ default:
2397+ if(InSendMessage()) {
2398+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::windowproc - Unknown MSG from other thread / MSG:%04x, W:%08x, L:%08x"), msg, wp, lp);
2399+ }
2400+ break;
2401+ }
2402+
2403+ return uDefWindowProc(wnd,msg,wp,lp);
2404+}
2405+
2406+std::pair<bool, LRESULT> WINAPI DummyAmp::innerWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp)
2407+{
2408+ switch(msg)
2409+ {
2410+ case WM_WA_IPC:
2411+ {
2412+ PlayInfo::EPlayStatus playStatus = DummyAmp::getInstance()->getPlayInfo().getPlayStatus();
2413+ int playPosition = DummyAmp::getInstance()->getPlayInfo().getPlayPosition();
2414+ int playLength = DummyAmp::getInstance()->getPlayInfo().getPlayLength();
2415+ int playCount = DummyAmp::getInstance()->getPlayInfo().getPlayCount();
2416+ int getPlayListFileTime = DummyAmp::getInstance()->getGetPlayListFileTime();
2417+ bool isPlayInfoMp3Available = DummyAmp::getInstance()->getPlayInfo().isPlayInfoMp3Available();
2418+ const string8 &playInfoMp3Path8 = DummyAmp::getInstance()->getPlayInfo().getPlayInfoMp3Path8();
2419+
2420+ switch(lp)
2421+ {
2422+ case IPC_ISPLAYING:
2423+ if(cfg_use_plugin == 1)
2424+ {
2425+ HANDLE hDirChangeNotify = DummyAmp::getInstance()->getDirChangeNotifyHandle();
2426+
2427+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_ISPLAYING / status [%d]"), playStatus);
2428+
2429+ if(playStatus != PlayInfo::PLAY_START)
2430+ {
2431+ if(DummyAmp::getInstance()->getPlayInfo().isResentMode()) {
2432+ DummyAmp::getInstance()->getPlayInfo().clearResentMode();
2433+ }
2434+
2435+ if(hDirChangeNotify != INVALID_HANDLE_VALUE)
2436+ {
2437+ LOG_WARN(_T("DummyAmp::innerWinampWindowProc - ディレクトリ変更通知イベントのハンドルが閉じられていません"));
2438+ LOG_WARN(_T("DummyAmp::innerWinampWindowProc - 安全のため、ここで閉じます"));
2439+ DummyAmp::getInstance()->closeDirChangeNotifyHandle();
2440+ }
2441+ }
2442+ else
2443+ {
2444+ if(hDirChangeNotify != INVALID_HANDLE_VALUE)
2445+ {
2446+ DWORD dwRes = ::WaitForMultipleObjects(1, &hDirChangeNotify, FALSE, 0);
2447+
2448+ if(dwRes == WAIT_OBJECT_0)
2449+ {
2450+ LOG_INFO(_T("mixi station successfully updated."));
2451+ DummyAmp::getInstance()->closeDirChangeNotifyHandle();
2452+ DummyAmp::getInstance()->getPlayInfo().setPlayStatusStop();
2453+ }
2454+ else if(playPosition >= getPlayListFileTime + RESENT_INTERVAL)
2455+ {
2456+ DummyAmp::getInstance()->closeDirChangeNotifyHandle();
2457+ LOG_WARN(_T("DummyAmp::innerWinampWindowProc - mixi station ディレクトリの変更通知イベントが待ち時間内に発生しませんでした"));
2458+#if !defined(DISABLE_KICK_GEN_MIXI_LOOP)
2459+ LOG_WARN(_T("DummyAmp::innerWinampWindowProc - gen_mixi_for_winamp に曲情報取得要求を再送させます"));
2460+ DummyAmp::getInstance()->getPlayInfo().setResentMode();
2461+ DummyAmp::getInstance()->updateDummyAmpTitle();
2462+#else
2463+ LOG_WARN(_T("DummyAmp::innerWinampWindowProc - 曲情報は破棄されました"));
2464+#endif
2465+ }
2466+ }
2467+ }
2468+ return std::make_pair(true, playStatus);
2469+ }
2470+ return std::make_pair(true, PlayInfo::PLAY_STOP);
2471+
2472+ case IPC_GETOUTPUTTIME:
2473+ if(cfg_use_plugin == 1)
2474+ {
2475+ if(playStatus == PlayInfo::PLAY_START)
2476+ {
2477+ if(wp == IPC_GETOUTPUTTIME_PositionMSec)
2478+ {
2479+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_GETOUTPUTTIME / position [%d sec.]"), playPosition / 1000);
2480+
2481+ return std::make_pair(true, playPosition);
2482+ }
2483+ else if(wp == IPC_GETOUTPUTTIME_TotalSec)
2484+ {
2485+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_GETOUTPUTTIME / length [%d sec.]"), playLength);
2486+ return std::make_pair(true, playLength);
2487+ }
2488+ }
2489+ }
2490+ return std::make_pair(true, -1);
2491+
2492+ case IPC_GETLISTPOS:
2493+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_GETLISTPOS / index [%d]"), playCount);
2494+ return std::make_pair(true, playCount);
2495+
2496+ case IPC_GETPLAYLISTFILE:
2497+ if(cfg_use_plugin == 1)
2498+ {
2499+ if(isPlayInfoMp3Available == true)
2500+ {
2501+ DEBUG_DUMMYAMP_PROC8(
2502+ "DummyAmp::innerWinampWindowProc - IPC_GETPLAYLISTFILE / #%d - path [%s]",
2503+ playCount, (LPCSTR)playInfoMp3Path8);
2504+
2505+ DummyAmp::getInstance()->setGetPlayListFileTime(playPosition);
2506+
2507+ tstring mixiAppDataPath = PathInfo::getMixiStationAppPath();
2508+
2509+ DummyAmp::getInstance()->setDirChangeNotifyHandle(
2510+ ::FindFirstChangeNotification(mixiAppDataPath.c_str(), FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE)
2511+ );
2512+
2513+ return std::make_pair(true, (LRESULT)(LPCSTR)playInfoMp3Path8);
2514+ }
2515+ else
2516+ {
2517+ if(cfg_disable_dummy_mp3 == 1)
2518+ {
2519+ DEBUG_DUMMYAMP_PROC(_T("DummyAm::innerWinampWindowProcp - IPC_GETPLAYLISTFILE / NULL (audio file codec type not supported.)"));
2520+ }
2521+ else
2522+ {
2523+ LOG_WARN(_T("DummyAmp::innerWinampWindowProc - IPC_GETPLAYLISTFILE / NULL (dummy mp3 file not enabled.)"));
2524+ }
2525+ }
2526+ }
2527+ return std::make_pair(true, NULL);
2528+
2529+ case IPC_INTERNAL_REFRESHLISTINFO: // 0x4000
2530+ {
2531+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_INTERNAL_REFRESHLISTINFO / refresh internal playlist informations."));
2532+
2533+ // make playlist info formats array
2534+ Strings plNumKeys;
2535+
2536+ plNumKeys.push_back(FORMAT_LISTINDEX);
2537+
2538+ // set current track informations
2539+ DummyAmp::getInstance()->getMutableTrackInfo().setPlaylistNumbers(plNumKeys);
2540+
2541+ // refresh dummyamp title
2542+ DummyAmp::getInstance()->refreshTitle();
2543+
2544+ return std::make_pair(true, 0);
2545+ }
2546+
2547+ case IPC_INTERNAL_REFRESHDYNINFO: // 0x4001
2548+ {
2549+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_INTERNAL_REFRESHDYNINFO / refresh internal dynamic informations."));
2550+
2551+ // make dynamic info formats array
2552+ Strings dynStrKeys;
2553+
2554+ dynStrKeys.push_back(FORMAT_ARTIST);
2555+ dynStrKeys.push_back(FORMAT_TRACKTITLE);
2556+ dynStrKeys.push_back(FORMAT_ALBUMTITLE);
2557+ dynStrKeys.push_back(FORMAT_GENRE);
2558+
2559+ // set current track informations
2560+ DummyAmp::getInstance()->getMutableTrackInfo().removeStrings(dynStrKeys);
2561+ DummyAmp::getInstance()->getMutableTrackInfo().setDynamicStrings(dynStrKeys);
2562+
2563+ // refresh dummyamp title
2564+ DummyAmp::getInstance()->refreshTitle();
2565+
2566+ // when explicitly tagged file only mode and artist or track name not found,
2567+ // then skip sending track informations
2568+ string8 title_utf8 = DummyAmp::getInstance()->getTrackInfo().getString(FORMAT_TRACKTITLE, true).c_str();
2569+ string8 artist_utf8 = DummyAmp::getInstance()->getTrackInfo().getString(FORMAT_ARTIST, true).c_str();
2570+ string8 album_utf8 = DummyAmp::getInstance()->getTrackInfo().getString(FORMAT_ALBUMTITLE).c_str();
2571+ string8 genre_utf8 = DummyAmp::getInstance()->getTrackInfo().getString(FORMAT_GENRE).c_str();
2572+
2573+ if( (cfg_explicitly_tagged_file_only == 1) && (!lstrcmpA(title_utf8, "?") || !lstrcmpA(artist_utf8, "?")) )
2574+ {
2575+ DEBUG_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_INTERNAL_REFRESHDYNINFO / SKIP this track. (artist or title not found)"));
2576+ }
2577+ else
2578+ {
2579+ if(!lstrcmpA(title_utf8, "?"))
2580+ {
2581+ DummyAmp::getInstance()->getMutableTrackInfo().removeString(FORMAT_TRACKTITLE);
2582+ DummyAmp::getInstance()->getMutableTrackInfo().putString(FORMAT_TRACKTITLE, (LPCSTR)cfg_no_title_name);
2583+ }
2584+
2585+ if(!lstrcmpA(artist_utf8, "?"))
2586+ {
2587+ DummyAmp::getInstance()->getMutableTrackInfo().removeString(FORMAT_ARTIST);
2588+ DummyAmp::getInstance()->getMutableTrackInfo().putString(FORMAT_ARTIST, (LPCSTR)cfg_no_artist_name);
2589+ }
2590+
2591+ if(!lstrcmpA(album_utf8, "?"))
2592+ {
2593+ DummyAmp::getInstance()->getMutableTrackInfo().removeString(FORMAT_ALBUMTITLE);
2594+ DummyAmp::getInstance()->getMutableTrackInfo().putString(FORMAT_ALBUMTITLE,(LPCSTR) cfg_no_album_name);
2595+ }
2596+
2597+ if(!lstrcmpA(genre_utf8, "?"))
2598+ {
2599+ DummyAmp::getInstance()->getMutableTrackInfo().removeString(FORMAT_GENRE);
2600+ DummyAmp::getInstance()->getMutableTrackInfo().putString(FORMAT_GENRE, (LPCSTR)cfg_no_genre_name);
2601+ }
2602+
2603+ // refresh dummyamp info
2604+ DummyAmp::getInstance()->refreshAmpInfo();
2605+ }
2606+
2607+ return std::make_pair(true, 0);
2608+ }
2609+
2610+ default:
2611+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - WM_WA_IPC (Unknown IPC command) / W:%08x, L:%08x"), wp, lp);
2612+ break;
2613+ }
2614+
2615+ }
2616+ break;
2617+ }
2618+
2619+ return std::make_pair(false, 0);
2620+}
2621+
2622+std::pair<bool, LRESULT> WINAPI DummyAmp::outerWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp)
2623+{
2624+ switch(msg)
2625+ {
2626+ case WM_WA_IPC:
2627+ {
2628+ PlayInfo::EPlayStatus rawPlayStatus = DummyAmp::getInstance()->getRawPlayInfo().getPlayStatus();
2629+ int rawPlayPosition = DummyAmp::getInstance()->getRawPlayInfo().getPlayPosition();
2630+ int rawPlayLength = DummyAmp::getInstance()->getRawPlayInfo().getPlayLength();
2631+ int rawPlayCount = DummyAmp::getInstance()->getPlayInfo().getPlayCount();
2632+ const string8 &rawPlayInfoMp3Path8 = DummyAmp::getInstance()->getRawPlayInfo().getPlayInfoMp3Path8();
2633+ const tstring &playlistTitle = DummyAmp::getInstance()->getPlaylistTitle();
2634+ const string8 &playlistTitle8 = DummyAmp::getInstance()->getPlaylistTitle8();
2635+
2636+ switch(lp)
2637+ {
2638+ case IPC_ISPLAYING:
2639+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_ISPLAYING / status [%d]"), rawPlayStatus);
2640+ return std::make_pair(true, rawPlayStatus);
2641+
2642+ case IPC_GETOUTPUTTIME:
2643+
2644+ if(rawPlayStatus != PlayInfo::PLAY_START)
2645+ {
2646+ rawPlayPosition = -1;
2647+ rawPlayLength = -1;
2648+ }
2649+ else if(true)
2650+ {
2651+#if IS_FB2K_VER08
2652+ rawPlayPosition = static_cast<int>(play_control::get()->get_playback_time() * 1000.0);
2653+#else IS_FB2K_VER09
2654+ rawPlayPosition = static_cast<int>(static_api_ptr_t<playback_control>()->playback_get_position() * 1000.0);
2655+#endif
2656+ }
2657+
2658+ if(wp == IPC_GETOUTPUTTIME_PositionMSec)
2659+ {
2660+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_GETOUTPUTTIME / position [%.3f sec.]"), rawPlayPosition / 1000.0);
2661+ return std::make_pair(true, rawPlayPosition);
2662+ }
2663+ else if(wp == IPC_GETOUTPUTTIME_TotalSec)
2664+ {
2665+ TRACE_DUMMYAMP_PROC(_T("DummyAm::outerWinampWindowProcp - IPC_GETOUTPUTTIME / length [%d sec.]"), rawPlayLength);
2666+ return std::make_pair(true, rawPlayLength);
2667+ }
2668+
2669+ return std::make_pair(true, -1);
2670+
2671+ case IPC_GETLISTPOS:
2672+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_GETLISTPOS / index [%d]"), rawPlayCount);
2673+ return std::make_pair(true, rawPlayCount);
2674+
2675+ case IPC_GETPLAYLISTFILE:
2676+ TRACE_DUMMYAMP_PROC8(
2677+ "DummyAmp::outerWinampWindowProc - IPC_GETPLAYLISTFILE / path [%s]", (LPCSTR)rawPlayInfoMp3Path8);
2678+ return std::make_pair(true, (LRESULT)(LPCSTR)rawPlayInfoMp3Path8);
2679+
2680+ case IPC_GETPLAYLISTTITLE:
2681+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_GETPLAYLISTTITLE")
2682+ _T(" / title [%s]"), (LPCTSTR)playlistTitle.c_str());
2683+ return std::make_pair(true, (LRESULT)(LPCSTR)playlistTitle8);
2684+
2685+ case IPC_JUMPTOTIME:
2686+ if(rawPlayStatus == PlayInfo::PLAY_START)
2687+ {
2688+ double jumpPos = wp / 1000.0;
2689+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_JUMPTOTIME")
2690+ _T(" / jump to [%.3f sec.]"), jumpPos);
2691+
2692+ if(jumpPos > rawPlayLength)
2693+ {
2694+ // eof
2695+ return std::make_pair(true, 1);
2696+ }
2697+ else
2698+ {
2699+#if IS_FB2K_VER08
2700+ play_control::get()->playback_seek(jumpPos);
2701+#else IS_FB2K_VER09
2702+ static_api_ptr_t<playback_control>()->playback_seek(jumpPos);
2703+#endif
2704+ return std::make_pair(true, 0);
2705+ }
2706+
2707+ }
2708+ return std::make_pair(true, -1);
2709+
2710+ default:
2711+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - WM_WA_IPC (Unknown IPC command) / W:%08x, L:%08x"), wp, lp);
2712+ break;
2713+ }
2714+ }
2715+ break;
2716+ }
2717+
2718+ return std::make_pair(false, 0);
2719+}
2720+
2721+#if defined(ENABLE_MSN)
2722+class MSNSender
2723+{
2724+ public:
2725+
2726+ static void SendTrackInfo(const TRACK_INFO_UTF8 &info)
2727+ {
2728+ string8 msg;
2729+ msg += "\\0Music\\01\\0{0} - {1} - {2} - {3}\\0";
2730+ msg += info.m_title;
2731+ msg += "\\0";
2732+ msg += info.m_artist;
2733+ msg += "\\0";
2734+ msg += info.m_album;
2735+ msg += "\\0";
2736+ msg += info.m_genre;
2737+ msg += "\\0";
2738+
2739+ console::info(msg);
2740+
2741+ string_wide_from_utf8 tmp(msg);
2742+ SendMessage(tmp);
2743+ }
2744+
2745+ static void SendMessage(LPCWSTR buf)
2746+ {
2747+ COPYDATASTRUCT copydata;
2748+ int nSendBufLen = (::lstrlenW(buf)*2)+2;
2749+
2750+ copydata.dwData = 0x0547;
2751+ copydata.lpData = (void*)buf;
2752+ copydata.cbData = nSendBufLen;
2753+
2754+ HWND hMsnUi = NULL;
2755+ hMsnUi = FindWindowEx(NULL, hMsnUi, _T("MsnMsgrUIManager"), _T("MSN Messenger式再生通知を受信する窓"));
2756+ if ( hMsnUi == NULL )
2757+ {
2758+ ERROR(_T("MSNSender::SendMessage - M2M not found."));
2759+ return ;
2760+ }
2761+
2762+ ::SendMessage(hMsnUi, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&copydata);
2763+ LOG_INFO(_T("MSNSender::SendMessage - send track informations to M2M."));
2764+ }
2765+};
2766+#endif
2767+
2768+#if IS_FB2K_VER08
2769+class play_callback_mixi : public play_callback
2770+#elif IS_FB2K_VER09
2771+class play_callback_mixi : public play_callback_static
2772+#endif
2773+{
2774+#if IS_FB2K_VER09
2775+ virtual unsigned get_flags() {
2776+ return flag_on_playback_all;
2777+ }
2778+#endif
2779+
2780+#if IS_FB2K_VER08
2781+ virtual void on_playback_starting()
2782+#elif IS_FB2K_VER09
2783+ virtual void on_playback_starting(play_control::t_track_command command, bool paused)
2784+#endif
2785+ {
2786+ TRACE_CALLBACK(_T("play_callback_mixi::on_playback_starting - called."));
2787+
2788+ // create my dummyamp window
2789+ DummyAmp::getInstance()->createWindow();
2790+ }
2791+
2792+#if IS_FB2K_VER08
2793+ virtual void on_playback_new_track(metadb_handle * track)
2794+#elif IS_FB2K_VER09
2795+ virtual void on_playback_new_track(metadb_handle_ptr track)
2796+#endif
2797+ {
2798+ TRACE_CALLBACK(_T("play_callback_mixi::on_playback_new_track - called."));
2799+
2800+ if(DummyAmp::getInstance()->isReady() == false)
2801+ {
2802+ LOG_ERROR(_T("play_callback_mixi::on_playback_new_track - mixi station への送信機能はエラーにより無効化されています"));
2803+ LOG_ERROR(_T("play_callback_mixi::on_playback_new_track - エラーの原因を取り除いた上で、foobar2000 を再起動してください"));
2804+ return;
2805+ }
2806+
2807+#if IS_FB2K_VER08
2808+ bool isTrackInLibrary = track->handle_is_permcached() == 1;
2809+#elif IS_FB2K_VER09
2810+ bool isTrackInLibrary = static_api_ptr_t<library_manager>()->is_item_in_library(track);
2811+#endif
2812+ if(cfg_media_library_registered_file_only == 1)
2813+ {
2814+ if(isTrackInLibrary)
2815+ {
2816+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_new_track - new track found on media library."));
2817+ }
2818+ else
2819+ {
2820+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_new_track - new track NOT IN media library."));
2821+ }
2822+ }
2823+
2824+ // get currently playbacked track informations
2825+ string8 winamp_title_utf8;
2826+ string8 playlist_title_utf8;
2827+
2828+ // make currently playbacked track information keys
2829+ Strings strKeys;
2830+
2831+ strKeys.push_back(FORMAT_FILEPATH);
2832+ strKeys.push_back(FORMAT_FILEPATHRAW);
2833+ strKeys.push_back(FORMAT_ARTIST);
2834+ strKeys.push_back(FORMAT_TRACKTITLE);
2835+ strKeys.push_back(FORMAT_ALBUMTITLE);
2836+ strKeys.push_back(FORMAT_GENRE);
2837+ strKeys.push_back(FORMAT_CODEC);
2838+
2839+ // set current track informations
2840+ TrackInfo &trackInfo(DummyAmp::getInstance()->getMutableTrackInfo());
2841+ trackInfo.clear();
2842+ trackInfo.setStrings(strKeys, track);
2843+
2844+ // set trackinfo to dummyAmp
2845+ //DummyAmp::getInstance()->setTrackInfo(trackInfo);
2846+
2847+ // set dynamic flag
2848+ setDynamic(trackInfo.getString(FORMAT_FILEPATHRAW));
2849+
2850+ if(isDynamic())
2851+ {
2852+ setFirstDynamicCallback(true);
2853+
2854+ // set song total length
2855+ m_song_total_sec = pfc_string_to_float(cfg_send_interval3) / pfc_string_to_float(cfg_send_interval2) * 100.0;
2856+ }
2857+ else
2858+ {
2859+#if defined(CONTROL_SEND_TIMING)
2860+ // reset send timing
2861+ resetSendTiming();
2862+#endif
2863+
2864+#if IS_FB2K_VER08
2865+ // get song total length
2866+ m_song_total_sec = track->handle_get_length();
2867+
2868+ // get formatted dummyamp title
2869+ track->handle_format_title(winamp_title_utf8, cfg_dummyamp_title_format, 0);
2870+
2871+ // get formatted playlist title
2872+ track->handle_format_title(playlist_title_utf8, cfg_dummyamp_playlist_format, 0);
2873+
2874+#elif IS_FB2K_VER09
2875+ // get song total length
2876+ m_song_total_sec = track->get_length();
2877+
2878+ service_ptr_t<titleformat_object> titleformat;
2879+
2880+ // get formatted dummyamp title
2881+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, cfg_dummyamp_title_format);
2882+ track->format_title(NULL, winamp_title_utf8, titleformat, 0);
2883+
2884+ // get formatted playlist title
2885+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, cfg_dummyamp_playlist_format);
2886+ track->format_title(NULL, playlist_title_utf8, titleformat, 0);
2887+
2888+#endif
2889+ string_os_from_utf8 winamp_title(winamp_title_utf8);
2890+ string_os_from_utf8 playlist_title(playlist_title_utf8);
2891+
2892+ // set base winamp title to dummyamp
2893+ DummyAmp::getInstance()->setBaseWinampTitle(winamp_title);
2894+
2895+ // set winamp playlist current item title to dummyamp
2896+ DummyAmp::getInstance()->setPlaylistTitle(playlist_title);
2897+
2898+ // clear raw playinfo on dummyamp (no resent mode)
2899+ DummyAmp::getInstance()->getRawPlayInfo().clearPlayInfo(false);
2900+
2901+ // set playinfo raw mp3 file path to dummyAmp
2902+ DummyAmp::getInstance()->getRawPlayInfo().setPlayInfoMp3Path(trackInfo.getString(FORMAT_FILEPATH).c_str());
2903+
2904+ // set dummyamp raw status PLAY_START
2905+ DummyAmp::getInstance()->getRawPlayInfo().setPlayStatusStart();
2906+
2907+ // set raw song total length
2908+ DummyAmp::getInstance()->getRawPlayInfo().setPlayLength(static_cast<int>(m_song_total_sec));
2909+
2910+ // increment play counter
2911+ DummyAmp::getInstance()->getRawPlayInfo().incrementPlayCount();
2912+
2913+ // clear playinfo on dummyamp
2914+ DummyAmp::getInstance()->getPlayInfo().clearPlayInfo();
2915+
2916+ // set song total length
2917+ DummyAmp::getInstance()->getPlayInfo().setPlayLength(static_cast<int>(m_song_total_sec));
2918+
2919+ // increment play counter on dummyamp
2920+ DummyAmp::getInstance()->getPlayInfo().incrementPlayCount();
2921+ }
2922+
2923+ if(isDynamic())
2924+ {
2925+ // post IPC_INTERNAL_REFRESHLISTINFO
2926+ ::PostMessage(DummyAmp::getInstance()->getWnd(), WM_WA_IPC, 0, IPC_INTERNAL_REFRESHLISTINFO);
2927+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_new_track - IPC_INTERNAL_REFRESHLISTINFO posted."));
2928+ }
2929+ else
2930+ {
2931+ bool bSkip = false;
2932+
2933+ string8 title_utf8 = trackInfo.getString(FORMAT_TRACKTITLE).c_str();
2934+ string8 artist_utf8 = trackInfo.getString(FORMAT_ARTIST).c_str();
2935+ string8 album_utf8 = trackInfo.getString(FORMAT_ALBUMTITLE).c_str();
2936+ string8 genre_utf8 = trackInfo.getString(FORMAT_GENRE).c_str();
2937+
2938+ // when media library only mode and track not found on media library,
2939+ // then skip sending track informations
2940+ if((cfg_media_library_registered_file_only == 1) && (isTrackInLibrary == false))
2941+ {
2942+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_new_track - SKIP this track. (not in media library)"));
2943+ bSkip = true;
2944+ }
2945+
2946+ // when explicitly tagged file only mode and artist or track name not found,
2947+ // then skip sending track informations
2948+ if( (cfg_explicitly_tagged_file_only == 1) && (!lstrcmpA(title_utf8, "?") || !lstrcmpA(artist_utf8, "?")) )
2949+ {
2950+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_new_track - SKIP this track. (artist or title not found)"));
2951+ bSkip = true;
2952+ }
2953+
2954+ if(!lstrcmpA(title_utf8, "?"))
2955+ {
2956+ trackInfo.removeString(FORMAT_TRACKTITLE);
2957+ trackInfo.putString(FORMAT_TRACKTITLE, (LPCSTR)cfg_no_title_name);
2958+ }
2959+
2960+ if(!lstrcmpA(artist_utf8, "?"))
2961+ {
2962+ trackInfo.removeString(FORMAT_ARTIST);
2963+ trackInfo.putString(FORMAT_ARTIST, (LPCSTR)cfg_no_artist_name);
2964+ }
2965+
2966+ if(!lstrcmpA(album_utf8, "?"))
2967+ {
2968+ trackInfo.removeString(FORMAT_ALBUMTITLE);
2969+ trackInfo.putString(FORMAT_ALBUMTITLE, (LPCSTR)cfg_no_album_name);
2970+ }
2971+
2972+ if(!lstrcmpA(genre_utf8, "?"))
2973+ {
2974+ trackInfo.removeString(FORMAT_GENRE);
2975+ trackInfo.putString(FORMAT_GENRE, (LPCSTR)cfg_no_genre_name);
2976+ }
2977+
2978+ // refresh dummy amp informations when skip flag not set
2979+ if(!bSkip) {
2980+ DummyAmp::getInstance()->refreshAmpInfo();
2981+
2982+ // post IPC_INTERNAL_REFRESHLISTINFO
2983+ ::PostMessage(DummyAmp::getInstance()->getWnd(), WM_WA_IPC, 0, IPC_INTERNAL_REFRESHLISTINFO);
2984+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_new_track - IPC_INTERNAL_REFRESHLISTINFO posted."));
2985+ }
2986+ }
2987+ }
2988+
2989+#if IS_FB2K_VER08
2990+ virtual void on_playback_stop(play_control::stop_reason reason)
2991+#elif IS_FB2K_VER09
2992+ virtual void on_playback_stop(play_control::t_stop_reason reason)
2993+#endif
2994+ {
2995+ TRACE_CALLBACK(_T("play_callback_mixi::on_playback_stop - called."));
2996+
2997+ // set dummyamp status PLAY_STOP
2998+ DummyAmp::getInstance()->getPlayInfo().setPlayStatusStop();
2999+
3000+ // set dummyamp raw status PLAY_STOP
3001+ DummyAmp::getInstance()->getRawPlayInfo().setPlayStatusStop();
3002+
3003+ // clear dummyamp title
3004+ DummyAmp::getInstance()->clearDummyAmpTitle();
3005+ }
3006+
3007+ virtual void on_playback_seek(double time) // time is second.
3008+ {
3009+ TRACE_CALLBACK(_T("play_callback_mixi::on_playback_seek - called."));
3010+
3011+#if !defined(CONTROL_SEND_TIMING)
3012+ // update current position on dummyamp
3013+ DummyAmp::getInstance()->getPlayInfo().setPlayPosition((int)(time * 1000));
3014+#else
3015+ // update raw current position on dummyamp
3016+ DummyAmp::getInstance()->getRawPlayInfo().setPlayPosition((int)(time * 1000));
3017+
3018+ // reset send timing
3019+ resetSendTiming();
3020+#endif
3021+ }
3022+
3023+#if IS_FB2K_VER08
3024+ virtual void on_playback_pause(int state)
3025+#elif IS_FB2K_VER09
3026+ virtual void on_playback_pause(bool state)
3027+#endif
3028+ {
3029+ TRACE_CALLBACK(_T("play_callback_mixi::on_playback_pause - called."));
3030+
3031+#if IS_FB2K_VER08
3032+ if(state == 1)
3033+#elif IS_FB2K_VER09
3034+ if(state == true)
3035+#endif
3036+ {
3037+ // set dummyamp status PLAY_PAUSE
3038+ DummyAmp::getInstance()->getPlayInfo().setPlayStatusPause();
3039+
3040+ // set dummyamp raw status PLAY_PAUSE
3041+ DummyAmp::getInstance()->getRawPlayInfo().setPlayStatusPause();
3042+
3043+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_pause - fb2k paused."));
3044+ }
3045+ else
3046+ {
3047+#if !defined(CONTROL_SEND_TIMING)
3048+ // set dummyamp status PLAY_START
3049+ DummyAmp::getInstance()->getPlayInfo().setPlayStatusStart();
3050+#else
3051+ // set dummyamp status PLAY_STOP
3052+ DummyAmp::getInstance()->getPlayInfo().setPlayStatusStop();
3053+#endif
3054+
3055+ // set dummyamp rawa status PLAY_START
3056+ DummyAmp::getInstance()->getRawPlayInfo().setPlayStatusStart();
3057+
3058+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_pause - fb2k unpaused."));
3059+ }
3060+ }
3061+
3062+#if IS_FB2K_VER08
3063+ virtual void on_playback_edited(metadb_handle * track){}//currently played file got edited
3064+#elif IS_FB2K_VER09
3065+ virtual void on_playback_edited(metadb_handle_ptr track){}//currently played file got edited
3066+#endif
3067+
3068+#if IS_FB2K_VER08
3069+ virtual void on_playback_dynamic_info(const file_info * info,bool b_track_change)
3070+#elif IS_FB2K_VER09
3071+ virtual void on_playback_dynamic_info(const file_info & info)
3072+#endif
3073+ {
3074+#if IS_FB2K_VER08
3075+ TRACE_CALLBACK(_T("play_callback_mixi::on_playback_dynamic_info - called."));
3076+
3077+ if(isDynamic() && b_track_change)
3078+ {
3079+ refreshDynamicInfo();
3080+ }
3081+#endif
3082+ }
3083+
3084+#if IS_FB2K_VER09
3085+ virtual void on_playback_dynamic_info_track(const file_info & p_info) {
3086+
3087+ TRACE_CALLBACK(_T("play_callback_mixi::on_playback_dynamic_info_track - called."));
3088+
3089+ if(isDynamic())
3090+ {
3091+ refreshDynamicInfo();
3092+ }
3093+ };
3094+#endif
3095+
3096+#if IS_FB2K_VER08
3097+ virtual void on_playback_time(metadb_handle * track, double time)//called every second
3098+#elif IS_FB2K_VER09
3099+ virtual void on_playback_time(double time)//called every second
3100+#endif
3101+ {
3102+ TRACE_CALLBACK(_T("play_callback_mixi::on_playback_time - called."));
3103+
3104+ // update current raw position on dummyamp
3105+ DummyAmp::getInstance()->getRawPlayInfo().setPlayPosition((int)(time * 1000));
3106+
3107+ if(DummyAmp::getInstance()->getPlayInfo().isPlayInfoMp3Available() == true)
3108+ {
3109+#if !defined(CONTROL_SEND_TIMING)
3110+ // update current position on dummyamp
3111+ DummyAmp::getInstance()->getPlayInfo().setPlayPosition((int)(time * 1000));
3112+#else
3113+#if !defined(ENABLE_MSN)
3114+ if(m_bPassThesholdTime == true) {
3115+ // update current position on dummyamp
3116+ DummyAmp::getInstance()->getPlayInfo().setPlayPosition((int)(time * 1000));
3117+ }
3118+#endif
3119+ if(checkSendTiming(time) == true)
3120+ {
3121+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_time - send track informations ..."));
3122+
3123+#if !defined(ENABLE_MSN)
3124+ //dummyamp resent mode
3125+ DummyAmp::getInstance()->getPlayInfo().setPlayPosition((int)(time * 1000));
3126+ DummyAmp::getInstance()->getPlayInfo().setResentMode(false);
3127+
3128+// // update dummyamp title
3129+// DummyAmp::getInstance()->updateDummyAmpTitle();
3130+
3131+ // set dummyamp status PLAY_START
3132+ DummyAmp::getInstance()->getPlayInfo().setPlayStatusStart();
3133+#else
3134+ // send track informations to M2M
3135+ MSNSender::SendTrackInfo(m_trackInfoUtf8);
3136+#endif
3137+ }
3138+#endif
3139+ }
3140+ }
3141+
3142+protected:
3143+
3144+#if defined(CONTROL_SEND_TIMING)
3145+ void resetSendTiming()
3146+ {
3147+ TRACE_CALLBACK(_T("play_callback_mixi::resetSendTiming - called."));
3148+
3149+ m_previous_sec = -1.0;
3150+ m_bPassThesholdTime = false;
3151+ }
3152+
3153+ bool checkSendTiming(double sec)
3154+ {
3155+ TRACE_CALLBACK(_T("play_callback_mixi::checkSendTiming - called."));
3156+
3157+ double lowerBoundTime = pfc_string_to_float(cfg_send_interval1);
3158+
3159+ // target track required minimum threshold seconds
3160+ if(m_song_total_sec < lowerBoundTime) return false;
3161+
3162+ // already passed threshold seconds
3163+ if(m_bPassThesholdTime == true) return false;
3164+
3165+ // set base position for elapsed seconds
3166+ if(m_previous_sec < 0.0) {
3167+ m_previous_sec = sec - 1.0;
3168+ }
3169+
3170+ double elapsedTime = sec - m_previous_sec;
3171+
3172+ double thresholdTime1 = m_song_total_sec * pfc_string_to_float(cfg_send_interval2) / 100.0;
3173+ double thresholdTime2 = pfc_string_to_float(cfg_send_interval3);
3174+ double thresholdTime = min(thresholdTime1, thresholdTime2) - GEN_MIXI_TRIGGER_SECONDS;
3175+
3176+ if(m_bPassThesholdTime == false)
3177+ {
3178+ TRACE_CALLBACK(_T("play_callback_mixi::checkSendTiming - pos: %5.1f, threshold:%5.1f, elapse:%5.1f"),
3179+ sec, thresholdTime, elapsedTime);
3180+
3181+ if(thresholdTime <= elapsedTime + GEN_MIXI_MARGIN_SECONDS) // add gen_mixi response time
3182+ {
3183+ m_bPassThesholdTime = true;
3184+ return true;
3185+ }
3186+ }
3187+
3188+ return false;
3189+ }
3190+#endif
3191+
3192+ void refreshDynamicInfo()
3193+ {
3194+ if(cfg_enable_streaming_file == 0)
3195+ {
3196+ DEBUG_CALLBACK(_T("play_callback_mixi::refreshDynamicInfo - SKIP this track. (ストリーミング情報の送信が許可されていません)"));
3197+ setFirstDynamicCallback(false);
3198+ return ;
3199+ }
3200+
3201+ if(cfg_disable_dummy_mp3 == 1)
3202+ {
3203+ DEBUG_CALLBACK(_T("play_callback_mixi::refreshDynamicInfo - SKIP this track. (ストリーミング情報を送信するには、ダミーMP3ファイルが有効にしてください)"));
3204+ setFirstDynamicCallback(false);
3205+ return ;
3206+ }
3207+
3208+#if defined(CONTROL_SEND_TIMING)
3209+ // reset send timing
3210+ resetSendTiming();
3211+#endif
3212+
3213+ // clear raw playinfo on dummyamp (no resent mode)
3214+ DummyAmp::getInstance()->getRawPlayInfo().clearPlayInfo(false);
3215+
3216+ // set playinfo raw mp3 file path to dummyAmp
3217+ DummyAmp::getInstance()->getRawPlayInfo().setPlayInfoMp3Path(DummyAmp::getInstance()->getTrackInfo().getString(FORMAT_FILEPATH).c_str());
3218+
3219+ // set dummyamp raw status PLAY_START
3220+ DummyAmp::getInstance()->getRawPlayInfo().setPlayStatusStart();
3221+
3222+ // set raw song total length
3223+ DummyAmp::getInstance()->getRawPlayInfo().setPlayLength(static_cast<int>(m_song_total_sec));
3224+
3225+ // increment play counter
3226+ DummyAmp::getInstance()->getRawPlayInfo().incrementPlayCount();
3227+
3228+ // clear playinfo on dummyamp
3229+ DummyAmp::getInstance()->getPlayInfo().clearPlayInfo();
3230+
3231+ // set song total length
3232+ DummyAmp::getInstance()->getPlayInfo().setPlayLength(static_cast<int>(m_song_total_sec));
3233+
3234+ // increment play counter on dummyamp
3235+ DummyAmp::getInstance()->getPlayInfo().incrementPlayCount();
3236+
3237+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_dynamic_info_track - IPC_INTERNAL_REFRESHDYNINFO posted."));
3238+ ::PostMessage(DummyAmp::getInstance()->getWnd(), WM_WA_IPC, 0, IPC_INTERNAL_REFRESHDYNINFO);
3239+ setFirstDynamicCallback(false);
3240+ }
3241+
3242+#if IS_FB2K_VER09
3243+ // User changed volume settings. Possibly called when not playing.
3244+ virtual void on_volume_change(float new_val) {}
3245+#endif
3246+
3247+ void setFirstDynamicCallback(bool isFirst) {
3248+ m_isFirstDynamicCallback = isFirst;
3249+ }
3250+
3251+ bool isFirstDynamicCallback() const {
3252+ return m_isFirstDynamicCallback;
3253+ }
3254+
3255+ void setDynamic(const std::string &rawFilePath)
3256+ {
3257+ bool isFileProtocol = rawFilePath.find("file://") != std::string::npos;
3258+ bool isCddaProtocol = rawFilePath.find("cdda://") != std::string::npos;
3259+ bool isDriveName = false;
3260+
3261+ if(rawFilePath.length() >= 3) {
3262+ LPCSTR pRawFilePath = rawFilePath.c_str();
3263+ isDriveName = ::isalpha(pRawFilePath[0]) && (pRawFilePath[1] == ':') && (pRawFilePath[2] == '\\');
3264+ }
3265+
3266+ m_isDynamic = !(isFileProtocol || isCddaProtocol || isDriveName);
3267+ }
3268+
3269+ bool isDynamic() const {
3270+ return m_isDynamic;
3271+ }
3272+
3273+protected:
3274+
3275+// TrackInfo m_trackInfo;
3276+
3277+ double m_previous_sec;
3278+ double m_song_total_sec;
3279+
3280+ bool m_bPassThesholdTime;
3281+
3282+ bool m_isDynamic;
3283+ bool m_isFirstDynamicCallback;
3284+};
3285+
3286+
3287+class initquit_mixi : public initquit
3288+{
3289+ typedef std::auto_ptr<DummyAmp> DummyAmpAutoPtr;
3290+ DummyAmpAutoPtr m_apDummyAmp;
3291+
3292+ virtual void on_init()
3293+ {
3294+ m_apDummyAmp = DummyAmpAutoPtr(DummyAmp::getInstance());
3295+ m_apDummyAmp->load();
3296+ }
3297+
3298+ virtual void on_quit()
3299+ {
3300+ m_apDummyAmp->release();
3301+ {
3302+ DummyAmpAutoPtr sink(m_apDummyAmp);
3303+ }
3304+ }
3305+
3306+ virtual void on_system_shutdown()
3307+ {
3308+ on_quit();
3309+ }
3310+};
3311+
3312+#if IS_FB2K_VER08
3313+class menu_item_mixi : public menu_item_main
3314+#elif IS_FB2K_VER09
3315+// {E8BF1F91-9262-4c0b-AD39-00C0B24B4210}
3316+static const GUID menu_item_mixi_guid = { 0xe8bf1f91, 0x9262, 0x4c0b, { 0xad, 0x39, 0x0, 0xc0, 0xb2, 0x4b, 0x42, 0x10 } };
3317+class menu_item_mixi : public mainmenu_commands
3318+#endif
3319+{
3320+#if IS_FB2K_VER08
3321+ virtual unsigned get_num_items() {
3322+#elif IS_FB2K_VER09
3323+ virtual t_uint32 get_command_count() {
3324+#endif
3325+ return 1;
3326+ }
3327+
3328+#if IS_FB2K_VER08
3329+ virtual void enum_item(unsigned n, string_base & out) {
3330+ out = (n==0 ? g_menu_item : "");
3331+ }
3332+#elif IS_FB2K_VER09
3333+ virtual GUID get_command(t_uint32 p_index)
3334+ {
3335+ if (p_index == 0) {
3336+ return menu_item_mixi_guid;
3337+ }
3338+
3339+ return pfc::guid_null;
3340+ }
3341+
3342+ virtual void get_name(t_uint32 p_index, string_base & p_out)
3343+ {
3344+ if (p_index == 0)
3345+ {
3346+ p_out = g_menu_item_title;
3347+ }
3348+ }
3349+
3350+ virtual bool get_description(t_uint32 p_index, string_base & p_out)
3351+ {
3352+ if (p_index == 0)
3353+ {
3354+ p_out = g_menu_item_description;
3355+ }
3356+ else
3357+ {
3358+ return false;
3359+ }
3360+
3361+ return true;
3362+ }
3363+
3364+ virtual GUID get_parent() {
3365+ return mainmenu_groups::playback_etc;
3366+ }
3367+
3368+#endif
3369+
3370+#if IS_FB2K_VER08
3371+ virtual bool is_checked(int index)
3372+ {
3373+ bool flags = false;
3374+ static const bool flag_checked = TRUE;
3375+#elif IS_FB2K_VER09
3376+ virtual bool get_display(t_uint32 index, pfc::string_base & text, t_uint32 & flags)
3377+ {
3378+ flags = 0;
3379+#endif
3380+ switch (index)
3381+ {
3382+ case 0:
3383+ if (cfg_use_plugin == 1) flags = flag_checked;
3384+ break;
3385+ }
3386+
3387+#if IS_FB2K_VER08
3388+ return flags;
3389+#elif IS_FB2K_VER09
3390+ get_name(index, text);
3391+ return true;
3392+#endif
3393+ }
3394+
3395+#if IS_FB2K_VER08
3396+ virtual void perform_command(unsigned index)
3397+ {
3398+#elif IS_FB2K_VER09
3399+ virtual void execute(t_uint32 index, service_ptr_t<service_base> /* reserved for future use */)
3400+ {
3401+#endif
3402+ if ((index == 0) && core_api::assert_main_thread())
3403+ {
3404+ cfg_use_plugin = 1 - cfg_use_plugin;
3405+
3406+ if(cfg_use_plugin > 1)
3407+ {
3408+ cfg_use_plugin = 1;
3409+ }
3410+ else if(cfg_use_plugin < 0)
3411+ {
3412+ cfg_use_plugin = 0;
3413+ }
3414+
3415+ if (cfg_use_plugin == 1)
3416+ {
3417+ DEBUG_PLUGIN(_T("menu_item_mixi::execute - mixiミュージック連携を有効にしました"));
3418+ }
3419+ else
3420+ {
3421+ DEBUG_PLUGIN(_T("menu_item_mixi::execute - mixiミュージック連携を無効にしました"));
3422+ }
3423+ }
3424+ }
3425+};
3426+
3427+#define CLEARTYPE_QUALITY 5
3428+
3429+#if IS_FB2K_VER08
3430+class config_page_mixi : public config
3431+#elif IS_FB2K_VER09
3432+// {976D6C46-31E4-4ab4-8BFF-5FB2E9BFD599}
3433+static const GUID config_page_mixi_guid = { 0x976d6c46, 0x31e4, 0x4ab4, { 0x8b, 0xff, 0x5f, 0xb2, 0xe9, 0xbf, 0xd5, 0x99 } };
3434+class config_page_mixi : public preferences_page
3435+#endif
3436+{
3437+ static HFONT hIntervalFont;
3438+
3439+ static BOOL CALLBACK ConfigProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
3440+ {
3441+ HWND hSendInterval1 = uGetDlgItem(wnd, IDC_SEND_INTERVAL_SLIDER_1ST);
3442+ HWND hSendInterval2 = uGetDlgItem(wnd, IDC_SEND_INTERVAL_SLIDER_2ND);
3443+ HWND hSendInterval3 = uGetDlgItem(wnd, IDC_SEND_INTERVAL_SLIDER_3RD);
3444+
3445+ HWND hSendInterval1Text = uGetDlgItem(wnd, IDC_SEND_INTERVAL_1ST);
3446+ HWND hSendInterval2Text = uGetDlgItem(wnd, IDC_SEND_INTERVAL_2ND);
3447+ HWND hSendInterval3Text = uGetDlgItem(wnd, IDC_SEND_INTERVAL_3RD);
3448+
3449+ switch(msg)
3450+ {
3451+ case WM_INITDIALOG:
3452+ {
3453+ HDC hWndDC = ::GetWindowDC(wnd);
3454+ hIntervalFont = ::CreateFont(
3455+ -MulDiv(20, GetDeviceCaps(hWndDC, LOGPIXELSY), 72), 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
3456+ ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, FIXED_PITCH, _T("Arial")
3457+ );
3458+ ::ReleaseDC(wnd, hWndDC);
3459+
3460+ uSendMessage(hSendInterval1Text, WM_SETFONT, (WPARAM)hIntervalFont, (LPARAM)FALSE);
3461+ uSendMessage(hSendInterval2Text, WM_SETFONT, (WPARAM)hIntervalFont, (LPARAM)FALSE);
3462+ uSendMessage(hSendInterval3Text, WM_SETFONT, (WPARAM)hIntervalFont, (LPARAM)FALSE);
3463+
3464+ uButton_SetCheck(wnd, IDC_USE_PLUGIN, (cfg_use_plugin == 1) ? true : false);
3465+
3466+ uButton_SetCheck(wnd, IDC_DISABLE_DUPLICATE_SONG, (cfg_disable_duplicate_song == 1) ? true : false);
3467+ uButton_SetCheck(wnd, IDC_DISABLE_DUMMY_MP3, (cfg_disable_dummy_mp3 == 1) ? true : false);
3468+ uButton_SetCheck(wnd, IDC_MEDIA_LIBRARY_REGISTERED_FILE_ONLY, (cfg_media_library_registered_file_only == 1) ? true : false);
3469+ uButton_SetCheck(wnd, IDC_EXPLICITLY_TAGGED_FILE_ONLY, (cfg_explicitly_tagged_file_only == 1) ? true : false);
3470+
3471+ uSetDlgItemText(wnd, IDC_NO_ARTIST_NAME, cfg_no_artist_name);
3472+ uSetDlgItemText(wnd, IDC_NO_TITLE_NAME, cfg_no_title_name);
3473+ uSetDlgItemText(wnd, IDC_NO_ALBUM_NAME, cfg_no_album_name);
3474+ uSetDlgItemText(wnd, IDC_NO_GENRE_NAME, cfg_no_genre_name);
3475+
3476+ EnableNoNames(wnd, (cfg_explicitly_tagged_file_only == 0) ? true : false);
3477+
3478+ uButton_SetCheck(wnd, IDC_ENABLE_STREAMING_FILE, (cfg_enable_streaming_file == 1) ? true : false);
3479+
3480+ uSetDlgItemText(wnd, IDC_SEND_INTERVAL_1ST, cfg_send_interval1);
3481+ uSetDlgItemText(wnd, IDC_SEND_INTERVAL_2ND, cfg_send_interval2);
3482+ uSetDlgItemText(wnd, IDC_SEND_INTERVAL_3RD, cfg_send_interval3);
3483+
3484+ uSendMessage(hSendInterval1, TBM_SETRANGE, (WPARAM)FALSE, (LPARAM)MAKELONG(REQUIRED_MINIMUM_TIME, 300));
3485+ uSendMessage(hSendInterval1, TBM_SETLINESIZE, (WPARAM)0, (LPARAM)1);
3486+ uSendMessage(hSendInterval1, TBM_SETPAGESIZE, (WPARAM)0, (LPARAM)20);
3487+ uSendMessage(hSendInterval1, TBM_SETTICFREQ, (WPARAM)20, (LPARAM)0);
3488+
3489+ double pos1 = pfc_string_to_float(cfg_send_interval1);
3490+ uSendMessage(hSendInterval1, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos1);
3491+
3492+ uSendMessage(hSendInterval2, TBM_SETRANGE, (WPARAM)FALSE, (LPARAM)MAKELONG(SEND_TIME_RATE_LOWERBOUND, 100));
3493+ uSendMessage(hSendInterval2, TBM_SETLINESIZE, (WPARAM)0, (LPARAM)1);
3494+ uSendMessage(hSendInterval2, TBM_SETPAGESIZE, (WPARAM)0, (LPARAM)5);
3495+ uSendMessage(hSendInterval2, TBM_SETTICFREQ, (WPARAM)10, (LPARAM)0);
3496+
3497+ double pos2 = pfc_string_to_float(cfg_send_interval2);
3498+ uSendMessage(hSendInterval2, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos2);
3499+
3500+ uSendMessage(hSendInterval3, TBM_SETRANGE, (WPARAM)FALSE, (LPARAM)MAKELONG(REQUIRED_MAXIMUM_TIME / 60, 165));
3501+ uSendMessage(hSendInterval3, TBM_SETLINESIZE, (WPARAM)0, (LPARAM)1);
3502+ uSendMessage(hSendInterval3, TBM_SETPAGESIZE, (WPARAM)0, (LPARAM)5);
3503+ uSendMessage(hSendInterval3, TBM_SETTICFREQ, (WPARAM)20, (LPARAM)0);
3504+
3505+ double pos3 = pfc_string_to_float(cfg_send_interval3);
3506+ uSendMessage(hSendInterval3, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos3 / 60);
3507+
3508+ setDlgVersionInfo(wnd, IDC_VERSION, IDC_BUILD);
3509+ }
3510+ break;
3511+
3512+ case WM_COMMAND:
3513+ switch(wp)
3514+ {
3515+ case (BN_CLICKED<<16)|IDC_USE_PLUGIN:
3516+ cfg_use_plugin = uButton_GetCheck(wnd, IDC_USE_PLUGIN) ? 1 : 0;
3517+ break;
3518+
3519+ case (EN_UPDATE<<16)|IDC_NO_ARTIST_NAME:
3520+ {
3521+ string8 name;
3522+ uGetWindowText(reinterpret_cast<HWND>(lp), name);
3523+ cfg_no_artist_name = name;
3524+ }
3525+ break;
3526+
3527+ case (EN_UPDATE<<16)|IDC_NO_TITLE_NAME:
3528+ {
3529+ string8 name;
3530+ uGetWindowText(reinterpret_cast<HWND>(lp), name);
3531+ cfg_no_title_name = name;
3532+ }
3533+ break;
3534+
3535+ case (EN_UPDATE<<16)|IDC_NO_ALBUM_NAME:
3536+ {
3537+ string8 name;
3538+ uGetWindowText(reinterpret_cast<HWND>(lp), name);
3539+ cfg_no_album_name = name;
3540+ }
3541+ break;
3542+
3543+ case (EN_UPDATE<<16)|IDC_NO_GENRE_NAME:
3544+ {
3545+ string8 name;
3546+ uGetWindowText(reinterpret_cast<HWND>(lp), name);
3547+ cfg_no_genre_name = name;
3548+ }
3549+ break;
3550+
3551+ case (BN_CLICKED<<16)|IDC_DISABLE_DUPLICATE_SONG:
3552+ cfg_disable_duplicate_song = uButton_GetCheck(wnd, IDC_DISABLE_DUPLICATE_SONG) ? 1 : 0;
3553+ break;
3554+
3555+ case (BN_CLICKED<<16)|IDC_DISABLE_DUMMY_MP3:
3556+ cfg_disable_dummy_mp3 = uButton_GetCheck(wnd, IDC_DISABLE_DUMMY_MP3) ? 1 : 0;
3557+ break;
3558+
3559+ case (BN_CLICKED<<16)|IDC_MEDIA_LIBRARY_REGISTERED_FILE_ONLY:
3560+ cfg_media_library_registered_file_only = uButton_GetCheck(wnd, IDC_MEDIA_LIBRARY_REGISTERED_FILE_ONLY) ? 1 : 0;
3561+ break;
3562+
3563+ case (BN_CLICKED<<16)|IDC_EXPLICITLY_TAGGED_FILE_ONLY:
3564+ cfg_explicitly_tagged_file_only = uButton_GetCheck(wnd, IDC_EXPLICITLY_TAGGED_FILE_ONLY) ? 1 : 0;
3565+ EnableNoNames(wnd, (cfg_explicitly_tagged_file_only == 0) ? true : false);
3566+ break;
3567+
3568+ case (BN_CLICKED<<16)|IDC_ENABLE_STREAMING_FILE:
3569+ cfg_enable_streaming_file = uButton_GetCheck(wnd, IDC_ENABLE_STREAMING_FILE) ? 1 : 0;
3570+ break;
3571+
3572+ case (BN_CLICKED<<16)|IDC_CONFIGURE:
3573+ DummyAmp::getInstance()->config();
3574+ break;
3575+ }
3576+ break;
3577+
3578+ case WM_HSCROLL:
3579+ {
3580+ HWND hTrackBar = (HWND)lp;
3581+
3582+ if((hTrackBar == hSendInterval1)
3583+ || (hTrackBar == hSendInterval2)
3584+ || (hTrackBar == hSendInterval3))
3585+ {
3586+ switch(LOWORD(wp))
3587+ {
3588+ case TB_THUMBPOSITION:
3589+ case TB_THUMBTRACK:
3590+ case TB_TOP:
3591+ case TB_BOTTOM:
3592+ case TB_PAGEUP:
3593+ case TB_PAGEDOWN:
3594+ case TB_LINEUP:
3595+ case TB_LINEDOWN:
3596+ case TB_ENDTRACK:
3597+ {
3598+ LRESULT lPos = 0;
3599+
3600+ switch(LOWORD(wp))
3601+ {
3602+ case TB_THUMBPOSITION:
3603+ case TB_THUMBTRACK:
3604+ lPos = HIWORD(wp);
3605+ break;
3606+ default:
3607+ lPos = uSendMessage(hTrackBar, TBM_GETPOS, 0, 0);
3608+ break;
3609+ }
3610+
3611+ uSendMessage(hTrackBar, TBM_SETPOS, (WPARAM)TRUE, lPos);
3612+
3613+ if(hTrackBar == hSendInterval1)
3614+ {
3615+ setDlgItemFloat(wnd, IDC_SEND_INTERVAL_1ST, (double)lPos);
3616+ string8 pos;
3617+ float2String(pos, (double)lPos);
3618+ cfg_send_interval1 = pos;
3619+ }
3620+ else if(hTrackBar == hSendInterval2)
3621+ {
3622+ setDlgItemFloat(wnd, IDC_SEND_INTERVAL_2ND, (double)lPos);
3623+ string8 pos;
3624+ float2String(pos, (double)lPos);
3625+ cfg_send_interval2 = pos;
3626+ }
3627+ else if(hTrackBar == hSendInterval3)
3628+ {
3629+ setDlgItemFloat(wnd, IDC_SEND_INTERVAL_3RD, (double)lPos * 60);
3630+ string8 pos;
3631+ float2String(pos, (double)lPos * 60);
3632+ cfg_send_interval3 = pos;
3633+ }
3634+ }
3635+ break;
3636+
3637+ default:
3638+ break;
3639+ }
3640+ }
3641+ }
3642+ break;
3643+ case WM_DESTROY:
3644+ if(hIntervalFont != INVALID_HANDLE_VALUE) {
3645+ ::DeleteObject(hIntervalFont);
3646+ }
3647+ break;
3648+ }
3649+
3650+ return 0;
3651+ }
3652+
3653+ static void setDlgItemFloat(HWND wnd, UINT id, double val)
3654+ {
3655+ string8 pos;
3656+ float2String(pos, val);
3657+
3658+ uSetDlgItemText(wnd, id, pos);
3659+ }
3660+
3661+ static void float2String(string8 &str, double val)
3662+ {
3663+#if IS_FB2K_VER08
3664+ char *pStr = str.buffer_get(1024);
3665+ pfc_float_to_string(pStr, val, 0);
3666+ str.buffer_done();
3667+#elif IS_FB2K_VER09
3668+ char *pStr = str.lock_buffer(1024);
3669+ float_to_string(pStr, 1024, val, 0);
3670+ str.unlock_buffer();
3671+#endif
3672+ }
3673+
3674+ static void EnableNoNames(HWND wnd, bool bNoNameEnabled) {
3675+ EnableNoName(wnd, IDC_NO_ARTIST_NAME, bNoNameEnabled);
3676+ EnableNoName(wnd, IDC_NO_TITLE_NAME, bNoNameEnabled);
3677+ EnableNoName(wnd, IDC_NO_ALBUM_NAME, bNoNameEnabled);
3678+ EnableNoName(wnd, IDC_NO_GENRE_NAME, bNoNameEnabled);
3679+ }
3680+
3681+ static void EnableNoName(HWND wnd, UINT id, bool bEnable) {
3682+ HWND hControlWnd = uGetDlgItem(wnd, id);
3683+ uEnableWindow(hControlWnd, bEnable);
3684+ }
3685+
3686+public:
3687+ virtual HWND create(HWND parent)
3688+ {
3689+ return uCreateDialog(IDD_PREFERENCE, parent, ConfigProc);
3690+ }
3691+
3692+ virtual const char * get_name() {
3693+ return g_pluginCaption8;
3694+ }
3695+
3696+ virtual const char * get_parent_name() {
3697+ return "Components";
3698+ }
3699+
3700+#if IS_FB2K_VER09
3701+ virtual GUID get_guid() {
3702+ return config_page_mixi_guid;
3703+ }
3704+
3705+ virtual GUID get_parent_guid() {
3706+ return guid_tools;
3707+ }
3708+
3709+ virtual bool reset_query() {
3710+ return true;
3711+ }
3712+
3713+ virtual void reset()
3714+ {
3715+ cfg_use_plugin = 1;
3716+ cfg_disable_duplicate_song = 0;
3717+ cfg_media_library_registered_file_only = 0;
3718+ cfg_send_interval1 = "20";
3719+ cfg_send_interval2 = "66";
3720+ cfg_send_interval3 = "300";
3721+ }
3722+
3723+ virtual bool get_help_url(pfc::string_base & p_out)
3724+ {
3725+ p_out = URL_FOO_MIXI_HOME;
3726+ return true;
3727+ }
3728+#endif
3729+};
3730+
3731+HFONT config_page_mixi::hIntervalFont = (HFONT)INVALID_HANDLE_VALUE;
3732+
3733+#if IS_FB2K_VER08
3734+class config_page_mixi_advanced : public config
3735+#elif IS_FB2K_VER09
3736+// {E01262F2-E6BF-4f3e-B0F2-5B8C08E2C2E3}
3737+static const GUID config_page_mixi_advanced_guid = { 0xe01262f2, 0xe6bf, 0x4f3e, { 0xb0, 0xf2, 0x5b, 0x8c, 0x8, 0xe2, 0xc2, 0xe3 } };
3738+class config_page_mixi_advanced : public preferences_page_v2
3739+#endif
3740+{
3741+ static int nOldDummyMp3Location;
3742+ static string8 oldGenMixiPath;
3743+
3744+ static BOOL CALLBACK ConfigProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
3745+ {
3746+ switch(msg)
3747+ {
3748+ case WM_INITDIALOG:
3749+ {
3750+ uSetDlgItemText(wnd, IDC_CAPTION_ADVANCED, g_advancedSettingsCaption8);
3751+
3752+ uButton_SetCheck(wnd, IDC_DISABLE_DUMMY_MP3, (cfg_disable_dummy_mp3 == 1) ? true : false);
3753+
3754+ uSendDlgItemMessage(wnd, IDC_DUMMY_MP3_LOCATION, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(_T("ダミーMP3ファイルをユーザプロファイルに作成する")));
3755+ uSendDlgItemMessage(wnd, IDC_DUMMY_MP3_LOCATION, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(_T("ダミーMP3ファイルを一時フォルダに作成する")));
3756+ uSendDlgItemMessage(wnd, IDC_DUMMY_MP3_LOCATION, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(_T("ダミーMP3ファイルを Components フォルダに作成する")));
3757+
3758+ uEnableWindow(uGetDlgItem(wnd, IDC_DUMMY_MP3_LOCATION), (cfg_disable_dummy_mp3 == 0) ? true : false);
3759+
3760+ uSendDlgItemMessage(wnd, IDC_DUMMY_MP3_LOCATION, CB_SETCURSEL, (int)cfg_dummy_mp3_location, 0);
3761+ nOldDummyMp3Location = (int)cfg_dummy_mp3_location;
3762+
3763+ uSetDlgItemText(wnd, IDC_GEN_MIXI_PATH, cfg_gen_mixi_path);
3764+ oldGenMixiPath = cfg_gen_mixi_path;
3765+
3766+ Str64K dummyAmpFrameCaptionBuf;
3767+
3768+ _stprintf_s(
3769+ dummyAmpFrameCaptionBuf, sizeof(dummyAmpFrameCaptionBuf) / sizeof(TCHAR),
3770+ DUMMYAMP_FRAME_CAPTION,
3771+ DummyAmp::getInstance()->getWnd() == INVALID_HANDLE_VALUE ? DUMMYAMP_BEFORE_INIT_MODE :
3772+ DummyAmp::getInstance()->isAnotherWinampWindowAvailable() ? DUMMYAMP_HOOK_MODE : DUMMYAMP_STANDALONE_MODE
3773+ );
3774+
3775+ ::SetDlgItemText(wnd, IDC_DUMMYAMP_FRAME, dummyAmpFrameCaptionBuf);
3776+
3777+ uButton_SetCheck(wnd, IDC_SHOW_DUMMYAMP, (cfg_show_dummyamp == 1) ? true : false);
3778+ if(DummyAmp::getInstance()->getWnd() == INVALID_HANDLE_VALUE) {
3779+ HWND hControlWnd = uGetDlgItem(wnd, IDC_SHOW_DUMMYAMP);
3780+ uEnableWindow(hControlWnd, false);
3781+ }
3782+
3783+ uSetDlgItemText(wnd, IDC_DUMMYAMP_TITLE_FORMAT, cfg_dummyamp_title_format);
3784+ uSetDlgItemText(wnd, IDC_DUMMYAMP_PLAYLIST_FORMAT, cfg_dummyamp_playlist_format);
3785+
3786+ uButton_SetCheck(wnd, IDC_DISABLE_ANSI_TRANS, (cfg_disable_ansi_trans == 1) ? true : false);
3787+ uButton_SetCheck(wnd, IDC_ENABLE_EXT_IPC_PROC, (cfg_enable_ext_ipc_proc == 1) ? true : false);
3788+ if(DummyAmp::getInstance()->isAnotherWinampWindowAvailable() == false) {
3789+ HWND hControlWnd = uGetDlgItem(wnd, IDC_ENABLE_EXT_IPC_PROC);
3790+ uEnableWindow(hControlWnd, false);
3791+ }
3792+
3793+ setDlgVersionInfo(wnd, IDC_VERSION_ADVANCED, IDC_BUILD_ADVANCED);
3794+ }
3795+ break;
3796+
3797+ case WM_COMMAND:
3798+ switch(wp)
3799+ {
3800+ case (BN_CLICKED<<16)|IDC_DISABLE_DUMMY_MP3:
3801+ {
3802+ cfg_disable_dummy_mp3 = uButton_GetCheck(wnd, IDC_DISABLE_DUMMY_MP3) ? 1 : 0;
3803+ uEnableWindow(uGetDlgItem(wnd, IDC_DUMMY_MP3_LOCATION), (cfg_disable_dummy_mp3 == 0) ? true : false);
3804+ }
3805+ break;
3806+
3807+ case (CBN_SELCHANGE<<16)|IDC_DUMMY_MP3_LOCATION:
3808+ {
3809+ int sel = static_cast<int>(uSendMessage(reinterpret_cast<HWND>(lp), CB_GETCURSEL, 0, 0));
3810+ cfg_dummy_mp3_location = sel;
3811+ }
3812+ break;
3813+
3814+ case (EN_UPDATE<<16)|IDC_GEN_MIXI_PATH:
3815+ {
3816+ string8 path;
3817+ uGetWindowText(reinterpret_cast<HWND>(lp), path);
3818+ cfg_gen_mixi_path = path;
3819+ }
3820+ break;
3821+
3822+ case (BN_CLICKED<<16)|IDC_GEN_MIXI_PATH_REF:
3823+ {
3824+ string8 path(cfg_gen_mixi_path);
3825+
3826+ OPENFILENAME ofn;
3827+ TCHAR strFile[MAX_PATH];
3828+
3829+ ::ZeroMemory(&ofn, sizeof(OPENFILENAME));
3830+ strFile[0] = _T('\0');
3831+
3832+ ofn.lStructSize = sizeof(OPENFILENAME);
3833+ ofn.hwndOwner = wnd;
3834+ ofn.lpstrFilter = _T("gen_mixi_for_winamp.dll\0gen_mixi_for_winamp.dll\0\0");
3835+ ofn.nFilterIndex = 0;
3836+ ofn.lpstrInitialDir = PathInfo::splitPath(path).c_str();
3837+ ofn.lpstrFile = strFile;
3838+ ofn.nMaxFile = MAX_PATH;
3839+ ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
3840+
3841+ if(::GetOpenFileName(&ofn) == TRUE)
3842+ {
3843+ tstring genMixiPath(PathInfo::splitPath(strFile));
3844+ string_utf8_from_os genMixiPath8(genMixiPath.c_str());
3845+
3846+ cfg_gen_mixi_path = genMixiPath8;
3847+ ::uSetDlgItemText(wnd, IDC_GEN_MIXI_PATH, genMixiPath8);
3848+ }
3849+ }
3850+
3851+ case (BN_CLICKED<<16)|IDC_SHOW_DUMMYAMP:
3852+ {
3853+ bool bShowDummyAmp = uButton_GetCheck(wnd, IDC_SHOW_DUMMYAMP);
3854+ cfg_show_dummyamp = bShowDummyAmp ? 1 : 0;
3855+
3856+ DummyAmp::getInstance()->showDummyAmpWindow(bShowDummyAmp);
3857+ }
3858+ break;
3859+
3860+ case (EN_UPDATE<<16)|IDC_DUMMYAMP_TITLE_FORMAT:
3861+ {
3862+ string8 format;
3863+ uGetWindowText(reinterpret_cast<HWND>(lp), format);
3864+ cfg_dummyamp_title_format = format;
3865+ }
3866+ break;
3867+
3868+ case (EN_UPDATE<<16)|IDC_DUMMYAMP_PLAYLIST_FORMAT:
3869+ {
3870+ string8 format;
3871+ uGetWindowText(reinterpret_cast<HWND>(lp), format);
3872+ cfg_dummyamp_playlist_format = format;
3873+ }
3874+ break;
3875+
3876+ case (BN_CLICKED<<16)|IDC_DISABLE_ANSI_TRANS:
3877+ {
3878+ cfg_disable_ansi_trans = uButton_GetCheck(wnd, IDC_DISABLE_ANSI_TRANS) ? 1 : 0;
3879+ }
3880+ break;
3881+
3882+ case (BN_CLICKED<<16)|IDC_ENABLE_EXT_IPC_PROC:
3883+ {
3884+ cfg_enable_ext_ipc_proc = uButton_GetCheck(wnd, IDC_ENABLE_EXT_IPC_PROC) ? 1 : 0;
3885+ }
3886+ break;
3887+
3888+ default:
3889+ break;
3890+ }
3891+ break;
3892+ case WM_DESTROY:
3893+ {
3894+ bool rebootNeeded = false;
3895+
3896+ do
3897+ {
3898+ if(nOldDummyMp3Location != -1)
3899+ {
3900+ if(nOldDummyMp3Location != cfg_dummy_mp3_location)
3901+ {
3902+ int nRes = ::MessageBox(
3903+ NULL, _T("ダミーMP3ファイルの生成場所の変更は、foobar2000本体の再起動後に有効になります。\n\n")
3904+ _T("今すぐ、foobar2000をシャットダウンしますか?"),
3905+ _T(PLUGIN_CAPTION), MB_YESNO | MB_ICONEXCLAMATION);
3906+
3907+ if(nRes == IDYES) {
3908+ rebootNeeded = true;
3909+ break;
3910+ } else {
3911+ rebootNeeded = false;
3912+ }
3913+ }
3914+ }
3915+
3916+ if(::strcmp(oldGenMixiPath, cfg_gen_mixi_path) != 0)
3917+ {
3918+ int nRes = ::MessageBox(
3919+ NULL, GEN_MIXI_FILE_NAME _T(" の配置場所の変更は、foobar2000本体の再起動後に有効になります。\n\n")
3920+ _T("今すぐ、foobar2000をシャットダウンしますか?"),
3921+ _T(PLUGIN_CAPTION), MB_YESNO | MB_ICONEXCLAMATION);
3922+
3923+ if(nRes == IDYES) {
3924+ rebootNeeded = true;
3925+ break;
3926+ } else {
3927+ rebootNeeded = false;
3928+ }
3929+ }
3930+
3931+ } while(0);
3932+
3933+ nOldDummyMp3Location = (int)cfg_dummy_mp3_location;
3934+ oldGenMixiPath = cfg_gen_mixi_path;
3935+
3936+ if(rebootNeeded) {
3937+ ::PostQuitMessage(0);
3938+ }
3939+ }
3940+ break;
3941+ }
3942+
3943+ return 0;
3944+ }
3945+
3946+public:
3947+
3948+ virtual HWND create(HWND parent)
3949+ {
3950+ return uCreateDialog(IDD_ADVANCED_SETTINGS, parent, ConfigProc);
3951+ }
3952+
3953+ virtual const char * get_name() {
3954+ return g_advancedSettingsCaption8;
3955+ }
3956+ virtual const char * get_parent_name() {
3957+ return g_pluginCaption8;
3958+ }
3959+
3960+#if IS_FB2K_VER09
3961+ virtual GUID get_guid() {
3962+ return config_page_mixi_advanced_guid;
3963+ }
3964+
3965+ virtual GUID get_parent_guid() {
3966+ return config_page_mixi_guid;
3967+ }
3968+
3969+ virtual double get_sort_priority() {
3970+ return 1.0;
3971+ }
3972+
3973+ virtual bool reset_query() {
3974+ return true;
3975+ }
3976+
3977+ virtual void reset() {
3978+ cfg_disable_dummy_mp3 = 0;
3979+ cfg_dummy_mp3_location = 0;
3980+ cfg_gen_mixi_path = PathInfo::getGenMixiDefaultPath().c_str();
3981+
3982+ cfg_show_dummyamp = 0;
3983+ cfg_dummyamp_title_format = DEFAULT_DUMMYAMP_TITLE;
3984+ cfg_dummyamp_playlist_format = DEFAULT_DUMMYAMP_TITLE;
3985+ }
3986+
3987+ virtual bool get_help_url(pfc::string_base & p_out) {
3988+ p_out = URL_FOO_MIXI_HOME;
3989+ return true;
3990+ }
3991+#endif
3992+};
3993+
3994+int config_page_mixi_advanced::nOldDummyMp3Location = -1;
3995+string8 config_page_mixi_advanced::oldGenMixiPath;
3996+
3997+#if IS_FB2K_VER08
3998+class config_page_mixi_debug : public config
3999+#elif IS_FB2K_VER09
4000+// {ADD3AC74-B1A7-4d04-BADB-6BEB7D132669}
4001+static const GUID config_page_mixi_debug_guid = { 0xadd3ac74, 0xb1a7, 0x4d04, { 0xba, 0xdb, 0x6b, 0xeb, 0x7d, 0x13, 0x26, 0x69 } };
4002+class config_page_mixi_debug : public preferences_page_v2
4003+#endif
4004+{
4005+ static BOOL CALLBACK ConfigProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
4006+ {
4007+ switch(msg)
4008+ {
4009+ case WM_INITDIALOG:
4010+ {
4011+ uSetDlgItemText(wnd, IDC_CAPTION_DEBUG, g_debugSettingsCaption8);
4012+
4013+ bool bDebugLogEnabled = (cfg_enable_debug_log == 1) ? true : false;
4014+ uButton_SetCheck(wnd, IDC_ENABLE_DEBUG_LOG, bDebugLogEnabled);
4015+
4016+ InitDebugLevelList(wnd, IDC_DEBUG_DUMMYAMP_INIT);
4017+ InitDebugLevelList(wnd, IDC_DEBUG_DUMMYAMP_PROC);
4018+ InitDebugLevelList(wnd, IDC_DEBUG_TRACK_INFO);
4019+ InitDebugLevelList(wnd, IDC_DEBUG_PLUGIN);
4020+ InitDebugLevelList(wnd, IDC_DEBUG_CALLBACK);
4021+
4022+ EnableDebugLevelLists(wnd, bDebugLogEnabled);
4023+
4024+ uSendDlgItemMessage(wnd, IDC_DEBUG_DUMMYAMP_INIT, CB_SETCURSEL, (int)cfg_debug_dummyamp_init, 0);
4025+ uSendDlgItemMessage(wnd, IDC_DEBUG_DUMMYAMP_PROC, CB_SETCURSEL, (int)cfg_debug_dummyamp_proc, 0);
4026+ uSendDlgItemMessage(wnd, IDC_DEBUG_TRACK_INFO, CB_SETCURSEL, (int)cfg_debug_track_info, 0);
4027+ uSendDlgItemMessage(wnd, IDC_DEBUG_PLUGIN, CB_SETCURSEL, (int)cfg_debug_plugin, 0);
4028+ uSendDlgItemMessage(wnd, IDC_DEBUG_CALLBACK, CB_SETCURSEL, (int)cfg_debug_callback, 0);
4029+
4030+ setDlgVersionInfo(wnd, IDC_VERSION_DEBUG, IDC_BUILD_DEBUG);
4031+ }
4032+ break;
4033+
4034+ case WM_COMMAND:
4035+ switch(wp)
4036+ {
4037+ case (BN_CLICKED<<16)|IDC_ENABLE_DEBUG_LOG:
4038+ {
4039+ bool bDebugLogEnabled = uButton_GetCheck(wnd, IDC_ENABLE_DEBUG_LOG);
4040+ cfg_enable_debug_log = bDebugLogEnabled ? 1 : 0;
4041+
4042+ EnableDebugLevelLists(wnd, bDebugLogEnabled);
4043+ }
4044+ break;
4045+
4046+ case (CBN_SELCHANGE<<16)|IDC_DEBUG_DUMMYAMP_INIT:
4047+ {
4048+ int sel = static_cast<int>(uSendMessage(reinterpret_cast<HWND>(lp), CB_GETCURSEL, 0, 0));
4049+ cfg_debug_dummyamp_init = sel;
4050+ }
4051+ break;
4052+
4053+ case (CBN_SELCHANGE<<16)|IDC_DEBUG_DUMMYAMP_PROC:
4054+ {
4055+ int sel = static_cast<int>(uSendMessage(reinterpret_cast<HWND>(lp), CB_GETCURSEL, 0, 0));
4056+ cfg_debug_dummyamp_proc = sel;
4057+ }
4058+ break;
4059+
4060+ case (CBN_SELCHANGE<<16)|IDC_DEBUG_TRACK_INFO:
4061+ {
4062+ int sel = static_cast<int>(uSendMessage(reinterpret_cast<HWND>(lp), CB_GETCURSEL, 0, 0));
4063+ cfg_debug_track_info = sel;
4064+ }
4065+ break;
4066+
4067+ case (CBN_SELCHANGE<<16)|IDC_DEBUG_PLUGIN:
4068+ {
4069+ int sel = static_cast<int>(uSendMessage(reinterpret_cast<HWND>(lp), CB_GETCURSEL, 0, 0));
4070+ cfg_debug_plugin = sel;
4071+ }
4072+ break;
4073+
4074+ case (CBN_SELCHANGE<<16)|IDC_DEBUG_CALLBACK:
4075+ {
4076+ int sel = static_cast<int>(uSendMessage(reinterpret_cast<HWND>(lp), CB_GETCURSEL, 0, 0));
4077+ cfg_debug_callback = sel;
4078+ }
4079+ break;
4080+
4081+ default:
4082+ break;
4083+ }
4084+ break;
4085+
4086+ case WM_DESTROY:
4087+ break;
4088+ }
4089+
4090+ return 0;
4091+ }
4092+
4093+protected:
4094+
4095+ static void InitDebugLevelList(HWND wnd, UINT id) {
4096+ uSendDlgItemMessage(wnd, id, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(_T("なし")));
4097+ uSendDlgItemMessage(wnd, id, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(_T("簡易レベル")));
4098+ uSendDlgItemMessage(wnd, id, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(_T("詳細レベル")));
4099+ }
4100+
4101+ static void EnableDebugLevelLists(HWND wnd, bool bDebugLogEnabled) {
4102+ EnableDebugLevelList(wnd, IDC_DEBUG_DUMMYAMP_INIT, bDebugLogEnabled);
4103+ EnableDebugLevelList(wnd, IDC_DEBUG_DUMMYAMP_PROC, bDebugLogEnabled);
4104+ EnableDebugLevelList(wnd, IDC_DEBUG_TRACK_INFO, bDebugLogEnabled);
4105+ EnableDebugLevelList(wnd, IDC_DEBUG_PLUGIN, bDebugLogEnabled);
4106+ EnableDebugLevelList(wnd, IDC_DEBUG_CALLBACK, bDebugLogEnabled);
4107+ }
4108+
4109+ static void EnableDebugLevelList(HWND wnd, UINT id, bool bEnable) {
4110+ HWND hControlWnd = uGetDlgItem(wnd, id);
4111+ uEnableWindow(hControlWnd, bEnable);
4112+ }
4113+
4114+public:
4115+
4116+ virtual HWND create(HWND parent)
4117+ {
4118+ return uCreateDialog(IDD_DEBUG_SETTINGS, parent, ConfigProc);
4119+ }
4120+
4121+ virtual const char * get_name() {
4122+ return g_debugSettingsCaption8;
4123+ }
4124+ virtual const char * get_parent_name() {
4125+ return g_pluginCaption8;
4126+ }
4127+
4128+#if IS_FB2K_VER09
4129+ virtual GUID get_guid() {
4130+ return config_page_mixi_debug_guid;
4131+ }
4132+
4133+ virtual GUID get_parent_guid() {
4134+ return config_page_mixi_guid;
4135+ }
4136+
4137+ virtual bool reset_query() {
4138+ return true;
4139+ }
4140+
4141+ virtual double get_sort_priority() {
4142+ return 2.0;
4143+ }
4144+
4145+ virtual void reset() {
4146+ cfg_enable_debug_log = 1;
4147+ cfg_debug_dummyamp_init = 1;
4148+ cfg_debug_dummyamp_proc = 1;
4149+ cfg_debug_track_info = 1;
4150+ cfg_debug_plugin = 1;
4151+ cfg_debug_callback = 1;
4152+ }
4153+
4154+ virtual bool get_help_url(pfc::string_base & p_out) {
4155+ p_out = URL_FOO_MIXI_HOME;
4156+ return true;
4157+ }
4158+#endif
4159+};
4160+
4161+#if IS_FB2K_VER08
4162+static service_factory_single_t<play_callback, play_callback_mixi> foo1;
4163+static service_factory_single_t<initquit, initquit_mixi> foo2;
4164+static menu_item_factory<menu_item_mixi> foo3;
4165+static service_factory_single_t<config, config_page_mixi> foo4;
4166+static service_factory_single_t<config, config_page_mixi_advanced> foo5;
4167+static service_factory_single_t<config, config_page_mixi_debug> foo6;
4168+#elif IS_FB2K_VER09
4169+static service_factory_single_t<play_callback_mixi> foo1;
4170+static initquit_factory_t<initquit_mixi> foo2;
4171+static mainmenu_commands_factory_t<menu_item_mixi> foo3;
4172+static preferences_page_factory_t<config_page_mixi> foo4;
4173+static preferences_page_factory_t<config_page_mixi_advanced> foo5;
4174+static preferences_page_factory_t<config_page_mixi_debug> foo6;
4175+#endif
4176+
4177+tstring GetErrorMessage(DWORD errCode)
4178+{
4179+
4180+ LPVOID lpMsgBuf;
4181+
4182+ FormatMessage(
4183+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
4184+ FORMAT_MESSAGE_FROM_SYSTEM |
4185+ FORMAT_MESSAGE_IGNORE_INSERTS,
4186+ NULL,
4187+ errCode,
4188+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // デフォルト言語
4189+ (LPTSTR) &lpMsgBuf,
4190+ 0,
4191+ NULL
4192+ );
4193+
4194+ tstring msg = (LPCTSTR)lpMsgBuf;
4195+
4196+ GlobalFree(lpMsgBuf);
4197+
4198+ return msg;
4199+}
4200+
4201+void putLogError(LPCTSTR pMethod, LPCTSTR pErrMsg, DWORD dwErrCode)
4202+{
4203+ tstring errMsg = GetErrorMessage(dwErrCode);
4204+
4205+ LOG_ERROR(_T("%s - %s"), pMethod, pErrMsg);
4206+ LOG_ERROR(_T("%s - コード: %08x, 理由: %s"), pMethod, dwErrCode, errMsg.c_str());
4207+}
4208+
4209+void setDlgVersionInfo(HWND wnd, UINT idc_version, UINT idc_build) {
4210+
4211+ StrDBCS64K version;
4212+
4213+ sprintf_s(version, sizeof(StrDBCS64K), PLUGIN_CAPTION " " PLUGIN_VERSION " with SDK%d (compatible%d)",
4214+ foobar2000_client::FOOBAR2000_CLIENT_VERSION, foobar2000_client::FOOBAR2000_CLIENT_VERSION_COMPATIBLE);
4215+
4216+ uSetDlgItemText(wnd, idc_version, version);
4217+ uSetDlgItemText(wnd, idc_build, "build on " __DATE__ ", " __TIME__);
4218+}
4219+
4220+void DebugPrint(int severity, LPCTSTR lpszFormat, ...)
4221+{
4222+ static Str64K buf;
4223+ va_list marker;
4224+
4225+ va_start(marker, lpszFormat);
4226+ _vstprintf_s(buf, sizeof(Str64K), lpszFormat, marker);
4227+ va_end(marker);
4228+
4229+ OutputDebugString(buf);
4230+ OutputDebugString(_T("\n"));
4231+
4232+ string_utf8_from_os tmp(buf);
4233+
4234+#if IS_FB2K_VER08
4235+ console::output(severity, tmp);
4236+#else
4237+ switch(severity)
4238+ {
4239+ case console::SEVERITY_INFO:
4240+ console::info(tmp);
4241+ break;
4242+ case console::SEVERITY_WARNING:
4243+ console::warning(tmp);
4244+ break;
4245+ case console::SEVERITY_CRITICAL:
4246+ console::error(tmp);
4247+ break;
4248+ }
4249+#endif
4250+}
4251+
4252+void DebugPrint8(int severity, LPCSTR lpszFormat, ...)
4253+{
4254+ static StrDBCS64K buf;
4255+
4256+ va_list marker;
4257+
4258+ va_start(marker, lpszFormat);
4259+ vsprintf_s(buf, sizeof(StrDBCS64K), lpszFormat, marker);
4260+ va_end(marker);
4261+
4262+#if IS_FB2K_VER08
4263+ console::output(severity, buf);
4264+#else
4265+ switch(severity)
4266+ {
4267+ case console::SEVERITY_INFO:
4268+ console::info(buf);
4269+ break;
4270+ case console::SEVERITY_WARNING:
4271+ console::warning(buf);
4272+ break;
4273+ case console::SEVERITY_CRITICAL:
4274+ console::error(buf);
4275+ break;
4276+ }
4277+#endif
4278+
4279+ string_os_from_utf8 tmp(buf);
4280+
4281+ OutputDebugString(tmp);
4282+ OutputDebugString(_T("\n"));
4283+}
4284+
4285+#if defined(BUILD_UNICODE)
4286+void DebugPrintDBCS(int severity, LPCSTR lpszFormat, ...)
4287+{
4288+ static StrDBCS64K buf;
4289+ va_list marker;
4290+
4291+ va_start(marker, lpszFormat);
4292+ vsprintf_s(buf, sizeof(StrDBCS64K), lpszFormat, marker);
4293+ va_end(marker);
4294+
4295+ string_wide_from_ansi tmp(buf);
4296+
4297+ OutputDebugString(tmp);
4298+ OutputDebugString(L"\n");
4299+
4300+#if IS_FB2K_VER08
4301+ console::output(severity, buf);
4302+#else
4303+ switch(severity)
4304+ {
4305+ case console::SEVERITY_INFO:
4306+ console::info(buf);
4307+ break;
4308+ case console::SEVERITY_WARNING:
4309+ console::warning(buf);
4310+ break;
4311+ case console::SEVERITY_CRITICAL:
4312+ console::error(buf);
4313+ break;
4314+ }
4315+#endif
4316+}
4317+#endif
\ No newline at end of file
--- src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_4_SDK72/resource.h (nonexistent)
+++ src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_4_SDK72/resource.h (revision 69)
@@ -0,0 +1,58 @@
1+//{{NO_DEPENDENCIES}}
2+// Microsoft Visual C++ generated include file.
3+// Used by foo_mixi_feat_winamp.rc
4+//
5+#define IDD_PREFERENCE 101
6+#define IDD_ADVANCED_SETTINGS 102
7+#define IDD_DEBUG_SETTINGS 103
8+#define IDC_CONFIGURE 1000
9+#define IDC_USE_PLUGIN 1001
10+#define IDC_VERSION 1002
11+#define IDC_BUILD 1003
12+#define IDC_SEND_INTERVAL_1ST 1004
13+#define IDC_SEND_INTERVAL_2ND 1005
14+#define IDC_SEND_INTERVAL_SLIDER_2ND 1006
15+#define IDC_SEND_INTERVAL_SLIDER_1ST 1007
16+#define IDC_DISABLE_DUPLICATE_SONG 1008
17+#define IDC_DISABLE_DUMMY_MP3 1009
18+#define IDC_SEND_INTERVAL_SLIDER_3RD 1010
19+#define IDC_SEND_INTERVAL_3RD 1011
20+#define IDC_CAPTION_ADVANCED 1012
21+#define IDC_DUMMY_MP3_LOCATION 1013
22+#define IDC_VERSION_ADVANCED 1014
23+#define IDC_BUILD_ADVANCED 1015
24+#define IDC_MEDIA_LIBRARY_REGISTERED_FILE_ONLY 1016
25+#define IDC_EXPLICITLY_TAGGED_FILE_ONLY 1017
26+#define IDC_GEN_MIXI_PATH 1018
27+#define IDC_GEN_MIXI_PATH_REF 1019
28+#define IDC_CAPTION_DEBUG 1020
29+#define IDC_ENABLE_DEBUG_LOG 1021
30+#define IDC_DEBUG_DUMMYAMP_INIT 1022
31+#define IDC_DEBUG_DUMMYAMP_PROC 1023
32+#define IDC_DEBUG_TRACK_INFO 1024
33+#define IDC_DEBUG_PLUGIN 1025
34+#define IDC_DEBUG_CALLBACK 1026
35+#define IDC_VERSION_DEBUG 1027
36+#define IDC_BUILD_DEBUG 1028
37+#define IDC_SHOW_DUMMYAMP 1029
38+#define IDC_DUMMYAMP_TITLE_FORMAT 1030
39+#define IDC_DUMMYAMP_PLAYLIST_FORMAT 1031
40+#define IDC_DISABLE_ANSI_TRANS 1032
41+#define IDC_ENABLE_EXT_IPC_PROC 1033
42+#define IDC_DUMMYAMP_FRAME 1034
43+#define IDC_ENABLE_STREAMING_FILE 1035
44+#define IDC_NO_ARTIST_NAME 1036
45+#define IDC_NO_TITLE_NAME 1037
46+#define IDC_NO_ALBUM_NAME 1038
47+#define IDC_NO_GENRE_NAME 1039
48+
49+// Next default values for new objects
50+//
51+#ifdef APSTUDIO_INVOKED
52+#ifndef APSTUDIO_READONLY_SYMBOLS
53+#define _APS_NEXT_RESOURCE_VALUE 104
54+#define _APS_NEXT_COMMAND_VALUE 40001
55+#define _APS_NEXT_CONTROL_VALUE 1040
56+#define _APS_NEXT_SYMED_VALUE 101
57+#endif
58+#endif
--- src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_4_SDK72/COPYING (nonexistent)
+++ src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_4_SDK72/COPYING (revision 69)
@@ -0,0 +1,674 @@
1+ GNU GENERAL PUBLIC LICENSE
2+ Version 3, 29 June 2007
3+
4+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
5+ Everyone is permitted to copy and distribute verbatim copies
6+ of this license document, but changing it is not allowed.
7+
8+ Preamble
9+
10+ The GNU General Public License is a free, copyleft license for
11+software and other kinds of works.
12+
13+ The licenses for most software and other practical works are designed
14+to take away your freedom to share and change the works. By contrast,
15+the GNU General Public License is intended to guarantee your freedom to
16+share and change all versions of a program--to make sure it remains free
17+software for all its users. We, the Free Software Foundation, use the
18+GNU General Public License for most of our software; it applies also to
19+any other work released this way by its authors. You can apply it to
20+your programs, too.
21+
22+ When we speak of free software, we are referring to freedom, not
23+price. Our General Public Licenses are designed to make sure that you
24+have the freedom to distribute copies of free software (and charge for
25+them if you wish), that you receive source code or can get it if you
26+want it, that you can change the software or use pieces of it in new
27+free programs, and that you know you can do these things.
28+
29+ To protect your rights, we need to prevent others from denying you
30+these rights or asking you to surrender the rights. Therefore, you have
31+certain responsibilities if you distribute copies of the software, or if
32+you modify it: responsibilities to respect the freedom of others.
33+
34+ For example, if you distribute copies of such a program, whether
35+gratis or for a fee, you must pass on to the recipients the same
36+freedoms that you received. You must make sure that they, too, receive
37+or can get the source code. And you must show them these terms so they
38+know their rights.
39+
40+ Developers that use the GNU GPL protect your rights with two steps:
41+(1) assert copyright on the software, and (2) offer you this License
42+giving you legal permission to copy, distribute and/or modify it.
43+
44+ For the developers' and authors' protection, the GPL clearly explains
45+that there is no warranty for this free software. For both users' and
46+authors' sake, the GPL requires that modified versions be marked as
47+changed, so that their problems will not be attributed erroneously to
48+authors of previous versions.
49+
50+ Some devices are designed to deny users access to install or run
51+modified versions of the software inside them, although the manufacturer
52+can do so. This is fundamentally incompatible with the aim of
53+protecting users' freedom to change the software. The systematic
54+pattern of such abuse occurs in the area of products for individuals to
55+use, which is precisely where it is most unacceptable. Therefore, we
56+have designed this version of the GPL to prohibit the practice for those
57+products. If such problems arise substantially in other domains, we
58+stand ready to extend this provision to those domains in future versions
59+of the GPL, as needed to protect the freedom of users.
60+
61+ Finally, every program is threatened constantly by software patents.
62+States should not allow patents to restrict development and use of
63+software on general-purpose computers, but in those that do, we wish to
64+avoid the special danger that patents applied to a free program could
65+make it effectively proprietary. To prevent this, the GPL assures that
66+patents cannot be used to render the program non-free.
67+
68+ The precise terms and conditions for copying, distribution and
69+modification follow.
70+
71+ TERMS AND CONDITIONS
72+
73+ 0. Definitions.
74+
75+ "This License" refers to version 3 of the GNU General Public License.
76+
77+ "Copyright" also means copyright-like laws that apply to other kinds of
78+works, such as semiconductor masks.
79+
80+ "The Program" refers to any copyrightable work licensed under this
81+License. Each licensee is addressed as "you". "Licensees" and
82+"recipients" may be individuals or organizations.
83+
84+ To "modify" a work means to copy from or adapt all or part of the work
85+in a fashion requiring copyright permission, other than the making of an
86+exact copy. The resulting work is called a "modified version" of the
87+earlier work or a work "based on" the earlier work.
88+
89+ A "covered work" means either the unmodified Program or a work based
90+on the Program.
91+
92+ To "propagate" a work means to do anything with it that, without
93+permission, would make you directly or secondarily liable for
94+infringement under applicable copyright law, except executing it on a
95+computer or modifying a private copy. Propagation includes copying,
96+distribution (with or without modification), making available to the
97+public, and in some countries other activities as well.
98+
99+ To "convey" a work means any kind of propagation that enables other
100+parties to make or receive copies. Mere interaction with a user through
101+a computer network, with no transfer of a copy, is not conveying.
102+
103+ An interactive user interface displays "Appropriate Legal Notices"
104+to the extent that it includes a convenient and prominently visible
105+feature that (1) displays an appropriate copyright notice, and (2)
106+tells the user that there is no warranty for the work (except to the
107+extent that warranties are provided), that licensees may convey the
108+work under this License, and how to view a copy of this License. If
109+the interface presents a list of user commands or options, such as a
110+menu, a prominent item in the list meets this criterion.
111+
112+ 1. Source Code.
113+
114+ The "source code" for a work means the preferred form of the work
115+for making modifications to it. "Object code" means any non-source
116+form of a work.
117+
118+ A "Standard Interface" means an interface that either is an official
119+standard defined by a recognized standards body, or, in the case of
120+interfaces specified for a particular programming language, one that
121+is widely used among developers working in that language.
122+
123+ The "System Libraries" of an executable work include anything, other
124+than the work as a whole, that (a) is included in the normal form of
125+packaging a Major Component, but which is not part of that Major
126+Component, and (b) serves only to enable use of the work with that
127+Major Component, or to implement a Standard Interface for which an
128+implementation is available to the public in source code form. A
129+"Major Component", in this context, means a major essential component
130+(kernel, window system, and so on) of the specific operating system
131+(if any) on which the executable work runs, or a compiler used to
132+produce the work, or an object code interpreter used to run it.
133+
134+ The "Corresponding Source" for a work in object code form means all
135+the source code needed to generate, install, and (for an executable
136+work) run the object code and to modify the work, including scripts to
137+control those activities. However, it does not include the work's
138+System Libraries, or general-purpose tools or generally available free
139+programs which are used unmodified in performing those activities but
140+which are not part of the work. For example, Corresponding Source
141+includes interface definition files associated with source files for
142+the work, and the source code for shared libraries and dynamically
143+linked subprograms that the work is specifically designed to require,
144+such as by intimate data communication or control flow between those
145+subprograms and other parts of the work.
146+
147+ The Corresponding Source need not include anything that users
148+can regenerate automatically from other parts of the Corresponding
149+Source.
150+
151+ The Corresponding Source for a work in source code form is that
152+same work.
153+
154+ 2. Basic Permissions.
155+
156+ All rights granted under this License are granted for the term of
157+copyright on the Program, and are irrevocable provided the stated
158+conditions are met. This License explicitly affirms your unlimited
159+permission to run the unmodified Program. The output from running a
160+covered work is covered by this License only if the output, given its
161+content, constitutes a covered work. This License acknowledges your
162+rights of fair use or other equivalent, as provided by copyright law.
163+
164+ You may make, run and propagate covered works that you do not
165+convey, without conditions so long as your license otherwise remains
166+in force. You may convey covered works to others for the sole purpose
167+of having them make modifications exclusively for you, or provide you
168+with facilities for running those works, provided that you comply with
169+the terms of this License in conveying all material for which you do
170+not control copyright. Those thus making or running the covered works
171+for you must do so exclusively on your behalf, under your direction
172+and control, on terms that prohibit them from making any copies of
173+your copyrighted material outside their relationship with you.
174+
175+ Conveying under any other circumstances is permitted solely under
176+the conditions stated below. Sublicensing is not allowed; section 10
177+makes it unnecessary.
178+
179+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180+
181+ No covered work shall be deemed part of an effective technological
182+measure under any applicable law fulfilling obligations under article
183+11 of the WIPO copyright treaty adopted on 20 December 1996, or
184+similar laws prohibiting or restricting circumvention of such
185+measures.
186+
187+ When you convey a covered work, you waive any legal power to forbid
188+circumvention of technological measures to the extent such circumvention
189+is effected by exercising rights under this License with respect to
190+the covered work, and you disclaim any intention to limit operation or
191+modification of the work as a means of enforcing, against the work's
192+users, your or third parties' legal rights to forbid circumvention of
193+technological measures.
194+
195+ 4. Conveying Verbatim Copies.
196+
197+ You may convey verbatim copies of the Program's source code as you
198+receive it, in any medium, provided that you conspicuously and
199+appropriately publish on each copy an appropriate copyright notice;
200+keep intact all notices stating that this License and any
201+non-permissive terms added in accord with section 7 apply to the code;
202+keep intact all notices of the absence of any warranty; and give all
203+recipients a copy of this License along with the Program.
204+
205+ You may charge any price or no price for each copy that you convey,
206+and you may offer support or warranty protection for a fee.
207+
208+ 5. Conveying Modified Source Versions.
209+
210+ You may convey a work based on the Program, or the modifications to
211+produce it from the Program, in the form of source code under the
212+terms of section 4, provided that you also meet all of these conditions:
213+
214+ a) The work must carry prominent notices stating that you modified
215+ it, and giving a relevant date.
216+
217+ b) The work must carry prominent notices stating that it is
218+ released under this License and any conditions added under section
219+ 7. This requirement modifies the requirement in section 4 to
220+ "keep intact all notices".
221+
222+ c) You must license the entire work, as a whole, under this
223+ License to anyone who comes into possession of a copy. This
224+ License will therefore apply, along with any applicable section 7
225+ additional terms, to the whole of the work, and all its parts,
226+ regardless of how they are packaged. This License gives no
227+ permission to license the work in any other way, but it does not
228+ invalidate such permission if you have separately received it.
229+
230+ d) If the work has interactive user interfaces, each must display
231+ Appropriate Legal Notices; however, if the Program has interactive
232+ interfaces that do not display Appropriate Legal Notices, your
233+ work need not make them do so.
234+
235+ A compilation of a covered work with other separate and independent
236+works, which are not by their nature extensions of the covered work,
237+and which are not combined with it such as to form a larger program,
238+in or on a volume of a storage or distribution medium, is called an
239+"aggregate" if the compilation and its resulting copyright are not
240+used to limit the access or legal rights of the compilation's users
241+beyond what the individual works permit. Inclusion of a covered work
242+in an aggregate does not cause this License to apply to the other
243+parts of the aggregate.
244+
245+ 6. Conveying Non-Source Forms.
246+
247+ You may convey a covered work in object code form under the terms
248+of sections 4 and 5, provided that you also convey the
249+machine-readable Corresponding Source under the terms of this License,
250+in one of these ways:
251+
252+ a) Convey the object code in, or embodied in, a physical product
253+ (including a physical distribution medium), accompanied by the
254+ Corresponding Source fixed on a durable physical medium
255+ customarily used for software interchange.
256+
257+ b) Convey the object code in, or embodied in, a physical product
258+ (including a physical distribution medium), accompanied by a
259+ written offer, valid for at least three years and valid for as
260+ long as you offer spare parts or customer support for that product
261+ model, to give anyone who possesses the object code either (1) a
262+ copy of the Corresponding Source for all the software in the
263+ product that is covered by this License, on a durable physical
264+ medium customarily used for software interchange, for a price no
265+ more than your reasonable cost of physically performing this
266+ conveying of source, or (2) access to copy the
267+ Corresponding Source from a network server at no charge.
268+
269+ c) Convey individual copies of the object code with a copy of the
270+ written offer to provide the Corresponding Source. This
271+ alternative is allowed only occasionally and noncommercially, and
272+ only if you received the object code with such an offer, in accord
273+ with subsection 6b.
274+
275+ d) Convey the object code by offering access from a designated
276+ place (gratis or for a charge), and offer equivalent access to the
277+ Corresponding Source in the same way through the same place at no
278+ further charge. You need not require recipients to copy the
279+ Corresponding Source along with the object code. If the place to
280+ copy the object code is a network server, the Corresponding Source
281+ may be on a different server (operated by you or a third party)
282+ that supports equivalent copying facilities, provided you maintain
283+ clear directions next to the object code saying where to find the
284+ Corresponding Source. Regardless of what server hosts the
285+ Corresponding Source, you remain obligated to ensure that it is
286+ available for as long as needed to satisfy these requirements.
287+
288+ e) Convey the object code using peer-to-peer transmission, provided
289+ you inform other peers where the object code and Corresponding
290+ Source of the work are being offered to the general public at no
291+ charge under subsection 6d.
292+
293+ A separable portion of the object code, whose source code is excluded
294+from the Corresponding Source as a System Library, need not be
295+included in conveying the object code work.
296+
297+ A "User Product" is either (1) a "consumer product", which means any
298+tangible personal property which is normally used for personal, family,
299+or household purposes, or (2) anything designed or sold for incorporation
300+into a dwelling. In determining whether a product is a consumer product,
301+doubtful cases shall be resolved in favor of coverage. For a particular
302+product received by a particular user, "normally used" refers to a
303+typical or common use of that class of product, regardless of the status
304+of the particular user or of the way in which the particular user
305+actually uses, or expects or is expected to use, the product. A product
306+is a consumer product regardless of whether the product has substantial
307+commercial, industrial or non-consumer uses, unless such uses represent
308+the only significant mode of use of the product.
309+
310+ "Installation Information" for a User Product means any methods,
311+procedures, authorization keys, or other information required to install
312+and execute modified versions of a covered work in that User Product from
313+a modified version of its Corresponding Source. The information must
314+suffice to ensure that the continued functioning of the modified object
315+code is in no case prevented or interfered with solely because
316+modification has been made.
317+
318+ If you convey an object code work under this section in, or with, or
319+specifically for use in, a User Product, and the conveying occurs as
320+part of a transaction in which the right of possession and use of the
321+User Product is transferred to the recipient in perpetuity or for a
322+fixed term (regardless of how the transaction is characterized), the
323+Corresponding Source conveyed under this section must be accompanied
324+by the Installation Information. But this requirement does not apply
325+if neither you nor any third party retains the ability to install
326+modified object code on the User Product (for example, the work has
327+been installed in ROM).
328+
329+ The requirement to provide Installation Information does not include a
330+requirement to continue to provide support service, warranty, or updates
331+for a work that has been modified or installed by the recipient, or for
332+the User Product in which it has been modified or installed. Access to a
333+network may be denied when the modification itself materially and
334+adversely affects the operation of the network or violates the rules and
335+protocols for communication across the network.
336+
337+ Corresponding Source conveyed, and Installation Information provided,
338+in accord with this section must be in a format that is publicly
339+documented (and with an implementation available to the public in
340+source code form), and must require no special password or key for
341+unpacking, reading or copying.
342+
343+ 7. Additional Terms.
344+
345+ "Additional permissions" are terms that supplement the terms of this
346+License by making exceptions from one or more of its conditions.
347+Additional permissions that are applicable to the entire Program shall
348+be treated as though they were included in this License, to the extent
349+that they are valid under applicable law. If additional permissions
350+apply only to part of the Program, that part may be used separately
351+under those permissions, but the entire Program remains governed by
352+this License without regard to the additional permissions.
353+
354+ When you convey a copy of a covered work, you may at your option
355+remove any additional permissions from that copy, or from any part of
356+it. (Additional permissions may be written to require their own
357+removal in certain cases when you modify the work.) You may place
358+additional permissions on material, added by you to a covered work,
359+for which you have or can give appropriate copyright permission.
360+
361+ Notwithstanding any other provision of this License, for material you
362+add to a covered work, you may (if authorized by the copyright holders of
363+that material) supplement the terms of this License with terms:
364+
365+ a) Disclaiming warranty or limiting liability differently from the
366+ terms of sections 15 and 16 of this License; or
367+
368+ b) Requiring preservation of specified reasonable legal notices or
369+ author attributions in that material or in the Appropriate Legal
370+ Notices displayed by works containing it; or
371+
372+ c) Prohibiting misrepresentation of the origin of that material, or
373+ requiring that modified versions of such material be marked in
374+ reasonable ways as different from the original version; or
375+
376+ d) Limiting the use for publicity purposes of names of licensors or
377+ authors of the material; or
378+
379+ e) Declining to grant rights under trademark law for use of some
380+ trade names, trademarks, or service marks; or
381+
382+ f) Requiring indemnification of licensors and authors of that
383+ material by anyone who conveys the material (or modified versions of
384+ it) with contractual assumptions of liability to the recipient, for
385+ any liability that these contractual assumptions directly impose on
386+ those licensors and authors.
387+
388+ All other non-permissive additional terms are considered "further
389+restrictions" within the meaning of section 10. If the Program as you
390+received it, or any part of it, contains a notice stating that it is
391+governed by this License along with a term that is a further
392+restriction, you may remove that term. If a license document contains
393+a further restriction but permits relicensing or conveying under this
394+License, you may add to a covered work material governed by the terms
395+of that license document, provided that the further restriction does
396+not survive such relicensing or conveying.
397+
398+ If you add terms to a covered work in accord with this section, you
399+must place, in the relevant source files, a statement of the
400+additional terms that apply to those files, or a notice indicating
401+where to find the applicable terms.
402+
403+ Additional terms, permissive or non-permissive, may be stated in the
404+form of a separately written license, or stated as exceptions;
405+the above requirements apply either way.
406+
407+ 8. Termination.
408+
409+ You may not propagate or modify a covered work except as expressly
410+provided under this License. Any attempt otherwise to propagate or
411+modify it is void, and will automatically terminate your rights under
412+this License (including any patent licenses granted under the third
413+paragraph of section 11).
414+
415+ However, if you cease all violation of this License, then your
416+license from a particular copyright holder is reinstated (a)
417+provisionally, unless and until the copyright holder explicitly and
418+finally terminates your license, and (b) permanently, if the copyright
419+holder fails to notify you of the violation by some reasonable means
420+prior to 60 days after the cessation.
421+
422+ Moreover, your license from a particular copyright holder is
423+reinstated permanently if the copyright holder notifies you of the
424+violation by some reasonable means, this is the first time you have
425+received notice of violation of this License (for any work) from that
426+copyright holder, and you cure the violation prior to 30 days after
427+your receipt of the notice.
428+
429+ Termination of your rights under this section does not terminate the
430+licenses of parties who have received copies or rights from you under
431+this License. If your rights have been terminated and not permanently
432+reinstated, you do not qualify to receive new licenses for the same
433+material under section 10.
434+
435+ 9. Acceptance Not Required for Having Copies.
436+
437+ You are not required to accept this License in order to receive or
438+run a copy of the Program. Ancillary propagation of a covered work
439+occurring solely as a consequence of using peer-to-peer transmission
440+to receive a copy likewise does not require acceptance. However,
441+nothing other than this License grants you permission to propagate or
442+modify any covered work. These actions infringe copyright if you do
443+not accept this License. Therefore, by modifying or propagating a
444+covered work, you indicate your acceptance of this License to do so.
445+
446+ 10. Automatic Licensing of Downstream Recipients.
447+
448+ Each time you convey a covered work, the recipient automatically
449+receives a license from the original licensors, to run, modify and
450+propagate that work, subject to this License. You are not responsible
451+for enforcing compliance by third parties with this License.
452+
453+ An "entity transaction" is a transaction transferring control of an
454+organization, or substantially all assets of one, or subdividing an
455+organization, or merging organizations. If propagation of a covered
456+work results from an entity transaction, each party to that
457+transaction who receives a copy of the work also receives whatever
458+licenses to the work the party's predecessor in interest had or could
459+give under the previous paragraph, plus a right to possession of the
460+Corresponding Source of the work from the predecessor in interest, if
461+the predecessor has it or can get it with reasonable efforts.
462+
463+ You may not impose any further restrictions on the exercise of the
464+rights granted or affirmed under this License. For example, you may
465+not impose a license fee, royalty, or other charge for exercise of
466+rights granted under this License, and you may not initiate litigation
467+(including a cross-claim or counterclaim in a lawsuit) alleging that
468+any patent claim is infringed by making, using, selling, offering for
469+sale, or importing the Program or any portion of it.
470+
471+ 11. Patents.
472+
473+ A "contributor" is a copyright holder who authorizes use under this
474+License of the Program or a work on which the Program is based. The
475+work thus licensed is called the contributor's "contributor version".
476+
477+ A contributor's "essential patent claims" are all patent claims
478+owned or controlled by the contributor, whether already acquired or
479+hereafter acquired, that would be infringed by some manner, permitted
480+by this License, of making, using, or selling its contributor version,
481+but do not include claims that would be infringed only as a
482+consequence of further modification of the contributor version. For
483+purposes of this definition, "control" includes the right to grant
484+patent sublicenses in a manner consistent with the requirements of
485+this License.
486+
487+ Each contributor grants you a non-exclusive, worldwide, royalty-free
488+patent license under the contributor's essential patent claims, to
489+make, use, sell, offer for sale, import and otherwise run, modify and
490+propagate the contents of its contributor version.
491+
492+ In the following three paragraphs, a "patent license" is any express
493+agreement or commitment, however denominated, not to enforce a patent
494+(such as an express permission to practice a patent or covenant not to
495+sue for patent infringement). To "grant" such a patent license to a
496+party means to make such an agreement or commitment not to enforce a
497+patent against the party.
498+
499+ If you convey a covered work, knowingly relying on a patent license,
500+and the Corresponding Source of the work is not available for anyone
501+to copy, free of charge and under the terms of this License, through a
502+publicly available network server or other readily accessible means,
503+then you must either (1) cause the Corresponding Source to be so
504+available, or (2) arrange to deprive yourself of the benefit of the
505+patent license for this particular work, or (3) arrange, in a manner
506+consistent with the requirements of this License, to extend the patent
507+license to downstream recipients. "Knowingly relying" means you have
508+actual knowledge that, but for the patent license, your conveying the
509+covered work in a country, or your recipient's use of the covered work
510+in a country, would infringe one or more identifiable patents in that
511+country that you have reason to believe are valid.
512+
513+ If, pursuant to or in connection with a single transaction or
514+arrangement, you convey, or propagate by procuring conveyance of, a
515+covered work, and grant a patent license to some of the parties
516+receiving the covered work authorizing them to use, propagate, modify
517+or convey a specific copy of the covered work, then the patent license
518+you grant is automatically extended to all recipients of the covered
519+work and works based on it.
520+
521+ A patent license is "discriminatory" if it does not include within
522+the scope of its coverage, prohibits the exercise of, or is
523+conditioned on the non-exercise of one or more of the rights that are
524+specifically granted under this License. You may not convey a covered
525+work if you are a party to an arrangement with a third party that is
526+in the business of distributing software, under which you make payment
527+to the third party based on the extent of your activity of conveying
528+the work, and under which the third party grants, to any of the
529+parties who would receive the covered work from you, a discriminatory
530+patent license (a) in connection with copies of the covered work
531+conveyed by you (or copies made from those copies), or (b) primarily
532+for and in connection with specific products or compilations that
533+contain the covered work, unless you entered into that arrangement,
534+or that patent license was granted, prior to 28 March 2007.
535+
536+ Nothing in this License shall be construed as excluding or limiting
537+any implied license or other defenses to infringement that may
538+otherwise be available to you under applicable patent law.
539+
540+ 12. No Surrender of Others' Freedom.
541+
542+ If conditions are imposed on you (whether by court order, agreement or
543+otherwise) that contradict the conditions of this License, they do not
544+excuse you from the conditions of this License. If you cannot convey a
545+covered work so as to satisfy simultaneously your obligations under this
546+License and any other pertinent obligations, then as a consequence you may
547+not convey it at all. For example, if you agree to terms that obligate you
548+to collect a royalty for further conveying from those to whom you convey
549+the Program, the only way you could satisfy both those terms and this
550+License would be to refrain entirely from conveying the Program.
551+
552+ 13. Use with the GNU Affero General Public License.
553+
554+ Notwithstanding any other provision of this License, you have
555+permission to link or combine any covered work with a work licensed
556+under version 3 of the GNU Affero General Public License into a single
557+combined work, and to convey the resulting work. The terms of this
558+License will continue to apply to the part which is the covered work,
559+but the special requirements of the GNU Affero General Public License,
560+section 13, concerning interaction through a network will apply to the
561+combination as such.
562+
563+ 14. Revised Versions of this License.
564+
565+ The Free Software Foundation may publish revised and/or new versions of
566+the GNU General Public License from time to time. Such new versions will
567+be similar in spirit to the present version, but may differ in detail to
568+address new problems or concerns.
569+
570+ Each version is given a distinguishing version number. If the
571+Program specifies that a certain numbered version of the GNU General
572+Public License "or any later version" applies to it, you have the
573+option of following the terms and conditions either of that numbered
574+version or of any later version published by the Free Software
575+Foundation. If the Program does not specify a version number of the
576+GNU General Public License, you may choose any version ever published
577+by the Free Software Foundation.
578+
579+ If the Program specifies that a proxy can decide which future
580+versions of the GNU General Public License can be used, that proxy's
581+public statement of acceptance of a version permanently authorizes you
582+to choose that version for the Program.
583+
584+ Later license versions may give you additional or different
585+permissions. However, no additional obligations are imposed on any
586+author or copyright holder as a result of your choosing to follow a
587+later version.
588+
589+ 15. Disclaimer of Warranty.
590+
591+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599+
600+ 16. Limitation of Liability.
601+
602+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610+SUCH DAMAGES.
611+
612+ 17. Interpretation of Sections 15 and 16.
613+
614+ If the disclaimer of warranty and limitation of liability provided
615+above cannot be given local legal effect according to their terms,
616+reviewing courts shall apply local law that most closely approximates
617+an absolute waiver of all civil liability in connection with the
618+Program, unless a warranty or assumption of liability accompanies a
619+copy of the Program in return for a fee.
620+
621+ END OF TERMS AND CONDITIONS
622+
623+ How to Apply These Terms to Your New Programs
624+
625+ If you develop a new program, and you want it to be of the greatest
626+possible use to the public, the best way to achieve this is to make it
627+free software which everyone can redistribute and change under these terms.
628+
629+ To do so, attach the following notices to the program. It is safest
630+to attach them to the start of each source file to most effectively
631+state the exclusion of warranty; and each file should have at least
632+the "copyright" line and a pointer to where the full notice is found.
633+
634+ <one line to give the program's name and a brief idea of what it does.>
635+ Copyright (C) <year> <name of author>
636+
637+ This program is free software: you can redistribute it and/or modify
638+ it under the terms of the GNU General Public License as published by
639+ the Free Software Foundation, either version 3 of the License, or
640+ (at your option) any later version.
641+
642+ This program is distributed in the hope that it will be useful,
643+ but WITHOUT ANY WARRANTY; without even the implied warranty of
644+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645+ GNU General Public License for more details.
646+
647+ You should have received a copy of the GNU General Public License
648+ along with this program. If not, see <http://www.gnu.org/licenses/>.
649+
650+Also add information on how to contact you by electronic and paper mail.
651+
652+ If the program does terminal interaction, make it output a short
653+notice like this when it starts in an interactive mode:
654+
655+ <program> Copyright (C) <year> <name of author>
656+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657+ This is free software, and you are welcome to redistribute it
658+ under certain conditions; type `show c' for details.
659+
660+The hypothetical commands `show w' and `show c' should show the appropriate
661+parts of the General Public License. Of course, your program's commands
662+might be different; for a GUI interface, you would use an "about box".
663+
664+ You should also get your employer (if you work as a programmer) or school,
665+if any, to sign a "copyright disclaimer" for the program, if necessary.
666+For more information on this, and how to apply and follow the GNU GPL, see
667+<http://www.gnu.org/licenses/>.
668+
669+ The GNU General Public License does not permit incorporating your program
670+into proprietary programs. If your program is a subroutine library, you
671+may consider it more useful to permit linking proprietary applications with
672+the library. If this is what you want to do, use the GNU Lesser General
673+Public License instead of this License. But first, please read
674+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
--- src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_4_SDK72/wa_ipc.h (nonexistent)
+++ src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_4_SDK72/wa_ipc.h (revision 69)
@@ -0,0 +1,1022 @@
1+/*
2+** Copyright (C) 2003 Nullsoft, Inc.
3+**
4+** This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held
5+** liable for any damages arising from the use of this software.
6+**
7+** Permission is granted to anyone to use this software for any purpose, including commercial applications, and to
8+** alter it and redistribute it freely, subject to the following restrictions:
9+**
10+** 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
11+** If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
12+**
13+** 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
14+**
15+** 3. This notice may not be removed or altered from any source distribution.
16+**
17+*/
18+
19+#ifndef _WA_IPC_H_
20+#define _WA_IPC_H_
21+
22+/*
23+** This is the modern replacement for the classic 'frontend.h'. Most of these
24+** updates are designed for in-process use, i.e. from a plugin.
25+**
26+*/
27+
28+/* message used to sent many messages to winamp's main window.
29+** most all of the IPC_* messages involve sending the message in the form of:
30+** result = SendMessage(hwnd_winamp,WM_WA_IPC,(parameter),IPC_*);
31+*/
32+#define WM_WA_IPC WM_USER
33+/* but some of them use WM_COPYDATA. be afraid.
34+*/
35+
36+#define IPC_GETVERSION 0
37+/* int version = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETVERSION);
38+**
39+** Version will be 0x20yx for winamp 2.yx. versions previous to Winamp 2.0
40+** typically (but not always) use 0x1zyx for 1.zx versions. Weird, I know.
41+*/
42+
43+#define IPC_GETREGISTEREDVERSION 770
44+
45+
46+typedef struct {
47+ char *filename;
48+ char *title;
49+ int length;
50+} enqueueFileWithMetaStruct; // send this to a IPC_PLAYFILE in a non WM_COPYDATA,
51+// and you get the nice desired result. if title is NULL, it is treated as a "thing",
52+// otherwise it's assumed to be a file (for speed)
53+
54+#define IPC_PLAYFILE 100 // dont be fooled, this is really the same as enqueufile
55+#define IPC_ENQUEUEFILE 100
56+/* sent as a WM_COPYDATA, with IPC_PLAYFILE as the dwData, and the string to play
57+** as the lpData. Just enqueues, does not clear the playlist or change the playback
58+** state.
59+*/
60+
61+
62+#define IPC_DELETE 101
63+#define IPC_DELETE_INT 1101 // don't use this, it's used internally by winamp when
64+ // dealing with some lame explorer issues.
65+/* SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_DELETE);
66+** Use IPC_DELETE to clear Winamp's internal playlist.
67+*/
68+
69+
70+#define IPC_STARTPLAY 102 // starts playback. almost like hitting play in Winamp.
71+#define IPC_STARTPLAY_INT 1102 // used internally, don't bother using it (won't be any fun)
72+
73+
74+#define IPC_CHDIR 103
75+/* sent as a WM_COPYDATA, with IPC_CHDIR as the dwData, and the directory to change to
76+** as the lpData.
77+*/
78+
79+
80+#define IPC_ISPLAYING 104
81+/* int res = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_ISPLAYING);
82+** If it returns 1, it is playing. if it returns 3, it is paused,
83+** if it returns 0, it is not playing.
84+*/
85+
86+
87+#define IPC_GETOUTPUTTIME 105
88+/* int res = SendMessage(hwnd_winamp,WM_WA_IPC,mode,IPC_GETOUTPUTTIME);
89+** returns the position in milliseconds of the current track (mode = 0),
90+** or the track length, in seconds (mode = 1). Returns -1 if not playing or error.
91+*/
92+
93+
94+#define IPC_JUMPTOTIME 106
95+/* (requires Winamp 1.60+)
96+** SendMessage(hwnd_winamp,WM_WA_IPC,ms,IPC_JUMPTOTIME);
97+** IPC_JUMPTOTIME sets the position in milliseconds of the
98+** current song (approximately).
99+** Returns -1 if not playing, 1 on eof, or 0 if successful
100+*/
101+
102+#define IPC_GETMODULENAME 109
103+#define IPC_EX_ISRIGHTEXE 666
104+/* usually shouldnt bother using these, but here goes:
105+** send a WM_COPYDATA with IPC_GETMODULENAME, and an internal
106+** flag gets set, which if you send a normal WM_WA_IPC message with
107+** IPC_EX_ISRIGHTEXE, it returns whether or not that filename
108+** matches. lame, I know.
109+*/
110+
111+#define IPC_WRITEPLAYLIST 120
112+/* (requires Winamp 1.666+)
113+** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_WRITEPLAYLIST);
114+**
115+** IPC_WRITEPLAYLIST writes the current playlist to <winampdir>\\Winamp.m3u,
116+** and returns the current playlist position.
117+** Kinda obsoleted by some of the 2.x new stuff, but still good for when
118+** using a front-end (instead of a plug-in)
119+*/
120+
121+
122+#define IPC_SETPLAYLISTPOS 121
123+/* (requires Winamp 2.0+)
124+** SendMessage(hwnd_winamp,WM_WA_IPC,position,IPC_SETPLAYLISTPOS)
125+** IPC_SETPLAYLISTPOS sets the playlist position to 'position'. It
126+** does not change playback or anything, it just sets position, and
127+** updates the view if necessary
128+*/
129+
130+
131+#define IPC_SETVOLUME 122
132+/* (requires Winamp 2.0+)
133+** SendMessage(hwnd_winamp,WM_WA_IPC,volume,IPC_SETVOLUME);
134+** IPC_SETVOLUME sets the volume of Winamp (from 0-255).
135+*/
136+
137+
138+#define IPC_SETPANNING 123
139+/* (requires Winamp 2.0+)
140+** SendMessage(hwnd_winamp,WM_WA_IPC,panning,IPC_SETPANNING);
141+** IPC_SETPANNING sets the panning of Winamp (from 0 (left) to 255 (right)).
142+*/
143+
144+
145+#define IPC_GETLISTLENGTH 124
146+/* (requires Winamp 2.0+)
147+** int length = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTLENGTH);
148+** IPC_GETLISTLENGTH returns the length of the current playlist, in
149+** tracks.
150+*/
151+
152+
153+#define IPC_GETLISTPOS 125
154+/* (requires Winamp 2.05+)
155+** int pos=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTPOS);
156+** IPC_GETLISTPOS returns the playlist position. A lot like IPC_WRITEPLAYLIST
157+** only faster since it doesn't have to write out the list. Heh, silly me.
158+*/
159+
160+
161+#define IPC_GETINFO 126
162+/* (requires Winamp 2.05+)
163+** int inf=SendMessage(hwnd_winamp,WM_WA_IPC,mode,IPC_GETINFO);
164+** IPC_GETINFO returns info about the current playing song. The value
165+** it returns depends on the value of 'mode'.
166+** Mode Meaning
167+** ------------------
168+** 0 Samplerate (i.e. 44100)
169+** 1 Bitrate (i.e. 128)
170+** 2 Channels (i.e. 2)
171+** 3 (5+) Video LOWORD=w HIWORD=h
172+** 4 (5+) > 65536, string (video description)
173+*/
174+
175+
176+#define IPC_GETEQDATA 127
177+/* (requires Winamp 2.05+)
178+** int data=SendMessage(hwnd_winamp,WM_WA_IPC,pos,IPC_GETEQDATA);
179+** IPC_GETEQDATA queries the status of the EQ.
180+** The value returned depends on what 'pos' is set to:
181+** Value Meaning
182+** ------------------
183+** 0-9 The 10 bands of EQ data. 0-63 (+20db - -20db)
184+** 10 The preamp value. 0-63 (+20db - -20db)
185+** 11 Enabled. zero if disabled, nonzero if enabled.
186+** 12 Autoload. zero if disabled, nonzero if enabled.
187+*/
188+
189+
190+#define IPC_SETEQDATA 128
191+/* (requires Winamp 2.05+)
192+** SendMessage(hwnd_winamp,WM_WA_IPC,pos,IPC_GETEQDATA);
193+** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_SETEQDATA);
194+** IPC_SETEQDATA sets the value of the last position retrieved
195+** by IPC_GETEQDATA. This is pretty lame, and we should provide
196+** an extended version that lets you do a MAKELPARAM(pos,value).
197+** someday...
198+
199+ new (2.92+):
200+ if the high byte is set to 0xDB, then the third byte specifies
201+ which band, and the bottom word specifies the value.
202+*/
203+
204+#define IPC_ADDBOOKMARK 129
205+/* (requires Winamp 2.4+)
206+** Sent as a WM_COPYDATA, using IPC_ADDBOOKMARK, adds the specified
207+** file/url to the Winamp bookmark list.
208+*/
209+/*
210+In winamp 5+, we use this as a normal WM_WA_IPC and the string:
211+
212+ "filename\0title\0"
213+
214+ to notify the library/bookmark editor that a bookmark
215+was added. Note that using this message in this context does not
216+actually add the bookmark.
217+do not use :)
218+*/
219+
220+
221+#define IPC_INSTALLPLUGIN 130
222+/* not implemented, but if it was you could do a WM_COPYDATA with
223+** a path to a .wpz, and it would install it.
224+*/
225+
226+
227+#define IPC_RESTARTWINAMP 135
228+/* (requires Winamp 2.2+)
229+** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_RESTARTWINAMP);
230+** IPC_RESTARTWINAMP will restart Winamp (isn't that obvious ? :)
231+*/
232+
233+
234+#define IPC_ISFULLSTOP 400
235+/* (requires winamp 2.7+ I think)
236+** ret=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_ISFULLSTOP);
237+** useful for when you're an output plugin, and you want to see
238+** if the stop/close is a full stop, or just between tracks.
239+** returns nonzero if it's full, zero if it's just a new track.
240+*/
241+
242+
243+#define IPC_INETAVAILABLE 242
244+/* (requires Winamp 2.05+)
245+** val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_INETAVAILABLE);
246+** IPC_INETAVAILABLE will return 1 if the Internet connection is available for Winamp.
247+*/
248+
249+
250+#define IPC_UPDTITLE 243
251+/* (requires Winamp 2.2+)
252+** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_UPDTITLE);
253+** IPC_UPDTITLE will ask Winamp to update the informations about the current title.
254+*/
255+
256+
257+#define IPC_REFRESHPLCACHE 247
258+/* (requires Winamp 2.2+)
259+** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_REFRESHPLCACHE);
260+** IPC_REFRESHPLCACHE will flush the playlist cache buffer.
261+** (send this if you want it to go refetch titles for tracks)
262+*/
263+
264+
265+#define IPC_GET_SHUFFLE 250
266+/* (requires Winamp 2.4+)
267+** val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_SHUFFLE);
268+**
269+** IPC_GET_SHUFFLE returns the status of the Shuffle option (1 if set)
270+*/
271+
272+
273+#define IPC_GET_REPEAT 251
274+/* (requires Winamp 2.4+)
275+** val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_REPEAT);
276+**
277+** IPC_GET_REPEAT returns the status of the Repeat option (1 if set)
278+*/
279+
280+
281+#define IPC_SET_SHUFFLE 252
282+/* (requires Winamp 2.4+)
283+** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_SET_SHUFFLE);
284+**
285+** IPC_SET_SHUFFLE sets the status of the Shuffle option (1 to turn it on)
286+*/
287+
288+
289+#define IPC_SET_REPEAT 253
290+/* (requires Winamp 2.4+)
291+** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_SET_REPEAT);
292+**
293+** IPC_SET_REPEAT sets the status of the Repeat option (1 to turn it on)
294+*/
295+
296+
297+#define IPC_ENABLEDISABLE_ALL_WINDOWS 259 // 0xdeadbeef to disable
298+/* (requires Winamp 2.9+)
299+** SendMessage(hwnd_winamp,WM_WA_IPC,enable?0:0xdeadbeef,IPC_MBOPENREAL);
300+** sending with 0xdeadbeef as the param disables all winamp windows,
301+** any other values will enable all winamp windows.
302+*/
303+
304+
305+#define IPC_GETWND 260
306+/* (requires Winamp 2.9+)
307+** HWND h=SendMessage(hwnd_winamp,WM_WA_IPC,IPC_GETWND_xxx,IPC_GETWND);
308+** returns the HWND of the window specified.
309+*/
310+ #define IPC_GETWND_EQ 0 // use one of these for the param
311+ #define IPC_GETWND_PE 1
312+ #define IPC_GETWND_MB 2
313+ #define IPC_GETWND_VIDEO 3
314+#define IPC_ISWNDVISIBLE 261 // same param as IPC_GETWND
315+
316+
317+
318+
319+/************************************************************************
320+***************** in-process only (WE LOVE PLUGINS)
321+************************************************************************/
322+
323+
324+#define IPC_SETSKIN 200
325+/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
326+** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)"skinname",IPC_SETSKIN);
327+** IPC_SETSKIN sets the current skin to "skinname". Note that skinname
328+** can be the name of a skin, a skin .zip file, with or without path.
329+** If path isn't specified, the default search path is the winamp skins
330+** directory.
331+*/
332+
333+
334+#define IPC_GETSKIN 201
335+/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
336+** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)skinname_buffer,IPC_GETSKIN);
337+** IPC_GETSKIN puts the directory where skin bitmaps can be found
338+** into skinname_buffer.
339+** skinname_buffer must be MAX_PATH characters in length.
340+** When using a .zip'd skin file, it'll return a temporary directory
341+** where the ZIP was decompressed.
342+*/
343+
344+
345+#define IPC_EXECPLUG 202
346+/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
347+** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)"vis_file.dll",IPC_EXECPLUG);
348+** IPC_EXECPLUG executes a visualization plug-in pointed to by WPARAM.
349+** the format of this string can be:
350+** "vis_whatever.dll"
351+** "vis_whatever.dll,0" // (first mod, file in winamp plug-in dir)
352+** "C:\\dir\\vis_whatever.dll,1"
353+*/
354+
355+
356+#define IPC_GETPLAYLISTFILE 211
357+/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
358+** char *name=SendMessage(hwnd_winamp,WM_WA_IPC,index,IPC_GETPLAYLISTFILE);
359+** IPC_GETPLAYLISTFILE gets the filename of the playlist entry [index].
360+** returns a pointer to it. returns NULL on error.
361+*/
362+
363+
364+#define IPC_GETPLAYLISTTITLE 212
365+/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
366+** char *name=SendMessage(hwnd_winamp,WM_WA_IPC,index,IPC_GETPLAYLISTTITLE);
367+**
368+** IPC_GETPLAYLISTTITLE gets the title of the playlist entry [index].
369+** returns a pointer to it. returns NULL on error.
370+*/
371+
372+
373+#define IPC_GETHTTPGETTER 240
374+/* retrieves a function pointer to a HTTP retrieval function.
375+** if this is unsupported, returns 1 or 0.
376+** the function should be:
377+** int (*httpRetrieveFile)(HWND hwnd, char *url, char *file, char *dlgtitle);
378+** if you call this function, with a parent window, a URL, an output file, and a dialog title,
379+** it will return 0 on successful download, 1 on error.
380+*/
381+
382+
383+#define IPC_MBOPEN 241
384+/* (requires Winamp 2.05+)
385+** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_MBOPEN);
386+** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)url,IPC_MBOPEN);
387+** IPC_MBOPEN will open a new URL in the minibrowser. if url is NULL, it will open the Minibrowser window.
388+*/
389+
390+
391+
392+#define IPC_CHANGECURRENTFILE 245
393+/* (requires Winamp 2.05+)
394+** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)file,IPC_CHANGECURRENTFILE);
395+** IPC_CHANGECURRENTFILE will set the current playlist item.
396+*/
397+
398+
399+#define IPC_GETMBURL 246
400+/* (requires Winamp 2.2+)
401+** char buffer[4096]; // Urls can be VERY long
402+** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)buffer,IPC_GETMBURL);
403+** IPC_GETMBURL will retrieve the current Minibrowser URL into buffer.
404+** buffer must be at least 4096 bytes long.
405+*/
406+
407+
408+#define IPC_MBBLOCK 248
409+/* (requires Winamp 2.4+)
410+** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_MBBLOCK);
411+**
412+** IPC_MBBLOCK will block the Minibrowser from updates if value is set to 1
413+*/
414+
415+#define IPC_MBOPENREAL 249
416+/* (requires Winamp 2.4+)
417+** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)url,IPC_MBOPENREAL);
418+**
419+** IPC_MBOPENREAL works the same as IPC_MBOPEN except that it will works even if
420+** IPC_MBBLOCK has been set to 1
421+*/
422+
423+#define IPC_ADJUST_OPTIONSMENUPOS 280
424+/* (requires Winamp 2.9+)
425+** int newpos=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_OPTIONSMENUPOS);
426+** moves where winamp expects the Options menu in the main menu. Useful if you wish to insert a
427+** menu item above the options/skins/vis menus.
428+*/
429+
430+#define IPC_GET_HMENU 281
431+/* (requires Winamp 2.9+)
432+** HMENU hMenu=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)0,IPC_GET_HMENU);
433+** values for data:
434+** 0 : main popup menu
435+** 1 : main menubar file menu
436+** 2 : main menubar options menu
437+** 3 : main menubar windows menu
438+** 4 : main menubar help menu
439+** other values will return NULL.
440+*/
441+
442+#define IPC_GET_EXTENDED_FILE_INFO 290 //pass a pointer to the following struct in wParam
443+#define IPC_GET_EXTENDED_FILE_INFO_HOOKABLE 296
444+/* (requires Winamp 2.9+)
445+** to use, create an extendedFileInfoStruct, point the values filename and metadata to the
446+** filename and metadata field you wish to query, and ret to a buffer, with retlen to the
447+** length of that buffer, and then SendMessage(hwnd_winamp,WM_WA_IPC,&struct,IPC_GET_EXTENDED_FILE_INFO);
448+** the results should be in the buffer pointed to by ret.
449+** returns 1 if the decoder supports a getExtendedFileInfo method
450+*/
451+typedef struct {
452+ char *filename;
453+ char *metadata;
454+ char *ret;
455+ int retlen;
456+} extendedFileInfoStruct;
457+
458+#define IPC_GET_BASIC_FILE_INFO 291 //pass a pointer to the following struct in wParam
459+typedef struct {
460+ char *filename;
461+
462+ int quickCheck; // set to 0 to always get, 1 for quick, 2 for default (if 2, quickCheck will be set to 0 if quick wasnot used)
463+
464+ // filled in by winamp
465+ int length;
466+ char *title;
467+ int titlelen;
468+} basicFileInfoStruct;
469+
470+#define IPC_GET_EXTLIST 292 //returns doublenull delimited. GlobalFree() it when done. if data is 0, returns raw extlist, if 1, returns something suitable for getopenfilename
471+
472+#define IPC_INFOBOX 293
473+typedef struct {
474+ HWND parent;
475+ char *filename;
476+} infoBoxParam;
477+
478+#define IPC_SET_EXTENDED_FILE_INFO 294 //pass a pointer to the a extendedFileInfoStruct in wParam
479+/* (requires Winamp 2.9+)
480+** to use, create an extendedFileInfoStruct, point the values filename and metadata to the
481+** filename and metadata field you wish to write in ret. (retlen is not used). and then
482+** SendMessage(hwnd_winamp,WM_WA_IPC,&struct,IPC_SET_EXTENDED_FILE_INFO);
483+** returns 1 if the metadata is supported
484+** Call IPC_WRITE_EXTENDED_FILE_INFO once you're done setting all the metadata you want to update
485+*/
486+
487+#define IPC_WRITE_EXTENDED_FILE_INFO 295
488+/* (requires Winamp 2.9+)
489+** writes all the metadata set thru IPC_SET_EXTENDED_FILE_INFO to the file
490+** returns 1 if the file has been successfully updated, 0 if error
491+*/
492+
493+#define IPC_FORMAT_TITLE 297
494+typedef struct
495+{
496+ char *spec; // NULL=default winamp spec
497+ void *p;
498+
499+ char *out;
500+ int out_len;
501+
502+ char * (*TAGFUNC)(char * tag, void * p); //return 0 if not found
503+ void (*TAGFREEFUNC)(char * tag,void * p);
504+} waFormatTitle;
505+
506+#define IPC_GETUNCOMPRESSINTERFACE 331
507+/* returns a function pointer to uncompress().
508+** int (*uncompress)(unsigned char *dest, unsigned long *destLen, const unsigned char *source, unsigned long sourceLen);
509+** right out of zlib, useful for decompressing zlibbed data.
510+** if you pass the parm of 0x10100000, it will return a wa_inflate_struct * to an inflate API.
511+*/
512+
513+typedef struct {
514+ int (*inflateReset)(void *strm);
515+ int (*inflateInit_)(void *strm,const char *version, int stream_size);
516+ int (*inflate)(void *strm, int flush);
517+ int (*inflateEnd)(void *strm);
518+ unsigned long (*crc32)(unsigned long crc, const unsigned char *buf, unsigned int len);
519+} wa_inflate_struct;
520+
521+
522+#define IPC_ADD_PREFS_DLG 332
523+#define IPC_REMOVE_PREFS_DLG 333
524+/* (requires Winamp 2.9+)
525+** to use, allocate a prefsDlgRec structure (either on the heap or some global
526+** data, but NOT on the stack), initialze the members:
527+** hInst to the DLL instance where the resource is located
528+** dlgID to the ID of the dialog,
529+** proc to the window procedure for the dialog
530+** name to the name of the prefs page in the prefs.
531+** where to 0 (eventually we may add more options)
532+** then, SendMessage(hwnd_winamp,WM_WA_IPC,&prefsRec,IPC_ADD_PREFS_DLG);
533+**
534+** you can also IPC_REMOVE_PREFS_DLG with the address of the same prefsRec,
535+** but you shouldn't really ever have to.
536+**
537+*/
538+#define IPC_OPENPREFSTOPAGE 380 // pass an id of a builtin page, or a &prefsDlgRec of prefs page to open
539+
540+typedef struct _prefsDlgRec {
541+ HINSTANCE hInst;
542+ int dlgID;
543+ void *proc;
544+
545+ char *name;
546+ int where; // 0 for options, 1 for plugins, 2 for skins, 3 for bookmarks, 4 for prefs
547+
548+
549+ int _id;
550+ struct _prefsDlgRec *next;
551+} prefsDlgRec;
552+
553+
554+#define IPC_GETINIFILE 334 // returns a pointer to winamp.ini
555+#define IPC_GETINIDIRECTORY 335 // returns a pointer to the directory to put config files in (if you dont want to use winamp.ini)
556+
557+#define IPC_SPAWNBUTTONPOPUP 361 // param =
558+// 0 = eject
559+// 1 = previous
560+// 2 = next
561+// 3 = pause
562+// 4 = play
563+// 5 = stop
564+
565+#define IPC_OPENURLBOX 360 // pass a HWND to a parent, returns a HGLOBAL that needs to be freed with GlobalFree(), if successful
566+#define IPC_OPENFILEBOX 362 // pass a HWND to a parent
567+#define IPC_OPENDIRBOX 363 // pass a HWND to a parent
568+
569+// pass an HWND to a parent. call this if you take over the whole UI so that the dialogs are not appearing on the
570+// bottom right of the screen since the main winamp window is at 3000x3000, call again with NULL to reset
571+#define IPC_SETDIALOGBOXPARENT 364
572+
573+
574+
575+// pass 0 for a copy of the skin HBITMAP
576+// pass 1 for name of font to use for playlist editor likeness
577+// pass 2 for font charset
578+// pass 3 for font size
579+#define IPC_GET_GENSKINBITMAP 503
580+
581+
582+#define IPC_GET_EMBEDIF 505 // pass an embedWindowState
583+// returns an HWND embedWindow(embedWindowState *); if the data is NULL, otherwise returns the HWND directly
584+typedef struct
585+{
586+ HWND me; //hwnd of the window
587+
588+ int flags;
589+
590+ RECT r;
591+
592+ void *user_ptr; // for application use
593+
594+ int extra_data[64]; // for internal winamp use
595+} embedWindowState;
596+
597+#define EMBED_FLAGS_NORESIZE 1 // set this bit in embedWindowState.flags to keep window from being resizable
598+#define EMBED_FLAGS_NOTRANSPARENCY 2 // set this bit in embedWindowState.flags to make gen_ff turn transparency off for this wnd
599+
600+
601+#define IPC_EMBED_ENUM 532
602+typedef struct embedEnumStruct
603+{
604+ int (*enumProc)(embedWindowState *ws, struct embedEnumStruct *param); // return 1 to abort
605+ int user_data; // or more :)
606+} embedEnumStruct;
607+ // pass
608+
609+#define IPC_EMBED_ISVALID 533
610+
611+#define IPC_CONVERTFILE 506
612+/* (requires Winamp 2.92+)
613+** Converts a given file to a different format (PCM, MP3, etc...)
614+** To use, pass a pointer to a waFileConvertStruct struct
615+** This struct can be either on the heap or some global
616+** data, but NOT on the stack. At least, until the conversion is done.
617+**
618+** eg: SendMessage(hwnd_winamp,WM_WA_IPC,&myConvertStruct,IPC_CONVERTFILE);
619+**
620+** Return value:
621+** 0: Can't start the conversion. Look at myConvertStruct->error for details.
622+** 1: Conversion started. Status messages will be sent to the specified callbackhwnd.
623+** Be sure to call IPC_CONVERTFILE_END when your callback window receives the
624+** IPC_CB_CONVERT_DONE message.
625+*/
626+typedef struct
627+{
628+ char *sourcefile; // "c:\\source.mp3"
629+ char *destfile; // "c:\\dest.pcm"
630+ int destformat[8]; // like 'PCM ',srate,nch,bps
631+ HWND callbackhwnd; // window that will receive the IPC_CB_CONVERT notification messages
632+
633+ //filled in by winamp.exe
634+ char *error; //if IPC_CONVERTFILE returns 0, the reason will be here
635+
636+ int bytes_done; //you can look at both of these values for speed statistics
637+ int bytes_total;
638+ int bytes_out;
639+
640+ int killswitch; // don't set it manually, use IPC_CONVERTFILE_END
641+ int extra_data[64]; // for internal winamp use
642+} convertFileStruct;
643+
644+#define IPC_CONVERTFILE_END 507
645+/* (requires Winamp 2.92+)
646+** Stop/ends a convert process started from IPC_CONVERTFILE
647+** You need to call this when you receive the IPC_CB_CONVERTDONE message or when you
648+** want to abort a conversion process
649+**
650+** eg: SendMessage(hwnd_winamp,WM_WA_IPC,&myConvertStruct,IPC_CONVERTFILE_END);
651+**
652+** No return value
653+*/
654+
655+typedef struct {
656+ HWND hwndParent;
657+ int format;
658+
659+ //filled in by winamp.exe
660+ HWND hwndConfig;
661+ int extra_data[8];
662+} convertConfigStruct;
663+#define IPC_CONVERT_CONFIG 508
664+#define IPC_CONVERT_CONFIG_END 509
665+
666+typedef struct
667+{
668+ void (*enumProc)(int user_data, const char *desc, int fourcc);
669+ int user_data;
670+} converterEnumFmtStruct;
671+#define IPC_CONVERT_CONFIG_ENUMFMTS 510
672+/* (requires Winamp 2.92+)
673+*/
674+
675+
676+typedef struct
677+{
678+ char cdletter;
679+ char *playlist_file;
680+ HWND callback_hwnd;
681+
682+ //filled in by winamp.exe
683+ char *error;
684+} burnCDStruct;
685+#define IPC_BURN_CD 511
686+/* (requires Winamp 5.0+)
687+*/
688+
689+typedef struct
690+{
691+ convertFileStruct *cfs;
692+ int priority;
693+} convertSetPriority;
694+#define IPC_CONVERT_SET_PRIORITY 512
695+
696+typedef struct
697+{
698+ char *filename;
699+ char *title; // 2048 bytes
700+ int length;
701+ int force_useformatting; // can set this to 1 if you want to force a url to use title formatting shit
702+} waHookTitleStruct;
703+// return TRUE if you hook this
704+#define IPC_HOOK_TITLES 850
705+
706+#define IPC_GETSADATAFUNC 800
707+// 0: returns a char *export_sa_get() that returns 150 bytes of data
708+// 1: returns a export_sa_setreq(int want);
709+
710+#define IPC_ISMAINWNDVISIBLE 900
711+
712+
713+#define IPC_SETPLEDITCOLORS 920
714+typedef struct
715+{
716+ int numElems;
717+ int *elems;
718+ HBITMAP bm; // set if you want to override
719+} waSetPlColorsStruct;
720+
721+
722+// the following IPC use waSpawnMenuParms as parameter
723+#define IPC_SPAWNEQPRESETMENU 933
724+#define IPC_SPAWNFILEMENU 934 //menubar
725+#define IPC_SPAWNOPTIONSMENU 935 //menubar
726+#define IPC_SPAWNWINDOWSMENU 936 //menubar
727+#define IPC_SPAWNHELPMENU 937 //menubar
728+#define IPC_SPAWNPLAYMENU 938 //menubar
729+#define IPC_SPAWNPEFILEMENU 939 //menubar
730+#define IPC_SPAWNPEPLAYLISTMENU 940 //menubar
731+#define IPC_SPAWNPESORTMENU 941 //menubar
732+#define IPC_SPAWNPEHELPMENU 942 //menubar
733+#define IPC_SPAWNMLFILEMENU 943 //menubar
734+#define IPC_SPAWNMLVIEWMENU 944 //menubar
735+#define IPC_SPAWNMLHELPMENU 945 //menubar
736+#define IPC_SPAWNPELISTOFPLAYLISTS 946
737+
738+typedef struct
739+{
740+ HWND wnd;
741+ int xpos; // in screen coordinates
742+ int ypos;
743+} waSpawnMenuParms;
744+
745+// waSpawnMenuParms2 is used by the menubar submenus
746+typedef struct
747+{
748+ HWND wnd;
749+ int xpos; // in screen coordinates
750+ int ypos;
751+ int width;
752+ int height;
753+} waSpawnMenuParms2;
754+
755+
756+// system tray sends this (you might want to simulate it)
757+#define WM_WA_SYSTRAY WM_USER+1
758+
759+// input plugins send this when they are done playing back
760+#define WM_WA_MPEG_EOF WM_USER+2
761+
762+
763+
764+//// video stuff
765+
766+#define IPC_IS_PLAYING_VIDEO 501 // returns >1 if playing, 0 if not, 1 if old version (so who knows):)
767+#define IPC_GET_IVIDEOOUTPUT 500 // see below for IVideoOutput interface
768+#define VIDEO_MAKETYPE(A,B,C,D) ((A) | ((B)<<8) | ((C)<<16) | ((D)<<24))
769+#define VIDUSER_SET_INFOSTRING 0x1000
770+#define VIDUSER_GET_VIDEOHWND 0x1001
771+#define VIDUSER_SET_VFLIP 0x1002
772+
773+#ifndef NO_IVIDEO_DECLARE
774+#ifdef __cplusplus
775+
776+class VideoOutput;
777+class SubsItem;
778+
779+typedef struct {
780+ unsigned char* baseAddr;
781+ long rowBytes;
782+} YV12_PLANE;
783+
784+typedef struct {
785+ YV12_PLANE y;
786+ YV12_PLANE u;
787+ YV12_PLANE v;
788+} YV12_PLANES;
789+
790+class IVideoOutput
791+{
792+ public:
793+ virtual ~IVideoOutput() { }
794+ virtual int open(int w, int h, int vflip, double aspectratio, unsigned int fmt)=0;
795+ virtual void setcallback(LRESULT (*msgcallback)(void *token, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam), void *token) { }
796+ virtual void close()=0;
797+ virtual void draw(void *frame)=0;
798+ virtual void drawSubtitle(SubsItem *item) { }
799+ virtual void showStatusMsg(const char *text) { }
800+ virtual int get_latency() { return 0; }
801+ virtual void notifyBufferState(int bufferstate) { } /* 0-255*/
802+
803+ virtual int extended(int param1, int param2, int param3) { return 0; } // Dispatchable, eat this!
804+};
805+#endif //cplusplus
806+#endif//NO_IVIDEO_DECLARE
807+
808+// these messages are callbacks that you can grab by subclassing the winamp window
809+
810+// wParam =
811+#define IPC_CB_WND_EQ 0 // use one of these for the param
812+#define IPC_CB_WND_PE 1
813+#define IPC_CB_WND_MB 2
814+#define IPC_CB_WND_VIDEO 3
815+#define IPC_CB_WND_MAIN 4
816+
817+#define IPC_CB_ONSHOWWND 600
818+#define IPC_CB_ONHIDEWND 601
819+
820+#define IPC_CB_GETTOOLTIP 602
821+
822+#define IPC_CB_MISC 603
823+ #define IPC_CB_MISC_TITLE 0
824+ #define IPC_CB_MISC_VOLUME 1 // volume/pan
825+ #define IPC_CB_MISC_STATUS 2
826+ #define IPC_CB_MISC_EQ 3
827+ #define IPC_CB_MISC_INFO 4
828+ #define IPC_CB_MISC_VIDEOINFO 5
829+
830+#define IPC_CB_CONVERT_STATUS 604 // param value goes from 0 to 100 (percent)
831+#define IPC_CB_CONVERT_DONE 605
832+
833+#define IPC_ADJUST_FFWINDOWSMENUPOS 606
834+/* (requires Winamp 2.9+)
835+** int newpos=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_FFWINDOWSMENUPOS);
836+** moves where winamp expects the freeform windows in the menubar windows main menu. Useful if you wish to insert a
837+** menu item above extra freeform windows.
838+*/
839+
840+#define IPC_ISDOUBLESIZE 608
841+
842+#define IPC_ADJUST_FFOPTIONSMENUPOS 609
843+/* (requires Winamp 2.9+)
844+** int newpos=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_FFOPTIONSMENUPOS);
845+** moves where winamp expects the freeform preferences item in the menubar windows main menu. Useful if you wish to insert a
846+** menu item above preferences item.
847+*/
848+
849+#define IPC_GETTIMEDISPLAYMODE 610 // returns 0 if displaying elapsed time or 1 if displaying remaining time
850+
851+#define IPC_SETVISWND 611 // param is hwnd, setting this allows you to receive ID_VIS_NEXT/PREVOUS/RANDOM/FS wm_commands
852+#define ID_VIS_NEXT 40382
853+#define ID_VIS_PREV 40383
854+#define ID_VIS_RANDOM 40384
855+#define ID_VIS_FS 40389
856+#define ID_VIS_CFG 40390
857+#define ID_VIS_MENU 40391
858+
859+#define IPC_GETVISWND 612 // returns the vis cmd handler hwnd
860+#define IPC_ISVISRUNNING 613
861+#define IPC_CB_VISRANDOM 628 // param is status of random
862+
863+#define IPC_SETIDEALVIDEOSIZE 614 // sent by winamp to winamp, trap it if you need it. width=HIWORD(param), height=LOWORD(param)
864+
865+#define IPC_GETSTOPONVIDEOCLOSE 615
866+#define IPC_SETSTOPONVIDEOCLOSE 616
867+
868+typedef struct {
869+ HWND hwnd;
870+ int uMsg;
871+ int wParam;
872+ int lParam;
873+} transAccelStruct;
874+
875+#define IPC_TRANSLATEACCELERATOR 617
876+
877+typedef struct {
878+ int cmd;
879+ int x;
880+ int y;
881+ int align;
882+} windowCommand; // send this as param to an IPC_PLCMD, IPC_MBCMD, IPC_VIDCMD
883+
884+#define IPC_CB_ONTOGGLEAOT 618
885+
886+#define IPC_GETPREFSWND 619
887+
888+#define IPC_SET_PE_WIDTHHEIGHT 620 // data is a pointer to a POINT structure that holds width & height
889+
890+#define IPC_GETLANGUAGEPACKINSTANCE 621
891+
892+#define IPC_CB_PEINFOTEXT 622 // data is a string, ie: "04:21/45:02"
893+
894+#define IPC_CB_OUTPUTCHANGED 623 // output plugin was changed in config
895+
896+#define IPC_GETOUTPUTPLUGIN 625
897+
898+#define IPC_SETDRAWBORDERS 626
899+#define IPC_DISABLESKINCURSORS 627
900+#define IPC_CB_RESETFONT 629
901+
902+#define IPC_IS_FULLSCREEN 630 // returns 1 if video or vis is in fullscreen mode
903+#define IPC_SET_VIS_FS_FLAG 631 // a vis should send this message with 1/as param to notify winamp that it has gone to or has come back from fullscreen mode
904+
905+#define IPC_SHOW_NOTIFICATION 632
906+
907+#define IPC_GETSKININFO 633
908+
909+// >>>>>>>>>>> Next is 634
910+
911+#define IPC_PLCMD 1000
912+
913+#define PLCMD_ADD 0
914+#define PLCMD_REM 1
915+#define PLCMD_SEL 2
916+#define PLCMD_MISC 3
917+#define PLCMD_LIST 4
918+
919+#define IPC_MBCMD 1001
920+
921+#define MBCMD_BACK 0
922+#define MBCMD_FORWARD 1
923+#define MBCMD_STOP 2
924+#define MBCMD_RELOAD 3
925+#define MBCMD_MISC 4
926+
927+#define IPC_VIDCMD 1002
928+
929+#define VIDCMD_FULLSCREEN 0
930+#define VIDCMD_1X 1
931+#define VIDCMD_2X 2
932+#define VIDCMD_LIB 3
933+#define VIDPOPUP_MISC 4
934+
935+#define IPC_MBURL 1003 //sets the URL
936+#define IPC_MBGETCURURL 1004 //copies the current URL into wParam (have a 4096 buffer ready)
937+#define IPC_MBGETDESC 1005 //copies the current URL description into wParam (have a 4096 buffer ready)
938+#define IPC_MBCHECKLOCFILE 1006 //checks that the link file is up to date (otherwise updates it). wParam=parent HWND
939+#define IPC_MBREFRESH 1007 //refreshes the "now playing" view in the library
940+#define IPC_MBGETDEFURL 1008 //copies the default URL into wParam (have a 4096 buffer ready)
941+
942+#define IPC_STATS_LIBRARY_ITEMCNT 1300 // updates library count status
943+
944+// IPC 2000-3000 reserved for freeform messages, see gen_ff/ff_ipc.h
945+#define IPC_FF_FIRST 2000
946+#define IPC_FF_LAST 3000
947+
948+#define IPC_GETDROPTARGET 3001
949+
950+#define IPC_PLAYLIST_MODIFIED 3002 // sent to main wnd whenever the playlist is modified
951+
952+#define IPC_PLAYING_FILE 3003 // sent to main wnd with the file as parm whenever a file is played
953+#define IPC_FILE_TAG_MAY_HAVE_UPDATED 3004 // sent to main wnd with the file as parm whenever a file tag might be updated
954+
955+
956+#define IPC_ALLOW_PLAYTRACKING 3007
957+// send nonzero to allow, zero to disallow
958+
959+#define IPC_HOOK_OKTOQUIT 3010 // return 0 to abort a quit, nonzero if quit is OK
960+
961+#define IPC_WRITECONFIG 3011 // pass 2 to write all, 1 to write playlist + common, 0 to write common+less common
962+
963+// pass a string to be the name to register, and returns a value > 65536, which is a unique value you can use
964+// for custom WM_WA_IPC messages.
965+#define IPC_REGISTER_WINAMP_IPCMESSAGE 65536
966+
967+/**************************************************************************/
968+
969+/*
970+** Finally there are some WM_COMMAND messages that you can use to send
971+** Winamp misc commands.
972+**
973+** To send these, use:
974+**
975+** SendMessage(hwnd_winamp, WM_COMMAND,command_name,0);
976+*/
977+
978+#define WINAMP_OPTIONS_EQ 40036 // toggles the EQ window
979+#define WINAMP_OPTIONS_PLEDIT 40040 // toggles the playlist window
980+#define WINAMP_VOLUMEUP 40058 // turns the volume up a little
981+#define WINAMP_VOLUMEDOWN 40059 // turns the volume down a little
982+#define WINAMP_FFWD5S 40060 // fast forwards 5 seconds
983+#define WINAMP_REW5S 40061 // rewinds 5 seconds
984+
985+// the following are the five main control buttons, with optionally shift
986+// or control pressed
987+// (for the exact functions of each, just try it out)
988+#define WINAMP_BUTTON1 40044
989+#define WINAMP_BUTTON2 40045
990+#define WINAMP_BUTTON3 40046
991+#define WINAMP_BUTTON4 40047
992+#define WINAMP_BUTTON5 40048
993+#define WINAMP_BUTTON1_SHIFT 40144
994+#define WINAMP_BUTTON2_SHIFT 40145
995+#define WINAMP_BUTTON3_SHIFT 40146
996+#define WINAMP_BUTTON4_SHIFT 40147
997+#define WINAMP_BUTTON5_SHIFT 40148
998+#define WINAMP_BUTTON1_CTRL 40154
999+#define WINAMP_BUTTON2_CTRL 40155
1000+#define WINAMP_BUTTON3_CTRL 40156
1001+#define WINAMP_BUTTON4_CTRL 40157
1002+#define WINAMP_BUTTON5_CTRL 40158
1003+
1004+#define WINAMP_FILE_PLAY 40029 // pops up the load file(s) box
1005+#define WINAMP_FILE_DIR 40187 // pops up the load directory box
1006+#define WINAMP_OPTIONS_PREFS 40012 // pops up the preferences
1007+#define WINAMP_OPTIONS_AOT 40019 // toggles always on top
1008+#define WINAMP_HELP_ABOUT 40041 // pops up the about box :)
1009+
1010+#define ID_MAIN_PLAY_AUDIOCD1 40323 // starts playing the audio CD in the first CD reader
1011+#define ID_MAIN_PLAY_AUDIOCD2 40323 // plays the 2nd
1012+#define ID_MAIN_PLAY_AUDIOCD3 40323 // plays the 3nd
1013+#define ID_MAIN_PLAY_AUDIOCD4 40323 // plays the 4nd
1014+
1015+// IDs 42000 to 45000 are reserved for gen_ff
1016+// IDs from 45000 to 57000 are reserved for library
1017+
1018+#endif//_WA_IPC_H_
1019+
1020+/*
1021+** EOF.. Enjoy.
1022+*/
\ No newline at end of file
--- src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_4_SDK72/README (nonexistent)
+++ src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_4_SDK72/README (revision 69)
@@ -0,0 +1,48 @@
1+foo_mixi_feat_winamp 0.0.0.7,
2+Mixi Music plugin for Winamp, bridge component.
3+Copyright (C) 2006,2007 Yossiepon Oniichan, All Rights Reserved.
4+
5+
6+* Copying
7+
8+ This program is free software: you can redistribute it and/or modify
9+ it under the terms of the GNU Lesser General Public License as
10+ published by the Free Software Foundation, either version 3 of
11+ the License, or (at your option) any later version.
12+
13+ This program is distributed in the hope that it will be useful,
14+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+ GNU Lesser General Public License for more details.
17+
18+ You should have received a copy of the GNU Lesser General Public License
19+ along with this program. If not, see <http://www.gnu.org/licenses/>.
20+
21+ Please see the file COPYING and COPYING.LESSER in this directory for
22+ full copyright information.
23+
24+
25+* Compilation and Installation
26+
27+ Please read INSTALL for compilation instructions.
28+
29+
30+* See also
31+
32+ The latest version of foo_mixi_feat_winamp can be obtained at
33+ http://foo-mixi.sourceforge.net/
34+
35+ There are two mailing lists
36+ foo-mixi-users@lists.sourceforge.jp
37+ foo-mixi-dev@lists.sourceforge.jp
38+
39+ please follow the link in
40+
41+ http://sourceforge.jp/projects/foo-mixi
42+
43+ to subscribe to the lists or to visit the archives.
44+
45+
46+Enjoy,
47+
48+Yossiepon Oniichan (yoshy at users.sourceforge.jp) (06 November 2007)
--- src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_8_3/foo_mixi_feat_winamp.cpp (revision 68)
+++ src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_8_3/foo_mixi_feat_winamp.cpp (revision 69)
@@ -36,6 +36,7 @@
3636 typedef UIntMap::const_iterator UIntMapCIt;
3737
3838 #include "../SDK/foobar2000.h"
39+#include "../SDK/component.h"
3940 #include "../helpers/helpers.h"
4041
4142 #if 0
@@ -74,7 +75,7 @@
7475 #define CODEC_TYPE_VORBIS "Vorbis"
7576 #define CODEC_TYPE_MP3 "MP3"
7677
77-#define IS_SUPPORTED_FORMAT_BY_GEN_MIXI(codec) ( !::lstrcmpA(codec, CODEC_TYPE_VORBIS) || !::lstrcmpA(codec, CODEC_TYPE_MP3))
78+#define IS_SUPPORTED_FORMAT_BY_GEN_MIXI(codec) (!::lstrcmpA(codec, CODEC_TYPE_VORBIS) || !::lstrcmpA(codec, CODEC_TYPE_MP3))
7879
7980 #if !defined(ENABLE_MSN)
8081 #define PLUGIN_CAPTION "mixi music plugin for Winamp, bridge component"
@@ -89,7 +90,7 @@
8990 #define DUMMYAMP_HOOK_MODE _T("既存 Winamp API Emulator をフック中")
9091 #define DUMMYAMP_STANDALONE_MODE _T("単独で Winamp API をエミュレート中")
9192 #define DEBUG_SETTINGS_CAPTION "デバッグ用の設定"
92-#define PLUGIN_VERSION "0.2.0.1"
93+#define PLUGIN_VERSION "0.2.1.0"
9394
9495 #define DEFAULT_DUMMYAMP_TITLE_FORMAT "[%artist% - ]$if(%title%,%title%,%_filename%)"
9596
@@ -119,10 +120,14 @@
119120 #define FORCE_RESENT_MODE 0
120121 //#define DISABLE_KICK_GEN_MIXI_LOOP
121122
122-#define REQUIRED_MINIMUM_TIME 3
123-#define SEND_TIME_RATE_LOWERBOUND 33
124-#define REQUIRED_MAXIMUM_TIME 20
123+#define GEN_MIXI_REQUIRED_SECONDS 6
124+#define GEN_MIXI_TRIGGER_SECONDS 6
125+#define GEN_MIXI_MARGIN_SECONDS 0
125126
127+#define REQUIRED_MINIMUM_TIME 8
128+#define SEND_TIME_RATE_LOWERBOUND 0
129+#define REQUIRED_MAXIMUM_TIME 0
130+
126131 #define CONTROL_SEND_TIMING
127132
128133 //#define ENABLE_MSN
@@ -185,6 +190,7 @@
185190
186191 tstring GetErrorMessage(DWORD errCode);
187192 void putLogError(LPCTSTR pMethod, LPCTSTR pErrMsg, DWORD dwErrCode);
193+void setDlgVersionInfo(HWND wnd, UINT idc_version, UINT idc_build);
188194 void DebugPrint(int severity, LPCTSTR lpszFormat, ...);
189195 void DebugPrintDBCS(int severity, LPCSTR lpszFormat, ...);
190196 void DebugPrint8(int severity, LPCSTR lpszFormat, ...);
@@ -247,7 +253,7 @@
247253 static string_utf8_from_os g_pluginCaption8(_T(PLUGIN_CAPTION_JP));
248254 static string_utf8_from_os g_pluginVersion8(_T(PLUGIN_VERSION));
249255 static string_utf8_from_os g_pluginAbout8(
250- _T(PLUGIN_CAPTION_JP) _T(" ") _T(PLUGIN_VERSION) _T("\nCopyright (C) 2006-2008 Yossiepon Oniichan, All Rights Reserved."));
256+ _T(PLUGIN_CAPTION_JP) _T(" ") _T(PLUGIN_VERSION) _T("\nCopyright (C) 2006-2009 Yossiepon Oniichan, All Rights Reserved."));
251257
252258 DECLARE_COMPONENT_VERSION(g_pluginCaption8, g_pluginVersion8, g_pluginAbout8);
253259
@@ -979,7 +985,7 @@
979985 #else
980986 if(true) {
981987 #endif
982- return 0;
988+ return GEN_MIXI_REQUIRED_SECONDS;
983989 }
984990 return m_playLength;
985991 }
@@ -2418,7 +2424,7 @@
24182424 {
24192425 HANDLE hDirChangeNotify = DummyAmp::getInstance()->getDirChangeNotifyHandle();
24202426
2421- TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_ISPLAYING / status %d"), playStatus);
2427+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_ISPLAYING / status [%d]"), playStatus);
24222428
24232429 if(playStatus != PlayInfo::PLAY_START)
24242430 {
@@ -2470,13 +2476,13 @@
24702476 {
24712477 if(wp == IPC_GETOUTPUTTIME_PositionMSec)
24722478 {
2473- TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_GETOUTPUTTIME / position %d"), playPosition / 1000);
2479+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_GETOUTPUTTIME / position [%d sec.]"), playPosition / 1000);
24742480
24752481 return std::make_pair(true, playPosition);
24762482 }
24772483 else if(wp == IPC_GETOUTPUTTIME_TotalSec)
24782484 {
2479- TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_GETOUTPUTTIME / length %d"), playLength);
2485+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_GETOUTPUTTIME / length [%d sec.]"), playLength);
24802486 return std::make_pair(true, playLength);
24812487 }
24822488 }
@@ -2484,7 +2490,7 @@
24842490 return std::make_pair(true, -1);
24852491
24862492 case IPC_GETLISTPOS:
2487- TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_GETLISTPOS / index %d returned."), playCount);
2493+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_GETLISTPOS / index [%d]"), playCount);
24882494 return std::make_pair(true, playCount);
24892495
24902496 case IPC_GETPLAYLISTFILE:
@@ -2493,7 +2499,7 @@
24932499 if(isPlayInfoMp3Available == true)
24942500 {
24952501 DEBUG_DUMMYAMP_PROC8(
2496- "DummyAmp::innerWinampWindowProc - IPC_GETPLAYLISTFILE / #%d - path [%s] returned.",
2502+ "DummyAmp::innerWinampWindowProc - IPC_GETPLAYLISTFILE / #%d - path [%s]",
24972503 playCount, (LPCSTR)playInfoMp3Path8);
24982504
24992505 DummyAmp::getInstance()->setGetPlayListFileTime(playPosition);
@@ -2630,7 +2636,7 @@
26302636 switch(lp)
26312637 {
26322638 case IPC_ISPLAYING:
2633- TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_ISPLAYING / status %d"), rawPlayStatus);
2639+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_ISPLAYING / status [%d]"), rawPlayStatus);
26342640 return std::make_pair(true, rawPlayStatus);
26352641
26362642 case IPC_GETOUTPUTTIME:
@@ -2651,12 +2657,12 @@
26512657
26522658 if(wp == IPC_GETOUTPUTTIME_PositionMSec)
26532659 {
2654- TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_GETOUTPUTTIME / position %.3f"), rawPlayPosition / 1000.0);
2660+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_GETOUTPUTTIME / position [%.3f sec.]"), rawPlayPosition / 1000.0);
26552661 return std::make_pair(true, rawPlayPosition);
26562662 }
26572663 else if(wp == IPC_GETOUTPUTTIME_TotalSec)
26582664 {
2659- TRACE_DUMMYAMP_PROC(_T("DummyAm::outerWinampWindowProcp - IPC_GETOUTPUTTIME / length %d"), rawPlayLength);
2665+ TRACE_DUMMYAMP_PROC(_T("DummyAm::outerWinampWindowProcp - IPC_GETOUTPUTTIME / length [%d sec.]"), rawPlayLength);
26602666 return std::make_pair(true, rawPlayLength);
26612667 }
26622668
@@ -2663,17 +2669,17 @@
26632669 return std::make_pair(true, -1);
26642670
26652671 case IPC_GETLISTPOS:
2666- TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_GETLISTPOS / index %d returned."), rawPlayCount);
2672+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_GETLISTPOS / index [%d]"), rawPlayCount);
26672673 return std::make_pair(true, rawPlayCount);
26682674
26692675 case IPC_GETPLAYLISTFILE:
26702676 TRACE_DUMMYAMP_PROC8(
2671- "DummyAmp::outerWinampWindowProc - IPC_GETPLAYLISTFILE / path [%s] returned.", (LPCSTR)rawPlayInfoMp3Path8);
2677+ "DummyAmp::outerWinampWindowProc - IPC_GETPLAYLISTFILE / path [%s]", (LPCSTR)rawPlayInfoMp3Path8);
26722678 return std::make_pair(true, (LRESULT)(LPCSTR)rawPlayInfoMp3Path8);
26732679
26742680 case IPC_GETPLAYLISTTITLE:
26752681 TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_GETPLAYLISTTITLE")
2676- _T(" / title [%s] returned."), (LPCTSTR)playlistTitle.c_str());
2682+ _T(" / title [%s]"), (LPCTSTR)playlistTitle.c_str());
26772683 return std::make_pair(true, (LRESULT)(LPCSTR)playlistTitle8);
26782684
26792685 case IPC_JUMPTOTIME:
@@ -2681,7 +2687,7 @@
26812687 {
26822688 double jumpPos = wp / 1000.0;
26832689 TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_JUMPTOTIME")
2684- _T(" / jump to %.3f[sec.]"), jumpPos);
2690+ _T(" / jump to [%.3f sec.]"), jumpPos);
26852691
26862692 if(jumpPos > rawPlayLength)
26872693 {
@@ -3141,7 +3147,6 @@
31413147 TRACE_CALLBACK(_T("play_callback_mixi::resetSendTiming - called."));
31423148
31433149 m_previous_sec = -1.0;
3144- m_bPassLowerBoundTime = false;
31453150 m_bPassThesholdTime = false;
31463151 }
31473152
@@ -3149,8 +3154,15 @@
31493154 {
31503155 TRACE_CALLBACK(_T("play_callback_mixi::checkSendTiming - called."));
31513156
3157+ double lowerBoundTime = pfc_string_to_float(cfg_send_interval1);
3158+
3159+ // target track required minimum threshold seconds
3160+ if(m_song_total_sec < lowerBoundTime) return false;
3161+
3162+ // already passed threshold seconds
31523163 if(m_bPassThesholdTime == true) return false;
31533164
3165+ // set base position for elapsed seconds
31543166 if(m_previous_sec < 0.0) {
31553167 m_previous_sec = sec - 1.0;
31563168 }
@@ -3157,35 +3169,16 @@
31573169
31583170 double elapsedTime = sec - m_previous_sec;
31593171
3160- double lowerBoundTime = pfc_string_to_float(cfg_send_interval1);
31613172 double thresholdTime1 = m_song_total_sec * pfc_string_to_float(cfg_send_interval2) / 100.0;
31623173 double thresholdTime2 = pfc_string_to_float(cfg_send_interval3);
3163- double thresholdTime = min(thresholdTime1, thresholdTime2);
3174+ double thresholdTime = min(thresholdTime1, thresholdTime2) - GEN_MIXI_TRIGGER_SECONDS;
31643175
3165-#if 0
3166- if(lowerBoundTime < 10.0) lowerBoundTime = 10.0;
3167-
3168- if(thresholdTime < 10.0) thresholdTime = 10.0;
3169-#endif
3170- if(thresholdTime < lowerBoundTime) thresholdTime = lowerBoundTime;
3171-
3172- if(m_bPassLowerBoundTime == false)
3176+ if(m_bPassThesholdTime == false)
31733177 {
3174- TRACE_CALLBACK(_T("play_callback_mixi::checkSendTiming - pos: %5.1f, lowerBound:%5.1f, elapse:%5.1f"),
3175- sec, lowerBoundTime, elapsedTime);
3176-
3177- if(lowerBoundTime <= elapsedTime + 3) // add gen_mixi response time
3178- {
3179- m_bPassLowerBoundTime = true;
3180- }
3181- }
3182-
3183- if((m_bPassLowerBoundTime == true) && (m_bPassThesholdTime == false))
3184- {
31853178 TRACE_CALLBACK(_T("play_callback_mixi::checkSendTiming - pos: %5.1f, threshold:%5.1f, elapse:%5.1f"),
31863179 sec, thresholdTime, elapsedTime);
31873180
3188- if(thresholdTime <= elapsedTime + 3) // add gen_mixi response time
3181+ if(thresholdTime <= elapsedTime + GEN_MIXI_MARGIN_SECONDS) // add gen_mixi response time
31893182 {
31903183 m_bPassThesholdTime = true;
31913184 return true;
@@ -3212,8 +3205,10 @@
32123205 return ;
32133206 }
32143207
3208+#if defined(CONTROL_SEND_TIMING)
32153209 // reset send timing
32163210 resetSendTiming();
3211+#endif
32173212
32183213 // clear raw playinfo on dummyamp (no resent mode)
32193214 DummyAmp::getInstance()->getRawPlayInfo().clearPlayInfo(false);
@@ -3282,7 +3277,6 @@
32823277 double m_previous_sec;
32833278 double m_song_total_sec;
32843279
3285- bool m_bPassLowerBoundTime;
32863280 bool m_bPassThesholdTime;
32873281
32883282 bool m_isDynamic;
@@ -3498,21 +3492,20 @@
34983492 uSendMessage(hSendInterval2, TBM_SETRANGE, (WPARAM)FALSE, (LPARAM)MAKELONG(SEND_TIME_RATE_LOWERBOUND, 100));
34993493 uSendMessage(hSendInterval2, TBM_SETLINESIZE, (WPARAM)0, (LPARAM)1);
35003494 uSendMessage(hSendInterval2, TBM_SETPAGESIZE, (WPARAM)0, (LPARAM)5);
3501- uSendMessage(hSendInterval2, TBM_SETTICFREQ, (WPARAM)5, (LPARAM)0);
3495+ uSendMessage(hSendInterval2, TBM_SETTICFREQ, (WPARAM)10, (LPARAM)0);
35023496
35033497 double pos2 = pfc_string_to_float(cfg_send_interval2);
35043498 uSendMessage(hSendInterval2, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos2);
35053499
3506- uSendMessage(hSendInterval3, TBM_SETRANGE, (WPARAM)FALSE, (LPARAM)MAKELONG(REQUIRED_MAXIMUM_TIME, 9999));
3507- uSendMessage(hSendInterval3, TBM_SETLINESIZE, (WPARAM)0, (LPARAM)10);
3508- uSendMessage(hSendInterval3, TBM_SETPAGESIZE, (WPARAM)0, (LPARAM)100);
3509- uSendMessage(hSendInterval3, TBM_SETTICFREQ, (WPARAM)1000, (LPARAM)0);
3500+ uSendMessage(hSendInterval3, TBM_SETRANGE, (WPARAM)FALSE, (LPARAM)MAKELONG(REQUIRED_MAXIMUM_TIME / 60, 165));
3501+ uSendMessage(hSendInterval3, TBM_SETLINESIZE, (WPARAM)0, (LPARAM)1);
3502+ uSendMessage(hSendInterval3, TBM_SETPAGESIZE, (WPARAM)0, (LPARAM)5);
3503+ uSendMessage(hSendInterval3, TBM_SETTICFREQ, (WPARAM)20, (LPARAM)0);
35103504
35113505 double pos3 = pfc_string_to_float(cfg_send_interval3);
3512- uSendMessage(hSendInterval3, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos3);
3506+ uSendMessage(hSendInterval3, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos3 / 60);
35133507
3514- uSetDlgItemText(wnd, IDC_VERSION, PLUGIN_CAPTION " " PLUGIN_VERSION);
3515- uSetDlgItemText(wnd, IDC_BUILD, "build on " __DATE__ ", " __TIME__);
3508+ setDlgVersionInfo(wnd, IDC_VERSION, IDC_BUILD);
35163509 }
35173510 break;
35183511
@@ -3633,9 +3626,9 @@
36333626 }
36343627 else if(hTrackBar == hSendInterval3)
36353628 {
3636- setDlgItemFloat(wnd, IDC_SEND_INTERVAL_3RD, (double)lPos);
3629+ setDlgItemFloat(wnd, IDC_SEND_INTERVAL_3RD, (double)lPos * 60);
36373630 string8 pos;
3638- float2String(pos, (double)lPos);
3631+ float2String(pos, (double)lPos * 60);
36393632 cfg_send_interval3 = pos;
36403633 }
36413634 }
@@ -3797,8 +3790,7 @@
37973790 uEnableWindow(hControlWnd, false);
37983791 }
37993792
3800- uSetDlgItemText(wnd, IDC_VERSION_ADVANCED, PLUGIN_CAPTION " " PLUGIN_VERSION);
3801- uSetDlgItemText(wnd, IDC_BUILD_ADVANCED, "build on " __DATE__ ", " __TIME__);
3793+ setDlgVersionInfo(wnd, IDC_VERSION_ADVANCED, IDC_BUILD_ADVANCED);
38023794 }
38033795 break;
38043796
@@ -3901,37 +3893,43 @@
39013893 {
39023894 bool rebootNeeded = false;
39033895
3904- if(nOldDummyMp3Location != -1)
3896+ do
39053897 {
3906- if(nOldDummyMp3Location != cfg_dummy_mp3_location)
3898+ if(nOldDummyMp3Location != -1)
39073899 {
3900+ if(nOldDummyMp3Location != cfg_dummy_mp3_location)
3901+ {
3902+ int nRes = ::MessageBox(
3903+ NULL, _T("ダミーMP3ファイルの生成場所の変更は、foobar2000本体の再起動後に有効になります。\n\n")
3904+ _T("今すぐ、foobar2000をシャットダウンしますか?"),
3905+ _T(PLUGIN_CAPTION), MB_YESNO | MB_ICONEXCLAMATION);
3906+
3907+ if(nRes == IDYES) {
3908+ rebootNeeded = true;
3909+ break;
3910+ } else {
3911+ rebootNeeded = false;
3912+ }
3913+ }
3914+ }
3915+
3916+ if(::strcmp(oldGenMixiPath, cfg_gen_mixi_path) != 0)
3917+ {
39083918 int nRes = ::MessageBox(
3909- NULL, _T("ダミーMP3ファイルの生成場所の変更は、foobar2000本体の再起動後に有効になります。\n\n")
3919+ NULL, GEN_MIXI_FILE_NAME _T(" の配置場所の変更は、foobar2000本体の再起動後に有効になります。\n\n")
39103920 _T("今すぐ、foobar2000をシャットダウンしますか?"),
39113921 _T(PLUGIN_CAPTION), MB_YESNO | MB_ICONEXCLAMATION);
39123922
39133923 if(nRes == IDYES) {
39143924 rebootNeeded = true;
3925+ break;
39153926 } else {
39163927 rebootNeeded = false;
39173928 }
39183929 }
3919- }
39203930
3921- if(::strcmp(oldGenMixiPath, cfg_gen_mixi_path) != 0)
3922- {
3923- int nRes = ::MessageBox(
3924- NULL, GEN_MIXI_FILE_NAME _T(" の配置場所の変更は、foobar2000本体の再起動後に有効になります。\n\n")
3925- _T("今すぐ、foobar2000をシャットダウンしますか?"),
3926- _T(PLUGIN_CAPTION), MB_YESNO | MB_ICONEXCLAMATION);
3931+ } while(0);
39273932
3928- if(nRes == IDYES) {
3929- rebootNeeded = true;
3930- } else {
3931- rebootNeeded = false;
3932- }
3933- }
3934-
39353933 nOldDummyMp3Location = (int)cfg_dummy_mp3_location;
39363934 oldGenMixiPath = cfg_gen_mixi_path;
39373935
@@ -4029,8 +4027,7 @@
40294027 uSendDlgItemMessage(wnd, IDC_DEBUG_PLUGIN, CB_SETCURSEL, (int)cfg_debug_plugin, 0);
40304028 uSendDlgItemMessage(wnd, IDC_DEBUG_CALLBACK, CB_SETCURSEL, (int)cfg_debug_callback, 0);
40314029
4032- uSetDlgItemText(wnd, IDC_VERSION_DEBUG, PLUGIN_CAPTION " " PLUGIN_VERSION);
4033- uSetDlgItemText(wnd, IDC_BUILD_DEBUG, "build on " __DATE__ ", " __TIME__);
4030+ setDlgVersionInfo(wnd, IDC_VERSION_DEBUG, IDC_BUILD_DEBUG);
40344031 }
40354032 break;
40364033
@@ -4209,6 +4206,17 @@
42094206 LOG_ERROR(_T("%s - コード: %08x, 理由: %s"), pMethod, dwErrCode, errMsg.c_str());
42104207 }
42114208
4209+void setDlgVersionInfo(HWND wnd, UINT idc_version, UINT idc_build) {
4210+
4211+ StrDBCS64K version;
4212+
4213+ sprintf_s(version, sizeof(StrDBCS64K), PLUGIN_CAPTION " " PLUGIN_VERSION " with SDK%d (compatible%d)",
4214+ foobar2000_client::FOOBAR2000_CLIENT_VERSION, foobar2000_client::FOOBAR2000_CLIENT_VERSION_COMPATIBLE);
4215+
4216+ uSetDlgItemText(wnd, idc_version, version);
4217+ uSetDlgItemText(wnd, idc_build, "build on " __DATE__ ", " __TIME__);
4218+}
4219+
42124220 void DebugPrint(int severity, LPCTSTR lpszFormat, ...)
42134221 {
42144222 static Str64K buf;
--- src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_8_3/resource.h (revision 68)
+++ src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_8_3/resource.h (revision 69)
@@ -40,6 +40,11 @@
4040 #define IDC_DISABLE_ANSI_TRANS 1032
4141 #define IDC_ENABLE_EXT_IPC_PROC 1033
4242 #define IDC_DUMMYAMP_FRAME 1034
43+#define IDC_ENABLE_STREAMING_FILE 1035
44+#define IDC_NO_ARTIST_NAME 1036
45+#define IDC_NO_TITLE_NAME 1037
46+#define IDC_NO_ALBUM_NAME 1038
47+#define IDC_NO_GENRE_NAME 1039
4348
4449 // Next default values for new objects
4550 //
@@ -47,7 +52,7 @@
4752 #ifndef APSTUDIO_READONLY_SYMBOLS
4853 #define _APS_NEXT_RESOURCE_VALUE 104
4954 #define _APS_NEXT_COMMAND_VALUE 40001
50-#define _APS_NEXT_CONTROL_VALUE 1035
55+#define _APS_NEXT_CONTROL_VALUE 1040
5156 #define _APS_NEXT_SYMED_VALUE 101
5257 #endif
5358 #endif
--- src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_X_SDK73/foo_mixi_feat_winamp.cpp (nonexistent)
+++ src/foo_mixi_feat_winamp/branches/stable-0.2/foo_mixi_feat_winamp_for_fb2k_0_9_X_SDK73/foo_mixi_feat_winamp.cpp (revision 69)
@@ -0,0 +1,4317 @@
1+#define BUILD_UNICODE
2+
3+#if defined(BUILD_UNICODE)
4+#if !defined(UNICODE)
5+#define _UNICODE
6+#define UNICODE
7+#endif
8+#endif
9+
10+#if defined(UNICODE) && !defined(BUILD_UNICODE)
11+#define BUILD_UNICODE
12+#endif
13+
14+#define LONG_PTR_TO_WNDPROC(p) (reinterpret_cast<WNDPROC>(p))
15+#define WNDPROC_TO_LONG_PTR(p) (reinterpret_cast<LONG_PTR>(p))
16+
17+#include <windows.h>
18+#include <lmcons.h>
19+#include <process.h>
20+#include <shlobj.h>
21+
22+#include <string>
23+#include <vector>
24+#include <map>
25+
26+typedef std::vector<std::string> Strings;
27+typedef Strings::iterator StringsIt;
28+typedef Strings::const_iterator StringsCIt;
29+
30+typedef std::map<std::string, std::string> StringMap;
31+typedef StringMap::iterator StringMapIt;
32+typedef StringMap::const_iterator StringMapCIt;
33+
34+typedef std::map<std::string, UINT> UIntMap;
35+typedef UIntMap::iterator UIntMapIt;
36+typedef UIntMap::const_iterator UIntMapCIt;
37+
38+#include "../SDK/foobar2000.h"
39+#include "../SDK/component.h"
40+#include "../helpers/helpers.h"
41+
42+#if 0
43+#include <wx/string.h>
44+#endif
45+
46+#include "GEN.h"
47+#include "wa_ipc.h"
48+
49+#if 0
50+#define ID3LIB_LINKOPTION 3
51+#include <id3/tag.h>
52+#include <id3/misc_support.h>
53+#endif
54+
55+#include "resource.h"
56+
57+#if defined(_FOOBAR2000_UTF8API_H_)
58+# define FB2K_MAJOR_VERSION 8
59+#else
60+# define FB2K_MAJOR_VERSION 9
61+#endif
62+
63+#define IS_FB2K_VER08 (FB2K_MAJOR_VERSION == 8)
64+#define IS_FB2K_VER09 (FB2K_MAJOR_VERSION == 9)
65+
66+#define FB2K_COMPONENTS_DIR _T("components\\")
67+#define GEN_MIXI_FILE_NAME _T("gen_mixi_for_winamp.dll")
68+#define GEN_MIXI_FUNC_NAME_GET_GENERAL_PURPOSE_PLUGIN "winampGetGeneralPurposePlugin"
69+
70+#define DUMMY_MP3_FILE_NAME _T("foo_mixi_feat_winamp.mp3")
71+#define APPDATA_MIXI_STATION_DIR _T("\\mixi\\mixi")
72+#define DEFAULT_WINAMP_TITLE "Winamp"
73+#define DEFAULT_DUMMYAMP_TITLE "DummyAmp"
74+
75+#define CODEC_TYPE_VORBIS "Vorbis"
76+#define CODEC_TYPE_MP3 "MP3"
77+
78+#define IS_SUPPORTED_FORMAT_BY_GEN_MIXI(codec) (!::lstrcmpA(codec, CODEC_TYPE_VORBIS) || !::lstrcmpA(codec, CODEC_TYPE_MP3))
79+
80+#if !defined(ENABLE_MSN)
81+#define PLUGIN_CAPTION "mixi music plugin for Winamp, bridge component"
82+#define PLUGIN_CAPTION_JP "mixi ミュージック"
83+#else
84+#define PLUGIN_CAPTION "Mixi Music plugin for M2M"
85+#endif
86+
87+#define ADVANCED_SETTINGS_CAPTION "高度な設定"
88+#define DUMMYAMP_FRAME_CAPTION _T("DummyAmp の設定 (動作状態:%s)")
89+#define DUMMYAMP_BEFORE_INIT_MODE _T("初回再生の待機中")
90+#define DUMMYAMP_HOOK_MODE _T("既存 Winamp API Emulator をフック中")
91+#define DUMMYAMP_STANDALONE_MODE _T("単独で Winamp API をエミュレート中")
92+#define DEBUG_SETTINGS_CAPTION "デバッグ用の設定"
93+#define PLUGIN_VERSION "0.2.1.0"
94+
95+#define DEFAULT_DUMMYAMP_TITLE_FORMAT "[%artist% - ]$if(%title%,%title%,%_filename%)"
96+
97+#define URL_FOO_MIXI_HOME "http://foo-mixi.sourceforge.jp/"
98+
99+#define FORMAT_FILEPATH "%_path%"
100+#define FORMAT_FILEPATHRAW "%_path_raw%"
101+#define FORMAT_ARTIST "%artist%"
102+#define FORMAT_TRACKTITLE "%title%"
103+#define FORMAT_ALBUMTITLE "%album%"
104+#define FORMAT_GENRE "%genre%"
105+#define FORMAT_CODEC "%__codec%"
106+
107+#if IS_FB2K_VER08
108+#define FORMAT_LISTINDEX "%_playlist_number%"
109+#elif IS_FB2K_VER09
110+#define FORMAT_LISTINDEX "%list_index%"
111+#endif
112+
113+#define IPC_GETOUTPUTTIME_PositionMSec 0
114+#define IPC_GETOUTPUTTIME_TotalSec 1
115+
116+#define IPC_INTERNAL_REFRESHLISTINFO 0x4000
117+#define IPC_INTERNAL_REFRESHDYNINFO 0x4001
118+
119+#define RESENT_INTERVAL 5000
120+#define FORCE_RESENT_MODE 0
121+//#define DISABLE_KICK_GEN_MIXI_LOOP
122+
123+#define GEN_MIXI_REQUIRED_SECONDS 6
124+#define GEN_MIXI_TRIGGER_SECONDS 6
125+#define GEN_MIXI_MARGIN_SECONDS 0
126+
127+#define REQUIRED_MINIMUM_TIME 8
128+#define SEND_TIME_RATE_LOWERBOUND 0
129+#define REQUIRED_MAXIMUM_TIME 0
130+
131+#define CONTROL_SEND_TIMING
132+
133+//#define ENABLE_MSN
134+
135+#if IS_FB2K_VER09
136+using namespace pfc;
137+using namespace pfc::stringcvt;
138+#define pfc_string_to_float string_to_float
139+#endif
140+
141+/*
142+ foo_mixi_feat_winamp: project dependencies
143+
144+ foo_mixi_feat_winamp
145+ foobar2000_SDK
146+ utf8api(0.8.3)
147+ pfc
148+ foobar2000_sdk_helpers
149+ pfc
150+ foobar2000_component_client(0.9.X)
151+ id3lib
152+ zlib
153+
154+ library dependencies: wxbase28.lib, id3lib.lib, ../shared/shared.lib(0.9.X)
155+ runtime library: Multi-Thread (DLL) or (Debug,DLL)
156+ !! ensure all projects that depended from this project are correctly set to MT DLL !!
157+ ignore: LIBCMT [Win32 Release] (or LIBCMTD [Win32 Debug])
158+*/
159+
160+// if wxWidgets are updated, change lib names below and linker libpath option.
161+
162+#if 0
163+#if defined(_DEBUG)
164+#if defined(BUILD_UNICODE)
165+#pragma comment(lib, "wxbase28ud.lib")
166+#else
167+#pragma comment(lib, "wxbase28d.lib")
168+#endif
169+#else
170+#if defined(BUILD_UNICODE)
171+#pragma comment(lib, "wxbase28u.lib")
172+#else
173+#pragma comment(lib, "wxbase28.lib")
174+#endif
175+#endif
176+#endif
177+
178+// now id3lib automatically added to linker target,
179+// because it generated from depended project.
180+//#pragma comment(lib, "id3lib.lib")
181+
182+#if IS_FB2K_VER09
183+#pragma comment(lib, "../shared/shared.lib")
184+#endif
185+
186+typedef std::basic_string<TCHAR> tstring;
187+
188+typedef TCHAR Str64K[65536];
189+typedef char StrDBCS64K[65536];
190+
191+tstring GetErrorMessage(DWORD errCode);
192+void putLogError(LPCTSTR pMethod, LPCTSTR pErrMsg, DWORD dwErrCode);
193+void setDlgVersionInfo(HWND wnd, UINT idc_version, UINT idc_build);
194+void DebugPrint(int severity, LPCTSTR lpszFormat, ...);
195+void DebugPrintDBCS(int severity, LPCSTR lpszFormat, ...);
196+void DebugPrint8(int severity, LPCSTR lpszFormat, ...);
197+
198+#define LOGLEVEL_NONE 0
199+#define LOGLEVEL_WARNING 1
200+#define LOGLEVEL_ERROR 2
201+
202+#if IS_FB2K_VER09
203+namespace console
204+{
205+ enum {
206+ SEVERITY_INFO = 0,
207+ SEVERITY_WARNING = 1,
208+ SEVERITY_CRITICAL = 2
209+ };
210+};
211+#endif
212+
213+#define LOG_TRACE(f, ...) if(cfg_enable_debug_log) DebugPrint(console::SEVERITY_INFO, f, __VA_ARGS__)
214+#define LOG_DEBUG(f, ...) if(cfg_enable_debug_log) DebugPrint(console::SEVERITY_INFO, f, __VA_ARGS__)
215+
216+#define LOG_TRACE8(f, ...) if(cfg_enable_debug_log) DebugPrint8(console::SEVERITY_INFO, f, __VA_ARGS__)
217+#define LOG_DEBUG8(f, ...) if(cfg_enable_debug_log) DebugPrint8(console::SEVERITY_INFO, f, __VA_ARGS__)
218+
219+#define LOG_TRACE_ANSI(f, ...) if(cfg_enable_debug_log) DebugPrintDBCS(console::SEVERITY_INFO, f, __VA_ARGS__)
220+#define LOG_DEBUG_ANSI(f, ...) if(cfg_enable_debug_log) DebugPrintDBCS(console::SEVERITY_INFO, f, __VA_ARGS__)
221+
222+#define LOG_INFO(f, ...) DebugPrint(console::SEVERITY_INFO, f, __VA_ARGS__)
223+#define LOG_WARN(f, ...) DebugPrint(console::SEVERITY_WARNING, f, __VA_ARGS__)
224+#define LOG_ERROR(f, ...) DebugPrint(console::SEVERITY_CRITICAL, f, __VA_ARGS__)
225+
226+#if defined(BUILD_UNICODE)
227+#define TRACE_DBCS(f, ...) if(cfg_enable_debug_log) DebugPrintDBCS(console::SEVERITY_INFO, f, __VA_ARGS__)
228+#else
229+#define TRACE_DBCS(f, ...) if(cfg_enable_debug_log) DebugPrint(console::SEVERITY_INFO, f, __VA_ARGS__)
230+#endif
231+
232+#define DEBUG_DUMMYAMP_INIT(f, ...) if(cfg_debug_dummyamp_init >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
233+#define TRACE_DUMMYAMP_INIT(f, ...) if(cfg_debug_dummyamp_init >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
234+
235+#define DEBUG_DUMMYAMP_PROC(f, ...) if(cfg_debug_dummyamp_proc >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
236+#define DEBUG_DUMMYAMP_PROC8(f, ...) if(cfg_debug_dummyamp_proc >= LOGLEVEL_WARNING) LOG_DEBUG8(f, __VA_ARGS__)
237+#define TRACE_DUMMYAMP_PROC(f, ...) if(cfg_debug_dummyamp_proc >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
238+#define TRACE_DUMMYAMP_PROC8(f, ...) if(cfg_debug_dummyamp_proc >= LOGLEVEL_ERROR) LOG_TRACE8(f, __VA_ARGS__)
239+
240+#define DEBUG_TRACK_INFO(f, ...) if(cfg_debug_track_info >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
241+#define DEBUG_TRACK_INFO8(f, ...) if(cfg_debug_track_info >= LOGLEVEL_WARNING) LOG_DEBUG8(f, __VA_ARGS__)
242+#define DEBUG_TRACK_INFO_ANSI(f, ...) if(cfg_debug_track_info >= LOGLEVEL_WARNING) LOG_DEBUG_ANSI(f, __VA_ARGS__)
243+#define TRACE_TRACK_INFO(f, ...) if(cfg_debug_track_info >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
244+#define TRACE_TRACK_INFO8(f, ...) if(cfg_debug_track_info >= LOGLEVEL_ERROR) LOG_TRACE8(f, __VA_ARGS__)
245+#define TRACE_TRACK_INFO_ANSI(f, ...) if(cfg_debug_track_info >= LOGLEVEL_ERROR) LOG_TRACE_ANSI(f, __VA_ARGS__)
246+
247+#define DEBUG_PLUGIN(f, ...) if(cfg_debug_plugin >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
248+#define TRACE_PLUGIN(f, ...) if(cfg_debug_plugin >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
249+
250+#define DEBUG_CALLBACK(f, ...) if(cfg_debug_callback >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
251+#define TRACE_CALLBACK(f, ...) if(cfg_debug_callback >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
252+
253+static string_utf8_from_os g_pluginCaption8(_T(PLUGIN_CAPTION_JP));
254+static string_utf8_from_os g_pluginVersion8(_T(PLUGIN_VERSION));
255+static string_utf8_from_os g_pluginAbout8(
256+ _T(PLUGIN_CAPTION_JP) _T(" ") _T(PLUGIN_VERSION) _T("\nCopyright (C) 2006-2009 Yossiepon Oniichan, All Rights Reserved."));
257+
258+DECLARE_COMPONENT_VERSION(g_pluginCaption8, g_pluginVersion8, g_pluginAbout8);
259+
260+static string_utf8_from_os g_advancedSettingsCaption8(_T(ADVANCED_SETTINGS_CAPTION));
261+static string_utf8_from_os g_debugSettingsCaption8(_T(DEBUG_SETTINGS_CAPTION));
262+
263+static string_utf8_from_os g_menu_item(_T("Components/Mixi/mixiミュージック連携を有効にする"));
264+
265+static string_utf8_from_os g_menu_item_title(_T("mixiミュージック連携を有効にする"));
266+static string_utf8_from_os g_menu_item_description(_T("mixiミュージックへの曲情報の送信について、有効/無効を切り替えます"));
267+
268+#if IS_FB2K_VER08
269+static cfg_int cfg_use_plugin("usePlugin", 1);
270+
271+static cfg_string cfg_no_artist_name("NoArtistName", "No Artist");
272+static cfg_string cfg_no_title_name("NoTitleName", "No Title");
273+static cfg_string cfg_no_album_name("NoAlbumName", "No Title");
274+static cfg_string cfg_no_genre_name("NoGenreName", "Other");
275+
276+static cfg_string cfg_send_interval1("SendInterval1", "20");
277+static cfg_string cfg_send_interval2("SendInterval2", "66");
278+static cfg_string cfg_send_interval3("SendInterval3", "300");
279+
280+static cfg_int cfg_disable_duplicate_song("DisableDuplicateSong", 0);
281+static cfg_int cfg_media_library_registered_file_only("MediaLibraryRegisteredFileOnly", 0);
282+static cfg_int cfg_explicitly_tagged_file_only("ExplicitlyTaggedFileOnly", 0);
283+static cfg_int cfg_enable_streaming_file("EnableStreamingFile", 0);
284+
285+static cfg_int cfg_disable_dummy_mp3("DisableDummyMp3", 0);
286+static cfg_int cfg_dummy_mp3_location("DummyMp3Location", 0);
287+
288+static cfg_int cfg_show_dummyamp("ShowDummyAmp", 0);
289+static cfg_string cfg_dummyamp_title_format("DummyAmpTitleFormat", DEFAULT_DUMMYAMP_TITLE_FORMAT);
290+static cfg_string cfg_dummyamp_playlist_format("DummyAmpPlaylistFormat", DEFAULT_DUMMYAMP_TITLE_FORMAT);
291+static cfg_int cfg_disable_ansi_trans("DisableAnsiTrans", 0);
292+static cfg_int cfg_enable_ext_ipc_proc("EnableExtIpcProc", 1);
293+
294+static cfg_int cfg_enable_debug_log("EnableDebugLog", 1);
295+static cfg_int cfg_debug_dummyamp_init("DebugDummyAmpInit", 1);
296+static cfg_int cfg_debug_dummyamp_proc("DebugDummyAmpProc", 1);
297+static cfg_int cfg_debug_track_info("DebugTrackInfo", 1);
298+static cfg_int cfg_debug_plugin("DebugPlugin", 1);
299+static cfg_int cfg_debug_callback("DebugCallback", 1);
300+#elif IS_FB2K_VER09
301+// {DB051102-6DAE-4ff8-B5ED-AA06C2ACFEDE}
302+static const GUID cfg_use_plugin_guid = { 0xdb051102, 0x6dae, 0x4ff8, { 0xb5, 0xed, 0xaa, 0x6, 0xc2, 0xac, 0xfe, 0xde } };
303+static cfg_int cfg_use_plugin(cfg_use_plugin_guid, 1);
304+
305+// {1B27EDEC-A28A-4dac-96D4-1E3B51C92004}
306+static const GUID cfg_no_artist_name_guid = { 0x1b27edec, 0xa28a, 0x4dac, { 0x96, 0xd4, 0x1e, 0x3b, 0x51, 0xc9, 0x20, 0x4 } };
307+static cfg_string cfg_no_artist_name(cfg_no_artist_name_guid, "No Artist");
308+// {A8CFD50C-05EA-447d-AA74-F4C6975E750E}
309+static const GUID cfg_no_title_name_guid = { 0xa8cfd50c, 0x5ea, 0x447d, { 0xaa, 0x74, 0xf4, 0xc6, 0x97, 0x5e, 0x75, 0xe } };
310+static cfg_string cfg_no_title_name(cfg_no_title_name_guid, "No Title");
311+// {A7593537-8B09-4016-9B3C-0EF5516BBFF9}
312+static const GUID cfg_no_album_name_guid = { 0xa7593537, 0x8b09, 0x4016, { 0x9b, 0x3c, 0xe, 0xf5, 0x51, 0x6b, 0xbf, 0xf9 } };
313+static cfg_string cfg_no_album_name(cfg_no_album_name_guid, "No Title");
314+// {15774319-0CBE-45fd-B0E8-52D4728319A3}
315+static const GUID cfg_no_genre_name_guid = { 0x15774319, 0xcbe, 0x45fd, { 0xb0, 0xe8, 0x52, 0xd4, 0x72, 0x83, 0x19, 0xa3 } };
316+static cfg_string cfg_no_genre_name(cfg_no_genre_name_guid, "Other");
317+
318+// {ED0C715A-D06D-4641-A29A-AE4485A0B9EF}
319+static const GUID cfg_send_interval1_guid = { 0xed0c715a, 0xd06d, 0x4641, { 0xa2, 0x9a, 0xae, 0x44, 0x85, 0xa0, 0xb9, 0xef } };
320+static cfg_string cfg_send_interval1(cfg_send_interval1_guid, "20");
321+// {25989711-B458-4624-8A85-7304FCE799A3}
322+static const GUID cfg_send_interval2_guid = { 0x25989711, 0xb458, 0x4624, { 0x8a, 0x85, 0x73, 0x4, 0xfc, 0xe7, 0x99, 0xa3 } };
323+static cfg_string cfg_send_interval2(cfg_send_interval2_guid, "66");
324+// {4287A873-015D-44b5-A31E-34DEE1BF0525}
325+static const GUID cfg_send_interval3_guid = { 0x4287a873, 0x15d, 0x44b5, { 0xa3, 0x1e, 0x34, 0xde, 0xe1, 0xbf, 0x5, 0x25 } };
326+static cfg_string cfg_send_interval3(cfg_send_interval3_guid, "300");
327+
328+// {5C318451-2B6A-405f-814B-2795A764C1DE}
329+static const GUID cfg_disable_duplicate_song_guid = { 0x5c318451, 0x2b6a, 0x405f, { 0x81, 0x4b, 0x27, 0x95, 0xa7, 0x64, 0xc1, 0xde } };
330+static cfg_int cfg_disable_duplicate_song(cfg_disable_duplicate_song_guid, 0);
331+// {56688AED-A76D-4759-A835-A380D39D34D1}
332+static const GUID cfg_media_library_registered_file_only_guid = { 0x56688aed, 0xa76d, 0x4759, { 0xa8, 0x35, 0xa3, 0x80, 0xd3, 0x9d, 0x34, 0xd1 } };
333+static cfg_int cfg_media_library_registered_file_only(cfg_media_library_registered_file_only_guid, 0);
334+// {91E0D3D4-85DD-4c45-ADB5-7FAC6F3360CD}
335+static const GUID cfg_explicitly_tagged_file_only_guid = { 0x91e0d3d4, 0x85dd, 0x4c45, { 0xad, 0xb5, 0x7f, 0xac, 0x6f, 0x33, 0x60, 0xcd } };
336+static cfg_int cfg_explicitly_tagged_file_only(cfg_explicitly_tagged_file_only_guid, 0);
337+// {F4E85669-6EEF-4b75-AFC1-7964AEBE10B0}
338+static const GUID cfg_enable_streaming_file_guid = { 0xf4e85669, 0x6eef, 0x4b75, { 0xaf, 0xc1, 0x79, 0x64, 0xae, 0xbe, 0x10, 0xb0 } };
339+static cfg_int cfg_enable_streaming_file(cfg_enable_streaming_file_guid, 0);
340+
341+// {67341E11-A385-45d8-9DE6-B1FABA35AC62}
342+static const GUID cfg_disable_dummy_mp3_guid = { 0x67341e11, 0xa385, 0x45d8, { 0x9d, 0xe6, 0xb1, 0xfa, 0xba, 0x35, 0xac, 0x62 } };
343+static cfg_int cfg_disable_dummy_mp3(cfg_disable_dummy_mp3_guid, 0);
344+// {87D4D72C-43AB-42ab-8CAC-D689961DA5EA}
345+static const GUID cfg_dummy_mp3_location_guid = { 0x87d4d72c, 0x43ab, 0x42ab, { 0x8c, 0xac, 0xd6, 0x89, 0x96, 0x1d, 0xa5, 0xea } };
346+static cfg_int cfg_dummy_mp3_location(cfg_dummy_mp3_location_guid, 0);
347+
348+// {F9DB10F0-1A01-40dd-A342-486A6CB596E7}
349+static const GUID cfg_show_dummyamp_guid = { 0xf9db10f0, 0x1a01, 0x40dd, { 0xa3, 0x42, 0x48, 0x6a, 0x6c, 0xb5, 0x96, 0xe7 } };
350+static cfg_int cfg_show_dummyamp(cfg_show_dummyamp_guid, 0);
351+// {CC7785CA-B019-4107-9115-161A543B3952}
352+static const GUID cfg_dummyamp_title_format_guid = { 0xcc7785ca, 0xb019, 0x4107, { 0x91, 0x15, 0x16, 0x1a, 0x54, 0x3b, 0x39, 0x52 } };
353+static cfg_string cfg_dummyamp_title_format(cfg_dummyamp_title_format_guid, DEFAULT_DUMMYAMP_TITLE_FORMAT);
354+// {B964EB32-4957-4e7a-81B5-E89B4405AAAD}
355+static const GUID cfg_dummyamp_playlist_format_guid = { 0xb964eb32, 0x4957, 0x4e7a, { 0x81, 0xb5, 0xe8, 0x9b, 0x44, 0x5, 0xaa, 0xad } };
356+static cfg_string cfg_dummyamp_playlist_format(cfg_dummyamp_title_format_guid, DEFAULT_DUMMYAMP_TITLE_FORMAT);
357+
358+// {094571BA-1484-455c-9D6E-E18B13296149}
359+static const GUID cfg_disable_ansi_trans_guid = { 0x94571ba, 0x1484, 0x455c, { 0x9d, 0x6e, 0xe1, 0x8b, 0x13, 0x29, 0x61, 0x49 } };
360+static cfg_int cfg_disable_ansi_trans(cfg_disable_ansi_trans_guid, 0);
361+// {8961A829-F010-461c-9CC8-C06308BFA4A2}
362+static const GUID cfg_enable_ext_ipc_proc_guid = { 0x8961a829, 0xf010, 0x461c, { 0x9c, 0xc8, 0xc0, 0x63, 0x8, 0xbf, 0xa4, 0xa2 } };
363+static cfg_int cfg_enable_ext_ipc_proc(cfg_enable_ext_ipc_proc_guid, 1);
364+
365+// {3B6B73F9-F6AF-4b6c-8015-E73A1B87AD5C}
366+static const GUID cfg_enable_debug_log_guid = { 0x3b6b73f9, 0xf6af, 0x4b6c, { 0x80, 0x15, 0xe7, 0x3a, 0x1b, 0x87, 0xad, 0x5c } };
367+static cfg_int cfg_enable_debug_log(cfg_enable_debug_log_guid, 1); // debug log enabled
368+// {0BF3522F-BC55-4f77-AA95-B02F6E159544}
369+static const GUID cfg_debug_dummyamp_init_guid = { 0xbf3522f, 0xbc55, 0x4f77, { 0xaa, 0x95, 0xb0, 0x2f, 0x6e, 0x15, 0x95, 0x44 } };
370+static cfg_int cfg_debug_dummyamp_init(cfg_debug_dummyamp_init_guid, 1); // debug level
371+// {D1256573-7560-41db-A781-9985AE50CE07}
372+static const GUID cfg_debug_dummyamp_proc_guid = { 0xd1256573, 0x7560, 0x41db, { 0xa7, 0x81, 0x99, 0x85, 0xae, 0x50, 0xce, 0x7 } };
373+static cfg_int cfg_debug_dummyamp_proc(cfg_debug_dummyamp_proc_guid, 1); // debug level
374+// {0A7E2CAE-905F-4ecb-A82D-8DD853FBFFF3}
375+static const GUID cfg_debug_track_info_guid = { 0xa7e2cae, 0x905f, 0x4ecb, { 0xa8, 0x2d, 0x8d, 0xd8, 0x53, 0xfb, 0xff, 0xf3 } };
376+static cfg_int cfg_debug_track_info(cfg_debug_track_info_guid, 1); // debug level
377+// {67A78DB7-3591-4416-84FC-96436082B619}
378+static const GUID cfg_debug_plugin_guid = { 0x67a78db7, 0x3591, 0x4416, { 0x84, 0xfc, 0x96, 0x43, 0x60, 0x82, 0xb6, 0x19 } };
379+static cfg_int cfg_debug_plugin(cfg_debug_plugin_guid, 1); // debug level
380+// {DBED8400-527F-4b98-9227-2C0BA95B3206}
381+static const GUID cfg_debug_callback_guid = { 0xdbed8400, 0x527f, 0x4b98, { 0x92, 0x27, 0x2c, 0xb, 0xa9, 0x5b, 0x32, 0x6 } };
382+static cfg_int cfg_debug_callback(cfg_debug_callback_guid, 1); // debug level
383+#endif
384+
385+class TrackInfo
386+{
387+public:
388+ std::string m_nullStr;
389+
390+ StringMap m_infoMap8;
391+ StringMap m_infoMapAnsi;
392+
393+ UIntMap m_infoMapNum;
394+
395+ TrackInfo() {
396+ }
397+
398+ TrackInfo(const TrackInfo &other)
399+ : m_infoMap8(other.m_infoMap8)
400+ , m_infoMapAnsi(other.m_infoMapAnsi)
401+ , m_infoMapNum(other.m_infoMapNum) {
402+ }
403+
404+ ~TrackInfo() {
405+ }
406+
407+ TrackInfo &operator =(const TrackInfo &other)
408+ {
409+ TrackInfo temp(other);
410+ swap(temp);
411+
412+ return *this;
413+ }
414+
415+ void show_map(StringMap &map, bool bAnsi = false)
416+ {
417+ StringMapCIt beginIt(map.begin()), endIt(map.end()), it;
418+
419+ for(it = beginIt; it != endIt; it ++) {
420+
421+ if(bAnsi) {
422+ TRACE_TRACK_INFO_ANSI("show_map_ansi: [%s, %s]", it->first.c_str(), it->second.c_str());
423+ } else {
424+ TRACE_TRACK_INFO8("show_map8: [%s, %s]", it->first.c_str(), it->second.c_str());
425+ }
426+ }
427+ }
428+
429+ void swap(TrackInfo &other)
430+ {
431+ m_infoMap8.swap(other.m_infoMap8);
432+ m_infoMapAnsi.swap(other.m_infoMapAnsi);
433+ m_infoMapNum.swap(other.m_infoMapNum);
434+ }
435+
436+ void clear()
437+ {
438+ TRACE_TRACK_INFO(_T("TRACK_INFO::clear - called."));
439+
440+ m_infoMap8.clear();
441+ m_infoMapAnsi.clear();
442+ m_infoMapNum.clear();
443+ }
444+
445+ bool isEmpty() const { return m_infoMap8.empty() & m_infoMapNum.empty(); }
446+
447+public:
448+
449+#if IS_FB2K_VER08
450+ void setStrings(const Strings &keys, metadb_handle * track)
451+#elif IS_FB2K_VER09
452+ void setStrings(const Strings &keys, metadb_handle_ptr track)
453+#endif
454+ {
455+ TRACE_TRACK_INFO(_T("TrackInfo::setStrings - called."));
456+
457+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
458+
459+ for(it = beginIt; it != endIt; it ++) {
460+
461+ string8 info8;
462+
463+#if IS_FB2K_VER08
464+ track->handle_format_title(info8, it->c_str(), 0);
465+#elif IS_FB2K_VER09
466+ service_ptr_t<titleformat_object> titleformat;
467+
468+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
469+ track->format_title(NULL, info8, titleformat, 0);
470+#endif
471+// DEBUG_TRACK_INFO8("TrackInfo::setStrings - %s: %s", it->c_str(), (LPCSTR)info8);
472+
473+ putString(it->c_str(), (LPCSTR)info8);
474+ }
475+ }
476+
477+ void setDynamicStrings(const Strings &keys)
478+ {
479+ TRACE_TRACK_INFO(_T("TrackInfo::setDynamicStrings - called."));
480+
481+#if IS_FB2K_VER08
482+ metadb_handle *track = play_control::get()->get_now_playing();
483+#elif IS_FB2K_VER09
484+ metadb_handle_ptr track;
485+ static_api_ptr_t<playback_control>()->get_now_playing(track);
486+#endif
487+
488+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
489+
490+ for(it = beginIt; it != endIt; it ++) {
491+
492+ string8 info8;
493+
494+#if IS_FB2K_VER08
495+ play_control::get()->playback_format_title_ex(track, info8, it->c_str(), NULL, false, true);
496+#elif IS_FB2K_VER09
497+ service_ptr_t<titleformat_object> titleformat;
498+
499+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
500+ static_api_ptr_t<playback_control>()->playback_format_title_ex(track, NULL, info8, titleformat, NULL, play_control::display_level_titles);
501+#endif
502+// DEBUG_TRACK_INFO8("TrackInfo::setDynamicStrings - %s: %s", it->c_str(), (LPCSTR)info8);
503+
504+ const std::string &oldValue = getString(*it);
505+
506+ if((::lstrcmpA(info8, "?") != 0) || (oldValue.length() == 0))
507+ {
508+ putString(it->c_str(), (LPCSTR)info8);
509+ }
510+ }
511+
512+#if IS_FB2K_VER08
513+ if(track) {
514+ track->handle_release();
515+ }
516+#endif
517+ }
518+
519+ void setPlaylistStrings(const Strings &keys)
520+ {
521+ TRACE_TRACK_INFO(_T("TrackInfo::setPlaylistStrings - called."));
522+
523+#if IS_FB2K_VER08
524+ int track_index;
525+ track_index = playlist_oper::get()->get_now_playing();
526+#elif IS_FB2K_VER09
527+ t_size playlist_index, track_index;
528+ static_api_ptr_t<playlist_manager>()->get_playing_item_location(&playlist_index, &track_index);
529+#endif
530+
531+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
532+
533+ for(it = beginIt; it != endIt; it ++) {
534+
535+ string8 info8;
536+
537+#if IS_FB2K_VER08
538+ playlist_oper::get()->format_title(track_index, info8, it->c_str(), NULL);
539+#elif IS_FB2K_VER09
540+ service_ptr_t<titleformat_object> titleformat;
541+
542+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
543+ static_api_ptr_t<playlist_manager>()->playlist_item_format_title(playlist_index, track_index,
544+ NULL, info8, titleformat, NULL, play_control::display_level_titles);
545+#endif
546+// DEBUG_TRACK_INFO8("TrackInfo::setPlaylistStrings - %s: %s", it->c_str(), (LPCSTR)info8);
547+
548+ putString(it->c_str(), (LPCSTR)info8);
549+ }
550+ }
551+
552+#if IS_FB2K_VER08
553+ void setNumbers(const Strings &keys, metadb_handle * track)
554+#elif IS_FB2K_VER09
555+ void setNumbers(const Strings &keys, metadb_handle_ptr track)
556+#endif
557+ {
558+ TRACE_TRACK_INFO(_T("TrackInfo::setNumbers - called."));
559+
560+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
561+
562+ for(it = beginIt; it != endIt; it ++) {
563+
564+ string8 info8;
565+
566+#if IS_FB2K_VER08
567+ track->handle_format_title(info8, it->c_str(), 0);
568+#elif IS_FB2K_VER09
569+ service_ptr_t<titleformat_object> titleformat;
570+
571+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
572+ track->format_title(NULL, info8, titleformat, 0);
573+#endif
574+// DEBUG_TRACK_INFO8("TrackInfo::setNumbers - %s: %s", it->c_str(), (LPCSTR)info8);
575+
576+ putNumber(it->c_str(), static_cast<UINT>(::atol(info8)) );
577+ }
578+ }
579+
580+ void setDynamicNumbers(const Strings &keys)
581+ {
582+ TRACE_TRACK_INFO(_T("TrackInfo::setDynamicNumbers - called."));
583+
584+#if IS_FB2K_VER08
585+ metadb_handle *track = play_control::get()->get_now_playing();
586+#elif IS_FB2K_VER09
587+ metadb_handle_ptr track;
588+ static_api_ptr_t<playback_control>()->get_now_playing(track);
589+#endif
590+
591+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
592+
593+ for(it = beginIt; it != endIt; it ++) {
594+
595+ string8 info8;
596+
597+#if IS_FB2K_VER08
598+ play_control::get()->playback_format_title_ex(track, info8, it->c_str(), NULL, false, true);
599+#elif IS_FB2K_VER09
600+ service_ptr_t<titleformat_object> titleformat;
601+
602+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
603+ static_api_ptr_t<playback_control>()->playback_format_title_ex(track, NULL, info8, titleformat, NULL, play_control::display_level_titles);
604+#endif
605+// DEBUG_TRACK_INFO8("TrackInfo::setDynamicNumbers - %s: %s", it->c_str(), (LPCSTR)info8);
606+
607+ UINT newValue = static_cast<UINT>(::atol(info8));
608+ UINT oldValue = getNumber(*it);
609+
610+ if((newValue != 0) || (oldValue == 0)) {
611+ putNumber(it->c_str(), newValue);
612+ }
613+ }
614+
615+#if IS_FB2K_VER08
616+ if(track) {
617+ track->handle_release();
618+ }
619+#endif
620+ }
621+
622+ void setPlaylistNumbers(const Strings &keys)
623+ {
624+ TRACE_TRACK_INFO(_T("TrackInfo::setPlaylistNumbers - called."));
625+
626+#if IS_FB2K_VER08
627+ int track_index;
628+ track_index = playlist_oper::get()->get_now_playing();
629+#elif IS_FB2K_VER09
630+ t_size playlist_index, track_index;
631+ static_api_ptr_t<playlist_manager>()->get_playing_item_location(&playlist_index, &track_index);
632+#endif
633+
634+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
635+
636+ for(it = beginIt; it != endIt; it ++) {
637+
638+ string8 info8;
639+
640+#if IS_FB2K_VER08
641+ playlist_oper::get()->format_title(track_index, info8, it->c_str(), NULL);
642+#elif IS_FB2K_VER09
643+ service_ptr_t<titleformat_object> titleformat;
644+
645+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
646+ static_api_ptr_t<playlist_manager>()->playlist_item_format_title(playlist_index, track_index,
647+ NULL, info8, titleformat, NULL, play_control::display_level_titles);
648+#endif
649+// DEBUG_TRACK_INFO8("TrackInfo::setPlaylistNumbers - %s: %s", it->c_str(), (LPCSTR)info8);
650+
651+ putNumber(it->c_str(), static_cast<UINT>(::atol(info8)) );
652+ }
653+ }
654+
655+ void putString(const std::string &key, const std::string &value)
656+ {
657+ DEBUG_TRACK_INFO8("TrackInfo::putString - %s: %s", key.c_str(), value.c_str());
658+
659+ insert(m_infoMap8, key.c_str(), value.c_str());
660+
661+ string_ansi_from_utf8 valueAnsi(value.c_str());
662+
663+ insert(m_infoMapAnsi, key.c_str(), (LPCSTR)valueAnsi, true);
664+ }
665+
666+ void putNumber(const std::string &key, UINT value)
667+ {
668+ DEBUG_TRACK_INFO8("TrackInfo::putNumber - %s: %u", key.c_str(), value);
669+
670+ insert(m_infoMapNum, key.c_str(), value);
671+ }
672+
673+ const std::string &getString(const std::string &key, bool bForceUTF8 = false) const {
674+
675+ if((bForceUTF8 == true) || (cfg_disable_ansi_trans == 1))
676+ {
677+ StringMapCIt it(m_infoMap8.find(key)), endIt(m_infoMap8.end());
678+
679+ if(it == endIt) {
680+ return m_nullStr;
681+ }
682+
683+ return it->second;
684+ }
685+ else
686+ {
687+ StringMapCIt it(m_infoMapAnsi.find(key)), endIt(m_infoMapAnsi.end());
688+
689+ if(it == endIt) {
690+ return m_nullStr;
691+ }
692+
693+ return it->second;
694+ }
695+ }
696+
697+ const UINT getNumber(const std::string &key) const {
698+
699+ UIntMapCIt it(m_infoMapNum.find(key)), endIt(m_infoMapNum.end());
700+
701+ if(it == endIt) {
702+ return 0;
703+ }
704+
705+ return it->second;
706+ }
707+
708+ void removeStrings(const Strings &keys)
709+ {
710+ TRACE_TRACK_INFO(_T("TrackInfo::removeStrings - called."));
711+
712+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
713+
714+ for(it = beginIt; it != endIt; it ++) {
715+ removeString(*it);
716+ }
717+ }
718+
719+ void removeString(const std::string &key)
720+ {
721+ TRACE_TRACK_INFO8("TrackInfo::removeString - %s", key.c_str());
722+
723+ m_infoMap8.erase(m_infoMap8.find(key));
724+ m_infoMapAnsi.erase(m_infoMapAnsi.find(key));
725+ }
726+
727+ void removeNumbers(const Strings &keys)
728+ {
729+ TRACE_TRACK_INFO(_T("TrackInfo::removeNumbers - called."));
730+
731+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
732+
733+ for(it = beginIt; it != endIt; it ++) {
734+ removeNumber(*it);
735+ }
736+ }
737+
738+ void removeNumber(const std::string &key)
739+ {
740+ TRACE_TRACK_INFO8("TrackInfo::removeNumber - %s", key.c_str());
741+
742+ m_infoMapNum.erase(m_infoMapNum.find(key));
743+ }
744+
745+protected:
746+
747+ static void insert(StringMap &map, LPCSTR pKey, LPCSTR pValue, bool bAnsi = false)
748+ {
749+#if 0
750+ if(bAnsi) {
751+ TRACE_TRACK_INFO_ANSI("insertAnsi: [%s, %s]", pKey, pValue);
752+ } else {
753+ TRACE_TRACK_INFO8("insert8: [%s, %s]", pKey, pValue);
754+ }
755+#endif
756+
757+ map.insert(std::make_pair(pKey, pValue));
758+ }
759+
760+ static void insert(UIntMap &map, LPCSTR pKey, UINT value)
761+ {
762+// TRACE_TRACK_INFO8("insertNum: [%s, %u]", pKey, value);
763+
764+ map.insert(std::make_pair(pKey, value));
765+ }
766+};
767+
768+class PathInfo
769+{
770+ protected:
771+ PathInfo() {
772+ }
773+
774+ public:
775+ static tstring getFB2Kpath()
776+ {
777+ TCHAR modulePath[_MAX_PATH], moduleDrive[_MAX_DRIVE], moduleDir[_MAX_DIR];
778+ TCHAR returnPath[_MAX_PATH];
779+
780+ ::GetModuleFileName(NULL, modulePath, _MAX_PATH);
781+ ::_tsplitpath_s(modulePath, moduleDrive, _MAX_DRIVE, moduleDir, _MAX_DIR, NULL, 0, NULL, 0);
782+ ::_tmakepath_s(returnPath, _MAX_PATH, moduleDrive, moduleDir, NULL, NULL);
783+
784+ return tstring(returnPath);
785+ }
786+
787+ static tstring getFB2KComponentsPath() {
788+ return getFB2Kpath() + FB2K_COMPONENTS_DIR;
789+ }
790+
791+ static std::string getGenMixiDefaultPath()
792+ {
793+ string_utf8_from_os path(getFB2KComponentsPath().c_str());
794+ return (LPCSTR)path;
795+ }
796+
797+ static tstring getMixiStationAppPath() {
798+ return getSpecialFolderPath(CSIDL_APPDATA, FALSE) + APPDATA_MIXI_STATION_DIR;
799+ }
800+
801+ static tstring getFooMixiPlayInfoPath()
802+ {
803+ switch(cfg_dummy_mp3_location)
804+ {
805+ case 1:
806+ return getTemporaryFolderPath();
807+
808+ case 2:
809+ return getFB2KComponentsPath() ;
810+
811+ case 0:
812+ default:
813+ return getMixiStationAppPath() + _T("\\");
814+ }
815+ }
816+
817+ static tstring getDummyPlayInfoMp3Path() {
818+ return getFooMixiPlayInfoPath() + DUMMY_MP3_FILE_NAME;
819+ }
820+
821+ static tstring splitPath(const string8 &srcPath)
822+ {
823+ string_os_from_utf8 srcPathOs(srcPath);
824+ return splitPath(srcPathOs);
825+ }
826+
827+ static tstring splitPath(LPCTSTR srcPath)
828+ {
829+ TCHAR drive[_MAX_DRIVE], dir[_MAX_DIR], dstPath[_MAX_PATH];
830+ ::_tsplitpath_s(srcPath, drive, _MAX_DRIVE, dir, _MAX_DIR, NULL, 0, NULL, 0);
831+ ::_tmakepath_s(dstPath, _MAX_PATH, drive, dir, NULL, NULL);
832+ return dstPath;
833+ }
834+
835+ //! get the special folder path
836+ static tstring getSpecialFolderPath(int nFolder, BOOL bCreate)
837+ {
838+ tstring resStr;
839+ HRESULT hr = NO_ERROR;
840+
841+ IMalloc *pMalloc = 0;
842+ ITEMIDLIST *pItemID = 0;
843+ TCHAR folderPath[MAX_PATH];
844+
845+ folderPath[0] = _T('\0');
846+ hr = SHGetMalloc(&pMalloc);
847+
848+ if(hr == NO_ERROR)
849+ {
850+ hr = SHGetSpecialFolderLocation(0, nFolder, &pItemID);
851+
852+ if(hr == NO_ERROR)
853+ {
854+ if(SHGetPathFromIDList(pItemID, folderPath) == FALSE)
855+ hr = GetLastError();
856+
857+ pMalloc->Free(pItemID);
858+ }
859+
860+ pMalloc->Release();
861+ }
862+
863+ resStr = folderPath;
864+
865+ if(hr != NO_ERROR)
866+ {
867+ return _T("");
868+ }
869+
870+ return resStr;
871+ }
872+
873+ //! get the temporary folder path
874+ static tstring getTemporaryFolderPath() {
875+
876+ TCHAR strTempPath[MAX_PATH];
877+ ::GetTempPath(MAX_PATH, strTempPath);
878+
879+ return strTempPath;
880+ }
881+};
882+
883+#if IS_FB2K_VER08
884+static cfg_string cfg_gen_mixi_path("GenMixiPath", PathInfo::getGenMixiDefaultPath().c_str());
885+#elif IS_FB2K_VER09
886+// {1EC28435-C243-483c-81EC-E0E57A96727E}
887+static const GUID cfg_gen_mixi_path_guid = { 0x1ec28435, 0xc243, 0x483c, { 0x81, 0xec, 0xe0, 0xe5, 0x7a, 0x96, 0x72, 0x7e } };
888+static cfg_string cfg_gen_mixi_path(cfg_gen_mixi_path_guid, PathInfo::getGenMixiDefaultPath().c_str());
889+#endif
890+
891+class PlayInfo
892+{
893+ public:
894+
895+ enum EPlayStatus
896+ {
897+ PLAY_STOP = 0,
898+ PLAY_START = 1,
899+ PLAY_PAUSE = 3
900+ };
901+
902+ public:
903+
904+ PlayInfo() :
905+ m_playStatus(PLAY_STOP),
906+ m_isResentMode(false),
907+ m_playLength(0),
908+ m_playPosition(0),
909+ m_playCount(0),
910+ m_isPlayInfoMp3Available(false),
911+ m_resetBasePosition(0) {
912+ }
913+
914+ public:
915+
916+ void setPlayStatusStart() {
917+ setPlayStatus(PLAY_START);
918+ }
919+
920+ void setPlayStatusStop() {
921+ setPlayStatus(PLAY_STOP);
922+ }
923+
924+ void setPlayStatusPause() {
925+ setPlayStatus(PLAY_PAUSE);
926+ }
927+
928+ void clearPlayInfo(bool isResentMode = true)
929+ {
930+ setPlayStatusStop();
931+ m_isResentMode = isResentMode;
932+ setPlayPosition(0);
933+ setPlayLength(0);
934+ setPlayInfoMp3Available(false);
935+ m_resetBasePosition = 0;
936+ }
937+
938+ void setResentMode(bool bIncrementCounter = true)
939+ {
940+ if(bIncrementCounter) {
941+ incrementPlayCount();
942+ }
943+ m_isResentMode = true;
944+ m_resetBasePosition = m_playPosition;
945+ }
946+
947+ void clearResentMode() {
948+ m_isResentMode = false;
949+ }
950+
951+ void incrementPlayCount() {
952+ setPlayCount(getPlayCount() + 1);
953+ }
954+
955+ public:
956+
957+ EPlayStatus getPlayStatus() const
958+ {
959+ if((m_playStatus == PLAY_START) && m_isResentMode) {
960+ return PLAY_STOP;
961+ }
962+ return m_playStatus;
963+ }
964+
965+ void setPlayStatus(EPlayStatus status) {
966+ m_playStatus = status;
967+ }
968+
969+ int getPlayPosition() const
970+ {
971+ if(m_resetBasePosition > 0) {
972+ return m_playPosition - m_resetBasePosition;
973+ }
974+ return m_playPosition;
975+ }
976+
977+ void setPlayPosition(int pos) {
978+ m_playPosition = pos;
979+ }
980+
981+ int getPlayLength() const
982+ {
983+#if FORCE_RESENT_MODE == 0
984+ if(m_resetBasePosition > 0) {
985+#else
986+ if(true) {
987+#endif
988+ return GEN_MIXI_REQUIRED_SECONDS;
989+ }
990+ return m_playLength;
991+ }
992+
993+ void setPlayLength(int len) {
994+ m_playLength = len;
995+ }
996+
997+ int getPlayCount() const {
998+ return m_playCount;
999+ }
1000+
1001+ void setPlayCount(int count) {
1002+ m_playCount = count;
1003+ }
1004+
1005+ bool isPlayInfoMp3Available() const {
1006+ return m_isPlayInfoMp3Available;
1007+ }
1008+
1009+ void setPlayInfoMp3Available(bool isAvailable) {
1010+ m_isPlayInfoMp3Available = isAvailable;
1011+ }
1012+
1013+ void setPlayInfoMp3Path(LPCSTR path)
1014+ {
1015+#if 0
1016+ m_playInfoMp3Path = path;
1017+
1018+ string_utf8_from_os path8(path);
1019+
1020+ if(cfg_disable_ansi_trans == 1)
1021+ {
1022+
1023+ m_playInfoMp3Path8 = path8;
1024+ }
1025+ else
1026+ {
1027+ string_ansi_from_utf8 pathAnsi(path8);
1028+
1029+ m_playInfoMp3Path8 = pathAnsi;
1030+ }
1031+#else
1032+ m_playInfoMp3Path8 = path;
1033+#endif
1034+ }
1035+
1036+ const string8 &getPlayInfoMp3Path8() const {
1037+ return m_playInfoMp3Path8;
1038+ }
1039+
1040+ bool isResentMode() const {
1041+ return m_isResentMode;
1042+ }
1043+
1044+ protected:
1045+
1046+ EPlayStatus m_playStatus;
1047+
1048+ int m_playLength;
1049+ int m_playPosition;
1050+ int m_playCount;
1051+
1052+ bool m_isPlayInfoMp3Available;
1053+ bool m_isResentMode;
1054+ int m_resetBasePosition;
1055+
1056+ string8 m_playInfoMp3Path8;
1057+};
1058+
1059+class id3Info
1060+{
1061+ public:
1062+
1063+ typedef std::vector<UINT16> UInt16Array;
1064+
1065+ id3Info(const TrackInfo & info) : m_info(info), m_hMp3File(INVALID_HANDLE_VALUE) {
1066+ }
1067+
1068+ ~id3Info() {
1069+ close();
1070+ }
1071+
1072+ DWORD write(LPCTSTR path) {
1073+
1074+ string_wide_from_utf8 title_utf16(m_info.getString(FORMAT_TRACKTITLE, true).c_str());
1075+ string_wide_from_utf8 artist_utf16(m_info.getString(FORMAT_ARTIST, true).c_str());
1076+ string_wide_from_utf8 album_utf16(m_info.getString(FORMAT_ALBUMTITLE, true).c_str());
1077+ string_wide_from_utf8 genre_utf16(m_info.getString(FORMAT_GENRE, true).c_str());
1078+
1079+ DWORD dwErr = S_OK;
1080+
1081+ if((dwErr = open(path)) != S_OK) {
1082+ return dwErr;
1083+ }
1084+
1085+ UInt16Array title = makeTextFrame("TIT2", makeUTF16LE(title_utf16));
1086+ UInt16Array album = makeTextFrame("TALB", makeUTF16LE(album_utf16));
1087+ UInt16Array artist = makeTextFrame("TPE1", makeUTF16LE(artist_utf16));
1088+ UInt16Array genre = makeTextFrame("TCON", makeUTF16LE(genre_utf16));
1089+
1090+ dwErr = writeHeader(static_cast<UINT32>(
1091+ title.size()*2 + album.size()*2 + artist.size()*2 + genre.size()*2 + 4));
1092+ // add charset code size (4bytes)
1093+
1094+ if(dwErr == S_OK) {
1095+ dwErr = writeTextFrame(title);
1096+ }
1097+
1098+ if(dwErr == S_OK) {
1099+ dwErr = writeTextFrame(album);
1100+ }
1101+
1102+ if(dwErr == S_OK) {
1103+ dwErr = writeTextFrame(artist);
1104+ }
1105+
1106+ if(dwErr == S_OK) {
1107+ dwErr = writeTextFrame(genre);
1108+ }
1109+
1110+ close();
1111+
1112+ return dwErr;
1113+ }
1114+
1115+ protected:
1116+
1117+ DWORD open(LPCTSTR path)
1118+ {
1119+ close();
1120+
1121+ // open dummy mp3 file
1122+ m_hMp3File = ::CreateFile(
1123+ path, GENERIC_WRITE, 0, NULL,
1124+ TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
1125+ );
1126+
1127+ if(m_hMp3File == INVALID_HANDLE_VALUE)
1128+ {
1129+ return ::GetLastError();
1130+ }
1131+
1132+ return S_OK;
1133+ }
1134+
1135+ UInt16Array makeUTF16LE(const string_wide_from_utf8 &str) {
1136+
1137+ LPCWSTR pStr = str.get_ptr();
1138+ size_t len = ::lstrlenW(pStr);
1139+ UInt16Array utf16(len + 2);
1140+
1141+ utf16[0] = 0xfeff; // BOM
1142+ ::CopyMemory(&utf16[1], str.get_ptr(), len * 2);
1143+
1144+ // swap byte order (big endian to little endian);
1145+ for(size_t i = 0; i < len + 1; i++) {
1146+ utf16[i] = (utf16[i] << 8) | (utf16[i] >> 8);
1147+ }
1148+
1149+ utf16[len + 1] = 0; // add NULL character
1150+
1151+ return utf16;
1152+ }
1153+
1154+ UInt16Array makeTextFrame(LPCSTR pFrameID, const UInt16Array &data) {
1155+
1156+ UInt16Array frame(data.size() + 5);
1157+
1158+ UINT32 size = static_cast<UINT32>(data.size() * 2 + 1); // add charset code size (1byte)
1159+
1160+ const UCHAR *pUCFrameID = reinterpret_cast<const UCHAR *>(pFrameID);
1161+ const UCHAR *pUCSize = reinterpret_cast<const UCHAR *>(&size);
1162+
1163+ frame[0] = ((UINT16)pUCFrameID[1]) << 8 | pUCFrameID[0];
1164+ frame[1] = ((UINT16)pUCFrameID[3]) << 8 | pUCFrameID[2];
1165+
1166+ frame[2] = ((UINT16)pUCSize[2]) << 8 | pUCSize[3];
1167+ frame[3] = ((UINT16)pUCSize[0]) << 8 | pUCSize[1];
1168+
1169+ frame[4] = 0; // frame flag
1170+
1171+ ::CopyMemory(&frame[5], &data[0], data.size() * 2);
1172+
1173+ return frame;
1174+ }
1175+
1176+ void close() {
1177+ if(m_hMp3File != INVALID_HANDLE_VALUE) {
1178+ ::CloseHandle(m_hMp3File);
1179+ m_hMp3File = INVALID_HANDLE_VALUE;
1180+ }
1181+ }
1182+
1183+ DWORD writeHeader(UINT32 size)
1184+ {
1185+ UInt16Array header(5);
1186+
1187+ header[0] = ((UINT16)'D') << 8 | (UCHAR)'I';
1188+ header[1] = ((UINT16) 3 ) << 8 | (UCHAR)'3';
1189+
1190+ header[2] = 0;
1191+
1192+ UInt16Array length = makeLength(size);
1193+
1194+ header[3] = length[0];
1195+ header[4] = length[1];
1196+
1197+ DWORD dwSize;
1198+ if(!::WriteFile(m_hMp3File, &header[0], 10, &dwSize, NULL)) {
1199+ return ::GetLastError();
1200+ }
1201+
1202+ return S_OK;
1203+ }
1204+
1205+ DWORD writeTextFrame(const UInt16Array &packet)
1206+ {
1207+ DWORD dwErr = S_OK;
1208+
1209+ UCHAR charsetCode = 0x01; // UNICODE
1210+
1211+ DWORD dwSize;
1212+ if(!::WriteFile(m_hMp3File, &packet[0], 10, &dwSize, NULL)) {
1213+ return ::GetLastError();
1214+ }
1215+ if(!::WriteFile(m_hMp3File, &charsetCode, 1, &dwSize, NULL)) {
1216+ return ::GetLastError();
1217+ }
1218+ if(!::WriteFile(m_hMp3File, &packet[5], static_cast<DWORD>(packet.size() * 2 - 10), &dwSize, NULL)) {
1219+ return ::GetLastError();
1220+ }
1221+
1222+ return S_OK;
1223+ }
1224+
1225+ UInt16Array makeLength(UINT32 size)
1226+ {
1227+ UInt16Array length(2);
1228+ UCHAR sizes[4];
1229+
1230+ /*
1231+ 00001111111111111111111111111111
1232+
1233+ 1111111000000000000000000000
1234+ f e 0 0 0 0 0
1235+ 111111100000000000000
1236+ 1 f c 0 0 0
1237+ 11111110000000
1238+ 3 f 8 0
1239+ 1111111
1240+ 7 f
1241+ */
1242+
1243+ sizes[3] = static_cast<UCHAR>((size & 0x0000007f) >> 0);
1244+ sizes[2] = static_cast<UCHAR>((size & 0x00003f80) >> 7);
1245+ sizes[1] = static_cast<UCHAR>((size & 0x001fc000) >> 14);
1246+ sizes[0] = static_cast<UCHAR>((size & 0x0fe00000) >> 21);
1247+
1248+
1249+ length[0] = ((UINT16)sizes[1]) << 8 | sizes[0];
1250+ length[1] = ((UINT16)sizes[3]) << 8 | sizes[2];
1251+
1252+ return length;
1253+ }
1254+
1255+ protected:
1256+
1257+ TrackInfo m_info;
1258+ HANDLE m_hMp3File;
1259+};
1260+
1261+class DummyAmp
1262+{
1263+ public:
1264+
1265+ DummyAmp()
1266+ : m_bReady(false)
1267+ , m_hInstGenMixi((HINSTANCE)INVALID_HANDLE_VALUE)
1268+ , m_pGenMixi(NULL)
1269+ , m_hWinampWnd((HWND)INVALID_HANDLE_VALUE)
1270+ , m_GETPLAYLISTFILE_time(0)
1271+ , m_hDirChangeNotify((HANDLE)INVALID_HANDLE_VALUE)
1272+ , m_isDummyPlayInfoMp3Available(false)
1273+ , m_isAnotherWinampWindowAvailable(false)
1274+ {
1275+
1276+ m_winampTitle = _T("Winamp");
1277+ }
1278+
1279+ ~DummyAmp()
1280+ {
1281+ release();
1282+ destroyWindow();
1283+ closeDirChangeNotifyHandle();
1284+ }
1285+
1286+ public:
1287+
1288+ static DummyAmp *getInstance()
1289+ {
1290+ if(m_pMe == NULL)
1291+ {
1292+ m_pMe = new DummyAmp();
1293+ }
1294+
1295+ return m_pMe;
1296+ }
1297+
1298+ void load()
1299+ {
1300+ TRACE_DUMMYAMP_INIT(_T("DummyAmp::load - called."));
1301+
1302+ // initialize gen_mixi_for_winamp
1303+ initGenMixi();
1304+
1305+ // initialize dummy mp3 file, if dummy mp3 is enabled
1306+ if(cfg_disable_dummy_mp3 == 0) {
1307+ initDummyMp3();
1308+ }
1309+
1310+ // set ready flag, if initialization successfully done
1311+ if( (getGenMixi() != NULL) && ((cfg_disable_dummy_mp3 == 0) || (isDummyPlayInfoMp3Available() == true)) ){
1312+ setReady(true);
1313+ }
1314+ }
1315+
1316+ void config()
1317+ {
1318+ TRACE_DUMMYAMP_INIT(_T("DummyAmp::config - called."));
1319+
1320+ if(getGenMixi() != NULL) {
1321+ getGenMixi()->config();
1322+ }
1323+ }
1324+
1325+ void release()
1326+ {
1327+ TRACE_DUMMYAMP_INIT(_T("DummyAmp::release - called."));
1328+
1329+ // finalize gen_mixi_for_winamp
1330+ finalizeGenMixi();
1331+
1332+ // finalize dummy mp3 file, if dummy mp3 is enbaled
1333+ if(isDummyPlayInfoMp3Available())
1334+ {
1335+ finalizeDummyMp3();
1336+ }
1337+ }
1338+
1339+ void clearDummyAmpTitle()
1340+ {
1341+ uSetWindowText(getWnd(), DEFAULT_DUMMYAMP_TITLE);
1342+ }
1343+
1344+ void createWindow()
1345+ {
1346+ TRACE_PLUGIN(_T("DummyAmp::createWindow - called."));
1347+
1348+ if(getWnd() == INVALID_HANDLE_VALUE)
1349+ {
1350+ if(getGenMixi() != NULL)
1351+ {
1352+ HWND hAnotherWinamp = FindWindowEx(NULL, NULL, _T("Winamp v1.x"), NULL);
1353+
1354+ // found another winamp window
1355+ if(hAnotherWinamp != NULL)
1356+ {
1357+ DEBUG_PLUGIN(_T("DummyAmp::createWindow - Winamp のウィンドウを検出しました。ハンドル: %08x"), hAnotherWinamp);
1358+
1359+ DWORD dwAnotherWndProcessID;
1360+ ::GetWindowThreadProcessId(hAnotherWinamp, &dwAnotherWndProcessID);
1361+
1362+ DWORD dwFb2kProcessID = ::GetCurrentProcessId();
1363+
1364+ DEBUG_PLUGIN(_T("DummyAmp::createWindow - Winamp ウィンドウが属するプロセスのハンドル: %08x"), dwAnotherWndProcessID);
1365+ DEBUG_PLUGIN(_T("DummyAmp::createWindow - 現在実行中の foobar2000 プロセスのハンドル: %08x"), dwFb2kProcessID);
1366+
1367+ // another winamp window owned by foobar2000 process
1368+ if(dwAnotherWndProcessID == dwFb2kProcessID) {
1369+ // subclass it, because it's winamp api simulator plugin's window
1370+ setWnd(subclassWinampWindow(hAnotherWinamp));
1371+ } else {
1372+ LOG_ERROR(
1373+ _T("DummyAmp::createWindow - 検出した Winamp ウィンドウが他のプロセスに属しています"));
1374+ LOG_ERROR(
1375+ _T("DummyAmp::createWindow - Winamp と思われるプログラムが実行されているため、")
1376+ _T("mixi station への送信機能は使用できません"));
1377+ LOG_ERROR(
1378+ _T("DummyAmp::createWindow - 該当のプログラム(プロセスID:%d)を終了し、")
1379+ _T("foobar2000 を再起動してください")
1380+ , dwAnotherWndProcessID);
1381+
1382+ // unset dummyAmp ready flag
1383+ setReady(false);
1384+ }
1385+ }
1386+ // create own winamp simulating window
1387+ else
1388+ {
1389+ setWnd(createWinampWindow());
1390+ }
1391+
1392+ // initialize gen_mixi_for_winamp, if winamp window successfully created or subclassed
1393+ if(getWnd() != INVALID_HANDLE_VALUE)
1394+ {
1395+ getGenMixi()->hwndParent = getWnd();
1396+ getGenMixi()->hDllInstance = getHInstance();
1397+ getGenMixi()->init();
1398+ }
1399+ else
1400+ {
1401+ // unset dummyAmp ready flag
1402+ setReady(false);
1403+ }
1404+ }
1405+ }
1406+ }
1407+
1408+ void refreshAmpInfo()
1409+ {
1410+#if !defined(CONTROL_SEND_TIMING)
1411+ // increment play counter on dummyamp
1412+ getPlayInfo().incrementPlayCount();
1413+
1414+ // update dummyamp title
1415+ updateDummyAmpTitle();
1416+#endif
1417+ // use currently playing mp3 or ogg/vorbis file instead when dummy playinfo mp3 file disabled by user
1418+ // (other codec types will be ignored, because they are not supported by gen_mixi_for_winamp)
1419+ if(cfg_disable_dummy_mp3 == 1)
1420+ {
1421+ // set playinfo mp3 file path to dummyAmp
1422+ getPlayInfo().setPlayInfoMp3Path(m_trackInfo.getString(FORMAT_FILEPATH).c_str());
1423+
1424+ // set playinfo mp3 file available flag to dummyAmp
1425+ LPCSTR codec = m_trackInfo.getString(FORMAT_CODEC).c_str();
1426+ getPlayInfo().setPlayInfoMp3Available(IS_SUPPORTED_FORMAT_BY_GEN_MIXI(codec));
1427+ }
1428+ else
1429+ {
1430+ // check dummy playinfo mp3 exists and writable
1431+ if(isDummyPlayInfoMp3Available())
1432+ {
1433+ // update dummy mp3 file
1434+ tstring playInfoMp3Path = PathInfo::getDummyPlayInfoMp3Path();
1435+#if 1
1436+ id3Info id3Info(m_trackInfo);
1437+ DWORD dwErrCode;
1438+
1439+ if(( dwErrCode = id3Info.write(playInfoMp3Path.c_str()) ) == S_OK)
1440+ {
1441+ string_utf8_from_os dummyMp3Path8(playInfoMp3Path.c_str());
1442+
1443+ // set dummy playinfo mp3 file path to dummyAmp
1444+ getPlayInfo().setPlayInfoMp3Path(dummyMp3Path8);
1445+
1446+ // set playinfo mp3 file available flag to dummyAmp
1447+ getPlayInfo().setPlayInfoMp3Available(true);
1448+ }
1449+ else
1450+ {
1451+ putLogError(_T("DummyAmp::refreshAmpInfo"), _T("ダミーMP3ファイルの書き込み中にエラーが発生しました"), dwErrCode);
1452+ LOG_ERROR(_T("DummyAmp::refreshAmpInfo - ファイルパス: %s"), playInfoMp3Path.c_str());
1453+
1454+ // set playinfo mp3 file available flag
1455+ getPlayInfo().setPlayInfoMp3Available(false);
1456+
1457+ // unset dummyAmp ready flag
1458+ setReady(false);
1459+ }
1460+#else
1461+ // set id3v2 informations
1462+
1463+ string_utf8_from_os dummyMp3Path8(playInfoMp3Path.c_str());
1464+ string_ansi_from_utf8 dummyMp3PathAnsi(dummyMp3Path8);
1465+ ID3_Tag dummySong(dummyMp3PathAnsi);
1466+
1467+ string_wide_from_utf8 title_utf16(m_trackInfo.getString(FORMAT_TRACKTITLE, true).c_str());
1468+ string_wide_from_utf8 artist_utf16(m_trackInfo.getString(FORMAT_ARTIST, true).c_str());
1469+ string_wide_from_utf8 album_utf16(m_trackInfo.getString(FORMAT_ALBUMTITLE, true).c_str());
1470+ string_wide_from_utf8 genre_utf16(m_trackInfo.getString(FORMAT_GENRE, true).c_str());
1471+
1472+ AddTitle(&dummySong, title_utf16, true);
1473+ AddArtist(&dummySong, artist_utf16, true);
1474+ AddAlbum(&dummySong, album_utf16, true);
1475+ AddGenre(&dummySong, genre_utf16, true);
1476+
1477+ // write id3v2 tag
1478+ dummySong.SetPadding(false);
1479+ dummySong.SetUnsync(false);
1480+ if(dummySong.Update(ID3TT_ID3V2) != ID3TT_NONE)
1481+ {
1482+ // set dummy playinfo mp3 file path to dummyAmp
1483+ getPlayInfo().setPlayInfoMp3Path(dummyMp3Path8);
1484+
1485+ // set playinfo mp3 file available flag to dummyAmp
1486+ getPlayInfo().setPlayInfoMp3Available(true);
1487+ }
1488+ else
1489+ {
1490+ LOG_ERROR(_T("DummyAmp::refreshAmpInfo - ID3_Tag::Update(ID3TT_ID3V2) failed."));
1491+
1492+ // set playinfo mp3 file available flag
1493+ getPlayInfo().setPlayInfoMp3Available(false);
1494+
1495+ // unset dummyAmp ready flag
1496+ setReady(false);
1497+ }
1498+#endif
1499+ }
1500+ else
1501+ {
1502+ // reset playinfo mp3 file available flag
1503+ getPlayInfo().setPlayInfoMp3Available(false);
1504+
1505+ LOG_WARN(_T("DummyAmp::refreshAmpInfo - ダミーMP3ファイルが無効になっているため、送信情報を書き込めません。"));
1506+ }
1507+ }
1508+
1509+#if !defined(CONTROL_SEND_TIMING)
1510+ // set dummyamp status PLAY_START
1511+ getPlayInfo().setPlayStatusStart();
1512+#endif
1513+ }
1514+
1515+ public:
1516+
1517+ bool isReady() const {
1518+ return m_bReady;
1519+ }
1520+
1521+ HWND getWnd() const {
1522+ return m_hWinampWnd;
1523+ }
1524+
1525+ const TrackInfo &getTrackInfo() const {
1526+ return m_trackInfo;
1527+ }
1528+
1529+ TrackInfo &getMutableTrackInfo() {
1530+ return m_trackInfo;
1531+ }
1532+
1533+ void setTrackInfo(const TrackInfo &trackInfo) {
1534+ m_trackInfo = trackInfo;
1535+ }
1536+
1537+ PlayInfo &getPlayInfo() {
1538+ return m_playInfo;
1539+ }
1540+
1541+ PlayInfo &getRawPlayInfo() {
1542+ return m_rawPlayInfo;
1543+ }
1544+
1545+
1546+ void setPlaylistTitle(LPCTSTR pTitle) {
1547+
1548+ TRACE_PLUGIN(_T("DummyAmp::setPlayListTitle - %s"), pTitle);
1549+
1550+ m_playlistTitle = pTitle;
1551+
1552+ string_utf8_from_os playListTitle8(pTitle);
1553+
1554+ if(cfg_disable_ansi_trans == 1)
1555+ {
1556+
1557+ m_playlistTitle8 = playListTitle8;
1558+ }
1559+ else
1560+ {
1561+ string_ansi_from_utf8 playListTitleAnsi(playListTitle8);
1562+
1563+ m_playlistTitle8 = playListTitleAnsi;
1564+ }
1565+ }
1566+
1567+ const tstring &getPlaylistTitle() const {
1568+ return m_playlistTitle;
1569+ }
1570+
1571+ const string8 &getPlaylistTitle8() const {
1572+ return m_playlistTitle8;
1573+ }
1574+
1575+ void setWinampTitle(LPCTSTR pTitle) {
1576+
1577+ TRACE_PLUGIN(_T("DummyAmp::setWinampTitle - %s"), pTitle);
1578+
1579+ m_winampTitle = pTitle;
1580+ }
1581+
1582+ const tstring &getWinampTitle() const {
1583+ return m_winampTitle;
1584+ }
1585+
1586+ void setBaseWinampTitle(LPCTSTR pTitle)
1587+ {
1588+ TRACE_PLUGIN(_T("DummyAmp::setRawWinampTitle - %s"), pTitle);
1589+
1590+ m_baseWinampTitle = pTitle;
1591+
1592+ updateDummyAmpTitle();
1593+ }
1594+
1595+ const tstring &getBaseWinampTitle() const {
1596+ return m_baseWinampTitle;
1597+ }
1598+
1599+ const tstring &getDummyPlayInfoMp3Path() const {
1600+ return m_dummyPlayInfoMp3Path;
1601+ }
1602+
1603+ bool isDummyPlayInfoMp3Available() const {
1604+ return m_isDummyPlayInfoMp3Available;
1605+ }
1606+
1607+ bool isAnotherWinampWindowAvailable() const {
1608+ return m_isAnotherWinampWindowAvailable;
1609+ }
1610+
1611+ void showDummyAmpWindow(bool bShow) {
1612+ showDummyAmpWindow(getWnd(), bShow);
1613+ }
1614+
1615+ protected:
1616+
1617+ void initGenMixi()
1618+ {
1619+ string_os_from_utf8 path(cfg_gen_mixi_path);
1620+ tstring genMixiPath = path;
1621+ genMixiPath += GEN_MIXI_FILE_NAME;
1622+
1623+ setHInstance(::LoadLibrary(genMixiPath.c_str()));
1624+
1625+ if(getHInstance() == NULL)
1626+ {
1627+ setHInstance((HINSTANCE)INVALID_HANDLE_VALUE);
1628+
1629+ tstring msg;
1630+ msg = GEN_MIXI_FILE_NAME _T(" が見つかりません。\n以下のパスにファイルが存在するか確認してください。\n");
1631+ msg += genMixiPath;
1632+
1633+ string_utf8_from_os uMsg(msg.c_str());
1634+
1635+ uMessageBox(NULL, uMsg, PLUGIN_CAPTION, MB_ICONEXCLAMATION | MB_OK);
1636+ }
1637+ else
1638+ {
1639+ winampGeneralPurposePluginGetter funcWinampGetGeneralPurposePlugin = NULL;
1640+
1641+ funcWinampGetGeneralPurposePlugin = (winampGeneralPurposePluginGetter)
1642+ ::GetProcAddress(getHInstance(), GEN_MIXI_FUNC_NAME_GET_GENERAL_PURPOSE_PLUGIN);
1643+
1644+ if(funcWinampGetGeneralPurposePlugin != NULL)
1645+ {
1646+ setGenMixi(funcWinampGetGeneralPurposePlugin());
1647+ // create window later.
1648+ }
1649+ else
1650+ {
1651+ tstring msg;
1652+ msg = _T("関数 ") _T(GEN_MIXI_FUNC_NAME_GET_GENERAL_PURPOSE_PLUGIN) _T("() が見つかりません。\n")
1653+ GEN_MIXI_FILE_NAME _T(" が壊れている可能性があります。");
1654+
1655+ string_utf8_from_os uMsg(msg.c_str());
1656+
1657+ uMessageBox(NULL, uMsg, PLUGIN_CAPTION, MB_ICONEXCLAMATION | MB_OK);
1658+ }
1659+ }
1660+ }
1661+
1662+ void initDummyMp3()
1663+ {
1664+ // if dummy mp3 file not exist
1665+ tstring dummyPlayInfoMp3Path = PathInfo::getDummyPlayInfoMp3Path();
1666+ DWORD dwAttr = ::GetFileAttributes(dummyPlayInfoMp3Path.c_str());
1667+
1668+ if(dwAttr == -1)
1669+ {
1670+ // create dummy mp3 file
1671+ HANDLE hMp3File = ::CreateFile(
1672+ dummyPlayInfoMp3Path.c_str(), 0, 0, NULL,
1673+ CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL
1674+ );
1675+
1676+ if(hMp3File == INVALID_HANDLE_VALUE)
1677+ {
1678+ DWORD dwErrCode = ::GetLastError();
1679+ putLogError(_T("DummyAmp::initDummyMp3"), _T("ダミーMP3ファイルの作成中にエラーが発生しました"), dwErrCode);
1680+ LOG_ERROR(_T("DummyAmp::initDummyMp3 - ファイルパス: %s"), dummyPlayInfoMp3Path.c_str());
1681+
1682+ LOG_ERROR(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルが使用できないため、送信機能は無効になります"));
1683+ }
1684+ else
1685+ {
1686+ DEBUG_DUMMYAMP_INIT(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルを [%s] に作成しました"), dummyPlayInfoMp3Path.c_str());
1687+
1688+ ::CloseHandle(hMp3File);
1689+
1690+ setDummyPlayInfoMp3Path(dummyPlayInfoMp3Path);
1691+ setDummyPlayInfoMp3Available(true);
1692+ }
1693+ }
1694+ else if((dwAttr & FILE_ATTRIBUTE_READONLY) != 0)
1695+ {
1696+ LOG_ERROR(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルがパス [%s] 上に既に存在しますが、")
1697+ _T("読み込み専用属性のため書き込みできません"), dummyPlayInfoMp3Path.c_str());
1698+
1699+ LOG_ERROR(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルが使用できないため、送信機能は無効になります"));
1700+ }
1701+ else
1702+ {
1703+ LOG_WARN(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルがパス [%s] 上に既に存在します"), dummyPlayInfoMp3Path.c_str());
1704+ LOG_WARN(_T("DummyAmp::initDummyMp3 - このMP3ファイルは逐次上書きされ、終了時に削除されます"));
1705+
1706+ setDummyPlayInfoMp3Path(dummyPlayInfoMp3Path);
1707+ setDummyPlayInfoMp3Available(true);
1708+ }
1709+ }
1710+
1711+ void finalizeGenMixi()
1712+ {
1713+ if(getHInstance() != INVALID_HANDLE_VALUE)
1714+ {
1715+ if(getGenMixi() != NULL)
1716+ {
1717+ getGenMixi()->quit();
1718+ setGenMixi(NULL);
1719+ }
1720+ ::FreeLibrary(getHInstance());
1721+ setHInstance((HINSTANCE)INVALID_HANDLE_VALUE);
1722+ }
1723+
1724+ }
1725+
1726+ void finalizeDummyMp3()
1727+ {
1728+ tstring dummyPlayInfoMp3Path = getDummyPlayInfoMp3Path();
1729+
1730+ if(::DeleteFile(dummyPlayInfoMp3Path.c_str()) == FALSE)
1731+ {
1732+ DWORD dwErrCode = ::GetLastError();
1733+ putLogError(_T("DummyAmp::finalizeDummyMp3"), _T("ダミーMP3ファイルの削除中にエラーが発生しました"), dwErrCode);
1734+ LOG_ERROR(_T("DummyAmp::finalizeDummyMp3 - ファイルパス: %s"), dummyPlayInfoMp3Path.c_str());
1735+ }
1736+ else
1737+ {
1738+ DEBUG_DUMMYAMP_INIT(_T("DummyAmp::finalizeDummyMp3 - ダミーMP3ファイル [%s] を削除しました"), dummyPlayInfoMp3Path.c_str());
1739+ setDummyPlayInfoMp3Available(false);
1740+ }
1741+ }
1742+
1743+ void updateDummyAmpTitle()
1744+ {
1745+ bool bDisableDuplicatedSong = (cfg_disable_duplicate_song == 0);
1746+ tstring winampTitle = makeDummyAmpTitle(getBaseWinampTitle(), bDisableDuplicatedSong);
1747+
1748+ setWinampTitle(winampTitle.c_str());
1749+
1750+ if(isAnotherWinampWindowAvailable() == false) {
1751+ ::SetWindowText(getWnd(), winampTitle.c_str());
1752+ }
1753+ }
1754+
1755+ protected:
1756+
1757+ void setReady(bool bReady) {
1758+ m_bReady = bReady;
1759+ }
1760+
1761+ void setWnd(HWND hWnd) {
1762+ m_hWinampWnd = hWnd;
1763+ }
1764+
1765+ HINSTANCE getHInstance() const {
1766+ return m_hInstGenMixi;
1767+ }
1768+
1769+ void setHInstance(HINSTANCE hInst) {
1770+ m_hInstGenMixi = hInst;
1771+ }
1772+
1773+ winampGeneralPurposePlugin *getGenMixi() const {
1774+ return m_pGenMixi;
1775+ }
1776+
1777+ void setGenMixi(winampGeneralPurposePlugin *pGenMixi) {
1778+ m_pGenMixi = pGenMixi;
1779+ }
1780+
1781+ void setDummyPlayInfoMp3Path(const tstring &path) {
1782+ m_dummyPlayInfoMp3Path = path;
1783+ }
1784+
1785+ void setDummyPlayInfoMp3Available(bool isAvailable) {
1786+ m_isDummyPlayInfoMp3Available = isAvailable;
1787+ }
1788+
1789+ void setAnotherWinampWindowAvailable(bool isAvailable) {
1790+ m_isAnotherWinampWindowAvailable = isAvailable;
1791+ }
1792+
1793+ int getGetPlayListFileTime() const {
1794+ return m_GETPLAYLISTFILE_time;
1795+ }
1796+
1797+ void setGetPlayListFileTime(int time) {
1798+ m_GETPLAYLISTFILE_time = time;
1799+ }
1800+
1801+ HANDLE getDirChangeNotifyHandle() const {
1802+ return m_hDirChangeNotify;
1803+ }
1804+
1805+ void setDirChangeNotifyHandle(HANDLE handle) {
1806+ m_hDirChangeNotify = handle;
1807+ }
1808+
1809+ protected:
1810+
1811+ HWND createWinampWindow()
1812+ {
1813+ TRACE_PLUGIN(_T("DummyAmp::createWinampWindow - called."));
1814+
1815+ static bool isInited = false;
1816+
1817+#if IS_FB2K_VER08
1818+ static const char class_name[] = "Winamp v1.x";
1819+ if (!isInited)
1820+ {
1821+ isInited = true;
1822+ uWNDCLASS wc;
1823+ memset(&wc,0,sizeof(wc));
1824+ wc.style = 0;
1825+ wc.lpfnWndProc = windowproc;
1826+ wc.hInstance = core_api::get_my_instance();
1827+ wc.hCursor = NULL; //uLoadCursor(0, IDC_ARROW);
1828+ wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
1829+ wc.lpszClassName = class_name;
1830+ uRegisterClass(&wc);
1831+ }
1832+ HWND hWinampWnd = uCreateWindowEx(
1833+ 0, class_name, DEFAULT_DUMMYAMP_TITLE,
1834+ WS_OVERLAPPED|WS_CAPTION|WS_SIZEBOX,
1835+ CW_USEDEFAULT, CW_USEDEFAULT, 300, 150,
1836+#if 1
1837+ core_api::get_main_window(), 0, core_api::get_my_instance(), NULL
1838+#else
1839+ NULL, 0, core_api::get_my_instance(), NULL
1840+#endif
1841+ );
1842+#elif IS_FB2K_VER09
1843+ static const TCHAR class_name[] = _T("Winamp v1.x");
1844+ if (!isInited)
1845+ {
1846+ isInited = true;
1847+ WNDCLASS wc;
1848+ memset(&wc,0,sizeof(wc));
1849+ wc.style = 0;
1850+ wc.lpfnWndProc = windowproc;
1851+ wc.hInstance = core_api::get_my_instance();
1852+ wc.hCursor = NULL; //uLoadCursor(0, IDC_ARROW);
1853+ wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
1854+ wc.lpszClassName = class_name;
1855+ RegisterClass(&wc);
1856+ }
1857+ HWND hWinampWnd = CreateWindowEx(
1858+ 0, class_name, _T(DEFAULT_DUMMYAMP_TITLE),
1859+ WS_OVERLAPPED|WS_CAPTION|WS_SIZEBOX,
1860+ CW_USEDEFAULT, CW_USEDEFAULT, 300, 150,
1861+#if 1
1862+ core_api::get_main_window(), 0, core_api::get_my_instance(), NULL
1863+#else
1864+ NULL, 0, core_api::get_my_instance(), NULL
1865+#endif
1866+ );
1867+#endif
1868+ if (!hWinampWnd)
1869+ {
1870+ DWORD dwErrCode = ::GetLastError();
1871+ putLogError(_T("DummyAmp::createWinampWindow"), _T("DummyAmp ウィンドウの生成に失敗しました"), dwErrCode);
1872+
1873+ return NULL;
1874+ }
1875+
1876+ DEBUG_PLUGIN(_T("DummyAmp::createWinampWindow - DummyAmp ウィンドウを生成しました"));
1877+
1878+ showDummyAmpWindow(hWinampWnd, cfg_show_dummyamp == 1);
1879+
1880+ return hWinampWnd;
1881+ }
1882+
1883+ HWND subclassWinampWindow(HWND hAnotherWinampWnd) {
1884+ // subclass another dummyamp window
1885+ m_pfnOldAnotherWinampProc =
1886+ SetWindowLongPtr(hAnotherWinampWnd, GWL_WNDPROC, WNDPROC_TO_LONG_PTR(hookWinampWindowProc));
1887+
1888+ if(hAnotherWinampWnd != NULL)
1889+ {
1890+ DEBUG_PLUGIN(_T("DummyAmp::subclassWinampWindow - API エミュレータと思われる Winamp ウィンドウのプロシージャをフックしました"));
1891+ setAnotherWinampWindowAvailable(true);
1892+
1893+ return hAnotherWinampWnd;
1894+ }
1895+ else
1896+ {
1897+ DWORD dwErrCode = ::GetLastError();
1898+ putLogError(_T("DummyAmp::subclassWinampWindow"), _T("Winamp ウィンドウのサブクラス化に失敗しました"), dwErrCode);
1899+
1900+ LOG_ERROR(_T("DummyAmp::subclassWinampWindow - Winamp ウィンドウのプロシージャをフックできなかったため、送信機能は無効になります"));
1901+ }
1902+
1903+ return (HWND)INVALID_HANDLE_VALUE;
1904+ }
1905+
1906+ void unsubclassWinampWindow() {
1907+ SetWindowLongPtr(getWnd(), GWL_WNDPROC, m_pfnOldAnotherWinampProc);
1908+ }
1909+
1910+ void showDummyAmpWindow(HWND hWinampWnd, bool bShow)
1911+ {
1912+ if(bShow) {
1913+ ShowWindow(hWinampWnd, SW_SHOW);
1914+ } else {
1915+ ShowWindow(hWinampWnd, SW_HIDE);
1916+ }
1917+ }
1918+
1919+ void destroyWindow()
1920+ {
1921+ TRACE_PLUGIN(_T("DummyAmp::destroyWindow - called."));
1922+
1923+ if(getWnd() != INVALID_HANDLE_VALUE)
1924+ {
1925+ if(isAnotherWinampWindowAvailable() == false) {
1926+ uDestroyWindow(getWnd());
1927+ } else {
1928+ unsubclassWinampWindow();
1929+
1930+ DEBUG_PLUGIN(_T("DummyAmp::destroyWindow - Winamp ウィンドウのサブクラス化を解除しました"));
1931+ }
1932+
1933+ setWnd((HWND)INVALID_HANDLE_VALUE);
1934+ }
1935+ }
1936+
1937+ void closeDirChangeNotifyHandle()
1938+ {
1939+ TRACE_PLUGIN(_T("DummyAmp::closeDirChangeNotifyHandle - called."));
1940+
1941+ if(m_hDirChangeNotify != INVALID_HANDLE_VALUE)
1942+ {
1943+ ::FindCloseChangeNotification(m_hDirChangeNotify);
1944+ TRACE_PLUGIN(_T("DummyAmp::closeDirChangeNotifyHandle - ディレクトリ変更通知イベントのハンドル (ID:%08x) を閉じました"), m_hDirChangeNotify);
1945+
1946+ m_hDirChangeNotify = (HANDLE)INVALID_HANDLE_VALUE;
1947+ }
1948+ }
1949+
1950+ tstring makeDummyAmpTitle(const tstring &rawTitle, bool bCounterReflection)
1951+ {
1952+ TRACE_PLUGIN(_T("DummyAmp::makeDummyAmpTitle - called."));
1953+
1954+ Str64K formatBuf;
1955+
1956+ if(bCounterReflection)
1957+ {
1958+ _stprintf_s(
1959+ formatBuf, sizeof(formatBuf) / sizeof(TCHAR),
1960+ _T("%d. %s - ") _T(DEFAULT_WINAMP_TITLE),
1961+ getPlayInfo().getPlayCount(),
1962+ (LPCTSTR)rawTitle.c_str()
1963+ );
1964+ }
1965+ else
1966+ {
1967+ _stprintf_s(
1968+ formatBuf, sizeof(formatBuf) / sizeof(TCHAR),
1969+ _T("%d. %s - ") _T(DEFAULT_WINAMP_TITLE),
1970+ m_trackInfo.getNumber(FORMAT_LISTINDEX),
1971+ (LPCTSTR)rawTitle.c_str()
1972+ );
1973+ }
1974+
1975+ return formatBuf;
1976+ }
1977+
1978+ void refreshTitle()
1979+ {
1980+ // get formatted dynamic titles
1981+ string8 dummyAmp_title8;
1982+ string8 playlist_title8;
1983+#if IS_FB2K_VER08
1984+ metadb_handle *track = play_control::get()->get_now_playing();
1985+ if(track)
1986+ {
1987+ play_control::get()->playback_format_title_ex(track, dummyAmp_title8, cfg_dummyamp_title_format, NULL, false, true);
1988+ play_control::get()->playback_format_title_ex(track, playlist_title8, cfg_dummyamp_playlist_format, NULL, false, true);
1989+ track->handle_release();
1990+ }
1991+#elif IS_FB2K_VER09
1992+ metadb_handle_ptr track;
1993+ static_api_ptr_t<playback_control>()->get_now_playing(track);
1994+
1995+ service_ptr_t<titleformat_object> titleformat;
1996+
1997+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, cfg_dummyamp_title_format);
1998+ static_api_ptr_t<playback_control>()->playback_format_title_ex(track, NULL, dummyAmp_title8, titleformat, NULL, play_control::display_level_all);
1999+
2000+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, cfg_dummyamp_playlist_format);
2001+ static_api_ptr_t<playback_control>()->playback_format_title_ex(track, NULL, playlist_title8, titleformat, NULL, play_control::display_level_all);
2002+#endif
2003+ // convert utf8 track informations to os charset
2004+ string_os_from_utf8 dummyAmp_title(dummyAmp_title8);
2005+ string_os_from_utf8 playlist_title(playlist_title8);
2006+
2007+ // set base dummyamp title to dummyamp
2008+ setBaseWinampTitle(dummyAmp_title);
2009+
2010+ // set dummyamp playlist current item title to dummyamp
2011+ setPlaylistTitle(playlist_title);
2012+ }
2013+
2014+#if 0
2015+ private:
2016+
2017+ ID3_Frame* AddArtist(ID3_Tag *tag, const wchar_t *text, bool replace)
2018+ {
2019+ ID3_Frame* frame = NULL;
2020+ if (NULL != tag && NULL != text && lstrlen(text) > 0)
2021+ {
2022+ if (replace)
2023+ {
2024+ RemoveArtists(tag);
2025+ }
2026+ if (replace ||
2027+ (tag->Find(ID3FID_LEADARTIST) == NULL &&
2028+ tag->Find(ID3FID_BAND) == NULL &&
2029+ tag->Find(ID3FID_CONDUCTOR) == NULL &&
2030+ tag->Find(ID3FID_COMPOSER) == NULL))
2031+ {
2032+ frame = new ID3_Frame(ID3FID_LEADARTIST);
2033+ if (frame)
2034+ {
2035+ frame->GetField(ID3FN_TEXT)->SetEncoding(ID3TE_UNICODE);
2036+ frame->GetField(ID3FN_TEXT)->Set(SwapByteOrder(text));
2037+ frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_UNICODE);
2038+ tag->AttachFrame(frame);
2039+ }
2040+ }
2041+ }
2042+ return frame;
2043+ }
2044+
2045+ size_t RemoveArtists(ID3_Tag *tag)
2046+ {
2047+ size_t num_removed = 0;
2048+ ID3_Frame *frame = NULL;
2049+
2050+ if (NULL == tag)
2051+ {
2052+ return num_removed;
2053+ }
2054+
2055+ while ((frame = tag->Find(ID3FID_LEADARTIST)) != NULL)
2056+ {
2057+ frame = tag->RemoveFrame(frame);
2058+ delete frame;
2059+ num_removed++;
2060+ }
2061+ while ((frame = tag->Find(ID3FID_BAND)) != NULL)
2062+ {
2063+ frame = tag->RemoveFrame(frame);
2064+ delete frame;
2065+ num_removed++;
2066+ }
2067+ while ((frame = tag->Find(ID3FID_CONDUCTOR)) != NULL)
2068+ {
2069+ frame = tag->RemoveFrame(frame);
2070+ delete frame;
2071+ num_removed++;
2072+ }
2073+ while ((frame = tag->Find(ID3FID_COMPOSER)) != NULL)
2074+ {
2075+ frame = tag->RemoveFrame(frame);
2076+ delete frame;
2077+ num_removed++;
2078+ }
2079+
2080+ return num_removed;
2081+ }
2082+
2083+ ID3_Frame* AddAlbum(ID3_Tag *tag, const wchar_t *text, bool replace)
2084+ {
2085+ ID3_Frame* frame = NULL;
2086+ if (NULL != tag && NULL != text && lstrlen(text) > 0)
2087+ {
2088+ if (replace)
2089+ {
2090+ RemoveAlbums(tag);
2091+ }
2092+ if (replace || tag->Find(ID3FID_ALBUM) == NULL)
2093+ {
2094+ frame = new ID3_Frame(ID3FID_ALBUM);
2095+ if (frame)
2096+ {
2097+ frame->GetField(ID3FN_TEXT)->SetEncoding(ID3TE_UNICODE);
2098+ frame->GetField(ID3FN_TEXT)->Set(SwapByteOrder(text));
2099+ frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_UNICODE);
2100+ tag->AttachFrame(frame);
2101+ }
2102+ }
2103+ }
2104+
2105+ return frame;
2106+ }
2107+
2108+ size_t RemoveAlbums(ID3_Tag *tag)
2109+ {
2110+ size_t num_removed = 0;
2111+ ID3_Frame *frame = NULL;
2112+
2113+ if (NULL == tag)
2114+ {
2115+ return num_removed;
2116+ }
2117+
2118+ while ((frame = tag->Find(ID3FID_ALBUM)) != NULL)
2119+ {
2120+ frame = tag->RemoveFrame(frame);
2121+ delete frame;
2122+ num_removed++;
2123+ }
2124+
2125+ return num_removed;
2126+ }
2127+
2128+ ID3_Frame* AddTitle(ID3_Tag *tag, const wchar_t *text, bool replace)
2129+ {
2130+ ID3_Frame* frame = NULL;
2131+ if (NULL != tag && NULL != text && lstrlen(text) > 0)
2132+ {
2133+ if (replace)
2134+ {
2135+ RemoveTitles(tag);
2136+ }
2137+ if (replace || tag->Find(ID3FID_TITLE) == NULL)
2138+ {
2139+ frame = new ID3_Frame(ID3FID_TITLE);
2140+ if (frame)
2141+ {
2142+ frame->GetField(ID3FN_TEXT)->SetEncoding(ID3TE_UNICODE);
2143+ frame->GetField(ID3FN_TEXT)->Set(SwapByteOrder(text));
2144+ frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_UNICODE);
2145+ tag->AttachFrame(frame);
2146+ }
2147+ }
2148+ }
2149+
2150+ return frame;
2151+ }
2152+
2153+ size_t RemoveTitles(ID3_Tag *tag)
2154+ {
2155+ size_t num_removed = 0;
2156+ ID3_Frame *frame = NULL;
2157+
2158+ if (NULL == tag)
2159+ {
2160+ return num_removed;
2161+ }
2162+
2163+ while ((frame = tag->Find(ID3FID_TITLE)) != NULL)
2164+ {
2165+ frame = tag->RemoveFrame(frame);
2166+ delete frame;
2167+ num_removed++;
2168+ }
2169+
2170+ return num_removed;
2171+ }
2172+
2173+ //following routine courtesy of John George
2174+ ID3_Frame* AddGenre(ID3_Tag* tag, const wchar_t *genre, bool replace)
2175+ {
2176+ ID3_Frame* frame = NULL;
2177+ if (NULL != tag && NULL != genre && lstrlen(genre) > 0)
2178+ {
2179+ if (replace)
2180+ {
2181+ RemoveGenres(tag);
2182+ }
2183+ if (replace || NULL == tag->Find(ID3FID_CONTENTTYPE))
2184+ {
2185+ frame = new ID3_Frame(ID3FID_CONTENTTYPE);
2186+ if (NULL != frame)
2187+ {
2188+ frame->GetField(ID3FN_TEXT)->SetEncoding(ID3TE_UNICODE);
2189+ frame->GetField(ID3FN_TEXT)->Set(SwapByteOrder(genre));
2190+ frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_UNICODE);
2191+ tag->AttachFrame(frame);
2192+ }
2193+ }
2194+ }
2195+
2196+ return frame;
2197+ }
2198+
2199+ size_t RemoveGenres(ID3_Tag *tag)
2200+ {
2201+ size_t num_removed = 0;
2202+ ID3_Frame *frame = NULL;
2203+
2204+ if (NULL == tag)
2205+ {
2206+ return num_removed;
2207+ }
2208+
2209+ while ((frame = tag->Find(ID3FID_CONTENTTYPE)) != NULL)
2210+ {
2211+ frame = tag->RemoveFrame(frame);
2212+ delete frame;
2213+ num_removed++;
2214+ }
2215+
2216+ return num_removed;
2217+ }
2218+
2219+ const unicode_t *SwapByteOrder(const wchar_t *text)
2220+ {
2221+ static unicode_t resBuf[65536];
2222+ const wchar_t *pText;
2223+ unicode_t *pBuf;
2224+
2225+ for(pText = text, pBuf = resBuf; *pText != L'\0'; pText ++, pBuf ++)
2226+ {
2227+ wchar_t srcVal = *pText;
2228+ //unicode_t dstVal = srcVal;
2229+ unicode_t dstVal = (srcVal << 8) | (srcVal >> 8);
2230+ *pBuf = dstVal;
2231+ }
2232+
2233+ *pBuf = L'\0';
2234+
2235+ return resBuf;
2236+ }
2237+#endif
2238+
2239+ protected:
2240+
2241+ static LRESULT WINAPI hookWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp);
2242+ static LRESULT WINAPI windowproc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp);
2243+ static std::pair<bool, LRESULT> WINAPI innerWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp);
2244+ static std::pair<bool, LRESULT> WINAPI outerWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp);
2245+
2246+ protected:
2247+
2248+ static DummyAmp *m_pMe;
2249+
2250+ bool m_bReady;
2251+
2252+ HINSTANCE m_hInstGenMixi;
2253+ winampGeneralPurposePlugin *m_pGenMixi;
2254+
2255+ HWND m_hWinampWnd;
2256+ bool m_isAnotherWinampWindowAvailable;
2257+
2258+ static LONG_PTR m_pfnOldAnotherWinampProc;
2259+
2260+ HANDLE m_hDirChangeNotify;
2261+
2262+ PlayInfo m_playInfo;
2263+ PlayInfo m_rawPlayInfo;
2264+
2265+ TrackInfo m_trackInfo;
2266+ int m_GETPLAYLISTFILE_time;
2267+
2268+ tstring m_playlistTitle;
2269+ string8 m_playlistTitle8;
2270+
2271+ tstring m_winampTitle;
2272+ tstring m_baseWinampTitle;
2273+
2274+ tstring m_dummyPlayInfoMp3Path;
2275+ bool m_isDummyPlayInfoMp3Available;
2276+};
2277+
2278+DummyAmp *DummyAmp::m_pMe = NULL;
2279+
2280+LONG_PTR DummyAmp::m_pfnOldAnotherWinampProc = NULL;
2281+
2282+LRESULT CALLBACK DummyAmp::hookWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp)
2283+{
2284+ if(InSendMessage() || (msg != WM_WA_IPC))
2285+ {
2286+ switch(msg)
2287+ {
2288+ case WM_CLOSE:
2289+ DEBUG_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_CLOSE %s"),
2290+ InSendMessage() == TRUE ? _T("from other thread") : _T(""));
2291+
2292+ DummyAmp::getInstance()->destroyWindow();
2293+ break;
2294+
2295+ case WM_GETTEXT:
2296+ {
2297+ // message from same thread
2298+ if((InSendMessage() == FALSE) && (DummyAmp::getInstance()->isAnotherWinampWindowAvailable() == true))
2299+ {
2300+ LPCTSTR pWinampTitle = DummyAmp::getInstance()->getWinampTitle().c_str();
2301+ int nLen = ::lstrlen(pWinampTitle);
2302+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_GETTEXT / window title [%s]."), pWinampTitle);
2303+
2304+ ::lstrcpyn(reinterpret_cast<LPTSTR>(lp), pWinampTitle, static_cast<int>(wp));
2305+
2306+ return (LRESULT)nLen;
2307+ }
2308+ }
2309+ break;
2310+
2311+ case WM_GETTEXTLENGTH:
2312+ {
2313+ // message from same thread
2314+ if((InSendMessage() == FALSE) && (DummyAmp::getInstance()->isAnotherWinampWindowAvailable() == true))
2315+ {
2316+ LPCTSTR pWinampTitle = DummyAmp::getInstance()->getWinampTitle().c_str();
2317+ int nLen = ::lstrlen(pWinampTitle);
2318+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_GETTEXTLENGTH / window title length %d."), nLen);
2319+
2320+ return (LRESULT)nLen;
2321+ }
2322+ }
2323+ break;
2324+
2325+ case WM_SETTEXT:
2326+ {
2327+ // message from same thread
2328+ if((InSendMessage() == FALSE) && (DummyAmp::getInstance()->isAnotherWinampWindowAvailable() == true))
2329+ {
2330+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_SETTEXT / window title [%s]."), reinterpret_cast<LPCTSTR>(lp));
2331+ }
2332+ }
2333+ break;
2334+
2335+ default:
2336+
2337+ if(InSendMessage())
2338+ {
2339+ if(msg == WM_WA_IPC) {
2340+ if(cfg_enable_ext_ipc_proc == 1)
2341+ {
2342+ std::pair<bool, LRESULT> res = outerWinampWindowProc(wnd, msg, wp, lp);
2343+ if(res.first == true) {
2344+ return res.second;
2345+ }
2346+ }
2347+
2348+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_WA_IPC from other thread / W:%08x, L:%08x"), wp, lp);
2349+
2350+ }
2351+ else
2352+ {
2353+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - ")
2354+ _T("message from other thread / MSG:%04x, W:%08x, L:%08x"), msg, wp, lp);
2355+ }
2356+ }
2357+
2358+ break;
2359+ }
2360+
2361+ return CallWindowProc(LONG_PTR_TO_WNDPROC(m_pfnOldAnotherWinampProc), wnd, msg, wp, lp);
2362+ }
2363+ else
2364+ {
2365+ return CallWindowProc(windowproc, wnd, msg, wp, lp);
2366+ }
2367+}
2368+
2369+LRESULT CALLBACK DummyAmp::windowproc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp)
2370+{
2371+ switch(msg)
2372+ {
2373+ case WM_CLOSE:
2374+ DEBUG_DUMMYAMP_PROC(_T("DummyAmp::windowproc - WM_CLOSE"));
2375+ DummyAmp::getInstance()->destroyWindow();
2376+ return 0;
2377+
2378+ case WM_WA_IPC:
2379+ // message from same thread
2380+ if(InSendMessage() == FALSE)
2381+ {
2382+ std::pair<bool, LRESULT> res = innerWinampWindowProc(wnd, msg, wp, lp);
2383+ if(res.first == true) {
2384+ return res.second;
2385+ }
2386+ }
2387+ // message from other thread
2388+ else
2389+ {
2390+ std::pair<bool, LRESULT> res = outerWinampWindowProc(wnd, msg, wp, lp);
2391+ if(res.first == true) {
2392+ return res.second;
2393+ }
2394+ }
2395+ break;
2396+ default:
2397+ if(InSendMessage()) {
2398+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::windowproc - Unknown MSG from other thread / MSG:%04x, W:%08x, L:%08x"), msg, wp, lp);
2399+ }
2400+ break;
2401+ }
2402+
2403+ return uDefWindowProc(wnd,msg,wp,lp);
2404+}
2405+
2406+std::pair<bool, LRESULT> WINAPI DummyAmp::innerWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp)
2407+{
2408+ switch(msg)
2409+ {
2410+ case WM_WA_IPC:
2411+ {
2412+ PlayInfo::EPlayStatus playStatus = DummyAmp::getInstance()->getPlayInfo().getPlayStatus();
2413+ int playPosition = DummyAmp::getInstance()->getPlayInfo().getPlayPosition();
2414+ int playLength = DummyAmp::getInstance()->getPlayInfo().getPlayLength();
2415+ int playCount = DummyAmp::getInstance()->getPlayInfo().getPlayCount();
2416+ int getPlayListFileTime = DummyAmp::getInstance()->getGetPlayListFileTime();
2417+ bool isPlayInfoMp3Available = DummyAmp::getInstance()->getPlayInfo().isPlayInfoMp3Available();
2418+ const string8 &playInfoMp3Path8 = DummyAmp::getInstance()->getPlayInfo().getPlayInfoMp3Path8();
2419+
2420+ switch(lp)
2421+ {
2422+ case IPC_ISPLAYING:
2423+ if(cfg_use_plugin == 1)
2424+ {
2425+ HANDLE hDirChangeNotify = DummyAmp::getInstance()->getDirChangeNotifyHandle();
2426+
2427+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_ISPLAYING / status [%d]"), playStatus);
2428+
2429+ if(playStatus != PlayInfo::PLAY_START)
2430+ {
2431+ if(DummyAmp::getInstance()->getPlayInfo().isResentMode()) {
2432+ DummyAmp::getInstance()->getPlayInfo().clearResentMode();
2433+ }
2434+
2435+ if(hDirChangeNotify != INVALID_HANDLE_VALUE)
2436+ {
2437+ LOG_WARN(_T("DummyAmp::innerWinampWindowProc - ディレクトリ変更通知イベントのハンドルが閉じられていません"));
2438+ LOG_WARN(_T("DummyAmp::innerWinampWindowProc - 安全のため、ここで閉じます"));
2439+ DummyAmp::getInstance()->closeDirChangeNotifyHandle();
2440+ }
2441+ }
2442+ else
2443+ {
2444+ if(hDirChangeNotify != INVALID_HANDLE_VALUE)
2445+ {
2446+ DWORD dwRes = ::WaitForMultipleObjects(1, &hDirChangeNotify, FALSE, 0);
2447+
2448+ if(dwRes == WAIT_OBJECT_0)
2449+ {
2450+ LOG_INFO(_T("mixi station successfully updated."));
2451+ DummyAmp::getInstance()->closeDirChangeNotifyHandle();
2452+ DummyAmp::getInstance()->getPlayInfo().setPlayStatusStop();
2453+ }
2454+ else if(playPosition >= getPlayListFileTime + RESENT_INTERVAL)
2455+ {
2456+ DummyAmp::getInstance()->closeDirChangeNotifyHandle();
2457+ LOG_WARN(_T("DummyAmp::innerWinampWindowProc - mixi station ディレクトリの変更通知イベントが待ち時間内に発生しませんでした"));
2458+#if !defined(DISABLE_KICK_GEN_MIXI_LOOP)
2459+ LOG_WARN(_T("DummyAmp::innerWinampWindowProc - gen_mixi_for_winamp に曲情報取得要求を再送させます"));
2460+ DummyAmp::getInstance()->getPlayInfo().setResentMode();
2461+ DummyAmp::getInstance()->updateDummyAmpTitle();
2462+#else
2463+ LOG_WARN(_T("DummyAmp::innerWinampWindowProc - 曲情報は破棄されました"));
2464+#endif
2465+ }
2466+ }
2467+ }
2468+ return std::make_pair(true, playStatus);
2469+ }
2470+ return std::make_pair(true, PlayInfo::PLAY_STOP);
2471+
2472+ case IPC_GETOUTPUTTIME:
2473+ if(cfg_use_plugin == 1)
2474+ {
2475+ if(playStatus == PlayInfo::PLAY_START)
2476+ {
2477+ if(wp == IPC_GETOUTPUTTIME_PositionMSec)
2478+ {
2479+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_GETOUTPUTTIME / position [%d sec.]"), playPosition / 1000);
2480+
2481+ return std::make_pair(true, playPosition);
2482+ }
2483+ else if(wp == IPC_GETOUTPUTTIME_TotalSec)
2484+ {
2485+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_GETOUTPUTTIME / length [%d sec.]"), playLength);
2486+ return std::make_pair(true, playLength);
2487+ }
2488+ }
2489+ }
2490+ return std::make_pair(true, -1);
2491+
2492+ case IPC_GETLISTPOS:
2493+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_GETLISTPOS / index [%d]"), playCount);
2494+ return std::make_pair(true, playCount);
2495+
2496+ case IPC_GETPLAYLISTFILE:
2497+ if(cfg_use_plugin == 1)
2498+ {
2499+ if(isPlayInfoMp3Available == true)
2500+ {
2501+ DEBUG_DUMMYAMP_PROC8(
2502+ "DummyAmp::innerWinampWindowProc - IPC_GETPLAYLISTFILE / #%d - path [%s]",
2503+ playCount, (LPCSTR)playInfoMp3Path8);
2504+
2505+ DummyAmp::getInstance()->setGetPlayListFileTime(playPosition);
2506+
2507+ tstring mixiAppDataPath = PathInfo::getMixiStationAppPath();
2508+
2509+ DummyAmp::getInstance()->setDirChangeNotifyHandle(
2510+ ::FindFirstChangeNotification(mixiAppDataPath.c_str(), FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE)
2511+ );
2512+
2513+ return std::make_pair(true, (LRESULT)(LPCSTR)playInfoMp3Path8);
2514+ }
2515+ else
2516+ {
2517+ if(cfg_disable_dummy_mp3 == 1)
2518+ {
2519+ DEBUG_DUMMYAMP_PROC(_T("DummyAm::innerWinampWindowProcp - IPC_GETPLAYLISTFILE / NULL (audio file codec type not supported.)"));
2520+ }
2521+ else
2522+ {
2523+ LOG_WARN(_T("DummyAmp::innerWinampWindowProc - IPC_GETPLAYLISTFILE / NULL (dummy mp3 file not enabled.)"));
2524+ }
2525+ }
2526+ }
2527+ return std::make_pair(true, NULL);
2528+
2529+ case IPC_INTERNAL_REFRESHLISTINFO: // 0x4000
2530+ {
2531+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_INTERNAL_REFRESHLISTINFO / refresh internal playlist informations."));
2532+
2533+ // make playlist info formats array
2534+ Strings plNumKeys;
2535+
2536+ plNumKeys.push_back(FORMAT_LISTINDEX);
2537+
2538+ // set current track informations
2539+ DummyAmp::getInstance()->getMutableTrackInfo().setPlaylistNumbers(plNumKeys);
2540+
2541+ // refresh dummyamp title
2542+ DummyAmp::getInstance()->refreshTitle();
2543+
2544+ return std::make_pair(true, 0);
2545+ }
2546+
2547+ case IPC_INTERNAL_REFRESHDYNINFO: // 0x4001
2548+ {
2549+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_INTERNAL_REFRESHDYNINFO / refresh internal dynamic informations."));
2550+
2551+ // make dynamic info formats array
2552+ Strings dynStrKeys;
2553+
2554+ dynStrKeys.push_back(FORMAT_ARTIST);
2555+ dynStrKeys.push_back(FORMAT_TRACKTITLE);
2556+ dynStrKeys.push_back(FORMAT_ALBUMTITLE);
2557+ dynStrKeys.push_back(FORMAT_GENRE);
2558+
2559+ // set current track informations
2560+ DummyAmp::getInstance()->getMutableTrackInfo().removeStrings(dynStrKeys);
2561+ DummyAmp::getInstance()->getMutableTrackInfo().setDynamicStrings(dynStrKeys);
2562+
2563+ // refresh dummyamp title
2564+ DummyAmp::getInstance()->refreshTitle();
2565+
2566+ // when explicitly tagged file only mode and artist or track name not found,
2567+ // then skip sending track informations
2568+ string8 title_utf8 = DummyAmp::getInstance()->getTrackInfo().getString(FORMAT_TRACKTITLE, true).c_str();
2569+ string8 artist_utf8 = DummyAmp::getInstance()->getTrackInfo().getString(FORMAT_ARTIST, true).c_str();
2570+ string8 album_utf8 = DummyAmp::getInstance()->getTrackInfo().getString(FORMAT_ALBUMTITLE).c_str();
2571+ string8 genre_utf8 = DummyAmp::getInstance()->getTrackInfo().getString(FORMAT_GENRE).c_str();
2572+
2573+ if( (cfg_explicitly_tagged_file_only == 1) && (!lstrcmpA(title_utf8, "?") || !lstrcmpA(artist_utf8, "?")) )
2574+ {
2575+ DEBUG_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_INTERNAL_REFRESHDYNINFO / SKIP this track. (artist or title not found)"));
2576+ }
2577+ else
2578+ {
2579+ if(!lstrcmpA(title_utf8, "?"))
2580+ {
2581+ DummyAmp::getInstance()->getMutableTrackInfo().removeString(FORMAT_TRACKTITLE);
2582+ DummyAmp::getInstance()->getMutableTrackInfo().putString(FORMAT_TRACKTITLE, (LPCSTR)cfg_no_title_name);
2583+ }
2584+
2585+ if(!lstrcmpA(artist_utf8, "?"))
2586+ {
2587+ DummyAmp::getInstance()->getMutableTrackInfo().removeString(FORMAT_ARTIST);
2588+ DummyAmp::getInstance()->getMutableTrackInfo().putString(FORMAT_ARTIST, (LPCSTR)cfg_no_artist_name);
2589+ }
2590+
2591+ if(!lstrcmpA(album_utf8, "?"))
2592+ {
2593+ DummyAmp::getInstance()->getMutableTrackInfo().removeString(FORMAT_ALBUMTITLE);
2594+ DummyAmp::getInstance()->getMutableTrackInfo().putString(FORMAT_ALBUMTITLE,(LPCSTR) cfg_no_album_name);
2595+ }
2596+
2597+ if(!lstrcmpA(genre_utf8, "?"))
2598+ {
2599+ DummyAmp::getInstance()->getMutableTrackInfo().removeString(FORMAT_GENRE);
2600+ DummyAmp::getInstance()->getMutableTrackInfo().putString(FORMAT_GENRE, (LPCSTR)cfg_no_genre_name);
2601+ }
2602+
2603+ // refresh dummyamp info
2604+ DummyAmp::getInstance()->refreshAmpInfo();
2605+ }
2606+
2607+ return std::make_pair(true, 0);
2608+ }
2609+
2610+ default:
2611+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - WM_WA_IPC (Unknown IPC command) / W:%08x, L:%08x"), wp, lp);
2612+ break;
2613+ }
2614+
2615+ }
2616+ break;
2617+ }
2618+
2619+ return std::make_pair(false, 0);
2620+}
2621+
2622+std::pair<bool, LRESULT> WINAPI DummyAmp::outerWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp)
2623+{
2624+ switch(msg)
2625+ {
2626+ case WM_WA_IPC:
2627+ {
2628+ PlayInfo::EPlayStatus rawPlayStatus = DummyAmp::getInstance()->getRawPlayInfo().getPlayStatus();
2629+ int rawPlayPosition = DummyAmp::getInstance()->getRawPlayInfo().getPlayPosition();
2630+ int rawPlayLength = DummyAmp::getInstance()->getRawPlayInfo().getPlayLength();
2631+ int rawPlayCount = DummyAmp::getInstance()->getPlayInfo().getPlayCount();
2632+ const string8 &rawPlayInfoMp3Path8 = DummyAmp::getInstance()->getRawPlayInfo().getPlayInfoMp3Path8();
2633+ const tstring &playlistTitle = DummyAmp::getInstance()->getPlaylistTitle();
2634+ const string8 &playlistTitle8 = DummyAmp::getInstance()->getPlaylistTitle8();
2635+
2636+ switch(lp)
2637+ {
2638+ case IPC_ISPLAYING:
2639+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_ISPLAYING / status [%d]"), rawPlayStatus);
2640+ return std::make_pair(true, rawPlayStatus);
2641+
2642+ case IPC_GETOUTPUTTIME:
2643+
2644+ if(rawPlayStatus != PlayInfo::PLAY_START)
2645+ {
2646+ rawPlayPosition = -1;
2647+ rawPlayLength = -1;
2648+ }
2649+ else if(true)
2650+ {
2651+#if IS_FB2K_VER08
2652+ rawPlayPosition = static_cast<int>(play_control::get()->get_playback_time() * 1000.0);
2653+#else IS_FB2K_VER09
2654+ rawPlayPosition = static_cast<int>(static_api_ptr_t<playback_control>()->playback_get_position() * 1000.0);
2655+#endif
2656+ }
2657+
2658+ if(wp == IPC_GETOUTPUTTIME_PositionMSec)
2659+ {
2660+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_GETOUTPUTTIME / position [%.3f sec.]"), rawPlayPosition / 1000.0);
2661+ return std::make_pair(true, rawPlayPosition);
2662+ }
2663+ else if(wp == IPC_GETOUTPUTTIME_TotalSec)
2664+ {
2665+ TRACE_DUMMYAMP_PROC(_T("DummyAm::outerWinampWindowProcp - IPC_GETOUTPUTTIME / length [%d sec.]"), rawPlayLength);
2666+ return std::make_pair(true, rawPlayLength);
2667+ }
2668+
2669+ return std::make_pair(true, -1);
2670+
2671+ case IPC_GETLISTPOS:
2672+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_GETLISTPOS / index [%d]"), rawPlayCount);
2673+ return std::make_pair(true, rawPlayCount);
2674+
2675+ case IPC_GETPLAYLISTFILE:
2676+ TRACE_DUMMYAMP_PROC8(
2677+ "DummyAmp::outerWinampWindowProc - IPC_GETPLAYLISTFILE / path [%s]", (LPCSTR)rawPlayInfoMp3Path8);
2678+ return std::make_pair(true, (LRESULT)(LPCSTR)rawPlayInfoMp3Path8);
2679+
2680+ case IPC_GETPLAYLISTTITLE:
2681+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_GETPLAYLISTTITLE")
2682+ _T(" / title [%s]"), (LPCTSTR)playlistTitle.c_str());
2683+ return std::make_pair(true, (LRESULT)(LPCSTR)playlistTitle8);
2684+
2685+ case IPC_JUMPTOTIME:
2686+ if(rawPlayStatus == PlayInfo::PLAY_START)
2687+ {
2688+ double jumpPos = wp / 1000.0;
2689+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_JUMPTOTIME")
2690+ _T(" / jump to [%.3f sec.]"), jumpPos);
2691+
2692+ if(jumpPos > rawPlayLength)
2693+ {
2694+ // eof
2695+ return std::make_pair(true, 1);
2696+ }
2697+ else
2698+ {
2699+#if IS_FB2K_VER08
2700+ play_control::get()->playback_seek(jumpPos);
2701+#else IS_FB2K_VER09
2702+ static_api_ptr_t<playback_control>()->playback_seek(jumpPos);
2703+#endif
2704+ return std::make_pair(true, 0);
2705+ }
2706+
2707+ }
2708+ return std::make_pair(true, -1);
2709+
2710+ default:
2711+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - WM_WA_IPC (Unknown IPC command) / W:%08x, L:%08x"), wp, lp);
2712+ break;
2713+ }
2714+ }
2715+ break;
2716+ }
2717+
2718+ return std::make_pair(false, 0);
2719+}
2720+
2721+#if defined(ENABLE_MSN)
2722+class MSNSender
2723+{
2724+ public:
2725+
2726+ static void SendTrackInfo(const TRACK_INFO_UTF8 &info)
2727+ {
2728+ string8 msg;
2729+ msg += "\\0Music\\01\\0{0} - {1} - {2} - {3}\\0";
2730+ msg += info.m_title;
2731+ msg += "\\0";
2732+ msg += info.m_artist;
2733+ msg += "\\0";
2734+ msg += info.m_album;
2735+ msg += "\\0";
2736+ msg += info.m_genre;
2737+ msg += "\\0";
2738+
2739+ console::info(msg);
2740+
2741+ string_wide_from_utf8 tmp(msg);
2742+ SendMessage(tmp);
2743+ }
2744+
2745+ static void SendMessage(LPCWSTR buf)
2746+ {
2747+ COPYDATASTRUCT copydata;
2748+ int nSendBufLen = (::lstrlenW(buf)*2)+2;
2749+
2750+ copydata.dwData = 0x0547;
2751+ copydata.lpData = (void*)buf;
2752+ copydata.cbData = nSendBufLen;
2753+
2754+ HWND hMsnUi = NULL;
2755+ hMsnUi = FindWindowEx(NULL, hMsnUi, _T("MsnMsgrUIManager"), _T("MSN Messenger式再生通知を受信する窓"));
2756+ if ( hMsnUi == NULL )
2757+ {
2758+ ERROR(_T("MSNSender::SendMessage - M2M not found."));
2759+ return ;
2760+ }
2761+
2762+ ::SendMessage(hMsnUi, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&copydata);
2763+ LOG_INFO(_T("MSNSender::SendMessage - send track informations to M2M."));
2764+ }
2765+};
2766+#endif
2767+
2768+#if IS_FB2K_VER08
2769+class play_callback_mixi : public play_callback
2770+#elif IS_FB2K_VER09
2771+class play_callback_mixi : public play_callback_static
2772+#endif
2773+{
2774+#if IS_FB2K_VER09
2775+ virtual unsigned get_flags() {
2776+ return flag_on_playback_all;
2777+ }
2778+#endif
2779+
2780+#if IS_FB2K_VER08
2781+ virtual void on_playback_starting()
2782+#elif IS_FB2K_VER09
2783+ virtual void on_playback_starting(play_control::t_track_command command, bool paused)
2784+#endif
2785+ {
2786+ TRACE_CALLBACK(_T("play_callback_mixi::on_playback_starting - called."));
2787+
2788+ // create my dummyamp window
2789+ DummyAmp::getInstance()->createWindow();
2790+ }
2791+
2792+#if IS_FB2K_VER08
2793+ virtual void on_playback_new_track(metadb_handle * track)
2794+#elif IS_FB2K_VER09
2795+ virtual void on_playback_new_track(metadb_handle_ptr track)
2796+#endif
2797+ {
2798+ TRACE_CALLBACK(_T("play_callback_mixi::on_playback_new_track - called."));
2799+
2800+ if(DummyAmp::getInstance()->isReady() == false)
2801+ {
2802+ LOG_ERROR(_T("play_callback_mixi::on_playback_new_track - mixi station への送信機能はエラーにより無効化されています"));
2803+ LOG_ERROR(_T("play_callback_mixi::on_playback_new_track - エラーの原因を取り除いた上で、foobar2000 を再起動してください"));
2804+ return;
2805+ }
2806+
2807+#if IS_FB2K_VER08
2808+ bool isTrackInLibrary = track->handle_is_permcached() == 1;
2809+#elif IS_FB2K_VER09
2810+ bool isTrackInLibrary = static_api_ptr_t<library_manager>()->is_item_in_library(track);
2811+#endif
2812+ if(cfg_media_library_registered_file_only == 1)
2813+ {
2814+ if(isTrackInLibrary)
2815+ {
2816+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_new_track - new track found on media library."));
2817+ }
2818+ else
2819+ {
2820+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_new_track - new track NOT IN media library."));
2821+ }
2822+ }
2823+
2824+ // get currently playbacked track informations
2825+ string8 winamp_title_utf8;
2826+ string8 playlist_title_utf8;
2827+
2828+ // make currently playbacked track information keys
2829+ Strings strKeys;
2830+
2831+ strKeys.push_back(FORMAT_FILEPATH);
2832+ strKeys.push_back(FORMAT_FILEPATHRAW);
2833+ strKeys.push_back(FORMAT_ARTIST);
2834+ strKeys.push_back(FORMAT_TRACKTITLE);
2835+ strKeys.push_back(FORMAT_ALBUMTITLE);
2836+ strKeys.push_back(FORMAT_GENRE);
2837+ strKeys.push_back(FORMAT_CODEC);
2838+
2839+ // set current track informations
2840+ TrackInfo &trackInfo(DummyAmp::getInstance()->getMutableTrackInfo());
2841+ trackInfo.clear();
2842+ trackInfo.setStrings(strKeys, track);
2843+
2844+ // set trackinfo to dummyAmp
2845+ //DummyAmp::getInstance()->setTrackInfo(trackInfo);
2846+
2847+ // set dynamic flag
2848+ setDynamic(trackInfo.getString(FORMAT_FILEPATHRAW));
2849+
2850+ if(isDynamic())
2851+ {
2852+ setFirstDynamicCallback(true);
2853+
2854+ // set song total length
2855+ m_song_total_sec = pfc_string_to_float(cfg_send_interval3) / pfc_string_to_float(cfg_send_interval2) * 100.0;
2856+ }
2857+ else
2858+ {
2859+#if defined(CONTROL_SEND_TIMING)
2860+ // reset send timing
2861+ resetSendTiming();
2862+#endif
2863+
2864+#if IS_FB2K_VER08
2865+ // get song total length
2866+ m_song_total_sec = track->handle_get_length();
2867+
2868+ // get formatted dummyamp title
2869+ track->handle_format_title(winamp_title_utf8, cfg_dummyamp_title_format, 0);
2870+
2871+ // get formatted playlist title
2872+ track->handle_format_title(playlist_title_utf8, cfg_dummyamp_playlist_format, 0);
2873+
2874+#elif IS_FB2K_VER09
2875+ // get song total length
2876+ m_song_total_sec = track->get_length();
2877+
2878+ service_ptr_t<titleformat_object> titleformat;
2879+
2880+ // get formatted dummyamp title
2881+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, cfg_dummyamp_title_format);
2882+ track->format_title(NULL, winamp_title_utf8, titleformat, 0);
2883+
2884+ // get formatted playlist title
2885+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, cfg_dummyamp_playlist_format);
2886+ track->format_title(NULL, playlist_title_utf8, titleformat, 0);
2887+
2888+#endif
2889+ string_os_from_utf8 winamp_title(winamp_title_utf8);
2890+ string_os_from_utf8 playlist_title(playlist_title_utf8);
2891+
2892+ // set base winamp title to dummyamp
2893+ DummyAmp::getInstance()->setBaseWinampTitle(winamp_title);
2894+
2895+ // set winamp playlist current item title to dummyamp
2896+ DummyAmp::getInstance()->setPlaylistTitle(playlist_title);
2897+
2898+ // clear raw playinfo on dummyamp (no resent mode)
2899+ DummyAmp::getInstance()->getRawPlayInfo().clearPlayInfo(false);
2900+
2901+ // set playinfo raw mp3 file path to dummyAmp
2902+ DummyAmp::getInstance()->getRawPlayInfo().setPlayInfoMp3Path(trackInfo.getString(FORMAT_FILEPATH).c_str());
2903+
2904+ // set dummyamp raw status PLAY_START
2905+ DummyAmp::getInstance()->getRawPlayInfo().setPlayStatusStart();
2906+
2907+ // set raw song total length
2908+ DummyAmp::getInstance()->getRawPlayInfo().setPlayLength(static_cast<int>(m_song_total_sec));
2909+
2910+ // increment play counter
2911+ DummyAmp::getInstance()->getRawPlayInfo().incrementPlayCount();
2912+
2913+ // clear playinfo on dummyamp
2914+ DummyAmp::getInstance()->getPlayInfo().clearPlayInfo();
2915+
2916+ // set song total length
2917+ DummyAmp::getInstance()->getPlayInfo().setPlayLength(static_cast<int>(m_song_total_sec));
2918+
2919+ // increment play counter on dummyamp
2920+ DummyAmp::getInstance()->getPlayI

Ein Teil der Diff wurde aufgrund der Größenbeschränkung abgeschnitten. Verwenden Sie Ihren lokalen Client, um die vollständige Diff.

Show on old repository browser