1 /*
2 LICENSE
3 -------
4 Copyright 2005-2013 Nullsoft, Inc.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without modification,
8 are permitted provided that the following conditions are met:
9
10 * Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12
13 * Redistributions in binary form must reproduce the above copyright notice,
14 this list of conditions and the following disclaimer in the documentation
15 and/or other materials provided with the distribution.
16
17 * Neither the name of Nullsoft nor the names of its contributors may be used to
18 endorse or promote products derived from this software without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
21 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
26 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
27 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "api.h"
31 #include <windows.h>
32 #include "vis.h"
33 #include "plugin.h"
34 #include "defines.h"
35 #include "resource.h"
36 #include "utility.h"
37
38 CPlugin g_plugin;
39 _locale_t g_use_C_locale = 0;
40 char keyMappings[8];
41 bool g_bFullyExited = true;
42
43 // wasabi based services for localisation support
44 api_service *WASABI_API_SVC = 0;
45 api_language *WASABI_API_LNG = 0;
46 api_application *WASABI_API_APP = 0;
47 api_syscb *WASABI_API_SYSCB = 0;
48 HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
49
50 void config(struct winampVisModule *this_mod); // configuration dialog
51 int init(struct winampVisModule *this_mod); // initialization for module
52 int render1(struct winampVisModule *this_mod); // rendering for module 1
53 void quit(struct winampVisModule *this_mod); // deinitialization for module
54
55 // our only plugin module in this plugin:
56 winampVisModule mod1 =
57 {
58 MODULEDESC,
59 NULL, // hwndParent
60 NULL, // hDllInstance
61 0, // sRate
62 0, // nCh
63 0, // latencyMS - tells winamp how much in advance you want the audio data,
64 // in ms.
65 10, // delayMS - if winamp tells the plugin to render a frame and it takes
66 // less than this # of milliseconds, winamp will sleep (go idle)
67 // for the remainder. In effect, this limits the framerate of
68 // the plugin. A value of 10 would cause a fps limit of ~100.
69 // Derivation: (1000 ms/sec) / (10 ms/frame) = 100 fps.
70 0, // spectrumNch
71 2, // waveformNch
72 { 0, }, // spectrumData
73 { 0, }, // waveformData
74 config,
75 init,
76 render1,
77 quit
78 };
79
80 // getmodule routine from the main header. Returns NULL if an invalid module was requested,
81 // otherwise returns either mod1, mod2 or mod3 depending on 'which'.
getModule(int which)82 winampVisModule *getModule(int which)
83 {
84 switch (which)
85 {
86 case 0: return &mod1;
87 //case 1: return &mod2;
88 //case 2: return &mod3;
89 default: return NULL;
90 }
91 }
92
93 // Module header, includes version, description, and address of the module retriever function
94 winampVisHeader hdr = { VIS_HDRVER, DLLDESC, getModule };
95
96 // use this to get our own HINSTANCE since overriding DllMain(..) causes instant crashes (should see why)
GetMyInstance()97 static HINSTANCE GetMyInstance()
98 {
99 MEMORY_BASIC_INFORMATION mbi = {0};
100 if(VirtualQuery(GetMyInstance, &mbi, sizeof(mbi)))
101 return (HINSTANCE)mbi.AllocationBase;
102 return NULL;
103 }
104
105 // this is the only exported symbol. returns our main header.
106 // if you are compiling C++, the extern "C" { is necessary, so we just #ifdef it
107 #ifdef __cplusplus
108 extern "C" {
109 #endif
winampVisGetHeader(HWND hwndParent)110 __declspec( dllexport ) winampVisHeader *winampVisGetHeader(HWND hwndParent)
111 {
112 if(!WASABI_API_LNG_HINST)
113 {
114 // loader so that we can get the localisation service api for use
115 WASABI_API_SVC = (api_service*)SendMessage(hwndParent, WM_WA_IPC, 0, IPC_GET_API_SERVICE);
116 if (WASABI_API_SVC == (api_service*)1) WASABI_API_SVC = NULL;
117
118 waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(languageApiGUID);
119 if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface());
120
121 sf = WASABI_API_SVC->service_getServiceByGuid(applicationApiServiceGuid);
122 if (sf) WASABI_API_APP = reinterpret_cast<api_application*>(sf->getInterface());
123
124 sf = WASABI_API_SVC->service_getServiceByGuid(syscbApiServiceGuid);
125 if (sf) WASABI_API_SYSCB = reinterpret_cast<api_syscb*>(sf->getInterface());
126
127 // need to have this initialised before we try to do anything with localisation features
128 WASABI_API_START_LANG(GetMyInstance(),VisMilkdropLangGUID);
129
130 /* added for v2.25 as a quick work around to allow partial
131 /* keyboard mappings (mainly coming from de-de requirements)
132 ** [yY][Y][yY][zZ]
133 ** 1 2 3 4
134 **
135 ** 1 - does yes for the 3 different prompt types
136 ** 2 - does Ctrl+Y for stopping display of custom message of song title
137 ** 3 - something for preset editing (not 100% sure what)
138 ** 4 - used for the previous track sent to Winamp
139 */
140 WASABI_API_LNGSTRING_BUF(IDS_KEY_MAPPINGS, keyMappings, 8);
141
142 // as we're under a different thread we need to set the locale
143 //WASABI_API_LNG->UseUserNumericLocale();
144 g_use_C_locale = WASABI_API_LNG->Get_C_NumericLocale();
145 }
146
147 return &hdr;
148 }
149 #ifdef __cplusplus
150 }
151 #endif
152
WaitUntilPluginFinished(HWND hWndWinamp)153 bool WaitUntilPluginFinished(HWND hWndWinamp)
154 {
155 int slept = 0;
156 while (!g_bFullyExited && slept < 1000)
157 {
158 Sleep(50);
159 slept += 50;
160 }
161
162 if (!g_bFullyExited)
163 {
164 wchar_t title[64];
165 MessageBoxW(hWndWinamp, WASABI_API_LNGSTRINGW(IDS_ERROR_THE_PLUGIN_IS_ALREADY_RUNNING),
166 WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
167 MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
168 return false;
169 }
170
171 return true;
172 }
173
GetDialogBoxParent(HWND winamp)174 HWND GetDialogBoxParent(HWND winamp)
175 {
176 HWND parent = (HWND)SendMessage(winamp, WM_WA_IPC, 0, IPC_GETDIALOGBOXPARENT);
177 if (!parent || parent == (HWND)1)
178 return winamp;
179 return parent;
180 }
181
182 // configuration. Passed this_mod, as a "this" parameter. Allows you to make one configuration
183 // function that shares code for all your modules (you don't HAVE to use it though, you can make
184 // config1(), config2(), etc...)
config(struct winampVisModule * this_mod)185 void config(struct winampVisModule *this_mod)
186 {
187 if (!g_bFullyExited)
188 {
189 g_plugin.OnAltK();
190 return;
191 }
192
193 g_bFullyExited = false;
194 g_plugin.PluginPreInitialize(this_mod->hwndParent, this_mod->hDllInstance);
195 WASABI_API_DIALOGBOXPARAMW(IDD_CONFIG, GetDialogBoxParent(this_mod->hwndParent), g_plugin.ConfigDialogProc, (LPARAM)&g_plugin);
196 g_bFullyExited = true;
197 }
198
199 int (*warand)(void) = 0;
200
fallback_rand_fn(void)201 int fallback_rand_fn(void) {
202 return rand();
203 }
204
205 // initialization. Registers our window class, creates our window, etc. Again, this one works for
206 // both modules, but you could make init1() and init2()...
207 // returns 0 on success, 1 on failure.
init(struct winampVisModule * this_mod)208 int init(struct winampVisModule *this_mod)
209 {
210 DWORD version = GetWinampVersion(mod1.hwndParent);
211
212 if (!warand)
213 {
214 warand = (int (*)(void))SendMessage(this_mod->hwndParent, WM_WA_IPC, 0, IPC_GET_RANDFUNC);
215 if ((size_t)warand <= 1)
216 {
217 warand = fallback_rand_fn;
218 }
219 }
220
221 if (!WaitUntilPluginFinished(this_mod->hwndParent))
222 {
223 return 1;
224 }
225
226 if (GetWinampVersion(mod1.hwndParent) < 0x4000)
227 {
228 // query winamp for its playback state
229 LRESULT ret = SendMessage(this_mod->hwndParent, WM_USER, 0, 104);
230 // ret=1: playing, ret=3: paused, other: stopped
231
232 if (ret != 1)
233 {
234 wchar_t title[64];
235 MessageBoxW(this_mod->hwndParent, WASABI_API_LNGSTRINGW(IDS_THIS_PLUGIN_NEEDS_MUSIC_TO_RUN),
236 WASABI_API_LNGSTRINGW_BUF(IDS_NO_MUSIC_PLAYING, title, 64),
237 MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL );
238 return 1; // failure
239 }
240 }
241
242 g_bFullyExited = false;
243
244 if (!g_plugin.PluginPreInitialize(this_mod->hwndParent, this_mod->hDllInstance))
245 {
246 g_plugin.PluginQuit();
247 g_bFullyExited = true;
248 return 1;
249 }
250
251 if (!g_plugin.PluginInitialize())
252 {
253 g_plugin.PluginQuit();
254 g_bFullyExited = true;
255 return 1;
256 }
257
258 return 0; // success
259 }
260
261 // render function for oscilliscope. Returns 0 if successful, 1 if visualization should end.
render1(struct winampVisModule * this_mod)262 int render1(struct winampVisModule *this_mod)
263 {
264 if (g_plugin.PluginRender(this_mod->waveformData[0], this_mod->waveformData[1]))
265 return 0; // ok
266 else
267 return 1; // failed
268 }
269
270 // cleanup (opposite of init()). Should destroy the window, unregister the window class, etc.
quit(struct winampVisModule * this_mod)271 void quit(struct winampVisModule *this_mod)
272 {
273 g_plugin.PluginQuit();
274 g_bFullyExited = true;
275 }