• R/O
  • SSH
  • HTTPS

foo-mixi: Commit


Commit MetaInfo

Révision66 (tree)
l'heure2009-02-13 03:13:45
Auteuryoshy

Message de Log

yoshy - 0.2.0.1mod - リリースタグ作成

Change Summary

Modification

--- src/foo_mixi_feat_winamp/tags/0.2.0.1mod_R20090213/foo_mixi_feat_winamp_for_fb2k_0_9_4_SDK72/foo_mixi_feat_winamp.cpp (nonexistent)
+++ src/foo_mixi_feat_winamp/tags/0.2.0.1mod_R20090213/foo_mixi_feat_winamp_for_fb2k_0_9_4_SDK72/foo_mixi_feat_winamp.cpp (revision 66)
@@ -0,0 +1,4321 @@
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.0.1mod"
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 REQUIRED_MINIMUM_TIME 3
124+#define SEND_TIME_RATE_LOWERBOUND 33
125+#define REQUIRED_MAXIMUM_TIME 20
126+
127+//#define CONTROL_SEND_TIMING
128+
129+//#define ENABLE_MSN
130+
131+#if IS_FB2K_VER09
132+using namespace pfc;
133+using namespace pfc::stringcvt;
134+#define pfc_string_to_float string_to_float
135+#endif
136+
137+/*
138+ foo_mixi_feat_winamp: project dependencies
139+
140+ foo_mixi_feat_winamp
141+ foobar2000_SDK
142+ utf8api(0.8.3)
143+ pfc
144+ foobar2000_sdk_helpers
145+ pfc
146+ foobar2000_component_client(0.9.X)
147+ id3lib
148+ zlib
149+
150+ library dependencies: wxbase28.lib, id3lib.lib, ../shared/shared.lib(0.9.X)
151+ runtime library: Multi-Thread (DLL) or (Debug,DLL)
152+ !! ensure all projects that depended from this project are correctly set to MT DLL !!
153+ ignore: LIBCMT [Win32 Release] (or LIBCMTD [Win32 Debug])
154+*/
155+
156+// if wxWidgets are updated, change lib names below and linker libpath option.
157+
158+#if 0
159+#if defined(_DEBUG)
160+#if defined(BUILD_UNICODE)
161+#pragma comment(lib, "wxbase28ud.lib")
162+#else
163+#pragma comment(lib, "wxbase28d.lib")
164+#endif
165+#else
166+#if defined(BUILD_UNICODE)
167+#pragma comment(lib, "wxbase28u.lib")
168+#else
169+#pragma comment(lib, "wxbase28.lib")
170+#endif
171+#endif
172+#endif
173+
174+// now id3lib automatically added to linker target,
175+// because it generated from depended project.
176+//#pragma comment(lib, "id3lib.lib")
177+
178+#if IS_FB2K_VER09
179+#pragma comment(lib, "../shared/shared.lib")
180+#endif
181+
182+typedef std::basic_string<TCHAR> tstring;
183+
184+typedef TCHAR Str64K[65536];
185+typedef char StrDBCS64K[65536];
186+
187+tstring GetErrorMessage(DWORD errCode);
188+void putLogError(LPCTSTR pMethod, LPCTSTR pErrMsg, DWORD dwErrCode);
189+void setDlgVersionInfo(HWND wnd, UINT idc_version, UINT idc_build);
190+void DebugPrint(int severity, LPCTSTR lpszFormat, ...);
191+void DebugPrintDBCS(int severity, LPCSTR lpszFormat, ...);
192+void DebugPrint8(int severity, LPCSTR lpszFormat, ...);
193+
194+#define LOGLEVEL_NONE 0
195+#define LOGLEVEL_WARNING 1
196+#define LOGLEVEL_ERROR 2
197+
198+#if IS_FB2K_VER09
199+namespace console
200+{
201+ enum {
202+ SEVERITY_INFO = 0,
203+ SEVERITY_WARNING = 1,
204+ SEVERITY_CRITICAL = 2
205+ };
206+};
207+#endif
208+
209+#define LOG_TRACE(f, ...) if(cfg_enable_debug_log) DebugPrint(console::SEVERITY_INFO, f, __VA_ARGS__)
210+#define LOG_DEBUG(f, ...) if(cfg_enable_debug_log) DebugPrint(console::SEVERITY_INFO, f, __VA_ARGS__)
211+
212+#define LOG_TRACE8(f, ...) if(cfg_enable_debug_log) DebugPrint8(console::SEVERITY_INFO, f, __VA_ARGS__)
213+#define LOG_DEBUG8(f, ...) if(cfg_enable_debug_log) DebugPrint8(console::SEVERITY_INFO, f, __VA_ARGS__)
214+
215+#define LOG_TRACE_ANSI(f, ...) if(cfg_enable_debug_log) DebugPrintDBCS(console::SEVERITY_INFO, f, __VA_ARGS__)
216+#define LOG_DEBUG_ANSI(f, ...) if(cfg_enable_debug_log) DebugPrintDBCS(console::SEVERITY_INFO, f, __VA_ARGS__)
217+
218+#define LOG_INFO(f, ...) DebugPrint(console::SEVERITY_INFO, f, __VA_ARGS__)
219+#define LOG_WARN(f, ...) DebugPrint(console::SEVERITY_WARNING, f, __VA_ARGS__)
220+#define LOG_ERROR(f, ...) DebugPrint(console::SEVERITY_CRITICAL, f, __VA_ARGS__)
221+
222+#if defined(BUILD_UNICODE)
223+#define TRACE_DBCS(f, ...) if(cfg_enable_debug_log) DebugPrintDBCS(console::SEVERITY_INFO, f, __VA_ARGS__)
224+#else
225+#define TRACE_DBCS(f, ...) if(cfg_enable_debug_log) DebugPrint(console::SEVERITY_INFO, f, __VA_ARGS__)
226+#endif
227+
228+#define DEBUG_DUMMYAMP_INIT(f, ...) if(cfg_debug_dummyamp_init >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
229+#define TRACE_DUMMYAMP_INIT(f, ...) if(cfg_debug_dummyamp_init >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
230+
231+#define DEBUG_DUMMYAMP_PROC(f, ...) if(cfg_debug_dummyamp_proc >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
232+#define DEBUG_DUMMYAMP_PROC8(f, ...) if(cfg_debug_dummyamp_proc >= LOGLEVEL_WARNING) LOG_DEBUG8(f, __VA_ARGS__)
233+#define TRACE_DUMMYAMP_PROC(f, ...) if(cfg_debug_dummyamp_proc >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
234+#define TRACE_DUMMYAMP_PROC8(f, ...) if(cfg_debug_dummyamp_proc >= LOGLEVEL_ERROR) LOG_TRACE8(f, __VA_ARGS__)
235+
236+#define DEBUG_TRACK_INFO(f, ...) if(cfg_debug_track_info >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
237+#define DEBUG_TRACK_INFO8(f, ...) if(cfg_debug_track_info >= LOGLEVEL_WARNING) LOG_DEBUG8(f, __VA_ARGS__)
238+#define DEBUG_TRACK_INFO_ANSI(f, ...) if(cfg_debug_track_info >= LOGLEVEL_WARNING) LOG_DEBUG_ANSI(f, __VA_ARGS__)
239+#define TRACE_TRACK_INFO(f, ...) if(cfg_debug_track_info >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
240+#define TRACE_TRACK_INFO8(f, ...) if(cfg_debug_track_info >= LOGLEVEL_ERROR) LOG_TRACE8(f, __VA_ARGS__)
241+#define TRACE_TRACK_INFO_ANSI(f, ...) if(cfg_debug_track_info >= LOGLEVEL_ERROR) LOG_TRACE_ANSI(f, __VA_ARGS__)
242+
243+#define DEBUG_PLUGIN(f, ...) if(cfg_debug_plugin >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
244+#define TRACE_PLUGIN(f, ...) if(cfg_debug_plugin >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
245+
246+#define DEBUG_CALLBACK(f, ...) if(cfg_debug_callback >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
247+#define TRACE_CALLBACK(f, ...) if(cfg_debug_callback >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
248+
249+static string_utf8_from_os g_pluginCaption8(_T(PLUGIN_CAPTION_JP));
250+static string_utf8_from_os g_pluginVersion8(_T(PLUGIN_VERSION));
251+static string_utf8_from_os g_pluginAbout8(
252+ _T(PLUGIN_CAPTION_JP) _T(" ") _T(PLUGIN_VERSION) _T("\nCopyright (C) 2006-2009 Yossiepon Oniichan, All Rights Reserved."));
253+
254+DECLARE_COMPONENT_VERSION(g_pluginCaption8, g_pluginVersion8, g_pluginAbout8);
255+
256+static string_utf8_from_os g_advancedSettingsCaption8(_T(ADVANCED_SETTINGS_CAPTION));
257+static string_utf8_from_os g_debugSettingsCaption8(_T(DEBUG_SETTINGS_CAPTION));
258+
259+static string_utf8_from_os g_menu_item(_T("Components/Mixi/mixiミュージック連携を有効にする"));
260+
261+static string_utf8_from_os g_menu_item_title(_T("mixiミュージック連携を有効にする"));
262+static string_utf8_from_os g_menu_item_description(_T("mixiミュージックへの曲情報の送信について、有効/無効を切り替えます"));
263+
264+#if IS_FB2K_VER08
265+static cfg_int cfg_use_plugin("usePlugin", 1);
266+
267+static cfg_string cfg_no_artist_name("NoArtistName", "No Artist");
268+static cfg_string cfg_no_title_name("NoTitleName", "No Title");
269+static cfg_string cfg_no_album_name("NoAlbumName", "No Title");
270+static cfg_string cfg_no_genre_name("NoGenreName", "Other");
271+
272+static cfg_string cfg_send_interval1("SendInterval1", "20");
273+static cfg_string cfg_send_interval2("SendInterval2", "66");
274+static cfg_string cfg_send_interval3("SendInterval3", "300");
275+
276+static cfg_int cfg_disable_duplicate_song("DisableDuplicateSong", 0);
277+static cfg_int cfg_media_library_registered_file_only("MediaLibraryRegisteredFileOnly", 0);
278+static cfg_int cfg_explicitly_tagged_file_only("ExplicitlyTaggedFileOnly", 0);
279+static cfg_int cfg_enable_streaming_file("EnableStreamingFile", 0);
280+
281+static cfg_int cfg_disable_dummy_mp3("DisableDummyMp3", 0);
282+static cfg_int cfg_dummy_mp3_location("DummyMp3Location", 0);
283+
284+static cfg_int cfg_show_dummyamp("ShowDummyAmp", 0);
285+static cfg_string cfg_dummyamp_title_format("DummyAmpTitleFormat", DEFAULT_DUMMYAMP_TITLE_FORMAT);
286+static cfg_string cfg_dummyamp_playlist_format("DummyAmpPlaylistFormat", DEFAULT_DUMMYAMP_TITLE_FORMAT);
287+static cfg_int cfg_disable_ansi_trans("DisableAnsiTrans", 0);
288+static cfg_int cfg_enable_ext_ipc_proc("EnableExtIpcProc", 1);
289+
290+static cfg_int cfg_enable_debug_log("EnableDebugLog", 1);
291+static cfg_int cfg_debug_dummyamp_init("DebugDummyAmpInit", 1);
292+static cfg_int cfg_debug_dummyamp_proc("DebugDummyAmpProc", 1);
293+static cfg_int cfg_debug_track_info("DebugTrackInfo", 1);
294+static cfg_int cfg_debug_plugin("DebugPlugin", 1);
295+static cfg_int cfg_debug_callback("DebugCallback", 1);
296+#elif IS_FB2K_VER09
297+// {DB051102-6DAE-4ff8-B5ED-AA06C2ACFEDE}
298+static const GUID cfg_use_plugin_guid = { 0xdb051102, 0x6dae, 0x4ff8, { 0xb5, 0xed, 0xaa, 0x6, 0xc2, 0xac, 0xfe, 0xde } };
299+static cfg_int cfg_use_plugin(cfg_use_plugin_guid, 1);
300+
301+// {1B27EDEC-A28A-4dac-96D4-1E3B51C92004}
302+static const GUID cfg_no_artist_name_guid = { 0x1b27edec, 0xa28a, 0x4dac, { 0x96, 0xd4, 0x1e, 0x3b, 0x51, 0xc9, 0x20, 0x4 } };
303+static cfg_string cfg_no_artist_name(cfg_no_artist_name_guid, "No Artist");
304+// {A8CFD50C-05EA-447d-AA74-F4C6975E750E}
305+static const GUID cfg_no_title_name_guid = { 0xa8cfd50c, 0x5ea, 0x447d, { 0xaa, 0x74, 0xf4, 0xc6, 0x97, 0x5e, 0x75, 0xe } };
306+static cfg_string cfg_no_title_name(cfg_no_title_name_guid, "No Title");
307+// {A7593537-8B09-4016-9B3C-0EF5516BBFF9}
308+static const GUID cfg_no_album_name_guid = { 0xa7593537, 0x8b09, 0x4016, { 0x9b, 0x3c, 0xe, 0xf5, 0x51, 0x6b, 0xbf, 0xf9 } };
309+static cfg_string cfg_no_album_name(cfg_no_album_name_guid, "No Title");
310+// {15774319-0CBE-45fd-B0E8-52D4728319A3}
311+static const GUID cfg_no_genre_name_guid = { 0x15774319, 0xcbe, 0x45fd, { 0xb0, 0xe8, 0x52, 0xd4, 0x72, 0x83, 0x19, 0xa3 } };
312+static cfg_string cfg_no_genre_name(cfg_no_genre_name_guid, "Other");
313+
314+// {ED0C715A-D06D-4641-A29A-AE4485A0B9EF}
315+static const GUID cfg_send_interval1_guid = { 0xed0c715a, 0xd06d, 0x4641, { 0xa2, 0x9a, 0xae, 0x44, 0x85, 0xa0, 0xb9, 0xef } };
316+static cfg_string cfg_send_interval1(cfg_send_interval1_guid, "20");
317+// {25989711-B458-4624-8A85-7304FCE799A3}
318+static const GUID cfg_send_interval2_guid = { 0x25989711, 0xb458, 0x4624, { 0x8a, 0x85, 0x73, 0x4, 0xfc, 0xe7, 0x99, 0xa3 } };
319+static cfg_string cfg_send_interval2(cfg_send_interval2_guid, "66");
320+// {4287A873-015D-44b5-A31E-34DEE1BF0525}
321+static const GUID cfg_send_interval3_guid = { 0x4287a873, 0x15d, 0x44b5, { 0xa3, 0x1e, 0x34, 0xde, 0xe1, 0xbf, 0x5, 0x25 } };
322+static cfg_string cfg_send_interval3(cfg_send_interval3_guid, "300");
323+
324+// {5C318451-2B6A-405f-814B-2795A764C1DE}
325+static const GUID cfg_disable_duplicate_song_guid = { 0x5c318451, 0x2b6a, 0x405f, { 0x81, 0x4b, 0x27, 0x95, 0xa7, 0x64, 0xc1, 0xde } };
326+static cfg_int cfg_disable_duplicate_song(cfg_disable_duplicate_song_guid, 0);
327+// {56688AED-A76D-4759-A835-A380D39D34D1}
328+static const GUID cfg_media_library_registered_file_only_guid = { 0x56688aed, 0xa76d, 0x4759, { 0xa8, 0x35, 0xa3, 0x80, 0xd3, 0x9d, 0x34, 0xd1 } };
329+static cfg_int cfg_media_library_registered_file_only(cfg_media_library_registered_file_only_guid, 0);
330+// {91E0D3D4-85DD-4c45-ADB5-7FAC6F3360CD}
331+static const GUID cfg_explicitly_tagged_file_only_guid = { 0x91e0d3d4, 0x85dd, 0x4c45, { 0xad, 0xb5, 0x7f, 0xac, 0x6f, 0x33, 0x60, 0xcd } };
332+static cfg_int cfg_explicitly_tagged_file_only(cfg_explicitly_tagged_file_only_guid, 0);
333+// {F4E85669-6EEF-4b75-AFC1-7964AEBE10B0}
334+static const GUID cfg_enable_streaming_file_guid = { 0xf4e85669, 0x6eef, 0x4b75, { 0xaf, 0xc1, 0x79, 0x64, 0xae, 0xbe, 0x10, 0xb0 } };
335+static cfg_int cfg_enable_streaming_file(cfg_enable_streaming_file_guid, 0);
336+
337+// {67341E11-A385-45d8-9DE6-B1FABA35AC62}
338+static const GUID cfg_disable_dummy_mp3_guid = { 0x67341e11, 0xa385, 0x45d8, { 0x9d, 0xe6, 0xb1, 0xfa, 0xba, 0x35, 0xac, 0x62 } };
339+static cfg_int cfg_disable_dummy_mp3(cfg_disable_dummy_mp3_guid, 0);
340+// {87D4D72C-43AB-42ab-8CAC-D689961DA5EA}
341+static const GUID cfg_dummy_mp3_location_guid = { 0x87d4d72c, 0x43ab, 0x42ab, { 0x8c, 0xac, 0xd6, 0x89, 0x96, 0x1d, 0xa5, 0xea } };
342+static cfg_int cfg_dummy_mp3_location(cfg_dummy_mp3_location_guid, 0);
343+
344+// {F9DB10F0-1A01-40dd-A342-486A6CB596E7}
345+static const GUID cfg_show_dummyamp_guid = { 0xf9db10f0, 0x1a01, 0x40dd, { 0xa3, 0x42, 0x48, 0x6a, 0x6c, 0xb5, 0x96, 0xe7 } };
346+static cfg_int cfg_show_dummyamp(cfg_show_dummyamp_guid, 0);
347+// {CC7785CA-B019-4107-9115-161A543B3952}
348+static const GUID cfg_dummyamp_title_format_guid = { 0xcc7785ca, 0xb019, 0x4107, { 0x91, 0x15, 0x16, 0x1a, 0x54, 0x3b, 0x39, 0x52 } };
349+static cfg_string cfg_dummyamp_title_format(cfg_dummyamp_title_format_guid, DEFAULT_DUMMYAMP_TITLE_FORMAT);
350+// {B964EB32-4957-4e7a-81B5-E89B4405AAAD}
351+static const GUID cfg_dummyamp_playlist_format_guid = { 0xb964eb32, 0x4957, 0x4e7a, { 0x81, 0xb5, 0xe8, 0x9b, 0x44, 0x5, 0xaa, 0xad } };
352+static cfg_string cfg_dummyamp_playlist_format(cfg_dummyamp_title_format_guid, DEFAULT_DUMMYAMP_TITLE_FORMAT);
353+
354+// {094571BA-1484-455c-9D6E-E18B13296149}
355+static const GUID cfg_disable_ansi_trans_guid = { 0x94571ba, 0x1484, 0x455c, { 0x9d, 0x6e, 0xe1, 0x8b, 0x13, 0x29, 0x61, 0x49 } };
356+static cfg_int cfg_disable_ansi_trans(cfg_disable_ansi_trans_guid, 0);
357+// {8961A829-F010-461c-9CC8-C06308BFA4A2}
358+static const GUID cfg_enable_ext_ipc_proc_guid = { 0x8961a829, 0xf010, 0x461c, { 0x9c, 0xc8, 0xc0, 0x63, 0x8, 0xbf, 0xa4, 0xa2 } };
359+static cfg_int cfg_enable_ext_ipc_proc(cfg_enable_ext_ipc_proc_guid, 1);
360+
361+// {3B6B73F9-F6AF-4b6c-8015-E73A1B87AD5C}
362+static const GUID cfg_enable_debug_log_guid = { 0x3b6b73f9, 0xf6af, 0x4b6c, { 0x80, 0x15, 0xe7, 0x3a, 0x1b, 0x87, 0xad, 0x5c } };
363+static cfg_int cfg_enable_debug_log(cfg_enable_debug_log_guid, 1); // debug log enabled
364+// {0BF3522F-BC55-4f77-AA95-B02F6E159544}
365+static const GUID cfg_debug_dummyamp_init_guid = { 0xbf3522f, 0xbc55, 0x4f77, { 0xaa, 0x95, 0xb0, 0x2f, 0x6e, 0x15, 0x95, 0x44 } };
366+static cfg_int cfg_debug_dummyamp_init(cfg_debug_dummyamp_init_guid, 1); // debug level
367+// {D1256573-7560-41db-A781-9985AE50CE07}
368+static const GUID cfg_debug_dummyamp_proc_guid = { 0xd1256573, 0x7560, 0x41db, { 0xa7, 0x81, 0x99, 0x85, 0xae, 0x50, 0xce, 0x7 } };
369+static cfg_int cfg_debug_dummyamp_proc(cfg_debug_dummyamp_proc_guid, 1); // debug level
370+// {0A7E2CAE-905F-4ecb-A82D-8DD853FBFFF3}
371+static const GUID cfg_debug_track_info_guid = { 0xa7e2cae, 0x905f, 0x4ecb, { 0xa8, 0x2d, 0x8d, 0xd8, 0x53, 0xfb, 0xff, 0xf3 } };
372+static cfg_int cfg_debug_track_info(cfg_debug_track_info_guid, 1); // debug level
373+// {67A78DB7-3591-4416-84FC-96436082B619}
374+static const GUID cfg_debug_plugin_guid = { 0x67a78db7, 0x3591, 0x4416, { 0x84, 0xfc, 0x96, 0x43, 0x60, 0x82, 0xb6, 0x19 } };
375+static cfg_int cfg_debug_plugin(cfg_debug_plugin_guid, 1); // debug level
376+// {DBED8400-527F-4b98-9227-2C0BA95B3206}
377+static const GUID cfg_debug_callback_guid = { 0xdbed8400, 0x527f, 0x4b98, { 0x92, 0x27, 0x2c, 0xb, 0xa9, 0x5b, 0x32, 0x6 } };
378+static cfg_int cfg_debug_callback(cfg_debug_callback_guid, 1); // debug level
379+#endif
380+
381+class TrackInfo
382+{
383+public:
384+ std::string m_nullStr;
385+
386+ StringMap m_infoMap8;
387+ StringMap m_infoMapAnsi;
388+
389+ UIntMap m_infoMapNum;
390+
391+ TrackInfo() {
392+ }
393+
394+ TrackInfo(const TrackInfo &other)
395+ : m_infoMap8(other.m_infoMap8)
396+ , m_infoMapAnsi(other.m_infoMapAnsi)
397+ , m_infoMapNum(other.m_infoMapNum) {
398+ }
399+
400+ ~TrackInfo() {
401+ }
402+
403+ TrackInfo &operator =(const TrackInfo &other)
404+ {
405+ TrackInfo temp(other);
406+ swap(temp);
407+
408+ return *this;
409+ }
410+
411+ void show_map(StringMap &map, bool bAnsi = false)
412+ {
413+ StringMapCIt beginIt(map.begin()), endIt(map.end()), it;
414+
415+ for(it = beginIt; it != endIt; it ++) {
416+
417+ if(bAnsi) {
418+ TRACE_TRACK_INFO_ANSI("show_map_ansi: [%s, %s]", it->first.c_str(), it->second.c_str());
419+ } else {
420+ TRACE_TRACK_INFO8("show_map8: [%s, %s]", it->first.c_str(), it->second.c_str());
421+ }
422+ }
423+ }
424+
425+ void swap(TrackInfo &other)
426+ {
427+ m_infoMap8.swap(other.m_infoMap8);
428+ m_infoMapAnsi.swap(other.m_infoMapAnsi);
429+ m_infoMapNum.swap(other.m_infoMapNum);
430+ }
431+
432+ void clear()
433+ {
434+ TRACE_TRACK_INFO(_T("TRACK_INFO::clear - called."));
435+
436+ m_infoMap8.clear();
437+ m_infoMapAnsi.clear();
438+ m_infoMapNum.clear();
439+ }
440+
441+ bool isEmpty() const { return m_infoMap8.empty() & m_infoMapNum.empty(); }
442+
443+public:
444+
445+#if IS_FB2K_VER08
446+ void setStrings(const Strings &keys, metadb_handle * track)
447+#elif IS_FB2K_VER09
448+ void setStrings(const Strings &keys, metadb_handle_ptr track)
449+#endif
450+ {
451+ TRACE_TRACK_INFO(_T("TrackInfo::setStrings - called."));
452+
453+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
454+
455+ for(it = beginIt; it != endIt; it ++) {
456+
457+ string8 info8;
458+
459+#if IS_FB2K_VER08
460+ track->handle_format_title(info8, it->c_str(), 0);
461+#elif IS_FB2K_VER09
462+ service_ptr_t<titleformat_object> titleformat;
463+
464+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
465+ track->format_title(NULL, info8, titleformat, 0);
466+#endif
467+// DEBUG_TRACK_INFO8("TrackInfo::setStrings - %s: %s", it->c_str(), (LPCSTR)info8);
468+
469+ putString(it->c_str(), (LPCSTR)info8);
470+ }
471+ }
472+
473+ void setDynamicStrings(const Strings &keys)
474+ {
475+ TRACE_TRACK_INFO(_T("TrackInfo::setDynamicStrings - called."));
476+
477+#if IS_FB2K_VER08
478+ metadb_handle *track = play_control::get()->get_now_playing();
479+#elif IS_FB2K_VER09
480+ metadb_handle_ptr track;
481+ static_api_ptr_t<playback_control>()->get_now_playing(track);
482+#endif
483+
484+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
485+
486+ for(it = beginIt; it != endIt; it ++) {
487+
488+ string8 info8;
489+
490+#if IS_FB2K_VER08
491+ play_control::get()->playback_format_title_ex(track, info8, it->c_str(), NULL, false, true);
492+#elif IS_FB2K_VER09
493+ service_ptr_t<titleformat_object> titleformat;
494+
495+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
496+ static_api_ptr_t<playback_control>()->playback_format_title_ex(track, NULL, info8, titleformat, NULL, play_control::display_level_titles);
497+#endif
498+// DEBUG_TRACK_INFO8("TrackInfo::setDynamicStrings - %s: %s", it->c_str(), (LPCSTR)info8);
499+
500+ const std::string &oldValue = getString(*it);
501+
502+ if((::lstrcmpA(info8, "?") != 0) || (oldValue.length() == 0))
503+ {
504+ putString(it->c_str(), (LPCSTR)info8);
505+ }
506+ }
507+
508+#if IS_FB2K_VER08
509+ if(track) {
510+ track->handle_release();
511+ }
512+#endif
513+ }
514+
515+ void setPlaylistStrings(const Strings &keys)
516+ {
517+ TRACE_TRACK_INFO(_T("TrackInfo::setPlaylistStrings - called."));
518+
519+#if IS_FB2K_VER08
520+ int track_index;
521+ track_index = playlist_oper::get()->get_now_playing();
522+#elif IS_FB2K_VER09
523+ t_size playlist_index, track_index;
524+ static_api_ptr_t<playlist_manager>()->get_playing_item_location(&playlist_index, &track_index);
525+#endif
526+
527+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
528+
529+ for(it = beginIt; it != endIt; it ++) {
530+
531+ string8 info8;
532+
533+#if IS_FB2K_VER08
534+ playlist_oper::get()->format_title(track_index, info8, it->c_str(), NULL);
535+#elif IS_FB2K_VER09
536+ service_ptr_t<titleformat_object> titleformat;
537+
538+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
539+ static_api_ptr_t<playlist_manager>()->playlist_item_format_title(playlist_index, track_index,
540+ NULL, info8, titleformat, NULL, play_control::display_level_titles);
541+#endif
542+// DEBUG_TRACK_INFO8("TrackInfo::setPlaylistStrings - %s: %s", it->c_str(), (LPCSTR)info8);
543+
544+ putString(it->c_str(), (LPCSTR)info8);
545+ }
546+ }
547+
548+#if IS_FB2K_VER08
549+ void setNumbers(const Strings &keys, metadb_handle * track)
550+#elif IS_FB2K_VER09
551+ void setNumbers(const Strings &keys, metadb_handle_ptr track)
552+#endif
553+ {
554+ TRACE_TRACK_INFO(_T("TrackInfo::setNumbers - called."));
555+
556+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
557+
558+ for(it = beginIt; it != endIt; it ++) {
559+
560+ string8 info8;
561+
562+#if IS_FB2K_VER08
563+ track->handle_format_title(info8, it->c_str(), 0);
564+#elif IS_FB2K_VER09
565+ service_ptr_t<titleformat_object> titleformat;
566+
567+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
568+ track->format_title(NULL, info8, titleformat, 0);
569+#endif
570+// DEBUG_TRACK_INFO8("TrackInfo::setNumbers - %s: %s", it->c_str(), (LPCSTR)info8);
571+
572+ putNumber(it->c_str(), static_cast<UINT>(::atol(info8)) );
573+ }
574+ }
575+
576+ void setDynamicNumbers(const Strings &keys)
577+ {
578+ TRACE_TRACK_INFO(_T("TrackInfo::setDynamicNumbers - called."));
579+
580+#if IS_FB2K_VER08
581+ metadb_handle *track = play_control::get()->get_now_playing();
582+#elif IS_FB2K_VER09
583+ metadb_handle_ptr track;
584+ static_api_ptr_t<playback_control>()->get_now_playing(track);
585+#endif
586+
587+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
588+
589+ for(it = beginIt; it != endIt; it ++) {
590+
591+ string8 info8;
592+
593+#if IS_FB2K_VER08
594+ play_control::get()->playback_format_title_ex(track, info8, it->c_str(), NULL, false, true);
595+#elif IS_FB2K_VER09
596+ service_ptr_t<titleformat_object> titleformat;
597+
598+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
599+ static_api_ptr_t<playback_control>()->playback_format_title_ex(track, NULL, info8, titleformat, NULL, play_control::display_level_titles);
600+#endif
601+// DEBUG_TRACK_INFO8("TrackInfo::setDynamicNumbers - %s: %s", it->c_str(), (LPCSTR)info8);
602+
603+ UINT newValue = static_cast<UINT>(::atol(info8));
604+ UINT oldValue = getNumber(*it);
605+
606+ if((newValue != 0) || (oldValue == 0)) {
607+ putNumber(it->c_str(), newValue);
608+ }
609+ }
610+
611+#if IS_FB2K_VER08
612+ if(track) {
613+ track->handle_release();
614+ }
615+#endif
616+ }
617+
618+ void setPlaylistNumbers(const Strings &keys)
619+ {
620+ TRACE_TRACK_INFO(_T("TrackInfo::setPlaylistNumbers - called."));
621+
622+#if IS_FB2K_VER08
623+ int track_index;
624+ track_index = playlist_oper::get()->get_now_playing();
625+#elif IS_FB2K_VER09
626+ t_size playlist_index, track_index;
627+ static_api_ptr_t<playlist_manager>()->get_playing_item_location(&playlist_index, &track_index);
628+#endif
629+
630+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
631+
632+ for(it = beginIt; it != endIt; it ++) {
633+
634+ string8 info8;
635+
636+#if IS_FB2K_VER08
637+ playlist_oper::get()->format_title(track_index, info8, it->c_str(), NULL);
638+#elif IS_FB2K_VER09
639+ service_ptr_t<titleformat_object> titleformat;
640+
641+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
642+ static_api_ptr_t<playlist_manager>()->playlist_item_format_title(playlist_index, track_index,
643+ NULL, info8, titleformat, NULL, play_control::display_level_titles);
644+#endif
645+// DEBUG_TRACK_INFO8("TrackInfo::setPlaylistNumbers - %s: %s", it->c_str(), (LPCSTR)info8);
646+
647+ putNumber(it->c_str(), static_cast<UINT>(::atol(info8)) );
648+ }
649+ }
650+
651+ void putString(const std::string &key, const std::string &value)
652+ {
653+ DEBUG_TRACK_INFO8("TrackInfo::putString - %s: %s", key.c_str(), value.c_str());
654+
655+ insert(m_infoMap8, key.c_str(), value.c_str());
656+
657+ string_ansi_from_utf8 valueAnsi(value.c_str());
658+
659+ insert(m_infoMapAnsi, key.c_str(), (LPCSTR)valueAnsi, true);
660+ }
661+
662+ void putNumber(const std::string &key, UINT value)
663+ {
664+ DEBUG_TRACK_INFO8("TrackInfo::putNumber - %s: %u", key.c_str(), value);
665+
666+ insert(m_infoMapNum, key.c_str(), value);
667+ }
668+
669+ const std::string &getString(const std::string &key, bool bForceUTF8 = false) const {
670+
671+ if((bForceUTF8 == true) || (cfg_disable_ansi_trans == 1))
672+ {
673+ StringMapCIt it(m_infoMap8.find(key)), endIt(m_infoMap8.end());
674+
675+ if(it == endIt) {
676+ return m_nullStr;
677+ }
678+
679+ return it->second;
680+ }
681+ else
682+ {
683+ StringMapCIt it(m_infoMapAnsi.find(key)), endIt(m_infoMapAnsi.end());
684+
685+ if(it == endIt) {
686+ return m_nullStr;
687+ }
688+
689+ return it->second;
690+ }
691+ }
692+
693+ const UINT getNumber(const std::string &key) const {
694+
695+ UIntMapCIt it(m_infoMapNum.find(key)), endIt(m_infoMapNum.end());
696+
697+ if(it == endIt) {
698+ return 0;
699+ }
700+
701+ return it->second;
702+ }
703+
704+ void removeStrings(const Strings &keys)
705+ {
706+ TRACE_TRACK_INFO(_T("TrackInfo::removeStrings - called."));
707+
708+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
709+
710+ for(it = beginIt; it != endIt; it ++) {
711+ removeString(*it);
712+ }
713+ }
714+
715+ void removeString(const std::string &key)
716+ {
717+ TRACE_TRACK_INFO8("TrackInfo::removeString - %s", key.c_str());
718+
719+ m_infoMap8.erase(m_infoMap8.find(key));
720+ m_infoMapAnsi.erase(m_infoMapAnsi.find(key));
721+ }
722+
723+ void removeNumbers(const Strings &keys)
724+ {
725+ TRACE_TRACK_INFO(_T("TrackInfo::removeNumbers - called."));
726+
727+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
728+
729+ for(it = beginIt; it != endIt; it ++) {
730+ removeNumber(*it);
731+ }
732+ }
733+
734+ void removeNumber(const std::string &key)
735+ {
736+ TRACE_TRACK_INFO8("TrackInfo::removeNumber - %s", key.c_str());
737+
738+ m_infoMapNum.erase(m_infoMapNum.find(key));
739+ }
740+
741+protected:
742+
743+ static void insert(StringMap &map, LPCSTR pKey, LPCSTR pValue, bool bAnsi = false)
744+ {
745+#if 0
746+ if(bAnsi) {
747+ TRACE_TRACK_INFO_ANSI("insertAnsi: [%s, %s]", pKey, pValue);
748+ } else {
749+ TRACE_TRACK_INFO8("insert8: [%s, %s]", pKey, pValue);
750+ }
751+#endif
752+
753+ map.insert(std::make_pair(pKey, pValue));
754+ }
755+
756+ static void insert(UIntMap &map, LPCSTR pKey, UINT value)
757+ {
758+// TRACE_TRACK_INFO8("insertNum: [%s, %u]", pKey, value);
759+
760+ map.insert(std::make_pair(pKey, value));
761+ }
762+};
763+
764+class PathInfo
765+{
766+ protected:
767+ PathInfo() {
768+ }
769+
770+ public:
771+ static tstring getFB2Kpath()
772+ {
773+ TCHAR modulePath[_MAX_PATH], moduleDrive[_MAX_DRIVE], moduleDir[_MAX_DIR];
774+ TCHAR returnPath[_MAX_PATH];
775+
776+ ::GetModuleFileName(NULL, modulePath, _MAX_PATH);
777+ ::_tsplitpath_s(modulePath, moduleDrive, _MAX_DRIVE, moduleDir, _MAX_DIR, NULL, 0, NULL, 0);
778+ ::_tmakepath_s(returnPath, _MAX_PATH, moduleDrive, moduleDir, NULL, NULL);
779+
780+ return tstring(returnPath);
781+ }
782+
783+ static tstring getFB2KComponentsPath() {
784+ return getFB2Kpath() + FB2K_COMPONENTS_DIR;
785+ }
786+
787+ static std::string getGenMixiDefaultPath()
788+ {
789+ string_utf8_from_os path(getFB2KComponentsPath().c_str());
790+ return (LPCSTR)path;
791+ }
792+
793+ static tstring getMixiStationAppPath() {
794+ return getSpecialFolderPath(CSIDL_APPDATA, FALSE) + APPDATA_MIXI_STATION_DIR;
795+ }
796+
797+ static tstring getFooMixiPlayInfoPath()
798+ {
799+ switch(cfg_dummy_mp3_location)
800+ {
801+ case 1:
802+ return getTemporaryFolderPath();
803+
804+ case 2:
805+ return getFB2KComponentsPath() ;
806+
807+ case 0:
808+ default:
809+ return getMixiStationAppPath() + _T("\\");
810+ }
811+ }
812+
813+ static tstring getDummyPlayInfoMp3Path() {
814+ return getFooMixiPlayInfoPath() + DUMMY_MP3_FILE_NAME;
815+ }
816+
817+ static tstring splitPath(const string8 &srcPath)
818+ {
819+ string_os_from_utf8 srcPathOs(srcPath);
820+ return splitPath(srcPathOs);
821+ }
822+
823+ static tstring splitPath(LPCTSTR srcPath)
824+ {
825+ TCHAR drive[_MAX_DRIVE], dir[_MAX_DIR], dstPath[_MAX_PATH];
826+ ::_tsplitpath_s(srcPath, drive, _MAX_DRIVE, dir, _MAX_DIR, NULL, 0, NULL, 0);
827+ ::_tmakepath_s(dstPath, _MAX_PATH, drive, dir, NULL, NULL);
828+ return dstPath;
829+ }
830+
831+ //! get the special folder path
832+ static tstring getSpecialFolderPath(int nFolder, BOOL bCreate)
833+ {
834+ tstring resStr;
835+ HRESULT hr = NO_ERROR;
836+
837+ IMalloc *pMalloc = 0;
838+ ITEMIDLIST *pItemID = 0;
839+ TCHAR folderPath[MAX_PATH];
840+
841+ folderPath[0] = _T('\0');
842+ hr = SHGetMalloc(&pMalloc);
843+
844+ if(hr == NO_ERROR)
845+ {
846+ hr = SHGetSpecialFolderLocation(0, nFolder, &pItemID);
847+
848+ if(hr == NO_ERROR)
849+ {
850+ if(SHGetPathFromIDList(pItemID, folderPath) == FALSE)
851+ hr = GetLastError();
852+
853+ pMalloc->Free(pItemID);
854+ }
855+
856+ pMalloc->Release();
857+ }
858+
859+ resStr = folderPath;
860+
861+ if(hr != NO_ERROR)
862+ {
863+ return _T("");
864+ }
865+
866+ return resStr;
867+ }
868+
869+ //! get the temporary folder path
870+ static tstring getTemporaryFolderPath() {
871+
872+ TCHAR strTempPath[MAX_PATH];
873+ ::GetTempPath(MAX_PATH, strTempPath);
874+
875+ return strTempPath;
876+ }
877+};
878+
879+#if IS_FB2K_VER08
880+static cfg_string cfg_gen_mixi_path("GenMixiPath", PathInfo::getGenMixiDefaultPath().c_str());
881+#elif IS_FB2K_VER09
882+// {1EC28435-C243-483c-81EC-E0E57A96727E}
883+static const GUID cfg_gen_mixi_path_guid = { 0x1ec28435, 0xc243, 0x483c, { 0x81, 0xec, 0xe0, 0xe5, 0x7a, 0x96, 0x72, 0x7e } };
884+static cfg_string cfg_gen_mixi_path(cfg_gen_mixi_path_guid, PathInfo::getGenMixiDefaultPath().c_str());
885+#endif
886+
887+class PlayInfo
888+{
889+ public:
890+
891+ enum EPlayStatus
892+ {
893+ PLAY_STOP = 0,
894+ PLAY_START = 1,
895+ PLAY_PAUSE = 3
896+ };
897+
898+ public:
899+
900+ PlayInfo() :
901+ m_playStatus(PLAY_STOP),
902+ m_isResentMode(false),
903+ m_playLength(0),
904+ m_playPosition(0),
905+ m_playCount(0),
906+ m_isPlayInfoMp3Available(false),
907+ m_resetBasePosition(0) {
908+ }
909+
910+ public:
911+
912+ void setPlayStatusStart() {
913+ setPlayStatus(PLAY_START);
914+ }
915+
916+ void setPlayStatusStop() {
917+ setPlayStatus(PLAY_STOP);
918+ }
919+
920+ void setPlayStatusPause() {
921+ setPlayStatus(PLAY_PAUSE);
922+ }
923+
924+ void clearPlayInfo(bool isResentMode = true)
925+ {
926+ setPlayStatusStop();
927+ m_isResentMode = isResentMode;
928+ setPlayPosition(0);
929+ setPlayLength(0);
930+ setPlayInfoMp3Available(false);
931+ m_resetBasePosition = 0;
932+ }
933+
934+ void setResentMode(bool bIncrementCounter = true)
935+ {
936+ if(bIncrementCounter) {
937+ incrementPlayCount();
938+ }
939+ m_isResentMode = true;
940+ m_resetBasePosition = m_playPosition;
941+ }
942+
943+ void clearResentMode() {
944+ m_isResentMode = false;
945+ }
946+
947+ void incrementPlayCount() {
948+ setPlayCount(getPlayCount() + 1);
949+ }
950+
951+ public:
952+
953+ EPlayStatus getPlayStatus() const
954+ {
955+ if((m_playStatus == PLAY_START) && m_isResentMode) {
956+ return PLAY_STOP;
957+ }
958+ return m_playStatus;
959+ }
960+
961+ void setPlayStatus(EPlayStatus status) {
962+ m_playStatus = status;
963+ }
964+
965+ int getPlayPosition() const
966+ {
967+ if(m_resetBasePosition > 0) {
968+ return m_playPosition - m_resetBasePosition;
969+ }
970+ return m_playPosition;
971+ }
972+
973+ void setPlayPosition(int pos) {
974+ m_playPosition = pos;
975+ }
976+
977+ int getPlayLength() const
978+ {
979+#if FORCE_RESENT_MODE == 0
980+ if(m_resetBasePosition > 0) {
981+#else
982+ if(true) {
983+#endif
984+ return 0;
985+ }
986+ return m_playLength;
987+ }
988+
989+ void setPlayLength(int len) {
990+ m_playLength = len;
991+ }
992+
993+ int getPlayCount() const {
994+ return m_playCount;
995+ }
996+
997+ void setPlayCount(int count) {
998+ m_playCount = count;
999+ }
1000+
1001+ bool isPlayInfoMp3Available() const {
1002+ return m_isPlayInfoMp3Available;
1003+ }
1004+
1005+ void setPlayInfoMp3Available(bool isAvailable) {
1006+ m_isPlayInfoMp3Available = isAvailable;
1007+ }
1008+
1009+ void setPlayInfoMp3Path(LPCSTR path)
1010+ {
1011+#if 0
1012+ m_playInfoMp3Path = path;
1013+
1014+ string_utf8_from_os path8(path);
1015+
1016+ if(cfg_disable_ansi_trans == 1)
1017+ {
1018+
1019+ m_playInfoMp3Path8 = path8;
1020+ }
1021+ else
1022+ {
1023+ string_ansi_from_utf8 pathAnsi(path8);
1024+
1025+ m_playInfoMp3Path8 = pathAnsi;
1026+ }
1027+#else
1028+ m_playInfoMp3Path8 = path;
1029+#endif
1030+ }
1031+
1032+ const string8 &getPlayInfoMp3Path8() const {
1033+ return m_playInfoMp3Path8;
1034+ }
1035+
1036+ bool isResentMode() const {
1037+ return m_isResentMode;
1038+ }
1039+
1040+ protected:
1041+
1042+ EPlayStatus m_playStatus;
1043+
1044+ int m_playLength;
1045+ int m_playPosition;
1046+ int m_playCount;
1047+
1048+ bool m_isPlayInfoMp3Available;
1049+ bool m_isResentMode;
1050+ int m_resetBasePosition;
1051+
1052+ string8 m_playInfoMp3Path8;
1053+};
1054+
1055+class id3Info
1056+{
1057+ public:
1058+
1059+ typedef std::vector<UINT16> UInt16Array;
1060+
1061+ id3Info(const TrackInfo & info) : m_info(info), m_hMp3File(INVALID_HANDLE_VALUE) {
1062+ }
1063+
1064+ ~id3Info() {
1065+ close();
1066+ }
1067+
1068+ DWORD write(LPCTSTR path) {
1069+
1070+ string_wide_from_utf8 title_utf16(m_info.getString(FORMAT_TRACKTITLE, true).c_str());
1071+ string_wide_from_utf8 artist_utf16(m_info.getString(FORMAT_ARTIST, true).c_str());
1072+ string_wide_from_utf8 album_utf16(m_info.getString(FORMAT_ALBUMTITLE, true).c_str());
1073+ string_wide_from_utf8 genre_utf16(m_info.getString(FORMAT_GENRE, true).c_str());
1074+
1075+ DWORD dwErr = S_OK;
1076+
1077+ if((dwErr = open(path)) != S_OK) {
1078+ return dwErr;
1079+ }
1080+
1081+ UInt16Array title = makeTextFrame("TIT2", makeUTF16LE(title_utf16));
1082+ UInt16Array album = makeTextFrame("TALB", makeUTF16LE(album_utf16));
1083+ UInt16Array artist = makeTextFrame("TPE1", makeUTF16LE(artist_utf16));
1084+ UInt16Array genre = makeTextFrame("TCON", makeUTF16LE(genre_utf16));
1085+
1086+ dwErr = writeHeader(static_cast<UINT32>(
1087+ title.size()*2 + album.size()*2 + artist.size()*2 + genre.size()*2 + 4));
1088+ // add charset code size (4bytes)
1089+
1090+ if(dwErr == S_OK) {
1091+ dwErr = writeTextFrame(title);
1092+ }
1093+
1094+ if(dwErr == S_OK) {
1095+ dwErr = writeTextFrame(album);
1096+ }
1097+
1098+ if(dwErr == S_OK) {
1099+ dwErr = writeTextFrame(artist);
1100+ }
1101+
1102+ if(dwErr == S_OK) {
1103+ dwErr = writeTextFrame(genre);
1104+ }
1105+
1106+ close();
1107+
1108+ return dwErr;
1109+ }
1110+
1111+ protected:
1112+
1113+ DWORD open(LPCTSTR path)
1114+ {
1115+ close();
1116+
1117+ // open dummy mp3 file
1118+ m_hMp3File = ::CreateFile(
1119+ path, GENERIC_WRITE, 0, NULL,
1120+ TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
1121+ );
1122+
1123+ if(m_hMp3File == INVALID_HANDLE_VALUE)
1124+ {
1125+ return ::GetLastError();
1126+ }
1127+
1128+ return S_OK;
1129+ }
1130+
1131+ UInt16Array makeUTF16LE(const string_wide_from_utf8 &str) {
1132+
1133+ LPCWSTR pStr = str.get_ptr();
1134+ size_t len = ::lstrlenW(pStr);
1135+ UInt16Array utf16(len + 2);
1136+
1137+ utf16[0] = 0xfeff; // BOM
1138+ ::CopyMemory(&utf16[1], str.get_ptr(), len * 2);
1139+
1140+ // swap byte order (big endian to little endian);
1141+ for(size_t i = 0; i < len + 1; i++) {
1142+ utf16[i] = (utf16[i] << 8) | (utf16[i] >> 8);
1143+ }
1144+
1145+ utf16[len + 1] = 0; // add NULL character
1146+
1147+ return utf16;
1148+ }
1149+
1150+ UInt16Array makeTextFrame(LPCSTR pFrameID, const UInt16Array &data) {
1151+
1152+ UInt16Array frame(data.size() + 5);
1153+
1154+ UINT32 size = static_cast<UINT32>(data.size() * 2 + 1); // add charset code size (1byte)
1155+
1156+ const UCHAR *pUCFrameID = reinterpret_cast<const UCHAR *>(pFrameID);
1157+ const UCHAR *pUCSize = reinterpret_cast<const UCHAR *>(&size);
1158+
1159+ frame[0] = ((UINT16)pUCFrameID[1]) << 8 | pUCFrameID[0];
1160+ frame[1] = ((UINT16)pUCFrameID[3]) << 8 | pUCFrameID[2];
1161+
1162+ frame[2] = ((UINT16)pUCSize[2]) << 8 | pUCSize[3];
1163+ frame[3] = ((UINT16)pUCSize[0]) << 8 | pUCSize[1];
1164+
1165+ frame[4] = 0; // frame flag
1166+
1167+ ::CopyMemory(&frame[5], &data[0], data.size() * 2);
1168+
1169+ return frame;
1170+ }
1171+
1172+ void close() {
1173+ if(m_hMp3File != INVALID_HANDLE_VALUE) {
1174+ ::CloseHandle(m_hMp3File);
1175+ m_hMp3File = INVALID_HANDLE_VALUE;
1176+ }
1177+ }
1178+
1179+ DWORD writeHeader(UINT32 size)
1180+ {
1181+ UInt16Array header(5);
1182+
1183+ header[0] = ((UINT16)'D') << 8 | (UCHAR)'I';
1184+ header[1] = ((UINT16) 3 ) << 8 | (UCHAR)'3';
1185+
1186+ header[2] = 0;
1187+
1188+ UInt16Array length = makeLength(size);
1189+
1190+ header[3] = length[0];
1191+ header[4] = length[1];
1192+
1193+ DWORD dwSize;
1194+ if(!::WriteFile(m_hMp3File, &header[0], 10, &dwSize, NULL)) {
1195+ return ::GetLastError();
1196+ }
1197+
1198+ return S_OK;
1199+ }
1200+
1201+ DWORD writeTextFrame(const UInt16Array &packet)
1202+ {
1203+ DWORD dwErr = S_OK;
1204+
1205+ UCHAR charsetCode = 0x01; // UNICODE
1206+
1207+ DWORD dwSize;
1208+ if(!::WriteFile(m_hMp3File, &packet[0], 10, &dwSize, NULL)) {
1209+ return ::GetLastError();
1210+ }
1211+ if(!::WriteFile(m_hMp3File, &charsetCode, 1, &dwSize, NULL)) {
1212+ return ::GetLastError();
1213+ }
1214+ if(!::WriteFile(m_hMp3File, &packet[5], static_cast<DWORD>(packet.size() * 2 - 10), &dwSize, NULL)) {
1215+ return ::GetLastError();
1216+ }
1217+
1218+ return S_OK;
1219+ }
1220+
1221+ UInt16Array makeLength(UINT32 size)
1222+ {
1223+ UInt16Array length(2);
1224+ UCHAR sizes[4];
1225+
1226+ /*
1227+ 00001111111111111111111111111111
1228+
1229+ 1111111000000000000000000000
1230+ f e 0 0 0 0 0
1231+ 111111100000000000000
1232+ 1 f c 0 0 0
1233+ 11111110000000
1234+ 3 f 8 0
1235+ 1111111
1236+ 7 f
1237+ */
1238+
1239+ sizes[3] = static_cast<UCHAR>((size & 0x0000007f) >> 0);
1240+ sizes[2] = static_cast<UCHAR>((size & 0x00003f80) >> 7);
1241+ sizes[1] = static_cast<UCHAR>((size & 0x001fc000) >> 14);
1242+ sizes[0] = static_cast<UCHAR>((size & 0x0fe00000) >> 21);
1243+
1244+
1245+ length[0] = ((UINT16)sizes[1]) << 8 | sizes[0];
1246+ length[1] = ((UINT16)sizes[3]) << 8 | sizes[2];
1247+
1248+ return length;
1249+ }
1250+
1251+ protected:
1252+
1253+ TrackInfo m_info;
1254+ HANDLE m_hMp3File;
1255+};
1256+
1257+class DummyAmp
1258+{
1259+ public:
1260+
1261+ DummyAmp()
1262+ : m_bReady(false)
1263+ , m_hInstGenMixi((HINSTANCE)INVALID_HANDLE_VALUE)
1264+ , m_pGenMixi(NULL)
1265+ , m_hWinampWnd((HWND)INVALID_HANDLE_VALUE)
1266+ , m_GETPLAYLISTFILE_time(0)
1267+ , m_hDirChangeNotify((HANDLE)INVALID_HANDLE_VALUE)
1268+ , m_isDummyPlayInfoMp3Available(false)
1269+ , m_isAnotherWinampWindowAvailable(false)
1270+ {
1271+
1272+ m_winampTitle = _T("Winamp");
1273+ }
1274+
1275+ ~DummyAmp()
1276+ {
1277+ release();
1278+ destroyWindow();
1279+ closeDirChangeNotifyHandle();
1280+ }
1281+
1282+ public:
1283+
1284+ static DummyAmp *getInstance()
1285+ {
1286+ if(m_pMe == NULL)
1287+ {
1288+ m_pMe = new DummyAmp();
1289+ }
1290+
1291+ return m_pMe;
1292+ }
1293+
1294+ void load()
1295+ {
1296+ TRACE_DUMMYAMP_INIT(_T("DummyAmp::load - called."));
1297+
1298+ // initialize gen_mixi_for_winamp
1299+ initGenMixi();
1300+
1301+ // initialize dummy mp3 file, if dummy mp3 is enabled
1302+ if(cfg_disable_dummy_mp3 == 0) {
1303+ initDummyMp3();
1304+ }
1305+
1306+ // set ready flag, if initialization successfully done
1307+ if( (getGenMixi() != NULL) && ((cfg_disable_dummy_mp3 == 0) || (isDummyPlayInfoMp3Available() == true)) ){
1308+ setReady(true);
1309+ }
1310+ }
1311+
1312+ void config()
1313+ {
1314+ TRACE_DUMMYAMP_INIT(_T("DummyAmp::config - called."));
1315+
1316+ if(getGenMixi() != NULL) {
1317+ getGenMixi()->config();
1318+ }
1319+ }
1320+
1321+ void release()
1322+ {
1323+ TRACE_DUMMYAMP_INIT(_T("DummyAmp::release - called."));
1324+
1325+ // finalize gen_mixi_for_winamp
1326+ finalizeGenMixi();
1327+
1328+ // finalize dummy mp3 file, if dummy mp3 is enbaled
1329+ if(isDummyPlayInfoMp3Available())
1330+ {
1331+ finalizeDummyMp3();
1332+ }
1333+ }
1334+
1335+ void clearDummyAmpTitle()
1336+ {
1337+ uSetWindowText(getWnd(), DEFAULT_DUMMYAMP_TITLE);
1338+ }
1339+
1340+ void createWindow()
1341+ {
1342+ TRACE_PLUGIN(_T("DummyAmp::createWindow - called."));
1343+
1344+ if(getWnd() == INVALID_HANDLE_VALUE)
1345+ {
1346+ if(getGenMixi() != NULL)
1347+ {
1348+ HWND hAnotherWinamp = FindWindowEx(NULL, NULL, _T("Winamp v1.x"), NULL);
1349+
1350+ // found another winamp window
1351+ if(hAnotherWinamp != NULL)
1352+ {
1353+ DEBUG_PLUGIN(_T("DummyAmp::createWindow - Winamp のウィンドウを検出しました。ハンドル: %08x"), hAnotherWinamp);
1354+
1355+ DWORD dwAnotherWndProcessID;
1356+ ::GetWindowThreadProcessId(hAnotherWinamp, &dwAnotherWndProcessID);
1357+
1358+ DWORD dwFb2kProcessID = ::GetCurrentProcessId();
1359+
1360+ DEBUG_PLUGIN(_T("DummyAmp::createWindow - Winamp ウィンドウが属するプロセスのハンドル: %08x"), dwAnotherWndProcessID);
1361+ DEBUG_PLUGIN(_T("DummyAmp::createWindow - 現在実行中の foobar2000 プロセスのハンドル: %08x"), dwFb2kProcessID);
1362+
1363+ // another winamp window owned by foobar2000 process
1364+ if(dwAnotherWndProcessID == dwFb2kProcessID) {
1365+ // subclass it, because it's winamp api simulator plugin's window
1366+ setWnd(subclassWinampWindow(hAnotherWinamp));
1367+ } else {
1368+ LOG_ERROR(
1369+ _T("DummyAmp::createWindow - 検出した Winamp ウィンドウが他のプロセスに属しています"));
1370+ LOG_ERROR(
1371+ _T("DummyAmp::createWindow - Winamp と思われるプログラムが実行されているため、")
1372+ _T("mixi station への送信機能は使用できません"));
1373+ LOG_ERROR(
1374+ _T("DummyAmp::createWindow - 該当のプログラム(プロセスID:%d)を終了し、")
1375+ _T("foobar2000 を再起動してください")
1376+ , dwAnotherWndProcessID);
1377+
1378+ // unset dummyAmp ready flag
1379+ setReady(false);
1380+ }
1381+ }
1382+ // create own winamp simulating window
1383+ else
1384+ {
1385+ setWnd(createWinampWindow());
1386+ }
1387+
1388+ // initialize gen_mixi_for_winamp, if winamp window successfully created or subclassed
1389+ if(getWnd() != INVALID_HANDLE_VALUE)
1390+ {
1391+ getGenMixi()->hwndParent = getWnd();
1392+ getGenMixi()->hDllInstance = getHInstance();
1393+ getGenMixi()->init();
1394+ }
1395+ else
1396+ {
1397+ // unset dummyAmp ready flag
1398+ setReady(false);
1399+ }
1400+ }
1401+ }
1402+ }
1403+
1404+ void refreshAmpInfo()
1405+ {
1406+#if !defined(CONTROL_SEND_TIMING)
1407+ // increment play counter on dummyamp
1408+ getPlayInfo().incrementPlayCount();
1409+
1410+ // update dummyamp title
1411+ updateDummyAmpTitle();
1412+#endif
1413+ // use currently playing mp3 or ogg/vorbis file instead when dummy playinfo mp3 file disabled by user
1414+ // (other codec types will be ignored, because they are not supported by gen_mixi_for_winamp)
1415+ if(cfg_disable_dummy_mp3 == 1)
1416+ {
1417+ // set playinfo mp3 file path to dummyAmp
1418+ getPlayInfo().setPlayInfoMp3Path(m_trackInfo.getString(FORMAT_FILEPATH).c_str());
1419+
1420+ // set playinfo mp3 file available flag to dummyAmp
1421+ LPCSTR codec = m_trackInfo.getString(FORMAT_CODEC).c_str();
1422+ getPlayInfo().setPlayInfoMp3Available(IS_SUPPORTED_FORMAT_BY_GEN_MIXI(codec));
1423+ }
1424+ else
1425+ {
1426+ // check dummy playinfo mp3 exists and writable
1427+ if(isDummyPlayInfoMp3Available())
1428+ {
1429+ // update dummy mp3 file
1430+ tstring playInfoMp3Path = PathInfo::getDummyPlayInfoMp3Path();
1431+#if 1
1432+ id3Info id3Info(m_trackInfo);
1433+ DWORD dwErrCode;
1434+
1435+ if(( dwErrCode = id3Info.write(playInfoMp3Path.c_str()) ) == S_OK)
1436+ {
1437+ string_utf8_from_os dummyMp3Path8(playInfoMp3Path.c_str());
1438+
1439+ // set dummy playinfo mp3 file path to dummyAmp
1440+ getPlayInfo().setPlayInfoMp3Path(dummyMp3Path8);
1441+
1442+ // set playinfo mp3 file available flag to dummyAmp
1443+ getPlayInfo().setPlayInfoMp3Available(true);
1444+ }
1445+ else
1446+ {
1447+ putLogError(_T("DummyAmp::refreshAmpInfo"), _T("ダミーMP3ファイルの書き込み中にエラーが発生しました"), dwErrCode);
1448+ LOG_ERROR(_T("DummyAmp::refreshAmpInfo - ファイルパス: %s"), playInfoMp3Path.c_str());
1449+
1450+ // set playinfo mp3 file available flag
1451+ getPlayInfo().setPlayInfoMp3Available(false);
1452+
1453+ // unset dummyAmp ready flag
1454+ setReady(false);
1455+ }
1456+#else
1457+ // set id3v2 informations
1458+
1459+ string_utf8_from_os dummyMp3Path8(playInfoMp3Path.c_str());
1460+ string_ansi_from_utf8 dummyMp3PathAnsi(dummyMp3Path8);
1461+ ID3_Tag dummySong(dummyMp3PathAnsi);
1462+
1463+ string_wide_from_utf8 title_utf16(m_trackInfo.getString(FORMAT_TRACKTITLE, true).c_str());
1464+ string_wide_from_utf8 artist_utf16(m_trackInfo.getString(FORMAT_ARTIST, true).c_str());
1465+ string_wide_from_utf8 album_utf16(m_trackInfo.getString(FORMAT_ALBUMTITLE, true).c_str());
1466+ string_wide_from_utf8 genre_utf16(m_trackInfo.getString(FORMAT_GENRE, true).c_str());
1467+
1468+ AddTitle(&dummySong, title_utf16, true);
1469+ AddArtist(&dummySong, artist_utf16, true);
1470+ AddAlbum(&dummySong, album_utf16, true);
1471+ AddGenre(&dummySong, genre_utf16, true);
1472+
1473+ // write id3v2 tag
1474+ dummySong.SetPadding(false);
1475+ dummySong.SetUnsync(false);
1476+ if(dummySong.Update(ID3TT_ID3V2) != ID3TT_NONE)
1477+ {
1478+ // set dummy playinfo mp3 file path to dummyAmp
1479+ getPlayInfo().setPlayInfoMp3Path(dummyMp3Path8);
1480+
1481+ // set playinfo mp3 file available flag to dummyAmp
1482+ getPlayInfo().setPlayInfoMp3Available(true);
1483+ }
1484+ else
1485+ {
1486+ LOG_ERROR(_T("DummyAmp::refreshAmpInfo - ID3_Tag::Update(ID3TT_ID3V2) failed."));
1487+
1488+ // set playinfo mp3 file available flag
1489+ getPlayInfo().setPlayInfoMp3Available(false);
1490+
1491+ // unset dummyAmp ready flag
1492+ setReady(false);
1493+ }
1494+#endif
1495+ }
1496+ else
1497+ {
1498+ // reset playinfo mp3 file available flag
1499+ getPlayInfo().setPlayInfoMp3Available(false);
1500+
1501+ LOG_WARN(_T("DummyAmp::refreshAmpInfo - ダミーMP3ファイルが無効になっているため、送信情報を書き込めません。"));
1502+ }
1503+ }
1504+
1505+#if !defined(CONTROL_SEND_TIMING)
1506+ // set dummyamp status PLAY_START
1507+ getPlayInfo().setPlayStatusStart();
1508+#endif
1509+ }
1510+
1511+ public:
1512+
1513+ bool isReady() const {
1514+ return m_bReady;
1515+ }
1516+
1517+ HWND getWnd() const {
1518+ return m_hWinampWnd;
1519+ }
1520+
1521+ const TrackInfo &getTrackInfo() const {
1522+ return m_trackInfo;
1523+ }
1524+
1525+ TrackInfo &getMutableTrackInfo() {
1526+ return m_trackInfo;
1527+ }
1528+
1529+ void setTrackInfo(const TrackInfo &trackInfo) {
1530+ m_trackInfo = trackInfo;
1531+ }
1532+
1533+ PlayInfo &getPlayInfo() {
1534+ return m_playInfo;
1535+ }
1536+
1537+ PlayInfo &getRawPlayInfo() {
1538+ return m_rawPlayInfo;
1539+ }
1540+
1541+
1542+ void setPlaylistTitle(LPCTSTR pTitle) {
1543+
1544+ TRACE_PLUGIN(_T("DummyAmp::setPlayListTitle - %s"), pTitle);
1545+
1546+ m_playlistTitle = pTitle;
1547+
1548+ string_utf8_from_os playListTitle8(pTitle);
1549+
1550+ if(cfg_disable_ansi_trans == 1)
1551+ {
1552+
1553+ m_playlistTitle8 = playListTitle8;
1554+ }
1555+ else
1556+ {
1557+ string_ansi_from_utf8 playListTitleAnsi(playListTitle8);
1558+
1559+ m_playlistTitle8 = playListTitleAnsi;
1560+ }
1561+ }
1562+
1563+ const tstring &getPlaylistTitle() const {
1564+ return m_playlistTitle;
1565+ }
1566+
1567+ const string8 &getPlaylistTitle8() const {
1568+ return m_playlistTitle8;
1569+ }
1570+
1571+ void setWinampTitle(LPCTSTR pTitle) {
1572+
1573+ TRACE_PLUGIN(_T("DummyAmp::setWinampTitle - %s"), pTitle);
1574+
1575+ m_winampTitle = pTitle;
1576+ }
1577+
1578+ const tstring &getWinampTitle() const {
1579+ return m_winampTitle;
1580+ }
1581+
1582+ void setBaseWinampTitle(LPCTSTR pTitle)
1583+ {
1584+ TRACE_PLUGIN(_T("DummyAmp::setRawWinampTitle - %s"), pTitle);
1585+
1586+ m_baseWinampTitle = pTitle;
1587+
1588+ updateDummyAmpTitle();
1589+ }
1590+
1591+ const tstring &getBaseWinampTitle() const {
1592+ return m_baseWinampTitle;
1593+ }
1594+
1595+ const tstring &getDummyPlayInfoMp3Path() const {
1596+ return m_dummyPlayInfoMp3Path;
1597+ }
1598+
1599+ bool isDummyPlayInfoMp3Available() const {
1600+ return m_isDummyPlayInfoMp3Available;
1601+ }
1602+
1603+ bool isAnotherWinampWindowAvailable() const {
1604+ return m_isAnotherWinampWindowAvailable;
1605+ }
1606+
1607+ void showDummyAmpWindow(bool bShow) {
1608+ showDummyAmpWindow(getWnd(), bShow);
1609+ }
1610+
1611+ protected:
1612+
1613+ void initGenMixi()
1614+ {
1615+ string_os_from_utf8 path(cfg_gen_mixi_path);
1616+ tstring genMixiPath = path;
1617+ genMixiPath += GEN_MIXI_FILE_NAME;
1618+
1619+ setHInstance(::LoadLibrary(genMixiPath.c_str()));
1620+
1621+ if(getHInstance() == NULL)
1622+ {
1623+ setHInstance((HINSTANCE)INVALID_HANDLE_VALUE);
1624+
1625+ tstring msg;
1626+ msg = GEN_MIXI_FILE_NAME _T(" が見つかりません。\n以下のパスにファイルが存在するか確認してください。\n");
1627+ msg += genMixiPath;
1628+
1629+ string_utf8_from_os uMsg(msg.c_str());
1630+
1631+ uMessageBox(NULL, uMsg, PLUGIN_CAPTION, MB_ICONEXCLAMATION | MB_OK);
1632+ }
1633+ else
1634+ {
1635+ winampGeneralPurposePluginGetter funcWinampGetGeneralPurposePlugin = NULL;
1636+
1637+ funcWinampGetGeneralPurposePlugin = (winampGeneralPurposePluginGetter)
1638+ ::GetProcAddress(getHInstance(), GEN_MIXI_FUNC_NAME_GET_GENERAL_PURPOSE_PLUGIN);
1639+
1640+ if(funcWinampGetGeneralPurposePlugin != NULL)
1641+ {
1642+ setGenMixi(funcWinampGetGeneralPurposePlugin());
1643+ // create window later.
1644+ }
1645+ else
1646+ {
1647+ tstring msg;
1648+ msg = _T("関数 ") _T(GEN_MIXI_FUNC_NAME_GET_GENERAL_PURPOSE_PLUGIN) _T("() が見つかりません。\n")
1649+ GEN_MIXI_FILE_NAME _T(" が壊れている可能性があります。");
1650+
1651+ string_utf8_from_os uMsg(msg.c_str());
1652+
1653+ uMessageBox(NULL, uMsg, PLUGIN_CAPTION, MB_ICONEXCLAMATION | MB_OK);
1654+ }
1655+ }
1656+ }
1657+
1658+ void initDummyMp3()
1659+ {
1660+ // if dummy mp3 file not exist
1661+ tstring dummyPlayInfoMp3Path = PathInfo::getDummyPlayInfoMp3Path();
1662+ DWORD dwAttr = ::GetFileAttributes(dummyPlayInfoMp3Path.c_str());
1663+
1664+ if(dwAttr == -1)
1665+ {
1666+ // create dummy mp3 file
1667+ HANDLE hMp3File = ::CreateFile(
1668+ dummyPlayInfoMp3Path.c_str(), 0, 0, NULL,
1669+ CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL
1670+ );
1671+
1672+ if(hMp3File == INVALID_HANDLE_VALUE)
1673+ {
1674+ DWORD dwErrCode = ::GetLastError();
1675+ putLogError(_T("DummyAmp::initDummyMp3"), _T("ダミーMP3ファイルの作成中にエラーが発生しました"), dwErrCode);
1676+ LOG_ERROR(_T("DummyAmp::initDummyMp3 - ファイルパス: %s"), dummyPlayInfoMp3Path.c_str());
1677+
1678+ LOG_ERROR(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルが使用できないため、送信機能は無効になります"));
1679+ }
1680+ else
1681+ {
1682+ DEBUG_DUMMYAMP_INIT(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルを [%s] に作成しました"), dummyPlayInfoMp3Path.c_str());
1683+
1684+ ::CloseHandle(hMp3File);
1685+
1686+ setDummyPlayInfoMp3Path(dummyPlayInfoMp3Path);
1687+ setDummyPlayInfoMp3Available(true);
1688+ }
1689+ }
1690+ else if((dwAttr & FILE_ATTRIBUTE_READONLY) != 0)
1691+ {
1692+ LOG_ERROR(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルがパス [%s] 上に既に存在しますが、")
1693+ _T("読み込み専用属性のため書き込みできません"), dummyPlayInfoMp3Path.c_str());
1694+
1695+ LOG_ERROR(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルが使用できないため、送信機能は無効になります"));
1696+ }
1697+ else
1698+ {
1699+ LOG_WARN(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルがパス [%s] 上に既に存在します"), dummyPlayInfoMp3Path.c_str());
1700+ LOG_WARN(_T("DummyAmp::initDummyMp3 - このMP3ファイルは逐次上書きされ、終了時に削除されます"));
1701+
1702+ setDummyPlayInfoMp3Path(dummyPlayInfoMp3Path);
1703+ setDummyPlayInfoMp3Available(true);
1704+ }
1705+ }
1706+
1707+ void finalizeGenMixi()
1708+ {
1709+ if(getHInstance() != INVALID_HANDLE_VALUE)
1710+ {
1711+ if(getGenMixi() != NULL)
1712+ {
1713+ getGenMixi()->quit();
1714+ setGenMixi(NULL);
1715+ }
1716+ ::FreeLibrary(getHInstance());
1717+ setHInstance((HINSTANCE)INVALID_HANDLE_VALUE);
1718+ }
1719+
1720+ }
1721+
1722+ void finalizeDummyMp3()
1723+ {
1724+ tstring dummyPlayInfoMp3Path = getDummyPlayInfoMp3Path();
1725+
1726+ if(::DeleteFile(dummyPlayInfoMp3Path.c_str()) == FALSE)
1727+ {
1728+ DWORD dwErrCode = ::GetLastError();
1729+ putLogError(_T("DummyAmp::finalizeDummyMp3"), _T("ダミーMP3ファイルの削除中にエラーが発生しました"), dwErrCode);
1730+ LOG_ERROR(_T("DummyAmp::finalizeDummyMp3 - ファイルパス: %s"), dummyPlayInfoMp3Path.c_str());
1731+ }
1732+ else
1733+ {
1734+ DEBUG_DUMMYAMP_INIT(_T("DummyAmp::finalizeDummyMp3 - ダミーMP3ファイル [%s] を削除しました"), dummyPlayInfoMp3Path.c_str());
1735+ setDummyPlayInfoMp3Available(false);
1736+ }
1737+ }
1738+
1739+ void updateDummyAmpTitle()
1740+ {
1741+ bool bDisableDuplicatedSong = (cfg_disable_duplicate_song == 0);
1742+ tstring winampTitle = makeDummyAmpTitle(getBaseWinampTitle(), bDisableDuplicatedSong);
1743+
1744+ setWinampTitle(winampTitle.c_str());
1745+
1746+ if(isAnotherWinampWindowAvailable() == false) {
1747+ ::SetWindowText(getWnd(), winampTitle.c_str());
1748+ }
1749+ }
1750+
1751+ protected:
1752+
1753+ void setReady(bool bReady) {
1754+ m_bReady = bReady;
1755+ }
1756+
1757+ void setWnd(HWND hWnd) {
1758+ m_hWinampWnd = hWnd;
1759+ }
1760+
1761+ HINSTANCE getHInstance() const {
1762+ return m_hInstGenMixi;
1763+ }
1764+
1765+ void setHInstance(HINSTANCE hInst) {
1766+ m_hInstGenMixi = hInst;
1767+ }
1768+
1769+ winampGeneralPurposePlugin *getGenMixi() const {
1770+ return m_pGenMixi;
1771+ }
1772+
1773+ void setGenMixi(winampGeneralPurposePlugin *pGenMixi) {
1774+ m_pGenMixi = pGenMixi;
1775+ }
1776+
1777+ void setDummyPlayInfoMp3Path(const tstring &path) {
1778+ m_dummyPlayInfoMp3Path = path;
1779+ }
1780+
1781+ void setDummyPlayInfoMp3Available(bool isAvailable) {
1782+ m_isDummyPlayInfoMp3Available = isAvailable;
1783+ }
1784+
1785+ void setAnotherWinampWindowAvailable(bool isAvailable) {
1786+ m_isAnotherWinampWindowAvailable = isAvailable;
1787+ }
1788+
1789+ int getGetPlayListFileTime() const {
1790+ return m_GETPLAYLISTFILE_time;
1791+ }
1792+
1793+ void setGetPlayListFileTime(int time) {
1794+ m_GETPLAYLISTFILE_time = time;
1795+ }
1796+
1797+ HANDLE getDirChangeNotifyHandle() const {
1798+ return m_hDirChangeNotify;
1799+ }
1800+
1801+ void setDirChangeNotifyHandle(HANDLE handle) {
1802+ m_hDirChangeNotify = handle;
1803+ }
1804+
1805+ protected:
1806+
1807+ HWND createWinampWindow()
1808+ {
1809+ TRACE_PLUGIN(_T("DummyAmp::createWinampWindow - called."));
1810+
1811+ static bool isInited = false;
1812+
1813+#if IS_FB2K_VER08
1814+ static const char class_name[] = "Winamp v1.x";
1815+ if (!isInited)
1816+ {
1817+ isInited = true;
1818+ uWNDCLASS wc;
1819+ memset(&wc,0,sizeof(wc));
1820+ wc.style = 0;
1821+ wc.lpfnWndProc = windowproc;
1822+ wc.hInstance = core_api::get_my_instance();
1823+ wc.hCursor = NULL; //uLoadCursor(0, IDC_ARROW);
1824+ wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
1825+ wc.lpszClassName = class_name;
1826+ uRegisterClass(&wc);
1827+ }
1828+ HWND hWinampWnd = uCreateWindowEx(
1829+ 0, class_name, DEFAULT_DUMMYAMP_TITLE,
1830+ WS_OVERLAPPED|WS_CAPTION|WS_SIZEBOX,
1831+ CW_USEDEFAULT, CW_USEDEFAULT, 300, 150,
1832+#if 1
1833+ core_api::get_main_window(), 0, core_api::get_my_instance(), NULL
1834+#else
1835+ NULL, 0, core_api::get_my_instance(), NULL
1836+#endif
1837+ );
1838+#elif IS_FB2K_VER09
1839+ static const TCHAR class_name[] = _T("Winamp v1.x");
1840+ if (!isInited)
1841+ {
1842+ isInited = true;
1843+ WNDCLASS wc;
1844+ memset(&wc,0,sizeof(wc));
1845+ wc.style = 0;
1846+ wc.lpfnWndProc = windowproc;
1847+ wc.hInstance = core_api::get_my_instance();
1848+ wc.hCursor = NULL; //uLoadCursor(0, IDC_ARROW);
1849+ wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
1850+ wc.lpszClassName = class_name;
1851+ RegisterClass(&wc);
1852+ }
1853+ HWND hWinampWnd = CreateWindowEx(
1854+ 0, class_name, _T(DEFAULT_DUMMYAMP_TITLE),
1855+ WS_OVERLAPPED|WS_CAPTION|WS_SIZEBOX,
1856+ CW_USEDEFAULT, CW_USEDEFAULT, 300, 150,
1857+#if 1
1858+ core_api::get_main_window(), 0, core_api::get_my_instance(), NULL
1859+#else
1860+ NULL, 0, core_api::get_my_instance(), NULL
1861+#endif
1862+ );
1863+#endif
1864+ if (!hWinampWnd)
1865+ {
1866+ DWORD dwErrCode = ::GetLastError();
1867+ putLogError(_T("DummyAmp::createWinampWindow"), _T("DummyAmp ウィンドウの生成に失敗しました"), dwErrCode);
1868+
1869+ return NULL;
1870+ }
1871+
1872+ DEBUG_PLUGIN(_T("DummyAmp::createWinampWindow - DummyAmp ウィンドウを生成しました"));
1873+
1874+ showDummyAmpWindow(hWinampWnd, cfg_show_dummyamp == 1);
1875+
1876+ return hWinampWnd;
1877+ }
1878+
1879+ HWND subclassWinampWindow(HWND hAnotherWinampWnd) {
1880+ // subclass another dummyamp window
1881+ m_pfnOldAnotherWinampProc =
1882+ SetWindowLongPtr(hAnotherWinampWnd, GWL_WNDPROC, WNDPROC_TO_LONG_PTR(hookWinampWindowProc));
1883+
1884+ if(hAnotherWinampWnd != NULL)
1885+ {
1886+ DEBUG_PLUGIN(_T("DummyAmp::subclassWinampWindow - API エミュレータと思われる Winamp ウィンドウのプロシージャをフックしました"));
1887+ setAnotherWinampWindowAvailable(true);
1888+
1889+ return hAnotherWinampWnd;
1890+ }
1891+ else
1892+ {
1893+ DWORD dwErrCode = ::GetLastError();
1894+ putLogError(_T("DummyAmp::subclassWinampWindow"), _T("Winamp ウィンドウのサブクラス化に失敗しました"), dwErrCode);
1895+
1896+ LOG_ERROR(_T("DummyAmp::subclassWinampWindow - Winamp ウィンドウのプロシージャをフックできなかったため、送信機能は無効になります"));
1897+ }
1898+
1899+ return (HWND)INVALID_HANDLE_VALUE;
1900+ }
1901+
1902+ void unsubclassWinampWindow() {
1903+ SetWindowLongPtr(getWnd(), GWL_WNDPROC, m_pfnOldAnotherWinampProc);
1904+ }
1905+
1906+ void showDummyAmpWindow(HWND hWinampWnd, bool bShow)
1907+ {
1908+ if(bShow) {
1909+ ShowWindow(hWinampWnd, SW_SHOW);
1910+ } else {
1911+ ShowWindow(hWinampWnd, SW_HIDE);
1912+ }
1913+ }
1914+
1915+ void destroyWindow()
1916+ {
1917+ TRACE_PLUGIN(_T("DummyAmp::destroyWindow - called."));
1918+
1919+ if(getWnd() != INVALID_HANDLE_VALUE)
1920+ {
1921+ if(isAnotherWinampWindowAvailable() == false) {
1922+ uDestroyWindow(getWnd());
1923+ } else {
1924+ unsubclassWinampWindow();
1925+
1926+ DEBUG_PLUGIN(_T("DummyAmp::destroyWindow - Winamp ウィンドウのサブクラス化を解除しました"));
1927+ }
1928+
1929+ setWnd((HWND)INVALID_HANDLE_VALUE);
1930+ }
1931+ }
1932+
1933+ void closeDirChangeNotifyHandle()
1934+ {
1935+ TRACE_PLUGIN(_T("DummyAmp::closeDirChangeNotifyHandle - called."));
1936+
1937+ if(m_hDirChangeNotify != INVALID_HANDLE_VALUE)
1938+ {
1939+ ::FindCloseChangeNotification(m_hDirChangeNotify);
1940+ TRACE_PLUGIN(_T("DummyAmp::closeDirChangeNotifyHandle - ディレクトリ変更通知イベントのハンドル (ID:%08x) を閉じました"), m_hDirChangeNotify);
1941+
1942+ m_hDirChangeNotify = (HANDLE)INVALID_HANDLE_VALUE;
1943+ }
1944+ }
1945+
1946+ tstring makeDummyAmpTitle(const tstring &rawTitle, bool bCounterReflection)
1947+ {
1948+ TRACE_PLUGIN(_T("DummyAmp::makeDummyAmpTitle - called."));
1949+
1950+ Str64K formatBuf;
1951+
1952+ if(bCounterReflection)
1953+ {
1954+ _stprintf_s(
1955+ formatBuf, sizeof(formatBuf) / sizeof(TCHAR),
1956+ _T("%d. %s - ") _T(DEFAULT_WINAMP_TITLE),
1957+ getPlayInfo().getPlayCount(),
1958+ (LPCTSTR)rawTitle.c_str()
1959+ );
1960+ }
1961+ else
1962+ {
1963+ _stprintf_s(
1964+ formatBuf, sizeof(formatBuf) / sizeof(TCHAR),
1965+ _T("%d. %s - ") _T(DEFAULT_WINAMP_TITLE),
1966+ m_trackInfo.getNumber(FORMAT_LISTINDEX),
1967+ (LPCTSTR)rawTitle.c_str()
1968+ );
1969+ }
1970+
1971+ return formatBuf;
1972+ }
1973+
1974+ void refreshTitle()
1975+ {
1976+ // get formatted dynamic titles
1977+ string8 dummyAmp_title8;
1978+ string8 playlist_title8;
1979+#if IS_FB2K_VER08
1980+ metadb_handle *track = play_control::get()->get_now_playing();
1981+ if(track)
1982+ {
1983+ play_control::get()->playback_format_title_ex(track, dummyAmp_title8, cfg_dummyamp_title_format, NULL, false, true);
1984+ play_control::get()->playback_format_title_ex(track, playlist_title8, cfg_dummyamp_playlist_format, NULL, false, true);
1985+ track->handle_release();
1986+ }
1987+#elif IS_FB2K_VER09
1988+ metadb_handle_ptr track;
1989+ static_api_ptr_t<playback_control>()->get_now_playing(track);
1990+
1991+ service_ptr_t<titleformat_object> titleformat;
1992+
1993+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, cfg_dummyamp_title_format);
1994+ static_api_ptr_t<playback_control>()->playback_format_title_ex(track, NULL, dummyAmp_title8, titleformat, NULL, play_control::display_level_all);
1995+
1996+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, cfg_dummyamp_playlist_format);
1997+ static_api_ptr_t<playback_control>()->playback_format_title_ex(track, NULL, playlist_title8, titleformat, NULL, play_control::display_level_all);
1998+#endif
1999+ // convert utf8 track informations to os charset
2000+ string_os_from_utf8 dummyAmp_title(dummyAmp_title8);
2001+ string_os_from_utf8 playlist_title(playlist_title8);
2002+
2003+ // set base dummyamp title to dummyamp
2004+ setBaseWinampTitle(dummyAmp_title);
2005+
2006+ // set dummyamp playlist current item title to dummyamp
2007+ setPlaylistTitle(playlist_title);
2008+ }
2009+
2010+#if 0
2011+ private:
2012+
2013+ ID3_Frame* AddArtist(ID3_Tag *tag, const wchar_t *text, bool replace)
2014+ {
2015+ ID3_Frame* frame = NULL;
2016+ if (NULL != tag && NULL != text && lstrlen(text) > 0)
2017+ {
2018+ if (replace)
2019+ {
2020+ RemoveArtists(tag);
2021+ }
2022+ if (replace ||
2023+ (tag->Find(ID3FID_LEADARTIST) == NULL &&
2024+ tag->Find(ID3FID_BAND) == NULL &&
2025+ tag->Find(ID3FID_CONDUCTOR) == NULL &&
2026+ tag->Find(ID3FID_COMPOSER) == NULL))
2027+ {
2028+ frame = new ID3_Frame(ID3FID_LEADARTIST);
2029+ if (frame)
2030+ {
2031+ frame->GetField(ID3FN_TEXT)->SetEncoding(ID3TE_UNICODE);
2032+ frame->GetField(ID3FN_TEXT)->Set(SwapByteOrder(text));
2033+ frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_UNICODE);
2034+ tag->AttachFrame(frame);
2035+ }
2036+ }
2037+ }
2038+ return frame;
2039+ }
2040+
2041+ size_t RemoveArtists(ID3_Tag *tag)
2042+ {
2043+ size_t num_removed = 0;
2044+ ID3_Frame *frame = NULL;
2045+
2046+ if (NULL == tag)
2047+ {
2048+ return num_removed;
2049+ }
2050+
2051+ while ((frame = tag->Find(ID3FID_LEADARTIST)) != NULL)
2052+ {
2053+ frame = tag->RemoveFrame(frame);
2054+ delete frame;
2055+ num_removed++;
2056+ }
2057+ while ((frame = tag->Find(ID3FID_BAND)) != NULL)
2058+ {
2059+ frame = tag->RemoveFrame(frame);
2060+ delete frame;
2061+ num_removed++;
2062+ }
2063+ while ((frame = tag->Find(ID3FID_CONDUCTOR)) != NULL)
2064+ {
2065+ frame = tag->RemoveFrame(frame);
2066+ delete frame;
2067+ num_removed++;
2068+ }
2069+ while ((frame = tag->Find(ID3FID_COMPOSER)) != NULL)
2070+ {
2071+ frame = tag->RemoveFrame(frame);
2072+ delete frame;
2073+ num_removed++;
2074+ }
2075+
2076+ return num_removed;
2077+ }
2078+
2079+ ID3_Frame* AddAlbum(ID3_Tag *tag, const wchar_t *text, bool replace)
2080+ {
2081+ ID3_Frame* frame = NULL;
2082+ if (NULL != tag && NULL != text && lstrlen(text) > 0)
2083+ {
2084+ if (replace)
2085+ {
2086+ RemoveAlbums(tag);
2087+ }
2088+ if (replace || tag->Find(ID3FID_ALBUM) == NULL)
2089+ {
2090+ frame = new ID3_Frame(ID3FID_ALBUM);
2091+ if (frame)
2092+ {
2093+ frame->GetField(ID3FN_TEXT)->SetEncoding(ID3TE_UNICODE);
2094+ frame->GetField(ID3FN_TEXT)->Set(SwapByteOrder(text));
2095+ frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_UNICODE);
2096+ tag->AttachFrame(frame);
2097+ }
2098+ }
2099+ }
2100+
2101+ return frame;
2102+ }
2103+
2104+ size_t RemoveAlbums(ID3_Tag *tag)
2105+ {
2106+ size_t num_removed = 0;
2107+ ID3_Frame *frame = NULL;
2108+
2109+ if (NULL == tag)
2110+ {
2111+ return num_removed;
2112+ }
2113+
2114+ while ((frame = tag->Find(ID3FID_ALBUM)) != NULL)
2115+ {
2116+ frame = tag->RemoveFrame(frame);
2117+ delete frame;
2118+ num_removed++;
2119+ }
2120+
2121+ return num_removed;
2122+ }
2123+
2124+ ID3_Frame* AddTitle(ID3_Tag *tag, const wchar_t *text, bool replace)
2125+ {
2126+ ID3_Frame* frame = NULL;
2127+ if (NULL != tag && NULL != text && lstrlen(text) > 0)
2128+ {
2129+ if (replace)
2130+ {
2131+ RemoveTitles(tag);
2132+ }
2133+ if (replace || tag->Find(ID3FID_TITLE) == NULL)
2134+ {
2135+ frame = new ID3_Frame(ID3FID_TITLE);
2136+ if (frame)
2137+ {
2138+ frame->GetField(ID3FN_TEXT)->SetEncoding(ID3TE_UNICODE);
2139+ frame->GetField(ID3FN_TEXT)->Set(SwapByteOrder(text));
2140+ frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_UNICODE);
2141+ tag->AttachFrame(frame);
2142+ }
2143+ }
2144+ }
2145+
2146+ return frame;
2147+ }
2148+
2149+ size_t RemoveTitles(ID3_Tag *tag)
2150+ {
2151+ size_t num_removed = 0;
2152+ ID3_Frame *frame = NULL;
2153+
2154+ if (NULL == tag)
2155+ {
2156+ return num_removed;
2157+ }
2158+
2159+ while ((frame = tag->Find(ID3FID_TITLE)) != NULL)
2160+ {
2161+ frame = tag->RemoveFrame(frame);
2162+ delete frame;
2163+ num_removed++;
2164+ }
2165+
2166+ return num_removed;
2167+ }
2168+
2169+ //following routine courtesy of John George
2170+ ID3_Frame* AddGenre(ID3_Tag* tag, const wchar_t *genre, bool replace)
2171+ {
2172+ ID3_Frame* frame = NULL;
2173+ if (NULL != tag && NULL != genre && lstrlen(genre) > 0)
2174+ {
2175+ if (replace)
2176+ {
2177+ RemoveGenres(tag);
2178+ }
2179+ if (replace || NULL == tag->Find(ID3FID_CONTENTTYPE))
2180+ {
2181+ frame = new ID3_Frame(ID3FID_CONTENTTYPE);
2182+ if (NULL != frame)
2183+ {
2184+ frame->GetField(ID3FN_TEXT)->SetEncoding(ID3TE_UNICODE);
2185+ frame->GetField(ID3FN_TEXT)->Set(SwapByteOrder(genre));
2186+ frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_UNICODE);
2187+ tag->AttachFrame(frame);
2188+ }
2189+ }
2190+ }
2191+
2192+ return frame;
2193+ }
2194+
2195+ size_t RemoveGenres(ID3_Tag *tag)
2196+ {
2197+ size_t num_removed = 0;
2198+ ID3_Frame *frame = NULL;
2199+
2200+ if (NULL == tag)
2201+ {
2202+ return num_removed;
2203+ }
2204+
2205+ while ((frame = tag->Find(ID3FID_CONTENTTYPE)) != NULL)
2206+ {
2207+ frame = tag->RemoveFrame(frame);
2208+ delete frame;
2209+ num_removed++;
2210+ }
2211+
2212+ return num_removed;
2213+ }
2214+
2215+ const unicode_t *SwapByteOrder(const wchar_t *text)
2216+ {
2217+ static unicode_t resBuf[65536];
2218+ const wchar_t *pText;
2219+ unicode_t *pBuf;
2220+
2221+ for(pText = text, pBuf = resBuf; *pText != L'\0'; pText ++, pBuf ++)
2222+ {
2223+ wchar_t srcVal = *pText;
2224+ //unicode_t dstVal = srcVal;
2225+ unicode_t dstVal = (srcVal << 8) | (srcVal >> 8);
2226+ *pBuf = dstVal;
2227+ }
2228+
2229+ *pBuf = L'\0';
2230+
2231+ return resBuf;
2232+ }
2233+#endif
2234+
2235+ protected:
2236+
2237+ static LRESULT WINAPI hookWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp);
2238+ static LRESULT WINAPI windowproc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp);
2239+ static std::pair<bool, LRESULT> WINAPI innerWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp);
2240+ static std::pair<bool, LRESULT> WINAPI outerWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp);
2241+
2242+ protected:
2243+
2244+ static DummyAmp *m_pMe;
2245+
2246+ bool m_bReady;
2247+
2248+ HINSTANCE m_hInstGenMixi;
2249+ winampGeneralPurposePlugin *m_pGenMixi;
2250+
2251+ HWND m_hWinampWnd;
2252+ bool m_isAnotherWinampWindowAvailable;
2253+
2254+ static LONG_PTR m_pfnOldAnotherWinampProc;
2255+
2256+ HANDLE m_hDirChangeNotify;
2257+
2258+ PlayInfo m_playInfo;
2259+ PlayInfo m_rawPlayInfo;
2260+
2261+ TrackInfo m_trackInfo;
2262+ int m_GETPLAYLISTFILE_time;
2263+
2264+ tstring m_playlistTitle;
2265+ string8 m_playlistTitle8;
2266+
2267+ tstring m_winampTitle;
2268+ tstring m_baseWinampTitle;
2269+
2270+ tstring m_dummyPlayInfoMp3Path;
2271+ bool m_isDummyPlayInfoMp3Available;
2272+};
2273+
2274+DummyAmp *DummyAmp::m_pMe = NULL;
2275+
2276+LONG_PTR DummyAmp::m_pfnOldAnotherWinampProc = NULL;
2277+
2278+LRESULT CALLBACK DummyAmp::hookWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp)
2279+{
2280+ if(InSendMessage() || (msg != WM_WA_IPC))
2281+ {
2282+ switch(msg)
2283+ {
2284+ case WM_CLOSE:
2285+ DEBUG_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_CLOSE %s"),
2286+ InSendMessage() == TRUE ? _T("from other thread") : _T(""));
2287+
2288+ DummyAmp::getInstance()->destroyWindow();
2289+ break;
2290+
2291+ case WM_GETTEXT:
2292+ {
2293+ // message from same thread
2294+ if((InSendMessage() == FALSE) && (DummyAmp::getInstance()->isAnotherWinampWindowAvailable() == true))
2295+ {
2296+ LPCTSTR pWinampTitle = DummyAmp::getInstance()->getWinampTitle().c_str();
2297+ int nLen = ::lstrlen(pWinampTitle);
2298+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_GETTEXT / window title [%s]."), pWinampTitle);
2299+
2300+ ::lstrcpyn(reinterpret_cast<LPTSTR>(lp), pWinampTitle, static_cast<int>(wp));
2301+
2302+ return (LRESULT)nLen;
2303+ }
2304+ }
2305+ break;
2306+
2307+ case WM_GETTEXTLENGTH:
2308+ {
2309+ // message from same thread
2310+ if((InSendMessage() == FALSE) && (DummyAmp::getInstance()->isAnotherWinampWindowAvailable() == true))
2311+ {
2312+ LPCTSTR pWinampTitle = DummyAmp::getInstance()->getWinampTitle().c_str();
2313+ int nLen = ::lstrlen(pWinampTitle);
2314+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_GETTEXTLENGTH / window title length %d."), nLen);
2315+
2316+ return (LRESULT)nLen;
2317+ }
2318+ }
2319+ break;
2320+
2321+ case WM_SETTEXT:
2322+ {
2323+ // message from same thread
2324+ if((InSendMessage() == FALSE) && (DummyAmp::getInstance()->isAnotherWinampWindowAvailable() == true))
2325+ {
2326+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_SETTEXT / window title [%s]."), reinterpret_cast<LPCTSTR>(lp));
2327+ }
2328+ }
2329+ break;
2330+
2331+ default:
2332+
2333+ if(InSendMessage())
2334+ {
2335+ if(msg == WM_WA_IPC) {
2336+ if(cfg_enable_ext_ipc_proc == 1)
2337+ {
2338+ std::pair<bool, LRESULT> res = outerWinampWindowProc(wnd, msg, wp, lp);
2339+ if(res.first == true) {
2340+ return res.second;
2341+ }
2342+ }
2343+
2344+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_WA_IPC from other thread / W:%08x, L:%08x"), wp, lp);
2345+
2346+ }
2347+ else
2348+ {
2349+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - ")
2350+ _T("message from other thread / MSG:%04x, W:%08x, L:%08x"), msg, wp, lp);
2351+ }
2352+ }
2353+
2354+ break;
2355+ }
2356+
2357+ return CallWindowProc(LONG_PTR_TO_WNDPROC(m_pfnOldAnotherWinampProc), wnd, msg, wp, lp);
2358+ }
2359+ else
2360+ {
2361+ return CallWindowProc(windowproc, wnd, msg, wp, lp);
2362+ }
2363+}
2364+
2365+LRESULT CALLBACK DummyAmp::windowproc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp)
2366+{
2367+ switch(msg)
2368+ {
2369+ case WM_CLOSE:
2370+ DEBUG_DUMMYAMP_PROC(_T("DummyAmp::windowproc - WM_CLOSE"));
2371+ DummyAmp::getInstance()->destroyWindow();
2372+ return 0;
2373+
2374+ case WM_WA_IPC:
2375+ // message from same thread
2376+ if(InSendMessage() == FALSE)
2377+ {
2378+ std::pair<bool, LRESULT> res = innerWinampWindowProc(wnd, msg, wp, lp);
2379+ if(res.first == true) {
2380+ return res.second;
2381+ }
2382+ }
2383+ // message from other thread
2384+ else
2385+ {
2386+ std::pair<bool, LRESULT> res = outerWinampWindowProc(wnd, msg, wp, lp);
2387+ if(res.first == true) {
2388+ return res.second;
2389+ }
2390+ }
2391+ break;
2392+ default:
2393+ if(InSendMessage()) {
2394+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::windowproc - Unknown MSG from other thread / MSG:%04x, W:%08x, L:%08x"), msg, wp, lp);
2395+ }
2396+ break;
2397+ }
2398+
2399+ return uDefWindowProc(wnd,msg,wp,lp);
2400+}
2401+
2402+std::pair<bool, LRESULT> WINAPI DummyAmp::innerWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp)
2403+{
2404+ switch(msg)
2405+ {
2406+ case WM_WA_IPC:
2407+ {
2408+ PlayInfo::EPlayStatus playStatus = DummyAmp::getInstance()->getPlayInfo().getPlayStatus();
2409+ int playPosition = DummyAmp::getInstance()->getPlayInfo().getPlayPosition();
2410+ int playLength = DummyAmp::getInstance()->getPlayInfo().getPlayLength();
2411+ int playCount = DummyAmp::getInstance()->getPlayInfo().getPlayCount();
2412+ int getPlayListFileTime = DummyAmp::getInstance()->getGetPlayListFileTime();
2413+ bool isPlayInfoMp3Available = DummyAmp::getInstance()->getPlayInfo().isPlayInfoMp3Available();
2414+ const string8 &playInfoMp3Path8 = DummyAmp::getInstance()->getPlayInfo().getPlayInfoMp3Path8();
2415+
2416+ switch(lp)
2417+ {
2418+ case IPC_ISPLAYING:
2419+ if(cfg_use_plugin == 1)
2420+ {
2421+ HANDLE hDirChangeNotify = DummyAmp::getInstance()->getDirChangeNotifyHandle();
2422+
2423+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_ISPLAYING / status [%d]"), playStatus);
2424+
2425+ if(playStatus != PlayInfo::PLAY_START)
2426+ {
2427+ if(DummyAmp::getInstance()->getPlayInfo().isResentMode()) {
2428+ DummyAmp::getInstance()->getPlayInfo().clearResentMode();
2429+ }
2430+
2431+ if(hDirChangeNotify != INVALID_HANDLE_VALUE)
2432+ {
2433+ LOG_WARN(_T("DummyAmp::innerWinampWindowProc - ディレクトリ変更通知イベントのハンドルが閉じられていません"));
2434+ LOG_WARN(_T("DummyAmp::innerWinampWindowProc - 安全のため、ここで閉じます"));
2435+ DummyAmp::getInstance()->closeDirChangeNotifyHandle();
2436+ }
2437+ }
2438+ else
2439+ {
2440+ if(hDirChangeNotify != INVALID_HANDLE_VALUE)
2441+ {
2442+ DWORD dwRes = ::WaitForMultipleObjects(1, &hDirChangeNotify, FALSE, 0);
2443+
2444+ if(dwRes == WAIT_OBJECT_0)
2445+ {
2446+ LOG_INFO(_T("mixi station successfully updated."));
2447+ DummyAmp::getInstance()->closeDirChangeNotifyHandle();
2448+ DummyAmp::getInstance()->getPlayInfo().setPlayStatusStop();
2449+ }
2450+ else if(playPosition >= getPlayListFileTime + RESENT_INTERVAL)
2451+ {
2452+ DummyAmp::getInstance()->closeDirChangeNotifyHandle();
2453+ LOG_WARN(_T("DummyAmp::innerWinampWindowProc - mixi station ディレクトリの変更通知イベントが待ち時間内に発生しませんでした"));
2454+#if !defined(DISABLE_KICK_GEN_MIXI_LOOP)
2455+ LOG_WARN(_T("DummyAmp::innerWinampWindowProc - gen_mixi_for_winamp に曲情報取得要求を再送させます"));
2456+ DummyAmp::getInstance()->getPlayInfo().setResentMode();
2457+ DummyAmp::getInstance()->updateDummyAmpTitle();
2458+#else
2459+ LOG_WARN(_T("DummyAmp::innerWinampWindowProc - 曲情報は破棄されました"));
2460+#endif
2461+ }
2462+ }
2463+ }
2464+ return std::make_pair(true, playStatus);
2465+ }
2466+ return std::make_pair(true, PlayInfo::PLAY_STOP);
2467+
2468+ case IPC_GETOUTPUTTIME:
2469+ if(cfg_use_plugin == 1)
2470+ {
2471+ if(playStatus == PlayInfo::PLAY_START)
2472+ {
2473+ if(wp == IPC_GETOUTPUTTIME_PositionMSec)
2474+ {
2475+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_GETOUTPUTTIME / position [%d sec.]"), playPosition / 1000);
2476+
2477+ return std::make_pair(true, playPosition);
2478+ }
2479+ else if(wp == IPC_GETOUTPUTTIME_TotalSec)
2480+ {
2481+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_GETOUTPUTTIME / length [%d sec.]"), playLength);
2482+ return std::make_pair(true, playLength);
2483+ }
2484+ }
2485+ }
2486+ return std::make_pair(true, -1);
2487+
2488+ case IPC_GETLISTPOS:
2489+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_GETLISTPOS / index [%d]"), playCount);
2490+ return std::make_pair(true, playCount);
2491+
2492+ case IPC_GETPLAYLISTFILE:
2493+ if(cfg_use_plugin == 1)
2494+ {
2495+ if(isPlayInfoMp3Available == true)
2496+ {
2497+ DEBUG_DUMMYAMP_PROC8(
2498+ "DummyAmp::innerWinampWindowProc - IPC_GETPLAYLISTFILE / #%d - path [%s]",
2499+ playCount, (LPCSTR)playInfoMp3Path8);
2500+
2501+ DummyAmp::getInstance()->setGetPlayListFileTime(playPosition);
2502+
2503+ tstring mixiAppDataPath = PathInfo::getMixiStationAppPath();
2504+
2505+ DummyAmp::getInstance()->setDirChangeNotifyHandle(
2506+ ::FindFirstChangeNotification(mixiAppDataPath.c_str(), FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE)
2507+ );
2508+
2509+ return std::make_pair(true, (LRESULT)(LPCSTR)playInfoMp3Path8);
2510+ }
2511+ else
2512+ {
2513+ if(cfg_disable_dummy_mp3 == 1)
2514+ {
2515+ DEBUG_DUMMYAMP_PROC(_T("DummyAm::innerWinampWindowProcp - IPC_GETPLAYLISTFILE / NULL (audio file codec type not supported.)"));
2516+ }
2517+ else
2518+ {
2519+ LOG_WARN(_T("DummyAmp::innerWinampWindowProc - IPC_GETPLAYLISTFILE / NULL (dummy mp3 file not enabled.)"));
2520+ }
2521+ }
2522+ }
2523+ return std::make_pair(true, NULL);
2524+
2525+ case IPC_INTERNAL_REFRESHLISTINFO: // 0x4000
2526+ {
2527+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_INTERNAL_REFRESHLISTINFO / refresh internal playlist informations."));
2528+
2529+ // make playlist info formats array
2530+ Strings plNumKeys;
2531+
2532+ plNumKeys.push_back(FORMAT_LISTINDEX);
2533+
2534+ // set current track informations
2535+ DummyAmp::getInstance()->getMutableTrackInfo().setPlaylistNumbers(plNumKeys);
2536+
2537+ // refresh dummyamp title
2538+ DummyAmp::getInstance()->refreshTitle();
2539+
2540+ return std::make_pair(true, 0);
2541+ }
2542+
2543+ case IPC_INTERNAL_REFRESHDYNINFO: // 0x4001
2544+ {
2545+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_INTERNAL_REFRESHDYNINFO / refresh internal dynamic informations."));
2546+
2547+ // make dynamic info formats array
2548+ Strings dynStrKeys;
2549+
2550+ dynStrKeys.push_back(FORMAT_ARTIST);
2551+ dynStrKeys.push_back(FORMAT_TRACKTITLE);
2552+ dynStrKeys.push_back(FORMAT_ALBUMTITLE);
2553+ dynStrKeys.push_back(FORMAT_GENRE);
2554+
2555+ // set current track informations
2556+ DummyAmp::getInstance()->getMutableTrackInfo().removeStrings(dynStrKeys);
2557+ DummyAmp::getInstance()->getMutableTrackInfo().setDynamicStrings(dynStrKeys);
2558+
2559+ // refresh dummyamp title
2560+ DummyAmp::getInstance()->refreshTitle();
2561+
2562+ // when explicitly tagged file only mode and artist or track name not found,
2563+ // then skip sending track informations
2564+ string8 title_utf8 = DummyAmp::getInstance()->getTrackInfo().getString(FORMAT_TRACKTITLE, true).c_str();
2565+ string8 artist_utf8 = DummyAmp::getInstance()->getTrackInfo().getString(FORMAT_ARTIST, true).c_str();
2566+ string8 album_utf8 = DummyAmp::getInstance()->getTrackInfo().getString(FORMAT_ALBUMTITLE).c_str();
2567+ string8 genre_utf8 = DummyAmp::getInstance()->getTrackInfo().getString(FORMAT_GENRE).c_str();
2568+
2569+ if( (cfg_explicitly_tagged_file_only == 1) && (!lstrcmpA(title_utf8, "?") || !lstrcmpA(artist_utf8, "?")) )
2570+ {
2571+ DEBUG_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - IPC_INTERNAL_REFRESHDYNINFO / SKIP this track. (artist or title not found)"));
2572+ }
2573+ else
2574+ {
2575+ if(!lstrcmpA(title_utf8, "?"))
2576+ {
2577+ DummyAmp::getInstance()->getMutableTrackInfo().removeString(FORMAT_TRACKTITLE);
2578+ DummyAmp::getInstance()->getMutableTrackInfo().putString(FORMAT_TRACKTITLE, (LPCSTR)cfg_no_title_name);
2579+ }
2580+
2581+ if(!lstrcmpA(artist_utf8, "?"))
2582+ {
2583+ DummyAmp::getInstance()->getMutableTrackInfo().removeString(FORMAT_ARTIST);
2584+ DummyAmp::getInstance()->getMutableTrackInfo().putString(FORMAT_ARTIST, (LPCSTR)cfg_no_artist_name);
2585+ }
2586+
2587+ if(!lstrcmpA(album_utf8, "?"))
2588+ {
2589+ DummyAmp::getInstance()->getMutableTrackInfo().removeString(FORMAT_ALBUMTITLE);
2590+ DummyAmp::getInstance()->getMutableTrackInfo().putString(FORMAT_ALBUMTITLE,(LPCSTR) cfg_no_album_name);
2591+ }
2592+
2593+ if(!lstrcmpA(genre_utf8, "?"))
2594+ {
2595+ DummyAmp::getInstance()->getMutableTrackInfo().removeString(FORMAT_GENRE);
2596+ DummyAmp::getInstance()->getMutableTrackInfo().putString(FORMAT_GENRE, (LPCSTR)cfg_no_genre_name);
2597+ }
2598+
2599+ // refresh dummyamp info
2600+ DummyAmp::getInstance()->refreshAmpInfo();
2601+ }
2602+
2603+ return std::make_pair(true, 0);
2604+ }
2605+
2606+ default:
2607+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::innerWinampWindowProc - WM_WA_IPC (Unknown IPC command) / W:%08x, L:%08x"), wp, lp);
2608+ break;
2609+ }
2610+
2611+ }
2612+ break;
2613+ }
2614+
2615+ return std::make_pair(false, 0);
2616+}
2617+
2618+std::pair<bool, LRESULT> WINAPI DummyAmp::outerWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp)
2619+{
2620+ switch(msg)
2621+ {
2622+ case WM_WA_IPC:
2623+ {
2624+ PlayInfo::EPlayStatus rawPlayStatus = DummyAmp::getInstance()->getRawPlayInfo().getPlayStatus();
2625+ int rawPlayPosition = DummyAmp::getInstance()->getRawPlayInfo().getPlayPosition();
2626+ int rawPlayLength = DummyAmp::getInstance()->getRawPlayInfo().getPlayLength();
2627+ int rawPlayCount = DummyAmp::getInstance()->getPlayInfo().getPlayCount();
2628+ const string8 &rawPlayInfoMp3Path8 = DummyAmp::getInstance()->getRawPlayInfo().getPlayInfoMp3Path8();
2629+ const tstring &playlistTitle = DummyAmp::getInstance()->getPlaylistTitle();
2630+ const string8 &playlistTitle8 = DummyAmp::getInstance()->getPlaylistTitle8();
2631+
2632+ switch(lp)
2633+ {
2634+ case IPC_ISPLAYING:
2635+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_ISPLAYING / status [%d]"), rawPlayStatus);
2636+ return std::make_pair(true, rawPlayStatus);
2637+
2638+ case IPC_GETOUTPUTTIME:
2639+
2640+ if(rawPlayStatus != PlayInfo::PLAY_START)
2641+ {
2642+ rawPlayPosition = -1;
2643+ rawPlayLength = -1;
2644+ }
2645+ else if(true)
2646+ {
2647+#if IS_FB2K_VER08
2648+ rawPlayPosition = static_cast<int>(play_control::get()->get_playback_time() * 1000.0);
2649+#else IS_FB2K_VER09
2650+ rawPlayPosition = static_cast<int>(static_api_ptr_t<playback_control>()->playback_get_position() * 1000.0);
2651+#endif
2652+ }
2653+
2654+ if(wp == IPC_GETOUTPUTTIME_PositionMSec)
2655+ {
2656+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_GETOUTPUTTIME / position [%.3f sec.]"), rawPlayPosition / 1000.0);
2657+ return std::make_pair(true, rawPlayPosition);
2658+ }
2659+ else if(wp == IPC_GETOUTPUTTIME_TotalSec)
2660+ {
2661+ TRACE_DUMMYAMP_PROC(_T("DummyAm::outerWinampWindowProcp - IPC_GETOUTPUTTIME / length [%d sec.]"), rawPlayLength);
2662+ return std::make_pair(true, rawPlayLength);
2663+ }
2664+
2665+ return std::make_pair(true, -1);
2666+
2667+ case IPC_GETLISTPOS:
2668+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_GETLISTPOS / index [%d]"), rawPlayCount);
2669+ return std::make_pair(true, rawPlayCount);
2670+
2671+ case IPC_GETPLAYLISTFILE:
2672+ TRACE_DUMMYAMP_PROC8(
2673+ "DummyAmp::outerWinampWindowProc - IPC_GETPLAYLISTFILE / path [%s]", (LPCSTR)rawPlayInfoMp3Path8);
2674+ return std::make_pair(true, (LRESULT)(LPCSTR)rawPlayInfoMp3Path8);
2675+
2676+ case IPC_GETPLAYLISTTITLE:
2677+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_GETPLAYLISTTITLE")
2678+ _T(" / title [%s]"), (LPCTSTR)playlistTitle.c_str());
2679+ return std::make_pair(true, (LRESULT)(LPCSTR)playlistTitle8);
2680+
2681+ case IPC_JUMPTOTIME:
2682+ if(rawPlayStatus == PlayInfo::PLAY_START)
2683+ {
2684+ double jumpPos = wp / 1000.0;
2685+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - IPC_JUMPTOTIME")
2686+ _T(" / jump to [%.3f sec.]"), jumpPos);
2687+
2688+ if(jumpPos > rawPlayLength)
2689+ {
2690+ // eof
2691+ return std::make_pair(true, 1);
2692+ }
2693+ else
2694+ {
2695+#if IS_FB2K_VER08
2696+ play_control::get()->playback_seek(jumpPos);
2697+#else IS_FB2K_VER09
2698+ static_api_ptr_t<playback_control>()->playback_seek(jumpPos);
2699+#endif
2700+ return std::make_pair(true, 0);
2701+ }
2702+
2703+ }
2704+ return std::make_pair(true, -1);
2705+
2706+ default:
2707+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::outerWinampWindowProc - WM_WA_IPC (Unknown IPC command) / W:%08x, L:%08x"), wp, lp);
2708+ break;
2709+ }
2710+ }
2711+ break;
2712+ }
2713+
2714+ return std::make_pair(false, 0);
2715+}
2716+
2717+#if defined(ENABLE_MSN)
2718+class MSNSender
2719+{
2720+ public:
2721+
2722+ static void SendTrackInfo(const TRACK_INFO_UTF8 &info)
2723+ {
2724+ string8 msg;
2725+ msg += "\\0Music\\01\\0{0} - {1} - {2} - {3}\\0";
2726+ msg += info.m_title;
2727+ msg += "\\0";
2728+ msg += info.m_artist;
2729+ msg += "\\0";
2730+ msg += info.m_album;
2731+ msg += "\\0";
2732+ msg += info.m_genre;
2733+ msg += "\\0";
2734+
2735+ console::info(msg);
2736+
2737+ string_wide_from_utf8 tmp(msg);
2738+ SendMessage(tmp);
2739+ }
2740+
2741+ static void SendMessage(LPCWSTR buf)
2742+ {
2743+ COPYDATASTRUCT copydata;
2744+ int nSendBufLen = (::lstrlenW(buf)*2)+2;
2745+
2746+ copydata.dwData = 0x0547;
2747+ copydata.lpData = (void*)buf;
2748+ copydata.cbData = nSendBufLen;
2749+
2750+ HWND hMsnUi = NULL;
2751+ hMsnUi = FindWindowEx(NULL, hMsnUi, _T("MsnMsgrUIManager"), _T("MSN Messenger式再生通知を受信する窓"));
2752+ if ( hMsnUi == NULL )
2753+ {
2754+ ERROR(_T("MSNSender::SendMessage - M2M not found."));
2755+ return ;
2756+ }
2757+
2758+ ::SendMessage(hMsnUi, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&copydata);
2759+ LOG_INFO(_T("MSNSender::SendMessage - send track informations to M2M."));
2760+ }
2761+};
2762+#endif
2763+
2764+#if IS_FB2K_VER08
2765+class play_callback_mixi : public play_callback
2766+#elif IS_FB2K_VER09
2767+class play_callback_mixi : public play_callback_static
2768+#endif
2769+{
2770+#if IS_FB2K_VER09
2771+ virtual unsigned get_flags() {
2772+ return flag_on_playback_all;
2773+ }
2774+#endif
2775+
2776+#if IS_FB2K_VER08
2777+ virtual void on_playback_starting()
2778+#elif IS_FB2K_VER09
2779+ virtual void on_playback_starting(play_control::t_track_command command, bool paused)
2780+#endif
2781+ {
2782+ TRACE_CALLBACK(_T("play_callback_mixi::on_playback_starting - called."));
2783+
2784+ // create my dummyamp window
2785+ DummyAmp::getInstance()->createWindow();
2786+ }
2787+
2788+#if IS_FB2K_VER08
2789+ virtual void on_playback_new_track(metadb_handle * track)
2790+#elif IS_FB2K_VER09
2791+ virtual void on_playback_new_track(metadb_handle_ptr track)
2792+#endif
2793+ {
2794+ TRACE_CALLBACK(_T("play_callback_mixi::on_playback_new_track - called."));
2795+
2796+ if(DummyAmp::getInstance()->isReady() == false)
2797+ {
2798+ LOG_ERROR(_T("play_callback_mixi::on_playback_new_track - mixi station への送信機能はエラーにより無効化されています"));
2799+ LOG_ERROR(_T("play_callback_mixi::on_playback_new_track - エラーの原因を取り除いた上で、foobar2000 を再起動してください"));
2800+ return;
2801+ }
2802+
2803+#if IS_FB2K_VER08
2804+ bool isTrackInLibrary = track->handle_is_permcached() == 1;
2805+#elif IS_FB2K_VER09
2806+ bool isTrackInLibrary = static_api_ptr_t<library_manager>()->is_item_in_library(track);
2807+#endif
2808+ if(cfg_media_library_registered_file_only == 1)
2809+ {
2810+ if(isTrackInLibrary)
2811+ {
2812+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_new_track - new track found on media library."));
2813+ }
2814+ else
2815+ {
2816+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_new_track - new track NOT IN media library."));
2817+ }
2818+ }
2819+
2820+ // get currently playbacked track informations
2821+ string8 winamp_title_utf8;
2822+ string8 playlist_title_utf8;
2823+
2824+ // make currently playbacked track information keys
2825+ Strings strKeys;
2826+
2827+ strKeys.push_back(FORMAT_FILEPATH);
2828+ strKeys.push_back(FORMAT_FILEPATHRAW);
2829+ strKeys.push_back(FORMAT_ARTIST);
2830+ strKeys.push_back(FORMAT_TRACKTITLE);
2831+ strKeys.push_back(FORMAT_ALBUMTITLE);
2832+ strKeys.push_back(FORMAT_GENRE);
2833+ strKeys.push_back(FORMAT_CODEC);
2834+
2835+ // set current track informations
2836+ TrackInfo &trackInfo(DummyAmp::getInstance()->getMutableTrackInfo());
2837+ trackInfo.clear();
2838+ trackInfo.setStrings(strKeys, track);
2839+
2840+ // set trackinfo to dummyAmp
2841+ //DummyAmp::getInstance()->setTrackInfo(trackInfo);
2842+
2843+ // set dynamic flag
2844+ setDynamic(trackInfo.getString(FORMAT_FILEPATHRAW));
2845+
2846+ if(isDynamic())
2847+ {
2848+ setFirstDynamicCallback(true);
2849+
2850+ // set song total length
2851+ m_song_total_sec = pfc_string_to_float(cfg_send_interval3) / pfc_string_to_float(cfg_send_interval2) * 100.0;
2852+ }
2853+ else
2854+ {
2855+#if defined(CONTROL_SEND_TIMING)
2856+ // reset send timing
2857+ resetSendTiming();
2858+#endif
2859+
2860+#if IS_FB2K_VER08
2861+ // get song total length
2862+ m_song_total_sec = track->handle_get_length();
2863+
2864+ // get formatted dummyamp title
2865+ track->handle_format_title(winamp_title_utf8, cfg_dummyamp_title_format, 0);
2866+
2867+ // get formatted playlist title
2868+ track->handle_format_title(playlist_title_utf8, cfg_dummyamp_playlist_format, 0);
2869+
2870+#elif IS_FB2K_VER09
2871+ // get song total length
2872+ m_song_total_sec = track->get_length();
2873+
2874+ service_ptr_t<titleformat_object> titleformat;
2875+
2876+ // get formatted dummyamp title
2877+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, cfg_dummyamp_title_format);
2878+ track->format_title(NULL, winamp_title_utf8, titleformat, 0);
2879+
2880+ // get formatted playlist title
2881+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, cfg_dummyamp_playlist_format);
2882+ track->format_title(NULL, playlist_title_utf8, titleformat, 0);
2883+
2884+#endif
2885+ string_os_from_utf8 winamp_title(winamp_title_utf8);
2886+ string_os_from_utf8 playlist_title(playlist_title_utf8);
2887+
2888+ // set base winamp title to dummyamp
2889+ DummyAmp::getInstance()->setBaseWinampTitle(winamp_title);
2890+
2891+ // set winamp playlist current item title to dummyamp
2892+ DummyAmp::getInstance()->setPlaylistTitle(playlist_title);
2893+
2894+ // clear raw playinfo on dummyamp (no resent mode)
2895+ DummyAmp::getInstance()->getRawPlayInfo().clearPlayInfo(false);
2896+
2897+ // set playinfo raw mp3 file path to dummyAmp
2898+ DummyAmp::getInstance()->getRawPlayInfo().setPlayInfoMp3Path(trackInfo.getString(FORMAT_FILEPATH).c_str());
2899+
2900+ // set dummyamp raw status PLAY_START
2901+ DummyAmp::getInstance()->getRawPlayInfo().setPlayStatusStart();
2902+
2903+ // set raw song total length
2904+ DummyAmp::getInstance()->getRawPlayInfo().setPlayLength(static_cast<int>(m_song_total_sec));
2905+
2906+ // increment play counter
2907+ DummyAmp::getInstance()->getRawPlayInfo().incrementPlayCount();
2908+
2909+ // clear playinfo on dummyamp
2910+ DummyAmp::getInstance()->getPlayInfo().clearPlayInfo();
2911+
2912+ // set song total length
2913+ DummyAmp::getInstance()->getPlayInfo().setPlayLength(static_cast<int>(m_song_total_sec));
2914+
2915+ // increment play counter on dummyamp
2916+ DummyAmp::getInstance()->getPlayInfo().incrementPlayCount();
2917+ }
2918+
2919+ if(isDynamic())
2920+ {
2921+ // post IPC_INTERNAL_REFRESHLISTINFO
2922+ ::PostMessage(DummyAmp::getInstance()->getWnd(), WM_WA_IPC, 0, IPC_INTERNAL_REFRESHLISTINFO);
2923+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_new_track - IPC_INTERNAL_REFRESHLISTINFO posted."));
2924+ }
2925+ else
2926+ {
2927+ bool bSkip = false;
2928+
2929+ string8 title_utf8 = trackInfo.getString(FORMAT_TRACKTITLE).c_str();
2930+ string8 artist_utf8 = trackInfo.getString(FORMAT_ARTIST).c_str();
2931+ string8 album_utf8 = trackInfo.getString(FORMAT_ALBUMTITLE).c_str();
2932+ string8 genre_utf8 = trackInfo.getString(FORMAT_GENRE).c_str();
2933+
2934+ // when media library only mode and track not found on media library,
2935+ // then skip sending track informations
2936+ if((cfg_media_library_registered_file_only == 1) && (isTrackInLibrary == false))
2937+ {
2938+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_new_track - SKIP this track. (not in media library)"));
2939+ bSkip = true;
2940+ }
2941+
2942+ // when explicitly tagged file only mode and artist or track name not found,
2943+ // then skip sending track informations
2944+ if( (cfg_explicitly_tagged_file_only == 1) && (!lstrcmpA(title_utf8, "?") || !lstrcmpA(artist_utf8, "?")) )
2945+ {
2946+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_new_track - SKIP this track. (artist or title not found)"));
2947+ bSkip = true;
2948+ }
2949+
2950+ if(!lstrcmpA(title_utf8, "?"))
2951+ {
2952+ trackInfo.removeString(FORMAT_TRACKTITLE);
2953+ trackInfo.putString(FORMAT_TRACKTITLE, (LPCSTR)cfg_no_title_name);
2954+ }
2955+
2956+ if(!lstrcmpA(artist_utf8, "?"))
2957+ {
2958+ trackInfo.removeString(FORMAT_ARTIST);
2959+ trackInfo.putString(FORMAT_ARTIST, (LPCSTR)cfg_no_artist_name);
2960+ }
2961+
2962+ if(!lstrcmpA(album_utf8, "?"))
2963+ {
2964+ trackInfo.removeString(FORMAT_ALBUMTITLE);
2965+ trackInfo.putString(FORMAT_ALBUMTITLE, (LPCSTR)cfg_no_album_name);
2966+ }
2967+
2968+ if(!lstrcmpA(genre_utf8, "?"))
2969+ {
2970+ trackInfo.removeString(FORMAT_GENRE);
2971+ trackInfo.putString(FORMAT_GENRE, (LPCSTR)cfg_no_genre_name);
2972+ }
2973+
2974+ // refresh dummy amp informations when skip flag not set
2975+ if(!bSkip) {
2976+ DummyAmp::getInstance()->refreshAmpInfo();
2977+
2978+ // post IPC_INTERNAL_REFRESHLISTINFO
2979+ ::PostMessage(DummyAmp::getInstance()->getWnd(), WM_WA_IPC, 0, IPC_INTERNAL_REFRESHLISTINFO);
2980+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_new_track - IPC_INTERNAL_REFRESHLISTINFO posted."));
2981+ }
2982+ }
2983+ }
2984+
2985+#if IS_FB2K_VER08
2986+ virtual void on_playback_stop(play_control::stop_reason reason)
2987+#elif IS_FB2K_VER09
2988+ virtual void on_playback_stop(play_control::t_stop_reason reason)
2989+#endif
2990+ {
2991+ TRACE_CALLBACK(_T("play_callback_mixi::on_playback_stop - called."));
2992+
2993+ // set dummyamp status PLAY_STOP
2994+ DummyAmp::getInstance()->getPlayInfo().setPlayStatusStop();
2995+
2996+ // set dummyamp raw status PLAY_STOP
2997+ DummyAmp::getInstance()->getRawPlayInfo().setPlayStatusStop();
2998+
2999+ // clear dummyamp title
3000+ DummyAmp::getInstance()->clearDummyAmpTitle();
3001+ }
3002+
3003+ virtual void on_playback_seek(double time) // time is second.
3004+ {
3005+ TRACE_CALLBACK(_T("play_callback_mixi::on_playback_seek - called."));
3006+
3007+#if !defined(CONTROL_SEND_TIMING)
3008+ // update current position on dummyamp
3009+ DummyAmp::getInstance()->getPlayInfo().setPlayPosition((int)(time * 1000));
3010+#else
3011+ // update raw current position on dummyamp
3012+ DummyAmp::getInstance()->getRawPlayInfo().setPlayPosition((int)(time * 1000));
3013+
3014+ // reset send timing
3015+ resetSendTiming();
3016+#endif
3017+ }
3018+
3019+#if IS_FB2K_VER08
3020+ virtual void on_playback_pause(int state)
3021+#elif IS_FB2K_VER09
3022+ virtual void on_playback_pause(bool state)
3023+#endif
3024+ {
3025+ TRACE_CALLBACK(_T("play_callback_mixi::on_playback_pause - called."));
3026+
3027+#if IS_FB2K_VER08
3028+ if(state == 1)
3029+#elif IS_FB2K_VER09
3030+ if(state == true)
3031+#endif
3032+ {
3033+ // set dummyamp status PLAY_PAUSE
3034+ DummyAmp::getInstance()->getPlayInfo().setPlayStatusPause();
3035+
3036+ // set dummyamp raw status PLAY_PAUSE
3037+ DummyAmp::getInstance()->getRawPlayInfo().setPlayStatusPause();
3038+
3039+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_pause - fb2k paused."));
3040+ }
3041+ else
3042+ {
3043+#if !defined(CONTROL_SEND_TIMING)
3044+ // set dummyamp status PLAY_START
3045+ DummyAmp::getInstance()->getPlayInfo().setPlayStatusStart();
3046+#else
3047+ // set dummyamp status PLAY_STOP
3048+ DummyAmp::getInstance()->getPlayInfo().setPlayStatusStop();
3049+#endif
3050+
3051+ // set dummyamp rawa status PLAY_START
3052+ DummyAmp::getInstance()->getRawPlayInfo().setPlayStatusStart();
3053+
3054+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_pause - fb2k unpaused."));
3055+ }
3056+ }
3057+
3058+#if IS_FB2K_VER08
3059+ virtual void on_playback_edited(metadb_handle * track){}//currently played file got edited
3060+#elif IS_FB2K_VER09
3061+ virtual void on_playback_edited(metadb_handle_ptr track){}//currently played file got edited
3062+#endif
3063+
3064+#if IS_FB2K_VER08
3065+ virtual void on_playback_dynamic_info(const file_info * info,bool b_track_change)
3066+#elif IS_FB2K_VER09
3067+ virtual void on_playback_dynamic_info(const file_info & info)
3068+#endif
3069+ {
3070+#if IS_FB2K_VER08
3071+ TRACE_CALLBACK(_T("play_callback_mixi::on_playback_dynamic_info - called."));
3072+
3073+ if(isDynamic() && b_track_change)
3074+ {
3075+ refreshDynamicInfo();
3076+ }
3077+#endif
3078+ }
3079+
3080+#if IS_FB2K_VER09
3081+ virtual void on_playback_dynamic_info_track(const file_info & p_info) {
3082+
3083+ TRACE_CALLBACK(_T("play_callback_mixi::on_playback_dynamic_info_track - called."));
3084+
3085+ if(isDynamic())
3086+ {
3087+ refreshDynamicInfo();
3088+ }
3089+ };
3090+#endif
3091+
3092+#if IS_FB2K_VER08
3093+ virtual void on_playback_time(metadb_handle * track, double time)//called every second
3094+#elif IS_FB2K_VER09
3095+ virtual void on_playback_time(double time)//called every second
3096+#endif
3097+ {
3098+ TRACE_CALLBACK(_T("play_callback_mixi::on_playback_time - called."));
3099+
3100+ // update current raw position on dummyamp
3101+ DummyAmp::getInstance()->getRawPlayInfo().setPlayPosition((int)(time * 1000));
3102+
3103+ if(DummyAmp::getInstance()->getPlayInfo().isPlayInfoMp3Available() == true)
3104+ {
3105+#if !defined(CONTROL_SEND_TIMING)
3106+ // update current position on dummyamp
3107+ DummyAmp::getInstance()->getPlayInfo().setPlayPosition((int)(time * 1000));
3108+#else
3109+#if !defined(ENABLE_MSN)
3110+ if(m_bPassThesholdTime == true) {
3111+ // update current position on dummyamp
3112+ DummyAmp::getInstance()->getPlayInfo().setPlayPosition((int)(time * 1000));
3113+ }
3114+#endif
3115+ if(checkSendTiming(time) == true)
3116+ {
3117+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_time - send track informations ..."));
3118+
3119+#if !defined(ENABLE_MSN)
3120+ //dummyamp resent mode
3121+ DummyAmp::getInstance()->getPlayInfo().setPlayPosition((int)(time * 1000));
3122+ DummyAmp::getInstance()->getPlayInfo().setResentMode(false);
3123+
3124+// // update dummyamp title
3125+// DummyAmp::getInstance()->updateDummyAmpTitle();
3126+
3127+ // set dummyamp status PLAY_START
3128+ DummyAmp::getInstance()->getPlayInfo().setPlayStatusStart();
3129+#else
3130+ // send track informations to M2M
3131+ MSNSender::SendTrackInfo(m_trackInfoUtf8);
3132+#endif
3133+ }
3134+#endif
3135+ }
3136+ }
3137+
3138+protected:
3139+
3140+#if defined(CONTROL_SEND_TIMING)
3141+ void resetSendTiming()
3142+ {
3143+ TRACE_CALLBACK(_T("play_callback_mixi::resetSendTiming - called."));
3144+
3145+ m_previous_sec = -1.0;
3146+ m_bPassLowerBoundTime = false;
3147+ m_bPassThesholdTime = false;
3148+ }
3149+
3150+ bool checkSendTiming(double sec)
3151+ {
3152+ TRACE_CALLBACK(_T("play_callback_mixi::checkSendTiming - called."));
3153+
3154+ if(m_bPassThesholdTime == true) return false;
3155+
3156+ if(m_previous_sec < 0.0) {
3157+ m_previous_sec = sec - 1.0;
3158+ }
3159+
3160+ double elapsedTime = sec - m_previous_sec;
3161+
3162+ double lowerBoundTime = pfc_string_to_float(cfg_send_interval1);
3163+ double thresholdTime1 = m_song_total_sec * pfc_string_to_float(cfg_send_interval2) / 100.0;
3164+ double thresholdTime2 = pfc_string_to_float(cfg_send_interval3);
3165+ double thresholdTime = min(thresholdTime1, thresholdTime2);
3166+
3167+#if 0
3168+ if(lowerBoundTime < 10.0) lowerBoundTime = 10.0;
3169+
3170+ if(thresholdTime < 10.0) thresholdTime = 10.0;
3171+#endif
3172+ if(thresholdTime < lowerBoundTime) thresholdTime = lowerBoundTime;
3173+
3174+ if(m_bPassLowerBoundTime == false)
3175+ {
3176+ TRACE_CALLBACK(_T("play_callback_mixi::checkSendTiming - pos: %5.1f, lowerBound:%5.1f, elapse:%5.1f"),
3177+ sec, lowerBoundTime, elapsedTime);
3178+
3179+ if(lowerBoundTime <= elapsedTime + 3) // add gen_mixi response time
3180+ {
3181+ m_bPassLowerBoundTime = true;
3182+ }
3183+ }
3184+
3185+ if((m_bPassLowerBoundTime == true) && (m_bPassThesholdTime == false))
3186+ {
3187+ TRACE_CALLBACK(_T("play_callback_mixi::checkSendTiming - pos: %5.1f, threshold:%5.1f, elapse:%5.1f"),
3188+ sec, thresholdTime, elapsedTime);
3189+
3190+ if(thresholdTime <= elapsedTime + 3) // add gen_mixi response time
3191+ {
3192+ m_bPassThesholdTime = true;
3193+ return true;
3194+ }
3195+ }
3196+
3197+ return false;
3198+ }
3199+#endif
3200+
3201+ void refreshDynamicInfo()
3202+ {
3203+ if(cfg_enable_streaming_file == 0)
3204+ {
3205+ DEBUG_CALLBACK(_T("play_callback_mixi::refreshDynamicInfo - SKIP this track. (ストリーミング情報の送信が許可されていません)"));
3206+ setFirstDynamicCallback(false);
3207+ return ;
3208+ }
3209+
3210+ if(cfg_disable_dummy_mp3 == 1)
3211+ {
3212+ DEBUG_CALLBACK(_T("play_callback_mixi::refreshDynamicInfo - SKIP this track. (ストリーミング情報を送信するには、ダミーMP3ファイルが有効にしてください)"));
3213+ setFirstDynamicCallback(false);
3214+ return ;
3215+ }
3216+
3217+#if defined(CONTROL_SEND_TIMING)
3218+ // reset send timing
3219+ resetSendTiming();
3220+#endif
3221+
3222+ // clear raw playinfo on dummyamp (no resent mode)
3223+ DummyAmp::getInstance()->getRawPlayInfo().clearPlayInfo(false);
3224+
3225+ // set playinfo raw mp3 file path to dummyAmp
3226+ DummyAmp::getInstance()->getRawPlayInfo().setPlayInfoMp3Path(DummyAmp::getInstance()->getTrackInfo().getString(FORMAT_FILEPATH).c_str());
3227+
3228+ // set dummyamp raw status PLAY_START
3229+ DummyAmp::getInstance()->getRawPlayInfo().setPlayStatusStart();
3230+
3231+ // set raw song total length
3232+ DummyAmp::getInstance()->getRawPlayInfo().setPlayLength(static_cast<int>(m_song_total_sec));
3233+
3234+ // increment play counter
3235+ DummyAmp::getInstance()->getRawPlayInfo().incrementPlayCount();
3236+
3237+ // clear playinfo on dummyamp
3238+ DummyAmp::getInstance()->getPlayInfo().clearPlayInfo();
3239+
3240+ // set song total length
3241+ DummyAmp::getInstance()->getPlayInfo().setPlayLength(static_cast<int>(m_song_total_sec));
3242+
3243+ // increment play counter on dummyamp
3244+ DummyAmp::getInstance()->getPlayInfo().incrementPlayCount();
3245+
3246+ DEBUG_CALLBACK(_T("play_callback_mixi::on_playback_dynamic_info_track - IPC_INTERNAL_REFRESHDYNINFO posted."));
3247+ ::PostMessage(DummyAmp::getInstance()->getWnd(), WM_WA_IPC, 0, IPC_INTERNAL_REFRESHDYNINFO);
3248+ setFirstDynamicCallback(false);
3249+ }
3250+
3251+#if IS_FB2K_VER09
3252+ // User changed volume settings. Possibly called when not playing.
3253+ virtual void on_volume_change(float new_val) {}
3254+#endif
3255+
3256+ void setFirstDynamicCallback(bool isFirst) {
3257+ m_isFirstDynamicCallback = isFirst;
3258+ }
3259+
3260+ bool isFirstDynamicCallback() const {
3261+ return m_isFirstDynamicCallback;
3262+ }
3263+
3264+ void setDynamic(const std::string &rawFilePath)
3265+ {
3266+ bool isFileProtocol = rawFilePath.find("file://") != std::string::npos;
3267+ bool isCddaProtocol = rawFilePath.find("cdda://") != std::string::npos;
3268+ bool isDriveName = false;
3269+
3270+ if(rawFilePath.length() >= 3) {
3271+ LPCSTR pRawFilePath = rawFilePath.c_str();
3272+ isDriveName = ::isalpha(pRawFilePath[0]) && (pRawFilePath[1] == ':') && (pRawFilePath[2] == '\\');
3273+ }
3274+
3275+ m_isDynamic = !(isFileProtocol || isCddaProtocol || isDriveName);
3276+ }
3277+
3278+ bool isDynamic() const {
3279+ return m_isDynamic;
3280+ }
3281+
3282+protected:
3283+
3284+// TrackInfo m_trackInfo;
3285+
3286+ double m_previous_sec;
3287+ double m_song_total_sec;
3288+
3289+ bool m_bPassLowerBoundTime;
3290+ bool m_bPassThesholdTime;
3291+
3292+ bool m_isDynamic;
3293+ bool m_isFirstDynamicCallback;
3294+};
3295+
3296+
3297+class initquit_mixi : public initquit
3298+{
3299+ typedef std::auto_ptr<DummyAmp> DummyAmpAutoPtr;
3300+ DummyAmpAutoPtr m_apDummyAmp;
3301+
3302+ virtual void on_init()
3303+ {
3304+ m_apDummyAmp = DummyAmpAutoPtr(DummyAmp::getInstance());
3305+ m_apDummyAmp->load();
3306+ }
3307+
3308+ virtual void on_quit()
3309+ {
3310+ m_apDummyAmp->release();
3311+ {
3312+ DummyAmpAutoPtr sink(m_apDummyAmp);
3313+ }
3314+ }
3315+
3316+ virtual void on_system_shutdown()
3317+ {
3318+ on_quit();
3319+ }
3320+};
3321+
3322+#if IS_FB2K_VER08
3323+class menu_item_mixi : public menu_item_main
3324+#elif IS_FB2K_VER09
3325+// {E8BF1F91-9262-4c0b-AD39-00C0B24B4210}
3326+static const GUID menu_item_mixi_guid = { 0xe8bf1f91, 0x9262, 0x4c0b, { 0xad, 0x39, 0x0, 0xc0, 0xb2, 0x4b, 0x42, 0x10 } };
3327+class menu_item_mixi : public mainmenu_commands
3328+#endif
3329+{
3330+#if IS_FB2K_VER08
3331+ virtual unsigned get_num_items() {
3332+#elif IS_FB2K_VER09
3333+ virtual t_uint32 get_command_count() {
3334+#endif
3335+ return 1;
3336+ }
3337+
3338+#if IS_FB2K_VER08
3339+ virtual void enum_item(unsigned n, string_base & out) {
3340+ out = (n==0 ? g_menu_item : "");
3341+ }
3342+#elif IS_FB2K_VER09
3343+ virtual GUID get_command(t_uint32 p_index)
3344+ {
3345+ if (p_index == 0) {
3346+ return menu_item_mixi_guid;
3347+ }
3348+
3349+ return pfc::guid_null;
3350+ }
3351+
3352+ virtual void get_name(t_uint32 p_index, string_base & p_out)
3353+ {
3354+ if (p_index == 0)
3355+ {
3356+ p_out = g_menu_item_title;
3357+ }
3358+ }
3359+
3360+ virtual bool get_description(t_uint32 p_index, string_base & p_out)
3361+ {
3362+ if (p_index == 0)
3363+ {
3364+ p_out = g_menu_item_description;
3365+ }
3366+ else
3367+ {
3368+ return false;
3369+ }
3370+
3371+ return true;
3372+ }
3373+
3374+ virtual GUID get_parent() {
3375+ return mainmenu_groups::playback_etc;
3376+ }
3377+
3378+#endif
3379+
3380+#if IS_FB2K_VER08
3381+ virtual bool is_checked(int index)
3382+ {
3383+ bool flags = false;
3384+ static const bool flag_checked = TRUE;
3385+#elif IS_FB2K_VER09
3386+ virtual bool get_display(t_uint32 index, pfc::string_base & text, t_uint32 & flags)
3387+ {
3388+ flags = 0;
3389+#endif
3390+ switch (index)
3391+ {
3392+ case 0:
3393+ if (cfg_use_plugin == 1) flags = flag_checked;
3394+ break;
3395+ }
3396+
3397+#if IS_FB2K_VER08
3398+ return flags;
3399+#elif IS_FB2K_VER09
3400+ get_name(index, text);
3401+ return true;
3402+#endif
3403+ }
3404+
3405+#if IS_FB2K_VER08
3406+ virtual void perform_command(unsigned index)
3407+ {
3408+#elif IS_FB2K_VER09
3409+ virtual void execute(t_uint32 index, service_ptr_t<service_base> /* reserved for future use */)
3410+ {
3411+#endif
3412+ if ((index == 0) && core_api::assert_main_thread())
3413+ {
3414+ cfg_use_plugin = 1 - cfg_use_plugin;
3415+
3416+ if(cfg_use_plugin > 1)
3417+ {
3418+ cfg_use_plugin = 1;
3419+ }
3420+ else if(cfg_use_plugin < 0)
3421+ {
3422+ cfg_use_plugin = 0;
3423+ }
3424+
3425+ if (cfg_use_plugin == 1)
3426+ {
3427+ DEBUG_PLUGIN(_T("menu_item_mixi::execute - mixiミュージック連携を有効にしました"));
3428+ }
3429+ else
3430+ {
3431+ DEBUG_PLUGIN(_T("menu_item_mixi::execute - mixiミュージック連携を無効にしました"));
3432+ }
3433+ }
3434+ }
3435+};
3436+
3437+#define CLEARTYPE_QUALITY 5
3438+
3439+#if IS_FB2K_VER08
3440+class config_page_mixi : public config
3441+#elif IS_FB2K_VER09
3442+// {976D6C46-31E4-4ab4-8BFF-5FB2E9BFD599}
3443+static const GUID config_page_mixi_guid = { 0x976d6c46, 0x31e4, 0x4ab4, { 0x8b, 0xff, 0x5f, 0xb2, 0xe9, 0xbf, 0xd5, 0x99 } };
3444+class config_page_mixi : public preferences_page
3445+#endif
3446+{
3447+ static HFONT hIntervalFont;
3448+
3449+ static BOOL CALLBACK ConfigProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
3450+ {
3451+ HWND hSendInterval1 = uGetDlgItem(wnd, IDC_SEND_INTERVAL_SLIDER_1ST);
3452+ HWND hSendInterval2 = uGetDlgItem(wnd, IDC_SEND_INTERVAL_SLIDER_2ND);
3453+ HWND hSendInterval3 = uGetDlgItem(wnd, IDC_SEND_INTERVAL_SLIDER_3RD);
3454+
3455+ HWND hSendInterval1Text = uGetDlgItem(wnd, IDC_SEND_INTERVAL_1ST);
3456+ HWND hSendInterval2Text = uGetDlgItem(wnd, IDC_SEND_INTERVAL_2ND);
3457+ HWND hSendInterval3Text = uGetDlgItem(wnd, IDC_SEND_INTERVAL_3RD);
3458+
3459+ switch(msg)
3460+ {
3461+ case WM_INITDIALOG:
3462+ {
3463+ HDC hWndDC = ::GetWindowDC(wnd);
3464+ hIntervalFont = ::CreateFont(
3465+ -MulDiv(20, GetDeviceCaps(hWndDC, LOGPIXELSY), 72), 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
3466+ ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, FIXED_PITCH, _T("Arial")
3467+ );
3468+ ::ReleaseDC(wnd, hWndDC);
3469+
3470+ uSendMessage(hSendInterval1Text, WM_SETFONT, (WPARAM)hIntervalFont, (LPARAM)FALSE);
3471+ uSendMessage(hSendInterval2Text, WM_SETFONT, (WPARAM)hIntervalFont, (LPARAM)FALSE);
3472+ uSendMessage(hSendInterval3Text, WM_SETFONT, (WPARAM)hIntervalFont, (LPARAM)FALSE);
3473+
3474+ uButton_SetCheck(wnd, IDC_USE_PLUGIN, (cfg_use_plugin == 1) ? true : false);
3475+
3476+ uButton_SetCheck(wnd, IDC_DISABLE_DUPLICATE_SONG, (cfg_disable_duplicate_song == 1) ? true : false);
3477+ uButton_SetCheck(wnd, IDC_DISABLE_DUMMY_MP3, (cfg_disable_dummy_mp3 == 1) ? true : false);
3478+ uButton_SetCheck(wnd, IDC_MEDIA_LIBRARY_REGISTERED_FILE_ONLY, (cfg_media_library_registered_file_only == 1) ? true : false);
3479+ uButton_SetCheck(wnd, IDC_EXPLICITLY_TAGGED_FILE_ONLY, (cfg_explicitly_tagged_file_only == 1) ? true : false);
3480+
3481+ uSetDlgItemText(wnd, IDC_NO_ARTIST_NAME, cfg_no_artist_name);
3482+ uSetDlgItemText(wnd, IDC_NO_TITLE_NAME, cfg_no_title_name);
3483+ uSetDlgItemText(wnd, IDC_NO_ALBUM_NAME, cfg_no_album_name);
3484+ uSetDlgItemText(wnd, IDC_NO_GENRE_NAME, cfg_no_genre_name);
3485+
3486+ EnableNoNames(wnd, (cfg_explicitly_tagged_file_only == 0) ? true : false);
3487+
3488+ uButton_SetCheck(wnd, IDC_ENABLE_STREAMING_FILE, (cfg_enable_streaming_file == 1) ? true : false);
3489+
3490+ uSetDlgItemText(wnd, IDC_SEND_INTERVAL_1ST, cfg_send_interval1);
3491+ uSetDlgItemText(wnd, IDC_SEND_INTERVAL_2ND, cfg_send_interval2);
3492+ uSetDlgItemText(wnd, IDC_SEND_INTERVAL_3RD, cfg_send_interval3);
3493+
3494+ uSendMessage(hSendInterval1, TBM_SETRANGE, (WPARAM)FALSE, (LPARAM)MAKELONG(REQUIRED_MINIMUM_TIME, 300));
3495+ uSendMessage(hSendInterval1, TBM_SETLINESIZE, (WPARAM)0, (LPARAM)1);
3496+ uSendMessage(hSendInterval1, TBM_SETPAGESIZE, (WPARAM)0, (LPARAM)20);
3497+ uSendMessage(hSendInterval1, TBM_SETTICFREQ, (WPARAM)20, (LPARAM)0);
3498+
3499+ double pos1 = pfc_string_to_float(cfg_send_interval1);
3500+ uSendMessage(hSendInterval1, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos1);
3501+
3502+ uSendMessage(hSendInterval2, TBM_SETRANGE, (WPARAM)FALSE, (LPARAM)MAKELONG(SEND_TIME_RATE_LOWERBOUND, 100));
3503+ uSendMessage(hSendInterval2, TBM_SETLINESIZE, (WPARAM)0, (LPARAM)1);
3504+ uSendMessage(hSendInterval2, TBM_SETPAGESIZE, (WPARAM)0, (LPARAM)5);
3505+ uSendMessage(hSendInterval2, TBM_SETTICFREQ, (WPARAM)5, (LPARAM)0);
3506+
3507+ double pos2 = pfc_string_to_float(cfg_send_interval2);
3508+ uSendMessage(hSendInterval2, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos2);
3509+
3510+ uSendMessage(hSendInterval3, TBM_SETRANGE, (WPARAM)FALSE, (LPARAM)MAKELONG(REQUIRED_MAXIMUM_TIME, 9999));
3511+ uSendMessage(hSendInterval3, TBM_SETLINESIZE, (WPARAM)0, (LPARAM)10);
3512+ uSendMessage(hSendInterval3, TBM_SETPAGESIZE, (WPARAM)0, (LPARAM)100);
3513+ uSendMessage(hSendInterval3, TBM_SETTICFREQ, (WPARAM)1000, (LPARAM)0);
3514+
3515+ double pos3 = pfc_string_to_float(cfg_send_interval3);
3516+ uSendMessage(hSendInterval3, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos3);
3517+
3518+ setDlgVersionInfo(wnd, IDC_VERSION, IDC_BUILD);
3519+ }
3520+ break;
3521+
3522+ case WM_COMMAND:
3523+ switch(wp)
3524+ {
3525+ case (BN_CLICKED<<16)|IDC_USE_PLUGIN:
3526+ cfg_use_plugin = uButton_GetCheck(wnd, IDC_USE_PLUGIN) ? 1 : 0;
3527+ break;
3528+
3529+ case (EN_UPDATE<<16)|IDC_NO_ARTIST_NAME:
3530+ {
3531+ string8 name;
3532+ uGetWindowText(reinterpret_cast<HWND>(lp), name);
3533+ cfg_no_artist_name = name;
3534+ }
3535+ break;
3536+
3537+ case (EN_UPDATE<<16)|IDC_NO_TITLE_NAME:
3538+ {
3539+ string8 name;
3540+ uGetWindowText(reinterpret_cast<HWND>(lp), name);
3541+ cfg_no_title_name = name;
3542+ }
3543+ break;
3544+
3545+ case (EN_UPDATE<<16)|IDC_NO_ALBUM_NAME:
3546+ {
3547+ string8 name;
3548+ uGetWindowText(reinterpret_cast<HWND>(lp), name);
3549+ cfg_no_album_name = name;
3550+ }
3551+ break;
3552+
3553+ case (EN_UPDATE<<16)|IDC_NO_GENRE_NAME:
3554+ {
3555+ string8 name;
3556+ uGetWindowText(reinterpret_cast<HWND>(lp), name);
3557+ cfg_no_genre_name = name;
3558+ }
3559+ break;
3560+
3561+ case (BN_CLICKED<<16)|IDC_DISABLE_DUPLICATE_SONG:
3562+ cfg_disable_duplicate_song = uButton_GetCheck(wnd, IDC_DISABLE_DUPLICATE_SONG) ? 1 : 0;
3563+ break;
3564+
3565+ case (BN_CLICKED<<16)|IDC_DISABLE_DUMMY_MP3:
3566+ cfg_disable_dummy_mp3 = uButton_GetCheck(wnd, IDC_DISABLE_DUMMY_MP3) ? 1 : 0;
3567+ break;
3568+
3569+ case (BN_CLICKED<<16)|IDC_MEDIA_LIBRARY_REGISTERED_FILE_ONLY:
3570+ cfg_media_library_registered_file_only = uButton_GetCheck(wnd, IDC_MEDIA_LIBRARY_REGISTERED_FILE_ONLY) ? 1 : 0;
3571+ break;
3572+
3573+ case (BN_CLICKED<<16)|IDC_EXPLICITLY_TAGGED_FILE_ONLY:
3574+ cfg_explicitly_tagged_file_only = uButton_GetCheck(wnd, IDC_EXPLICITLY_TAGGED_FILE_ONLY) ? 1 : 0;
3575+ EnableNoNames(wnd, (cfg_explicitly_tagged_file_only == 0) ? true : false);
3576+ break;
3577+
3578+ case (BN_CLICKED<<16)|IDC_ENABLE_STREAMING_FILE:
3579+ cfg_enable_streaming_file = uButton_GetCheck(wnd, IDC_ENABLE_STREAMING_FILE) ? 1 : 0;
3580+ break;
3581+
3582+ case (BN_CLICKED<<16)|IDC_CONFIGURE:
3583+ DummyAmp::getInstance()->config();
3584+ break;
3585+ }
3586+ break;
3587+
3588+ case WM_HSCROLL:
3589+ {
3590+ HWND hTrackBar = (HWND)lp;
3591+
3592+ if((hTrackBar == hSendInterval1)
3593+ || (hTrackBar == hSendInterval2)
3594+ || (hTrackBar == hSendInterval3))
3595+ {
3596+ switch(LOWORD(wp))
3597+ {
3598+ case TB_THUMBPOSITION:
3599+ case TB_THUMBTRACK:
3600+ case TB_TOP:
3601+ case TB_BOTTOM:
3602+ case TB_PAGEUP:
3603+ case TB_PAGEDOWN:
3604+ case TB_LINEUP:
3605+ case TB_LINEDOWN:
3606+ case TB_ENDTRACK:
3607+ {
3608+ LRESULT lPos = 0;
3609+
3610+ switch(LOWORD(wp))
3611+ {
3612+ case TB_THUMBPOSITION:
3613+ case TB_THUMBTRACK:
3614+ lPos = HIWORD(wp);
3615+ break;
3616+ default:
3617+ lPos = uSendMessage(hTrackBar, TBM_GETPOS, 0, 0);
3618+ break;
3619+ }
3620+
3621+ uSendMessage(hTrackBar, TBM_SETPOS, (WPARAM)TRUE, lPos);
3622+
3623+ if(hTrackBar == hSendInterval1)
3624+ {
3625+ setDlgItemFloat(wnd, IDC_SEND_INTERVAL_1ST, (double)lPos);
3626+ string8 pos;
3627+ float2String(pos, (double)lPos);
3628+ cfg_send_interval1 = pos;
3629+ }
3630+ else if(hTrackBar == hSendInterval2)
3631+ {
3632+ setDlgItemFloat(wnd, IDC_SEND_INTERVAL_2ND, (double)lPos);
3633+ string8 pos;
3634+ float2String(pos, (double)lPos);
3635+ cfg_send_interval2 = pos;
3636+ }
3637+ else if(hTrackBar == hSendInterval3)
3638+ {
3639+ setDlgItemFloat(wnd, IDC_SEND_INTERVAL_3RD, (double)lPos);
3640+ string8 pos;
3641+ float2String(pos, (double)lPos);
3642+ cfg_send_interval3 = pos;
3643+ }
3644+ }
3645+ break;
3646+
3647+ default:
3648+ break;
3649+ }
3650+ }
3651+ }
3652+ break;
3653+ case WM_DESTROY:
3654+ if(hIntervalFont != INVALID_HANDLE_VALUE) {
3655+ ::DeleteObject(hIntervalFont);
3656+ }
3657+ break;
3658+ }
3659+
3660+ return 0;
3661+ }
3662+
3663+ static void setDlgItemFloat(HWND wnd, UINT id, double val)
3664+ {
3665+ string8 pos;
3666+ float2String(pos, val);
3667+
3668+ uSetDlgItemText(wnd, id, pos);
3669+ }
3670+
3671+ static void float2String(string8 &str, double val)
3672+ {
3673+#if IS_FB2K_VER08
3674+ char *pStr = str.buffer_get(1024);
3675+ pfc_float_to_string(pStr, val, 0);
3676+ str.buffer_done();
3677+#elif IS_FB2K_VER09
3678+ char *pStr = str.lock_buffer(1024);
3679+ float_to_string(pStr, 1024, val, 0);
3680+ str.unlock_buffer();
3681+#endif
3682+ }
3683+
3684+ static void EnableNoNames(HWND wnd, bool bNoNameEnabled) {
3685+ EnableNoName(wnd, IDC_NO_ARTIST_NAME, bNoNameEnabled);
3686+ EnableNoName(wnd, IDC_NO_TITLE_NAME, bNoNameEnabled);
3687+ EnableNoName(wnd, IDC_NO_ALBUM_NAME, bNoNameEnabled);
3688+ EnableNoName(wnd, IDC_NO_GENRE_NAME, bNoNameEnabled);
3689+ }
3690+
3691+ static void EnableNoName(HWND wnd, UINT id, bool bEnable) {
3692+ HWND hControlWnd = uGetDlgItem(wnd, id);
3693+ uEnableWindow(hControlWnd, bEnable);
3694+ }
3695+
3696+public:
3697+ virtual HWND create(HWND parent)
3698+ {
3699+ return uCreateDialog(IDD_PREFERENCE, parent, ConfigProc);
3700+ }
3701+
3702+ virtual const char * get_name() {
3703+ return g_pluginCaption8;
3704+ }
3705+
3706+ virtual const char * get_parent_name() {
3707+ return "Components";
3708+ }
3709+
3710+#if IS_FB2K_VER09
3711+ virtual GUID get_guid() {
3712+ return config_page_mixi_guid;
3713+ }
3714+
3715+ virtual GUID get_parent_guid() {
3716+ return guid_tools;
3717+ }
3718+
3719+ virtual bool reset_query() {
3720+ return true;
3721+ }
3722+
3723+ virtual void reset()
3724+ {
3725+ cfg_use_plugin = 1;
3726+ cfg_disable_duplicate_song = 0;
3727+ cfg_media_library_registered_file_only = 0;
3728+ cfg_send_interval1 = "20";
3729+ cfg_send_interval2 = "66";
3730+ cfg_send_interval3 = "300";
3731+ }
3732+
3733+ virtual bool get_help_url(pfc::string_base & p_out)
3734+ {
3735+ p_out = URL_FOO_MIXI_HOME;
3736+ return true;
3737+ }
3738+#endif
3739+};
3740+
3741+HFONT config_page_mixi::hIntervalFont = (HFONT)INVALID_HANDLE_VALUE;
3742+
3743+#if IS_FB2K_VER08
3744+class config_page_mixi_advanced : public config
3745+#elif IS_FB2K_VER09
3746+// {E01262F2-E6BF-4f3e-B0F2-5B8C08E2C2E3}
3747+static const GUID config_page_mixi_advanced_guid = { 0xe01262f2, 0xe6bf, 0x4f3e, { 0xb0, 0xf2, 0x5b, 0x8c, 0x8, 0xe2, 0xc2, 0xe3 } };
3748+class config_page_mixi_advanced : public preferences_page_v2
3749+#endif
3750+{
3751+ static int nOldDummyMp3Location;
3752+ static string8 oldGenMixiPath;
3753+
3754+ static BOOL CALLBACK ConfigProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
3755+ {
3756+ switch(msg)
3757+ {
3758+ case WM_INITDIALOG:
3759+ {
3760+ uSetDlgItemText(wnd, IDC_CAPTION_ADVANCED, g_advancedSettingsCaption8);
3761+
3762+ uButton_SetCheck(wnd, IDC_DISABLE_DUMMY_MP3, (cfg_disable_dummy_mp3 == 1) ? true : false);
3763+
3764+ uSendDlgItemMessage(wnd, IDC_DUMMY_MP3_LOCATION, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(_T("ダミーMP3ファイルをユーザプロファイルに作成する")));
3765+ uSendDlgItemMessage(wnd, IDC_DUMMY_MP3_LOCATION, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(_T("ダミーMP3ファイルを一時フォルダに作成する")));
3766+ uSendDlgItemMessage(wnd, IDC_DUMMY_MP3_LOCATION, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(_T("ダミーMP3ファイルを Components フォルダに作成する")));
3767+
3768+ uEnableWindow(uGetDlgItem(wnd, IDC_DUMMY_MP3_LOCATION), (cfg_disable_dummy_mp3 == 0) ? true : false);
3769+
3770+ uSendDlgItemMessage(wnd, IDC_DUMMY_MP3_LOCATION, CB_SETCURSEL, (int)cfg_dummy_mp3_location, 0);
3771+ nOldDummyMp3Location = (int)cfg_dummy_mp3_location;
3772+
3773+ uSetDlgItemText(wnd, IDC_GEN_MIXI_PATH, cfg_gen_mixi_path);
3774+ oldGenMixiPath = cfg_gen_mixi_path;
3775+
3776+ Str64K dummyAmpFrameCaptionBuf;
3777+
3778+ _stprintf_s(
3779+ dummyAmpFrameCaptionBuf, sizeof(dummyAmpFrameCaptionBuf) / sizeof(TCHAR),
3780+ DUMMYAMP_FRAME_CAPTION,
3781+ DummyAmp::getInstance()->getWnd() == INVALID_HANDLE_VALUE ? DUMMYAMP_BEFORE_INIT_MODE :
3782+ DummyAmp::getInstance()->isAnotherWinampWindowAvailable() ? DUMMYAMP_HOOK_MODE : DUMMYAMP_STANDALONE_MODE
3783+ );
3784+
3785+ ::SetDlgItemText(wnd, IDC_DUMMYAMP_FRAME, dummyAmpFrameCaptionBuf);
3786+
3787+ uButton_SetCheck(wnd, IDC_SHOW_DUMMYAMP, (cfg_show_dummyamp == 1) ? true : false);
3788+ if(DummyAmp::getInstance()->getWnd() == INVALID_HANDLE_VALUE) {
3789+ HWND hControlWnd = uGetDlgItem(wnd, IDC_SHOW_DUMMYAMP);
3790+ uEnableWindow(hControlWnd, false);
3791+ }
3792+
3793+ uSetDlgItemText(wnd, IDC_DUMMYAMP_TITLE_FORMAT, cfg_dummyamp_title_format);
3794+ uSetDlgItemText(wnd, IDC_DUMMYAMP_PLAYLIST_FORMAT, cfg_dummyamp_playlist_format);
3795+
3796+ uButton_SetCheck(wnd, IDC_DISABLE_ANSI_TRANS, (cfg_disable_ansi_trans == 1) ? true : false);
3797+ uButton_SetCheck(wnd, IDC_ENABLE_EXT_IPC_PROC, (cfg_enable_ext_ipc_proc == 1) ? true : false);
3798+ if(DummyAmp::getInstance()->isAnotherWinampWindowAvailable() == false) {
3799+ HWND hControlWnd = uGetDlgItem(wnd, IDC_ENABLE_EXT_IPC_PROC);
3800+ uEnableWindow(hControlWnd, false);
3801+ }
3802+
3803+ setDlgVersionInfo(wnd, IDC_VERSION_ADVANCED, IDC_BUILD_ADVANCED);
3804+ }
3805+ break;
3806+
3807+ case WM_COMMAND:
3808+ switch(wp)
3809+ {
3810+ case (BN_CLICKED<<16)|IDC_DISABLE_DUMMY_MP3:
3811+ {
3812+ cfg_disable_dummy_mp3 = uButton_GetCheck(wnd, IDC_DISABLE_DUMMY_MP3) ? 1 : 0;
3813+ uEnableWindow(uGetDlgItem(wnd, IDC_DUMMY_MP3_LOCATION), (cfg_disable_dummy_mp3 == 0) ? true : false);
3814+ }
3815+ break;
3816+
3817+ case (CBN_SELCHANGE<<16)|IDC_DUMMY_MP3_LOCATION:
3818+ {
3819+ int sel = static_cast<int>(uSendMessage(reinterpret_cast<HWND>(lp), CB_GETCURSEL, 0, 0));
3820+ cfg_dummy_mp3_location = sel;
3821+ }
3822+ break;
3823+
3824+ case (EN_UPDATE<<16)|IDC_GEN_MIXI_PATH:
3825+ {
3826+ string8 path;
3827+ uGetWindowText(reinterpret_cast<HWND>(lp), path);
3828+ cfg_gen_mixi_path = path;
3829+ }
3830+ break;
3831+
3832+ case (BN_CLICKED<<16)|IDC_GEN_MIXI_PATH_REF:
3833+ {
3834+ string8 path(cfg_gen_mixi_path);
3835+
3836+ OPENFILENAME ofn;
3837+ TCHAR strFile[MAX_PATH];
3838+
3839+ ::ZeroMemory(&ofn, sizeof(OPENFILENAME));
3840+ strFile[0] = _T('\0');
3841+
3842+ ofn.lStructSize = sizeof(OPENFILENAME);
3843+ ofn.hwndOwner = wnd;
3844+ ofn.lpstrFilter = _T("gen_mixi_for_winamp.dll\0gen_mixi_for_winamp.dll\0\0");
3845+ ofn.nFilterIndex = 0;
3846+ ofn.lpstrInitialDir = PathInfo::splitPath(path).c_str();
3847+ ofn.lpstrFile = strFile;
3848+ ofn.nMaxFile = MAX_PATH;
3849+ ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
3850+
3851+ if(::GetOpenFileName(&ofn) == TRUE)
3852+ {
3853+ tstring genMixiPath(PathInfo::splitPath(strFile));
3854+ string_utf8_from_os genMixiPath8(genMixiPath.c_str());
3855+
3856+ cfg_gen_mixi_path = genMixiPath8;
3857+ ::uSetDlgItemText(wnd, IDC_GEN_MIXI_PATH, genMixiPath8);
3858+ }
3859+ }
3860+
3861+ case (BN_CLICKED<<16)|IDC_SHOW_DUMMYAMP:
3862+ {
3863+ bool bShowDummyAmp = uButton_GetCheck(wnd, IDC_SHOW_DUMMYAMP);
3864+ cfg_show_dummyamp = bShowDummyAmp ? 1 : 0;
3865+
3866+ DummyAmp::getInstance()->showDummyAmpWindow(bShowDummyAmp);
3867+ }
3868+ break;
3869+
3870+ case (EN_UPDATE<<16)|IDC_DUMMYAMP_TITLE_FORMAT:
3871+ {
3872+ string8 format;
3873+ uGetWindowText(reinterpret_cast<HWND>(lp), format);
3874+ cfg_dummyamp_title_format = format;
3875+ }
3876+ break;
3877+
3878+ case (EN_UPDATE<<16)|IDC_DUMMYAMP_PLAYLIST_FORMAT:
3879+ {
3880+ string8 format;
3881+ uGetWindowText(reinterpret_cast<HWND>(lp), format);
3882+ cfg_dummyamp_playlist_format = format;
3883+ }
3884+ break;
3885+
3886+ case (BN_CLICKED<<16)|IDC_DISABLE_ANSI_TRANS:
3887+ {
3888+ cfg_disable_ansi_trans = uButton_GetCheck(wnd, IDC_DISABLE_ANSI_TRANS) ? 1 : 0;
3889+ }
3890+ break;
3891+
3892+ case (BN_CLICKED<<16)|IDC_ENABLE_EXT_IPC_PROC:
3893+ {
3894+ cfg_enable_ext_ipc_proc = uButton_GetCheck(wnd, IDC_ENABLE_EXT_IPC_PROC) ? 1 : 0;
3895+ }
3896+ break;
3897+
3898+ default:
3899+ break;
3900+ }
3901+ break;
3902+ case WM_DESTROY:
3903+ {
3904+ bool rebootNeeded = false;
3905+
3906+ if(nOldDummyMp3Location != -1)
3907+ {
3908+ if(nOldDummyMp3Location != cfg_dummy_mp3_location)
3909+ {
3910+ int nRes = ::MessageBox(
3911+ NULL, _T("ダミーMP3ファイルの生成場所の変更は、foobar2000本体の再起動後に有効になります。\n\n")
3912+ _T("今すぐ、foobar2000をシャットダウンしますか?"),
3913+ _T(PLUGIN_CAPTION), MB_YESNO | MB_ICONEXCLAMATION);
3914+
3915+ if(nRes == IDYES) {
3916+ rebootNeeded = true;
3917+ } else {
3918+ rebootNeeded = false;
3919+ }
3920+ }
3921+ }
3922+
3923+ if(::strcmp(oldGenMixiPath, cfg_gen_mixi_path) != 0)
3924+ {
3925+ int nRes = ::MessageBox(
3926+ NULL, GEN_MIXI_FILE_NAME _T(" の配置場所の変更は、foobar2000本体の再起動後に有効になります。\n\n")
3927+ _T("今すぐ、foobar2000をシャットダウンしますか?"),
3928+ _T(PLUGIN_CAPTION), MB_YESNO | MB_ICONEXCLAMATION);
3929+
3930+ if(nRes == IDYES) {
3931+ rebootNeeded = true;
3932+ } else {
3933+ rebootNeeded = false;
3934+ }
3935+ }
3936+
3937+ nOldDummyMp3Location = (int)cfg_dummy_mp3_location;
3938+ oldGenMixiPath = cfg_gen_mixi_path;
3939+
3940+ if(rebootNeeded) {
3941+ ::PostQuitMessage(0);
3942+ }
3943+ }
3944+ break;
3945+ }
3946+
3947+ return 0;
3948+ }
3949+
3950+public:
3951+
3952+ virtual HWND create(HWND parent)
3953+ {
3954+ return uCreateDialog(IDD_ADVANCED_SETTINGS, parent, ConfigProc);
3955+ }
3956+
3957+ virtual const char * get_name() {
3958+ return g_advancedSettingsCaption8;
3959+ }
3960+ virtual const char * get_parent_name() {
3961+ return g_pluginCaption8;
3962+ }
3963+
3964+#if IS_FB2K_VER09
3965+ virtual GUID get_guid() {
3966+ return config_page_mixi_advanced_guid;
3967+ }
3968+
3969+ virtual GUID get_parent_guid() {
3970+ return config_page_mixi_guid;
3971+ }
3972+
3973+ virtual double get_sort_priority() {
3974+ return 1.0;
3975+ }
3976+
3977+ virtual bool reset_query() {
3978+ return true;
3979+ }
3980+
3981+ virtual void reset() {
3982+ cfg_disable_dummy_mp3 = 0;
3983+ cfg_dummy_mp3_location = 0;
3984+ cfg_gen_mixi_path = PathInfo::getGenMixiDefaultPath().c_str();
3985+
3986+ cfg_show_dummyamp = 0;
3987+ cfg_dummyamp_title_format = DEFAULT_DUMMYAMP_TITLE;
3988+ cfg_dummyamp_playlist_format = DEFAULT_DUMMYAMP_TITLE;
3989+ }
3990+
3991+ virtual bool get_help_url(pfc::string_base & p_out) {
3992+ p_out = URL_FOO_MIXI_HOME;
3993+ return true;
3994+ }
3995+#endif
3996+};
3997+
3998+int config_page_mixi_advanced::nOldDummyMp3Location = -1;
3999+string8 config_page_mixi_advanced::oldGenMixiPath;
4000+
4001+#if IS_FB2K_VER08
4002+class config_page_mixi_debug : public config
4003+#elif IS_FB2K_VER09
4004+// {ADD3AC74-B1A7-4d04-BADB-6BEB7D132669}
4005+static const GUID config_page_mixi_debug_guid = { 0xadd3ac74, 0xb1a7, 0x4d04, { 0xba, 0xdb, 0x6b, 0xeb, 0x7d, 0x13, 0x26, 0x69 } };
4006+class config_page_mixi_debug : public preferences_page_v2
4007+#endif
4008+{
4009+ static BOOL CALLBACK ConfigProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
4010+ {
4011+ switch(msg)
4012+ {
4013+ case WM_INITDIALOG:
4014+ {
4015+ uSetDlgItemText(wnd, IDC_CAPTION_DEBUG, g_debugSettingsCaption8);
4016+
4017+ bool bDebugLogEnabled = (cfg_enable_debug_log == 1) ? true : false;
4018+ uButton_SetCheck(wnd, IDC_ENABLE_DEBUG_LOG, bDebugLogEnabled);
4019+
4020+ InitDebugLevelList(wnd, IDC_DEBUG_DUMMYAMP_INIT);
4021+ InitDebugLevelList(wnd, IDC_DEBUG_DUMMYAMP_PROC);
4022+ InitDebugLevelList(wnd, IDC_DEBUG_TRACK_INFO);
4023+ InitDebugLevelList(wnd, IDC_DEBUG_PLUGIN);
4024+ InitDebugLevelList(wnd, IDC_DEBUG_CALLBACK);
4025+
4026+ EnableDebugLevelLists(wnd, bDebugLogEnabled);
4027+
4028+ uSendDlgItemMessage(wnd, IDC_DEBUG_DUMMYAMP_INIT, CB_SETCURSEL, (int)cfg_debug_dummyamp_init, 0);
4029+ uSendDlgItemMessage(wnd, IDC_DEBUG_DUMMYAMP_PROC, CB_SETCURSEL, (int)cfg_debug_dummyamp_proc, 0);
4030+ uSendDlgItemMessage(wnd, IDC_DEBUG_TRACK_INFO, CB_SETCURSEL, (int)cfg_debug_track_info, 0);
4031+ uSendDlgItemMessage(wnd, IDC_DEBUG_PLUGIN, CB_SETCURSEL, (int)cfg_debug_plugin, 0);
4032+ uSendDlgItemMessage(wnd, IDC_DEBUG_CALLBACK, CB_SETCURSEL, (int)cfg_debug_callback, 0);
4033+
4034+ setDlgVersionInfo(wnd, IDC_VERSION_DEBUG, IDC_BUILD_DEBUG);
4035+ }
4036+ break;
4037+
4038+ case WM_COMMAND:
4039+ switch(wp)
4040+ {
4041+ case (BN_CLICKED<<16)|IDC_ENABLE_DEBUG_LOG:
4042+ {
4043+ bool bDebugLogEnabled = uButton_GetCheck(wnd, IDC_ENABLE_DEBUG_LOG);
4044+ cfg_enable_debug_log = bDebugLogEnabled ? 1 : 0;
4045+
4046+ EnableDebugLevelLists(wnd, bDebugLogEnabled);
4047+ }
4048+ break;
4049+
4050+ case (CBN_SELCHANGE<<16)|IDC_DEBUG_DUMMYAMP_INIT:
4051+ {
4052+ int sel = static_cast<int>(uSendMessage(reinterpret_cast<HWND>(lp), CB_GETCURSEL, 0, 0));
4053+ cfg_debug_dummyamp_init = sel;
4054+ }
4055+ break;
4056+
4057+ case (CBN_SELCHANGE<<16)|IDC_DEBUG_DUMMYAMP_PROC:
4058+ {
4059+ int sel = static_cast<int>(uSendMessage(reinterpret_cast<HWND>(lp), CB_GETCURSEL, 0, 0));
4060+ cfg_debug_dummyamp_proc = sel;
4061+ }
4062+ break;
4063+
4064+ case (CBN_SELCHANGE<<16)|IDC_DEBUG_TRACK_INFO:
4065+ {
4066+ int sel = static_cast<int>(uSendMessage(reinterpret_cast<HWND>(lp), CB_GETCURSEL, 0, 0));
4067+ cfg_debug_track_info = sel;
4068+ }
4069+ break;
4070+
4071+ case (CBN_SELCHANGE<<16)|IDC_DEBUG_PLUGIN:
4072+ {
4073+ int sel = static_cast<int>(uSendMessage(reinterpret_cast<HWND>(lp), CB_GETCURSEL, 0, 0));
4074+ cfg_debug_plugin = sel;
4075+ }
4076+ break;
4077+
4078+ case (CBN_SELCHANGE<<16)|IDC_DEBUG_CALLBACK:
4079+ {
4080+ int sel = static_cast<int>(uSendMessage(reinterpret_cast<HWND>(lp), CB_GETCURSEL, 0, 0));
4081+ cfg_debug_callback = sel;
4082+ }
4083+ break;
4084+
4085+ default:
4086+ break;
4087+ }
4088+ break;
4089+
4090+ case WM_DESTROY:
4091+ break;
4092+ }
4093+
4094+ return 0;
4095+ }
4096+
4097+protected:
4098+
4099+ static void InitDebugLevelList(HWND wnd, UINT id) {
4100+ uSendDlgItemMessage(wnd, id, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(_T("なし")));
4101+ uSendDlgItemMessage(wnd, id, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(_T("簡易レベル")));
4102+ uSendDlgItemMessage(wnd, id, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(_T("詳細レベル")));
4103+ }
4104+
4105+ static void EnableDebugLevelLists(HWND wnd, bool bDebugLogEnabled) {
4106+ EnableDebugLevelList(wnd, IDC_DEBUG_DUMMYAMP_INIT, bDebugLogEnabled);
4107+ EnableDebugLevelList(wnd, IDC_DEBUG_DUMMYAMP_PROC, bDebugLogEnabled);
4108+ EnableDebugLevelList(wnd, IDC_DEBUG_TRACK_INFO, bDebugLogEnabled);
4109+ EnableDebugLevelList(wnd, IDC_DEBUG_PLUGIN, bDebugLogEnabled);
4110+ EnableDebugLevelList(wnd, IDC_DEBUG_CALLBACK, bDebugLogEnabled);
4111+ }
4112+
4113+ static void EnableDebugLevelList(HWND wnd, UINT id, bool bEnable) {
4114+ HWND hControlWnd = uGetDlgItem(wnd, id);
4115+ uEnableWindow(hControlWnd, bEnable);
4116+ }
4117+
4118+public:
4119+
4120+ virtual HWND create(HWND parent)
4121+ {
4122+ return uCreateDialog(IDD_DEBUG_SETTINGS, parent, ConfigProc);
4123+ }
4124+
4125+ virtual const char * get_name() {
4126+ return g_debugSettingsCaption8;
4127+ }
4128+ virtual const char * get_parent_name() {
4129+ return g_pluginCaption8;
4130+ }
4131+
4132+#if IS_FB2K_VER09
4133+ virtual GUID get_guid() {
4134+ return config_page_mixi_debug_guid;
4135+ }
4136+
4137+ virtual GUID get_parent_guid() {
4138+ return config_page_mixi_guid;
4139+ }
4140+
4141+ virtual bool reset_query() {
4142+ return true;
4143+ }
4144+
4145+ virtual double get_sort_priority() {
4146+ return 2.0;
4147+ }
4148+
4149+ virtual void reset() {
4150+ cfg_enable_debug_log = 1;
4151+ cfg_debug_dummyamp_init = 1;
4152+ cfg_debug_dummyamp_proc = 1;
4153+ cfg_debug_track_info = 1;
4154+ cfg_debug_plugin = 1;
4155+ cfg_debug_callback = 1;
4156+ }
4157+
4158+ virtual bool get_help_url(pfc::string_base & p_out) {
4159+ p_out = URL_FOO_MIXI_HOME;
4160+ return true;
4161+ }
4162+#endif
4163+};
4164+
4165+#if IS_FB2K_VER08
4166+static service_factory_single_t<play_callback, play_callback_mixi> foo1;
4167+static service_factory_single_t<initquit, initquit_mixi> foo2;
4168+static menu_item_factory<menu_item_mixi> foo3;
4169+static service_factory_single_t<config, config_page_mixi> foo4;
4170+static service_factory_single_t<config, config_page_mixi_advanced> foo5;
4171+static service_factory_single_t<config, config_page_mixi_debug> foo6;
4172+#elif IS_FB2K_VER09
4173+static service_factory_single_t<play_callback_mixi> foo1;
4174+static initquit_factory_t<initquit_mixi> foo2;
4175+static mainmenu_commands_factory_t<menu_item_mixi> foo3;
4176+static preferences_page_factory_t<config_page_mixi> foo4;
4177+static preferences_page_factory_t<config_page_mixi_advanced> foo5;
4178+static preferences_page_factory_t<config_page_mixi_debug> foo6;
4179+#endif
4180+
4181+tstring GetErrorMessage(DWORD errCode)
4182+{
4183+
4184+ LPVOID lpMsgBuf;
4185+
4186+ FormatMessage(
4187+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
4188+ FORMAT_MESSAGE_FROM_SYSTEM |
4189+ FORMAT_MESSAGE_IGNORE_INSERTS,
4190+ NULL,
4191+ errCode,
4192+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // デフォルト言語
4193+ (LPTSTR) &lpMsgBuf,
4194+ 0,
4195+ NULL
4196+ );
4197+
4198+ tstring msg = (LPCTSTR)lpMsgBuf;
4199+
4200+ GlobalFree(lpMsgBuf);
4201+
4202+ return msg;
4203+}
4204+
4205+void putLogError(LPCTSTR pMethod, LPCTSTR pErrMsg, DWORD dwErrCode)
4206+{
4207+ tstring errMsg = GetErrorMessage(dwErrCode);
4208+
4209+ LOG_ERROR(_T("%s - %s"), pMethod, pErrMsg);
4210+ LOG_ERROR(_T("%s - コード: %08x, 理由: %s"), pMethod, dwErrCode, errMsg.c_str());
4211+}
4212+
4213+void setDlgVersionInfo(HWND wnd, UINT idc_version, UINT idc_build) {
4214+
4215+ StrDBCS64K version;
4216+
4217+ sprintf_s(version, sizeof(StrDBCS64K), PLUGIN_CAPTION " " PLUGIN_VERSION " with SDK%d (compatible%d)",
4218+ foobar2000_client::FOOBAR2000_CLIENT_VERSION, foobar2000_client::FOOBAR2000_CLIENT_VERSION_COMPATIBLE);
4219+
4220+ uSetDlgItemText(wnd, idc_version, version);
4221+ uSetDlgItemText(wnd, idc_build, "build on " __DATE__ ", " __TIME__);
4222+}
4223+
4224+void DebugPrint(int severity, LPCTSTR lpszFormat, ...)
4225+{
4226+ static Str64K buf;
4227+ va_list marker;
4228+
4229+ va_start(marker, lpszFormat);
4230+ _vstprintf_s(buf, sizeof(Str64K), lpszFormat, marker);
4231+ va_end(marker);
4232+
4233+ OutputDebugString(buf);
4234+ OutputDebugString(_T("\n"));
4235+
4236+ string_utf8_from_os tmp(buf);
4237+
4238+#if IS_FB2K_VER08
4239+ console::output(severity, tmp);
4240+#else
4241+ switch(severity)
4242+ {
4243+ case console::SEVERITY_INFO:
4244+ console::info(tmp);
4245+ break;
4246+ case console::SEVERITY_WARNING:
4247+ console::warning(tmp);
4248+ break;
4249+ case console::SEVERITY_CRITICAL:
4250+ console::error(tmp);
4251+ break;
4252+ }
4253+#endif
4254+}
4255+
4256+void DebugPrint8(int severity, LPCSTR lpszFormat, ...)
4257+{
4258+ static StrDBCS64K buf;
4259+
4260+ va_list marker;
4261+
4262+ va_start(marker, lpszFormat);
4263+ vsprintf_s(buf, sizeof(StrDBCS64K), lpszFormat, marker);
4264+ va_end(marker);
4265+
4266+#if IS_FB2K_VER08
4267+ console::output(severity, buf);
4268+#else
4269+ switch(severity)
4270+ {
4271+ case console::SEVERITY_INFO:
4272+ console::info(buf);
4273+ break;
4274+ case console::SEVERITY_WARNING:
4275+ console::warning(buf);
4276+ break;
4277+ case console::SEVERITY_CRITICAL:
4278+ console::error(buf);
4279+ break;
4280+ }
4281+#endif
4282+
4283+ string_os_from_utf8 tmp(buf);
4284+
4285+ OutputDebugString(tmp);
4286+ OutputDebugString(_T("\n"));
4287+}
4288+
4289+#if defined(BUILD_UNICODE)
4290+void DebugPrintDBCS(int severity, LPCSTR lpszFormat, ...)
4291+{
4292+ static StrDBCS64K buf;
4293+ va_list marker;
4294+
4295+ va_start(marker, lpszFormat);
4296+ vsprintf_s(buf, sizeof(StrDBCS64K), lpszFormat, marker);
4297+ va_end(marker);
4298+
4299+ string_wide_from_ansi tmp(buf);
4300+
4301+ OutputDebugString(tmp);
4302+ OutputDebugString(L"\n");
4303+
4304+#if IS_FB2K_VER08
4305+ console::output(severity, buf);
4306+#else
4307+ switch(severity)
4308+ {
4309+ case console::SEVERITY_INFO:
4310+ console::info(buf);
4311+ break;
4312+ case console::SEVERITY_WARNING:
4313+ console::warning(buf);
4314+ break;
4315+ case console::SEVERITY_CRITICAL:
4316+ console::error(buf);
4317+ break;
4318+ }
4319+#endif
4320+}
4321+#endif
\ No newline at end of file
--- src/foo_mixi_feat_winamp/tags/0.2.0.1mod_R20090213/foo_mixi_feat_winamp_for_fb2k_0_9_4_SDK72/resource.h (nonexistent)
+++ src/foo_mixi_feat_winamp/tags/0.2.0.1mod_R20090213/foo_mixi_feat_winamp_for_fb2k_0_9_4_SDK72/resource.h (revision 66)
@@ -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/tags/0.2.0.1mod_R20090213/foo_mixi_feat_winamp_for_fb2k_0_9_4_SDK72/COPYING (nonexistent)
+++ src/foo_mixi_feat_winamp/tags/0.2.0.1mod_R20090213/foo_mixi_feat_winamp_for_fb2k_0_9_4_SDK72/COPYING (revision 66)
@@ -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/tags/0.2.0.1mod_R20090213/foo_mixi_feat_winamp_for_fb2k_0_9_4_SDK72/wa_ipc.h (nonexistent)
+++ src/foo_mixi_feat_winamp/tags/0.2.0.1mod_R20090213/foo_mixi_feat_winamp_for_fb2k_0_9_4_SDK72/wa_ipc.h (revision 66)
@@ -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/tags/0.2.0.1mod_R20090213/foo_mixi_feat_winamp_for_fb2k_0_9_4_SDK72/README (nonexistent)
+++ src/foo_mixi_feat_winamp/tags/0.2.0.1mod_R20090213/foo_mixi_feat_winamp_for_fb2k_0_9_4_SDK72/README (revision 66)
@@ -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/tags/0.2.0.1mod_R20090213/foo_mixi_feat_winamp_for_fb2k_0_8_3/foo_mixi_feat_winamp.cpp (nonexistent)
+++ src/foo_mixi_feat_winamp/tags/0.2.0.1mod_R20090213/foo_mixi_feat_winamp_for_fb2k_0_8_3/foo_mixi_feat_winamp.cpp (revision 66)
@@ -0,0 +1,4321 @@
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.0.1mod"
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 REQUIRED_MINIMUM_TIME 3
124+#define SEND_TIME_RATE_LOWERBOUND 33
125+#define REQUIRED_MAXIMUM_TIME 20
126+
127+//#define CONTROL_SEND_TIMING
128+
129+//#define ENABLE_MSN
130+
131+#if IS_FB2K_VER09
132+using namespace pfc;
133+using namespace pfc::stringcvt;
134+#define pfc_string_to_float string_to_float
135+#endif
136+
137+/*
138+ foo_mixi_feat_winamp: project dependencies
139+
140+ foo_mixi_feat_winamp
141+ foobar2000_SDK
142+ utf8api(0.8.3)
143+ pfc
144+ foobar2000_sdk_helpers
145+ pfc
146+ foobar2000_component_client(0.9.X)
147+ id3lib
148+ zlib
149+
150+ library dependencies: wxbase28.lib, id3lib.lib, ../shared/shared.lib(0.9.X)
151+ runtime library: Multi-Thread (DLL) or (Debug,DLL)
152+ !! ensure all projects that depended from this project are correctly set to MT DLL !!
153+ ignore: LIBCMT [Win32 Release] (or LIBCMTD [Win32 Debug])
154+*/
155+
156+// if wxWidgets are updated, change lib names below and linker libpath option.
157+
158+#if 0
159+#if defined(_DEBUG)
160+#if defined(BUILD_UNICODE)
161+#pragma comment(lib, "wxbase28ud.lib")
162+#else
163+#pragma comment(lib, "wxbase28d.lib")
164+#endif
165+#else
166+#if defined(BUILD_UNICODE)
167+#pragma comment(lib, "wxbase28u.lib")
168+#else
169+#pragma comment(lib, "wxbase28.lib")
170+#endif
171+#endif
172+#endif
173+
174+// now id3lib automatically added to linker target,
175+// because it generated from depended project.
176+//#pragma comment(lib, "id3lib.lib")
177+
178+#if IS_FB2K_VER09
179+#pragma comment(lib, "../shared/shared.lib")
180+#endif
181+
182+typedef std::basic_string<TCHAR> tstring;
183+
184+typedef TCHAR Str64K[65536];
185+typedef char StrDBCS64K[65536];
186+
187+tstring GetErrorMessage(DWORD errCode);
188+void putLogError(LPCTSTR pMethod, LPCTSTR pErrMsg, DWORD dwErrCode);
189+void setDlgVersionInfo(HWND wnd, UINT idc_version, UINT idc_build);
190+void DebugPrint(int severity, LPCTSTR lpszFormat, ...);
191+void DebugPrintDBCS(int severity, LPCSTR lpszFormat, ...);
192+void DebugPrint8(int severity, LPCSTR lpszFormat, ...);
193+
194+#define LOGLEVEL_NONE 0
195+#define LOGLEVEL_WARNING 1
196+#define LOGLEVEL_ERROR 2
197+
198+#if IS_FB2K_VER09
199+namespace console
200+{
201+ enum {
202+ SEVERITY_INFO = 0,
203+ SEVERITY_WARNING = 1,
204+ SEVERITY_CRITICAL = 2
205+ };
206+};
207+#endif
208+
209+#define LOG_TRACE(f, ...) if(cfg_enable_debug_log) DebugPrint(console::SEVERITY_INFO, f, __VA_ARGS__)
210+#define LOG_DEBUG(f, ...) if(cfg_enable_debug_log) DebugPrint(console::SEVERITY_INFO, f, __VA_ARGS__)
211+
212+#define LOG_TRACE8(f, ...) if(cfg_enable_debug_log) DebugPrint8(console::SEVERITY_INFO, f, __VA_ARGS__)
213+#define LOG_DEBUG8(f, ...) if(cfg_enable_debug_log) DebugPrint8(console::SEVERITY_INFO, f, __VA_ARGS__)
214+
215+#define LOG_TRACE_ANSI(f, ...) if(cfg_enable_debug_log) DebugPrintDBCS(console::SEVERITY_INFO, f, __VA_ARGS__)
216+#define LOG_DEBUG_ANSI(f, ...) if(cfg_enable_debug_log) DebugPrintDBCS(console::SEVERITY_INFO, f, __VA_ARGS__)
217+
218+#define LOG_INFO(f, ...) DebugPrint(console::SEVERITY_INFO, f, __VA_ARGS__)
219+#define LOG_WARN(f, ...) DebugPrint(console::SEVERITY_WARNING, f, __VA_ARGS__)
220+#define LOG_ERROR(f, ...) DebugPrint(console::SEVERITY_CRITICAL, f, __VA_ARGS__)
221+
222+#if defined(BUILD_UNICODE)
223+#define TRACE_DBCS(f, ...) if(cfg_enable_debug_log) DebugPrintDBCS(console::SEVERITY_INFO, f, __VA_ARGS__)
224+#else
225+#define TRACE_DBCS(f, ...) if(cfg_enable_debug_log) DebugPrint(console::SEVERITY_INFO, f, __VA_ARGS__)
226+#endif
227+
228+#define DEBUG_DUMMYAMP_INIT(f, ...) if(cfg_debug_dummyamp_init >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
229+#define TRACE_DUMMYAMP_INIT(f, ...) if(cfg_debug_dummyamp_init >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
230+
231+#define DEBUG_DUMMYAMP_PROC(f, ...) if(cfg_debug_dummyamp_proc >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
232+#define DEBUG_DUMMYAMP_PROC8(f, ...) if(cfg_debug_dummyamp_proc >= LOGLEVEL_WARNING) LOG_DEBUG8(f, __VA_ARGS__)
233+#define TRACE_DUMMYAMP_PROC(f, ...) if(cfg_debug_dummyamp_proc >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
234+#define TRACE_DUMMYAMP_PROC8(f, ...) if(cfg_debug_dummyamp_proc >= LOGLEVEL_ERROR) LOG_TRACE8(f, __VA_ARGS__)
235+
236+#define DEBUG_TRACK_INFO(f, ...) if(cfg_debug_track_info >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
237+#define DEBUG_TRACK_INFO8(f, ...) if(cfg_debug_track_info >= LOGLEVEL_WARNING) LOG_DEBUG8(f, __VA_ARGS__)
238+#define DEBUG_TRACK_INFO_ANSI(f, ...) if(cfg_debug_track_info >= LOGLEVEL_WARNING) LOG_DEBUG_ANSI(f, __VA_ARGS__)
239+#define TRACE_TRACK_INFO(f, ...) if(cfg_debug_track_info >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
240+#define TRACE_TRACK_INFO8(f, ...) if(cfg_debug_track_info >= LOGLEVEL_ERROR) LOG_TRACE8(f, __VA_ARGS__)
241+#define TRACE_TRACK_INFO_ANSI(f, ...) if(cfg_debug_track_info >= LOGLEVEL_ERROR) LOG_TRACE_ANSI(f, __VA_ARGS__)
242+
243+#define DEBUG_PLUGIN(f, ...) if(cfg_debug_plugin >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
244+#define TRACE_PLUGIN(f, ...) if(cfg_debug_plugin >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
245+
246+#define DEBUG_CALLBACK(f, ...) if(cfg_debug_callback >= LOGLEVEL_WARNING) LOG_DEBUG(f, __VA_ARGS__)
247+#define TRACE_CALLBACK(f, ...) if(cfg_debug_callback >= LOGLEVEL_ERROR) LOG_TRACE(f, __VA_ARGS__)
248+
249+static string_utf8_from_os g_pluginCaption8(_T(PLUGIN_CAPTION_JP));
250+static string_utf8_from_os g_pluginVersion8(_T(PLUGIN_VERSION));
251+static string_utf8_from_os g_pluginAbout8(
252+ _T(PLUGIN_CAPTION_JP) _T(" ") _T(PLUGIN_VERSION) _T("\nCopyright (C) 2006-2009 Yossiepon Oniichan, All Rights Reserved."));
253+
254+DECLARE_COMPONENT_VERSION(g_pluginCaption8, g_pluginVersion8, g_pluginAbout8);
255+
256+static string_utf8_from_os g_advancedSettingsCaption8(_T(ADVANCED_SETTINGS_CAPTION));
257+static string_utf8_from_os g_debugSettingsCaption8(_T(DEBUG_SETTINGS_CAPTION));
258+
259+static string_utf8_from_os g_menu_item(_T("Components/Mixi/mixiミュージック連携を有効にする"));
260+
261+static string_utf8_from_os g_menu_item_title(_T("mixiミュージック連携を有効にする"));
262+static string_utf8_from_os g_menu_item_description(_T("mixiミュージックへの曲情報の送信について、有効/無効を切り替えます"));
263+
264+#if IS_FB2K_VER08
265+static cfg_int cfg_use_plugin("usePlugin", 1);
266+
267+static cfg_string cfg_no_artist_name("NoArtistName", "No Artist");
268+static cfg_string cfg_no_title_name("NoTitleName", "No Title");
269+static cfg_string cfg_no_album_name("NoAlbumName", "No Title");
270+static cfg_string cfg_no_genre_name("NoGenreName", "Other");
271+
272+static cfg_string cfg_send_interval1("SendInterval1", "20");
273+static cfg_string cfg_send_interval2("SendInterval2", "66");
274+static cfg_string cfg_send_interval3("SendInterval3", "300");
275+
276+static cfg_int cfg_disable_duplicate_song("DisableDuplicateSong", 0);
277+static cfg_int cfg_media_library_registered_file_only("MediaLibraryRegisteredFileOnly", 0);
278+static cfg_int cfg_explicitly_tagged_file_only("ExplicitlyTaggedFileOnly", 0);
279+static cfg_int cfg_enable_streaming_file("EnableStreamingFile", 0);
280+
281+static cfg_int cfg_disable_dummy_mp3("DisableDummyMp3", 0);
282+static cfg_int cfg_dummy_mp3_location("DummyMp3Location", 0);
283+
284+static cfg_int cfg_show_dummyamp("ShowDummyAmp", 0);
285+static cfg_string cfg_dummyamp_title_format("DummyAmpTitleFormat", DEFAULT_DUMMYAMP_TITLE_FORMAT);
286+static cfg_string cfg_dummyamp_playlist_format("DummyAmpPlaylistFormat", DEFAULT_DUMMYAMP_TITLE_FORMAT);
287+static cfg_int cfg_disable_ansi_trans("DisableAnsiTrans", 0);
288+static cfg_int cfg_enable_ext_ipc_proc("EnableExtIpcProc", 1);
289+
290+static cfg_int cfg_enable_debug_log("EnableDebugLog", 1);
291+static cfg_int cfg_debug_dummyamp_init("DebugDummyAmpInit", 1);
292+static cfg_int cfg_debug_dummyamp_proc("DebugDummyAmpProc", 1);
293+static cfg_int cfg_debug_track_info("DebugTrackInfo", 1);
294+static cfg_int cfg_debug_plugin("DebugPlugin", 1);
295+static cfg_int cfg_debug_callback("DebugCallback", 1);
296+#elif IS_FB2K_VER09
297+// {DB051102-6DAE-4ff8-B5ED-AA06C2ACFEDE}
298+static const GUID cfg_use_plugin_guid = { 0xdb051102, 0x6dae, 0x4ff8, { 0xb5, 0xed, 0xaa, 0x6, 0xc2, 0xac, 0xfe, 0xde } };
299+static cfg_int cfg_use_plugin(cfg_use_plugin_guid, 1);
300+
301+// {1B27EDEC-A28A-4dac-96D4-1E3B51C92004}
302+static const GUID cfg_no_artist_name_guid = { 0x1b27edec, 0xa28a, 0x4dac, { 0x96, 0xd4, 0x1e, 0x3b, 0x51, 0xc9, 0x20, 0x4 } };
303+static cfg_string cfg_no_artist_name(cfg_no_artist_name_guid, "No Artist");
304+// {A8CFD50C-05EA-447d-AA74-F4C6975E750E}
305+static const GUID cfg_no_title_name_guid = { 0xa8cfd50c, 0x5ea, 0x447d, { 0xaa, 0x74, 0xf4, 0xc6, 0x97, 0x5e, 0x75, 0xe } };
306+static cfg_string cfg_no_title_name(cfg_no_title_name_guid, "No Title");
307+// {A7593537-8B09-4016-9B3C-0EF5516BBFF9}
308+static const GUID cfg_no_album_name_guid = { 0xa7593537, 0x8b09, 0x4016, { 0x9b, 0x3c, 0xe, 0xf5, 0x51, 0x6b, 0xbf, 0xf9 } };
309+static cfg_string cfg_no_album_name(cfg_no_album_name_guid, "No Title");
310+// {15774319-0CBE-45fd-B0E8-52D4728319A3}
311+static const GUID cfg_no_genre_name_guid = { 0x15774319, 0xcbe, 0x45fd, { 0xb0, 0xe8, 0x52, 0xd4, 0x72, 0x83, 0x19, 0xa3 } };
312+static cfg_string cfg_no_genre_name(cfg_no_genre_name_guid, "Other");
313+
314+// {ED0C715A-D06D-4641-A29A-AE4485A0B9EF}
315+static const GUID cfg_send_interval1_guid = { 0xed0c715a, 0xd06d, 0x4641, { 0xa2, 0x9a, 0xae, 0x44, 0x85, 0xa0, 0xb9, 0xef } };
316+static cfg_string cfg_send_interval1(cfg_send_interval1_guid, "20");
317+// {25989711-B458-4624-8A85-7304FCE799A3}
318+static const GUID cfg_send_interval2_guid = { 0x25989711, 0xb458, 0x4624, { 0x8a, 0x85, 0x73, 0x4, 0xfc, 0xe7, 0x99, 0xa3 } };
319+static cfg_string cfg_send_interval2(cfg_send_interval2_guid, "66");
320+// {4287A873-015D-44b5-A31E-34DEE1BF0525}
321+static const GUID cfg_send_interval3_guid = { 0x4287a873, 0x15d, 0x44b5, { 0xa3, 0x1e, 0x34, 0xde, 0xe1, 0xbf, 0x5, 0x25 } };
322+static cfg_string cfg_send_interval3(cfg_send_interval3_guid, "300");
323+
324+// {5C318451-2B6A-405f-814B-2795A764C1DE}
325+static const GUID cfg_disable_duplicate_song_guid = { 0x5c318451, 0x2b6a, 0x405f, { 0x81, 0x4b, 0x27, 0x95, 0xa7, 0x64, 0xc1, 0xde } };
326+static cfg_int cfg_disable_duplicate_song(cfg_disable_duplicate_song_guid, 0);
327+// {56688AED-A76D-4759-A835-A380D39D34D1}
328+static const GUID cfg_media_library_registered_file_only_guid = { 0x56688aed, 0xa76d, 0x4759, { 0xa8, 0x35, 0xa3, 0x80, 0xd3, 0x9d, 0x34, 0xd1 } };
329+static cfg_int cfg_media_library_registered_file_only(cfg_media_library_registered_file_only_guid, 0);
330+// {91E0D3D4-85DD-4c45-ADB5-7FAC6F3360CD}
331+static const GUID cfg_explicitly_tagged_file_only_guid = { 0x91e0d3d4, 0x85dd, 0x4c45, { 0xad, 0xb5, 0x7f, 0xac, 0x6f, 0x33, 0x60, 0xcd } };
332+static cfg_int cfg_explicitly_tagged_file_only(cfg_explicitly_tagged_file_only_guid, 0);
333+// {F4E85669-6EEF-4b75-AFC1-7964AEBE10B0}
334+static const GUID cfg_enable_streaming_file_guid = { 0xf4e85669, 0x6eef, 0x4b75, { 0xaf, 0xc1, 0x79, 0x64, 0xae, 0xbe, 0x10, 0xb0 } };
335+static cfg_int cfg_enable_streaming_file(cfg_enable_streaming_file_guid, 0);
336+
337+// {67341E11-A385-45d8-9DE6-B1FABA35AC62}
338+static const GUID cfg_disable_dummy_mp3_guid = { 0x67341e11, 0xa385, 0x45d8, { 0x9d, 0xe6, 0xb1, 0xfa, 0xba, 0x35, 0xac, 0x62 } };
339+static cfg_int cfg_disable_dummy_mp3(cfg_disable_dummy_mp3_guid, 0);
340+// {87D4D72C-43AB-42ab-8CAC-D689961DA5EA}
341+static const GUID cfg_dummy_mp3_location_guid = { 0x87d4d72c, 0x43ab, 0x42ab, { 0x8c, 0xac, 0xd6, 0x89, 0x96, 0x1d, 0xa5, 0xea } };
342+static cfg_int cfg_dummy_mp3_location(cfg_dummy_mp3_location_guid, 0);
343+
344+// {F9DB10F0-1A01-40dd-A342-486A6CB596E7}
345+static const GUID cfg_show_dummyamp_guid = { 0xf9db10f0, 0x1a01, 0x40dd, { 0xa3, 0x42, 0x48, 0x6a, 0x6c, 0xb5, 0x96, 0xe7 } };
346+static cfg_int cfg_show_dummyamp(cfg_show_dummyamp_guid, 0);
347+// {CC7785CA-B019-4107-9115-161A543B3952}
348+static const GUID cfg_dummyamp_title_format_guid = { 0xcc7785ca, 0xb019, 0x4107, { 0x91, 0x15, 0x16, 0x1a, 0x54, 0x3b, 0x39, 0x52 } };
349+static cfg_string cfg_dummyamp_title_format(cfg_dummyamp_title_format_guid, DEFAULT_DUMMYAMP_TITLE_FORMAT);
350+// {B964EB32-4957-4e7a-81B5-E89B4405AAAD}
351+static const GUID cfg_dummyamp_playlist_format_guid = { 0xb964eb32, 0x4957, 0x4e7a, { 0x81, 0xb5, 0xe8, 0x9b, 0x44, 0x5, 0xaa, 0xad } };
352+static cfg_string cfg_dummyamp_playlist_format(cfg_dummyamp_title_format_guid, DEFAULT_DUMMYAMP_TITLE_FORMAT);
353+
354+// {094571BA-1484-455c-9D6E-E18B13296149}
355+static const GUID cfg_disable_ansi_trans_guid = { 0x94571ba, 0x1484, 0x455c, { 0x9d, 0x6e, 0xe1, 0x8b, 0x13, 0x29, 0x61, 0x49 } };
356+static cfg_int cfg_disable_ansi_trans(cfg_disable_ansi_trans_guid, 0);
357+// {8961A829-F010-461c-9CC8-C06308BFA4A2}
358+static const GUID cfg_enable_ext_ipc_proc_guid = { 0x8961a829, 0xf010, 0x461c, { 0x9c, 0xc8, 0xc0, 0x63, 0x8, 0xbf, 0xa4, 0xa2 } };
359+static cfg_int cfg_enable_ext_ipc_proc(cfg_enable_ext_ipc_proc_guid, 1);
360+
361+// {3B6B73F9-F6AF-4b6c-8015-E73A1B87AD5C}
362+static const GUID cfg_enable_debug_log_guid = { 0x3b6b73f9, 0xf6af, 0x4b6c, { 0x80, 0x15, 0xe7, 0x3a, 0x1b, 0x87, 0xad, 0x5c } };
363+static cfg_int cfg_enable_debug_log(cfg_enable_debug_log_guid, 1); // debug log enabled
364+// {0BF3522F-BC55-4f77-AA95-B02F6E159544}
365+static const GUID cfg_debug_dummyamp_init_guid = { 0xbf3522f, 0xbc55, 0x4f77, { 0xaa, 0x95, 0xb0, 0x2f, 0x6e, 0x15, 0x95, 0x44 } };
366+static cfg_int cfg_debug_dummyamp_init(cfg_debug_dummyamp_init_guid, 1); // debug level
367+// {D1256573-7560-41db-A781-9985AE50CE07}
368+static const GUID cfg_debug_dummyamp_proc_guid = { 0xd1256573, 0x7560, 0x41db, { 0xa7, 0x81, 0x99, 0x85, 0xae, 0x50, 0xce, 0x7 } };
369+static cfg_int cfg_debug_dummyamp_proc(cfg_debug_dummyamp_proc_guid, 1); // debug level
370+// {0A7E2CAE-905F-4ecb-A82D-8DD853FBFFF3}
371+static const GUID cfg_debug_track_info_guid = { 0xa7e2cae, 0x905f, 0x4ecb, { 0xa8, 0x2d, 0x8d, 0xd8, 0x53, 0xfb, 0xff, 0xf3 } };
372+static cfg_int cfg_debug_track_info(cfg_debug_track_info_guid, 1); // debug level
373+// {67A78DB7-3591-4416-84FC-96436082B619}
374+static const GUID cfg_debug_plugin_guid = { 0x67a78db7, 0x3591, 0x4416, { 0x84, 0xfc, 0x96, 0x43, 0x60, 0x82, 0xb6, 0x19 } };
375+static cfg_int cfg_debug_plugin(cfg_debug_plugin_guid, 1); // debug level
376+// {DBED8400-527F-4b98-9227-2C0BA95B3206}
377+static const GUID cfg_debug_callback_guid = { 0xdbed8400, 0x527f, 0x4b98, { 0x92, 0x27, 0x2c, 0xb, 0xa9, 0x5b, 0x32, 0x6 } };
378+static cfg_int cfg_debug_callback(cfg_debug_callback_guid, 1); // debug level
379+#endif
380+
381+class TrackInfo
382+{
383+public:
384+ std::string m_nullStr;
385+
386+ StringMap m_infoMap8;
387+ StringMap m_infoMapAnsi;
388+
389+ UIntMap m_infoMapNum;
390+
391+ TrackInfo() {
392+ }
393+
394+ TrackInfo(const TrackInfo &other)
395+ : m_infoMap8(other.m_infoMap8)
396+ , m_infoMapAnsi(other.m_infoMapAnsi)
397+ , m_infoMapNum(other.m_infoMapNum) {
398+ }
399+
400+ ~TrackInfo() {
401+ }
402+
403+ TrackInfo &operator =(const TrackInfo &other)
404+ {
405+ TrackInfo temp(other);
406+ swap(temp);
407+
408+ return *this;
409+ }
410+
411+ void show_map(StringMap &map, bool bAnsi = false)
412+ {
413+ StringMapCIt beginIt(map.begin()), endIt(map.end()), it;
414+
415+ for(it = beginIt; it != endIt; it ++) {
416+
417+ if(bAnsi) {
418+ TRACE_TRACK_INFO_ANSI("show_map_ansi: [%s, %s]", it->first.c_str(), it->second.c_str());
419+ } else {
420+ TRACE_TRACK_INFO8("show_map8: [%s, %s]", it->first.c_str(), it->second.c_str());
421+ }
422+ }
423+ }
424+
425+ void swap(TrackInfo &other)
426+ {
427+ m_infoMap8.swap(other.m_infoMap8);
428+ m_infoMapAnsi.swap(other.m_infoMapAnsi);
429+ m_infoMapNum.swap(other.m_infoMapNum);
430+ }
431+
432+ void clear()
433+ {
434+ TRACE_TRACK_INFO(_T("TRACK_INFO::clear - called."));
435+
436+ m_infoMap8.clear();
437+ m_infoMapAnsi.clear();
438+ m_infoMapNum.clear();
439+ }
440+
441+ bool isEmpty() const { return m_infoMap8.empty() & m_infoMapNum.empty(); }
442+
443+public:
444+
445+#if IS_FB2K_VER08
446+ void setStrings(const Strings &keys, metadb_handle * track)
447+#elif IS_FB2K_VER09
448+ void setStrings(const Strings &keys, metadb_handle_ptr track)
449+#endif
450+ {
451+ TRACE_TRACK_INFO(_T("TrackInfo::setStrings - called."));
452+
453+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
454+
455+ for(it = beginIt; it != endIt; it ++) {
456+
457+ string8 info8;
458+
459+#if IS_FB2K_VER08
460+ track->handle_format_title(info8, it->c_str(), 0);
461+#elif IS_FB2K_VER09
462+ service_ptr_t<titleformat_object> titleformat;
463+
464+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
465+ track->format_title(NULL, info8, titleformat, 0);
466+#endif
467+// DEBUG_TRACK_INFO8("TrackInfo::setStrings - %s: %s", it->c_str(), (LPCSTR)info8);
468+
469+ putString(it->c_str(), (LPCSTR)info8);
470+ }
471+ }
472+
473+ void setDynamicStrings(const Strings &keys)
474+ {
475+ TRACE_TRACK_INFO(_T("TrackInfo::setDynamicStrings - called."));
476+
477+#if IS_FB2K_VER08
478+ metadb_handle *track = play_control::get()->get_now_playing();
479+#elif IS_FB2K_VER09
480+ metadb_handle_ptr track;
481+ static_api_ptr_t<playback_control>()->get_now_playing(track);
482+#endif
483+
484+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
485+
486+ for(it = beginIt; it != endIt; it ++) {
487+
488+ string8 info8;
489+
490+#if IS_FB2K_VER08
491+ play_control::get()->playback_format_title_ex(track, info8, it->c_str(), NULL, false, true);
492+#elif IS_FB2K_VER09
493+ service_ptr_t<titleformat_object> titleformat;
494+
495+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
496+ static_api_ptr_t<playback_control>()->playback_format_title_ex(track, NULL, info8, titleformat, NULL, play_control::display_level_titles);
497+#endif
498+// DEBUG_TRACK_INFO8("TrackInfo::setDynamicStrings - %s: %s", it->c_str(), (LPCSTR)info8);
499+
500+ const std::string &oldValue = getString(*it);
501+
502+ if((::lstrcmpA(info8, "?") != 0) || (oldValue.length() == 0))
503+ {
504+ putString(it->c_str(), (LPCSTR)info8);
505+ }
506+ }
507+
508+#if IS_FB2K_VER08
509+ if(track) {
510+ track->handle_release();
511+ }
512+#endif
513+ }
514+
515+ void setPlaylistStrings(const Strings &keys)
516+ {
517+ TRACE_TRACK_INFO(_T("TrackInfo::setPlaylistStrings - called."));
518+
519+#if IS_FB2K_VER08
520+ int track_index;
521+ track_index = playlist_oper::get()->get_now_playing();
522+#elif IS_FB2K_VER09
523+ t_size playlist_index, track_index;
524+ static_api_ptr_t<playlist_manager>()->get_playing_item_location(&playlist_index, &track_index);
525+#endif
526+
527+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
528+
529+ for(it = beginIt; it != endIt; it ++) {
530+
531+ string8 info8;
532+
533+#if IS_FB2K_VER08
534+ playlist_oper::get()->format_title(track_index, info8, it->c_str(), NULL);
535+#elif IS_FB2K_VER09
536+ service_ptr_t<titleformat_object> titleformat;
537+
538+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
539+ static_api_ptr_t<playlist_manager>()->playlist_item_format_title(playlist_index, track_index,
540+ NULL, info8, titleformat, NULL, play_control::display_level_titles);
541+#endif
542+// DEBUG_TRACK_INFO8("TrackInfo::setPlaylistStrings - %s: %s", it->c_str(), (LPCSTR)info8);
543+
544+ putString(it->c_str(), (LPCSTR)info8);
545+ }
546+ }
547+
548+#if IS_FB2K_VER08
549+ void setNumbers(const Strings &keys, metadb_handle * track)
550+#elif IS_FB2K_VER09
551+ void setNumbers(const Strings &keys, metadb_handle_ptr track)
552+#endif
553+ {
554+ TRACE_TRACK_INFO(_T("TrackInfo::setNumbers - called."));
555+
556+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
557+
558+ for(it = beginIt; it != endIt; it ++) {
559+
560+ string8 info8;
561+
562+#if IS_FB2K_VER08
563+ track->handle_format_title(info8, it->c_str(), 0);
564+#elif IS_FB2K_VER09
565+ service_ptr_t<titleformat_object> titleformat;
566+
567+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
568+ track->format_title(NULL, info8, titleformat, 0);
569+#endif
570+// DEBUG_TRACK_INFO8("TrackInfo::setNumbers - %s: %s", it->c_str(), (LPCSTR)info8);
571+
572+ putNumber(it->c_str(), static_cast<UINT>(::atol(info8)) );
573+ }
574+ }
575+
576+ void setDynamicNumbers(const Strings &keys)
577+ {
578+ TRACE_TRACK_INFO(_T("TrackInfo::setDynamicNumbers - called."));
579+
580+#if IS_FB2K_VER08
581+ metadb_handle *track = play_control::get()->get_now_playing();
582+#elif IS_FB2K_VER09
583+ metadb_handle_ptr track;
584+ static_api_ptr_t<playback_control>()->get_now_playing(track);
585+#endif
586+
587+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
588+
589+ for(it = beginIt; it != endIt; it ++) {
590+
591+ string8 info8;
592+
593+#if IS_FB2K_VER08
594+ play_control::get()->playback_format_title_ex(track, info8, it->c_str(), NULL, false, true);
595+#elif IS_FB2K_VER09
596+ service_ptr_t<titleformat_object> titleformat;
597+
598+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
599+ static_api_ptr_t<playback_control>()->playback_format_title_ex(track, NULL, info8, titleformat, NULL, play_control::display_level_titles);
600+#endif
601+// DEBUG_TRACK_INFO8("TrackInfo::setDynamicNumbers - %s: %s", it->c_str(), (LPCSTR)info8);
602+
603+ UINT newValue = static_cast<UINT>(::atol(info8));
604+ UINT oldValue = getNumber(*it);
605+
606+ if((newValue != 0) || (oldValue == 0)) {
607+ putNumber(it->c_str(), newValue);
608+ }
609+ }
610+
611+#if IS_FB2K_VER08
612+ if(track) {
613+ track->handle_release();
614+ }
615+#endif
616+ }
617+
618+ void setPlaylistNumbers(const Strings &keys)
619+ {
620+ TRACE_TRACK_INFO(_T("TrackInfo::setPlaylistNumbers - called."));
621+
622+#if IS_FB2K_VER08
623+ int track_index;
624+ track_index = playlist_oper::get()->get_now_playing();
625+#elif IS_FB2K_VER09
626+ t_size playlist_index, track_index;
627+ static_api_ptr_t<playlist_manager>()->get_playing_item_location(&playlist_index, &track_index);
628+#endif
629+
630+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
631+
632+ for(it = beginIt; it != endIt; it ++) {
633+
634+ string8 info8;
635+
636+#if IS_FB2K_VER08
637+ playlist_oper::get()->format_title(track_index, info8, it->c_str(), NULL);
638+#elif IS_FB2K_VER09
639+ service_ptr_t<titleformat_object> titleformat;
640+
641+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, it->c_str());
642+ static_api_ptr_t<playlist_manager>()->playlist_item_format_title(playlist_index, track_index,
643+ NULL, info8, titleformat, NULL, play_control::display_level_titles);
644+#endif
645+// DEBUG_TRACK_INFO8("TrackInfo::setPlaylistNumbers - %s: %s", it->c_str(), (LPCSTR)info8);
646+
647+ putNumber(it->c_str(), static_cast<UINT>(::atol(info8)) );
648+ }
649+ }
650+
651+ void putString(const std::string &key, const std::string &value)
652+ {
653+ DEBUG_TRACK_INFO8("TrackInfo::putString - %s: %s", key.c_str(), value.c_str());
654+
655+ insert(m_infoMap8, key.c_str(), value.c_str());
656+
657+ string_ansi_from_utf8 valueAnsi(value.c_str());
658+
659+ insert(m_infoMapAnsi, key.c_str(), (LPCSTR)valueAnsi, true);
660+ }
661+
662+ void putNumber(const std::string &key, UINT value)
663+ {
664+ DEBUG_TRACK_INFO8("TrackInfo::putNumber - %s: %u", key.c_str(), value);
665+
666+ insert(m_infoMapNum, key.c_str(), value);
667+ }
668+
669+ const std::string &getString(const std::string &key, bool bForceUTF8 = false) const {
670+
671+ if((bForceUTF8 == true) || (cfg_disable_ansi_trans == 1))
672+ {
673+ StringMapCIt it(m_infoMap8.find(key)), endIt(m_infoMap8.end());
674+
675+ if(it == endIt) {
676+ return m_nullStr;
677+ }
678+
679+ return it->second;
680+ }
681+ else
682+ {
683+ StringMapCIt it(m_infoMapAnsi.find(key)), endIt(m_infoMapAnsi.end());
684+
685+ if(it == endIt) {
686+ return m_nullStr;
687+ }
688+
689+ return it->second;
690+ }
691+ }
692+
693+ const UINT getNumber(const std::string &key) const {
694+
695+ UIntMapCIt it(m_infoMapNum.find(key)), endIt(m_infoMapNum.end());
696+
697+ if(it == endIt) {
698+ return 0;
699+ }
700+
701+ return it->second;
702+ }
703+
704+ void removeStrings(const Strings &keys)
705+ {
706+ TRACE_TRACK_INFO(_T("TrackInfo::removeStrings - called."));
707+
708+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
709+
710+ for(it = beginIt; it != endIt; it ++) {
711+ removeString(*it);
712+ }
713+ }
714+
715+ void removeString(const std::string &key)
716+ {
717+ TRACE_TRACK_INFO8("TrackInfo::removeString - %s", key.c_str());
718+
719+ m_infoMap8.erase(m_infoMap8.find(key));
720+ m_infoMapAnsi.erase(m_infoMapAnsi.find(key));
721+ }
722+
723+ void removeNumbers(const Strings &keys)
724+ {
725+ TRACE_TRACK_INFO(_T("TrackInfo::removeNumbers - called."));
726+
727+ StringsCIt beginIt(keys.begin()), endIt(keys.end()), it;
728+
729+ for(it = beginIt; it != endIt; it ++) {
730+ removeNumber(*it);
731+ }
732+ }
733+
734+ void removeNumber(const std::string &key)
735+ {
736+ TRACE_TRACK_INFO8("TrackInfo::removeNumber - %s", key.c_str());
737+
738+ m_infoMapNum.erase(m_infoMapNum.find(key));
739+ }
740+
741+protected:
742+
743+ static void insert(StringMap &map, LPCSTR pKey, LPCSTR pValue, bool bAnsi = false)
744+ {
745+#if 0
746+ if(bAnsi) {
747+ TRACE_TRACK_INFO_ANSI("insertAnsi: [%s, %s]", pKey, pValue);
748+ } else {
749+ TRACE_TRACK_INFO8("insert8: [%s, %s]", pKey, pValue);
750+ }
751+#endif
752+
753+ map.insert(std::make_pair(pKey, pValue));
754+ }
755+
756+ static void insert(UIntMap &map, LPCSTR pKey, UINT value)
757+ {
758+// TRACE_TRACK_INFO8("insertNum: [%s, %u]", pKey, value);
759+
760+ map.insert(std::make_pair(pKey, value));
761+ }
762+};
763+
764+class PathInfo
765+{
766+ protected:
767+ PathInfo() {
768+ }
769+
770+ public:
771+ static tstring getFB2Kpath()
772+ {
773+ TCHAR modulePath[_MAX_PATH], moduleDrive[_MAX_DRIVE], moduleDir[_MAX_DIR];
774+ TCHAR returnPath[_MAX_PATH];
775+
776+ ::GetModuleFileName(NULL, modulePath, _MAX_PATH);
777+ ::_tsplitpath_s(modulePath, moduleDrive, _MAX_DRIVE, moduleDir, _MAX_DIR, NULL, 0, NULL, 0);
778+ ::_tmakepath_s(returnPath, _MAX_PATH, moduleDrive, moduleDir, NULL, NULL);
779+
780+ return tstring(returnPath);
781+ }
782+
783+ static tstring getFB2KComponentsPath() {
784+ return getFB2Kpath() + FB2K_COMPONENTS_DIR;
785+ }
786+
787+ static std::string getGenMixiDefaultPath()
788+ {
789+ string_utf8_from_os path(getFB2KComponentsPath().c_str());
790+ return (LPCSTR)path;
791+ }
792+
793+ static tstring getMixiStationAppPath() {
794+ return getSpecialFolderPath(CSIDL_APPDATA, FALSE) + APPDATA_MIXI_STATION_DIR;
795+ }
796+
797+ static tstring getFooMixiPlayInfoPath()
798+ {
799+ switch(cfg_dummy_mp3_location)
800+ {
801+ case 1:
802+ return getTemporaryFolderPath();
803+
804+ case 2:
805+ return getFB2KComponentsPath() ;
806+
807+ case 0:
808+ default:
809+ return getMixiStationAppPath() + _T("\\");
810+ }
811+ }
812+
813+ static tstring getDummyPlayInfoMp3Path() {
814+ return getFooMixiPlayInfoPath() + DUMMY_MP3_FILE_NAME;
815+ }
816+
817+ static tstring splitPath(const string8 &srcPath)
818+ {
819+ string_os_from_utf8 srcPathOs(srcPath);
820+ return splitPath(srcPathOs);
821+ }
822+
823+ static tstring splitPath(LPCTSTR srcPath)
824+ {
825+ TCHAR drive[_MAX_DRIVE], dir[_MAX_DIR], dstPath[_MAX_PATH];
826+ ::_tsplitpath_s(srcPath, drive, _MAX_DRIVE, dir, _MAX_DIR, NULL, 0, NULL, 0);
827+ ::_tmakepath_s(dstPath, _MAX_PATH, drive, dir, NULL, NULL);
828+ return dstPath;
829+ }
830+
831+ //! get the special folder path
832+ static tstring getSpecialFolderPath(int nFolder, BOOL bCreate)
833+ {
834+ tstring resStr;
835+ HRESULT hr = NO_ERROR;
836+
837+ IMalloc *pMalloc = 0;
838+ ITEMIDLIST *pItemID = 0;
839+ TCHAR folderPath[MAX_PATH];
840+
841+ folderPath[0] = _T('\0');
842+ hr = SHGetMalloc(&pMalloc);
843+
844+ if(hr == NO_ERROR)
845+ {
846+ hr = SHGetSpecialFolderLocation(0, nFolder, &pItemID);
847+
848+ if(hr == NO_ERROR)
849+ {
850+ if(SHGetPathFromIDList(pItemID, folderPath) == FALSE)
851+ hr = GetLastError();
852+
853+ pMalloc->Free(pItemID);
854+ }
855+
856+ pMalloc->Release();
857+ }
858+
859+ resStr = folderPath;
860+
861+ if(hr != NO_ERROR)
862+ {
863+ return _T("");
864+ }
865+
866+ return resStr;
867+ }
868+
869+ //! get the temporary folder path
870+ static tstring getTemporaryFolderPath() {
871+
872+ TCHAR strTempPath[MAX_PATH];
873+ ::GetTempPath(MAX_PATH, strTempPath);
874+
875+ return strTempPath;
876+ }
877+};
878+
879+#if IS_FB2K_VER08
880+static cfg_string cfg_gen_mixi_path("GenMixiPath", PathInfo::getGenMixiDefaultPath().c_str());
881+#elif IS_FB2K_VER09
882+// {1EC28435-C243-483c-81EC-E0E57A96727E}
883+static const GUID cfg_gen_mixi_path_guid = { 0x1ec28435, 0xc243, 0x483c, { 0x81, 0xec, 0xe0, 0xe5, 0x7a, 0x96, 0x72, 0x7e } };
884+static cfg_string cfg_gen_mixi_path(cfg_gen_mixi_path_guid, PathInfo::getGenMixiDefaultPath().c_str());
885+#endif
886+
887+class PlayInfo
888+{
889+ public:
890+
891+ enum EPlayStatus
892+ {
893+ PLAY_STOP = 0,
894+ PLAY_START = 1,
895+ PLAY_PAUSE = 3
896+ };
897+
898+ public:
899+
900+ PlayInfo() :
901+ m_playStatus(PLAY_STOP),
902+ m_isResentMode(false),
903+ m_playLength(0),
904+ m_playPosition(0),
905+ m_playCount(0),
906+ m_isPlayInfoMp3Available(false),
907+ m_resetBasePosition(0) {
908+ }
909+
910+ public:
911+
912+ void setPlayStatusStart() {
913+ setPlayStatus(PLAY_START);
914+ }
915+
916+ void setPlayStatusStop() {
917+ setPlayStatus(PLAY_STOP);
918+ }
919+
920+ void setPlayStatusPause() {
921+ setPlayStatus(PLAY_PAUSE);
922+ }
923+
924+ void clearPlayInfo(bool isResentMode = true)
925+ {
926+ setPlayStatusStop();
927+ m_isResentMode = isResentMode;
928+ setPlayPosition(0);
929+ setPlayLength(0);
930+ setPlayInfoMp3Available(false);
931+ m_resetBasePosition = 0;
932+ }
933+
934+ void setResentMode(bool bIncrementCounter = true)
935+ {
936+ if(bIncrementCounter) {
937+ incrementPlayCount();
938+ }
939+ m_isResentMode = true;
940+ m_resetBasePosition = m_playPosition;
941+ }
942+
943+ void clearResentMode() {
944+ m_isResentMode = false;
945+ }
946+
947+ void incrementPlayCount() {
948+ setPlayCount(getPlayCount() + 1);
949+ }
950+
951+ public:
952+
953+ EPlayStatus getPlayStatus() const
954+ {
955+ if((m_playStatus == PLAY_START) && m_isResentMode) {
956+ return PLAY_STOP;
957+ }
958+ return m_playStatus;
959+ }
960+
961+ void setPlayStatus(EPlayStatus status) {
962+ m_playStatus = status;
963+ }
964+
965+ int getPlayPosition() const
966+ {
967+ if(m_resetBasePosition > 0) {
968+ return m_playPosition - m_resetBasePosition;
969+ }
970+ return m_playPosition;
971+ }
972+
973+ void setPlayPosition(int pos) {
974+ m_playPosition = pos;
975+ }
976+
977+ int getPlayLength() const
978+ {
979+#if FORCE_RESENT_MODE == 0
980+ if(m_resetBasePosition > 0) {
981+#else
982+ if(true) {
983+#endif
984+ return 0;
985+ }
986+ return m_playLength;
987+ }
988+
989+ void setPlayLength(int len) {
990+ m_playLength = len;
991+ }
992+
993+ int getPlayCount() const {
994+ return m_playCount;
995+ }
996+
997+ void setPlayCount(int count) {
998+ m_playCount = count;
999+ }
1000+
1001+ bool isPlayInfoMp3Available() const {
1002+ return m_isPlayInfoMp3Available;
1003+ }
1004+
1005+ void setPlayInfoMp3Available(bool isAvailable) {
1006+ m_isPlayInfoMp3Available = isAvailable;
1007+ }
1008+
1009+ void setPlayInfoMp3Path(LPCSTR path)
1010+ {
1011+#if 0
1012+ m_playInfoMp3Path = path;
1013+
1014+ string_utf8_from_os path8(path);
1015+
1016+ if(cfg_disable_ansi_trans == 1)
1017+ {
1018+
1019+ m_playInfoMp3Path8 = path8;
1020+ }
1021+ else
1022+ {
1023+ string_ansi_from_utf8 pathAnsi(path8);
1024+
1025+ m_playInfoMp3Path8 = pathAnsi;
1026+ }
1027+#else
1028+ m_playInfoMp3Path8 = path;
1029+#endif
1030+ }
1031+
1032+ const string8 &getPlayInfoMp3Path8() const {
1033+ return m_playInfoMp3Path8;
1034+ }
1035+
1036+ bool isResentMode() const {
1037+ return m_isResentMode;
1038+ }
1039+
1040+ protected:
1041+
1042+ EPlayStatus m_playStatus;
1043+
1044+ int m_playLength;
1045+ int m_playPosition;
1046+ int m_playCount;
1047+
1048+ bool m_isPlayInfoMp3Available;
1049+ bool m_isResentMode;
1050+ int m_resetBasePosition;
1051+
1052+ string8 m_playInfoMp3Path8;
1053+};
1054+
1055+class id3Info
1056+{
1057+ public:
1058+
1059+ typedef std::vector<UINT16> UInt16Array;
1060+
1061+ id3Info(const TrackInfo & info) : m_info(info), m_hMp3File(INVALID_HANDLE_VALUE) {
1062+ }
1063+
1064+ ~id3Info() {
1065+ close();
1066+ }
1067+
1068+ DWORD write(LPCTSTR path) {
1069+
1070+ string_wide_from_utf8 title_utf16(m_info.getString(FORMAT_TRACKTITLE, true).c_str());
1071+ string_wide_from_utf8 artist_utf16(m_info.getString(FORMAT_ARTIST, true).c_str());
1072+ string_wide_from_utf8 album_utf16(m_info.getString(FORMAT_ALBUMTITLE, true).c_str());
1073+ string_wide_from_utf8 genre_utf16(m_info.getString(FORMAT_GENRE, true).c_str());
1074+
1075+ DWORD dwErr = S_OK;
1076+
1077+ if((dwErr = open(path)) != S_OK) {
1078+ return dwErr;
1079+ }
1080+
1081+ UInt16Array title = makeTextFrame("TIT2", makeUTF16LE(title_utf16));
1082+ UInt16Array album = makeTextFrame("TALB", makeUTF16LE(album_utf16));
1083+ UInt16Array artist = makeTextFrame("TPE1", makeUTF16LE(artist_utf16));
1084+ UInt16Array genre = makeTextFrame("TCON", makeUTF16LE(genre_utf16));
1085+
1086+ dwErr = writeHeader(static_cast<UINT32>(
1087+ title.size()*2 + album.size()*2 + artist.size()*2 + genre.size()*2 + 4));
1088+ // add charset code size (4bytes)
1089+
1090+ if(dwErr == S_OK) {
1091+ dwErr = writeTextFrame(title);
1092+ }
1093+
1094+ if(dwErr == S_OK) {
1095+ dwErr = writeTextFrame(album);
1096+ }
1097+
1098+ if(dwErr == S_OK) {
1099+ dwErr = writeTextFrame(artist);
1100+ }
1101+
1102+ if(dwErr == S_OK) {
1103+ dwErr = writeTextFrame(genre);
1104+ }
1105+
1106+ close();
1107+
1108+ return dwErr;
1109+ }
1110+
1111+ protected:
1112+
1113+ DWORD open(LPCTSTR path)
1114+ {
1115+ close();
1116+
1117+ // open dummy mp3 file
1118+ m_hMp3File = ::CreateFile(
1119+ path, GENERIC_WRITE, 0, NULL,
1120+ TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
1121+ );
1122+
1123+ if(m_hMp3File == INVALID_HANDLE_VALUE)
1124+ {
1125+ return ::GetLastError();
1126+ }
1127+
1128+ return S_OK;
1129+ }
1130+
1131+ UInt16Array makeUTF16LE(const string_wide_from_utf8 &str) {
1132+
1133+ LPCWSTR pStr = str.get_ptr();
1134+ size_t len = ::lstrlenW(pStr);
1135+ UInt16Array utf16(len + 2);
1136+
1137+ utf16[0] = 0xfeff; // BOM
1138+ ::CopyMemory(&utf16[1], str.get_ptr(), len * 2);
1139+
1140+ // swap byte order (big endian to little endian);
1141+ for(size_t i = 0; i < len + 1; i++) {
1142+ utf16[i] = (utf16[i] << 8) | (utf16[i] >> 8);
1143+ }
1144+
1145+ utf16[len + 1] = 0; // add NULL character
1146+
1147+ return utf16;
1148+ }
1149+
1150+ UInt16Array makeTextFrame(LPCSTR pFrameID, const UInt16Array &data) {
1151+
1152+ UInt16Array frame(data.size() + 5);
1153+
1154+ UINT32 size = static_cast<UINT32>(data.size() * 2 + 1); // add charset code size (1byte)
1155+
1156+ const UCHAR *pUCFrameID = reinterpret_cast<const UCHAR *>(pFrameID);
1157+ const UCHAR *pUCSize = reinterpret_cast<const UCHAR *>(&size);
1158+
1159+ frame[0] = ((UINT16)pUCFrameID[1]) << 8 | pUCFrameID[0];
1160+ frame[1] = ((UINT16)pUCFrameID[3]) << 8 | pUCFrameID[2];
1161+
1162+ frame[2] = ((UINT16)pUCSize[2]) << 8 | pUCSize[3];
1163+ frame[3] = ((UINT16)pUCSize[0]) << 8 | pUCSize[1];
1164+
1165+ frame[4] = 0; // frame flag
1166+
1167+ ::CopyMemory(&frame[5], &data[0], data.size() * 2);
1168+
1169+ return frame;
1170+ }
1171+
1172+ void close() {
1173+ if(m_hMp3File != INVALID_HANDLE_VALUE) {
1174+ ::CloseHandle(m_hMp3File);
1175+ m_hMp3File = INVALID_HANDLE_VALUE;
1176+ }
1177+ }
1178+
1179+ DWORD writeHeader(UINT32 size)
1180+ {
1181+ UInt16Array header(5);
1182+
1183+ header[0] = ((UINT16)'D') << 8 | (UCHAR)'I';
1184+ header[1] = ((UINT16) 3 ) << 8 | (UCHAR)'3';
1185+
1186+ header[2] = 0;
1187+
1188+ UInt16Array length = makeLength(size);
1189+
1190+ header[3] = length[0];
1191+ header[4] = length[1];
1192+
1193+ DWORD dwSize;
1194+ if(!::WriteFile(m_hMp3File, &header[0], 10, &dwSize, NULL)) {
1195+ return ::GetLastError();
1196+ }
1197+
1198+ return S_OK;
1199+ }
1200+
1201+ DWORD writeTextFrame(const UInt16Array &packet)
1202+ {
1203+ DWORD dwErr = S_OK;
1204+
1205+ UCHAR charsetCode = 0x01; // UNICODE
1206+
1207+ DWORD dwSize;
1208+ if(!::WriteFile(m_hMp3File, &packet[0], 10, &dwSize, NULL)) {
1209+ return ::GetLastError();
1210+ }
1211+ if(!::WriteFile(m_hMp3File, &charsetCode, 1, &dwSize, NULL)) {
1212+ return ::GetLastError();
1213+ }
1214+ if(!::WriteFile(m_hMp3File, &packet[5], static_cast<DWORD>(packet.size() * 2 - 10), &dwSize, NULL)) {
1215+ return ::GetLastError();
1216+ }
1217+
1218+ return S_OK;
1219+ }
1220+
1221+ UInt16Array makeLength(UINT32 size)
1222+ {
1223+ UInt16Array length(2);
1224+ UCHAR sizes[4];
1225+
1226+ /*
1227+ 00001111111111111111111111111111
1228+
1229+ 1111111000000000000000000000
1230+ f e 0 0 0 0 0
1231+ 111111100000000000000
1232+ 1 f c 0 0 0
1233+ 11111110000000
1234+ 3 f 8 0
1235+ 1111111
1236+ 7 f
1237+ */
1238+
1239+ sizes[3] = static_cast<UCHAR>((size & 0x0000007f) >> 0);
1240+ sizes[2] = static_cast<UCHAR>((size & 0x00003f80) >> 7);
1241+ sizes[1] = static_cast<UCHAR>((size & 0x001fc000) >> 14);
1242+ sizes[0] = static_cast<UCHAR>((size & 0x0fe00000) >> 21);
1243+
1244+
1245+ length[0] = ((UINT16)sizes[1]) << 8 | sizes[0];
1246+ length[1] = ((UINT16)sizes[3]) << 8 | sizes[2];
1247+
1248+ return length;
1249+ }
1250+
1251+ protected:
1252+
1253+ TrackInfo m_info;
1254+ HANDLE m_hMp3File;
1255+};
1256+
1257+class DummyAmp
1258+{
1259+ public:
1260+
1261+ DummyAmp()
1262+ : m_bReady(false)
1263+ , m_hInstGenMixi((HINSTANCE)INVALID_HANDLE_VALUE)
1264+ , m_pGenMixi(NULL)
1265+ , m_hWinampWnd((HWND)INVALID_HANDLE_VALUE)
1266+ , m_GETPLAYLISTFILE_time(0)
1267+ , m_hDirChangeNotify((HANDLE)INVALID_HANDLE_VALUE)
1268+ , m_isDummyPlayInfoMp3Available(false)
1269+ , m_isAnotherWinampWindowAvailable(false)
1270+ {
1271+
1272+ m_winampTitle = _T("Winamp");
1273+ }
1274+
1275+ ~DummyAmp()
1276+ {
1277+ release();
1278+ destroyWindow();
1279+ closeDirChangeNotifyHandle();
1280+ }
1281+
1282+ public:
1283+
1284+ static DummyAmp *getInstance()
1285+ {
1286+ if(m_pMe == NULL)
1287+ {
1288+ m_pMe = new DummyAmp();
1289+ }
1290+
1291+ return m_pMe;
1292+ }
1293+
1294+ void load()
1295+ {
1296+ TRACE_DUMMYAMP_INIT(_T("DummyAmp::load - called."));
1297+
1298+ // initialize gen_mixi_for_winamp
1299+ initGenMixi();
1300+
1301+ // initialize dummy mp3 file, if dummy mp3 is enabled
1302+ if(cfg_disable_dummy_mp3 == 0) {
1303+ initDummyMp3();
1304+ }
1305+
1306+ // set ready flag, if initialization successfully done
1307+ if( (getGenMixi() != NULL) && ((cfg_disable_dummy_mp3 == 0) || (isDummyPlayInfoMp3Available() == true)) ){
1308+ setReady(true);
1309+ }
1310+ }
1311+
1312+ void config()
1313+ {
1314+ TRACE_DUMMYAMP_INIT(_T("DummyAmp::config - called."));
1315+
1316+ if(getGenMixi() != NULL) {
1317+ getGenMixi()->config();
1318+ }
1319+ }
1320+
1321+ void release()
1322+ {
1323+ TRACE_DUMMYAMP_INIT(_T("DummyAmp::release - called."));
1324+
1325+ // finalize gen_mixi_for_winamp
1326+ finalizeGenMixi();
1327+
1328+ // finalize dummy mp3 file, if dummy mp3 is enbaled
1329+ if(isDummyPlayInfoMp3Available())
1330+ {
1331+ finalizeDummyMp3();
1332+ }
1333+ }
1334+
1335+ void clearDummyAmpTitle()
1336+ {
1337+ uSetWindowText(getWnd(), DEFAULT_DUMMYAMP_TITLE);
1338+ }
1339+
1340+ void createWindow()
1341+ {
1342+ TRACE_PLUGIN(_T("DummyAmp::createWindow - called."));
1343+
1344+ if(getWnd() == INVALID_HANDLE_VALUE)
1345+ {
1346+ if(getGenMixi() != NULL)
1347+ {
1348+ HWND hAnotherWinamp = FindWindowEx(NULL, NULL, _T("Winamp v1.x"), NULL);
1349+
1350+ // found another winamp window
1351+ if(hAnotherWinamp != NULL)
1352+ {
1353+ DEBUG_PLUGIN(_T("DummyAmp::createWindow - Winamp のウィンドウを検出しました。ハンドル: %08x"), hAnotherWinamp);
1354+
1355+ DWORD dwAnotherWndProcessID;
1356+ ::GetWindowThreadProcessId(hAnotherWinamp, &dwAnotherWndProcessID);
1357+
1358+ DWORD dwFb2kProcessID = ::GetCurrentProcessId();
1359+
1360+ DEBUG_PLUGIN(_T("DummyAmp::createWindow - Winamp ウィンドウが属するプロセスのハンドル: %08x"), dwAnotherWndProcessID);
1361+ DEBUG_PLUGIN(_T("DummyAmp::createWindow - 現在実行中の foobar2000 プロセスのハンドル: %08x"), dwFb2kProcessID);
1362+
1363+ // another winamp window owned by foobar2000 process
1364+ if(dwAnotherWndProcessID == dwFb2kProcessID) {
1365+ // subclass it, because it's winamp api simulator plugin's window
1366+ setWnd(subclassWinampWindow(hAnotherWinamp));
1367+ } else {
1368+ LOG_ERROR(
1369+ _T("DummyAmp::createWindow - 検出した Winamp ウィンドウが他のプロセスに属しています"));
1370+ LOG_ERROR(
1371+ _T("DummyAmp::createWindow - Winamp と思われるプログラムが実行されているため、")
1372+ _T("mixi station への送信機能は使用できません"));
1373+ LOG_ERROR(
1374+ _T("DummyAmp::createWindow - 該当のプログラム(プロセスID:%d)を終了し、")
1375+ _T("foobar2000 を再起動してください")
1376+ , dwAnotherWndProcessID);
1377+
1378+ // unset dummyAmp ready flag
1379+ setReady(false);
1380+ }
1381+ }
1382+ // create own winamp simulating window
1383+ else
1384+ {
1385+ setWnd(createWinampWindow());
1386+ }
1387+
1388+ // initialize gen_mixi_for_winamp, if winamp window successfully created or subclassed
1389+ if(getWnd() != INVALID_HANDLE_VALUE)
1390+ {
1391+ getGenMixi()->hwndParent = getWnd();
1392+ getGenMixi()->hDllInstance = getHInstance();
1393+ getGenMixi()->init();
1394+ }
1395+ else
1396+ {
1397+ // unset dummyAmp ready flag
1398+ setReady(false);
1399+ }
1400+ }
1401+ }
1402+ }
1403+
1404+ void refreshAmpInfo()
1405+ {
1406+#if !defined(CONTROL_SEND_TIMING)
1407+ // increment play counter on dummyamp
1408+ getPlayInfo().incrementPlayCount();
1409+
1410+ // update dummyamp title
1411+ updateDummyAmpTitle();
1412+#endif
1413+ // use currently playing mp3 or ogg/vorbis file instead when dummy playinfo mp3 file disabled by user
1414+ // (other codec types will be ignored, because they are not supported by gen_mixi_for_winamp)
1415+ if(cfg_disable_dummy_mp3 == 1)
1416+ {
1417+ // set playinfo mp3 file path to dummyAmp
1418+ getPlayInfo().setPlayInfoMp3Path(m_trackInfo.getString(FORMAT_FILEPATH).c_str());
1419+
1420+ // set playinfo mp3 file available flag to dummyAmp
1421+ LPCSTR codec = m_trackInfo.getString(FORMAT_CODEC).c_str();
1422+ getPlayInfo().setPlayInfoMp3Available(IS_SUPPORTED_FORMAT_BY_GEN_MIXI(codec));
1423+ }
1424+ else
1425+ {
1426+ // check dummy playinfo mp3 exists and writable
1427+ if(isDummyPlayInfoMp3Available())
1428+ {
1429+ // update dummy mp3 file
1430+ tstring playInfoMp3Path = PathInfo::getDummyPlayInfoMp3Path();
1431+#if 1
1432+ id3Info id3Info(m_trackInfo);
1433+ DWORD dwErrCode;
1434+
1435+ if(( dwErrCode = id3Info.write(playInfoMp3Path.c_str()) ) == S_OK)
1436+ {
1437+ string_utf8_from_os dummyMp3Path8(playInfoMp3Path.c_str());
1438+
1439+ // set dummy playinfo mp3 file path to dummyAmp
1440+ getPlayInfo().setPlayInfoMp3Path(dummyMp3Path8);
1441+
1442+ // set playinfo mp3 file available flag to dummyAmp
1443+ getPlayInfo().setPlayInfoMp3Available(true);
1444+ }
1445+ else
1446+ {
1447+ putLogError(_T("DummyAmp::refreshAmpInfo"), _T("ダミーMP3ファイルの書き込み中にエラーが発生しました"), dwErrCode);
1448+ LOG_ERROR(_T("DummyAmp::refreshAmpInfo - ファイルパス: %s"), playInfoMp3Path.c_str());
1449+
1450+ // set playinfo mp3 file available flag
1451+ getPlayInfo().setPlayInfoMp3Available(false);
1452+
1453+ // unset dummyAmp ready flag
1454+ setReady(false);
1455+ }
1456+#else
1457+ // set id3v2 informations
1458+
1459+ string_utf8_from_os dummyMp3Path8(playInfoMp3Path.c_str());
1460+ string_ansi_from_utf8 dummyMp3PathAnsi(dummyMp3Path8);
1461+ ID3_Tag dummySong(dummyMp3PathAnsi);
1462+
1463+ string_wide_from_utf8 title_utf16(m_trackInfo.getString(FORMAT_TRACKTITLE, true).c_str());
1464+ string_wide_from_utf8 artist_utf16(m_trackInfo.getString(FORMAT_ARTIST, true).c_str());
1465+ string_wide_from_utf8 album_utf16(m_trackInfo.getString(FORMAT_ALBUMTITLE, true).c_str());
1466+ string_wide_from_utf8 genre_utf16(m_trackInfo.getString(FORMAT_GENRE, true).c_str());
1467+
1468+ AddTitle(&dummySong, title_utf16, true);
1469+ AddArtist(&dummySong, artist_utf16, true);
1470+ AddAlbum(&dummySong, album_utf16, true);
1471+ AddGenre(&dummySong, genre_utf16, true);
1472+
1473+ // write id3v2 tag
1474+ dummySong.SetPadding(false);
1475+ dummySong.SetUnsync(false);
1476+ if(dummySong.Update(ID3TT_ID3V2) != ID3TT_NONE)
1477+ {
1478+ // set dummy playinfo mp3 file path to dummyAmp
1479+ getPlayInfo().setPlayInfoMp3Path(dummyMp3Path8);
1480+
1481+ // set playinfo mp3 file available flag to dummyAmp
1482+ getPlayInfo().setPlayInfoMp3Available(true);
1483+ }
1484+ else
1485+ {
1486+ LOG_ERROR(_T("DummyAmp::refreshAmpInfo - ID3_Tag::Update(ID3TT_ID3V2) failed."));
1487+
1488+ // set playinfo mp3 file available flag
1489+ getPlayInfo().setPlayInfoMp3Available(false);
1490+
1491+ // unset dummyAmp ready flag
1492+ setReady(false);
1493+ }
1494+#endif
1495+ }
1496+ else
1497+ {
1498+ // reset playinfo mp3 file available flag
1499+ getPlayInfo().setPlayInfoMp3Available(false);
1500+
1501+ LOG_WARN(_T("DummyAmp::refreshAmpInfo - ダミーMP3ファイルが無効になっているため、送信情報を書き込めません。"));
1502+ }
1503+ }
1504+
1505+#if !defined(CONTROL_SEND_TIMING)
1506+ // set dummyamp status PLAY_START
1507+ getPlayInfo().setPlayStatusStart();
1508+#endif
1509+ }
1510+
1511+ public:
1512+
1513+ bool isReady() const {
1514+ return m_bReady;
1515+ }
1516+
1517+ HWND getWnd() const {
1518+ return m_hWinampWnd;
1519+ }
1520+
1521+ const TrackInfo &getTrackInfo() const {
1522+ return m_trackInfo;
1523+ }
1524+
1525+ TrackInfo &getMutableTrackInfo() {
1526+ return m_trackInfo;
1527+ }
1528+
1529+ void setTrackInfo(const TrackInfo &trackInfo) {
1530+ m_trackInfo = trackInfo;
1531+ }
1532+
1533+ PlayInfo &getPlayInfo() {
1534+ return m_playInfo;
1535+ }
1536+
1537+ PlayInfo &getRawPlayInfo() {
1538+ return m_rawPlayInfo;
1539+ }
1540+
1541+
1542+ void setPlaylistTitle(LPCTSTR pTitle) {
1543+
1544+ TRACE_PLUGIN(_T("DummyAmp::setPlayListTitle - %s"), pTitle);
1545+
1546+ m_playlistTitle = pTitle;
1547+
1548+ string_utf8_from_os playListTitle8(pTitle);
1549+
1550+ if(cfg_disable_ansi_trans == 1)
1551+ {
1552+
1553+ m_playlistTitle8 = playListTitle8;
1554+ }
1555+ else
1556+ {
1557+ string_ansi_from_utf8 playListTitleAnsi(playListTitle8);
1558+
1559+ m_playlistTitle8 = playListTitleAnsi;
1560+ }
1561+ }
1562+
1563+ const tstring &getPlaylistTitle() const {
1564+ return m_playlistTitle;
1565+ }
1566+
1567+ const string8 &getPlaylistTitle8() const {
1568+ return m_playlistTitle8;
1569+ }
1570+
1571+ void setWinampTitle(LPCTSTR pTitle) {
1572+
1573+ TRACE_PLUGIN(_T("DummyAmp::setWinampTitle - %s"), pTitle);
1574+
1575+ m_winampTitle = pTitle;
1576+ }
1577+
1578+ const tstring &getWinampTitle() const {
1579+ return m_winampTitle;
1580+ }
1581+
1582+ void setBaseWinampTitle(LPCTSTR pTitle)
1583+ {
1584+ TRACE_PLUGIN(_T("DummyAmp::setRawWinampTitle - %s"), pTitle);
1585+
1586+ m_baseWinampTitle = pTitle;
1587+
1588+ updateDummyAmpTitle();
1589+ }
1590+
1591+ const tstring &getBaseWinampTitle() const {
1592+ return m_baseWinampTitle;
1593+ }
1594+
1595+ const tstring &getDummyPlayInfoMp3Path() const {
1596+ return m_dummyPlayInfoMp3Path;
1597+ }
1598+
1599+ bool isDummyPlayInfoMp3Available() const {
1600+ return m_isDummyPlayInfoMp3Available;
1601+ }
1602+
1603+ bool isAnotherWinampWindowAvailable() const {
1604+ return m_isAnotherWinampWindowAvailable;
1605+ }
1606+
1607+ void showDummyAmpWindow(bool bShow) {
1608+ showDummyAmpWindow(getWnd(), bShow);
1609+ }
1610+
1611+ protected:
1612+
1613+ void initGenMixi()
1614+ {
1615+ string_os_from_utf8 path(cfg_gen_mixi_path);
1616+ tstring genMixiPath = path;
1617+ genMixiPath += GEN_MIXI_FILE_NAME;
1618+
1619+ setHInstance(::LoadLibrary(genMixiPath.c_str()));
1620+
1621+ if(getHInstance() == NULL)
1622+ {
1623+ setHInstance((HINSTANCE)INVALID_HANDLE_VALUE);
1624+
1625+ tstring msg;
1626+ msg = GEN_MIXI_FILE_NAME _T(" が見つかりません。\n以下のパスにファイルが存在するか確認してください。\n");
1627+ msg += genMixiPath;
1628+
1629+ string_utf8_from_os uMsg(msg.c_str());
1630+
1631+ uMessageBox(NULL, uMsg, PLUGIN_CAPTION, MB_ICONEXCLAMATION | MB_OK);
1632+ }
1633+ else
1634+ {
1635+ winampGeneralPurposePluginGetter funcWinampGetGeneralPurposePlugin = NULL;
1636+
1637+ funcWinampGetGeneralPurposePlugin = (winampGeneralPurposePluginGetter)
1638+ ::GetProcAddress(getHInstance(), GEN_MIXI_FUNC_NAME_GET_GENERAL_PURPOSE_PLUGIN);
1639+
1640+ if(funcWinampGetGeneralPurposePlugin != NULL)
1641+ {
1642+ setGenMixi(funcWinampGetGeneralPurposePlugin());
1643+ // create window later.
1644+ }
1645+ else
1646+ {
1647+ tstring msg;
1648+ msg = _T("関数 ") _T(GEN_MIXI_FUNC_NAME_GET_GENERAL_PURPOSE_PLUGIN) _T("() が見つかりません。\n")
1649+ GEN_MIXI_FILE_NAME _T(" が壊れている可能性があります。");
1650+
1651+ string_utf8_from_os uMsg(msg.c_str());
1652+
1653+ uMessageBox(NULL, uMsg, PLUGIN_CAPTION, MB_ICONEXCLAMATION | MB_OK);
1654+ }
1655+ }
1656+ }
1657+
1658+ void initDummyMp3()
1659+ {
1660+ // if dummy mp3 file not exist
1661+ tstring dummyPlayInfoMp3Path = PathInfo::getDummyPlayInfoMp3Path();
1662+ DWORD dwAttr = ::GetFileAttributes(dummyPlayInfoMp3Path.c_str());
1663+
1664+ if(dwAttr == -1)
1665+ {
1666+ // create dummy mp3 file
1667+ HANDLE hMp3File = ::CreateFile(
1668+ dummyPlayInfoMp3Path.c_str(), 0, 0, NULL,
1669+ CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL
1670+ );
1671+
1672+ if(hMp3File == INVALID_HANDLE_VALUE)
1673+ {
1674+ DWORD dwErrCode = ::GetLastError();
1675+ putLogError(_T("DummyAmp::initDummyMp3"), _T("ダミーMP3ファイルの作成中にエラーが発生しました"), dwErrCode);
1676+ LOG_ERROR(_T("DummyAmp::initDummyMp3 - ファイルパス: %s"), dummyPlayInfoMp3Path.c_str());
1677+
1678+ LOG_ERROR(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルが使用できないため、送信機能は無効になります"));
1679+ }
1680+ else
1681+ {
1682+ DEBUG_DUMMYAMP_INIT(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルを [%s] に作成しました"), dummyPlayInfoMp3Path.c_str());
1683+
1684+ ::CloseHandle(hMp3File);
1685+
1686+ setDummyPlayInfoMp3Path(dummyPlayInfoMp3Path);
1687+ setDummyPlayInfoMp3Available(true);
1688+ }
1689+ }
1690+ else if((dwAttr & FILE_ATTRIBUTE_READONLY) != 0)
1691+ {
1692+ LOG_ERROR(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルがパス [%s] 上に既に存在しますが、")
1693+ _T("読み込み専用属性のため書き込みできません"), dummyPlayInfoMp3Path.c_str());
1694+
1695+ LOG_ERROR(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルが使用できないため、送信機能は無効になります"));
1696+ }
1697+ else
1698+ {
1699+ LOG_WARN(_T("DummyAmp::initDummyMp3 - ダミーMP3ファイルがパス [%s] 上に既に存在します"), dummyPlayInfoMp3Path.c_str());
1700+ LOG_WARN(_T("DummyAmp::initDummyMp3 - このMP3ファイルは逐次上書きされ、終了時に削除されます"));
1701+
1702+ setDummyPlayInfoMp3Path(dummyPlayInfoMp3Path);
1703+ setDummyPlayInfoMp3Available(true);
1704+ }
1705+ }
1706+
1707+ void finalizeGenMixi()
1708+ {
1709+ if(getHInstance() != INVALID_HANDLE_VALUE)
1710+ {
1711+ if(getGenMixi() != NULL)
1712+ {
1713+ getGenMixi()->quit();
1714+ setGenMixi(NULL);
1715+ }
1716+ ::FreeLibrary(getHInstance());
1717+ setHInstance((HINSTANCE)INVALID_HANDLE_VALUE);
1718+ }
1719+
1720+ }
1721+
1722+ void finalizeDummyMp3()
1723+ {
1724+ tstring dummyPlayInfoMp3Path = getDummyPlayInfoMp3Path();
1725+
1726+ if(::DeleteFile(dummyPlayInfoMp3Path.c_str()) == FALSE)
1727+ {
1728+ DWORD dwErrCode = ::GetLastError();
1729+ putLogError(_T("DummyAmp::finalizeDummyMp3"), _T("ダミーMP3ファイルの削除中にエラーが発生しました"), dwErrCode);
1730+ LOG_ERROR(_T("DummyAmp::finalizeDummyMp3 - ファイルパス: %s"), dummyPlayInfoMp3Path.c_str());
1731+ }
1732+ else
1733+ {
1734+ DEBUG_DUMMYAMP_INIT(_T("DummyAmp::finalizeDummyMp3 - ダミーMP3ファイル [%s] を削除しました"), dummyPlayInfoMp3Path.c_str());
1735+ setDummyPlayInfoMp3Available(false);
1736+ }
1737+ }
1738+
1739+ void updateDummyAmpTitle()
1740+ {
1741+ bool bDisableDuplicatedSong = (cfg_disable_duplicate_song == 0);
1742+ tstring winampTitle = makeDummyAmpTitle(getBaseWinampTitle(), bDisableDuplicatedSong);
1743+
1744+ setWinampTitle(winampTitle.c_str());
1745+
1746+ if(isAnotherWinampWindowAvailable() == false) {
1747+ ::SetWindowText(getWnd(), winampTitle.c_str());
1748+ }
1749+ }
1750+
1751+ protected:
1752+
1753+ void setReady(bool bReady) {
1754+ m_bReady = bReady;
1755+ }
1756+
1757+ void setWnd(HWND hWnd) {
1758+ m_hWinampWnd = hWnd;
1759+ }
1760+
1761+ HINSTANCE getHInstance() const {
1762+ return m_hInstGenMixi;
1763+ }
1764+
1765+ void setHInstance(HINSTANCE hInst) {
1766+ m_hInstGenMixi = hInst;
1767+ }
1768+
1769+ winampGeneralPurposePlugin *getGenMixi() const {
1770+ return m_pGenMixi;
1771+ }
1772+
1773+ void setGenMixi(winampGeneralPurposePlugin *pGenMixi) {
1774+ m_pGenMixi = pGenMixi;
1775+ }
1776+
1777+ void setDummyPlayInfoMp3Path(const tstring &path) {
1778+ m_dummyPlayInfoMp3Path = path;
1779+ }
1780+
1781+ void setDummyPlayInfoMp3Available(bool isAvailable) {
1782+ m_isDummyPlayInfoMp3Available = isAvailable;
1783+ }
1784+
1785+ void setAnotherWinampWindowAvailable(bool isAvailable) {
1786+ m_isAnotherWinampWindowAvailable = isAvailable;
1787+ }
1788+
1789+ int getGetPlayListFileTime() const {
1790+ return m_GETPLAYLISTFILE_time;
1791+ }
1792+
1793+ void setGetPlayListFileTime(int time) {
1794+ m_GETPLAYLISTFILE_time = time;
1795+ }
1796+
1797+ HANDLE getDirChangeNotifyHandle() const {
1798+ return m_hDirChangeNotify;
1799+ }
1800+
1801+ void setDirChangeNotifyHandle(HANDLE handle) {
1802+ m_hDirChangeNotify = handle;
1803+ }
1804+
1805+ protected:
1806+
1807+ HWND createWinampWindow()
1808+ {
1809+ TRACE_PLUGIN(_T("DummyAmp::createWinampWindow - called."));
1810+
1811+ static bool isInited = false;
1812+
1813+#if IS_FB2K_VER08
1814+ static const char class_name[] = "Winamp v1.x";
1815+ if (!isInited)
1816+ {
1817+ isInited = true;
1818+ uWNDCLASS wc;
1819+ memset(&wc,0,sizeof(wc));
1820+ wc.style = 0;
1821+ wc.lpfnWndProc = windowproc;
1822+ wc.hInstance = core_api::get_my_instance();
1823+ wc.hCursor = NULL; //uLoadCursor(0, IDC_ARROW);
1824+ wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
1825+ wc.lpszClassName = class_name;
1826+ uRegisterClass(&wc);
1827+ }
1828+ HWND hWinampWnd = uCreateWindowEx(
1829+ 0, class_name, DEFAULT_DUMMYAMP_TITLE,
1830+ WS_OVERLAPPED|WS_CAPTION|WS_SIZEBOX,
1831+ CW_USEDEFAULT, CW_USEDEFAULT, 300, 150,
1832+#if 1
1833+ core_api::get_main_window(), 0, core_api::get_my_instance(), NULL
1834+#else
1835+ NULL, 0, core_api::get_my_instance(), NULL
1836+#endif
1837+ );
1838+#elif IS_FB2K_VER09
1839+ static const TCHAR class_name[] = _T("Winamp v1.x");
1840+ if (!isInited)
1841+ {
1842+ isInited = true;
1843+ WNDCLASS wc;
1844+ memset(&wc,0,sizeof(wc));
1845+ wc.style = 0;
1846+ wc.lpfnWndProc = windowproc;
1847+ wc.hInstance = core_api::get_my_instance();
1848+ wc.hCursor = NULL; //uLoadCursor(0, IDC_ARROW);
1849+ wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
1850+ wc.lpszClassName = class_name;
1851+ RegisterClass(&wc);
1852+ }
1853+ HWND hWinampWnd = CreateWindowEx(
1854+ 0, class_name, _T(DEFAULT_DUMMYAMP_TITLE),
1855+ WS_OVERLAPPED|WS_CAPTION|WS_SIZEBOX,
1856+ CW_USEDEFAULT, CW_USEDEFAULT, 300, 150,
1857+#if 1
1858+ core_api::get_main_window(), 0, core_api::get_my_instance(), NULL
1859+#else
1860+ NULL, 0, core_api::get_my_instance(), NULL
1861+#endif
1862+ );
1863+#endif
1864+ if (!hWinampWnd)
1865+ {
1866+ DWORD dwErrCode = ::GetLastError();
1867+ putLogError(_T("DummyAmp::createWinampWindow"), _T("DummyAmp ウィンドウの生成に失敗しました"), dwErrCode);
1868+
1869+ return NULL;
1870+ }
1871+
1872+ DEBUG_PLUGIN(_T("DummyAmp::createWinampWindow - DummyAmp ウィンドウを生成しました"));
1873+
1874+ showDummyAmpWindow(hWinampWnd, cfg_show_dummyamp == 1);
1875+
1876+ return hWinampWnd;
1877+ }
1878+
1879+ HWND subclassWinampWindow(HWND hAnotherWinampWnd) {
1880+ // subclass another dummyamp window
1881+ m_pfnOldAnotherWinampProc =
1882+ SetWindowLongPtr(hAnotherWinampWnd, GWL_WNDPROC, WNDPROC_TO_LONG_PTR(hookWinampWindowProc));
1883+
1884+ if(hAnotherWinampWnd != NULL)
1885+ {
1886+ DEBUG_PLUGIN(_T("DummyAmp::subclassWinampWindow - API エミュレータと思われる Winamp ウィンドウのプロシージャをフックしました"));
1887+ setAnotherWinampWindowAvailable(true);
1888+
1889+ return hAnotherWinampWnd;
1890+ }
1891+ else
1892+ {
1893+ DWORD dwErrCode = ::GetLastError();
1894+ putLogError(_T("DummyAmp::subclassWinampWindow"), _T("Winamp ウィンドウのサブクラス化に失敗しました"), dwErrCode);
1895+
1896+ LOG_ERROR(_T("DummyAmp::subclassWinampWindow - Winamp ウィンドウのプロシージャをフックできなかったため、送信機能は無効になります"));
1897+ }
1898+
1899+ return (HWND)INVALID_HANDLE_VALUE;
1900+ }
1901+
1902+ void unsubclassWinampWindow() {
1903+ SetWindowLongPtr(getWnd(), GWL_WNDPROC, m_pfnOldAnotherWinampProc);
1904+ }
1905+
1906+ void showDummyAmpWindow(HWND hWinampWnd, bool bShow)
1907+ {
1908+ if(bShow) {
1909+ ShowWindow(hWinampWnd, SW_SHOW);
1910+ } else {
1911+ ShowWindow(hWinampWnd, SW_HIDE);
1912+ }
1913+ }
1914+
1915+ void destroyWindow()
1916+ {
1917+ TRACE_PLUGIN(_T("DummyAmp::destroyWindow - called."));
1918+
1919+ if(getWnd() != INVALID_HANDLE_VALUE)
1920+ {
1921+ if(isAnotherWinampWindowAvailable() == false) {
1922+ uDestroyWindow(getWnd());
1923+ } else {
1924+ unsubclassWinampWindow();
1925+
1926+ DEBUG_PLUGIN(_T("DummyAmp::destroyWindow - Winamp ウィンドウのサブクラス化を解除しました"));
1927+ }
1928+
1929+ setWnd((HWND)INVALID_HANDLE_VALUE);
1930+ }
1931+ }
1932+
1933+ void closeDirChangeNotifyHandle()
1934+ {
1935+ TRACE_PLUGIN(_T("DummyAmp::closeDirChangeNotifyHandle - called."));
1936+
1937+ if(m_hDirChangeNotify != INVALID_HANDLE_VALUE)
1938+ {
1939+ ::FindCloseChangeNotification(m_hDirChangeNotify);
1940+ TRACE_PLUGIN(_T("DummyAmp::closeDirChangeNotifyHandle - ディレクトリ変更通知イベントのハンドル (ID:%08x) を閉じました"), m_hDirChangeNotify);
1941+
1942+ m_hDirChangeNotify = (HANDLE)INVALID_HANDLE_VALUE;
1943+ }
1944+ }
1945+
1946+ tstring makeDummyAmpTitle(const tstring &rawTitle, bool bCounterReflection)
1947+ {
1948+ TRACE_PLUGIN(_T("DummyAmp::makeDummyAmpTitle - called."));
1949+
1950+ Str64K formatBuf;
1951+
1952+ if(bCounterReflection)
1953+ {
1954+ _stprintf_s(
1955+ formatBuf, sizeof(formatBuf) / sizeof(TCHAR),
1956+ _T("%d. %s - ") _T(DEFAULT_WINAMP_TITLE),
1957+ getPlayInfo().getPlayCount(),
1958+ (LPCTSTR)rawTitle.c_str()
1959+ );
1960+ }
1961+ else
1962+ {
1963+ _stprintf_s(
1964+ formatBuf, sizeof(formatBuf) / sizeof(TCHAR),
1965+ _T("%d. %s - ") _T(DEFAULT_WINAMP_TITLE),
1966+ m_trackInfo.getNumber(FORMAT_LISTINDEX),
1967+ (LPCTSTR)rawTitle.c_str()
1968+ );
1969+ }
1970+
1971+ return formatBuf;
1972+ }
1973+
1974+ void refreshTitle()
1975+ {
1976+ // get formatted dynamic titles
1977+ string8 dummyAmp_title8;
1978+ string8 playlist_title8;
1979+#if IS_FB2K_VER08
1980+ metadb_handle *track = play_control::get()->get_now_playing();
1981+ if(track)
1982+ {
1983+ play_control::get()->playback_format_title_ex(track, dummyAmp_title8, cfg_dummyamp_title_format, NULL, false, true);
1984+ play_control::get()->playback_format_title_ex(track, playlist_title8, cfg_dummyamp_playlist_format, NULL, false, true);
1985+ track->handle_release();
1986+ }
1987+#elif IS_FB2K_VER09
1988+ metadb_handle_ptr track;
1989+ static_api_ptr_t<playback_control>()->get_now_playing(track);
1990+
1991+ service_ptr_t<titleformat_object> titleformat;
1992+
1993+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, cfg_dummyamp_title_format);
1994+ static_api_ptr_t<playback_control>()->playback_format_title_ex(track, NULL, dummyAmp_title8, titleformat, NULL, play_control::display_level_all);
1995+
1996+ static_api_ptr_t<titleformat_compiler>()->compile_safe(titleformat, cfg_dummyamp_playlist_format);
1997+ static_api_ptr_t<playback_control>()->playback_format_title_ex(track, NULL, playlist_title8, titleformat, NULL, play_control::display_level_all);
1998+#endif
1999+ // convert utf8 track informations to os charset
2000+ string_os_from_utf8 dummyAmp_title(dummyAmp_title8);
2001+ string_os_from_utf8 playlist_title(playlist_title8);
2002+
2003+ // set base dummyamp title to dummyamp
2004+ setBaseWinampTitle(dummyAmp_title);
2005+
2006+ // set dummyamp playlist current item title to dummyamp
2007+ setPlaylistTitle(playlist_title);
2008+ }
2009+
2010+#if 0
2011+ private:
2012+
2013+ ID3_Frame* AddArtist(ID3_Tag *tag, const wchar_t *text, bool replace)
2014+ {
2015+ ID3_Frame* frame = NULL;
2016+ if (NULL != tag && NULL != text && lstrlen(text) > 0)
2017+ {
2018+ if (replace)
2019+ {
2020+ RemoveArtists(tag);
2021+ }
2022+ if (replace ||
2023+ (tag->Find(ID3FID_LEADARTIST) == NULL &&
2024+ tag->Find(ID3FID_BAND) == NULL &&
2025+ tag->Find(ID3FID_CONDUCTOR) == NULL &&
2026+ tag->Find(ID3FID_COMPOSER) == NULL))
2027+ {
2028+ frame = new ID3_Frame(ID3FID_LEADARTIST);
2029+ if (frame)
2030+ {
2031+ frame->GetField(ID3FN_TEXT)->SetEncoding(ID3TE_UNICODE);
2032+ frame->GetField(ID3FN_TEXT)->Set(SwapByteOrder(text));
2033+ frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_UNICODE);
2034+ tag->AttachFrame(frame);
2035+ }
2036+ }
2037+ }
2038+ return frame;
2039+ }
2040+
2041+ size_t RemoveArtists(ID3_Tag *tag)
2042+ {
2043+ size_t num_removed = 0;
2044+ ID3_Frame *frame = NULL;
2045+
2046+ if (NULL == tag)
2047+ {
2048+ return num_removed;
2049+ }
2050+
2051+ while ((frame = tag->Find(ID3FID_LEADARTIST)) != NULL)
2052+ {
2053+ frame = tag->RemoveFrame(frame);
2054+ delete frame;
2055+ num_removed++;
2056+ }
2057+ while ((frame = tag->Find(ID3FID_BAND)) != NULL)
2058+ {
2059+ frame = tag->RemoveFrame(frame);
2060+ delete frame;
2061+ num_removed++;
2062+ }
2063+ while ((frame = tag->Find(ID3FID_CONDUCTOR)) != NULL)
2064+ {
2065+ frame = tag->RemoveFrame(frame);
2066+ delete frame;
2067+ num_removed++;
2068+ }
2069+ while ((frame = tag->Find(ID3FID_COMPOSER)) != NULL)
2070+ {
2071+ frame = tag->RemoveFrame(frame);
2072+ delete frame;
2073+ num_removed++;
2074+ }
2075+
2076+ return num_removed;
2077+ }
2078+
2079+ ID3_Frame* AddAlbum(ID3_Tag *tag, const wchar_t *text, bool replace)
2080+ {
2081+ ID3_Frame* frame = NULL;
2082+ if (NULL != tag && NULL != text && lstrlen(text) > 0)
2083+ {
2084+ if (replace)
2085+ {
2086+ RemoveAlbums(tag);
2087+ }
2088+ if (replace || tag->Find(ID3FID_ALBUM) == NULL)
2089+ {
2090+ frame = new ID3_Frame(ID3FID_ALBUM);
2091+ if (frame)
2092+ {
2093+ frame->GetField(ID3FN_TEXT)->SetEncoding(ID3TE_UNICODE);
2094+ frame->GetField(ID3FN_TEXT)->Set(SwapByteOrder(text));
2095+ frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_UNICODE);
2096+ tag->AttachFrame(frame);
2097+ }
2098+ }
2099+ }
2100+
2101+ return frame;
2102+ }
2103+
2104+ size_t RemoveAlbums(ID3_Tag *tag)
2105+ {
2106+ size_t num_removed = 0;
2107+ ID3_Frame *frame = NULL;
2108+
2109+ if (NULL == tag)
2110+ {
2111+ return num_removed;
2112+ }
2113+
2114+ while ((frame = tag->Find(ID3FID_ALBUM)) != NULL)
2115+ {
2116+ frame = tag->RemoveFrame(frame);
2117+ delete frame;
2118+ num_removed++;
2119+ }
2120+
2121+ return num_removed;
2122+ }
2123+
2124+ ID3_Frame* AddTitle(ID3_Tag *tag, const wchar_t *text, bool replace)
2125+ {
2126+ ID3_Frame* frame = NULL;
2127+ if (NULL != tag && NULL != text && lstrlen(text) > 0)
2128+ {
2129+ if (replace)
2130+ {
2131+ RemoveTitles(tag);
2132+ }
2133+ if (replace || tag->Find(ID3FID_TITLE) == NULL)
2134+ {
2135+ frame = new ID3_Frame(ID3FID_TITLE);
2136+ if (frame)
2137+ {
2138+ frame->GetField(ID3FN_TEXT)->SetEncoding(ID3TE_UNICODE);
2139+ frame->GetField(ID3FN_TEXT)->Set(SwapByteOrder(text));
2140+ frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_UNICODE);
2141+ tag->AttachFrame(frame);
2142+ }
2143+ }
2144+ }
2145+
2146+ return frame;
2147+ }
2148+
2149+ size_t RemoveTitles(ID3_Tag *tag)
2150+ {
2151+ size_t num_removed = 0;
2152+ ID3_Frame *frame = NULL;
2153+
2154+ if (NULL == tag)
2155+ {
2156+ return num_removed;
2157+ }
2158+
2159+ while ((frame = tag->Find(ID3FID_TITLE)) != NULL)
2160+ {
2161+ frame = tag->RemoveFrame(frame);
2162+ delete frame;
2163+ num_removed++;
2164+ }
2165+
2166+ return num_removed;
2167+ }
2168+
2169+ //following routine courtesy of John George
2170+ ID3_Frame* AddGenre(ID3_Tag* tag, const wchar_t *genre, bool replace)
2171+ {
2172+ ID3_Frame* frame = NULL;
2173+ if (NULL != tag && NULL != genre && lstrlen(genre) > 0)
2174+ {
2175+ if (replace)
2176+ {
2177+ RemoveGenres(tag);
2178+ }
2179+ if (replace || NULL == tag->Find(ID3FID_CONTENTTYPE))
2180+ {
2181+ frame = new ID3_Frame(ID3FID_CONTENTTYPE);
2182+ if (NULL != frame)
2183+ {
2184+ frame->GetField(ID3FN_TEXT)->SetEncoding(ID3TE_UNICODE);
2185+ frame->GetField(ID3FN_TEXT)->Set(SwapByteOrder(genre));
2186+ frame->GetField(ID3FN_TEXTENC)->Set(ID3TE_UNICODE);
2187+ tag->AttachFrame(frame);
2188+ }
2189+ }
2190+ }
2191+
2192+ return frame;
2193+ }
2194+
2195+ size_t RemoveGenres(ID3_Tag *tag)
2196+ {
2197+ size_t num_removed = 0;
2198+ ID3_Frame *frame = NULL;
2199+
2200+ if (NULL == tag)
2201+ {
2202+ return num_removed;
2203+ }
2204+
2205+ while ((frame = tag->Find(ID3FID_CONTENTTYPE)) != NULL)
2206+ {
2207+ frame = tag->RemoveFrame(frame);
2208+ delete frame;
2209+ num_removed++;
2210+ }
2211+
2212+ return num_removed;
2213+ }
2214+
2215+ const unicode_t *SwapByteOrder(const wchar_t *text)
2216+ {
2217+ static unicode_t resBuf[65536];
2218+ const wchar_t *pText;
2219+ unicode_t *pBuf;
2220+
2221+ for(pText = text, pBuf = resBuf; *pText != L'\0'; pText ++, pBuf ++)
2222+ {
2223+ wchar_t srcVal = *pText;
2224+ //unicode_t dstVal = srcVal;
2225+ unicode_t dstVal = (srcVal << 8) | (srcVal >> 8);
2226+ *pBuf = dstVal;
2227+ }
2228+
2229+ *pBuf = L'\0';
2230+
2231+ return resBuf;
2232+ }
2233+#endif
2234+
2235+ protected:
2236+
2237+ static LRESULT WINAPI hookWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp);
2238+ static LRESULT WINAPI windowproc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp);
2239+ static std::pair<bool, LRESULT> WINAPI innerWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp);
2240+ static std::pair<bool, LRESULT> WINAPI outerWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp);
2241+
2242+ protected:
2243+
2244+ static DummyAmp *m_pMe;
2245+
2246+ bool m_bReady;
2247+
2248+ HINSTANCE m_hInstGenMixi;
2249+ winampGeneralPurposePlugin *m_pGenMixi;
2250+
2251+ HWND m_hWinampWnd;
2252+ bool m_isAnotherWinampWindowAvailable;
2253+
2254+ static LONG_PTR m_pfnOldAnotherWinampProc;
2255+
2256+ HANDLE m_hDirChangeNotify;
2257+
2258+ PlayInfo m_playInfo;
2259+ PlayInfo m_rawPlayInfo;
2260+
2261+ TrackInfo m_trackInfo;
2262+ int m_GETPLAYLISTFILE_time;
2263+
2264+ tstring m_playlistTitle;
2265+ string8 m_playlistTitle8;
2266+
2267+ tstring m_winampTitle;
2268+ tstring m_baseWinampTitle;
2269+
2270+ tstring m_dummyPlayInfoMp3Path;
2271+ bool m_isDummyPlayInfoMp3Available;
2272+};
2273+
2274+DummyAmp *DummyAmp::m_pMe = NULL;
2275+
2276+LONG_PTR DummyAmp::m_pfnOldAnotherWinampProc = NULL;
2277+
2278+LRESULT CALLBACK DummyAmp::hookWinampWindowProc(HWND wnd,UINT msg, WPARAM wp, LPARAM lp)
2279+{
2280+ if(InSendMessage() || (msg != WM_WA_IPC))
2281+ {
2282+ switch(msg)
2283+ {
2284+ case WM_CLOSE:
2285+ DEBUG_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_CLOSE %s"),
2286+ InSendMessage() == TRUE ? _T("from other thread") : _T(""));
2287+
2288+ DummyAmp::getInstance()->destroyWindow();
2289+ break;
2290+
2291+ case WM_GETTEXT:
2292+ {
2293+ // message from same thread
2294+ if((InSendMessage() == FALSE) && (DummyAmp::getInstance()->isAnotherWinampWindowAvailable() == true))
2295+ {
2296+ LPCTSTR pWinampTitle = DummyAmp::getInstance()->getWinampTitle().c_str();
2297+ int nLen = ::lstrlen(pWinampTitle);
2298+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_GETTEXT / window title [%s]."), pWinampTitle);
2299+
2300+ ::lstrcpyn(reinterpret_cast<LPTSTR>(lp), pWinampTitle, static_cast<int>(wp));
2301+
2302+ return (LRESULT)nLen;
2303+ }
2304+ }
2305+ break;
2306+
2307+ case WM_GETTEXTLENGTH:
2308+ {
2309+ // message from same thread
2310+ if((InSendMessage() == FALSE) && (DummyAmp::getInstance()->isAnotherWinampWindowAvailable() == true))
2311+ {
2312+ LPCTSTR pWinampTitle = DummyAmp::getInstance()->getWinampTitle().c_str();
2313+ int nLen = ::lstrlen(pWinampTitle);
2314+ TRACE_DUMMYAMP_PROC(_T("DummyAmp::hookWinampWindowProc - WM_GETTEXTLENGTH / window title length %d."), nLen);
2315+
2316+ return (LRESULT)nLen;
2317+ }
2318+ }
2319+ break;
2320+