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 "utility.h"
32 #include <math.h>
33 #include <locale.h>
34 #include <windows.h>
35 #ifdef _DEBUG
36     #define D3D_DEBUG_INFO  // declare this before including d3d9.h
37 #endif
38 #include <d3d9.h>
39 #include "../Winamp/wa_ipc.h"
40 #include "resource.h"
41 #include <shellapi.h>
42 
myOpenURL(HWND hwnd,wchar_t * loc)43 intptr_t myOpenURL(HWND hwnd, wchar_t *loc)
44 {
45 	if (loc)
46 	{
47 		bool override=false;
48 		WASABI_API_SYSCB->syscb_issueCallback(SysCallback::BROWSER, BrowserCallback::ONOPENURL, reinterpret_cast<intptr_t>(loc), reinterpret_cast<intptr_t>(&override));
49 		if (!override)
50 			return (intptr_t)ShellExecuteW(hwnd, L"open", loc, NULL, NULL, SW_SHOWNORMAL);
51 		else
52 			return 33;
53 	}
54 	return 33;
55 }
56 
PowCosineInterp(float x,float pow)57 float PowCosineInterp(float x, float pow)
58 {
59     // input (x) & output should be in range 0..1.
60     // pow > 0: tends to push things toward 0 and 1
61     // pow < 0: tends to push things toward 0.5.
62 
63     if (x<0)
64         return 0;
65     if (x>1)
66         return 1;
67 
68     int bneg = (pow < 0) ? 1 : 0;
69     if (bneg)
70         pow = -pow;
71 
72     if (pow>1000) pow=1000;
73 
74     int its = (int)pow;
75     for (int i=0; i<its; i++)
76     {
77         if (bneg)
78             x = InvCosineInterp(x);
79         else
80             x = CosineInterp(x);
81     }
82     float x2 = (bneg) ? InvCosineInterp(x) : CosineInterp(x);
83     float dx = pow - its;
84     return ((1-dx)*x + (dx)*x2);
85 }
86 
AdjustRateToFPS(float per_frame_decay_rate_at_fps1,float fps1,float actual_fps)87 float AdjustRateToFPS(float per_frame_decay_rate_at_fps1, float fps1, float actual_fps)
88 {
89     // returns the equivalent per-frame decay rate at actual_fps
90 
91     // basically, do all your testing at fps1 and get a good decay rate;
92     // then, in the real application, adjust that rate by the actual fps each time you use it.
93 
94     float per_second_decay_rate_at_fps1 = powf(per_frame_decay_rate_at_fps1, fps1);
95     float per_frame_decay_rate_at_fps2 = powf(per_second_decay_rate_at_fps1, 1.0f/actual_fps);
96 
97     return per_frame_decay_rate_at_fps2;
98 }
99 
GetPrivateProfileFloatW(wchar_t * szSectionName,wchar_t * szKeyName,float fDefault,wchar_t * szIniFile)100 float GetPrivateProfileFloatW(wchar_t *szSectionName, wchar_t *szKeyName, float fDefault, wchar_t *szIniFile)
101 {
102     wchar_t string[64];
103     wchar_t szDefault[64];
104     float ret = fDefault;
105 
106     _swprintf_l(szDefault, L"%f", g_use_C_locale, fDefault);
107 
108     if (GetPrivateProfileStringW(szSectionName, szKeyName, szDefault, string, 64, szIniFile) > 0)
109     {
110         _swscanf_l(string, L"%f", g_use_C_locale, &ret);
111     }
112     return ret;
113 }
114 
WritePrivateProfileFloatW(float f,wchar_t * szKeyName,wchar_t * szIniFile,wchar_t * szSectionName)115 bool WritePrivateProfileFloatW(float f, wchar_t *szKeyName, wchar_t *szIniFile, wchar_t *szSectionName)
116 {
117     wchar_t szValue[32];
118     _swprintf_l(szValue, L"%f", g_use_C_locale, f);
119     return (WritePrivateProfileStringW(szSectionName, szKeyName, szValue, szIniFile) != 0);
120 }
121 
WritePrivateProfileIntW(int d,wchar_t * szKeyName,wchar_t * szIniFile,wchar_t * szSectionName)122 bool WritePrivateProfileIntW(int d, wchar_t *szKeyName, wchar_t *szIniFile, wchar_t *szSectionName)
123 {
124     wchar_t szValue[32];
125     swprintf(szValue, L"%d", d);
126     return (WritePrivateProfileStringW(szSectionName, szKeyName, szValue, szIniFile) != 0);
127 }
128 
SetScrollLock(int bNewState,bool bPreventHandling)129 void SetScrollLock(int bNewState, bool bPreventHandling)
130 {
131 	if(bPreventHandling) return;
132 
133     if (bNewState != (GetKeyState(VK_SCROLL) & 1))
134     {
135         // Simulate a key press
136         keybd_event( VK_SCROLL,
137                       0x45,
138                       KEYEVENTF_EXTENDEDKEY | 0,
139                       0 );
140 
141         // Simulate a key release
142         keybd_event( VK_SCROLL,
143                       0x45,
144                       KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,
145                       0);
146     }
147 }
148 
RemoveExtension(wchar_t * str)149 void RemoveExtension(wchar_t *str)
150 {
151     wchar_t *p = wcsrchr(str, L'.');
152     if (p) *p = 0;
153 }
154 
ShiftDown(wchar_t * str)155 static void ShiftDown(wchar_t *str)
156 {
157 	while (*str)
158 	{
159 		str[0] = str[1];
160 		str++;
161 	}
162 }
163 
RemoveSingleAmpersands(wchar_t * str)164 void RemoveSingleAmpersands(wchar_t *str)
165 {
166 	while (*str)
167 	{
168 		if (str[0] == L'&')
169 		{
170 			if (str[1] == L'&') // two in a row: replace with single ampersand, move on
171 				str++;
172 
173 			ShiftDown(str);
174 		}
175 		else
176 			str = CharNextW(str);
177 	}
178 }
179 
TextToGuid(char * str,GUID * pGUID)180 void TextToGuid(char *str, GUID *pGUID)
181 {
182     if (!str) return;
183     if (!pGUID) return;
184 
185     DWORD d[11];
186 
187     sscanf(str, "%X %X %X %X %X %X %X %X %X %X %X",
188         &d[0], &d[1], &d[2], &d[3], &d[4], &d[5], &d[6], &d[7], &d[8], &d[9], &d[10]);
189 
190     pGUID->Data1 = (DWORD)d[0];
191     pGUID->Data2 = (WORD)d[1];
192     pGUID->Data3 = (WORD)d[2];
193     pGUID->Data4[0] = (BYTE)d[3];
194     pGUID->Data4[1] = (BYTE)d[4];
195     pGUID->Data4[2] = (BYTE)d[5];
196     pGUID->Data4[3] = (BYTE)d[6];
197     pGUID->Data4[4] = (BYTE)d[7];
198     pGUID->Data4[5] = (BYTE)d[8];
199     pGUID->Data4[6] = (BYTE)d[9];
200     pGUID->Data4[7] = (BYTE)d[10];
201 }
202 
GuidToText(GUID * pGUID,char * str,int nStrLen)203 void GuidToText(GUID *pGUID, char *str, int nStrLen)
204 {
205     // note: nStrLen should be set to sizeof(str).
206     if (!str) return;
207     if (!nStrLen) return;
208     str[0] = 0;
209     if (!pGUID) return;
210 
211     DWORD d[11];
212     d[0]  = (DWORD)pGUID->Data1;
213     d[1]  = (DWORD)pGUID->Data2;
214     d[2]  = (DWORD)pGUID->Data3;
215     d[3]  = (DWORD)pGUID->Data4[0];
216     d[4]  = (DWORD)pGUID->Data4[1];
217     d[5]  = (DWORD)pGUID->Data4[2];
218     d[6]  = (DWORD)pGUID->Data4[3];
219     d[7]  = (DWORD)pGUID->Data4[4];
220     d[8]  = (DWORD)pGUID->Data4[5];
221     d[9]  = (DWORD)pGUID->Data4[6];
222     d[10] = (DWORD)pGUID->Data4[7];
223 
224     sprintf(str, "%08X %04X %04X %02X %02X %02X %02X %02X %02X %02X %02X",
225         d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10]);
226 }
227 
228 /*
229 int GetPentiumTimeRaw(unsigned __int64 *cpu_timestamp)
230 {
231     // returns 0 on failure, 1 on success
232     // warning: watch out for wraparound!
233 
234     // note: it's probably better to use QueryPerformanceFrequency
235     // and QueryPerformanceCounter()!
236 
237     // get high-precision time:
238     __try
239     {
240         unsigned __int64 *dest = (unsigned __int64 *)cpu_timestamp;
241         __asm
242         {
243             _emit 0xf        // these two bytes form the 'rdtsc' asm instruction,
244             _emit 0x31       //  available on Pentium I and later.
245             mov esi, dest
246             mov [esi  ], eax    // lower 32 bits of tsc
247             mov [esi+4], edx    // upper 32 bits of tsc
248         }
249         return 1;
250     }
251     __except(EXCEPTION_EXECUTE_HANDLER)
252     {
253         return 0;
254     }
255 
256     return 0;
257 }
258 
259 double GetPentiumTimeAsDouble(unsigned __int64 frequency)
260 {
261     // returns < 0 on failure; otherwise, returns current cpu time, in seconds.
262     // warning: watch out for wraparound!
263 
264     // note: it's probably better to use QueryPerformanceFrequency
265     // and QueryPerformanceCounter()!
266 
267     if (frequency==0)
268         return -1.0;
269 
270     // get high-precision time:
271     __try
272     {
273         unsigned __int64 high_perf_time;
274         unsigned __int64 *dest = &high_perf_time;
275         __asm
276         {
277             _emit 0xf        // these two bytes form the 'rdtsc' asm instruction,
278             _emit 0x31       //  available on Pentium I and later.
279             mov esi, dest
280             mov [esi  ], eax    // lower 32 bits of tsc
281             mov [esi+4], edx    // upper 32 bits of tsc
282         }
283         __int64 time_s     = (__int64)(high_perf_time / frequency);  // unsigned->sign conversion should be safe here
284         __int64 time_fract = (__int64)(high_perf_time % frequency);  // unsigned->sign conversion should be safe here
285         // note: here, we wrap the timer more frequently (once per week)
286         // than it otherwise would (VERY RARELY - once every 585 years on
287         // a 1 GHz), to alleviate floating-point precision errors that start
288         // to occur when you get to very high counter values.
289         double ret = (time_s % (60*60*24*7)) + (double)time_fract/(double)((__int64)frequency);
290         return ret;
291     }
292     __except(EXCEPTION_EXECUTE_HANDLER)
293     {
294         return -1.0;
295     }
296 
297     return -1.0;
298 }
299 */
300 
301 #ifdef _DEBUG
OutputDebugMessage(char * szStartText,HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)302     void OutputDebugMessage(char *szStartText, HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
303     {
304         // note: this function does NOT log WM_MOUSEMOVE, WM_NCHITTEST, or WM_SETCURSOR
305         //        messages, since they are so frequent.
306         // note: these identifiers were pulled from winuser.h
307 
308         //if (msg == WM_MOUSEMOVE || msg == WM_NCHITTEST || msg == WM_SETCURSOR)
309         //    return;
310 
311         #ifdef _DEBUG
312             char buf[64];
313             int matched = 1;
314 
315             sprintf(buf, "WM_");
316 
317             switch(msg)
318             {
319             case 0x0001: lstrcat(buf, "CREATE"); break;
320             case 0x0002: lstrcat(buf, "DESTROY"); break;
321             case 0x0003: lstrcat(buf, "MOVE"); break;
322             case 0x0005: lstrcat(buf, "SIZE"); break;
323             case 0x0006: lstrcat(buf, "ACTIVATE"); break;
324             case 0x0007: lstrcat(buf, "SETFOCUS"); break;
325             case 0x0008: lstrcat(buf, "KILLFOCUS"); break;
326             case 0x000A: lstrcat(buf, "ENABLE"); break;
327             case 0x000B: lstrcat(buf, "SETREDRAW"); break;
328             case 0x000C: lstrcat(buf, "SETTEXT"); break;
329             case 0x000D: lstrcat(buf, "GETTEXT"); break;
330             case 0x000E: lstrcat(buf, "GETTEXTLENGTH"); break;
331             case 0x000F: lstrcat(buf, "PAINT"); break;
332             case 0x0010: lstrcat(buf, "CLOSE"); break;
333             case 0x0011: lstrcat(buf, "QUERYENDSESSION"); break;
334             case 0x0012: lstrcat(buf, "QUIT"); break;
335             case 0x0013: lstrcat(buf, "QUERYOPEN"); break;
336             case 0x0014: lstrcat(buf, "ERASEBKGND"); break;
337             case 0x0015: lstrcat(buf, "SYSCOLORCHANGE"); break;
338             case 0x0016: lstrcat(buf, "ENDSESSION"); break;
339             case 0x0018: lstrcat(buf, "SHOWWINDOW"); break;
340             case 0x001A: lstrcat(buf, "WININICHANGE"); break;
341             case 0x001B: lstrcat(buf, "DEVMODECHANGE"); break;
342             case 0x001C: lstrcat(buf, "ACTIVATEAPP"); break;
343             case 0x001D: lstrcat(buf, "FONTCHANGE"); break;
344             case 0x001E: lstrcat(buf, "TIMECHANGE"); break;
345             case 0x001F: lstrcat(buf, "CANCELMODE"); break;
346             case 0x0020: lstrcat(buf, "SETCURSOR"); break;
347             case 0x0021: lstrcat(buf, "MOUSEACTIVATE"); break;
348             case 0x0022: lstrcat(buf, "CHILDACTIVATE"); break;
349             case 0x0023: lstrcat(buf, "QUEUESYNC"); break;
350             case 0x0024: lstrcat(buf, "GETMINMAXINFO"); break;
351             case 0x0026: lstrcat(buf, "PAINTICON"); break;
352             case 0x0027: lstrcat(buf, "ICONERASEBKGND"); break;
353             case 0x0028: lstrcat(buf, "NEXTDLGCTL"); break;
354             case 0x002A: lstrcat(buf, "SPOOLERSTATUS"); break;
355             case 0x002B: lstrcat(buf, "DRAWITEM"); break;
356             case 0x002C: lstrcat(buf, "MEASUREITEM"); break;
357             case 0x002D: lstrcat(buf, "DELETEITEM"); break;
358             case 0x002E: lstrcat(buf, "VKEYTOITEM"); break;
359             case 0x002F: lstrcat(buf, "CHARTOITEM"); break;
360             case 0x0030: lstrcat(buf, "SETFONT"); break;
361             case 0x0031: lstrcat(buf, "GETFONT"); break;
362             case 0x0032: lstrcat(buf, "SETHOTKEY"); break;
363             case 0x0033: lstrcat(buf, "GETHOTKEY"); break;
364             case 0x0037: lstrcat(buf, "QUERYDRAGICON"); break;
365             case 0x0039: lstrcat(buf, "COMPAREITEM"); break;
366             case 0x0041: lstrcat(buf, "COMPACTING"); break;
367             case 0x0044: lstrcat(buf, "COMMNOTIFY"); break;
368             case 0x0046: lstrcat(buf, "WINDOWPOSCHANGING"); break;
369             case 0x0047: lstrcat(buf, "WINDOWPOSCHANGED"); break;
370             case 0x0048: lstrcat(buf, "POWER"); break;
371             case 0x004A: lstrcat(buf, "COPYDATA"); break;
372             case 0x004B: lstrcat(buf, "CANCELJOURNAL"); break;
373 
374             #if(WINVER >= 0x0400)
375             case 0x004E: lstrcat(buf, "NOTIFY"); break;
376             case 0x0050: lstrcat(buf, "INPUTLANGCHANGEREQUEST"); break;
377             case 0x0051: lstrcat(buf, "INPUTLANGCHANGE"); break;
378             case 0x0052: lstrcat(buf, "TCARD"); break;
379             case 0x0053: lstrcat(buf, "HELP"); break;
380             case 0x0054: lstrcat(buf, "USERCHANGED"); break;
381             case 0x0055: lstrcat(buf, "NOTIFYFORMAT"); break;
382             case 0x007B: lstrcat(buf, "CONTEXTMENU"); break;
383             case 0x007C: lstrcat(buf, "STYLECHANGING"); break;
384             case 0x007D: lstrcat(buf, "STYLECHANGED"); break;
385             case 0x007E: lstrcat(buf, "DISPLAYCHANGE"); break;
386             case 0x007F: lstrcat(buf, "GETICON"); break;
387             case 0x0080: lstrcat(buf, "SETICON"); break;
388             #endif
389 
390             case 0x0081: lstrcat(buf, "NCCREATE"); break;
391             case 0x0082: lstrcat(buf, "NCDESTROY"); break;
392             case 0x0083: lstrcat(buf, "NCCALCSIZE"); break;
393             case 0x0084: lstrcat(buf, "NCHITTEST"); break;
394             case 0x0085: lstrcat(buf, "NCPAINT"); break;
395             case 0x0086: lstrcat(buf, "NCACTIVATE"); break;
396             case 0x0087: lstrcat(buf, "GETDLGCODE"); break;
397             case 0x0088: lstrcat(buf, "SYNCPAINT"); break;
398             case 0x00A0: lstrcat(buf, "NCMOUSEMOVE"); break;
399             case 0x00A1: lstrcat(buf, "NCLBUTTONDOWN"); break;
400             case 0x00A2: lstrcat(buf, "NCLBUTTONUP"); break;
401             case 0x00A3: lstrcat(buf, "NCLBUTTONDBLCLK"); break;
402             case 0x00A4: lstrcat(buf, "NCRBUTTONDOWN"); break;
403             case 0x00A5: lstrcat(buf, "NCRBUTTONUP"); break;
404             case 0x00A6: lstrcat(buf, "NCRBUTTONDBLCLK"); break;
405             case 0x00A7: lstrcat(buf, "NCMBUTTONDOWN"); break;
406             case 0x00A8: lstrcat(buf, "NCMBUTTONUP"); break;
407             case 0x00A9: lstrcat(buf, "NCMBUTTONDBLCLK"); break;
408             case 0x0100: lstrcat(buf, "KEYDOWN"); break;
409             case 0x0101: lstrcat(buf, "KEYUP"); break;
410             case 0x0102: lstrcat(buf, "CHAR"); break;
411             case 0x0103: lstrcat(buf, "DEADCHAR"); break;
412             case 0x0104: lstrcat(buf, "SYSKEYDOWN"); break;
413             case 0x0105: lstrcat(buf, "SYSKEYUP"); break;
414             case 0x0106: lstrcat(buf, "SYSCHAR"); break;
415             case 0x0107: lstrcat(buf, "SYSDEADCHAR"); break;
416             case 0x0108: lstrcat(buf, "KEYLAST"); break;
417 
418             #if(WINVER >= 0x0400)
419             case 0x010D: lstrcat(buf, "IME_STARTCOMPOSITION"); break;
420             case 0x010E: lstrcat(buf, "IME_ENDCOMPOSITION"); break;
421             case 0x010F: lstrcat(buf, "IME_COMPOSITION"); break;
422             //case 0x010F: lstrcat(buf, "IME_KEYLAST"); break;
423             #endif
424 
425             case 0x0110: lstrcat(buf, "INITDIALOG"); break;
426             case 0x0111: lstrcat(buf, "COMMAND"); break;
427             case 0x0112: lstrcat(buf, "SYSCOMMAND"); break;
428             case 0x0113: lstrcat(buf, "TIMER"); break;
429             case 0x0114: lstrcat(buf, "HSCROLL"); break;
430             case 0x0115: lstrcat(buf, "VSCROLL"); break;
431             case 0x0116: lstrcat(buf, "INITMENU"); break;
432             case 0x0117: lstrcat(buf, "INITMENUPOPUP"); break;
433             case 0x011F: lstrcat(buf, "MENUSELECT"); break;
434             case 0x0120: lstrcat(buf, "MENUCHAR"); break;
435             case 0x0121: lstrcat(buf, "ENTERIDLE"); break;
436             #if(WINVER >= 0x0500)
437             case 0x0122: lstrcat(buf, "MENURBUTTONUP"); break;
438             case 0x0123: lstrcat(buf, "MENUDRAG"); break;
439             case 0x0124: lstrcat(buf, "MENUGETOBJECT"); break;
440             case 0x0125: lstrcat(buf, "UNINITMENUPOPUP"); break;
441             case 0x0126: lstrcat(buf, "MENUCOMMAND"); break;
442             #endif
443 
444             case 0x0132: lstrcat(buf, "CTLCOLORMSGBOX"); break;
445             case 0x0133: lstrcat(buf, "CTLCOLOREDIT"); break;
446             case 0x0134: lstrcat(buf, "CTLCOLORLISTBOX"); break;
447             case 0x0135: lstrcat(buf, "CTLCOLORBTN"); break;
448             case 0x0136: lstrcat(buf, "CTLCOLORDLG"); break;
449             case 0x0137: lstrcat(buf, "CTLCOLORSCROLLBAR"); break;
450             case 0x0138: lstrcat(buf, "CTLCOLORSTATIC"); break;
451 
452             //case 0x0200: lstrcat(buf, "MOUSEFIRST"); break;
453             case 0x0200: lstrcat(buf, "MOUSEMOVE"); break;
454             case 0x0201: lstrcat(buf, "LBUTTONDOWN"); break;
455             case 0x0202: lstrcat(buf, "LBUTTONUP"); break;
456             case 0x0203: lstrcat(buf, "LBUTTONDBLCLK"); break;
457             case 0x0204: lstrcat(buf, "RBUTTONDOWN"); break;
458             case 0x0205: lstrcat(buf, "RBUTTONUP"); break;
459             case 0x0206: lstrcat(buf, "RBUTTONDBLCLK"); break;
460             case 0x0207: lstrcat(buf, "MBUTTONDOWN"); break;
461             case 0x0208: lstrcat(buf, "MBUTTONUP"); break;
462             case 0x0209: lstrcat(buf, "MBUTTONDBLCLK"); break;
463 
464             #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
465             case 0x020A: lstrcat(buf, "MOUSEWHEEL"); break;
466             case 0x020E: lstrcat(buf, "MOUSELAST"); break;
467             #else
468             //case 0x0209: lstrcat(buf, "MOUSELAST"); break;
469             #endif
470 
471             case 0x0210: lstrcat(buf, "PARENTNOTIFY"); break;
472             case 0x0211: lstrcat(buf, "ENTERMENULOOP"); break;
473             case 0x0212: lstrcat(buf, "EXITMENULOOP"); break;
474 
475             #if(WINVER >= 0x0400)
476             case 0x0213: lstrcat(buf, "NEXTMENU"); break;
477             case 0x0214: lstrcat(buf, "SIZING"); break;
478             case 0x0215: lstrcat(buf, "CAPTURECHANGED"); break;
479             case 0x0216: lstrcat(buf, "MOVING"); break;
480             case 0x0218: lstrcat(buf, "POWERBROADCAST"); break;
481             case 0x0219: lstrcat(buf, "DEVICECHANGE"); break;
482             #endif
483 
484             /*
485             case 0x0220: lstrcat(buf, "MDICREATE"); break;
486             case 0x0221: lstrcat(buf, "MDIDESTROY"); break;
487             case 0x0222: lstrcat(buf, "MDIACTIVATE"); break;
488             case 0x0223: lstrcat(buf, "MDIRESTORE"); break;
489             case 0x0224: lstrcat(buf, "MDINEXT"); break;
490             case 0x0225: lstrcat(buf, "MDIMAXIMIZE"); break;
491             case 0x0226: lstrcat(buf, "MDITILE"); break;
492             case 0x0227: lstrcat(buf, "MDICASCADE"); break;
493             case 0x0228: lstrcat(buf, "MDIICONARRANGE"); break;
494             case 0x0229: lstrcat(buf, "MDIGETACTIVE"); break;
495             */
496 
497             case 0x0230: lstrcat(buf, "MDISETMENU"); break;
498             case 0x0231: lstrcat(buf, "ENTERSIZEMOVE"); break;
499             case 0x0232: lstrcat(buf, "EXITSIZEMOVE"); break;
500             case 0x0233: lstrcat(buf, "DROPFILES"); break;
501             case 0x0234: lstrcat(buf, "MDIREFRESHMENU"); break;
502 
503 
504             /*
505             #if(WINVER >= 0x0400)
506             case 0x0281: lstrcat(buf, "IME_SETCONTEXT"); break;
507             case 0x0282: lstrcat(buf, "IME_NOTIFY"); break;
508             case 0x0283: lstrcat(buf, "IME_CONTROL"); break;
509             case 0x0284: lstrcat(buf, "IME_COMPOSITIONFULL"); break;
510             case 0x0285: lstrcat(buf, "IME_SELECT"); break;
511             case 0x0286: lstrcat(buf, "IME_CHAR"); break;
512             #endif
513             #if(WINVER >= 0x0500)
514             case 0x0288: lstrcat(buf, "IME_REQUEST"); break;
515             #endif
516             #if(WINVER >= 0x0400)
517             case 0x0290: lstrcat(buf, "IME_KEYDOWN"); break;
518             case 0x0291: lstrcat(buf, "IME_KEYUP"); break;
519             #endif
520             */
521 
522             #if(_WIN32_WINNT >= 0x0400)
523             case 0x02A1: lstrcat(buf, "MOUSEHOVER"); break;
524             case 0x02A3: lstrcat(buf, "MOUSELEAVE"); break;
525             #endif
526 
527             case 0x0300: lstrcat(buf, "CUT"); break;
528             case 0x0301: lstrcat(buf, "COPY"); break;
529             case 0x0302: lstrcat(buf, "PASTE"); break;
530             case 0x0303: lstrcat(buf, "CLEAR"); break;
531             case 0x0304: lstrcat(buf, "UNDO"); break;
532             case 0x0305: lstrcat(buf, "RENDERFORMAT"); break;
533             case 0x0306: lstrcat(buf, "RENDERALLFORMATS"); break;
534             case 0x0307: lstrcat(buf, "DESTROYCLIPBOARD"); break;
535             case 0x0308: lstrcat(buf, "DRAWCLIPBOARD"); break;
536             case 0x0309: lstrcat(buf, "PAINTCLIPBOARD"); break;
537             case 0x030A: lstrcat(buf, "VSCROLLCLIPBOARD"); break;
538             case 0x030B: lstrcat(buf, "SIZECLIPBOARD"); break;
539             case 0x030C: lstrcat(buf, "ASKCBFORMATNAME"); break;
540             case 0x030D: lstrcat(buf, "CHANGECBCHAIN"); break;
541             case 0x030E: lstrcat(buf, "HSCROLLCLIPBOARD"); break;
542             case 0x030F: lstrcat(buf, "QUERYNEWPALETTE"); break;
543             case 0x0310: lstrcat(buf, "PALETTEISCHANGING"); break;
544             case 0x0311: lstrcat(buf, "PALETTECHANGED"); break;
545             case 0x0312: lstrcat(buf, "HOTKEY"); break;
546 
547             #if(WINVER >= 0x0400)
548             case 0x0317: lstrcat(buf, "PRINT"); break;
549             case 0x0318: lstrcat(buf, "PRINTCLIENT"); break;
550 
551             case 0x0358: lstrcat(buf, "HANDHELDFIRST"); break;
552             case 0x035F: lstrcat(buf, "HANDHELDLAST"); break;
553 
554             case 0x0360: lstrcat(buf, "AFXFIRST"); break;
555             case 0x037F: lstrcat(buf, "AFXLAST"); break;
556             #endif
557 
558             case 0x0380: lstrcat(buf, "PENWINFIRST"); break;
559             case 0x038F: lstrcat(buf, "PENWINLAST"); break;
560 
561             default:
562                 sprintf(buf, "unknown");
563                 matched = 0;
564                 break;
565             }
566 
567             int n = strlen(buf);
568             int desired_len = 24;
569             int spaces_to_append = desired_len-n;
570             if (spaces_to_append>0)
571             {
572                 for (int i=0; i<spaces_to_append; i++)
573                     buf[n+i] = ' ';
574                 buf[desired_len] = 0;
575             }
576 
577             char buf2[256];
578             if (matched)
579                 sprintf(buf2, "%shwnd=%08x, msg=%s, w=%08x, l=%08x\n", szStartText, hwnd, buf, wParam, lParam);
580             else
581                 sprintf(buf2, "%shwnd=%08x, msg=unknown/0x%08x, w=%08x, l=%08x\n", szStartText, hwnd, msg, wParam, lParam);
582             OutputDebugString(buf2);
583         #endif
584     }
585 #endif
586 
DownloadDirectX(HWND hwnd)587 void DownloadDirectX(HWND hwnd)
588 {
589     wchar_t szUrl[] = L"http://www.microsoft.com/download/details.aspx?id=35";
590     intptr_t ret = myOpenURL(NULL, szUrl);
591     if (ret <= 32)
592     {
593         wchar_t buf[1024];
594         switch(ret)
595         {
596         case SE_ERR_FNF:
597         case SE_ERR_PNF:
598             swprintf(buf, WASABI_API_LNGSTRINGW(IDS_URL_COULD_NOT_OPEN), szUrl);
599             break;
600         case SE_ERR_ACCESSDENIED:
601         case SE_ERR_SHARE:
602             swprintf(buf, WASABI_API_LNGSTRINGW(IDS_ACCESS_TO_URL_WAS_DENIED), szUrl);
603             break;
604         case SE_ERR_NOASSOC:
605             swprintf(buf, WASABI_API_LNGSTRINGW(IDS_ACCESS_TO_URL_FAILED_DUE_TO_NO_ASSOC), szUrl);
606             break;
607         default:
608             swprintf(buf, WASABI_API_LNGSTRINGW(IDS_ACCESS_TO_URL_FAILED_CODE_X), szUrl, ret);
609             break;
610         }
611         MessageBoxW(hwnd, buf, WASABI_API_LNGSTRINGW(IDS_ERROR_OPENING_URL),
612 					MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL);
613     }
614 }
615 
MissingDirectX(HWND hwnd)616 void MissingDirectX(HWND hwnd)
617 {
618     // DIRECTX MISSING OR CORRUPT -> PROMPT TO GO TO WEB.
619 	wchar_t title[128];
620     int ret = MessageBoxW(hwnd,
621         #ifndef D3D_SDK_VERSION
622             --- error; you need to #include <d3d9.h> ---
623         #endif
624         #if (D3D_SDK_VERSION==120)
625             // plugin was *built* using the DirectX 9.0 sdk, therefore,
626             // the dx9.0 runtime is missing or corrupt
627             "Failed to initialize DirectX 9.0 or later.\n"
628             "Milkdrop requires d3dx9_31.dll to be installed.\n"
629             "\n"
630             "Would you like to be taken to:\n"
631 			"http://www.microsoft.com/download/details.aspx?id=35,\n"
632             "where you can update DirectX 9.0?\n"
633             XXXXXXX
634         #else
635             // plugin was *built* using some other version of the DirectX9 sdk, such as
636             // 9.1b; therefore, we don't know exactly what version to tell them they need
637             // to install; so we ask them to go get the *latest* version.
638             WASABI_API_LNGSTRINGW(IDS_DIRECTX_MISSING_OR_CORRUPT_TEXT)
639         #endif
640         ,
641 		WASABI_API_LNGSTRINGW_BUF(IDS_DIRECTX_MISSING_OR_CORRUPT, title, 128),
642 		MB_YESNO|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL);
643 
644     if (ret==IDYES)
645         DownloadDirectX(hwnd);
646 }
647 
CheckForMMX()648 bool CheckForMMX()
649 {
650     DWORD bMMX = 0;
651     DWORD *pbMMX = &bMMX;
652     __try {
653         __asm {
654             mov eax, 1
655             cpuid
656             mov edi, pbMMX
657             mov dword ptr [edi], edx
658         }
659     }
660     __except(EXCEPTION_EXECUTE_HANDLER)
661     {
662         bMMX = 0;
663     }
664 
665     if (bMMX & 0x00800000)  // check bit 23
666 		return true;
667 
668 	return false;
669 }
670 
CheckForSSE()671 bool CheckForSSE()
672 {
673 #ifdef _WIN64
674 	return true; // All x64 processors support SSE
675 #else
676     /*
677     The SSE instruction set was introduced with the Pentium III and features:
678         * Additional MMX instructions such as min/max
679         * Prefetch and write-through instructions for optimizing data movement
680             from and to the L2/L3 caches and main memory
681         * 8 New 128 bit XMM registers (xmm0..xmm7) and corresponding 32 bit floating point
682             (single precision) instructions
683     */
684 
685 	DWORD bSSE = 0;
686 	DWORD *pbSSE = &bSSE;
687     __try {
688 	    __asm
689 	    {
690 		    mov eax, 1
691 		    cpuid
692             mov edi, pbSSE
693             mov dword ptr [edi], edx
694 	    }
695     }
696     __except(EXCEPTION_EXECUTE_HANDLER)
697     {
698         bSSE = 0;
699     }
700 
701 	if (bSSE & 0x02000000)  // check bit 25
702 		return true;
703 
704 	return false;
705 #endif
706 }
707 
GetDesktopFolder(char * szDesktopFolder)708 void GetDesktopFolder(char *szDesktopFolder) // should be MAX_PATH len.
709 {
710     // returns the path to the desktop folder, WITHOUT a trailing backslash.
711     szDesktopFolder[0] = 0;
712     ITEMIDLIST pidl;
713     ZeroMemory(&pidl, sizeof(pidl));
714     if (!SHGetPathFromIDList(&pidl, szDesktopFolder))
715         szDesktopFolder[0] = 0;
716 }
717 
ExecutePidl(LPITEMIDLIST pidl,char * szPathAndFile,char * szWorkingDirectory,HWND hWnd)718 void ExecutePidl(LPITEMIDLIST pidl, char *szPathAndFile, char *szWorkingDirectory, HWND hWnd)
719 {
720     // This function was based on code by Jeff Prosise.
721 
722     // Note: for some reason, ShellExecuteEx fails when executing
723     // *shortcuts* (.lnk files) from the desktop, using their PIDLs.
724     // So, if that fails, we try again w/the plain old text filename
725     // (szPathAndFile).
726 
727     char szVerb[] = "open";
728     char szFilename2[MAX_PATH];
729 
730     sprintf(szFilename2, "%s.lnk", szPathAndFile);
731 
732     // -without the "no-verb" pass,
733     //   certain icons still don't work (like shortcuts
734     //   to IE, VTune...)
735     // -without the "context menu" pass,
736     //   certain others STILL don't work (Netscape...)
737     // -without the 'ntry' pass, shortcuts (to folders/files)
738     //   don't work
739     for (int verb_pass=0; verb_pass<2; verb_pass++)
740     {
741         for (int ntry=0; ntry<3; ntry++)
742         {
743             for (int context_pass=0; context_pass<2; context_pass++)
744             {
745                 SHELLEXECUTEINFO sei = { sizeof(sei) };
746                 sei.hwnd = hWnd;
747                 sei.fMask = SEE_MASK_FLAG_NO_UI;
748                 if (context_pass==1)
749                     sei.fMask |= SEE_MASK_INVOKEIDLIST;
750                 sei.lpVerb = (verb_pass) ? NULL : szVerb;
751                 sei.lpDirectory = szWorkingDirectory;
752                 sei.nShow = SW_SHOWNORMAL;
753 
754                 if (ntry==0)
755                 {
756                     // this case works for most non-shortcuts
757                     sei.fMask |= SEE_MASK_IDLIST;
758                     sei.lpIDList = pidl;
759                 }
760                 else if (ntry==1)
761                 {
762                     // this case is required for *shortcuts to folders* to work
763                     sei.lpFile = szPathAndFile;
764                 }
765                 else if (ntry==2)
766                 {
767                     // this case is required for *shortcuts to files* to work
768                     sei.lpFile = szFilename2;
769                 }
770 
771                 if (ShellExecuteEx(&sei))
772                     return;
773             }
774         }
775     }
776 }
777 
778 WNDPROC        g_pOldWndProc;
779 LPCONTEXTMENU2 g_pIContext2or3;
780 
HookWndProc(HWND hWnd,UINT msg,WPARAM wp,LPARAM lp)781 LRESULT CALLBACK HookWndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
782 {
783    //UINT uItem;
784    //TCHAR szBuf[MAX_PATH];
785 
786    switch (msg)
787    {
788    case WM_DRAWITEM:
789    case WM_MEASUREITEM:
790       if(wp) break; // not menu related
791    case WM_INITMENUPOPUP:
792       g_pIContext2or3->HandleMenuMsg(msg, wp, lp);
793       return (msg==WM_INITMENUPOPUP ? 0 : TRUE); // handled
794 
795    /*case WM_MENUSELECT:
796       // if this is a shell item, get its descriptive text
797       uItem = (UINT) LOWORD(wp);
798       if(0 == (MF_POPUP & HIWORD(wp)) && uItem >= 1 && uItem <= 0x7fff)
799       {
800          g_pIContext2or3->GetCommandString(uItem-1, GCS_HELPTEXT,
801             NULL, szBuf, sizeof(szBuf)/sizeof(szBuf[0]) );
802 
803          // set the status bar text
804          ((CFrameWnd*)(AfxGetApp()->m_pMainWnd))->SetMessageText(szBuf);
805          return 0;
806       }
807       break;*/
808 
809 	default:
810 		break;
811 	}
812 
813 	// for all untreated messages, call the original wndproc
814 	return ::CallWindowProc(g_pOldWndProc, hWnd, msg, wp, lp);
815 }
816 
DoExplorerMenu(HWND hwnd,LPITEMIDLIST pidlMain,POINT point)817 BOOL DoExplorerMenu (HWND hwnd, LPITEMIDLIST pidlMain, POINT point)
818 {
819     LPMALLOC pMalloc;
820     LPSHELLFOLDER psfFolder, psfNextFolder;
821     LPITEMIDLIST pidlItem, pidlNextItem, *ppidl;
822     LPCONTEXTMENU pContextMenu;
823     CMINVOKECOMMANDINFO ici;
824     UINT nCount, nCmd;
825     BOOL bResult;
826     HMENU hMenu;
827 
828     //
829     // Get pointers to the shell's IMalloc interface and the desktop's
830     // IShellFolder interface.
831     //
832     bResult = FALSE;
833 
834     if (!SUCCEEDED (SHGetMalloc (&pMalloc)))
835 		return bResult;
836 
837     if (!SUCCEEDED (SHGetDesktopFolder (&psfFolder))) {
838         pMalloc->Release();
839         return bResult;
840     }
841 
842     if (nCount = GetItemCount (pidlMain)) // nCount must be > 0
843     {
844         //
845         // Initialize psfFolder with a pointer to the IShellFolder
846         // interface of the folder that contains the item whose context
847         // menu we're after, and initialize pidlItem with a pointer to
848         // the item's item ID. If nCount > 1, this requires us to walk
849         // the list of item IDs stored in pidlMain and bind to each
850         // subfolder referenced in the list.
851         //
852         pidlItem = pidlMain;
853 
854         while (--nCount) {
855             //
856             // Create a 1-item item ID list for the next item in pidlMain.
857             //
858             pidlNextItem = DuplicateItem (pMalloc, pidlItem);
859             if (pidlNextItem == NULL) {
860                 psfFolder->Release();
861                 pMalloc->Release();
862                 return bResult;
863             }
864 
865             //
866             // Bind to the folder specified in the new item ID list.
867             //
868             if (!SUCCEEDED (psfFolder->BindToObject(pidlNextItem, NULL, IID_IShellFolder, (void**)&psfNextFolder)))  // modified by RG
869             {
870                 pMalloc->Free(pidlNextItem);
871                 psfFolder->Release();
872                 pMalloc->Release();
873                 return bResult;
874             }
875 
876             //
877             // Release the IShellFolder pointer to the parent folder
878             // and set psfFolder equal to the IShellFolder pointer for
879             // the current folder.
880             //
881             psfFolder->Release();
882             psfFolder = psfNextFolder;
883 
884             //
885             // Release the storage for the 1-item item ID list we created
886             // just a moment ago and initialize pidlItem so that it points
887             // to the next item in pidlMain.
888             //
889             pMalloc->Free(pidlNextItem);
890             pidlItem = GetNextItem (pidlItem);
891         }
892 
893         //
894         // Get a pointer to the item's IContextMenu interface and call
895         // IContextMenu::QueryContextMenu to initialize a context menu.
896         //
897         ppidl = &pidlItem;
898         if (SUCCEEDED (psfFolder->GetUIObjectOf(hwnd, 1, (LPCITEMIDLIST*)ppidl, IID_IContextMenu, NULL, (void**)&pContextMenu)))   // modified by RG
899         {
900             // try to see if we can upgrade to an IContextMenu3
901             // or IContextMenu2 interface pointer:
902             int level = 1;
903             void *pCM = NULL;
904             if (pContextMenu->QueryInterface(IID_IContextMenu3, &pCM) == NOERROR)
905             {
906                 pContextMenu->Release();
907                 pContextMenu = (LPCONTEXTMENU)pCM;
908                 level = 3;
909             }
910             else if (pContextMenu->QueryInterface(IID_IContextMenu2, &pCM) == NOERROR)
911             {
912                 pContextMenu->Release();
913                 pContextMenu = (LPCONTEXTMENU)pCM;
914                 level = 2;
915             }
916 
917             hMenu = CreatePopupMenu ();
918             if (SUCCEEDED (pContextMenu->QueryContextMenu(hMenu, 0, 1, 0x7FFF, CMF_EXPLORE)))
919             {
920                 ClientToScreen (hwnd, &point);
921 
922                 // install the subclassing "hook", for versions 2 or 3
923                 if (level >= 2)
924                 {
925                     g_pOldWndProc   = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (DWORD_PTR)HookWndProc);
926                     g_pIContext2or3 = (LPCONTEXTMENU2)pContextMenu; // cast ok for ICMv3
927                 }
928                 else
929                 {
930                     g_pOldWndProc   = NULL;
931                     g_pIContext2or3 = NULL;
932                 }
933 
934                 //
935                 // Display the context menu.
936                 //
937                 nCmd = TrackPopupMenu (hMenu, TPM_LEFTALIGN |
938                     TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD,
939                     point.x, point.y, 0, hwnd, NULL);
940 
941                 // restore old wndProc
942                 if (g_pOldWndProc)
943                 {
944                     SetWindowLongPtr(hwnd, GWL_WNDPROC, (LONG_PTR)g_pOldWndProc);
945                 }
946 
947                 //
948                 // If a command was selected from the menu, execute it.
949                 //
950                 if (nCmd >= 1 && nCmd <= 0x7fff)
951                 {
952                     ZeroMemory(&ici, sizeof(ici));
953                     ici.cbSize          = sizeof (CMINVOKECOMMANDINFO);
954                     //ici.fMask           = 0;
955                     ici.hwnd            = hwnd;
956                     ici.lpVerb          = MAKEINTRESOURCE (nCmd - 1);
957                     //ici.lpParameters    = NULL;
958                     //ici.lpDirectory     = NULL;
959                     ici.nShow           = SW_SHOWNORMAL;
960                     //ici.dwHotKey        = 0;
961                     //ici.hIcon           = NULL;
962 
963                     if (SUCCEEDED ( pContextMenu->InvokeCommand (&ici)))
964                         bResult = TRUE;
965                 }
966                 /*else if (nCmd)
967                 {
968                     PostMessage(hwnd, WM_COMMAND, nCmd, NULL); // our command
969                 }*/
970             }
971             DestroyMenu (hMenu);
972             pContextMenu->Release();
973         }
974     }
975 
976     //
977     // Clean up and return.
978     //
979     psfFolder->Release();
980     pMalloc->Release();
981 
982     return bResult;
983 }
984 
985 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
986 //
987 //  Note: a special thanks goes out to Jeff Prosise for writing & publishing
988 //        the following code!
989 //
990 //  FUNCTION:       GetItemCount
991 //
992 //  DESCRIPTION:    Computes the number of item IDs in an item ID list.
993 //
994 //  INPUT:          pidl = Pointer to an item ID list.
995 //
996 //  RETURNS:        Number of item IDs in the list.
997 //
998 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
999 
GetItemCount(LPITEMIDLIST pidl)1000 UINT GetItemCount (LPITEMIDLIST pidl)
1001 {
1002     USHORT nLen;
1003     UINT nCount;
1004 
1005     nCount = 0;
1006     while ((nLen = pidl->mkid.cb) != 0) {
1007         pidl = GetNextItem (pidl);
1008         nCount++;
1009     }
1010     return nCount;
1011 }
1012 
1013 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1014 //
1015 //  Note: a special thanks goes out to Jeff Prosise for writing & publishing
1016 //        the following code!
1017 //
1018 //  FUNCTION:       GetNextItem
1019 //
1020 //  DESCRIPTION:    Finds the next item in an item ID list.
1021 //
1022 //  INPUT:          pidl = Pointer to an item ID list.
1023 //
1024 //  RETURNS:        Pointer to the next item.
1025 //
1026 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1027 
GetNextItem(LPITEMIDLIST pidl)1028 LPITEMIDLIST GetNextItem (LPITEMIDLIST pidl)
1029 {
1030     USHORT nLen;
1031 
1032     if ((nLen = pidl->mkid.cb) == 0)
1033         return NULL;
1034 
1035     return (LPITEMIDLIST) (((LPBYTE) pidl) + nLen);
1036 }
1037 
1038 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1039 //
1040 //  Note: a special thanks goes out to Jeff Prosise for writing & publishing
1041 //        the following code!
1042 //
1043 //  FUNCTION:       DuplicateItem
1044 //
1045 //  DESCRIPTION:    Makes a copy of the next item in an item ID list.
1046 //
1047 //  INPUT:          pMalloc = Pointer to an IMalloc interface.
1048 //                  pidl    = Pointer to an item ID list.
1049 //
1050 //  RETURNS:        Pointer to an ITEMIDLIST containing the copied item ID.
1051 //
1052 //  NOTES:          It is the caller's responsibility to free the memory
1053 //                  allocated by this function when the item ID is no longer
1054 //                  needed. Example:
1055 //
1056 //                    pidlItem = DuplicateItem (pMalloc, pidl);
1057 //                      .
1058 //                      .
1059 //                      .
1060 //                    pMalloc->lpVtbl->Free (pMalloc, pidlItem);
1061 //
1062 //                  Failure to free the ITEMIDLIST will result in memory
1063 //                  leaks.
1064 //
1065 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1066 
DuplicateItem(LPMALLOC pMalloc,LPITEMIDLIST pidl)1067 LPITEMIDLIST DuplicateItem (LPMALLOC pMalloc, LPITEMIDLIST pidl)
1068 {
1069     USHORT nLen;
1070     LPITEMIDLIST pidlNew;
1071 
1072     nLen = pidl->mkid.cb;
1073     if (nLen == 0)
1074         return NULL;
1075 
1076     pidlNew = (LPITEMIDLIST) pMalloc->Alloc (
1077         nLen + sizeof (USHORT));
1078     if (pidlNew == NULL)
1079         return NULL;
1080 
1081     CopyMemory (pidlNew, pidl, nLen);
1082     *((USHORT*) (((LPBYTE) pidlNew) + nLen)) = 0;
1083 
1084     return pidlNew;
1085 }
1086 
1087 //----------------------------------------------------------------------
1088 // A special thanks goes out to Jeroen-bart Engelen (Yeep) for providing
1089 // his source code for getting the position & label information for all
1090 // the icons on the desktop, as found below.  See his article at
1091 // http://www.digiwar.com/scripts/renderpage.php?section=2&subsection=2
1092 //----------------------------------------------------------------------
1093 
FindDesktopWindows(HWND * desktop_progman,HWND * desktopview_wnd,HWND * listview_wnd)1094 void FindDesktopWindows(HWND *desktop_progman, HWND *desktopview_wnd, HWND *listview_wnd)
1095 {
1096     *desktop_progman = NULL;
1097 	*desktopview_wnd = NULL;
1098 	*listview_wnd = NULL;
1099 
1100 	*desktop_progman = FindWindow(NULL, ("Program Manager"));
1101 	if(*desktop_progman == NULL)
1102 	{
1103 		//MessageBox(NULL, "Unable to get the handle to the Program Manager.", "Fatal error", MB_OK|MB_ICONERROR);
1104 		return;
1105 	}
1106 
1107 	*desktopview_wnd = FindWindowEx(*desktop_progman, NULL, "SHELLDLL_DefView", NULL);
1108 	if(*desktopview_wnd == NULL)
1109 	{
1110 		//MessageBox(NULL, "Unable to get the handle to the desktopview.", "Fatal error", MB_OK|MB_ICONERROR);
1111 		return;
1112 	}
1113 
1114 	// Thanks ef_ef_ef@yahoo.com for pointing out this works in NT 4 and not the way I did it originally.
1115 	*listview_wnd = FindWindowEx(*desktopview_wnd, NULL, "SysListView32", NULL);
1116 	if(*listview_wnd == NULL)
1117 	{
1118 		//MessageBox(NULL, "Unable to get the handle to the folderview.", "Fatal error", MB_OK|MB_ICONERROR);
1119 		return;
1120 	}
1121 }
1122 
1123 //----------------------------------------------------------------------
1124 
GetDesktopIconSize()1125 int GetDesktopIconSize()
1126 {
1127     int ret = 32;
1128 
1129     // reads the key: HKEY_CURRENT_USER\Control Panel, Desktop\WindowMetrics\Shell Icon Size
1130     unsigned char buf[64];
1131     unsigned long len = sizeof(buf);
1132     DWORD type;
1133     HKEY key;
1134 
1135     if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, "Control Panel\\Desktop\\WindowMetrics", 0, KEY_READ, &key))
1136     {
1137         if (ERROR_SUCCESS == RegQueryValueEx(key, "Shell Icon Size", NULL, &type, (unsigned char*)buf, &len) &&
1138             type == REG_SZ)
1139         {
1140             int x = _atoi_l((char*)buf, g_use_C_locale);
1141             if (x>0 && x<=128)
1142                 ret = x;
1143         }
1144 
1145         RegCloseKey(key);
1146     }
1147 
1148     return ret;
1149 }
1150 
1151 //----------------------------------------------------------------------
1152 
1153 // handy functions for populating Combo Boxes:
SelectItemByValue(HWND ctrl,DWORD value)1154 int SelectItemByValue(HWND ctrl, DWORD value)
1155 {
1156     int count = SendMessage(ctrl, CB_GETCOUNT, 0, 0);
1157 	for (int i=0; i<count; i++)
1158 	{
1159 		DWORD value_i = SendMessage( ctrl, CB_GETITEMDATA, i, 0);
1160 		if (value_i == value)
1161         {
1162 			SendMessage( ctrl, CB_SETCURSEL, i, 0);
1163             return i;
1164         }
1165 	}
1166     return -1;
1167 }
1168 
ReadCBValue(HWND hwnd,DWORD ctrl_id,int * pRetValue)1169 bool ReadCBValue(HWND hwnd, DWORD ctrl_id, int* pRetValue)
1170 {
1171     if (!pRetValue)
1172         return false;
1173     HWND ctrl = GetDlgItem( hwnd, ctrl_id );
1174 	int t = SendMessage( ctrl, CB_GETCURSEL, 0, 0);
1175 	if (t == CB_ERR)
1176         return false;
1177     *pRetValue = (int)SendMessage( ctrl, CB_GETITEMDATA, t, 0);
1178     return true;
1179 }
1180 
1181 D3DXCREATEFONTW pCreateFontW=0;
1182 D3DXMATRIXMULTIPLY pMatrixMultiply=0;
1183 D3DXMATRIXTRANSLATION pMatrixTranslation=0;
1184 D3DXMATRIXSCALING pMatrixScaling=0;
1185 D3DXMATRIXROTATION pMatrixRotationX=0, pMatrixRotationY=0, pMatrixRotationZ=0;
1186 D3DXCREATETEXTUREFROMFILEEXW pCreateTextureFromFileExW=0;
1187 D3DXMATRIXORTHOLH pMatrixOrthoLH = 0;
1188 D3DXCOMPILESHADER pCompileShader=0;
1189 D3DXMATRIXLOOKATLH pMatrixLookAtLH=0;
1190 D3DXCREATETEXTURE pCreateTexture=0;
1191 //----------------------------------------------------------------------
FindD3DX9(HWND winamp)1192 HMODULE FindD3DX9(HWND winamp)
1193 {
1194 	HMODULE d3dx9 = (HMODULE)SendMessage(winamp,WM_WA_IPC, 0, IPC_GET_D3DX9);
1195 	if (!d3dx9 || d3dx9 == (HMODULE)1)
1196 	{
1197 
1198 	// TODO: benski> this is a quick-fix, we should call FindFirstFile() on the system directory
1199 	d3dx9=NULL;
1200 	if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_36.dll");
1201 	if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_35.dll");
1202 	if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_34.dll");
1203 	if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_33.dll");
1204 	if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_32.dll");
1205 	if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_31.dll");
1206 	if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_30.dll");
1207 	if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_29.dll");
1208 	if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_28.dll");
1209 	if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_27.dll");
1210 	if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_26.dll");
1211 	if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_25.dll");
1212 	if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_24.dll");
1213 	}
1214 
1215 	if (d3dx9)
1216 	{
1217 		pCreateFontW = (D3DXCREATEFONTW) GetProcAddress(d3dx9,"D3DXCreateFontW");
1218 		pMatrixMultiply = (D3DXMATRIXMULTIPLY) GetProcAddress(d3dx9,"D3DXMatrixMultiply");
1219 		pMatrixTranslation = (D3DXMATRIXTRANSLATION)GetProcAddress(d3dx9,"D3DXMatrixTranslation");
1220 		pMatrixScaling = (D3DXMATRIXSCALING)GetProcAddress(d3dx9,"D3DXMatrixScaling");
1221 		pMatrixRotationX = (D3DXMATRIXROTATION)GetProcAddress(d3dx9,"D3DXMatrixRotationX");
1222 		pMatrixRotationY = (D3DXMATRIXROTATION)GetProcAddress(d3dx9,"D3DXMatrixRotationY");
1223 		pMatrixRotationZ = (D3DXMATRIXROTATION)GetProcAddress(d3dx9,"D3DXMatrixRotationZ");
1224 		pCreateTextureFromFileExW = (D3DXCREATETEXTUREFROMFILEEXW)GetProcAddress(d3dx9,"D3DXCreateTextureFromFileExW");
1225 		pMatrixOrthoLH = (D3DXMATRIXORTHOLH)GetProcAddress(d3dx9,"D3DXMatrixOrthoLH");
1226 		pCompileShader = (D3DXCOMPILESHADER)GetProcAddress(d3dx9,"D3DXCompileShader");
1227 		pMatrixLookAtLH = (D3DXMATRIXLOOKATLH)GetProcAddress(d3dx9,"D3DXMatrixLookAtLH");
1228 		pCreateTexture = (D3DXCREATETEXTURE)GetProcAddress(d3dx9,"D3DXCreateTexture");
1229 
1230 
1231 
1232 	}
1233 
1234 	return d3dx9;
1235 }
1236 
GetWinampVersion(HWND winamp)1237 LRESULT GetWinampVersion(HWND winamp)
1238 {
1239 	static LRESULT version=0;
1240 	if (!version)
1241 		version=SendMessage(winamp,WM_WA_IPC,0,0);
1242 	return version;
1243 }
1244 
GetTextResource(UINT id,int no_fallback)1245 void* GetTextResource(UINT id, int no_fallback){
1246 	void* data = 0;
1247 	HINSTANCE hinst = WASABI_API_LNG_HINST;
1248 	HRSRC rsrc = FindResource(hinst,MAKEINTRESOURCE(id),"TEXT");
1249 	if(!rsrc && !no_fallback) rsrc = FindResource((hinst = WASABI_API_ORIG_HINST),MAKEINTRESOURCE(id),"TEXT");
1250 	if(rsrc){
1251 	HGLOBAL resourceHandle = LoadResource(hinst,rsrc);
1252 		data = LockResource(resourceHandle);
1253 	}
1254 	return data;
1255 }