aboutsummaryrefslogtreecommitdiff
path: root/Src/omBrowser
diff options
context:
space:
mode:
Diffstat (limited to 'Src/omBrowser')
-rw-r--r--Src/omBrowser/addressEncoder.cpp518
-rw-r--r--Src/omBrowser/addressEncoder.h15
-rw-r--r--Src/omBrowser/browser.cpp1579
-rw-r--r--Src/omBrowser/browser.h226
-rw-r--r--Src/omBrowser/browserClass.cpp191
-rw-r--r--Src/omBrowser/browserClass.h46
-rw-r--r--Src/omBrowser/browserFactory.cpp90
-rw-r--r--Src/omBrowser/browserFactory.h40
-rw-r--r--Src/omBrowser/browserHost.cpp1232
-rw-r--r--Src/omBrowser/browserHost.h180
-rw-r--r--Src/omBrowser/browserInternal.cpp45
-rw-r--r--Src/omBrowser/browserInternal.h34
-rw-r--r--Src/omBrowser/browserObject.cpp503
-rw-r--r--Src/omBrowser/browserObject.h95
-rw-r--r--Src/omBrowser/browserPopup.cpp2093
-rw-r--r--Src/omBrowser/browserPopup.h77
-rw-r--r--Src/omBrowser/browserRegistry.cpp356
-rw-r--r--Src/omBrowser/browserRegistry.h49
-rw-r--r--Src/omBrowser/browserThread.cpp413
-rw-r--r--Src/omBrowser/browserThread.h34
-rw-r--r--Src/omBrowser/browserUiCommon.cpp694
-rw-r--r--Src/omBrowser/browserUiCommon.h111
-rw-r--r--Src/omBrowser/browserUiHook.cpp321
-rw-r--r--Src/omBrowser/browserUiHook.h70
-rw-r--r--Src/omBrowser/browserUiInternal.h37
-rw-r--r--Src/omBrowser/browserView.cpp1131
-rw-r--r--Src/omBrowser/browserView.h48
-rw-r--r--Src/omBrowser/browserWndEnum.cpp179
-rw-r--r--Src/omBrowser/browserWndEnum.h48
-rw-r--r--Src/omBrowser/browserWndRecord.cpp67
-rw-r--r--Src/omBrowser/browserWndRecord.h33
-rw-r--r--Src/omBrowser/cacheDownloader.cpp274
-rw-r--r--Src/omBrowser/cacheDownloader.h73
-rw-r--r--Src/omBrowser/cacheGroup.cpp472
-rw-r--r--Src/omBrowser/cacheGroup.h63
-rw-r--r--Src/omBrowser/cacheManager.cpp192
-rw-r--r--Src/omBrowser/cacheManager.h47
-rw-r--r--Src/omBrowser/cacheRecord.cpp496
-rw-r--r--Src/omBrowser/cacheRecord.h73
-rw-r--r--Src/omBrowser/common.h53
-rw-r--r--Src/omBrowser/component.cpp549
-rw-r--r--Src/omBrowser/component.h84
-rw-r--r--Src/omBrowser/configIni.cpp704
-rw-r--r--Src/omBrowser/configIni.h106
-rw-r--r--Src/omBrowser/curtain.cpp758
-rw-r--r--Src/omBrowser/curtain.h24
-rw-r--r--Src/omBrowser/enumAsync.cpp347
-rw-r--r--Src/omBrowser/enumAsync.h63
-rw-r--r--Src/omBrowser/enumIniFile.cpp215
-rw-r--r--Src/omBrowser/enumIniFile.h44
-rw-r--r--Src/omBrowser/enumXmlBuffer.cpp243
-rw-r--r--Src/omBrowser/enumXmlBuffer.h62
-rw-r--r--Src/omBrowser/enumXmlFile.cpp275
-rw-r--r--Src/omBrowser/enumXmlFile.h61
-rw-r--r--Src/omBrowser/errorPages.rc20
-rw-r--r--Src/omBrowser/flagTracker.cpp96
-rw-r--r--Src/omBrowser/flagTracker.h37
-rw-r--r--Src/omBrowser/graphics.cpp309
-rw-r--r--Src/omBrowser/graphics.h23
-rw-r--r--Src/omBrowser/graphicsObject.cpp135
-rw-r--r--Src/omBrowser/graphicsObject.h45
-rw-r--r--Src/omBrowser/ieversion.cpp81
-rw-r--r--Src/omBrowser/ieversion.h11
-rw-r--r--Src/omBrowser/ifc_imageloader.h53
-rw-r--r--Src/omBrowser/ifc_menucustomizer.h60
-rw-r--r--Src/omBrowser/ifc_mlnavigationcallback.h35
-rw-r--r--Src/omBrowser/ifc_mlnavigationhelper.h76
-rw-r--r--Src/omBrowser/ifc_ombrowserclass.h66
-rw-r--r--Src/omBrowser/ifc_ombrowserconfig.h72
-rw-r--r--Src/omBrowser/ifc_ombrowserevent.h44
-rw-r--r--Src/omBrowser/ifc_ombrowsereventmngr.h61
-rw-r--r--Src/omBrowser/ifc_ombrowserregistry.h57
-rw-r--r--Src/omBrowser/ifc_ombrowserwndenum.h50
-rw-r--r--Src/omBrowser/ifc_ombrowserwndmngr.h51
-rw-r--r--Src/omBrowser/ifc_omcachecallback.h39
-rw-r--r--Src/omBrowser/ifc_omcachegroup.h60
-rw-r--r--Src/omBrowser/ifc_omcachemanager.h52
-rw-r--r--Src/omBrowser/ifc_omcacherecord.h99
-rw-r--r--Src/omBrowser/ifc_omconfig.h94
-rw-r--r--Src/omBrowser/ifc_omconfigcallback.h36
-rw-r--r--Src/omBrowser/ifc_omdebugconfig.h92
-rw-r--r--Src/omBrowser/ifc_omfilestorage.h45
-rw-r--r--Src/omBrowser/ifc_omgraphics.h97
-rw-r--r--Src/omBrowser/ifc_omservice.h135
-rw-r--r--Src/omBrowser/ifc_omservicecommand.h81
-rw-r--r--Src/omBrowser/ifc_omservicecopier.h40
-rw-r--r--Src/omBrowser/ifc_omservicedetails.h78
-rw-r--r--Src/omBrowser/ifc_omserviceeditor.h177
-rw-r--r--Src/omBrowser/ifc_omserviceenum.h52
-rw-r--r--Src/omBrowser/ifc_omserviceevent.h45
-rw-r--r--Src/omBrowser/ifc_omserviceeventmngr.h62
-rw-r--r--Src/omBrowser/ifc_omservicehost.h75
-rw-r--r--Src/omBrowser/ifc_omservicehostext.h44
-rw-r--r--Src/omBrowser/ifc_omservicemanager.h73
-rw-r--r--Src/omBrowser/ifc_omstatusbarconfig.h46
-rw-r--r--Src/omBrowser/ifc_omstorage.h131
-rw-r--r--Src/omBrowser/ifc_omstorageasync.h62
-rw-r--r--Src/omBrowser/ifc_omstorageenum.h50
-rw-r--r--Src/omBrowser/ifc_omstorageext.h37
-rw-r--r--Src/omBrowser/ifc_omstoragehandler.h45
-rw-r--r--Src/omBrowser/ifc_omstoragehandlerenum.h50
-rw-r--r--Src/omBrowser/ifc_omstoragehelper.h55
-rw-r--r--Src/omBrowser/ifc_omtoolbarconfig.h105
-rw-r--r--Src/omBrowser/ifc_omutility.h105
-rw-r--r--Src/omBrowser/ifc_omwebstorage.h28
-rw-r--r--Src/omBrowser/ifc_omxmlserviceenum.h42
-rw-r--r--Src/omBrowser/ifc_skinhelper.h85
-rw-r--r--Src/omBrowser/ifc_skinnedbrowser.h78
-rw-r--r--Src/omBrowser/ifc_skinnedmenu.h61
-rw-r--r--Src/omBrowser/ifc_skinnedrating.h62
-rw-r--r--Src/omBrowser/ifc_travelloghelper.h44
-rw-r--r--Src/omBrowser/ifc_wasabihelper.h124
-rw-r--r--Src/omBrowser/ifc_winamphook.h77
-rw-r--r--Src/omBrowser/internetFeatures.cpp224
-rw-r--r--Src/omBrowser/internetFeatures.h65
-rw-r--r--Src/omBrowser/loaderIni.cpp657
-rw-r--r--Src/omBrowser/loaderIni.h63
-rw-r--r--Src/omBrowser/localization/localization.vcproj120
-rw-r--r--Src/omBrowser/localization/localization.vcxproj256
-rw-r--r--Src/omBrowser/localization/localization.vcxproj.filters24
-rw-r--r--Src/omBrowser/main.cpp662
-rw-r--r--Src/omBrowser/main.h87
-rw-r--r--Src/omBrowser/menu.cpp160
-rw-r--r--Src/omBrowser/menu.h33
-rw-r--r--Src/omBrowser/mlNavigationHelper.cpp599
-rw-r--r--Src/omBrowser/mlNavigationHelper.h93
-rw-r--r--Src/omBrowser/obj_ombrowser.h145
-rw-r--r--Src/omBrowser/omBrowser.rc315
-rw-r--r--Src/omBrowser/omBrowser.sln44
-rw-r--r--Src/omBrowser/omBrowser.vcxproj483
-rw-r--r--Src/omBrowser/omBrowser.vcxproj.filters675
-rw-r--r--Src/omBrowser/options.cpp399
-rw-r--r--Src/omBrowser/options.h37
-rw-r--r--Src/omBrowser/optionsDebug.cpp203
-rw-r--r--Src/omBrowser/optionsHook.cpp93
-rw-r--r--Src/omBrowser/optionsHook.h39
-rw-r--r--Src/omBrowser/optionsInfo.cpp199
-rw-r--r--Src/omBrowser/optionsUi.cpp373
-rw-r--r--Src/omBrowser/png.rc17
-rw-r--r--Src/omBrowser/pngLoader.cpp360
-rw-r--r--Src/omBrowser/pngLoader.h46
-rw-r--r--Src/omBrowser/ratingMenu.cpp148
-rw-r--r--Src/omBrowser/ratingMenu.h17
-rw-r--r--Src/omBrowser/ratingMenuCustomizer.cpp161
-rw-r--r--Src/omBrowser/ratingMenuCustomizer.h47
-rw-r--r--Src/omBrowser/resource.h134
-rw-r--r--Src/omBrowser/resources/curtainProgress.png5
-rw-r--r--Src/omBrowser/resources/menuArrow.pngbin0 -> 133 bytes
-rw-r--r--Src/omBrowser/resources/pages/dnsError.htm44
-rw-r--r--Src/omBrowser/resources/pages/errorIcon.pngbin0 -> 2254 bytes
-rw-r--r--Src/omBrowser/resources/pages/errorPageFunctions.js288
-rw-r--r--Src/omBrowser/resources/pages/errorPageStrings.js138
-rw-r--r--Src/omBrowser/resources/pages/httpError.htm44
-rw-r--r--Src/omBrowser/resources/pages/inetDisabled.htm26
-rw-r--r--Src/omBrowser/resources/pages/navCancel.htm26
-rw-r--r--Src/omBrowser/resources/pages/winampError.css64
-rw-r--r--Src/omBrowser/resources/serviceIcon.pngbin0 -> 272 bytes
-rw-r--r--Src/omBrowser/resources/toolbarAddress.pngbin0 -> 220 bytes
-rw-r--r--Src/omBrowser/resources/toolbarLarge.pngbin0 -> 11748 bytes
-rw-r--r--Src/omBrowser/resources/toolbarProgress.pngbin0 -> 1194 bytes
-rw-r--r--Src/omBrowser/service.cpp391
-rw-r--r--Src/omBrowser/service.h152
-rw-r--r--Src/omBrowser/serviceDetails.cpp55
-rw-r--r--Src/omBrowser/serviceDispatch.cpp87
-rw-r--r--Src/omBrowser/serviceEditor.cpp257
-rw-r--r--Src/omBrowser/serviceEventMngr.cpp119
-rw-r--r--Src/omBrowser/serviceFactory.cpp90
-rw-r--r--Src/omBrowser/serviceFactory.h36
-rw-r--r--Src/omBrowser/serviceList.cpp149
-rw-r--r--Src/omBrowser/serviceList.h51
-rw-r--r--Src/omBrowser/serviceManager.cpp214
-rw-r--r--Src/omBrowser/serviceManager.h49
-rw-r--r--Src/omBrowser/skinHelper.cpp602
-rw-r--r--Src/omBrowser/skinHelper.h133
-rw-r--r--Src/omBrowser/statusbar.cpp931
-rw-r--r--Src/omBrowser/statusbar.h47
-rw-r--r--Src/omBrowser/storageDwnld.cpp395
-rw-r--r--Src/omBrowser/storageDwnld.h84
-rw-r--r--Src/omBrowser/storageEnum.cpp119
-rw-r--r--Src/omBrowser/storageEnum.h42
-rw-r--r--Src/omBrowser/storageHandler.cpp92
-rw-r--r--Src/omBrowser/storageHandler.h47
-rw-r--r--Src/omBrowser/storageHandlerEnum.cpp154
-rw-r--r--Src/omBrowser/storageHandlerEnum.h48
-rw-r--r--Src/omBrowser/storageHelper.cpp77
-rw-r--r--Src/omBrowser/storageHelper.h35
-rw-r--r--Src/omBrowser/storageIni.cpp317
-rw-r--r--Src/omBrowser/storageIni.h54
-rw-r--r--Src/omBrowser/storageUrl.cpp255
-rw-r--r--Src/omBrowser/storageUrl.h47
-rw-r--r--Src/omBrowser/storageXml.cpp146
-rw-r--r--Src/omBrowser/storageXml.h49
-rw-r--r--Src/omBrowser/stringBuilder.cpp84
-rw-r--r--Src/omBrowser/stringBuilder.h30
-rw-r--r--Src/omBrowser/toolbar.cpp3572
-rw-r--r--Src/omBrowser/toolbar.h293
-rw-r--r--Src/omBrowser/toolbarAddress.cpp761
-rw-r--r--Src/omBrowser/toolbarAddress.h79
-rw-r--r--Src/omBrowser/toolbarButton.cpp300
-rw-r--r--Src/omBrowser/toolbarButton.h56
-rw-r--r--Src/omBrowser/toolbarEditbox.cpp990
-rw-r--r--Src/omBrowser/toolbarEditbox.h32
-rw-r--r--Src/omBrowser/toolbarItem.cpp117
-rw-r--r--Src/omBrowser/toolbarItem.h107
-rw-r--r--Src/omBrowser/toolbarProgress.cpp197
-rw-r--r--Src/omBrowser/toolbarProgress.h34
-rw-r--r--Src/omBrowser/toolbarRating.cpp461
-rw-r--r--Src/omBrowser/toolbarRating.h55
-rw-r--r--Src/omBrowser/toolbarStatic.cpp115
-rw-r--r--Src/omBrowser/toolbarStatic.h39
-rw-r--r--Src/omBrowser/travelLogHelper.cpp331
-rw-r--r--Src/omBrowser/travelLogHelper.h62
-rw-r--r--Src/omBrowser/utility.cpp343
-rw-r--r--Src/omBrowser/utility.h53
-rw-r--r--Src/omBrowser/utilityFactory.cpp91
-rw-r--r--Src/omBrowser/utilityFactory.h39
-rw-r--r--Src/omBrowser/version.rc239
-rw-r--r--Src/omBrowser/wasabiHelper.cpp252
-rw-r--r--Src/omBrowser/wasabiHelper.h57
-rw-r--r--Src/omBrowser/winampHook.cpp288
-rw-r--r--Src/omBrowser/winampHook.h62
-rw-r--r--Src/omBrowser/xmlResponseParser.cpp207
-rw-r--r--Src/omBrowser/xmlResponseParser.h56
-rw-r--r--Src/omBrowser/xmlServiceParser.cpp331
-rw-r--r--Src/omBrowser/xmlServiceParser.h54
225 files changed, 42502 insertions, 0 deletions
diff --git a/Src/omBrowser/addressEncoder.cpp b/Src/omBrowser/addressEncoder.cpp
new file mode 100644
index 00000000..199cc701
--- /dev/null
+++ b/Src/omBrowser/addressEncoder.cpp
@@ -0,0 +1,518 @@
+#include "main.h"
+#include "./addressEncoder.h"
+
+
+#include <wininet.h>
+#include <strsafe.h>
+
+
+typedef struct __ENCODEBUFFER
+{
+ LPWSTR buffer;
+ size_t bufferMax;
+ LPWSTR cursor;
+ size_t remaining;
+} ENCODEBUFFER;
+
+HRESULT AddressEncoder_ReAllocBuffer(ENCODEBUFFER *decoder, size_t cchBufferSize)
+{
+ if (NULL == decoder)
+ return E_INVALIDARG;
+
+ if (cchBufferSize == decoder->bufferMax)
+ return S_FALSE;
+
+ if (cchBufferSize < decoder->bufferMax)
+ return E_FAIL;
+
+ LPWSTR test = Plugin_ReAllocString(decoder->buffer, cchBufferSize);
+ if (NULL == test)
+ return E_OUTOFMEMORY;
+
+ decoder->cursor = test + (decoder->cursor - decoder->buffer);
+ decoder->remaining += (cchBufferSize - decoder->bufferMax);
+ decoder->buffer = test;
+ decoder->bufferMax = cchBufferSize;
+
+ return S_OK;
+}
+HRESULT AddressEncoder_AppendAnsiString(ENCODEBUFFER *decoder, LPCSTR pszString, size_t cchString)
+{
+ if (NULL == decoder)
+ return E_INVALIDARG;
+
+ INT cchConverted;
+ while(0 ==(cchConverted = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, pszString, (int)cchString, decoder->cursor, (int)decoder->remaining)))
+ {
+ DWORD errorCode = GetLastError();
+ if (ERROR_INSUFFICIENT_BUFFER == errorCode)
+ {
+ INT cchNeed = MultiByteToWideChar(CP_UTF8, 0, pszString, (int)cchString, NULL, 0) - (INT)decoder->remaining;
+ if (cchNeed < 32) cchNeed = 32;
+ HRESULT hr = AddressEncoder_ReAllocBuffer(decoder, decoder->bufferMax + cchNeed);
+ if (FAILED(hr))
+ return hr;
+ }
+ else
+ {
+ return HRESULT_FROM_WIN32(errorCode);
+ }
+ }
+
+ if (0 != cchConverted)
+ {
+ decoder->cursor += cchConverted;
+ decoder->remaining -= cchConverted;
+ }
+
+ return S_OK;
+}
+
+HRESULT AddressEncoder_AppendString(ENCODEBUFFER *decoder, LPCWSTR pszString, size_t cchString)
+{
+ if (NULL == decoder)
+ return E_INVALIDARG;
+
+ LPWSTR cursor;
+ size_t remaining;
+
+ HRESULT hr;
+ if (cchString >= decoder->remaining)
+ {
+ hr = AddressEncoder_ReAllocBuffer(decoder, decoder->bufferMax + (cchString - decoder->remaining) + 1);
+ if (FAILED(hr)) return hr;
+ }
+
+ hr = StringCchCopyNEx(decoder->cursor, decoder->remaining, pszString, cchString, &cursor, &remaining, 0);
+ if (SUCCEEDED(hr))
+ {
+ decoder->cursor = cursor;
+ decoder->remaining = remaining;
+ }
+ return hr;
+}
+
+HRESULT AddressEncoder_GetEscapeBlock(LPCWSTR pszEscape, LPCWSTR *ppszEnd, size_t *pcchEscapeLen, LPSTR pszBuffer, UINT *pcbBufferMax)
+{
+ if (NULL == pszEscape || (NULL != pszBuffer && NULL == pcbBufferMax))
+ return E_INVALIDARG;
+
+ UINT cbBinary = 0;
+ WORD charInfo;
+ WCHAR szDigit[3] = {0};
+
+ HRESULT hr = S_OK;
+
+ LPCWSTR cursor = pszEscape;
+ while (L'%' == *cursor)
+ {
+ LPCWSTR testChar = CharNext(cursor);
+ if (L'\0' == *testChar ||
+ FALSE == GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, testChar, 1, &charInfo) ||
+ 0 == (C1_XDIGIT & charInfo))
+ {
+ break;
+ }
+ szDigit[0] = *testChar;
+
+ testChar = CharNext(testChar);
+ if (L'\0' == *testChar ||
+ FALSE == GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, testChar, 1, &charInfo) ||
+ 0 == (C1_XDIGIT & charInfo))
+ {
+ break;
+ }
+
+ szDigit[1] = *testChar;
+ CharUpperBuff(szDigit, 2);
+
+ BYTE binaryData = ((szDigit[0] - ((szDigit[0] <= L'9' ? L'0' : L'A' - 10))) << 4) & 0xf0;
+ binaryData += (szDigit[1] - ((szDigit[1] <= L'9' ? L'0' : L'A' - 10))) & 0x0f;
+ if (NULL != pszBuffer)
+ {
+ if (cbBinary < *pcbBufferMax)
+ pszBuffer[cbBinary] = binaryData;
+ else
+ hr = E_OUTOFMEMORY;
+ }
+ cbBinary++;
+
+ cursor = CharNext(testChar);
+ }
+
+ if (cursor == pszEscape)
+ hr = HRESULT_FROM_WIN32(ERROR_INVALID_BLOCK_LENGTH);
+
+ if (NULL != ppszEnd)
+ *ppszEnd = cursor;
+
+ if (NULL != pcchEscapeLen)
+ *pcchEscapeLen = (size_t)(cursor - pszEscape);
+
+ if (NULL != pcbBufferMax)
+ *pcbBufferMax = cbBinary;
+
+ return hr;
+}
+
+HRESULT AddressEncoder_DecodeString(LPCWSTR pszUrl, LPWSTR *ppResult)
+{
+ if (NULL == pszUrl)
+ {
+ *ppResult = NULL;
+ return S_FALSE;
+ }
+
+ UINT cchUrl = 0;
+ UINT escapeSize = 0;
+ UINT escapeBlockSize,escapeBlockMaxSize = 0;
+ LPCWSTR escapeBlockEnd;
+ for (LPCWSTR cursor = pszUrl; L'\0' != *cursor;)
+ {
+ if (L'%' == *cursor && SUCCEEDED(AddressEncoder_GetEscapeBlock(cursor, &escapeBlockEnd, NULL, NULL, &escapeBlockSize)))
+ {
+ escapeSize += escapeBlockSize;
+ if (escapeBlockSize > escapeBlockMaxSize)
+ escapeBlockMaxSize = escapeBlockSize;
+
+ cursor = escapeBlockEnd;
+ }
+ else
+ {
+ cchUrl++;
+ cursor = CharNext(cursor);
+ }
+ }
+
+ if (0 == escapeSize)
+ {
+ *ppResult = Plugin_CopyString(pszUrl);
+ if (NULL == *ppResult) return E_OUTOFMEMORY;
+ return S_FALSE;
+ }
+
+ HRESULT hr = S_OK;
+
+ ENCODEBUFFER decoder;
+ ZeroMemory(&decoder, sizeof(decoder));
+
+ LPSTR escapeBuffer = Plugin_MallocAnsiString(escapeBlockMaxSize);
+ if (NULL == escapeBuffer)
+ {
+ hr = E_OUTOFMEMORY;
+ }
+ else
+ {
+ hr = AddressEncoder_ReAllocBuffer(&decoder, cchUrl + (escapeSize + 1)* sizeof(WCHAR));
+ if (SUCCEEDED(hr))
+ {
+ LPCWSTR cursor = pszUrl;
+ LPCWSTR copyBlock = cursor;
+
+ for (;;)
+ {
+ escapeBlockSize = escapeBlockMaxSize;
+ if (L'%' == *cursor && SUCCEEDED(AddressEncoder_GetEscapeBlock(cursor, &escapeBlockEnd, NULL, escapeBuffer, &escapeBlockSize)))
+ {
+ if (copyBlock != cursor)
+ {
+ hr = AddressEncoder_AppendString(&decoder, copyBlock, cursor - copyBlock);
+ if (FAILED(hr))
+ break;
+ copyBlock = cursor;
+ }
+
+ HRESULT convertResult = AddressEncoder_AppendAnsiString(&decoder, escapeBuffer, escapeBlockSize);
+ if (L'\0' == *cursor)
+ break;
+
+ cursor = escapeBlockEnd;
+ if (SUCCEEDED(convertResult))
+ {
+ copyBlock = cursor;
+ }
+
+
+
+ continue;
+ }
+
+ if (L'\0' == *cursor)
+ {
+ if (copyBlock != cursor)
+ hr = AddressEncoder_AppendString(&decoder, copyBlock, cursor - copyBlock);
+ break;
+ }
+ else
+ cursor = CharNext(cursor);
+ }
+
+ }
+
+ }
+
+ if (NULL != escapeBuffer)
+ Plugin_FreeAnsiString(escapeBuffer);
+
+ if (FAILED(hr))
+ {
+ Plugin_FreeString(decoder.buffer);
+ decoder.buffer = NULL;
+ }
+ else
+ {
+ *decoder.cursor = L'\0';
+ }
+
+ *ppResult = decoder.buffer;
+
+ return hr;
+}
+HRESULT AddressEncoder_GetWideBlock(LPCWSTR pszWide, LPCWSTR *pszEnd, LPWSTR pszBuffer, size_t *pcchBufferMax)
+{
+ LPCWSTR cursor = pszWide;
+ if (NULL == pszWide)
+ return E_INVALIDARG;
+
+ if (NULL != pszBuffer && NULL == pcchBufferMax)
+ return E_INVALIDARG;
+
+ while (L'\0' == *cursor || *cursor > 0xFF)
+ {
+ if (L'\0' == *cursor)
+ break;
+ cursor = CharNext(cursor);
+ }
+
+ if (NULL != pszEnd)
+ *pszEnd = cursor;
+
+ HRESULT hr = S_OK;
+ size_t cchBuffer = 0;
+
+ if (cursor == pszWide)
+ {
+ hr = S_FALSE;
+ }
+ else
+ {
+ size_t bytesCount = WideCharToMultiByte(CP_UTF8, 0, pszWide, (int)(cursor - pszWide), NULL, 0, NULL, NULL);
+ if (0 == bytesCount)
+ {
+ DWORD errorCode = GetLastError();
+ if (ERROR_SUCCESS != errorCode)
+ hr = HRESULT_FROM_WIN32(errorCode);
+ }
+ else
+ {
+ cchBuffer = 3 * bytesCount;
+ if (NULL != pszBuffer)
+ {
+ if (*pcchBufferMax >= cchBuffer)
+ {
+ LPWSTR p = pszBuffer;
+ BYTE *bytes = ((BYTE*)(pszBuffer + *pcchBufferMax)) - bytesCount;
+ WideCharToMultiByte(CP_UTF8, 0, pszWide, (int)(cursor - pszWide), (LPSTR)bytes, (int)bytesCount, NULL, NULL);
+ for (size_t i = 0; i < bytesCount; i++)
+ {
+ BYTE b = bytes[i];
+ *p++ = L'%';
+ BYTE c = (b >> 4) & 0x0F;
+ *p++ = (c < 10) ? (L'0' + c) : (L'A' + (c -10));
+ c = b & 0x0F;
+ *p++ = (c < 10) ? (L'0' + c) : (L'A' + (c -10));
+ }
+
+ }
+ else
+ {
+ hr = E_OUTOFMEMORY;
+ }
+ }
+ }
+ }
+
+ if (NULL != pcchBufferMax)
+ {
+ *pcchBufferMax = cchBuffer;
+ }
+
+
+ return hr;
+}
+HRESULT AddressEncoder_EncodeWideChars(LPCWSTR pszAddress, size_t cchAddress, LPWSTR *ppResult)
+{
+ if (NULL == ppResult)
+ return E_POINTER;
+
+ if (NULL == pszAddress)
+ {
+ *ppResult = NULL;
+ return S_FALSE;
+ }
+
+ LPCWSTR blockEnd;
+ size_t blockSize;
+ size_t cchResultMax = 0;
+ BOOL needEncode = FALSE;
+ for (LPCWSTR cursor = pszAddress; L'\0' != *cursor;)
+ {
+ if (*cursor > 0xFF && SUCCEEDED(AddressEncoder_GetWideBlock(cursor, &blockEnd, NULL, &blockSize)))
+ {
+ cursor = blockEnd;
+ cchResultMax += blockSize;
+ needEncode = TRUE;
+ }
+ else
+ {
+ cursor = CharNext(cursor);
+ cchResultMax++;
+ }
+ }
+
+ if (FALSE == needEncode)
+ {
+ *ppResult = NULL;
+ return S_FALSE;
+ }
+
+ HRESULT hr;
+ cchResultMax++;
+ LPWSTR result = Plugin_MallocString(cchResultMax);
+ if (NULL == result)
+ hr = E_OUTOFMEMORY;
+ else
+ {
+ LPWSTR cursor = result;
+ size_t remaining = cchResultMax;
+ LPCWSTR address = pszAddress;
+ LPCWSTR addressBlock = address;
+
+ for (;;)
+ {
+ if (*address > 0xFF)
+ {
+ if (addressBlock != address)
+ {
+ hr = StringCchCopyNEx(cursor, remaining, addressBlock, (size_t)(address - addressBlock), &cursor, &remaining, 0);
+ if (FAILED(hr)) break;
+ }
+
+ blockSize = remaining;
+ hr = AddressEncoder_GetWideBlock(address, &address, cursor, &blockSize);
+ if (FAILED(hr)) break;
+
+ cursor += blockSize;
+ remaining -= blockSize;
+
+ addressBlock = address;
+ continue;
+ }
+
+ if (L'\0' == *address)
+ {
+ if (addressBlock != address)
+ {
+ hr = StringCchCopyNEx(cursor, remaining, addressBlock, (size_t)(address - addressBlock), &cursor, &remaining, 0);
+ }
+ break;
+ }
+ else
+ address = CharNext(address);
+ }
+
+ *cursor = L'\0';
+ }
+
+
+
+ if (FAILED(hr))
+ {
+ Plugin_FreeString(result);
+ result = NULL;
+ }
+
+ *ppResult = result;
+ return hr;
+}
+
+HRESULT AddressEncoder_EncodeString(LPCWSTR pszAddress, LPWSTR pszBuffer, size_t *pcchBufferMax, UINT flags)
+{
+ if (NULL == pszBuffer || NULL == pcchBufferMax)
+ return E_INVALIDARG;
+
+ if (NULL == pszAddress || L'\0' == *pszAddress)
+ {
+ *pszBuffer = L'\0';
+ *pcchBufferMax = 0;
+ return S_OK;
+ }
+
+ INT cchAddress = lstrlen(pszAddress);
+ LPCWSTR begin, end;
+ begin = pszAddress;
+ end = pszAddress + cchAddress;
+ WORD charType;
+ while (L'\0' != *begin &&
+ FALSE != GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, begin, 1, &charType) && 0 != (C1_SPACE & charType))
+ {
+ begin = CharNext(begin);
+ }
+ while (begin != end &&
+ FALSE != GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, begin, 1, &charType) && 0 != (C1_SPACE & charType))
+ {
+ end = CharPrev(begin, end);
+ }
+
+ if (end <= begin)
+ {
+ *pszBuffer = L'\0';
+ *pcchBufferMax = 0;
+ return S_OK;
+ }
+
+ LPWSTR encoded;
+ HRESULT hr = AddressEncoder_EncodeWideChars(begin, (end - begin), &encoded);
+ if (FAILED(hr)) return hr;
+
+ if (S_OK == hr)
+ {
+ begin = encoded;
+ end = begin + lstrlen(begin);
+ }
+
+ DWORD bufferLen = (DWORD)(*pcchBufferMax);
+ if (FALSE == InternetCanonicalizeUrl(begin, pszBuffer, &bufferLen, flags))
+ {
+ DWORD errorCode = GetLastError();
+ if (ERROR_INSUFFICIENT_BUFFER == errorCode)
+ {
+ *pcchBufferMax = bufferLen;
+ hr = ENC_E_INSUFFICIENT_BUFFER;
+ }
+ else
+ {
+ size_t cchNeeded = (end - begin);
+ if (cchNeeded < *pcchBufferMax)
+ {
+ hr = StringCchCopyN(pszBuffer, *pcchBufferMax, begin, cchNeeded);
+ if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
+ {
+ hr = ENC_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ else
+ {
+ hr = ENC_E_INSUFFICIENT_BUFFER;
+ }
+ *pcchBufferMax = cchNeeded + 1;
+ }
+ }
+
+ else
+ hr = S_OK;
+
+
+ Plugin_FreeString(encoded);
+ return hr;
+} \ No newline at end of file
diff --git a/Src/omBrowser/addressEncoder.h b/Src/omBrowser/addressEncoder.h
new file mode 100644
index 00000000..63322e22
--- /dev/null
+++ b/Src/omBrowser/addressEncoder.h
@@ -0,0 +1,15 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_ADDRESS_DECODER_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_ADDRESS_DECODER_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+#define ENC_E_INSUFFICIENT_BUFFER (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
+
+HRESULT AddressEncoder_DecodeString(LPCWSTR pszAddress, LPWSTR *ppResult);
+HRESULT AddressEncoder_EncodeString(LPCWSTR pszAddress, LPWSTR pszBuffer, size_t *pcchBufferMax, UINT flags);
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_ADDRESS_DECODER_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/browser.cpp b/Src/omBrowser/browser.cpp
new file mode 100644
index 00000000..8e955d3d
--- /dev/null
+++ b/Src/omBrowser/browser.cpp
@@ -0,0 +1,1579 @@
+#include "main.h"
+#include "./browser.h"
+#include "./browserRegistry.h"
+#include "./graphics.h"
+#include "./resource.h"
+
+#include "../winamp/wa_dlg.h"
+#include "../Plugins/General/gen_ml/colors.h"
+#include "../winamp/IWasabiDispatchable.h"
+#include "../winamp/JSAPI_Info.h"
+
+#include "./obj_ombrowser.h"
+#include "./ifc_skinhelper.h"
+#include "./ifc_skinnedbrowser.h"
+#include "./ifc_wasabihelper.h"
+#include "./ifc_omservice.h"
+#include "./ifc_omdebugconfig.h"
+#include "./travelLogHelper.h"
+#include "./menu.h"
+
+#include <wininet.h>
+#include <exdisp.h>
+#include <exdispid.h>
+#include <mshtmdid.h>
+#include <mshtml.h>
+
+#include <shlwapi.h>
+#include <strsafe.h>
+
+#define CONTROL_DOWNLOADFLAGS ( DLCTL_DLIMAGES | \
+ DLCTL_VIDEOS | \
+ /*DLCTL_PRAGMA_NO_CACHE |*/ \
+ /*DLCTL_NO_CLIENTPULL | */ \
+ DLCTL_RESYNCHRONIZE | \
+ 0)
+
+
+#define CONTROL_HOSTINFOFLAGS ( DOCHOSTUIFLAG_DISABLE_HELP_MENU | \
+ DOCHOSTUIFLAG_NO3DBORDER | \
+ DOCHOSTUIFLAG_DISABLE_SCRIPT_INACTIVE | \
+ DOCHOSTUIFLAG_ACTIVATE_CLIENTHIT_ONLY | \
+ DOCHOSTUIFLAG_ENABLE_INPLACE_NAVIGATION | \
+ DOCHOSTUIFLAG_THEME | \
+ DOCHOSTUIFLAG_NOPICS | \
+ DOCHOSTUIFLAG_NO3DOUTERBORDER | \
+ DOCHOSTUIFLAG_DISABLE_UNTRUSTEDPROTOCOL | \
+ DOCHOSTUIFLAG_ENABLE_REDIRECT_NOTIFICATION | \
+ DOCHOSTUIFLAG_USE_WINDOWLESS_SELECTCONTROL | \
+ DOCHOSTUIFLAG_ENABLE_FORMS_AUTOCOMPLETE | \
+ DOCHOSTUIFLAG_IME_ENABLE_RECONVERSION | \
+ 0)
+
+#ifndef LOAD_LIBRARY_AS_IMAGE_RESOURCE
+ #define LOAD_LIBRARY_AS_IMAGE_RESOURCE 0x000000020
+#endif //LOAD_LIBRARY_AS_IMAGE_RESOURCE
+
+ /*BHNAVCOMPLETECALLBACK EventDocumentReady;
+ BHNAVCOMPLETECALLBACK EventNavigateComplete;
+ BHCALLBACK EventDownloadBegin;
+ BHCALLBACK EventDownloadComplete;
+ BHCALLBACK EventContainerDestroyed;
+ BHCMDSTATECALLBACK EventCommandStateChange;
+ BHTEXTCALLBACK EventStatusChange;
+ BHTEXTCALLBACK EventTitleChange;
+ BHCALLBACK EventSecureLockIconChange;
+ BHCREATEPOPUPCALLBACK EventCreatePopup;
+ BHBOOLCALLBACK EventVisible;
+ BHBOOLCALLBACK EventSetResizable;
+ BHCLOSECALLBACK EventWindowClosing;
+ BHSHOWUICALLBACK EventShowUiElement;
+ BHCLIENTTOHOSTCALLBACK EventClientToHost;
+ BHWINDOWPOSCALLBACK EventSetWindowPos;
+ BHFOCUSCHANGECALLBACK EventFocusChange;
+ BHBOOLCALLBACK EventSetFullscreen;
+ BHCALLBACK EventClosePopup;*/
+
+Browser::Browser(obj_ombrowser *browserMngr, HWND winampWindow, HWND hParent)
+ : HTMLContainer2(winampWindow, hParent),
+ EventDocumentReady(NULL),
+ EventNavigateComplete(NULL),
+ EventDownloadBegin(NULL),
+ EventDownloadComplete(NULL),
+ EventContainerDestroyed(NULL),
+ EventCommandStateChange(NULL),
+ EventStatusChange(NULL),
+ EventTitleChange(NULL),
+ EventSecureLockIconChange(NULL),
+ EventCreatePopup(NULL),
+ EventVisible(NULL),
+ EventSetResizable(NULL),
+ EventWindowClosing(NULL),
+ EventShowUiElement(NULL),
+ EventClientToHost(NULL),
+ EventSetWindowPos(NULL),
+ EventFocusChange(NULL),
+ EventSetFullscreen(NULL),
+ EventClosePopup(NULL),
+ CallbackGetOmService(NULL),
+ CallbackRedirectKey(NULL),
+ browserManager(browserMngr), externalDisp(NULL),
+ pDropTargetHerlper(NULL), navigationState(0),
+ secureLockIcon(secureLockIconUnsecure),
+ pszUserAgent(NULL), uiFlags(0)
+{
+ memset(szDone, 0, sizeof(szDone));
+
+ if (NULL != externalDisp)
+ externalDisp->AddRef();
+
+ if (NULL != browserManager)
+ browserManager->AddRef();
+}
+
+Browser::~Browser()
+{
+ if (NULL != EventContainerDestroyed)
+ EventContainerDestroyed(this);
+
+ if (NULL != externalDisp)
+ externalDisp->Release();
+
+ if (NULL != pszUserAgent)
+ Plugin_FreeString(pszUserAgent);
+
+ if (NULL != pDropTargetHerlper)
+ pDropTargetHerlper->Release();
+
+ if (NULL != browserManager)
+ browserManager->Release();
+}
+
+HRESULT Browser::SetExternal(IDispatch *pDispatch)
+{
+ if (NULL != externalDisp)
+ externalDisp->Release();
+
+ externalDisp = pDispatch;
+
+ if (NULL != externalDisp)
+ externalDisp->AddRef();
+
+ return S_OK;
+}
+
+Browser *Browser::CreateInstance(obj_ombrowser *browserManager, HWND winampWindow, HWND hParent)
+{
+ Browser *instance = new Browser(browserManager, winampWindow, hParent);
+ return instance;
+}
+
+ULONG Browser::AddRef(void)
+{
+ return HTMLContainer2::AddRef();
+}
+
+ULONG Browser::Release(void)
+{
+ return HTMLContainer2::Release();
+}
+
+STDMETHODIMP Browser::Initialize(BOOL fRegisterAsBrowser)
+{
+ HRESULT hr = __super::Initialize();
+ if (SUCCEEDED(hr))
+ {
+ if (FALSE != fRegisterAsBrowser)
+ {
+ IWebBrowser2 *pWeb2 = NULL;
+ if (SUCCEEDED(GetIWebBrowser2(&pWeb2)) && pWeb2 != NULL)
+ {
+ pWeb2->put_RegisterAsBrowser(VARIANT_TRUE);
+ pWeb2->Release();
+ }
+ }
+
+ szDone[0] = L'\0';
+ HINSTANCE hModule;
+
+ if (L'\0' == szDone[0] && NULL != (hModule = LoadLibraryExW(L"ieframe.dll.mui", NULL,
+ LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE)))
+ {
+ LoadString(hModule, 8169, szDone, ARRAYSIZE(szDone));
+ FreeLibrary(hModule);
+ }
+
+ if (L'\0' == szDone[0] && NULL != (hModule = LoadLibraryExW(L"shdoclc.dll", NULL,
+ LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE)))
+ {
+ LoadString(hModule, 8169, szDone, ARRAYSIZE(szDone));
+ FreeLibrary(hModule);
+ }
+
+ if (L'\0' == szDone[0])
+ StringCchPrintf(szDone, ARRAYSIZE(szDone), L"Done");
+ }
+ return hr;
+}
+
+STDMETHODIMP Browser::Finish(void)
+{
+ IWebBrowser2 *pWeb2 = NULL;
+ if (SUCCEEDED(GetIWebBrowser2(&pWeb2)) && pWeb2 != NULL)
+ {
+ pWeb2->put_RegisterAsBrowser(VARIANT_FALSE);
+ pWeb2->Release();
+ }
+ return HTMLContainer2::Finish();
+}
+
+STDMETHODIMP Browser::QueryInterface(REFIID riid, PVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ if (IsEqualIID(riid, IID_IDropTarget))
+ {
+ *ppvObject = (IDropTarget*)this;
+ ((IUnknown*)*ppvObject)->AddRef();
+ return S_OK;
+ }
+ else if (IsEqualIID(riid, IID_IProtectFocus))
+ {
+ *ppvObject = (IProtectFocus*)this;
+ ((IUnknown*)*ppvObject)->AddRef();
+ return S_OK;
+ }
+
+ return HTMLContainer2::QueryInterface(riid, ppvObject);
+}
+
+STDMETHODIMP Browser::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
+{
+ *pdwEffect = (0x00FFFFFF & ~(*pdwEffect));
+
+ if (NULL == pDropTargetHerlper &&
+ FAILED(CoCreateInstance(CLSID_DragDropHelper, NULL, CLSCTX_INPROC_SERVER, IID_IDropTargetHelper, (PVOID*)&pDropTargetHerlper)))
+ {
+ pDropTargetHerlper = NULL;
+ }
+
+ if (NULL != pDropTargetHerlper)
+ {
+ POINT pt = { ptl.x, ptl.y};
+ HWND hwnd = this->GetHostHWND();
+ pDropTargetHerlper->DragEnter(hwnd, pDataObject, &pt, *pdwEffect);
+ }
+ return S_OK;
+}
+
+STDMETHODIMP Browser::DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
+{
+ *pdwEffect = (0x00FFFFFF & ~(*pdwEffect));
+
+ if (NULL != pDropTargetHerlper)
+ {
+ POINT pt = { ptl.x, ptl.y};
+ pDropTargetHerlper->DragOver(&pt, *pdwEffect);
+ }
+ return S_OK;
+}
+
+STDMETHODIMP Browser::DragLeave(void)
+{
+ if (NULL != pDropTargetHerlper)
+ pDropTargetHerlper->DragLeave();
+
+ return S_OK;
+}
+
+STDMETHODIMP Browser::Drop(IDataObject *pDataObject, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
+{
+ *pdwEffect = (0x00FFFFFF & ~(*pdwEffect));
+
+ if (NULL != pDropTargetHerlper)
+ {
+ POINT pt = { ptl.x, ptl.y};
+ pDropTargetHerlper->Drop(pDataObject, &pt, *pdwEffect);
+ }
+ return S_OK;
+}
+
+STDMETHODIMP Browser::GetDropTarget(IDropTarget *pDropTarget, IDropTarget **ppDropTarget)
+{
+ if (NULL == ppDropTarget)
+ return E_POINTER;
+
+ HRESULT hr = QueryInterface(IID_IDropTarget, (void**)ppDropTarget);
+ if (SUCCEEDED(hr))
+ return S_OK;
+
+ return HTMLContainer2::GetDropTarget(pDropTarget, ppDropTarget);
+}
+
+STDMETHODIMP Browser::GetOverrideKeyPath(LPOLESTR __RPC_FAR *pchKey, DWORD dw)
+{
+ HRESULT hr;
+ size_t cbBuffer = 0;
+ ifc_ombrowserregistry *browserRegistry = NULL;
+ if (NULL != browserManager && SUCCEEDED(browserManager->GetRegistry(&browserRegistry)) && browserRegistry != NULL)
+ {
+ WCHAR szBuffer[256] = {0};
+ if (SUCCEEDED(browserRegistry->GetPath(szBuffer, ARRAYSIZE(szBuffer))) &&
+ SUCCEEDED(StringCbLengthW(szBuffer, ARRAYSIZE(szBuffer), &cbBuffer)))
+ {
+ cbBuffer += sizeof(WCHAR);
+ *pchKey = (LPOLESTR)CoTaskMemAlloc(cbBuffer);
+ if (NULL != *pchKey)
+ {
+ hr = StringCbCopyW(*pchKey, cbBuffer, szBuffer);
+ if (FAILED(hr))
+ {
+ CoTaskMemFree(*pchKey);
+ }
+ }
+ else
+ {
+ hr = E_OUTOFMEMORY;
+ }
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+
+ browserRegistry->Release();
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+
+ if (FAILED(hr))
+ {
+ *pchKey = NULL;
+ }
+ return hr;
+}
+
+STDMETHODIMP Browser::GetExternal(IDispatch __RPC_FAR *__RPC_FAR *ppDispatch)
+{
+ if (ppDispatch && NULL != externalDisp)
+ {
+ externalDisp->AddRef();
+ *ppDispatch = externalDisp;
+ return S_OK;
+ }
+ return HTMLContainer2::GetExternal(ppDispatch);
+}
+
+STDMETHODIMP Browser::ShowContextMenu(DWORD dwID, POINT __RPC_FAR *ppt, IUnknown __RPC_FAR *pcmdtReserved, IDispatch __RPC_FAR *pdispReserved)
+{
+ if (0 != (flagUiDisableContextMenu & uiFlags))
+ return S_OK;
+
+ return S_FALSE;
+}
+
+STDMETHODIMP Browser::ShowMessage(HWND hwnd, LPOLESTR lpstrText, LPOLESTR lpstrCaption, DWORD dwType, LPOLESTR lpstrHelpFile, DWORD dwHelpContext, LRESULT *plResult)
+{
+ wchar_t szBuffer[256] = {0};
+ lpstrCaption = (LPOLESTR)Plugin_LoadString(IDS_OMBROWSER_TITLE, szBuffer, ARRAYSIZE(szBuffer));
+ *plResult = MessageBoxW(hwnd, lpstrText, lpstrCaption, dwType);
+ return S_OK;
+}
+
+STDMETHODIMP Browser::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
+{
+ HRESULT hr = S_OK;
+
+ if (NULL != pguidCmdGroup)
+ {
+ if (IsEqualGUID(*pguidCmdGroup, CGID_DocHostCommandHandler))
+ {
+ switch (nCmdID)
+ {
+ case OLECMDID_SHOWSCRIPTERROR:
+ {
+ ifc_omdebugconfig *debugConfig = NULL;
+ HRESULT showError = GetDebugConfig(&debugConfig);
+ if (SUCCEEDED(showError) && debugConfig != NULL)
+ {
+ showError = debugConfig->GetScriptErrorEnabled();
+ debugConfig->Release();
+ }
+
+ if (S_FALSE == showError)
+ {
+ OutputDebugStringA("~~<<=== script error\r\n");
+ (*pvaOut).vt = VT_BOOL;
+ (*pvaOut).boolVal = VARIANT_TRUE;
+ }
+ else
+ {
+ hr = OLECMDERR_E_NOTSUPPORTED;
+ }
+ }
+ break;
+ default:
+ hr = OLECMDERR_E_NOTSUPPORTED;
+ break;
+ }
+ }
+ else if (IsEqualGUID(*pguidCmdGroup, CGID_ShellDocView))
+ {
+ switch (nCmdID)
+ {
+ case 53 /*SHDVID_ADDMENUEXTENSIONS*/:
+ return S_OK;
+ }
+ }
+ else
+ {
+ hr = OLECMDERR_E_UNKNOWNGROUP;
+ }
+ }
+ else
+ {
+ hr = OLECMDERR_E_UNKNOWNGROUP;
+ }
+
+ return hr;
+}
+
+STDMETHODIMP Browser::QueryService(REFGUID guidService, REFIID riid, void **ppv)
+{
+ if (IsEqualIID(riid, SID_SProtectFocus))
+ {
+ *ppv = (IProtectFocus*)this;
+ this->AddRef();
+ return S_OK;
+ }
+ else if (IsEqualIID(guidService, SID_SHTMLOMWindowServices))
+ {
+ if (IsEqualIID(riid, IID_IHTMLOMWindowServices))
+ {
+ *ppv = (IHTMLOMWindowServices*)this;
+ this->AddRef();
+ return S_OK;
+ }
+ }
+ else if (IsEqualIID(riid, IID_INewWindowManager))
+ {
+ *ppv = (INewWindowManager*)this;
+ this->AddRef();
+ return S_OK;
+ }
+ return HTMLContainer2::QueryService(guidService, riid, ppv);
+}
+
+STDMETHODIMP Browser::AllowFocusChange(BOOL *pfAllow)
+{
+ if (NULL == pfAllow)
+ return E_POINTER;
+
+ if (NULL != EventFocusChange)
+ {
+ VARIANT_BOOL Allow = VARIANT_TRUE;
+ EventFocusChange(this, &Allow);
+ if (VARIANT_FALSE == Allow)
+ {
+ *pfAllow = FALSE;
+ }
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP Browser::moveTo(LONG x, LONG y)
+{
+ if (NULL == EventSetWindowPos)
+ return E_FAIL;
+
+ EventSetWindowPos(this, HTMLContainer2::wndLeft | HTMLContainer2::wndTop, x, y, 0, 0);
+ return S_OK;
+}
+
+STDMETHODIMP Browser::moveBy(LONG x, LONG y)
+{
+ if (NULL == EventSetWindowPos)
+ return E_FAIL;
+
+ EventSetWindowPos(this, HTMLContainer2::wndLeft | HTMLContainer2::wndTop | HTMLContainer2::wndRelative, x, y, 0, 0);
+ return S_OK;
+}
+
+STDMETHODIMP Browser::resizeTo(LONG x, LONG y)
+{
+ if (NULL == EventSetWindowPos)
+ return E_FAIL;
+
+ EventSetWindowPos(this, HTMLContainer2::wndWidth | HTMLContainer2::wndHeight, 0, 0, x, y);
+ return S_OK;
+}
+
+STDMETHODIMP Browser::resizeBy(LONG x, LONG y)
+{
+ if (NULL == EventSetWindowPos)
+ return E_FAIL;
+
+ EventSetWindowPos(this, HTMLContainer2::wndWidth | HTMLContainer2::wndHeight | HTMLContainer2::wndRelative, 0, 0, x, y);
+ return S_OK;
+}
+
+STDMETHODIMP Browser::EvaluateNewWindow(LPCWSTR pszUrl, LPCWSTR pszName, LPCWSTR pszUrlContext, LPCWSTR pszFeatures, BOOL fReplace, DWORD dwFlags, DWORD dwUserActionTime)
+{
+ #ifdef _DEBUG
+ char szBuffer[2048] = {0}, szFlags[128] = {0};
+ LPSTR cursor = szFlags;
+ size_t remaining = ARRAYSIZE(szFlags);
+ if (0 != (NWMF_UNLOADING & dwFlags)) StringCchCopyExA(cursor, remaining, " unloading |", &cursor, &remaining, 0);
+ if (0 != (NWMF_USERINITED & dwFlags)) StringCchCopyExA(cursor, remaining, " userInited |", &cursor, &remaining, 0);
+ if (0 != (0x0004/*NWMF_FIRST_USERINITED*/ & dwFlags)) StringCchCopyExA(cursor, remaining, " first |", &cursor, &remaining, 0);
+ if (0 != (NWMF_OVERRIDEKEY & dwFlags)) StringCchCopyExA(cursor, remaining, " overrideKey |", &cursor, &remaining, 0);
+ if (0 != (NWMF_SHOWHELP & dwFlags)) StringCchCopyExA(cursor, remaining, " showHelp |", &cursor, &remaining, 0);
+ if (0 != (NWMF_HTMLDIALOG & dwFlags)) StringCchCopyExA(cursor, remaining, " htmlDialog |", &cursor, &remaining, 0);
+ if (0 != (0x80/*NWMF_USERREQUESTED*/ & dwFlags)) StringCchCopyExA(cursor, remaining, " userRequested |", &cursor, &remaining, 0);
+ if (0 != (0x100/*NWMF_USERALLOWED*/ & dwFlags)) StringCchCopyExA(cursor, remaining, " userAllowed |", &cursor, &remaining, 0);
+ if (0 != (0x10000/*NWMF_FORCEWINDOW*/ & dwFlags)) StringCchCopyExA(cursor, remaining, " forceWindow |", &cursor, &remaining, 0);
+ if (0 != (0x20000/*NWMF_FORCETAB*/ & dwFlags)) StringCchCopyExA(cursor, remaining, " forceTab |", &cursor, &remaining, 0);
+ if (0 != (0x40000/*NWMF_SUGGESTWINDOW*/ & dwFlags)) StringCchCopyExA(cursor, remaining, " suggestWindow |", &cursor, &remaining, 0);
+ if (0 != (0x80000/*NWMF_SUGGESTTAB*/ & dwFlags)) StringCchCopyExA(cursor, remaining, " suggestTab |", &cursor, &remaining, 0);
+ if (0 != (0x100000/*NWMF_INACTIVETAB*/ & dwFlags)) StringCchCopyExA(cursor, remaining, " inactiveTab |", &cursor, &remaining, 0);
+
+ if (cursor != szFlags)
+ {
+ cursor -= 2;
+ *cursor = '\0';
+ }
+ else
+ {
+ StringCchCopyExA(cursor, remaining, " <none>", &cursor, &remaining, 0);
+ }
+
+ StringCchPrintfA(szBuffer, ARRAYSIZE(szBuffer), "EvaluateNewWindow:\r\n\turlContext: %S,\r\n\turl: %S,\r\n\tflags:%s\r\n",
+ ((NULL == pszUrlContext || L'\0' == *pszUrlContext) ? L"<empty>" : pszUrlContext),
+ ((NULL == pszUrl || L'\0' == *pszUrl) ? L"<empty>" : pszUrl),
+ szFlags);
+
+ OutputDebugStringA(szBuffer);
+#endif // _DEBUG
+
+ if (0 != (NWMF_UNLOADING & dwFlags))
+ {
+ return S_FALSE;
+ }
+
+ return S_OK;
+}
+
+OLECHAR *Browser::OnGetHostCSS(void)
+{
+ if (0 != (flagUiDisableHostCss & uiFlags))
+ return NULL;
+
+ ifc_skinnedbrowser *skinnedBrowser = NULL;
+ if (FAILED(Plugin_GetBrowserSkin(&skinnedBrowser)))
+ return NULL;
+
+ OLECHAR *hostCss = NULL;
+ if (FAILED(skinnedBrowser->GetHostCss(&hostCss)))
+ hostCss = NULL;
+
+ skinnedBrowser->Release();
+ return hostCss;
+}
+
+COLORREF Browser::OnGetHostBkColor(void)
+{
+ if (0 != (flagUiDisableHostCss & uiFlags))
+ return GetSysColor(COLOR_WINDOW);
+
+ COLORREF rgbBk;
+ ifc_skinhelper *skin = NULL;
+ if (SUCCEEDED(Plugin_GetSkinHelper(&skin)) && skin != NULL)
+ {
+ skin->GetColor(WADLG_ITEMBG, &rgbBk);
+ skin->Release();
+ }
+
+ if (FAILED(rgbBk))
+ rgbBk = GetSysColor(COLOR_WINDOW);
+
+ return rgbBk;
+}
+
+DWORD Browser::OnGetHostInfoFlags(void)
+{
+ DWORD flags = CONTROL_HOSTINFOFLAGS;
+
+ if (0 != (flagUiDisableScroll & uiFlags))
+ flags |= DOCHOSTUIFLAG_SCROLL_NO;
+
+ if (0 != (flagUiDialogMode & uiFlags))
+ flags |= DOCHOSTUIFLAG_DIALOG;
+
+ return flags;
+}
+
+DWORD Browser::OnGetDownlodFlags(void)
+{
+ return CONTROL_DOWNLOADFLAGS;
+}
+
+HRESULT Browser::GetExternalName(LPWSTR pszBuffer, INT cchBufferMax)
+{
+ if (NULL == pszBuffer)
+ return E_POINTER;
+
+ pszBuffer[0] = L'\0';
+
+ IDocHostUIHandler *pHandler = NULL;
+ HRESULT hr = QueryInterface(IID_IDocHostUIHandler, (void**)&pHandler);
+ if (SUCCEEDED(hr) && pHandler != NULL)
+ {
+ IDispatch *pDispatch = NULL;
+ hr = pHandler->GetExternal(&pDispatch);
+ if (SUCCEEDED(hr) && NULL != pDispatch)
+ {
+ IWasabiDispatchable *pWasabi = NULL;
+ hr = pDispatch->QueryInterface(IID_IWasabiDispatchable, (void**)&pWasabi);
+ if (SUCCEEDED(hr) && pWasabi != NULL)
+ {
+ JSAPI::ifc_info *pInfo = NULL;
+ hr = pWasabi->QueryDispatchable(JSAPI::IID_JSAPI_ifc_info, (Dispatchable**)&pInfo);
+ if (SUCCEEDED(hr) && pInfo != NULL)
+ {
+ LPCWSTR p = pInfo->GetUserAgent();
+ if (NULL != p && L'\0' != *p)
+ StringCchCopy(pszBuffer, cchBufferMax, p);
+
+ pInfo->Release();
+ }
+ pWasabi->Release();
+ }
+ pDispatch->Release();
+ }
+ pHandler->Release();
+ }
+ return S_OK;
+}
+
+LPCWSTR Browser::OnGetUserAgent(void)
+{
+ if (NULL == pszUserAgent)
+ {
+ BSTR version = NULL;
+
+ if (SUCCEEDED(GetUserAgent(&version)) && NULL != version)
+ {
+ WCHAR szExternal[128] = {0};
+ size_t cchExternal = 0;
+
+ if (FAILED(GetExternalName(szExternal, ARRAYSIZE(szExternal)))
+ || FAILED(StringCchLength(szExternal, ARRAYSIZE(szExternal), &cchExternal)))
+ {
+ cchExternal = 0;
+ }
+
+ INT cchVersion = (NULL != version) ? SysStringLen(version) : 0;
+ INT cchBufferMax = cchVersion + (INT)cchExternal;
+ if (0 != cchExternal)
+ cchBufferMax += 4; // for ", "
+
+ if (cchBufferMax > 0)
+ {
+ pszUserAgent = Plugin_MallocString(cchBufferMax);
+ if (NULL != pszUserAgent)
+ {
+ HRESULT hr = S_OK;
+ LPWSTR cursor = pszUserAgent;
+ size_t remaining = cchBufferMax;
+
+ if (L'\0' != *version && SUCCEEDED(hr))
+ {
+ hr = StringCchCopyEx(cursor, remaining,
+ version, &cursor,
+ &remaining,
+ STRSAFE_NULL_ON_FAILURE);
+ }
+
+ if (SUCCEEDED(hr) && 0 != cchExternal)
+ {
+ BOOL needCloseBracket = FALSE;
+
+ if (cursor > pszUserAgent)
+ {
+ if (L')' == *(cursor - 1))
+ {
+ *(cursor - 1) = L',';
+ needCloseBracket = TRUE;
+ }
+
+ hr = StringCchCopyEx(cursor, remaining,
+ L" ", &cursor,
+ &remaining,
+ STRSAFE_NULL_ON_FAILURE);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = StringCchCopyEx(cursor, remaining,
+ szExternal, &cursor,
+ &remaining,
+ STRSAFE_NULL_ON_FAILURE);
+ }
+
+ if (SUCCEEDED(hr) && FALSE != needCloseBracket)
+ {
+ hr = StringCchCopyEx(cursor, remaining, L")",
+ &cursor, &remaining,
+ STRSAFE_NULL_ON_FAILURE);
+ }
+
+ if (FAILED(hr))
+ {
+ hr = S_OK;
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ Plugin_FreeString(pszUserAgent);
+ pszUserAgent = NULL;
+ }
+ }
+ }
+
+ if (NULL != version)
+ SysFreeString(version);
+ }
+ }
+
+ return pszUserAgent;
+}
+
+HRESULT Browser::SendCommand(INT commandId)
+{
+ IWebBrowser2 *pWeb2 = NULL;
+ HRESULT hr = GetIWebBrowser2(&pWeb2);
+ if (SUCCEEDED(hr) && pWeb2 != NULL)
+ {
+ switch(commandId)
+ {
+ case Browser::commandBack:
+ hr = pWeb2->GoBack();
+ break;
+ case Browser::commandForward:
+ hr = pWeb2->GoForward();
+ break;
+ case Browser::commandStop:
+ hr = pWeb2->Stop();
+ break;
+ case Browser::commandRefresh:
+ hr = pWeb2->Refresh();
+ break;
+ case Browser::commandRefreshCompletely:
+ {
+ VARIANT param;
+ VariantInit(&param);
+ V_VT(&param) = VT_I4;
+ V_I4(&param) = REFRESH_COMPLETELY;
+ hr = pWeb2->Refresh2(&param);
+ }
+ break;
+ default:
+ hr = E_INVALIDARG;
+ break;
+ }
+ pWeb2->Release();
+ }
+ return hr;
+}
+
+#define POSTAPPCMD(/*HWND*/ __hwndTarget, /*HWND*/__hwndSource, /*INT*/__commandId)\
+ (PostMessage((__hwndTarget), WM_APPCOMMAND, (WPARAM)(__hwndSource), MAKELPARAM(0, FAPPCOMMAND_KEY | (__commandId))))
+
+BOOL Browser::TranslateKey(LPMSG pMsg)
+{
+ UINT vKey = (UINT)pMsg->wParam;
+ BOOL redirectKey = TRUE;
+ if (0 != (0x8000 & GetAsyncKeyState(VK_MENU)))
+ {
+ if (0 != (0x8000 & GetAsyncKeyState(VK_CONTROL)))
+ {
+ redirectKey = FALSE;
+ }
+ else
+ {
+ switch(vKey)
+ {
+ case VK_TAB:
+ case VK_BACK:
+ case VK_UP:
+ case VK_DOWN:
+ case VK_LEFT:
+ case VK_RIGHT:
+ case VK_NEXT:
+ case VK_PRIOR:
+ case VK_END:
+ case VK_INSERT:
+ case VK_DELETE:
+ redirectKey = FALSE;
+ break;
+ }
+ }
+ }
+ else if (0 != (0x8000 & GetAsyncKeyState(VK_CONTROL)))
+ {
+ switch(vKey)
+ {
+ case VK_BACK:
+ case VK_UP:
+ case VK_DOWN:
+ case VK_LEFT:
+ case VK_RIGHT:
+ case VK_NEXT:
+ case VK_PRIOR:
+ case VK_HOME:
+ case VK_END:
+ case VK_INSERT:
+ case VK_DELETE:
+ case VK_F5:
+ case 'R':
+ case 'X':
+ case 'C':
+ case 'V':
+ case 'A':
+ case 'Z':
+ case 'Y':
+ redirectKey = FALSE;
+ break;
+ }
+ }
+ else
+ {
+ if (WM_KEYDOWN == pMsg->message && VK_ESCAPE == vKey)
+ {
+ POSTAPPCMD(hParent, pMsg->hwnd, APPCOMMAND_BROWSER_STOP);
+ return TRUE;
+ }
+
+ redirectKey = FALSE;
+ }
+
+ if (FALSE != redirectKey && NULL != CallbackRedirectKey && FALSE != CallbackRedirectKey(this, pMsg))
+ {
+ return TRUE;
+ }
+
+ return __super::TranslateKey(pMsg);
+}
+
+STDMETHODIMP Browser::TranslateAccelerator(LPMSG lpMsg, const GUID __RPC_FAR *pguidCmdGroup, DWORD nCmdID)
+{
+ return E_NOTIMPL; // override HtmlContainer2 cause we already filtered keys
+}
+
+static INT OLECMDFTOCOMMANDSTATE(OLECMDF cmdf)
+{
+ INT state = 0;
+ if ( 0 != (OLECMDF_SUPPORTED & cmdf))
+ state |= Browser::commandStateSupported;
+ if ( 0 != (OLECMDF_ENABLED & cmdf))
+ state |= Browser::commandStateEnabled;
+ if ( 0 != (OLECMDF_LATCHED & cmdf))
+ state |= Browser::commandStateLatched;
+
+ return state;
+}
+
+HRESULT Browser::QueryCommandState(INT commandId, INT *commandState)
+{
+ if (NULL == commandState)
+ return E_INVALIDARG;
+
+ HRESULT hr(S_OK);
+ *commandState = 0;
+ IWebBrowser2 *pWeb2 = NULL;
+ OLECMDF cmdf = (OLECMDF)0;
+
+ switch(commandId)
+ {
+ case Browser::commandBack:
+ if (0 != (Browser::navigationBackEnabled & navigationState))
+ *commandState |= (Browser::commandStateSupported | Browser::commandStateEnabled);
+ break;
+ case Browser::commandForward:
+ if (0 != (Browser::navigationForwardEnabled & navigationState))
+ *commandState |= (Browser::commandStateSupported | Browser::commandStateEnabled);
+ break;
+ case Browser::commandStop:
+ hr = GetIWebBrowser2(&pWeb2);
+ if (SUCCEEDED(hr) && pWeb2 != NULL)
+ {
+ hr = pWeb2->QueryStatusWB(OLECMDID_STOP, &cmdf);
+ if (SUCCEEDED(hr))
+ *commandState = OLECMDFTOCOMMANDSTATE(cmdf);
+ pWeb2->Release();
+ }
+ break;
+ case Browser::commandRefresh:
+ hr = GetIWebBrowser2(&pWeb2);
+ if (SUCCEEDED(hr) && pWeb2 != NULL)
+ {
+ hr = pWeb2->QueryStatusWB(OLECMDID_REFRESH, &cmdf);
+ if (SUCCEEDED(hr))
+ *commandState = OLECMDFTOCOMMANDSTATE(cmdf);
+ pWeb2->Release();
+ }
+ break;
+ }
+
+ return hr;
+}
+
+void Browser::OnBeforeNavigate(IDispatch *pDispatch, VARIANT *URL, VARIANT *Flags, VARIANT *TargetFrameName, VARIANT *PostData, VARIANT *Headers, VARIANT_BOOL *Cancel)
+{
+ HTMLContainer2::OnBeforeNavigate(pDispatch, URL, Flags, TargetFrameName, PostData, Headers, Cancel);
+}
+
+void Browser::OnDownloadBegin(void)
+{
+ HTMLContainer2::OnDownloadBegin();
+
+ if (NULL != EventDownloadBegin)
+ EventDownloadBegin(this);
+}
+
+void Browser::OnDownloadComplete(void)
+{
+ HTMLContainer2::OnDownloadComplete();
+
+ if (NULL != EventDownloadComplete)
+ EventDownloadComplete(this);
+}
+
+void Browser::OnNavigateComplete(IDispatch *pDispatch, VARIANT *URL)
+{
+ HTMLContainer2::OnNavigateComplete(pDispatch, URL);
+
+ if (NULL != EventNavigateComplete)
+ EventNavigateComplete(this, pDispatch, URL);
+}
+
+HRESULT Browser::GetErrorPageName(LPWSTR pszBuffer, HRESULT cchBufferMax, UINT errorCode, BOOL fCancel)
+{
+ WCHAR szPath[MAX_PATH] = {0}, szTemp[MAX_PATH] = {0};
+ LPCWSTR pszFile = NULL;
+
+ ifc_omdebugconfig *debugConfig = NULL;
+ if (SUCCEEDED(GetDebugConfig(&debugConfig)) && debugConfig != NULL)
+ {
+ debugConfig->GetBrowserPath(szPath, ARRAYSIZE(szPath));
+ debugConfig->Release();
+ }
+
+ if (FALSE == fCancel)
+ {
+ pszFile = (errorCode < 0x800C0000) ? L"httpError.htm" : L"dnsError.htm";
+ }
+ else
+ {
+ pszFile = (errorCode == -1 ? L"inetDisabled.htm" : L"navCancel.htm");
+ }
+
+ if (L'0' != szPath[0] &&
+ FALSE != PathCombine(szTemp, szPath, pszFile) &&
+ FALSE != PathFileExists(szTemp))
+ {
+ return StringCchCopy(pszBuffer, cchBufferMax, szTemp);
+ }
+
+ HINSTANCE hModule = Plugin_GetLangInstance();
+ if (NULL != hModule &&
+ NULL == FindResource(hModule, pszFile, /*RT_HTML*/MAKEINTRESOURCEW(23)))
+ {
+ hModule = NULL;
+ }
+
+ if (NULL == hModule)
+ {
+ hModule = Plugin_GetInstance();
+ if (NULL != hModule &&
+ NULL == FindResource(hModule, pszFile, /*RT_HTML*/MAKEINTRESOURCEW(23)))
+ {
+ hModule = NULL;
+ }
+ }
+
+ if (NULL != hModule)
+ {
+ if (0 == GetModuleFileName(hModule, szPath, ARRAYSIZE(szPath)))
+ return E_FAIL;
+
+ return StringCchPrintf(pszBuffer, cchBufferMax, L"res://%s/%s", szPath, pszFile);
+ }
+
+ return E_NOTIMPL;
+}
+
+static HRESULT Browser_FormatDefaultErrorMessage(LPWSTR pszBuffer, INT cchBufferMax, UINT errorCode, LPCWSTR pszUrl, BOOL fCancel)
+{
+ HRESULT hr;
+ if (FALSE != fCancel)
+ {
+ hr = StringCchCopy(pszBuffer, cchBufferMax,
+ L"about:<HEAD><title>Service page load cancelled</title></Head><Body><H3>Service page load canncelled</H3></Body>");
+ }
+ else
+ {
+ WCHAR szStatus[32] = {0};
+ hr = StringCchPrintf(szStatus, ARRAYSIZE(szStatus), ((errorCode < 0x800C0000) ? L"HTTP-%d" : L"0x%08X"), errorCode);
+
+ if (FAILED(hr))
+ szStatus[0] = L'\0';
+
+ hr = StringCchPrintf(pszBuffer, cchBufferMax,
+ L"about:<HEAD><title>Service load error</title></Head><Body><H3>Online Media cannot load service page</H3><p>URL: %s<br>Code: %s</p></Body>",
+ ((NULL != pszUrl && L'\0' != *pszUrl) ? pszUrl : L"Unknown"), szStatus);
+ }
+ return hr;
+}
+
+HRESULT Browser::FormatErrorParam(LPWSTR pszBuffer, INT cchBufferMax, UINT errorCode, LPCWSTR pszUrl)
+{
+ LPWSTR cursor = pszBuffer;
+ size_t remaining = cchBufferMax;
+
+ StringCchCopyEx(cursor, remaining, L"#", &cursor,&remaining, STRSAFE_NULL_ON_FAILURE);
+
+ if (((UINT)-1) != errorCode)
+ StringCchPrintfEx(cursor, remaining, &cursor,&remaining, STRSAFE_NULL_ON_FAILURE, L"errorcode=%d&", errorCode);
+
+ if (NULL != pszUrl && L'\0' != *pszUrl)
+ StringCchPrintfEx(cursor, remaining, &cursor,&remaining, STRSAFE_NULL_ON_FAILURE, L"url=%s&", pszUrl);
+
+ ifc_omservice *service = NULL;
+ if (NULL == CallbackGetOmService || FAILED(CallbackGetOmService(this, &service)))
+ service = NULL;
+
+ if (NULL != service)
+ {
+ StringCchPrintfEx(cursor, remaining, &cursor,&remaining, STRSAFE_NULL_ON_FAILURE, L"svcid=%d&", service->GetId());
+
+ WCHAR szName[256] = {0};
+ if (SUCCEEDED(service->GetName(szName, ARRAYSIZE(szName))) && L'\0' != *szName)
+ {
+ WCHAR szNameEscaped[ARRAYSIZE(szName)] = {0};
+ DWORD cchName = ARRAYSIZE(szNameEscaped);
+ if (SUCCEEDED(UrlEscape(szName, szNameEscaped, &cchName, URL_ESCAPE_SEGMENT_ONLY | URL_ESCAPE_PERCENT)) && 0 != cchName)
+ StringCchPrintfEx(cursor, remaining, &cursor,&remaining, STRSAFE_NULL_ON_FAILURE, L"servicename=%s&", szNameEscaped);
+ }
+
+ service->Release();
+ }
+
+ WCHAR szClient[128] = {0};
+ if (NULL != browserManager && SUCCEEDED(browserManager->GetClientId(szClient, ARRAYSIZE(szClient))))
+ StringCchPrintfEx(cursor, remaining, &cursor,&remaining, STRSAFE_NULL_ON_FAILURE, L"uniqueid=%s&", szClient);
+
+ if (cursor > pszBuffer)
+ *(--cursor) = L'\0';
+
+ return S_OK;
+}
+
+void Browser::OnNavigateError(IDispatch *pDispatch, VARIANT *URL, VARIANT *TargetFrameName, VARIANT *StatusCode, VARIANT_BOOL *Cancel)
+{
+ UINT errorCode = (NULL != StatusCode && VT_I4 == StatusCode->vt) ? StatusCode->lVal : 0;
+ if (200 == errorCode || 0 == errorCode)
+ {
+ return;
+ }
+
+ HTMLContainer2::OnNavigateError(pDispatch, URL, TargetFrameName, StatusCode, Cancel);
+
+ WCHAR szUrl[INTERNET_MAX_URL_LENGTH] = {0};
+ WCHAR szBuffer[INTERNET_MAX_URL_LENGTH] = {0};
+
+ DWORD cchUrl = ARRAYSIZE(szUrl);
+ DWORD cchBuffer = ARRAYSIZE(szBuffer);
+
+ if (FAILED(GetErrorPageName(szUrl, ARRAYSIZE(szUrl), errorCode, FALSE)) ||
+ FAILED(UrlEscape(szUrl, szBuffer, &cchBuffer, URL_ESCAPE_SPACES_ONLY | URL_DONT_ESCAPE_EXTRA_INFO)))
+ {
+ szBuffer[0] = L'\0';
+ cchBuffer = 0;
+ }
+
+ if (NULL == URL || VT_BSTR != URL->vt || NULL == URL->bstrVal || L'\0' == *URL->bstrVal ||
+ FAILED(UrlEscape(URL->bstrVal, szUrl, &cchUrl, URL_ESCAPE_SEGMENT_ONLY | URL_ESCAPE_PERCENT)))
+ {
+ szUrl[0] = L'\0';
+ }
+
+ if (0 != cchBuffer)
+ {
+ FormatErrorParam(szBuffer + cchBuffer, ARRAYSIZE(szBuffer) - cchBuffer, errorCode, szUrl);
+ }
+ else
+ {
+ if(FAILED(Browser_FormatDefaultErrorMessage(szBuffer, ARRAYSIZE(szBuffer), errorCode, szUrl, FALSE)))
+ return;
+ }
+
+ IWebBrowser2 *pWeb2 = NULL;
+ if (FAILED(GetIWebBrowser2(&pWeb2)))
+ return;
+
+ INT frameCount = 0;
+ if (FAILED(GetFramesCount(pWeb2, &frameCount)))
+ frameCount = 0;
+
+ BOOL invokeDlComplete = FALSE;
+
+ if (0 == frameCount)
+ {
+ pWeb2->Stop();
+ BSTR currentUrl;
+ if (FAILED(pWeb2->get_LocationURL(&currentUrl)))
+ currentUrl = NULL;
+
+ if (NULL != currentUrl &&
+ CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, currentUrl, -1, szBuffer, -1))
+ {
+ *Cancel = VARIANT_TRUE;
+ invokeDlComplete = TRUE;
+ }
+ else
+ {
+ if (FAILED(PostNavigateToName(szBuffer, navNoHistory)))
+ NavigateToName(szBuffer, navNoHistory);
+ }
+
+ if (NULL != currentUrl)
+ SysFreeString(currentUrl);
+ }
+ else
+ {
+ *Cancel = VARIANT_TRUE;
+ invokeDlComplete = TRUE;
+
+ IWebBrowser2* pWebActive;
+ if (NULL != pDispatch &&
+ SUCCEEDED(pDispatch->QueryInterface(IID_IWebBrowser2, (void**)&pWebActive)))
+ {
+ NavigateToNameEx(pWebActive, szBuffer, navNoHistory);
+ invokeDlComplete = FALSE;
+ pWebActive->Release();
+ }
+ }
+
+ if (FALSE != invokeDlComplete)
+ {
+ DISPPARAMS params;
+ ZeroMemory(&params, sizeof(DISPPARAMS));
+ Invoke(DISPID_DOWNLOADCOMPLETE, GUID_NULL, 0, DISPATCH_METHOD, &params, NULL, NULL, NULL);
+ }
+
+ pWeb2->Release();
+}
+
+void Browser::OnNavigateCancelled(LPCWSTR pszUrl, VARIANT_BOOL *Cancel)
+{
+ HTMLContainer2::OnNavigateCancelled(pszUrl, Cancel);
+
+ WCHAR szBuffer[2048] = {0};
+ if (SUCCEEDED(GetErrorPageName(szBuffer, ARRAYSIZE(szBuffer), (*Cancel == ((VARIANT_BOOL)-2) ? -1 : 0), TRUE)))
+ {
+ INT cchLen = lstrlen(szBuffer);
+ FormatErrorParam(szBuffer + cchLen, ARRAYSIZE(szBuffer) - cchLen, 0, pszUrl);
+ }
+ else
+ {
+ if(FAILED(Browser_FormatDefaultErrorMessage(szBuffer, ARRAYSIZE(szBuffer), 0, pszUrl, TRUE)))
+ return;
+ }
+
+ *Cancel = VARIANT_TRUE;
+ NavigateToName(szBuffer, navNoHistory);
+}
+
+void Browser::OnDocumentReady(IDispatch *pDispatch, VARIANT *URL)
+{
+ HTMLContainer2::OnDocumentReady(pDispatch, URL);
+ if (NULL != EventDocumentReady)
+ EventDocumentReady(this, pDispatch, URL);
+}
+
+void Browser::OnCommandStateChange(LONG commandId, VARIANT_BOOL Enable)
+{
+ HTMLContainer2::OnCommandStateChange(commandId, Enable);
+
+ switch(commandId)
+ {
+ case CSC_NAVIGATEBACK:
+ if (VARIANT_TRUE == Enable)
+ navigationState |= navigationBackEnabled;
+ else
+ navigationState &= ~3;
+
+ if (NULL != EventCommandStateChange)
+ EventCommandStateChange(this, commandBack, 0 != (navigationBackEnabled & navigationState));
+ break;
+
+ case CSC_NAVIGATEFORWARD:
+ if (VARIANT_TRUE == Enable)
+ navigationState |= navigationForwardEnabled;
+ else
+ navigationState &= ~navigationForwardEnabled;
+
+ if (NULL != EventCommandStateChange)
+ EventCommandStateChange(this, commandForward, 0 != (navigationForwardEnabled & navigationState));
+ break;
+
+ case CSC_UPDATECOMMANDS:
+ if (NULL != EventCommandStateChange)
+ {
+ INT state = 0;
+
+ if (SUCCEEDED(QueryCommandState(commandStop, &state)) && 0 != (commandStateSupported & state))
+ EventCommandStateChange(this, commandStop, 0 != (commandStateEnabled & state));
+ if (SUCCEEDED(QueryCommandState(commandRefresh, &state)) && 0 != (commandStateSupported & state))
+ EventCommandStateChange(this, commandRefresh, 0 != (commandStateEnabled & state));
+ }
+ break;
+ }
+}
+
+void Browser::OnStatusTextChange(LPCWSTR pszText)
+{
+ HTMLContainer2::OnStatusTextChange(pszText);
+
+ if (NULL != EventStatusChange)
+ {
+ if (NULL != pszText &&
+ CSTR_EQUAL == CompareString(CSTR_INVARIANT, 0, szDone, -1, pszText, -1))
+ {
+ pszText = NULL;
+ }
+ EventStatusChange(this, pszText);
+ }
+}
+
+void Browser::OnSetSecureLockIcon(UINT secureLockIcon)
+{
+ HTMLContainer2::OnSetSecureLockIcon(secureLockIcon);
+
+ this->secureLockIcon = secureLockIcon;
+
+ if (NULL != EventSecureLockIconChange)
+ EventSecureLockIconChange(this);
+}
+
+void Browser::OnTitleChange(BSTR pszText)
+{
+ if (NULL != EventTitleChange)
+ EventTitleChange(this, pszText);
+}
+
+void Browser::OnNewWindow3(IDispatch **ppDisp, VARIANT_BOOL *Cancel, DWORD dwFlags, BSTR bstrUrlContext, BSTR bstrUrl)
+{
+#ifdef _DEBUG
+ char szBuffer[2048], szFlags[128] = {0};
+ LPSTR cursor = szFlags;
+ size_t remaining = ARRAYSIZE(szFlags);
+ if (0 != (NWMF_UNLOADING & dwFlags)) StringCchCopyExA(cursor, remaining, " unloading |", &cursor, &remaining, 0);
+ if (0 != (NWMF_USERINITED & dwFlags)) StringCchCopyExA(cursor, remaining, " userInited |", &cursor, &remaining, 0);
+ if (0 != (0x0004/*NWMF_FIRST_USERINITED*/ & dwFlags)) StringCchCopyExA(cursor, remaining, " first |", &cursor, &remaining, 0);
+ if (0 != (NWMF_OVERRIDEKEY & dwFlags)) StringCchCopyExA(cursor, remaining, " overrideKey |", &cursor, &remaining, 0);
+ if (0 != (NWMF_SHOWHELP & dwFlags)) StringCchCopyExA(cursor, remaining, " showHelp |", &cursor, &remaining, 0);
+ if (0 != (NWMF_HTMLDIALOG & dwFlags)) StringCchCopyExA(cursor, remaining, " htmlDialog |", &cursor, &remaining, 0);
+ if (0 != (0x80/*NWMF_USERREQUESTED*/ & dwFlags)) StringCchCopyExA(cursor, remaining, " userRequested |", &cursor, &remaining, 0);
+ if (0 != (0x100/*NWMF_USERALLOWED*/ & dwFlags)) StringCchCopyExA(cursor, remaining, " userAllowed |", &cursor, &remaining, 0);
+ if (0 != (0x10000/*NWMF_FORCEWINDOW*/ & dwFlags)) StringCchCopyExA(cursor, remaining, " forceWindow |", &cursor, &remaining, 0);
+ if (0 != (0x20000/*NWMF_FORCETAB*/ & dwFlags)) StringCchCopyExA(cursor, remaining, " forceTab |", &cursor, &remaining, 0);
+ if (0 != (0x40000/*NWMF_SUGGESTWINDOW*/ & dwFlags)) StringCchCopyExA(cursor, remaining, " suggestWindow |", &cursor, &remaining, 0);
+ if (0 != (0x80000/*NWMF_SUGGESTTAB*/ & dwFlags)) StringCchCopyExA(cursor, remaining, " suggestTab |", &cursor, &remaining, 0);
+ if (0 != (0x100000/*NWMF_INACTIVETAB*/ & dwFlags)) StringCchCopyExA(cursor, remaining, " inactiveTab |", &cursor, &remaining, 0);
+
+ if (cursor != szFlags)
+ {
+ cursor -= 2;
+ *cursor = '\0';
+ }
+ else
+ {
+ StringCchCopyExA(cursor, remaining, " <none>", &cursor, &remaining, 0);
+ }
+
+ StringCchPrintfA(szBuffer, ARRAYSIZE(szBuffer), "NewWindow3:\r\n\turlContext: %S,\r\n\turl: %S,\r\n\tflags:%s\r\n",
+ ((NULL == bstrUrlContext || L'\0' == *bstrUrlContext) ? L"<empty>" : bstrUrlContext),
+ ((NULL == bstrUrl || L'\0' == *bstrUrl) ? L"<empty>" : bstrUrl), szFlags);
+
+ OutputDebugStringA(szBuffer);
+#endif // _DEBUG
+}
+
+void Browser::OnNewWindow2(IDispatch **ppDisp, VARIANT_BOOL *Cancel)
+{
+ if (NULL != EventCreatePopup)
+ {
+ EventCreatePopup(this, ppDisp, Cancel);
+ }
+ else if (NULL != Cancel)
+ {
+ *Cancel = VARIANT_TRUE;
+ }
+}
+
+void Browser::OnVisibleChange(VARIANT_BOOL Visible)
+{
+ if (NULL != EventVisible)
+ {
+ EventVisible(this, Visible);
+ }
+}
+
+void Browser::OnWindowClosing(VARIANT_BOOL IsChildWindow, VARIANT_BOOL *Cancel)
+{
+ if (NULL != EventWindowClosing)
+ {
+ EventWindowClosing(this, IsChildWindow, Cancel);
+ }
+}
+
+void Browser::OnShowUiElement(UINT elementId, VARIANT_BOOL fShow)
+{
+ HTMLContainer2::OnShowUiElement(elementId, fShow);
+ if (NULL != EventShowUiElement)
+ {
+ EventShowUiElement(this, elementId, fShow);
+ }
+}
+
+void Browser::OnWindowSetResizable(VARIANT_BOOL Enable)
+{
+ if (NULL != EventSetResizable)
+ {
+ EventSetResizable(this, Enable);
+ }
+}
+
+void Browser::OnEnableFullscreen(VARIANT_BOOL Enable)
+{
+ if (NULL != EventSetFullscreen)
+ {
+ EventSetFullscreen(this, Enable);
+ }
+}
+
+void Browser::OnClientToHostWindow(LONG *CX, LONG *CY)
+{
+ if (NULL != EventClientToHost)
+ {
+ EventClientToHost(this, CX, CY);
+ }
+}
+
+void Browser::OnSetWindowPos(UINT Flags, LONG X, LONG Y, LONG CX, LONG CY)
+{
+ if (NULL != EventSetWindowPos)
+ {
+ EventSetWindowPos(this, Flags, X, Y, CX, CY);
+ }
+}
+
+HANDLE Browser::InitializePopupHook(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hHook = NULL;
+ BSTR version = NULL;
+ if (SUCCEEDED(GetAppVersion(&version)) && NULL != version)
+ {
+ // if (NULL == StrStrIW(version, L"Trident/4.0") /*IE8*/ &&
+ // NULL == StrStrIW(version, L"Trident/5.0") /*IE9*/)
+ {
+ hHook = Menu_InitializeHook(hwnd, NULL);
+ }
+
+ SysFreeString(version);
+ }
+ return hHook;
+}
+
+void Browser::DeletePopupHook(HANDLE hHook)
+{
+ Menu_RemoveHook(hHook);
+}
+
+void Browser::InitializeMenuPopup(HWND hwnd, HMENU hMenu, INT iPos, BOOL fWindowMenu)
+{
+ UINT szItems[] = { 2263 /*Save Background As...*/,
+ 2264 /*Set as Background*/,
+ 2265 /*Copy Background*/,
+ 2266 /*Create Shortcut*/,
+ 2261 /*Add to Favorite*/,
+ 2268 /*Save Target As...*/,
+ 2269 /*Show Picture*/,
+ 2270 /*Save Picture As...*/,
+ 2288 /*Email Picture*/,
+ 2289 /*Print Picture*/,
+ 2287 /*Goto My Picures*/,
+ 2278 /*Set as Desktop Item...*/,
+ 2435 /*Open in New Tab*/,
+ };
+
+ if (NULL == hMenu)
+ return;
+
+ ifc_omdebugconfig *debugConfig = NULL;
+ if (SUCCEEDED(GetDebugConfig(&debugConfig)) && debugConfig != NULL)
+ {
+ HRESULT hr = debugConfig->GetMenuFilterEnabled();
+ debugConfig->Release();
+ if (S_FALSE == hr) return;
+ }
+
+ // remove known items
+ INT i;
+ for (i = 0; i < ARRAYSIZE(szItems); i++)
+ {
+ DeleteMenu(hMenu, szItems[i], MF_BYCOMMAND);
+ }
+
+ // fix separators and remove extensions
+ i = GetMenuItemCount(hMenu);
+
+ MENUITEMINFOW mi = {0};
+ mi.cbSize = sizeof(MENUITEMINFO);
+ mi.fMask = MIIM_ID | MIIM_FTYPE | MIIM_SUBMENU;
+
+ INT separatorIndex = i;
+ while(i--)
+ {
+ if (GetMenuItemInfoW(hMenu, i, TRUE, &mi))
+ {
+ if (0 != (MFT_SEPARATOR & mi.fType))
+ {
+ if ((i + 1) == separatorIndex)
+ {
+ DeleteMenu(hMenu, i, MF_BYPOSITION);
+ }
+ separatorIndex = i;
+ }
+ else if (mi.wID >= 3700 && NULL == mi.hSubMenu)
+ {
+ DeleteMenu(hMenu, i, MF_BYPOSITION);
+ if (separatorIndex > i)
+ separatorIndex--;
+ }
+ }
+ }
+}
+
+void Browser::SetUiFlags(UINT flags, UINT mask)
+{
+ uiFlags = (uiFlags & ~mask) | (flags & mask);
+}
+
+UINT Browser::GetUiFlags(UINT mask)
+{
+ return (mask & uiFlags);
+}
+
+HRESULT Browser::ToggleFullscreen()
+{
+ IWebBrowser2 *pWeb2 = NULL;
+ HRESULT hr = GetIWebBrowser2(&pWeb2);
+ if (FAILED(hr)) return hr;
+
+ VARIANT_BOOL fullscreenMode;
+
+ hr = pWeb2->get_FullScreen(&fullscreenMode);
+ if (SUCCEEDED(hr))
+ {
+ if (VARIANT_FALSE == fullscreenMode) fullscreenMode = VARIANT_TRUE;
+ else if (VARIANT_TRUE == fullscreenMode) fullscreenMode = VARIANT_FALSE;
+ else hr = E_UNEXPECTED;
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pWeb2->put_FullScreen(fullscreenMode);
+ if (SUCCEEDED(hr))
+ {
+ }
+ }
+ }
+
+ pWeb2->Release();
+ return hr;
+}
+
+HRESULT Browser::GetDebugConfig(ifc_omdebugconfig **debugConfig)
+{
+ if (NULL == debugConfig) return E_POINTER;
+ if (NULL == browserManager || FAILED(browserManager->GetConfig(&IFC_OmDebugConfig, (void**)debugConfig)))
+ {
+ *debugConfig = NULL;
+ return E_NOINTERFACE;
+ }
+ return S_OK;
+}
+
+HRESULT Browser::GetTravelLog(ifc_travelloghelper **travelLog)
+{
+ if (NULL == travelLog) return E_POINTER;
+
+ IWebBrowser2 *pWeb2 = NULL;
+ HRESULT hr = GetIWebBrowser2(&pWeb2);
+ if (FAILED(hr))
+ {
+ *travelLog = NULL;
+ return hr;
+ }
+
+ hr = TravelLogHelper::CreateInstance(pWeb2, (TravelLogHelper**)travelLog);
+ pWeb2->Release();
+
+ return hr;
+}
+
+BOOL Browser::InputLangChangeRequest(HWND hwnd, UINT flags, HKL hkl)
+{
+ HWND hTarget = GetParent(hwnd);
+ if (NULL != hTarget)
+ {
+ SendMessage(hTarget, WM_INPUTLANGCHANGEREQUEST, (WPARAM)flags, (LPARAM)hkl);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void Browser::InputLangChange(UINT charset, HKL hkl)
+{
+ ActivateKeyboardLayout(hkl, KLF_SETFORPROCESS);
+}
+
+void Browser::OnClosePopupInternal()
+{
+ if(NULL != EventClosePopup)
+ EventClosePopup(this);
+}
+
+#ifdef _DEBUG
+void BrowserDebug_PrintRefs(Browser *browser)
+{
+ if (NULL == browser)
+ {
+ aTRACE_LINE("browser object is NULL");
+ return;
+ }
+
+ browser->AddRef();
+ ULONG refBrowser, refUnknown, refWeb;
+
+ IUnknown *pUnk = NULL;
+ if (SUCCEEDED(browser->GetIUnknown(&pUnk)) && pUnk != NULL)
+ {
+ refUnknown = pUnk->Release();
+ }
+ else
+ {
+ refUnknown = ((ULONG)(0 - 2));
+ }
+
+ IWebBrowser2 *pWeb2 = NULL;
+ if (SUCCEEDED(browser->GetIWebBrowser2(&pWeb2)) && pWeb2 != NULL)
+ {
+ refWeb = pWeb2->Release();
+ }
+ else
+ {
+ refWeb = ((ULONG)(0 - 2));
+ }
+ refBrowser = browser->Release();
+
+ aTRACE_FMT("Browser Stats: Instance=%d, IUnknown=%d, IWebBrowser2=%d\r\n", refBrowser, refUnknown, refWeb);
+}
+#endif // _DEBUG \ No newline at end of file
diff --git a/Src/omBrowser/browser.h b/Src/omBrowser/browser.h
new file mode 100644
index 00000000..df9985b1
--- /dev/null
+++ b/Src/omBrowser/browser.h
@@ -0,0 +1,226 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+#include "../nu/HTMLContainer2.h"
+#include "./browserInternal.h"
+
+class obj_ombrowser;
+class Browser;
+class ifc_omdebugconfig;
+class ifc_omservice;
+class ifc_travelloghelper;
+
+typedef void (CALLBACK *BHCALLBACK)(Browser* /*browser*/);
+typedef void (CALLBACK *BHNAVCOMPLETECALLBACK)(Browser* /*browser*/, IDispatch* /*pDispatch*/, VARIANT* /*URL*/);
+typedef void (CALLBACK *BHCMDSTATECALLBACK)(Browser* /*browser*/, INT /*commandId*/, BOOL /*fEnabled*/);
+typedef void (CALLBACK *BHTEXTCALLBACK)(Browser* /*browser*/, LPCWSTR /*pszText*/);
+typedef HRESULT (CALLBACK *BHSERVICECALLBACK)(Browser* /*browser*/, ifc_omservice** /*ppService*/);
+typedef LRESULT (CALLBACK *BHMSGCALLBACK)(Browser* /*browser*/, MSG* /*pMsg*/);
+typedef void (CALLBACK *BHCREATEPOPUPCALLBACK)(Browser* /*browser*/, IDispatch** /*ppDisp*/, VARIANT_BOOL* /*Cancel*/);
+typedef void (CALLBACK *BHBOOLCALLBACK)(Browser* /*browser*/, VARIANT_BOOL /*Visible*/);
+typedef void (CALLBACK *BHCLOSECALLBACK)(Browser* /*browser*/, VARIANT_BOOL /*IsChild*/, VARIANT_BOOL* /*Cancel*/);
+typedef void (CALLBACK *BHSHOWUICALLBACK)(Browser* /*browser*/, UINT /*elementId*/, VARIANT_BOOL /*fShow*/);
+typedef void (CALLBACK *BHCLIENTTOHOSTCALLBACK)(Browser* /*browser*/, LONG* /*CX*/, LONG* /*CY*/);
+typedef void (CALLBACK *BHFOCUSCHANGECALLBACK)(Browser* /*browser*/, VARIANT_BOOL* /*fAllow*/);
+typedef void (CALLBACK *BHWINDOWPOSCALLBACK)(Browser* /*browser*/, UINT /*Flags*/, LONG /*X*/, LONG /*Y*/, LONG /*Width*/, LONG /*Height*/);
+
+
+class Browser : public HTMLContainer2,
+ public IDropTarget,
+ public IProtectFocus,
+ public IHTMLOMWindowServices,
+ public INewWindowManager
+{
+public:
+ typedef enum
+ {
+ commandNone = 0,
+ commandBack = 1,
+ commandForward = 2,
+ commandStop = 3,
+ commandRefresh = 4,
+ commandRefreshCompletely = 5,
+ } Commands;
+
+ typedef enum
+ {
+ commandStateSupported = 1,
+ commandStateEnabled = 2,
+ commandStateLatched = 4,
+ } CommandStates;
+
+ typedef enum
+ {
+ flagUiDisableScroll = 0x00000001,
+ flagUiDisableContextMenu = 0x00000002,
+ flagUiDialogMode = 0x00000004,
+ flagUiDisableHostCss = 0x00000008,
+ } UiFlags;
+
+protected:
+ Browser(obj_ombrowser *browserMngr, HWND winampWindow, HWND hParent);
+ ~Browser();
+
+public:
+ static Browser *CreateInstance(obj_ombrowser *browserManager, HWND winampWindow, HWND hParent);
+
+public:
+
+ /*** IUnknown ***/
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+ STDMETHOD (QueryInterface)(REFIID, LPVOID*);
+
+ /*** IDropTarget ***/
+ STDMETHOD (DragEnter)(IDataObject *, DWORD, POINTL, DWORD*);
+ STDMETHOD (DragOver)(DWORD, POINTL, DWORD*);
+ STDMETHOD (DragLeave)(void);
+ STDMETHOD (Drop)(IDataObject*, DWORD, POINTL, DWORD*);
+
+ STDMETHOD (GetDropTarget)(IDropTarget*, IDropTarget **);
+
+ STDMETHOD (GetExternal)(IDispatch __RPC_FAR *__RPC_FAR *ppDispatch);
+ STDMETHOD (ShowContextMenu)(DWORD dwID, POINT __RPC_FAR *ppt, IUnknown __RPC_FAR *pcmdtReserved, IDispatch __RPC_FAR *pdispReserved);
+ STDMETHOD (ShowMessage)(HWND hwnd, LPOLESTR lpstrText, LPOLESTR lpstrCaption, DWORD dwType, LPOLESTR lpstrHelpFile, DWORD dwHelpContext, LRESULT *plResult);
+
+
+ // *** IDocHostUIHandler ***
+ STDMETHOD (TranslateAccelerator)(LPMSG lpMsg, const GUID __RPC_FAR *pguidCmdGroup, DWORD nCmdID);
+
+ /*** IDocHostUIHandler2 ***/
+ STDMETHOD (GetOverrideKeyPath)(LPOLESTR __RPC_FAR *pchKey, DWORD dw);
+
+ /*** IOleCommandTarget ***/
+ STDMETHOD (Exec)(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut);
+
+ /*** IServiceProvider ***/
+ STDMETHOD (QueryService)(REFGUID guidService, REFIID riid, void **ppv);
+
+ /*** IProtectFocus ***/
+ STDMETHOD (AllowFocusChange)(BOOL *pfAllow);
+
+ /*** IHTMLOMWindowServices ***/
+ STDMETHOD (moveTo)(LONG x, LONG y);
+ STDMETHOD (moveBy)(LONG x, LONG y);
+ STDMETHOD (resizeTo)(LONG x, LONG y);
+ STDMETHOD (resizeBy)(LONG x, LONG y);
+
+ /*** INewWindowManager ***/
+ STDMETHOD (EvaluateNewWindow)(LPCWSTR pszUrl, LPCWSTR pszName, LPCWSTR pszUrlContext, LPCWSTR pszFeatures, BOOL fReplace, DWORD dwFlags, DWORD dwUserActionTime);
+
+
+ STDMETHOD (Initialize)(BOOL fRegisterAsBrowser);
+ STDMETHOD (Finish)(void);
+
+ HRESULT SetExternal(IDispatch *pDispatch);
+ HRESULT SendCommand(INT commandId);
+ HRESULT QueryCommandState(INT commandId, INT *commandState);
+ UINT GetSecueLockIcon() { return secureLockIcon; }
+
+ BOOL TranslateKey(LPMSG pMsg);
+
+ /*Events*/
+ BHNAVCOMPLETECALLBACK EventDocumentReady;
+ BHNAVCOMPLETECALLBACK EventNavigateComplete;
+ BHCALLBACK EventDownloadBegin;
+ BHCALLBACK EventDownloadComplete;
+ BHCALLBACK EventContainerDestroyed;
+ BHCMDSTATECALLBACK EventCommandStateChange;
+ BHTEXTCALLBACK EventStatusChange;
+ BHTEXTCALLBACK EventTitleChange;
+ BHCALLBACK EventSecureLockIconChange;
+ BHCREATEPOPUPCALLBACK EventCreatePopup;
+ BHBOOLCALLBACK EventVisible;
+ BHBOOLCALLBACK EventSetResizable;
+ BHCLOSECALLBACK EventWindowClosing;
+ BHSHOWUICALLBACK EventShowUiElement;
+ BHCLIENTTOHOSTCALLBACK EventClientToHost;
+ BHWINDOWPOSCALLBACK EventSetWindowPos;
+ BHFOCUSCHANGECALLBACK EventFocusChange;
+ BHBOOLCALLBACK EventSetFullscreen;
+ BHCALLBACK EventClosePopup;
+
+ BHSERVICECALLBACK CallbackGetOmService;
+ BHMSGCALLBACK CallbackRedirectKey;
+
+ HRESULT GetExternalName(LPWSTR pszBuffer, INT cchBufferMax);
+
+ void SetUiFlags(UINT flags, UINT mask);
+ UINT GetUiFlags(UINT mask);
+
+ HRESULT ToggleFullscreen();
+ HRESULT GetTravelLog(ifc_travelloghelper **travelLog);
+
+protected:
+
+ void OnBeforeNavigate(IDispatch *pDispatch, VARIANT *URL, VARIANT *Flags, VARIANT *TargetFrameName, VARIANT *PostData, VARIANT *Headers, VARIANT_BOOL *Cancel);
+ void OnDownloadBegin(void);
+ void OnDownloadComplete(void);
+ void OnNavigateComplete(IDispatch *pDispatch, VARIANT *URL);
+ void OnDocumentReady(IDispatch *pDispatch, VARIANT *URL);
+ void OnNavigateError(IDispatch *pDispatch, VARIANT *URL, VARIANT *TargetFrameName, VARIANT *StatusCode, VARIANT_BOOL *Cancel);
+ void OnCommandStateChange(LONG commandId, VARIANT_BOOL Enable);
+ void OnStatusTextChange(LPCWSTR pszText);
+ void OnSetSecureLockIcon(UINT secureLockIcon);
+ void OnNavigateCancelled(LPCWSTR pszUrl, VARIANT_BOOL *Cancel);
+ void OnNewWindow2(IDispatch **ppDisp, VARIANT_BOOL *Cancel);
+ void OnNewWindow3(IDispatch **ppDisp, VARIANT_BOOL *Cancel, DWORD dwFlags, BSTR bstrUrlContext, BSTR bstrUrl);
+ void OnTitleChange(BSTR pszText);
+ void OnVisibleChange(VARIANT_BOOL fVisible);
+ void OnWindowClosing(VARIANT_BOOL IsChildWindow, VARIANT_BOOL *Cancel);
+ void OnShowUiElement(UINT elementId, VARIANT_BOOL fShow);
+ void OnWindowSetResizable(VARIANT_BOOL Enable);
+ void OnEnableFullscreen(VARIANT_BOOL Enable);
+ void OnClientToHostWindow(LONG *CX, LONG *CY);
+ void OnSetWindowPos(UINT Flags, LONG X, LONG Y, LONG CX, LONG CY);
+
+ virtual COLORREF OnGetHostBkColor(void);
+ virtual DWORD OnGetHostInfoFlags(void);
+ virtual OLECHAR* OnGetHostCSS(void);
+ virtual DWORD OnGetDownlodFlags(void);
+ virtual LPCWSTR OnGetUserAgent(void);
+
+ HRESULT FormatErrorParam(LPWSTR pszBuffer, INT cchBufferMax, UINT errorCode, LPCWSTR pszUrl);
+
+ HANDLE InitializePopupHook(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ void DeletePopupHook(HANDLE hHook);
+ void InitializeMenuPopup(HWND hwnd, HMENU hMenu, INT iPos, BOOL fWindowMenu);
+
+ BOOL InputLangChangeRequest(HWND hwnd, UINT flags, HKL hkl);
+ void InputLangChange(UINT charset, HKL hkl);
+ void OnClosePopupInternal();
+
+ HRESULT GetDebugConfig(ifc_omdebugconfig **debugConfig);
+ HRESULT GetErrorPageName(LPWSTR pszBuffer, HRESULT cchBufferMax, UINT errorCode, BOOL fCancel);
+
+private:
+ typedef enum
+ {
+ navigationForwardEnabled = 0x0001,
+ navigationBackEnabled = 0x0002,
+ navigationActive = 0x0004,
+ } navigationState;
+
+private:
+ obj_ombrowser *browserManager;
+ IDispatch *externalDisp;
+ IDropTargetHelper *pDropTargetHerlper;
+ UINT navigationState;
+ UINT secureLockIcon;
+ WCHAR szDone[64];
+ LPWSTR pszUserAgent;
+ UINT uiFlags;
+};
+
+#ifdef _DEBUG
+ void BrowserDebug_PrintRefs(Browser *browser);
+#else
+ #define BrowserDebug_PrintRefs(x)
+#endif //_DEBUG
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/browserClass.cpp b/Src/omBrowser/browserClass.cpp
new file mode 100644
index 00000000..9a05846f
--- /dev/null
+++ b/Src/omBrowser/browserClass.cpp
@@ -0,0 +1,191 @@
+#include "main.h"
+#include "./browserClass.h"
+#include "./browserRegistry.h"
+#include "./configIni.h"
+#include <strsafe.h>
+
+OmBrowserClass::OmBrowserClass(LPCWSTR pszName)
+ : ref(1), name(NULL), config(NULL), registry(NULL)
+{
+ InitializeCriticalSection(&lock);
+ name = Plugin_CopyString(pszName);
+}
+
+OmBrowserClass::~OmBrowserClass()
+{
+ if (NULL != config)
+ config->Release();
+
+ if (NULL != registry)
+ {
+ registry->Delete();
+ registry->Release();
+ }
+
+ Plugin_FreeString(name);
+
+ DeleteCriticalSection(&lock);
+}
+
+HRESULT OmBrowserClass::CreateInstance(LPCWSTR pszName, OmBrowserClass **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ *instance = NULL;
+
+ *instance = new OmBrowserClass(pszName);
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t OmBrowserClass::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t OmBrowserClass::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ {
+ if (NULL != name && L'\0' != *name)
+ Plugin_UnregisterBrowserClass(name);
+ delete(this);
+ }
+
+ return r;
+}
+
+int OmBrowserClass::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmBrowserClass))
+ *object = static_cast<ifc_ombrowserclass*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT OmBrowserClass::GetName(LPWSTR pszBuffer, INT cchBufferMax)
+{
+ if (NULL == pszBuffer) return E_POINTER;
+ return StringCchCopyEx(pszBuffer, cchBufferMax, name, NULL, NULL, STRSAFE_IGNORE_NULLS);
+}
+
+HRESULT OmBrowserClass::IsEqual(LPCWSTR pszName)
+{
+ if (NULL == pszName || L'\0' == *pszName)
+ return E_INVALIDARG;
+
+ if (NULL == name)
+ return E_UNEXPECTED;
+
+ INT result = CompareString(CSTR_INVARIANT, NORM_IGNORECASE, pszName, -1, name, -1);
+ if (0 == result)
+ {
+ DWORD errorCode = GetLastError();
+ return HRESULT_FROM_WIN32(errorCode);
+ }
+
+ return (CSTR_EQUAL == result) ? S_OK : S_FALSE;
+}
+
+HRESULT OmBrowserClass::GetConfig(ifc_omconfig **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ *instance = NULL;
+
+ HRESULT hr = S_OK;
+
+ EnterCriticalSection(&lock);
+
+ if (NULL == config)
+ {
+ hr = OmConfigIni::CreateInstance(name, &config);
+ if (FAILED(hr))
+ {
+ config = NULL;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ *instance = config;
+ config->AddRef();
+ }
+
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+HRESULT OmBrowserClass::GetRegistry(ifc_ombrowserregistry **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ *instance = NULL;
+
+ HRESULT hr = S_OK;
+
+ EnterCriticalSection(&lock);
+
+ if (NULL == registry)
+ {
+ hr = OmBrowserRegistry::CreateInstance(name, &registry);
+ if (FAILED(hr))
+ {
+ registry = NULL;
+ }
+ else
+ {
+ registry->Write();
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ *instance = registry;
+ registry->AddRef();
+ }
+
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+HRESULT OmBrowserClass::UpdateRegColors()
+{
+ HRESULT hr = S_FALSE;
+ EnterCriticalSection(&lock);
+
+ if (NULL != registry)
+ hr = registry->UpdateColors();
+
+ LeaveCriticalSection(&lock);
+
+ return hr;
+}
+
+#define CBCLASS OmBrowserClass
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_GETNAME, GetName)
+CB(API_ISEQUAL, IsEqual)
+CB(API_GETCONFIG, GetConfig)
+CB(API_GETREGISTRY, GetRegistry)
+CB(API_UPDATEREGCOLORS, UpdateRegColors)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/browserClass.h b/Src/omBrowser/browserClass.h
new file mode 100644
index 00000000..5fa56344
--- /dev/null
+++ b/Src/omBrowser/browserClass.h
@@ -0,0 +1,46 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_CLASS_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_CLASS_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_ombrowserclass.h"
+
+class OmConfigIni;
+class OmBrowserRegistry;
+
+class OmBrowserClass : public ifc_ombrowserclass
+{
+protected:
+ OmBrowserClass(LPCWSTR pszName);
+ ~OmBrowserClass();
+
+public:
+ static HRESULT CreateInstance(LPCWSTR pszName, OmBrowserClass **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /*ifc_ombrowserclass */
+ HRESULT GetName(LPWSTR pszBuffer, INT cchBufferMax);
+ HRESULT IsEqual(LPCWSTR pszName);
+ HRESULT GetConfig(ifc_omconfig **instance);
+ HRESULT GetRegistry(ifc_ombrowserregistry **instance);
+ HRESULT UpdateRegColors();
+
+protected:
+ RECVS_DISPATCH;
+
+protected:
+ ULONG ref;
+ CRITICAL_SECTION lock;
+ LPWSTR name;
+ OmConfigIni *config;
+ OmBrowserRegistry *registry;
+};
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_CLASS_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/browserFactory.cpp b/Src/omBrowser/browserFactory.cpp
new file mode 100644
index 00000000..90ec7c9f
--- /dev/null
+++ b/Src/omBrowser/browserFactory.cpp
@@ -0,0 +1,90 @@
+#include "./browserFactory.h"
+#include "./browserObject.h"
+
+
+FOURCC OmBrowserFactory::GetServiceType()
+{
+ return WaSvc::UNIQUE;
+}
+
+const char *OmBrowserFactory::GetServiceName()
+{
+ return "OmBrowser Object";
+}
+
+const char *OmBrowserFactory::GetTestString()
+{
+ return NULL;
+}
+
+GUID OmBrowserFactory::GetGUID()
+{
+ return OBJ_OmBrowser;
+}
+
+
+void *OmBrowserFactory::GetInterface( int global_lock )
+{
+ OmBrowserObject *browserObject = NULL;
+
+ HRESULT hr = OmBrowserObject::CreateInstance( &browserObject );
+ if ( FAILED( hr ) )
+ browserObject = NULL;
+
+ return browserObject;
+}
+
+int OmBrowserFactory::ReleaseInterface( void *ifc )
+{
+ obj_ombrowser *object = (obj_ombrowser *)ifc;
+ if ( object != NULL )
+ object->Release();
+
+ return 1;
+}
+
+
+int OmBrowserFactory::SupportNonLockingInterface()
+{
+ return 1;
+}
+
+int OmBrowserFactory::ServiceNotify(int msg, int param1, int param2)
+{
+ return 1;
+}
+
+
+HRESULT OmBrowserFactory::Register( api_service *service )
+{
+ if ( service == NULL )
+ return E_INVALIDARG;
+
+ service->service_register( this );
+
+ return S_OK;
+}
+
+HRESULT OmBrowserFactory::Unregister( api_service *service )
+{
+ if ( service == NULL )
+ return E_INVALIDARG;
+
+ service->service_deregister( this );
+
+ return S_OK;
+}
+
+
+#define CBCLASS OmBrowserFactory
+START_DISPATCH;
+CB( WASERVICEFACTORY_GETSERVICETYPE, GetServiceType )
+CB( WASERVICEFACTORY_GETSERVICENAME, GetServiceName )
+CB( WASERVICEFACTORY_GETGUID, GetGUID )
+CB( WASERVICEFACTORY_GETINTERFACE, GetInterface )
+CB( WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface )
+CB( WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface )
+CB( WASERVICEFACTORY_GETTESTSTRING, GetTestString )
+CB( WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify )
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/browserFactory.h b/Src/omBrowser/browserFactory.h
new file mode 100644
index 00000000..d3b70839
--- /dev/null
+++ b/Src/omBrowser/browserFactory.h
@@ -0,0 +1,40 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_SERVICEFACTORY_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_SERVICEFACTORY_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <api/service/waservicefactory.h>
+#include <api/service/services.h>
+
+class obj_ombrowser;
+
+class OmBrowserFactory : public waServiceFactory
+{
+public:
+ OmBrowserFactory() {}
+ ~OmBrowserFactory() {}
+
+ FOURCC GetServiceType();
+ const char *GetServiceName();
+ const char *GetTestString();
+ GUID GetGUID();
+
+ void *GetInterface( int global_lock = 1 );
+ int ReleaseInterface( void *ifc );
+
+ int SupportNonLockingInterface();
+ int ServiceNotify( int msg, int param1, int param2 );
+
+ HRESULT Register( api_service *service );
+ HRESULT Unregister( api_service *service );
+
+protected:
+ RECVS_DISPATCH;
+
+};
+
+
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_SERVICEFACTORY_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/browserHost.cpp b/Src/omBrowser/browserHost.cpp
new file mode 100644
index 00000000..368dd43f
--- /dev/null
+++ b/Src/omBrowser/browserHost.cpp
@@ -0,0 +1,1232 @@
+#include "main.h"
+#include "./browser.h"
+#include "./browserHost.h"
+//#include "./browserPopup.h"
+#include "./graphics.h"
+
+//#include "../winamp/wa_dlg.h"
+#include "../Plugins/General/gen_ml/colors.h"
+
+#include "./browserThread.h"
+
+#include "../winamp/IWasabiDispatchable.h"
+#include "../winamp/JSAPI_Info.h"
+
+#include "./service.h"
+//#include "./menu.h"
+
+#include "./obj_ombrowser.h"
+#include "./ifc_skinhelper.h"
+#include "./ifc_skinnedbrowser.h"
+#include "./ifc_omservice.h"
+#include "./ifc_travelloghelper.h"
+#include "./ifc_wasabihelper.h"
+#include <exdispid.h>
+#include <strsafe.h>
+
+#define NWC_OMBROWSERHOST L"Nullsoft_omBrowserHost"
+
+typedef struct __BROWSERHOSTCREATEPARAM
+{
+ HWND hParent;
+ INT controlId;
+ UINT fStyle;
+ INT x;
+ INT y;
+ INT cx;
+ INT cy;
+ HINSTANCE hInstance;
+ HACCEL hAccel;
+ obj_ombrowser *browserManager;
+} BROWSERHOSTCREATEPARAM;
+
+typedef struct __BROWSERHOST
+{
+ Browser *container;
+ HACCEL hAccel;
+ obj_ombrowser *browserManager;
+} BROWSERHOST;
+
+
+#define BHT_CONTAINERDOWNLOAD 27
+#define BHT_ACTIVATECONTAINER_DELAY 15
+#define BHT_DEACTIVATECONTAINER_DELAY 75
+
+#define GetHost(__hwnd) ((BROWSERHOST*)(LONG_PTR)(LONGX86)GetWindowLongPtr((__hwnd), 0))
+
+static LRESULT CALLBACK BrowserHost_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+static void CALLBACK BrowserHost_OnDocumentReady(Browser *browser, IDispatch *pDispatch, VARIANT *URL);
+static void CALLBACK BrowserHost_OnNavigateComplete(Browser *browser, IDispatch *pDispatch, VARIANT *URL);
+static void CALLBACK BrowserHost_OnContainerDestroy(Browser *browser);
+static void CALLBACK BrowserHost_OnDownloadBegin(Browser *browser);
+static void CALLBACK BrowserHost_OnDownloadComplete(Browser *browser);
+static void CALLBACK BrowserHost_OnCommandStateChange(Browser *browser, INT commandId, BOOL fEnabled);
+static void CALLBACK BrowserHost_OnStatusChange(Browser *browser, LPCWSTR pszText);
+static void CALLBACK BrowserHost_OnTitleChange(Browser *browser, LPCWSTR pszText);
+static void CALLBACK BrowserHost_OnSecureLockIconChange(Browser *browser);
+static void CALLBACK BrowserHost_OnCreatePopup(Browser *browser, IDispatch **ppDisp, VARIANT_BOOL *Cancel);
+static void CALLBACK BrowserHost_OnVisibleChange(Browser *browser, VARIANT_BOOL fVisible);
+static void CALLBACK BrowserHost_OnSetResizable(Browser *browser, VARIANT_BOOL fAllow);
+static void CALLBACK BrowserHost_OnSetFullScreen(Browser *browser, VARIANT_BOOL fAllow);
+static void CALLBACK BrowserHost_OnWindowClosing(Browser *browser, VARIANT_BOOL fIsChild, VARIANT_BOOL *fCancel);
+static void CALLBACK BrowserHost_OnShowUiElenent(Browser *browser, UINT elementId, VARIANT_BOOL fShow);
+static void CALLBACK BrowserHost_OnClientToHost(Browser *browser, LONG *cx, LONG *cy);
+static void CALLBACK BrowserHost_OnSetWindowPos(Browser *browser, UINT Flags, LONG x, LONG y, LONG cx, LONG cy);
+static void CALLBACK BrowserHost_OnFocusChange(Browser *browser, VARIANT_BOOL *fAllow);
+static void CALLBACK BrowserHost_OnClosePopup(Browser *browser);
+
+static HRESULT CALLBACK BrowserHost_GetOmService(Browser *browser, ifc_omservice **ppService);
+static LRESULT CALLBACK BrowserHost_RedirectKey(Browser *browser, MSG *pMsg);
+
+static BOOL BrowserHost_RegisterClass(HINSTANCE hInstance)
+{
+ WNDCLASS wc = {0};
+ if (GetClassInfo(hInstance, NWC_OMBROWSERHOST, &wc)) return TRUE;
+
+ ZeroMemory(&wc, sizeof(WNDCLASS));
+ wc.hInstance = hInstance;
+ wc.lpszClassName = NWC_OMBROWSERHOST;
+ wc.lpfnWndProc = BrowserHost_WindowProc;
+ wc.style = CS_DBLCLKS;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = NULL;
+ wc.cbWndExtra = sizeof(BROWSERHOST*);
+
+ return ( 0 != RegisterClassW(&wc));
+}
+
+static HWND CALLBACK BrowserHost_CreateHostWindow(ULONG_PTR user)
+{
+ BROWSERHOSTCREATEPARAM *param = (BROWSERHOSTCREATEPARAM*)user;
+ if (NULL == param) return NULL;
+
+ return CreateWindowEx(WS_EX_NOPARENTNOTIFY | WS_EX_CONTROLPARENT,
+ NWC_OMBROWSERHOST, NULL,
+ WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | (0x00000FFF & param->fStyle),
+ param->x, param->y, param->cx, param->cy,
+ param->hParent, (HMENU)(INT_PTR)param->controlId,
+ param->hInstance, param);
+}
+
+static BOOL CALLBACK BrowserHost_KeyFilter(HWND hwnd, MSG *pMsg)
+{
+ BROWSERHOST *host = GetHost(hwnd);
+ if (NULL == host) return FALSE;
+
+ UINT vKey = (UINT)pMsg->wParam;
+ switch(vKey)
+ {
+ case VK_CONTROL:
+ case VK_MENU:
+ case VK_SHIFT:
+ return TRUE;
+ }
+
+ if (NULL != host->hAccel && (hwnd == pMsg->hwnd || IsChild(hwnd, pMsg->hwnd)))
+ {
+ HWND hParent = GetParent(hwnd);
+ if (NULL != hParent && 0 != TranslateAccelerator(hParent, host->hAccel, pMsg))
+ return TRUE;
+ }
+
+ return (NULL != host->container &&
+ FALSE != host->container->TranslateKey(pMsg));
+}
+
+HWND BrowserHost_CreateWindow(obj_ombrowser *browserManager, HWND hParent, UINT fStyle, INT x, INT y, INT cx, INT cy, INT controlId, HACCEL hAccel)
+{
+ if (FALSE == BrowserHost_RegisterClass(Plugin_GetInstance()))
+ return NULL;
+
+ BROWSERHOSTCREATEPARAM param = {0};
+
+ param.hParent = hParent;
+ param.controlId = controlId;
+ param.hInstance = Plugin_GetInstance();
+ param.x = x;
+ param.y = y;
+ param.cx = cx;
+ param.cy = cy;
+ param.fStyle = fStyle;
+ param.hAccel = hAccel;
+ param.browserManager = browserManager;
+
+ HWND hWinamp = NULL;
+ if (FAILED(Plugin_GetWinampWnd(&hWinamp)))
+ hWinamp = NULL;
+
+ HWND hHost = NULL;
+ HANDLE hThread = BrowserThread_Create(hWinamp, BrowserHost_CreateHostWindow, (ULONG_PTR)&param, BrowserHost_KeyFilter, &hHost, NULL);
+ if (NULL != hThread)
+ CloseHandle(hThread);
+
+ return hHost;
+}
+
+static LRESULT BrowserHost_SendBrowserNotification(Browser *browser, INT code, NMHDR *pnmh)
+{
+ HWND hHost = (NULL != browser) ? browser->GetParentHWND() : NULL;
+ if (NULL == hHost || NULL == pnmh)
+ return 0;
+
+ HWND hParent = GetParent(hHost);
+ if (NULL == hParent)
+ return 0;
+
+ pnmh->code = code;
+ pnmh->hwndFrom = hHost;
+ pnmh->idFrom = GetDlgCtrlID(hHost);
+
+ return SendMessage(hParent, WM_NOTIFY, (WPARAM)pnmh->idFrom, (LPARAM)pnmh);
+}
+
+static LRESULT BrowserHost_SendNotification(HWND hwnd, NMHDR *phdr)
+{
+ HWND hParent = GetParent(hwnd);
+ if (NULL == hParent || NULL == phdr || !IsWindow(hParent))
+ return 0;
+
+ return SendMessage(hParent, WM_NOTIFY, (WPARAM)phdr->idFrom, (LPARAM)phdr);
+}
+
+static void BrowserHost_UpdateLayout(HWND hwnd, BOOL fRedraw)
+{
+ BROWSERHOST *host = GetHost(hwnd);
+ if (NULL == host) return;
+
+ RECT clientRect;
+ if (!GetClientRect(hwnd, &clientRect))
+ return;
+
+ if (NULL != host->container)
+ {
+ host->container->SetLocation(clientRect.left, clientRect.top,
+ clientRect.right - clientRect.left,
+ clientRect.bottom - clientRect.top);
+ }
+}
+
+static COLORREF BrwoserHost_GetBackColor(HWND hwnd)
+{
+ COLORREF rgb;
+
+ ifc_skinnedbrowser *skinnedBrowser = NULL;
+ if (SUCCEEDED(Plugin_GetBrowserSkin(&skinnedBrowser)) && skinnedBrowser != NULL)
+ {
+ rgb = skinnedBrowser->GetBackColor();
+ skinnedBrowser->Release();
+ }
+ else
+ rgb = GetSysColor(COLOR_WINDOW);
+
+ return rgb;
+}
+
+static void BrowserHost_Paint(HWND hwnd, HDC hdc, const RECT *prcPaint, BOOL fErase)
+{
+ SetBkColor(hdc, BrwoserHost_GetBackColor(hwnd));
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, prcPaint, NULL, 0, NULL);
+}
+
+static LRESULT BrowserHost_OnCreate(HWND hwnd, CREATESTRUCT *pcs)
+{
+ BROWSERHOST *host= (BROWSERHOST*)calloc(1, sizeof(BROWSERHOST));
+ if (NULL != host)
+ {
+ SetLastError(ERROR_SUCCESS);
+ if (!SetWindowLongPtr(hwnd, 0, (LONGX86)(LONG_PTR)host) && ERROR_SUCCESS != GetLastError())
+ {
+ free(host);
+ host = NULL;
+ }
+ }
+
+ if (NULL == host)
+ {
+ DestroyWindow(hwnd);
+ return -1;
+ }
+
+ BROWSERHOSTCREATEPARAM *param = (BROWSERHOSTCREATEPARAM*)pcs->lpCreateParams;
+ host->hAccel = param->hAccel;
+ host->browserManager = param->browserManager;
+ if (NULL != host->browserManager)
+ host->browserManager->AddRef();
+
+ return 0;
+}
+
+static void BrowserHost_OnDestroy(HWND hwnd)
+{
+ BROWSERHOST *host = GetHost(hwnd);
+ /*if (NULL != host->container)
+ {
+ // SendMessage(hwnd, BTM_RELEASECONTAINER, 0, 0L);
+ // BrowserThread_SetFlags(BHTF_BEGINDESTROY, BHTF_BEGINDESTROY, FALSE);
+ }*/
+
+ SetWindowLongPtr(hwnd, 0, 0L);
+
+ if (NULL != host)
+ {
+ if (NULL != host->browserManager)
+ {
+ host->browserManager->Release();
+ }
+ free(host);
+ }
+
+#ifdef _DEBUG
+ aTRACE_FMT("[%d] %S: host window destroyed\r\n", GetCurrentThreadId(), OMBROWSER_NAME);
+#endif // _DEBUG
+}
+
+static void BrowserHost_OnPaint(HWND hwnd)
+{
+ PAINTSTRUCT ps = {0};
+ if (BeginPaint(hwnd, &ps))
+ {
+ if (ps.rcPaint.left != ps.rcPaint.right)
+ BrowserHost_Paint(hwnd, ps.hdc, &ps.rcPaint, ps.fErase);
+ EndPaint(hwnd, &ps);
+ }
+}
+
+static void BrowserHost_OnPrintClient(HWND hwnd, HDC hdc, UINT options)
+{
+ RECT clientRect;
+ if (GetClientRect(hwnd, &clientRect))
+ BrowserHost_Paint(hwnd, hdc, &clientRect, 0 != (PRF_ERASEBKGND & options));
+}
+
+static void BrowserHost_OnWindowPosChanged(HWND hwnd, WINDOWPOS *pwp)
+{
+ if (SWP_NOSIZE == ((SWP_NOSIZE | SWP_FRAMECHANGED) & pwp->flags))
+ return;
+ BrowserHost_UpdateLayout(hwnd, 0 == (SWP_NOREDRAW & pwp->flags));
+}
+
+static void BrowserHost_OnCommand(HWND hwnd, INT controlId, INT eventId, HWND hControl)
+{
+}
+
+static HRESULT BrowserHost_AssociateDispatch(HWND hwnd, IDispatch *pDispatch)
+{
+ if (NULL == pDispatch)
+ return E_INVALIDARG;
+
+ IWasabiDispatchable *pWasabi = NULL;
+ HRESULT hr = pDispatch->QueryInterface(IID_IWasabiDispatchable, (void**)&pWasabi);
+ if (SUCCEEDED(hr) && pWasabi != NULL)
+ {
+ JSAPI::ifc_info *pInfo = NULL;
+ hr = pWasabi->QueryDispatchable(JSAPI::IID_JSAPI_ifc_info, (Dispatchable**)&pInfo);
+ if (SUCCEEDED(hr) && pInfo != NULL)
+ {
+ HWND hParent = GetParent(hwnd);
+ if (NULL == hParent) hParent = hwnd;
+
+ pInfo->SetHWND(hParent);
+
+ WCHAR szBuffer[512] = {0};
+ BROWSERHOST *host = GetHost(hwnd);
+ if (NULL != host && NULL != host->container)
+ {
+ ifc_omservice *service = NULL;
+ if (SUCCEEDED(BrowserHost_GetOmService(host->container, &service)) && service != NULL)
+ {
+ if (FAILED(service->GetName(szBuffer, ARRAYSIZE(szBuffer))))
+ szBuffer[0]= L'\0';
+ service->Release();
+ }
+ }
+
+ pInfo->SetName(szBuffer);
+ pInfo->Release();
+ }
+ pWasabi->Release();
+ }
+ return hr;
+}
+
+static void BrowserHost_OnContainerInit(HWND winampWindow, HWND hwnd)
+{
+ BROWSERHOST *host = GetHost(hwnd);
+ if (NULL == host) return;
+
+ if (NULL != host->container) return; // we're alredy running
+
+ DWORD windowStyle = GetWindowStyle(hwnd);
+
+ HTMLContainer2_Initialize();
+
+ Browser *container = Browser::CreateInstance(host->browserManager, winampWindow, hwnd);
+ host->container = container;
+ if (NULL != container)
+ {
+ ifc_omservice *service = NULL;
+ if (SUCCEEDED(BrowserHost_GetOmService(container, &service)) && service != NULL)
+ {
+ IDispatch *pDispatch = NULL;
+ if (SUCCEEDED(service->GetExternal(&pDispatch)) && NULL != pDispatch)
+ {
+ BrowserHost_AssociateDispatch(hwnd, pDispatch);
+ container->SetExternal(pDispatch);
+ pDispatch->Release();
+ }
+ service->Release();
+ }
+
+ container->EventDocumentReady = BrowserHost_OnDocumentReady;
+ container->EventNavigateComplete = BrowserHost_OnNavigateComplete;
+ container->EventContainerDestroyed = BrowserHost_OnContainerDestroy;
+ container->EventDownloadBegin = BrowserHost_OnDownloadBegin;
+ container->EventDownloadComplete = BrowserHost_OnDownloadComplete;
+ container->EventCommandStateChange = BrowserHost_OnCommandStateChange;
+ container->EventStatusChange = BrowserHost_OnStatusChange;
+ container->EventTitleChange = BrowserHost_OnTitleChange;
+ container->EventSecureLockIconChange = BrowserHost_OnSecureLockIconChange;
+ container->EventCreatePopup = BrowserHost_OnCreatePopup;
+ container->EventFocusChange = BrowserHost_OnFocusChange;
+ container->EventWindowClosing = BrowserHost_OnWindowClosing;
+
+ if (0 != (NBHS_POPUP & windowStyle))
+ {
+ container->EventVisible = BrowserHost_OnVisibleChange;
+ container->EventSetResizable = BrowserHost_OnSetResizable;
+ container->EventSetFullscreen = BrowserHost_OnSetFullScreen;
+ container->EventShowUiElement = BrowserHost_OnShowUiElenent;
+ container->EventClientToHost = BrowserHost_OnClientToHost;
+ container->EventSetWindowPos = BrowserHost_OnSetWindowPos;
+ container->EventClosePopup = BrowserHost_OnClosePopup;
+ }
+
+ container->CallbackGetOmService = BrowserHost_GetOmService;
+ container->CallbackRedirectKey = BrowserHost_RedirectKey;
+
+ UINT uiFlags = 0;
+ if (0 != (NBHS_DISABLECONTEXTMENU & windowStyle)) uiFlags |= Browser::flagUiDisableContextMenu;
+ if (0 != (NBHS_DIALOGMODE & windowStyle)) uiFlags |= Browser::flagUiDialogMode;
+ if (0 != (NBHS_DISABLEHOSTCSS & windowStyle)) uiFlags |= Browser::flagUiDisableHostCss;
+
+ if (0 != uiFlags)
+ container->SetUiFlags(uiFlags, uiFlags);
+
+ HRESULT hr = container->Initialize(0 != (NBHS_POPUP & windowStyle));
+ if (SUCCEEDED(hr) && 0 == (NBHS_SCRIPTMODE & windowStyle))
+ {
+ // we need to do this to allow script error disabling
+ hr = container->NavigateToName(NULL, 0);
+ }
+
+ if (FAILED(hr) || 0 != (NBHS_SCRIPTMODE & windowStyle))
+ {
+ if (0 == (NBHS_BROWSERREADY & windowStyle))
+ {
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle | NBHS_BROWSERREADY);
+
+ NMHDR hdr;
+ BrowserHost_SendBrowserNotification(container, NBHN_READY, &hdr);
+ }
+ }
+ }
+
+ HWND hParent = GetParent(hwnd);
+ if (NULL != hParent)
+ {
+ DWORD threadMine = 0, threadParent = 0;
+ threadMine = GetCurrentThreadId();
+ threadParent = GetWindowThreadProcessId(hParent, NULL);
+ if (0 != threadMine && threadMine != threadParent)
+ {
+ AttachThreadInput(threadMine, threadParent, TRUE);
+
+ HKL hkl = GetKeyboardLayout(threadParent);
+ if (NULL != hkl)
+ ActivateKeyboardLayout(hkl, 0);
+ }
+ }
+}
+
+static void BrowserHost_OnContainerRelease(HWND hwnd)
+{
+ BROWSERHOST *host = GetHost(hwnd);
+ if (NULL == host) return;
+
+ Browser *container = host->container;
+ host->container = NULL;
+ if (NULL == container) return;
+
+ container->EventDocumentReady = NULL;
+ container->EventNavigateComplete = NULL;
+ container->EventDownloadBegin = NULL;
+ container->EventDownloadComplete = NULL;
+ container->EventCommandStateChange = NULL;
+ container->EventStatusChange = NULL;
+ container->EventTitleChange = NULL;
+ container->EventSecureLockIconChange = NULL;
+ container->EventCreatePopup = NULL;
+ container->EventVisible = NULL;
+ container->EventSetResizable = NULL;
+ container->EventSetFullscreen = NULL;
+ container->EventWindowClosing = NULL;
+ container->EventShowUiElement = NULL;
+ container->EventClientToHost = NULL;
+ container->EventSetWindowPos = NULL;
+ container->EventFocusChange = NULL;
+ container->CallbackGetOmService = NULL;
+ container->CallbackRedirectKey = NULL;
+
+ if (SUCCEEDED(container->SendCommand(Browser::commandStop)) &&
+ SUCCEEDED(container->NavigateToName(NULL, navNoHistory | navNoWriteToCache)))
+ {
+ IWebBrowser2 *pWeb2 = NULL;
+ if (SUCCEEDED(container->GetIWebBrowser2(&pWeb2)) && pWeb2 != NULL)
+ {
+ ReplyMessage(0);
+ BrowserThread_WaitNavigateComplete(pWeb2, 30000);
+ pWeb2->Release();
+ }
+ }
+ else
+ {
+ }
+
+ container->Finish();
+ container->Release();
+
+ HWND hParent = GetParent(hwnd);
+ if (NULL != hParent)
+ {
+ DWORD threadMine = 0, threadParent = 0;
+ threadMine = GetCurrentThreadId();
+ threadParent = GetWindowThreadProcessId(hParent, NULL);
+ if (0 != threadMine && threadMine != threadParent)
+ {
+ AttachThreadInput(threadMine, threadParent, FALSE);
+ }
+ }
+}
+
+static LRESULT BrowserHost_OnNiceDestroy(HWND hwnd, BOOL fImmediate)
+{
+ DWORD windowStyle = GetWindowStyle(hwnd);
+ if (0 != (WS_VISIBLE & windowStyle))
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE);
+
+ BROWSERHOST *host = GetHost(hwnd);
+ if (NULL != host && NULL != host->container && FALSE == fImmediate)
+ {
+ HWND hWinamp = NULL;
+ if (FAILED(Plugin_GetWinampWnd(&hWinamp)))
+ hWinamp = NULL;
+
+ if (hWinamp != GetParent(hwnd))
+ {
+ SetParent(hwnd, hWinamp);
+ SetWindowLongPtr(hwnd, GWLP_HWNDPARENT, (LONGX86)(LONG_PTR)hWinamp);
+ }
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
+
+ if (FALSE != BrowserThread_PostDestroy(hwnd))
+ return TRUE;
+ }
+
+ BrowserThread_SetFlags(BHTF_BEGINDESTROY, BHTF_BEGINDESTROY, FALSE);
+ BrowserHost_OnContainerRelease(hwnd);
+ return (0 != DestroyWindow(hwnd));
+}
+
+static void BrowserHost_OnContainerCommand(HWND hwnd, INT commandId)
+{
+ BROWSERHOST *host = GetHost(hwnd);
+ if (NULL == host) return;
+
+ if (NULL == host->container) return;
+ host->container->SendCommand(commandId);
+}
+
+static void BrowserHost_OnUpdateSkin(HWND hwnd)
+{
+ BROWSERHOST *host = GetHost(hwnd);
+ if (NULL == host) return;
+
+ if (NULL != host->container)
+ {
+ //HWND hWinamp;
+ //if (NULL == host->browserManager || FAILED(host->browserManager->GetWinampWindow(&hWinamp)))
+ // hWinamp = NULL;
+
+ //HCURSOR cursor = (HCURSOR)SENDWAIPC(hWinamp, IPC_GETSKINCURSORS, WACURSOR_NORMAL);
+ //if (NULL != cursor)
+ //{
+ // host->container->RegisterBrowserCursor(/*OCR_NORMAL*/32512, CopyCursor(cursor));
+ //}
+ }
+
+ UINT windowStyle = GetWindowStyle(hwnd);
+ if (NBHS_BROWSERREADY == ((NBHS_BROWSERREADY | NBHS_BROWSERACTIVE) & windowStyle))
+ {
+ PostMessage(hwnd, NBHM_CONTAINERCOMMAND, (WPARAM)Browser::commandRefresh, 0L);
+ }
+}
+
+static void BrowserHost_OnNavigate(HWND hwnd, BSTR url, UINT flags)
+{
+ BROWSERHOST *host = GetHost(hwnd);
+ if (NULL != host &&
+ NULL != host->container &&
+ FALSE == BrowserThread_IsQuiting())
+ {
+ host->container->NavigateToName(url, flags);
+ }
+ if (NULL != url)
+ {
+ SysFreeString(url);
+ }
+}
+
+static void BrowserHost_OnEnableContainerUpdate(HWND hwnd, BOOL fEnable, BOOL fRedraw)
+{
+ BROWSERHOST *host = GetHost(hwnd);
+ if (NULL == host || NULL == host->container) return;
+
+ HWND hContainer = host->container->GetHostHWND();
+ if (NULL == hContainer) return;
+
+ SendMessage(hContainer, WM_SETREDRAW, fEnable, 0L);
+ if (fEnable && fRedraw)
+ RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW | RDW_NOERASE | RDW_NOFRAME | RDW_NOINTERNALPAINT | RDW_VALIDATE | RDW_ERASENOW );
+}
+
+static void BrowserHost_OnQueueAPC(HWND hwnd, PAPCFUNC pfnApc, ULONG_PTR param)
+{
+ if (NULL == pfnApc) return;
+ pfnApc(param);
+}
+
+static void BrowserHost_OnShowHistoryPopup(HWND hwnd, UINT fuFlags, POINTS pts)
+{
+ BROWSERHOST *host = GetHost(hwnd);
+ if (NULL != host && NULL != host->container)
+ {
+ ifc_travelloghelper *travelLog;
+ if (SUCCEEDED(host->container->GetTravelLog(&travelLog)))
+ {
+ travelLog->ShowPopup(fuFlags, pts.x, pts.y, hwnd, NULL);
+ travelLog->Release();
+ }
+ }
+}
+
+static void BrowserHost_OnGetDispatchApc(HWND hwnd, DISPATCHAPC callback, ULONG_PTR param)
+{
+ if (NULL == callback) return;
+
+ IDispatch *pDisp = NULL;
+ BROWSERHOST *host = GetHost(hwnd);
+ if (NULL != host && NULL != host->container)
+ {
+ IWebBrowser2 *pWeb2 = NULL;
+ if (SUCCEEDED(host->container->GetIWebBrowser2(&pWeb2)) && pWeb2 != NULL)
+ {
+ pWeb2->get_Application(&pDisp);
+ pWeb2->Release();
+ }
+ }
+
+ callback(pDisp, param);
+
+ if (NULL != pDisp)
+ pDisp->Release();
+}
+
+static void BrowserHost_OnActivate(HWND hwnd)
+{
+ BROWSERHOST *host = GetHost(hwnd);
+ if (NULL != host && NULL != host->container)
+ {
+ host->container->SetFocus(TRUE);
+ }
+}
+
+static void BrowserHost_OnQueryTitle(HWND hwnd)
+{
+ BSTR bstrName = NULL;
+ BROWSERHOST *host = GetHost(hwnd);
+ if (NULL != host && NULL != host->container)
+ {
+ IWebBrowser2 *pWeb2 = NULL;
+ if (SUCCEEDED(host->container->GetIWebBrowser2(&pWeb2)) && pWeb2 != NULL)
+ {
+ if (FAILED(pWeb2->get_LocationName(&bstrName)))
+ bstrName = NULL;
+ pWeb2->Release();
+ }
+ }
+
+ BHNTEXTCHANGE textChange = {0};
+ textChange.hdr.code = NBHN_TITLECHANGE;
+ textChange.hdr.hwndFrom = hwnd;
+ textChange.hdr.idFrom = GetDlgCtrlID(hwnd);
+ textChange.pszText = bstrName;
+
+ BrowserHost_SendNotification(hwnd, (NMHDR*)&textChange);
+
+ SysFreeString(bstrName);
+}
+
+static void BrowserHost_OnToggleFullscreen(HWND hwnd)
+{
+ BROWSERHOST *host = GetHost(hwnd);
+ if (NULL == host || NULL == host->container)
+ return;
+
+ host->container->ToggleFullscreen();
+}
+
+static void BrowserHost_OnWriteDocument(HWND hwnd, BSTR documentData)
+{
+ BROWSERHOST *host = GetHost(hwnd);
+ if (NULL == host ||
+ NULL == host->container ||
+ FAILED(host->container->WriteDocument(documentData)))
+ {
+ SysFreeString(documentData);
+ }
+}
+
+static void BrowserHost_OnEnableWindow(HWND hwnd, BOOL fEnable)
+{
+ EnableWindow(hwnd, fEnable);
+}
+
+static void BrowserHost_OnUpdateExternal(HWND hwnd)
+{
+ BROWSERHOST *host = GetHost(hwnd);
+ if (NULL == host) return;
+
+ if (NULL != host->container)
+ {
+ ifc_omservice *service = NULL;
+ if (SUCCEEDED(BrowserHost_GetOmService(host->container, &service)) && service != NULL)
+ {
+ IDispatch *pDispatch = NULL;
+ if (SUCCEEDED(service->GetExternal(&pDispatch)) && NULL != pDispatch)
+ {
+ BrowserHost_AssociateDispatch(hwnd, pDispatch);
+ host->container->SetExternal(pDispatch);
+ pDispatch->Release();
+ }
+ service->Release();
+ }
+ }
+}
+
+static LRESULT CALLBACK BrowserHost_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_CREATE:
+ return BrowserHost_OnCreate(hwnd, (CREATESTRUCT*)lParam);
+ case WM_DESTROY:
+ BrowserHost_OnDestroy(hwnd);
+ break;
+ case WM_ERASEBKGND:
+ return 0;
+ case WM_PAINT:
+ BrowserHost_OnPaint(hwnd);
+ return 0;
+ case WM_PRINTCLIENT:
+ BrowserHost_OnPrintClient(hwnd, (HDC)wParam, (UINT)lParam);
+ return 0;
+ case WM_WINDOWPOSCHANGED:
+ BrowserHost_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam);
+ return 0;
+ case WM_COMMAND:
+ BrowserHost_OnCommand(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam);
+ break;
+ case BTM_INITCONTAINER:
+ BrowserHost_OnContainerInit((HWND)wParam, hwnd);
+ return 0;
+ case BTM_RELEASECONTAINER:
+ BrowserHost_OnContainerRelease(hwnd);
+ return 0;
+ case NBHM_DESTROY:
+ return BrowserHost_OnNiceDestroy(hwnd, (BOOL)wParam);
+ case NBHM_CONTAINERCOMMAND:
+ BrowserHost_OnContainerCommand(hwnd, (INT)wParam);
+ return 0;
+ case NBHM_UPDATESKIN:
+ BrowserHost_OnUpdateSkin(hwnd);
+ return 0;
+ case NBHM_NAVIGATE:
+ BrowserHost_OnNavigate(hwnd, (BSTR)lParam, (UINT)wParam);
+ return 0;
+ case NBHM_ENABLECONTAINERUPDATE:
+ BrowserHost_OnEnableContainerUpdate(hwnd, (BOOL)wParam, (BOOL)lParam);
+ return 0;
+ case NBHM_QUEUEAPC:
+ BrowserHost_OnQueueAPC(hwnd, (PAPCFUNC)lParam, (ULONG_PTR)wParam);
+ return 0;
+ case NBHM_SHOWHISTORYPOPUP:
+ BrowserHost_OnShowHistoryPopup(hwnd, (UINT)wParam, MAKEPOINTS(lParam));
+ return 0;
+ case NBHM_GETDISPATCHAPC:
+ BrowserHost_OnGetDispatchApc(hwnd, (DISPATCHAPC)lParam, (ULONG_PTR)wParam);
+ return 0;
+ case NBHM_ACTIVATE:
+ BrowserHost_OnActivate(hwnd);
+ return 0;
+ case NBHM_QUERYTITLE:
+ BrowserHost_OnQueryTitle(hwnd);
+ return 0;
+ case NBHM_TOGGLEFULLSCREEN:
+ BrowserHost_OnToggleFullscreen(hwnd);
+ return 0;
+ case NBHM_WRITEDOCUMENT:
+ BrowserHost_OnWriteDocument(hwnd, (BSTR)lParam);
+ return 0;
+ case NBHM_ENABLEWINDOW:
+ BrowserHost_OnEnableWindow(hwnd, (BOOL)lParam);
+ return 0;
+ case NBHM_UPDATEEXTERNAL:
+ BrowserHost_OnUpdateExternal(hwnd);
+ return 0;
+ }
+
+ return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+}
+
+static DWORD BrowserHost_GetBrowserFlags(Browser *browser)
+{
+ if (NULL == browser) return 0;
+ HWND hHost = browser->GetParentHWND();
+ if (NULL == hHost) return 0;
+
+ DWORD windowStyle = GetWindowStyle(hHost);
+ return (NBHS_BROWSERMASK & windowStyle);
+}
+
+static void CALLBACK BrowserHost_OnDocumentReady(Browser *browser, IDispatch *pDispatch, VARIANT *URL)
+{
+ HWND hHost = browser->GetParentHWND();
+ if (NULL == hHost) return;
+
+ DWORD windowStyle = GetWindowStyle(hHost);
+ if (0 == (NBHS_BROWSERREADY & windowStyle))
+ {
+ SetWindowLongPtr(hHost, GWL_STYLE, windowStyle | NBHS_BROWSERREADY);
+
+ NMHDR hdr = {0};
+ BrowserHost_SendBrowserNotification(browser, NBHN_READY, &hdr);
+ }
+ else
+ {
+ BHNNAVCOMPLETE document = {0};
+ document.pDispatch = pDispatch;
+ document.URL = URL;
+ document.fTopFrame = TRUE;
+ BrowserHost_SendBrowserNotification(browser, NBHN_DOCUMENTREADY, (NMHDR*)&document);
+ }
+}
+
+static void CALLBACK BrowserHost_OnNavigateComplete(Browser *browser, IDispatch *pDispatch, VARIANT *URL)
+{
+ HWND hHost = browser->GetParentHWND();
+ if (NULL == hHost) return;
+
+ DWORD windowStyle = GetWindowStyle(hHost);
+ if (0 == (NBHS_BROWSERREADY & windowStyle))
+ return;
+
+ IWebBrowser2 *pWeb1 = NULL, *pWeb2 = NULL;
+
+ if (FAILED(browser->GetIWebBrowser2(&pWeb1)))
+ pWeb1 = NULL;
+
+ if (NULL == pDispatch || FAILED(pDispatch->QueryInterface(IID_IWebBrowser2, (void**)&pWeb2)))
+ pWeb2 = NULL;
+
+ if (NULL != pWeb1) pWeb1->Release();
+ if (NULL != pWeb2) pWeb2->Release();
+
+ BHNNAVCOMPLETE document = {0};
+ document.pDispatch = pDispatch;
+ document.URL = URL;
+ document.fTopFrame = (NULL != pWeb1 && pWeb1 == pWeb2);
+ BrowserHost_SendBrowserNotification(browser, NBHN_NAVIGATECOMPLETE, (NMHDR*)&document);
+}
+
+static void CALLBACK BrowserHost_OnContainerDestroy(Browser *browser)
+{
+ BrowserThread_SetFlags(BHTF_BEGINDESTROY, BHTF_BEGINDESTROY, FALSE);
+ PostMessage(NULL, WM_QUIT, 0, 0L);
+}
+
+static void BrowserHost_NotifyContainerActive(HWND hwnd, BOOL fActive, UINT_PTR timerId)
+{
+ if (0 != timerId)
+ KillTimer(hwnd, timerId);
+
+ DWORD windowStyle = GetWindowStyle(hwnd);
+ if ((FALSE == fActive) != (0 == (NBHS_BROWSERACTIVE & windowStyle)))
+ return;
+
+ if (0 == (NBHS_BROWSERREADY & windowStyle))
+ fActive = FALSE;
+
+ BHNACTIVE active = {0};
+ active.hdr.code = NBHN_BROWSERACTIVE;
+ active.hdr.hwndFrom = hwnd;
+ active.hdr.idFrom = GetDlgCtrlID(hwnd);
+ active.fActive = fActive;
+ BrowserHost_SendNotification(hwnd, (NMHDR*)&active);
+
+ BROWSERHOST *host = GetHost(hwnd);
+ INT commandState = 0;
+ if (NULL != host &&
+ NULL != host->container &&
+ SUCCEEDED(host->container->QueryCommandState(Browser::commandStop, &commandState)))
+ {
+ BOOL fEnable = (0 != (Browser::commandStateEnabled & commandState));
+ BrowserHost_OnCommandStateChange(host->container, Browser::commandStop, fEnable);
+ }
+}
+
+static void CALLBACK BrowserHost_ActivateContainerTimer(HWND hwnd, UINT uMsg, UINT_PTR eventId, DWORD time)
+{
+ BrowserHost_NotifyContainerActive(hwnd, TRUE, eventId);
+}
+
+static void CALLBACK BrowserHost_DeactivateContainerTimer(HWND hwnd, UINT uMsg, UINT_PTR eventId, DWORD time)
+{
+ BrowserHost_NotifyContainerActive(hwnd, FALSE, eventId);
+}
+
+static void CALLBACK BrowserHost_OnDownloadBegin(Browser *browser)
+{
+ HWND hHost = browser->GetParentHWND();
+ if (NULL == hHost) return;
+
+ DWORD windowStyle = GetWindowStyle(hHost);
+ if (NBHS_BROWSERREADY == ((NBHS_BROWSERACTIVE | NBHS_BROWSERREADY) & windowStyle))
+ {
+ SetWindowLongPtr(hHost, GWL_STYLE, windowStyle | NBHS_BROWSERACTIVE);
+ SetTimer(hHost, BHT_CONTAINERDOWNLOAD, BHT_ACTIVATECONTAINER_DELAY, BrowserHost_ActivateContainerTimer);
+ }
+}
+
+static void CALLBACK BrowserHost_OnDownloadComplete(Browser *browser)
+{
+ HWND hHost = browser->GetParentHWND();
+ if (NULL == hHost) return;
+
+ DWORD windowStyle = GetWindowStyle(hHost);
+ if (0 != (NBHS_BROWSERACTIVE & windowStyle))
+ {
+ SetWindowLongPtr(hHost, GWL_STYLE, windowStyle & ~NBHS_BROWSERACTIVE);
+ SetTimer(hHost, BHT_CONTAINERDOWNLOAD, BHT_DEACTIVATECONTAINER_DELAY, BrowserHost_DeactivateContainerTimer);
+ }
+}
+
+static void CALLBACK BrowserHost_OnCommandStateChange(Browser *browser, INT commandId, BOOL fEnabled)
+{
+ if (Browser::commandStop == commandId && FALSE != fEnabled &&
+ NBHS_BROWSERREADY == ((NBHS_BROWSERACTIVE | NBHS_BROWSERREADY) & BrowserHost_GetBrowserFlags(browser)))
+ {
+ fEnabled = FALSE;
+ }
+
+ BHNCMDSTATE commandState = {0};
+ commandState.commandId = commandId;
+ commandState.fEnabled = fEnabled;
+ BrowserHost_SendBrowserNotification(browser, NBHN_COMMANDSTATECHANGE, (NMHDR*)&commandState);
+}
+
+static void CALLBACK BrowserHost_OnStatusChange(Browser *browser, LPCWSTR pszText)
+{
+ if (0 == (NBHS_BROWSERREADY & BrowserHost_GetBrowserFlags(browser)))
+ return;
+
+ BHNTEXTCHANGE textChange = {0};
+ textChange.pszText = pszText;
+ BrowserHost_SendBrowserNotification(browser, NBHN_STATUSCHANGE, (NMHDR*)&textChange);
+}
+
+static void CALLBACK BrowserHost_OnTitleChange(Browser *browser, LPCWSTR pszText)
+{
+ if (0 == (NBHS_BROWSERREADY & BrowserHost_GetBrowserFlags(browser)))
+ return;
+
+ BHNTEXTCHANGE textChange = {0};
+ textChange.pszText = pszText;
+ BrowserHost_SendBrowserNotification(browser, NBHN_TITLECHANGE, (NMHDR*)&textChange);
+}
+
+static void CALLBACK BrowserHost_OnSecureLockIconChange(Browser *browser)
+{
+ BHNSECUREICON icon = {0};
+ icon.iconId = browser->GetSecueLockIcon();
+ BrowserHost_SendBrowserNotification(browser, NBHN_SECUREICONCHANGE, (NMHDR*)&icon);
+}
+
+typedef struct __POPUPCALLBACKPARAM
+{
+ IDispatch **ppDisp;
+ HANDLE readyEvent;
+ HWND hHost;
+} POPUPCALLBACKPARAM;
+
+typedef struct __DISPATCHMARSHALPARAM
+{
+ LPSTREAM pStream;
+ IDispatch *pDisp;
+ HRESULT hr;
+} DISPATCHMARSHALPARAM;
+
+static void CALLBACK BrowserHost_DispatchMarshalApc(ULONG_PTR user)
+{
+ DISPATCHMARSHALPARAM *param = (DISPATCHMARSHALPARAM*)user;
+ if (NULL == param) return;
+
+ param->hr = CoGetInterfaceAndReleaseStream(param->pStream, IID_IDispatch, (void**)&param->pDisp);
+ //if (SUCCEEDED(param->hr) && NULL != param->pDisp)
+ // param->pDisp->AddRef();
+}
+
+static void CALLBACK BrowserHost_DispatchCallbackApc(IDispatch *pDisp, ULONG_PTR user)
+{
+ POPUPCALLBACKPARAM *param = (POPUPCALLBACKPARAM*)user;
+ if (NULL == param) return;
+
+ if (NULL != pDisp)
+ {
+ LPSTREAM pStream = NULL;
+ if (SUCCEEDED(CoMarshalInterThreadInterfaceInStream(IID_IDispatch, pDisp, &pStream)))
+ { // switch
+ DISPATCHMARSHALPARAM marshal = {0};
+ marshal.pStream = pStream;
+ SendMessage(param->hHost, NBHM_QUEUEAPC, (WPARAM)&marshal, (LPARAM)BrowserHost_DispatchMarshalApc);
+ if (SUCCEEDED(marshal.hr) && NULL != marshal.pDisp)
+ {
+ *param->ppDisp = marshal.pDisp;
+ }
+ }
+ }
+
+ if (NULL != param->readyEvent)
+ SetEvent(param->readyEvent);
+}
+
+static HRESULT BrowserHost_GetSecurityApi(JSAPI2::api_security **securityApi)
+{
+ if (NULL == securityApi)
+ return E_POINTER;
+
+ *securityApi = NULL;
+
+ ifc_wasabihelper *wasabiHelper = NULL;
+ HRESULT hr = Plugin_GetWasabiHelper(&wasabiHelper);
+ if (SUCCEEDED(hr) && wasabiHelper != NULL)
+ {
+ hr = wasabiHelper->GetSecurityApi(securityApi);
+ wasabiHelper->Release();
+ }
+ return hr;
+}
+
+static BOOL BrowserHost_IsPopupAllowed(HWND hwnd, Browser *browser)
+{
+ ifc_omservice *service = NULL;
+ if (FAILED(BrowserHost_GetOmService(browser, &service)) || NULL == service)
+ return TRUE;
+
+ BOOL fAllowed = TRUE;
+
+ JSAPI::ifc_info *pInfo = NULL;
+ WCHAR szKey[64] = {0};
+
+ if (FAILED(StringCchPrintfW(szKey, ARRAYSIZE(szKey), L"%u", service->GetId())))
+ szKey[0] = L'\0';
+
+ IDispatch *pDispatch = NULL;
+ if (SUCCEEDED(browser->GetExternal(&pDispatch)) && NULL != pDispatch)
+ {
+ IWasabiDispatchable *pWasabi = NULL;
+ if (SUCCEEDED(pDispatch->QueryInterface(IID_IWasabiDispatchable, (void**)&pWasabi)) && pWasabi != NULL)
+ {
+ if (FAILED(pWasabi->QueryDispatchable(JSAPI::IID_JSAPI_ifc_info, (Dispatchable**)&pInfo)))
+ pInfo = NULL;
+ pWasabi->Release();
+ }
+ pDispatch->Release();
+ }
+
+ if (NULL != pInfo && L'\0' != szKey)
+ {
+ JSAPI2::api_security *security = NULL;
+ if (SUCCEEDED(BrowserHost_GetSecurityApi(&security)) && security != NULL)
+ {
+ if (security->GetActionAuthorization(L"application", L"launchurl", szKey, pInfo,
+ JSAPI2::api_security::ACTION_PROMPT) != JSAPI2::api_security::ACTION_ALLOWED)
+ {
+ fAllowed = FALSE;
+ }
+ security->Release();
+ }
+ }
+
+ if (NULL != pInfo)
+ pInfo->Release();
+
+ service->Release();
+ return fAllowed;
+}
+
+static void CALLBACK BrowserHost_OnCreatePopup(Browser *browser, IDispatch **ppDisp, VARIANT_BOOL *Cancel)
+{
+ HWND hHost = browser->GetParentHWND();
+
+ if (FALSE == BrowserHost_IsPopupAllowed(hHost, browser))
+ {
+ if (NULL != Cancel) *Cancel = VARIANT_TRUE;
+ return;
+ }
+
+ POPUPCALLBACKPARAM param = {0};
+ param.hHost = browser->GetParentHWND();
+ if (NULL == param.hHost) return;
+
+ param.readyEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ param.ppDisp = ppDisp;
+
+ BHNCREATEPOPUP popup = {0};
+ popup.callback = BrowserHost_DispatchCallbackApc;
+ popup.param = (ULONG_PTR)&param;
+
+ if (FALSE != BrowserHost_SendBrowserNotification(browser, NBHN_CREATEPOPUP, (NMHDR*)&popup))
+ {
+ BrowserThread_ModalLoop(param.hHost, param.readyEvent, 30000);
+ }
+
+ if (NULL != param.readyEvent)
+ CloseHandle(param.readyEvent);
+}
+
+static void CALLBACK BrowserHost_OnVisibleChange(Browser *browser, VARIANT_BOOL fVisible)
+{
+ BHNVISIBLE visible = {0};
+ visible.fVisible = (VARIANT_FALSE != fVisible);
+ BrowserHost_SendBrowserNotification(browser, NBHN_VISIBLECHANGE, (NMHDR*)&visible);
+}
+
+static void CALLBACK BrowserHost_OnSetResizable(Browser *browser, VARIANT_BOOL fAllow)
+{
+ BHNRESIZABLE resizable = {0};
+ resizable.fEnabled = (VARIANT_FALSE != fAllow);
+ BrowserHost_SendBrowserNotification(browser, NBHN_RESIZABLE, (NMHDR*)&resizable);
+}
+
+static void CALLBACK BrowserHost_OnSetFullScreen(Browser *browser, VARIANT_BOOL fEnable)
+{
+ BHNFULLSCREEN fullscreen = {0};
+ fullscreen.fEnable = (VARIANT_FALSE != fEnable);
+ BrowserHost_SendBrowserNotification(browser, NBHN_FULLSCREEN, (NMHDR*)&fullscreen);
+}
+
+static void CALLBACK BrowserHost_OnWindowClosing(Browser *browser, VARIANT_BOOL fIsChild, VARIANT_BOOL *fCancel)
+{
+ BHNCLOSING closing = {0};
+ closing.isChild = (VARIANT_FALSE != fIsChild);
+ closing.cancel = FALSE;
+
+ BrowserHost_SendBrowserNotification(browser, NBHN_CLOSING, (NMHDR*)&closing);
+
+ if (FALSE != closing.cancel && NULL != fCancel)
+ *fCancel = VARIANT_TRUE;
+}
+
+static void CALLBACK BrowserHost_OnShowUiElenent(Browser *browser, UINT elementId, VARIANT_BOOL fShow)
+{
+ BHNSHOWUI ui = {0};
+ ui.elementId = elementId;
+ ui.fShow = fShow;
+
+ BrowserHost_SendBrowserNotification(browser, NBHN_SHOWUI, (NMHDR*)&ui);
+}
+
+static void CALLBACK BrowserHost_OnClientToHost(Browser *browser, LONG *cx, LONG *cy)
+{
+ BHNCLIENTTOHOST convert = {0};
+ convert.cx = *cx;
+ convert.cy = *cy;
+ BrowserHost_SendBrowserNotification(browser, NBHN_CLIENTTOHOST, (NMHDR*)&convert);
+
+ *cx = convert.cx;
+ *cy = convert.cy;
+}
+
+static void CALLBACK BrowserHost_OnSetWindowPos(Browser *browser, UINT flags, LONG x, LONG y, LONG cx, LONG cy)
+{
+ BHNSETWINDOWPOS windowPos = {0};
+ windowPos.flags = flags;
+ windowPos.x = x;
+ windowPos.y = y;
+ windowPos.cx = cx;
+ windowPos.cy = cy;
+
+ BrowserHost_SendBrowserNotification(browser, NBHN_SETWINDOWPOS, (NMHDR*)&windowPos);
+}
+
+static void CALLBACK BrowserHost_OnFocusChange(Browser *browser, VARIANT_BOOL *fAllow)
+{
+ BHNFOCUSCHANGE focus = {0};
+ focus.fAllow = (VARIANT_FALSE != *fAllow);
+
+ BrowserHost_SendBrowserNotification(browser, NBHN_FOCUSCHANGE, (NMHDR*)&focus);
+
+ *fAllow = (FALSE != focus.fAllow) ? VARIANT_TRUE : VARIANT_FALSE;
+}
+
+static void CALLBACK BrowserHost_OnClosePopup(Browser *browser)
+{
+ NMHDR hdr = {0};
+ BrowserHost_SendBrowserNotification(browser, NBHN_CLOSEPOPUP, &hdr);
+
+}
+static HRESULT CALLBACK BrowserHost_GetOmService(Browser *browser, ifc_omservice **ppService)
+{
+ if (NULL == ppService) return E_POINTER;
+
+ BHNSERVICE service = {0};
+
+ if (FALSE != BrowserHost_SendBrowserNotification(browser, NBHN_GETOMSERVICE, (NMHDR*)&service) &&
+ NULL != service.instance)
+ {
+ *ppService = (ifc_omservice*)service.instance;
+ return S_OK;
+ }
+
+ *ppService = NULL;
+ return E_NOTIMPL;
+}
+
+
+static LRESULT CALLBACK BrowserHost_RedirectKey(Browser *browser, MSG *pMsg)
+{
+ HWND hHost = browser->GetParentHWND();
+ HWND hParent = GetParent(hHost);
+
+ if (NULL == hParent)
+ {
+ BROWSERHOST *host = GetHost(hHost);
+
+ if (NULL != host && FAILED(Plugin_GetWinampWnd(&hParent)))
+ hParent = NULL;
+ }
+
+ return PostMessage(hParent, pMsg->message, pMsg->wParam, pMsg->lParam);
+} \ No newline at end of file
diff --git a/Src/omBrowser/browserHost.h b/Src/omBrowser/browserHost.h
new file mode 100644
index 00000000..355aa57f
--- /dev/null
+++ b/Src/omBrowser/browserHost.h
@@ -0,0 +1,180 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_BROWSERHOST_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_BROWSERHOST_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+class obj_ombrowser;
+
+typedef void (CALLBACK *DISPATCHAPC)(IDispatch *pDisp, ULONG_PTR /*param*/);
+
+HWND BrowserHost_CreateWindow(obj_ombrowser *browserManager, HWND hParent, UINT fStyle, INT x, INT y, INT cx, INT cy, INT controlId, HACCEL hAccel);
+
+#define NBHS_POPUP 0x00000001
+#define NBHS_SCRIPTMODE 0x00000002
+#define NBHS_DISABLECONTEXTMENU 0x00000004
+#define NBHS_DIALOGMODE 0x00000008
+#define NBHS_DISABLEHOSTCSS 0x00000010
+
+#define NBHS_BROWSERMASK 0x0000F000
+#define NBHS_BROWSERREADY 0x00001000
+#define NBHS_BROWSERACTIVE 0x00002000
+
+
+#define NBHM_FIRST (WM_USER + 200)
+#define NBHM_DESTROY (NBHM_FIRST + 10) // wParam = (WPARAM)(BOOL)fImmediate, lParam - not used. Preffered way to close it. Returns TRUE if processed
+
+// Post this messages
+#define NBHM_CONTAINERCOMMAND (NBHM_FIRST + 11) // wParam = (WPARAM)(INT)browserCommandId, lParam - not used
+#define NBHM_UPDATESKIN (NBHM_FIRST + 12) // wParam - not used, lParam - not used.
+#define NBHM_NAVIGATE (NBHM_FIRST + 13) // wParam - (WPARAM)(UINT)navigateFlags, lParam = (LPARAM)(BSTR)navigateUrl.
+#define NBHM_ENABLECONTAINERUPDATE (NBHM_FIRST + 14) // wParam - (WPARAM)(BOOL)fEnable, lParam = (WPARAM)(BOOL)fRedraw
+#define NBHM_QUEUEAPC (NBHM_FIRST + 15) // wParam = (WPARAM)userData, lParam = (LPARAM)(PAPCFUNC)pfnAPC
+
+
+#define NBHM_SHOWHISTORYPOPUP (NBHM_FIRST + 16) //wParam = (WPARAM)popupFlags, lParam =(LPARAM)MAKELPARAM(popupPos).
+#define NBHM_GETDISPATCHAPC (NBHM_FIRST + 17) // wParam = (WPARAM)param, lParam = (LPARAM)(DISPATCHAPC)callback
+#define NBHM_ACTIVATE (NBHM_FIRST + 18) // wParam - not used, lParam - not used. Activates browser (OLEIVERB_UIACTIVATE)
+#define NBHM_QUERYTITLE (NBHM_FIRST + 19) // wParam - not used, lParam - not used. Will query for current title and send NBHN_TITLECHANGE back
+#define NBHM_TOGGLEFULLSCREEN (NBHM_FIRST + 20) // wParam - not used, lParam - not used.
+
+#define NBHM_WRITEDOCUMENT (NBHM_FIRST + 21) // wParam - not used, lParam = (LPARAM)(BSTR)bstrDocument;
+#define NBHM_ENABLEWINDOW (NBHM_FIRST + 22) // wParam - not used, lParam = (LPARAM)(BOOL)fEnabled;
+#define NBHM_UPDATEEXTERNAL (NBHM_FIRST + 23) // wParam - not used, lParam - not used.
+
+#define NBHN_FIRST (200)
+#define NBHN_READY (NBHN_FIRST + 0)
+
+typedef struct __BHNNAVCOMPLETE
+{
+ NMHDR hdr;
+ IDispatch *pDispatch;
+ VARIANT *URL;
+ BOOL fTopFrame;
+} BHNNAVCOMPLETE;
+
+#define NBHN_DOCUMENTREADY (NBHN_FIRST + 1)
+#define NBHN_NAVIGATECOMPLETE (NBHN_FIRST + 2)
+
+
+typedef struct __BHNACTIVE
+{
+ NMHDR hdr;
+ BOOL fActive;
+} BHNACTIVE;
+#define NBHN_BROWSERACTIVE (NBHN_FIRST + 3)
+
+typedef struct __BHNCMDSTATE
+{
+ NMHDR hdr;
+ UINT commandId;
+ BOOL fEnabled;
+} BHNCMDSTATE;
+#define NBHN_COMMANDSTATECHANGE (NBHN_FIRST + 4)
+
+typedef struct __BHNTEXTCHANGE
+{
+ NMHDR hdr;
+ LPCWSTR pszText;
+} BHNTEXTCHANGE;
+
+#define NBHN_STATUSCHANGE (NBHN_FIRST + 5)
+#define NBHN_TITLECHANGE (NBHN_FIRST + 6)
+
+typedef struct __BHNSECUREICON
+{
+ NMHDR hdr;
+ UINT iconId;
+} BHNSECUREICON;
+#define NBHN_SECUREICONCHANGE (NBHN_FIRST + 7)
+
+
+typedef struct __BHNSERVICE
+{
+ NMHDR hdr;
+ void *instance;
+} BHNSERVICE;
+#define NBHN_GETOMSERVICE (NBHN_FIRST + 8) // call service->AddRef() and return TRUE if you support this
+
+typedef struct __BHNCREATEPOPUP
+{
+ NMHDR hdr;
+ DISPATCHAPC callback;
+ ULONG_PTR param;
+} BHNCREATEPOPUP;
+
+#define NBHN_CREATEPOPUP (NBHN_FIRST + 9)
+
+typedef struct __BHNVISIBLE
+{
+ NMHDR hdr;
+ BOOL fVisible;
+} BHNVISIBLE;
+#define NBHN_VISIBLECHANGE (NBHN_FIRST + 10) // send to popup
+
+typedef struct __BHNRESIZABLE
+{
+ NMHDR hdr;
+ BOOL fEnabled;
+} BHNRESIZABLE;
+#define NBHN_RESIZABLE (NBHN_FIRST + 11)
+
+typedef struct __BHNCLOSING
+{
+ NMHDR hdr;
+ BOOL isChild;
+ BOOL cancel;
+} BHNCLOSING;
+#define NBHN_CLOSING (NBHN_FIRST + 12)
+
+typedef struct __BHNSHOWUI
+{
+ NMHDR hdr;
+ UINT elementId;
+ BOOL fShow;
+} BHNSHOWUI;
+#define NBHN_SHOWUI (NBHN_FIRST + 13)
+
+typedef struct __BHNCLIENTTOHOST
+{
+ NMHDR hdr;
+ LONG cx;
+ LONG cy;
+} BHNCLIENTTOHOST;
+#define NBHN_CLIENTTOHOST (NBHN_FIRST + 14)
+
+typedef struct __BHNSETWINDOWPOS
+{
+ NMHDR hdr;
+ UINT flags;
+ LONG x;
+ LONG y;
+ LONG cx;
+ LONG cy;
+} BHNSETWINDOWPOS;
+#define NBHN_SETWINDOWPOS (NBHN_FIRST + 15)
+
+typedef struct __BHNFOCUSCHANGE
+{
+ NMHDR hdr;
+ BOOL fAllow;
+} BHNFOCUSCHANGE;
+#define NBHN_FOCUSCHANGE (NBHN_FIRST + 16)
+
+typedef struct __BHNFULLSCREEN
+{
+ NMHDR hdr;
+ BOOL fEnable;
+} BHNFULLSCREEN;
+#define NBHN_FULLSCREEN (NBHN_FIRST + 17)
+
+
+#define NBHN_CLOSEPOPUP (NBHN_FIRST + 18) // param = NMHDR
+
+
+
+
+#endif // NULLSOFT_WINAMP_OMBROWSER_BROWSERHOST_HEADER
diff --git a/Src/omBrowser/browserInternal.cpp b/Src/omBrowser/browserInternal.cpp
new file mode 100644
index 00000000..f40f37e4
--- /dev/null
+++ b/Src/omBrowser/browserInternal.cpp
@@ -0,0 +1,45 @@
+#include "main.h"
+#include "./browserInternal.h"
+#include "./resource.h"
+#include <exdisp.h>
+#include <strsafe.h>
+
+#if (_MSC_VER < 1500)
+// {D81F90A3-8156-44F7-AD28-5ABB87003274}
+EXTERN_C const IID IID_IProtectFocus =
+{ 0xd81f90a3, 0x8156, 0x44f7, { 0xad, 0x28, 0x5a, 0xbb, 0x87, 0x00, 0x32, 0x74 } };
+#endif
+
+HRESULT FormatEncryptionString(UINT encryptionId, LPWSTR pszBuffer, INT cchBufferMax)
+{
+ HRESULT hr = S_OK;
+ if (secureLockIconUnsecure == encryptionId)
+ {
+ Plugin_LoadString(IDS_CONNECTION_UNSECURE, pszBuffer, cchBufferMax);
+ return S_OK;
+ }
+
+ Plugin_LoadString(IDS_CONNECTION_ENCRYPTED, pszBuffer, cchBufferMax);
+
+ INT resId = 0;
+ switch(encryptionId)
+ {
+ case secureLockIconMixed: resId = IDS_ENCRYPTION_MIXED; break;
+ case secureLockIconSecure40Bit: resId = IDS_ENCRYPTION_40BIT; break;
+ case secureLockIconSecure56Bit: resId = IDS_ENCRYPTION_56BIT; break;
+ case secureLockIconSecureFortezza: resId = IDS_ENCRYPTION_FORTEZZA; break;
+ case secureLockIconSecure128Bit: resId = IDS_ENCRYPTION_128BIT; break;
+ }
+
+ if (0 != resId)
+ {
+ WCHAR szEncryption[96] = {0};
+ Plugin_LoadString(resId, szEncryption, ARRAYSIZE(szEncryption));
+ if (L'\0' != szEncryption[0])
+ {
+ INT cchLen = lstrlen(pszBuffer);
+ hr = StringCchPrintf(pszBuffer + cchLen, cchBufferMax - cchLen, L": %s", szEncryption);
+ }
+ }
+ return hr;
+} \ No newline at end of file
diff --git a/Src/omBrowser/browserInternal.h b/Src/omBrowser/browserInternal.h
new file mode 100644
index 00000000..e49b9c23
--- /dev/null
+++ b/Src/omBrowser/browserInternal.h
@@ -0,0 +1,34 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_INTERNAL_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_INTERNAL_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+#ifndef __IProtectFocus_INTERFACE_DEFINED__
+#define __IProtectFocus_INTERFACE_DEFINED__
+
+/* interface IProtectFocus */
+/* [unique][uuid][object] */
+
+EXTERN_C const IID IID_IProtectFocus;
+
+MIDL_INTERFACE("d81f90a3-8156-44f7-ad28-5abb87003274")
+IProtectFocus : public IUnknown
+{
+public:
+ virtual HRESULT STDMETHODCALLTYPE AllowFocusChange(/* [out] */ BOOL *pfAllow) = 0;
+
+};
+
+#endif /* __IProtectFocus_INTERFACE_DEFINED__ */
+
+#define SID_SProtectFocus IID_IProtectFocus
+
+typedef void (CALLBACK *DISPATCHAPC)(IDispatch *pDisp, ULONG_PTR /*param*/);
+
+HRESULT FormatEncryptionString(UINT encryptionId, LPWSTR pszBuffer, INT cchBufferMax);
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_INTERNAL_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/browserObject.cpp b/Src/omBrowser/browserObject.cpp
new file mode 100644
index 00000000..36b6f136
--- /dev/null
+++ b/Src/omBrowser/browserObject.cpp
@@ -0,0 +1,503 @@
+#include "main.h"
+#include "./browserObject.h"
+#include "./ifc_menucustomizer.h"
+#include "./ifc_wasabihelper.h"
+#include "./ifc_omconfig.h"
+#include "./browserView.h"
+#include "./browserPopup.h"
+#include "./options.h"
+#include "./ifc_ombrowserconfig.h"
+#include "./ifc_ombrowserregistry.h"
+#include "./ifc_ombrowserevent.h"
+#include "./ifc_omtoolbarconfig.h"
+#include "./ifc_omstatusbarconfig.h"
+#include "./ifc_ombrowserclass.h"
+#include "./ifc_omservice.h"
+#include "./ieversion.h"
+#include "./browserWndEnum.h"
+#include "./browserWndRecord.h"
+#include <strsafe.h>
+
+OmBrowserObject::OmBrowserObject() : ref(1), flags(0), browserClass(NULL)
+{
+ InitializeCriticalSection(&lock);
+}
+
+OmBrowserObject::~OmBrowserObject()
+{
+ if (NULL != browserClass)
+ browserClass->Release();
+
+ DeleteCriticalSection(&lock);
+}
+
+HRESULT OmBrowserObject::CreateInstance(OmBrowserObject **instance)
+{
+ if (NULL == instance) return E_POINTER;
+
+ *instance = new OmBrowserObject();
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t OmBrowserObject::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t OmBrowserObject::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int OmBrowserObject::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, OBJ_OmBrowser))
+ *object = static_cast<obj_ombrowser*>(this);
+ else if (IsEqualIID(interface_guid, IFC_OmBrowserWindowManager))
+ *object = static_cast<ifc_ombrowserwndmngr*>(this);
+ else if (IsEqualIID(interface_guid, IFC_OmBrowserEventManager))
+ *object = static_cast<ifc_ombrowsereventmngr*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT OmBrowserObject::Initialize(LPCWSTR pszName, HWND hwndWinamp)
+{
+ if ( browserClass != NULL )
+ return S_FALSE;
+
+ HRESULT hr = Plugin_Initialize(hwndWinamp);
+ if (SUCCEEDED(hr))
+ {
+ if (NULL == pszName || L'\0' == *pszName)
+ pszName = OMBROWSER_NAME;
+
+ hr = Plugin_GetBrowserClass(pszName, &browserClass);
+ }
+ return hr;
+}
+
+HRESULT OmBrowserObject::Finish(void)
+{
+ HRESULT hr = S_OK;
+
+ EnterCriticalSection(&lock);
+
+ flags |= flagFinishing;
+
+ size_t index = windowList.size();
+ while(index--)
+ {
+ OmBrowserWndRecord *r = windowList[index];
+ if (FALSE == DestroyWindow(r->GetHwnd()))
+ {
+ hr = E_FAIL;
+ }
+ else
+ {
+ windowList.erase(windowList.begin() + index);
+ r->Release();
+ }
+ }
+
+ while(!eventList.empty())
+ {
+ ifc_ombrowserevent *e = eventList.back();
+ if (NULL == e) break;
+ eventList.pop_back();
+ e->Release();
+ }
+
+ if (NULL != browserClass)
+ {
+ browserClass->Release();
+ browserClass = NULL;
+ }
+
+ LeaveCriticalSection(&lock);
+ return hr;
+}
+
+HRESULT OmBrowserObject::RegisterWinampHook(ifc_winamphook *hook, UINT *cookieOut)
+{
+ return Plugin_RegisterWinampHook(hook, cookieOut);
+}
+
+HRESULT OmBrowserObject::UnregisterWinampHook(UINT cookie)
+{
+ return Plugin_UnregisterWinampHook(cookie);
+}
+
+HRESULT OmBrowserObject::GetConfig(const GUID *configIfc, void **configOut)
+{
+ if (NULL == configOut) return E_POINTER;
+ if (NULL == browserClass) return E_UNEXPECTED;
+
+ ifc_omconfig *config = NULL;
+ HRESULT hr = browserClass->GetConfig(&config);
+
+ if (SUCCEEDED(hr) && config != NULL)
+ {
+ if (NULL == configIfc || IsEqualIID(*configIfc, GUID_NULL))
+ *configOut = config;
+ else
+ {
+ hr = config->QueryInterface(*configIfc, configOut);
+ config->Release();
+ }
+ }
+ return hr;
+}
+
+HRESULT OmBrowserObject::GetSessionId(LPWSTR pszBuffer, INT cchBufferMax)
+{
+ if (NULL == pszBuffer) return E_POINTER;
+ *pszBuffer = L'\0';
+
+ ifc_wasabihelper *wasabi = NULL;
+ HRESULT hr = Plugin_GetWasabiHelper(&wasabi);
+ if (SUCCEEDED(hr) && wasabi != NULL)
+ {
+ api_application *app = NULL;
+ hr = wasabi->GetApplicationApi(&app);
+ if (SUCCEEDED(hr))
+ {
+ UUID uid;
+ if (API_APPLICATION_SUCCESS == app->GetSessionID(&uid))
+ {
+ hr = Plugin_FormatUuidString(uid, pszBuffer, cchBufferMax);
+ }
+ else
+ {
+ hr = E_FAIL;
+ }
+ app->Release();
+ }
+ wasabi->Release();
+ }
+
+ if (FAILED(hr))
+ hr = StringCchCopy(pszBuffer, cchBufferMax, L"0123456789ABCDEF");
+
+ return hr;
+}
+
+HRESULT OmBrowserObject::GetClientId(LPWSTR pszBuffer, INT cchBufferMax)
+{
+ if (NULL == pszBuffer) return E_POINTER;
+ *pszBuffer = L'\0';
+
+ ifc_ombrowserconfig *browserConfig;
+ if (FAILED(GetConfig(&IFC_OmBrowserConfig, (void**)&browserConfig)))
+ return E_NOINTERFACE;
+
+ HRESULT hr = browserConfig->GetClientId(pszBuffer, cchBufferMax);
+ if (S_OK != hr)
+ {
+ UUID uid;
+ LPWSTR cursor = NULL;
+ size_t remaining = 0;
+ StringCchCopyEx(pszBuffer, cchBufferMax, L"WA-", &cursor, &remaining, 0);
+
+ if (RPC_S_OK != UuidCreate(&uid) ||
+ FAILED(Plugin_FormatUuidString(uid, cursor, remaining)) ||
+ FAILED(browserConfig->SetClientId(pszBuffer)))
+ {
+ *pszBuffer = L'\0';
+ hr = E_FAIL;
+ }
+ }
+
+ browserConfig->Release();
+ return hr;
+}
+
+HRESULT OmBrowserObject::GetRegistry(ifc_ombrowserregistry **registryOut)
+{
+ if (NULL == registryOut) return E_POINTER;
+ if (NULL == browserClass) return E_UNEXPECTED;
+ return browserClass->GetRegistry(registryOut);
+}
+
+HRESULT OmBrowserObject::CreateView(ifc_omservice *service, HWND hParent, LPCWSTR forceUrl, UINT viewStyle, HWND *hView)
+{
+ if (NULL == hView) return E_POINTER;
+ *hView = NULL;
+
+ if (NULL == hParent) return E_INVALIDARG;
+ *hView = BrowserView_Create(this, service, hParent, forceUrl, viewStyle);
+ if (NULL == *hView) return E_FAIL;
+
+ BrowserView_UpdateSkin(*hView, FALSE);
+ return S_OK;
+}
+
+HRESULT OmBrowserObject::CreatePopup(ifc_omservice *service, INT x, INT y, INT cx, INT cy, HWND hOwner, LPCWSTR forceUrl, UINT viewStyle, HWND *hWindow)
+{
+ if (NULL == hWindow) return E_POINTER;
+ *hWindow = NULL;
+
+ if (NULL == hOwner && FAILED(Plugin_GetWinampWnd(&hOwner)))
+ return E_INVALIDARG;
+
+ HWND hPopup = BrowserPopup_Create(this, service, viewStyle, x, y, cx, cy, hOwner, NULL, 0L);
+ if (NULL == hPopup) return E_FAIL;
+
+ *hWindow = hPopup;
+
+ BrowserPopup_UpdateSkin(hPopup, FALSE);
+ if (NULL != forceUrl)
+ {
+ BrowserPopup_Navigate(hPopup, forceUrl, 0L);
+ }
+ else
+ {
+ BrowserPopup_Navigate(hPopup, NAVIGATE_HOME, 0L);
+ }
+ return S_OK;
+}
+
+HRESULT OmBrowserObject::IsFinishing(void)
+{
+ return (0 != (flagFinishing & flags)) ? S_OK : S_FALSE;
+}
+
+HRESULT OmBrowserObject::GetClass(ifc_ombrowserclass **instance)
+{
+ if (NULL == instance)
+ return E_POINTER;
+
+ *instance = browserClass;
+ if (NULL == *instance) return E_UNEXPECTED;
+ browserClass->AddRef();
+
+ return S_OK;
+}
+
+HRESULT OmBrowserObject::GetVersion(int *major, int *minor)
+{
+ if (NULL != major) *major = OMBROWSER_VERSION_MAJOR;
+ if (NULL != minor) *minor = OMBROWSER_VERSION_MINOR;
+ return S_OK;
+}
+
+HRESULT OmBrowserObject::GetIEVersion(int *major, int *minor, int *build, int *subbuild)
+{
+ return MSIE_GetVersion(major, minor, build, subbuild);
+}
+
+HRESULT OmBrowserObject::ShowOptions(HWND hOwner, UINT style, BROWSEROPTIONSCALLBACK callback, ULONG_PTR user)
+{
+ return BrowserOptions_ShowDialog(this, hOwner, style, callback, user);
+}
+
+HRESULT OmBrowserObject::RegisterWindow(HWND hwnd, const GUID *windowType)
+{
+ if (NULL == hwnd) return E_INVALIDARG;
+
+ if (S_FALSE != IsFinishing())
+ return E_UNEXPECTED;
+
+ EnterCriticalSection(&lock);
+
+ size_t index = windowList.size();
+ while(index--)
+ {
+ if (windowList[index]->GetHwnd() == hwnd)
+ {
+ LeaveCriticalSection(&lock);
+ return S_FALSE;
+ }
+ }
+
+ OmBrowserWndRecord *r = NULL;
+ HRESULT hr = OmBrowserWndRecord::CreateInstance(hwnd, windowType, &r);
+ if (SUCCEEDED(hr) && r != NULL)
+ {
+ windowList.push_back(r);
+ }
+
+ LeaveCriticalSection(&lock);
+
+ return hr;
+}
+
+HRESULT OmBrowserObject::UnregisterWindow(HWND hwnd)
+{
+ if (NULL == hwnd) return E_INVALIDARG;
+
+ if (S_FALSE != IsFinishing())
+ return E_PENDING;
+
+ EnterCriticalSection(&lock);
+ size_t index = windowList.size();
+ while(index--)
+ {
+ OmBrowserWndRecord *r = windowList[index];
+
+ if (r->GetHwnd() == hwnd)
+ {
+ windowList.erase(windowList.begin() + index);
+ r->Release();
+
+ LeaveCriticalSection(&lock);
+ return S_OK;
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+ return S_FALSE;
+}
+
+HRESULT OmBrowserObject::Enumerate(const GUID *windowType, UINT *serviceIdFilter, ifc_ombrowserwndenum **enumerator)
+{
+ EnterCriticalSection(&lock);
+
+ HRESULT hr = OmBrowserWndEnumerator::CreateInstance(windowType, serviceIdFilter, windowList.size() ? &windowList.at(0) : nullptr,
+ windowList.size(), (OmBrowserWndEnumerator**)enumerator);
+
+ LeaveCriticalSection(&lock);
+ return hr;
+}
+
+HRESULT OmBrowserObject::RegisterEventHandler(ifc_ombrowserevent *eventHandler)
+{
+ if (NULL == eventHandler)
+ return E_INVALIDARG;
+
+ if (S_FALSE != IsFinishing())
+ return E_PENDING;
+
+ EnterCriticalSection(&lock);
+
+ size_t index = eventList.size();
+ while (index--)
+ {
+ if (eventList[index] == eventHandler)
+ {
+ LeaveCriticalSection(&lock);
+ return E_FAIL;
+ }
+ }
+
+ eventList.push_back(eventHandler);
+ eventHandler->AddRef();
+
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+HRESULT OmBrowserObject::UnregisterEventHandler(ifc_ombrowserevent *eventHandler)
+{
+ if (NULL == eventHandler)
+ return E_INVALIDARG;
+
+ if (S_FALSE != IsFinishing())
+ return E_PENDING;
+
+ EnterCriticalSection(&lock);
+
+ size_t index = eventList.size();
+ while (index--)
+ {
+ if (eventList[index] == eventHandler)
+ {
+ eventList.erase(eventList.begin() + index);
+ eventHandler->Release();
+ LeaveCriticalSection(&lock);
+ return S_OK;
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+ return S_FALSE;
+}
+
+HRESULT OmBrowserObject::Signal_WindowCreate(HWND hwnd, const GUID *windowType)
+{
+ EnterCriticalSection(&lock);
+
+ size_t index = eventList.size();
+ while (index--)
+ {
+ eventList[index]->WindowCreate(hwnd, windowType);
+ }
+
+ LeaveCriticalSection(&lock);
+ return S_OK;
+}
+
+HRESULT OmBrowserObject::Signal_WindowClose(HWND hwnd, const GUID *windowType)
+{
+ EnterCriticalSection(&lock);
+
+ size_t index = eventList.size();
+ while (index--)
+ {
+ eventList[index]->WindowClose(hwnd, windowType);
+ }
+
+ LeaveCriticalSection(&lock);
+ return S_OK;
+}
+
+#define CBCLASS OmBrowserObject
+START_MULTIPATCH;
+ START_PATCH(MPIID_OMBROWSER)
+ M_CB(MPIID_OMBROWSER, obj_ombrowser, ADDREF, AddRef);
+ M_CB(MPIID_OMBROWSER, obj_ombrowser, RELEASE, Release);
+ M_CB(MPIID_OMBROWSER, obj_ombrowser, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMBROWSER, obj_ombrowser, API_INITIALIZE, Initialize);
+ M_CB(MPIID_OMBROWSER, obj_ombrowser, API_FINISH, Finish);
+ M_CB(MPIID_OMBROWSER, obj_ombrowser, API_REGISTERWINAMPHOOK, RegisterWinampHook);
+ M_CB(MPIID_OMBROWSER, obj_ombrowser, API_UNREGISTERWINAMPHOOK, UnregisterWinampHook);
+ M_CB(MPIID_OMBROWSER, obj_ombrowser, API_GETCONFIG, GetConfig);
+ M_CB(MPIID_OMBROWSER, obj_ombrowser, API_GETSESSIONID, GetSessionId);
+ M_CB(MPIID_OMBROWSER, obj_ombrowser, API_GETCLIENTID, GetClientId);
+ M_CB(MPIID_OMBROWSER, obj_ombrowser, API_GETREGISTRY, GetRegistry);
+ M_CB(MPIID_OMBROWSER, obj_ombrowser, API_CREATEVIEW, CreateView);
+ M_CB(MPIID_OMBROWSER, obj_ombrowser, API_CREATEPOPUP, CreatePopup);
+ M_CB(MPIID_OMBROWSER, obj_ombrowser, API_ISFINISHING, IsFinishing);
+ M_CB(MPIID_OMBROWSER, obj_ombrowser, API_GETCLASS, GetClass);
+ M_CB(MPIID_OMBROWSER, obj_ombrowser, API_GETVERSION, GetVersion);
+ M_CB(MPIID_OMBROWSER, obj_ombrowser, API_GETIEVERSION, GetIEVersion);
+ M_CB(MPIID_OMBROWSER, obj_ombrowser, API_SHOWOPTIONS, ShowOptions);
+ NEXT_PATCH(MPIID_OMBROWSERWNDMNGR)
+ M_CB(MPIID_OMBROWSERWNDMNGR, ifc_ombrowserwndmngr, ADDREF, AddRef);
+ M_CB(MPIID_OMBROWSERWNDMNGR, ifc_ombrowserwndmngr, RELEASE, Release);
+ M_CB(MPIID_OMBROWSERWNDMNGR, ifc_ombrowserwndmngr, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMBROWSERWNDMNGR, ifc_ombrowserwndmngr, API_REGISTERWINDOW, RegisterWindow);
+ M_CB(MPIID_OMBROWSERWNDMNGR, ifc_ombrowserwndmngr, API_UNREGISTERWINDOW, UnregisterWindow);
+ M_CB(MPIID_OMBROWSERWNDMNGR, ifc_ombrowserwndmngr, API_ENUMERATE, Enumerate);
+ NEXT_PATCH(MPIID_OMBROWSEREVENTMNGR)
+ M_CB(MPIID_OMBROWSEREVENTMNGR, ifc_ombrowsereventmngr, ADDREF, AddRef);
+ M_CB(MPIID_OMBROWSEREVENTMNGR, ifc_ombrowsereventmngr, RELEASE, Release);
+ M_CB(MPIID_OMBROWSEREVENTMNGR, ifc_ombrowsereventmngr, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMBROWSEREVENTMNGR, ifc_ombrowsereventmngr, API_REGISTERHANDLER, RegisterEventHandler);
+ M_CB(MPIID_OMBROWSEREVENTMNGR, ifc_ombrowsereventmngr, API_UNREGISTERHANDLER, UnregisterEventHandler);
+ M_CB(MPIID_OMBROWSEREVENTMNGR, ifc_ombrowsereventmngr, API_SIGNAL_WINDOWCREATE, Signal_WindowCreate);
+ M_CB(MPIID_OMBROWSEREVENTMNGR, ifc_ombrowsereventmngr, API_SIGNAL_WINDOWCLOSE, Signal_WindowClose);
+ END_PATCH
+END_MULTIPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/browserObject.h b/Src/omBrowser/browserObject.h
new file mode 100644
index 00000000..ac4d0f56
--- /dev/null
+++ b/Src/omBrowser/browserObject.h
@@ -0,0 +1,95 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_OBJECT_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_OBJECT_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./obj_ombrowser.h"
+#include "./ifc_ombrowserwndmngr.h"
+#include "./ifc_ombrowsereventmngr.h"
+#include <bfc/multipatch.h>
+#include <vector>
+
+#define MPIID_OMBROWSER 10
+#define MPIID_OMBROWSERWNDMNGR 20
+#define MPIID_OMBROWSEREVENTMNGR 30
+
+class OmBrowserWndRecord;
+
+class OmBrowserObject : public MultiPatch<MPIID_OMBROWSER, obj_ombrowser>,
+ public MultiPatch<MPIID_OMBROWSERWNDMNGR, ifc_ombrowserwndmngr>,
+ public MultiPatch<MPIID_OMBROWSEREVENTMNGR, ifc_ombrowsereventmngr>
+{
+public:
+ typedef enum
+ {
+ flagFinishing = 0x0001,
+ } Falgs;
+protected:
+ OmBrowserObject();
+ ~OmBrowserObject();
+
+public:
+ static HRESULT CreateInstance(OmBrowserObject **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* obj_ombrowser */
+ HRESULT Initialize(LPCWSTR pszName, HWND hwndWinamp);
+ HRESULT Finish(void);
+ HRESULT RegisterWinampHook(ifc_winamphook *hook, UINT *cookieOut);
+ HRESULT UnregisterWinampHook(UINT cookie);
+ HRESULT GetConfig(const GUID *configIfc, void **configOut);
+ HRESULT GetSessionId(LPWSTR pszBuffer, INT cchBufferMax);
+ HRESULT GetClientId(LPWSTR pszBuffer, INT cchBufferMax);
+ HRESULT GetRegistry(ifc_ombrowserregistry **registryOut);
+ HRESULT CreateView(ifc_omservice *service, HWND hParent, LPCWSTR forceUrl, UINT viewStyle, HWND *hView);
+ HRESULT CreatePopup(ifc_omservice *service, INT x, INT y, INT cx, INT cy, HWND hOwner, LPCWSTR forceUrl, UINT viewStyle, HWND *hWindow);
+ HRESULT ShowOptions(HWND hOwner, UINT style, BROWSEROPTIONSCALLBACK callback, ULONG_PTR user);
+ HRESULT IsFinishing(void);
+ HRESULT GetClass(ifc_ombrowserclass **instance);
+ HRESULT GetVersion(int *major, int *minor);
+ HRESULT GetIEVersion(int *major, int *minor, int *build, int *subbuild);
+
+ /* ifc_ombrowserwndmngr */
+ HRESULT RegisterWindow(HWND hwnd, const GUID *windowType);
+ HRESULT UnregisterWindow(HWND hwnd);
+ HRESULT Enumerate(const GUID *windowType, UINT *serviceIdFilter, ifc_ombrowserwndenum **enumerator);
+
+ /* ifc_ombrowsereventmngr */
+ HRESULT RegisterEventHandler(ifc_ombrowserevent *eventHandler);
+ HRESULT UnregisterEventHandler(ifc_ombrowserevent *eventHandler);
+ HRESULT Signal_WindowCreate(HWND hwnd, const GUID *windowType);
+ HRESULT Signal_WindowClose(HWND hwnd, const GUID *windowType);
+
+protected:
+ LPCWSTR GetConfigFileInt(void);
+
+protected:
+ typedef struct __WindowRecord
+ {
+ HWND hwnd;
+ GUID type;
+ } WindowRecord;
+
+ typedef std::vector<OmBrowserWndRecord*> WindowList;
+ typedef std::vector<ifc_ombrowserevent*> EventList;
+
+protected:
+ ULONG ref;
+ UINT flags;
+ WindowList windowList;
+ ifc_ombrowserclass *browserClass;
+ EventList eventList;
+ CRITICAL_SECTION lock;
+
+protected:
+ RECVS_MULTIPATCH;
+};
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_OBJECT_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/browserPopup.cpp b/Src/omBrowser/browserPopup.cpp
new file mode 100644
index 00000000..866f537d
--- /dev/null
+++ b/Src/omBrowser/browserPopup.cpp
@@ -0,0 +1,2093 @@
+#include "main.h"
+#include "./browser.h"
+#include "./browserUiInternal.h"
+#include "./browserPopup.h"
+#include "./browserHost.h"
+#include "./browserThread.h"
+#include "./graphics.h"
+#include "./resource.h"
+#include "./toolbar.h"
+#include "./statusbar.h"
+#include "./curtain.h"
+#include "../winamp/skinWindowIPC.h"
+#include "../Plugins/General/gen_ml/colors.h"
+
+#include "./obj_ombrowser.h"
+#include "./ifc_omservice.h"
+#include "./ifc_omserviceeventmngr.h"
+#include "./ifc_omserviceevent.h"
+#include "./ifc_ombrowserwndmngr.h"
+#include "./ifc_ombrowsereventmngr.h"
+
+#include "./ifc_omconfig.h"
+#include "./ifc_omtoolbarconfig.h"
+#include "./ifc_omstatusbarconfig.h"
+
+#include "./ifc_wasabihelper.h"
+#include "./ifc_skinhelper.h"
+#include "./ifc_skinnedbrowser.h"
+
+#include "./browserUiHook.h"
+
+#ifdef _DEBUG
+#pragma warning( push )
+#pragma warning( disable : 4244 )
+#endif
+
+#include <api/wnd/api_window.h>
+
+#ifdef _DEBUG
+#pragma warning( pop )
+#endif
+
+
+#include "../winamp/wa_dlg.h"
+
+#include <exdispid.h>
+#include <strsafe.h>
+
+#define IDC_BROWSER 0x1000
+#define IDC_TOOLBAR 0x1001
+#define IDC_STATUSBAR 0x1002
+
+#define BPT_ACTIVATEFRAME 27
+#define BPT_ACTIVATEFRAME_DELAY 300
+
+#define OSWNDHOST_REQUEST_IDEAL_SIZE (WM_USER + 2048)
+
+typedef struct __BROWSERPOPUPCREATEPARAM
+{
+ obj_ombrowser *browserManager;
+ ifc_omservice *service;
+ WPARAM callbackParam;
+ DISPATCHAPC callback;
+ HWND hOwner;
+} BROWSERPOPUPCREATEPARAM;
+
+
+typedef struct __POPUPRESTORE
+{
+ UINT style;
+ UINT exStyle;
+ RECT rect;
+ UINT embedStyle;
+ UINT embedFlags;
+ GUID embedGuid;
+ HWND hOwner; // NULL - if DlgParent
+} POPUPRESTORE;
+
+#define BPF_LOCKRESIZE 0x00000001
+#define BPF_FORCEDTOPMOST 0x00000002
+#define BPF_MODECHANGELOCK 0x00000004
+
+typedef struct __BROWSERPOPUP
+{
+
+ UINT extendedStyle;
+ UINT flags;
+ obj_ombrowser *browserManager;
+ ifc_omservice *service;
+ LPWSTR storedUrl;
+ BSTR storedData;
+ HWND lastFocus;
+ BrowserUiHook *browserHook;
+ WPARAM callbackParam;
+ DISPATCHAPC callback;
+ COLORREF rgbBack;
+ POPUPRESTORE *restore;
+ HWND hOwner;
+} BROWSERPOPUP;
+
+#define FULLSCREEN_STYLE_FILTER (WS_CAPTION | WS_THICKFRAME | WS_SYSMENU | WS_POPUP)
+#define FULLSCREEN_EXSTYLE_FILTER (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_DLGMODALFRAME | WS_EX_TOOLWINDOW)
+
+
+#define GetPopup(__hwnd) ((BROWSERPOPUP*)(LONG_PTR)(LONGX86)GetWindowLongPtr((__hwnd), 0))
+
+static LRESULT CALLBACK BrowserPopup_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+
+static BOOL BrowserPopup_RegisterClass(HINSTANCE hInstance)
+{
+ WNDCLASS wc;
+ if (GetClassInfo(hInstance, NWC_OMBROWSERPOPUP, &wc)) return TRUE;
+
+ ZeroMemory(&wc, sizeof(WNDCLASS));
+
+ wc.hInstance = hInstance;
+ wc.lpszClassName = NWC_OMBROWSERPOPUP;
+ wc.lpfnWndProc = BrowserPopup_WindowProc;
+ wc.style = CS_DBLCLKS;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = NULL;
+ wc.cbWndExtra = sizeof(BROWSERPOPUP*);
+
+ if (0 == RegisterClassW(&wc))
+ return FALSE;
+
+
+ return TRUE;
+}
+
+
+HWND BrowserPopup_Create(obj_ombrowser *browserManager, ifc_omservice *service, UINT fStyle, INT x, INT y, INT cx, INT cy, HWND hOwner, DISPATCHAPC callback, ULONG_PTR callbackParam)
+{
+ if (FALSE == BrowserPopup_RegisterClass(Plugin_GetInstance()))
+ return NULL;
+
+ Toolbar_RegisterClass(Plugin_GetInstance());
+ Statusbar_RegisterClass(Plugin_GetInstance());
+
+ if (NULL == hOwner && FAILED(Plugin_GetWinampWnd(&hOwner)))
+ hOwner = NULL;
+
+ BROWSERPOPUPCREATEPARAM param;
+ ZeroMemory(&param, sizeof(BROWSERPOPUPCREATEPARAM));
+
+ param.browserManager = browserManager;
+ param.service = service;
+ param.callback = callback;
+ param.callbackParam = callbackParam;
+ param.hOwner = hOwner;
+
+ HWND hPopup = CreateWindowEx(WS_EX_WINDOWEDGE,
+ NWC_OMBROWSERPOPUP, OMBROWSER_NAME,
+ WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | (0x0000FFFFF & fStyle),
+ x, y, cx, cy,
+ hOwner, NULL,
+ Plugin_GetInstance(), &param);
+
+ return hPopup;
+}
+
+
+static HWND BrowserPopup_GetFrame(HWND hwnd)
+{
+ HWND hFrame = hwnd;
+ while (NULL != hFrame &&
+ 0 != (WS_CHILD & GetWindowLongPtr(hFrame, GWL_STYLE)))
+ {
+ hFrame = GetAncestor(hFrame, GA_PARENT);
+ }
+ return hFrame;
+}
+
+static void BrowserPopup_Paint(HWND hwnd, HDC hdc, const RECT *prcPaint, BOOL fErase)
+{
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup) return;
+
+ SetBkColor(hdc, popup->rgbBack);
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, prcPaint, NULL, 0, NULL);
+}
+
+static void BrowserPopup_UpdateTitle(HWND hwnd, LPCWSTR pszTitle)
+{
+ if (NULL == hwnd) return;
+
+ WCHAR szBuffer[256] = {0};
+ LPWSTR cursor = szBuffer;
+ size_t remaining = ARRAYSIZE(szBuffer);
+
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL != popup)
+ {
+ if (NULL != popup->service)
+ {
+ WCHAR szName[128] = {0};
+ if (SUCCEEDED(popup->service->GetName(szName, ARRAYSIZE(szName))) && L'\0' != szName[0])
+ StringCchCopyEx(cursor, remaining, szName, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
+ }
+
+ HWND hFrame = (SENDWAIPC(hwnd, IPC_SKINWINDOW_GETEMBEDNUMS, 0) ? NULL : BrowserPopup_GetFrame(hwnd));
+ if (NULL != pszTitle && hFrame != hwnd) // for now we can't update title in classic skin
+ {
+ if (cursor != szBuffer)
+ StringCchCopyEx(cursor, remaining, L": ", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
+ StringCchCopyEx(cursor, remaining, pszTitle, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
+ }
+ else
+ {
+ /* if (NULL != popup->container)
+ {
+ IWebBrowser2 *pWeb2;
+ if (SUCCEEDED(popup->container->GetIWebBrowser2(&pWeb2)))
+ {
+ BSTR bstrTitle;
+ if (SUCCEEDED(pWeb2->get_LocationName(&bstrTitle)) && NULL != bstrTitle)
+ {
+ StringCchCopyEx(cursor, remaining, bstrTitle, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
+ SysFreeString(bstrTitle);
+ }
+ pWeb2->Release();
+ }
+ }*/
+ }
+ }
+
+ if (cursor == szBuffer)
+ StringCchCopy(szBuffer, ARRAYSIZE(szBuffer), OMBROWSER_NAME);
+
+ SetWindowText(hwnd, szBuffer);
+}
+
+static HWND BrowserPopup_CreateToolbar(HWND hwnd)
+{
+ HWND hToolbar = GetDlgItem(hwnd, IDC_TOOLBAR);
+ if (NULL != hToolbar) return hToolbar;
+
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup) return NULL;
+
+ UINT fStyle = GetWindowStyle(hwnd);
+
+ UINT toolbarStyle = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBS_LOCKUPDATE | TBS_SHOWADDRESS;
+ if (0 == (NBCS_NOTOOLBAR & fStyle))
+ toolbarStyle |= WS_VISIBLE;
+
+ ifc_omtoolbarconfig *toolbarConfig;
+ if (NULL != popup->browserManager && SUCCEEDED(popup->browserManager->GetConfig(&IFC_OmToolbarConfig, (void**)&toolbarConfig)))
+ {
+ if (S_OK == toolbarConfig->GetBottomDockEnabled())
+ toolbarStyle |= TBS_BOTTOMDOCK;
+ if (S_OK == toolbarConfig->GetAutoHideEnabled())
+ toolbarStyle |= TBS_AUTOHIDE;
+ if (S_OK == toolbarConfig->GetTabStopEnabled())
+ toolbarStyle |= TBS_TABSTOP;
+ if (S_OK == toolbarConfig->GetForceAddressbarEnabled())
+ toolbarStyle |= TBS_FORCEADDRESS;
+ if (S_OK == toolbarConfig->GetFancyAddressbarEnabled())
+ toolbarStyle |= TBS_FANCYADDRESS;
+
+ toolbarConfig->Release();
+ }
+
+ HINSTANCE hInstance = (HINSTANCE)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
+
+ hToolbar = CreateWindowEx(WS_EX_NOPARENTNOTIFY,
+ NWC_ONLINEMEDIATOOLBAR, NULL, toolbarStyle,
+ 0, 0, 0, 0, hwnd, (HMENU)IDC_TOOLBAR, hInstance, NULL);
+
+ if (NULL == hToolbar)
+ return NULL;
+
+ UINT populateStyle = TBPF_NORMAL | TBPF_READONLYADDRESS;
+ if (0 != (NBCS_NOSERVICECOMMANDS & fStyle))
+ populateStyle |= TBPF_NOSERVICECOMMANDS;
+
+ Toolbar_AutoPopulate(hToolbar, popup->service, populateStyle);
+
+ toolbarStyle = GetWindowStyle(hToolbar);
+ if (0 != (TBS_LOCKUPDATE & toolbarStyle))
+ Toolbar_LockUpdate(hToolbar, FALSE);
+
+ return hToolbar;
+}
+
+static HWND BrowserPopup_CreateStatusbar(HWND hwnd)
+{
+ HWND hStatusbar = GetDlgItem(hwnd, IDC_STATUSBAR);
+ if (NULL != hStatusbar) return hStatusbar;
+
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup) return NULL;
+
+ UINT fStyle = GetWindowStyle(hwnd);
+
+ UINT statusbarStyle = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_DISABLED;
+ if (0 == (NBCS_NOSTATUSBAR & fStyle))
+ {
+ ifc_omstatusbarconfig *statusbarConfig;
+ if (NULL != popup->browserManager && SUCCEEDED(popup->browserManager->GetConfig(&IFC_OmStatusbarConfig, (void**)&statusbarConfig)))
+ {
+ if (S_OK == statusbarConfig->GetEnabled())
+ statusbarStyle &= ~WS_DISABLED;
+ statusbarConfig->Release();
+ }
+ }
+
+ HINSTANCE hInstance = (HINSTANCE)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
+
+ hStatusbar = CreateWindowEx(WS_EX_NOPARENTNOTIFY,
+ NWC_ONLINEMEDIASTATUSBAR, NULL, statusbarStyle,
+ 0, 0, 0, 0, hwnd, (HMENU)IDC_STATUSBAR, hInstance, NULL);
+
+ return hStatusbar;
+}
+
+static BOOL BrowserPopup_PushRect(HWND hwnd, const RECT *rectIn, BOOL fOnlyIfExist)
+{
+ if (NULL == rectIn) return FALSE;
+
+ RECT *rect = (RECT*)GetProp(hwnd, TEXT("omBrowserPopupRect"));
+ if (FALSE != fOnlyIfExist && NULL == rect)
+ return FALSE;
+
+ if (NULL == rect)
+ {
+ rect = (RECT*)calloc(1, sizeof(RECT));
+ if (NULL == rect || FALSE == SetProp(hwnd, TEXT("omBrowserPopupRect"), rect))
+ {
+ if (NULL != rect) free(rect);
+ return FALSE;
+ }
+ }
+ return CopyRect(rect, rectIn);
+}
+
+static BOOL BrwoserPopup_PushClientRect(HWND hwnd, BOOL fOnlyIfExists)
+{
+ RECT clientRect;
+ if (!GetClientRect(hwnd, &clientRect))
+ return FALSE;
+
+ MapWindowPoints(hwnd, HWND_DESKTOP, (POINT*)&clientRect, 2);
+ return BrowserPopup_PushRect(hwnd, &clientRect, fOnlyIfExists);
+}
+
+static BOOL BrowserPopup_PopRect(HWND hwnd, RECT *rectOut, BOOL fNoRemove)
+{
+ RECT *rect = (RECT*)GetProp(hwnd, TEXT("omBrowserPopupRect"));
+ if (FALSE == fNoRemove)
+ {
+ RemoveProp(hwnd, TEXT("omBrowserPopupRect"));
+ }
+
+ if (NULL == rect)
+ return FALSE;
+
+ if (NULL != rectOut)
+ CopyRect(rectOut, rect);
+
+ if (FALSE == fNoRemove)
+ free(rect);
+
+ return TRUE;
+}
+
+static BOOL BrowserPopup_ClientToFrame(HWND hwnd, RECT *rect)
+{
+ if (NULL == rect) return FALSE;
+ RECT frameRect, clientRect;
+
+ ifc_window *wasabiWnd = (ifc_window*)SENDWAIPC(hwnd, IPC_SKINWINDOW_GETWASABIWND, 0);
+ if (NULL != wasabiWnd)
+ {
+ ifc_window *wasabiParent = wasabiWnd->getDesktopParent();
+ if (NULL == wasabiParent) wasabiParent = wasabiWnd;
+
+ if (!wasabiParent->getWindowRect(&frameRect))
+ return FALSE;
+
+ wasabiWnd->getClientRect(&clientRect);
+ MapWindowPoints(wasabiWnd->gethWnd(), HWND_DESKTOP, (POINT*)&clientRect, 2);
+ }
+ else
+ {
+ HWND hFrame = BrowserPopup_GetFrame(hwnd);
+ if (!GetWindowRect(hFrame, &frameRect) || !GetClientRect(hwnd, &clientRect))
+ return FALSE;
+ MapWindowPoints(hwnd, HWND_DESKTOP, (POINT*)&clientRect, 2);
+ }
+
+ rect->left += (frameRect.left - clientRect.left);
+ rect->top += (frameRect.top - clientRect.top);
+ rect->right += (frameRect.right - clientRect.right);
+ rect->bottom += (frameRect.bottom - clientRect.bottom);
+
+ return TRUE;
+}
+
+static INT CALLBACK BrowserPopup_FFCallback(embedWindowState *windowState, INT eventId, LPARAM param)
+{
+ switch(eventId)
+ {
+ case FFC_CREATEEMBED:
+ if(NULL != windowState && NULL != param)
+ {
+ RECT rect;
+ if (BrowserPopup_PopRect(windowState->me, &rect, FALSE))
+ {
+ BrowserPopup_ClientToFrame(windowState->me, &rect);
+ BrowserPopup_SetFramePos(windowState->me, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
+ SWP_NOACTIVATE | SWP_NOZORDER);
+ }
+ }
+ break;
+ case FFC_DESTROYEMBED:
+ if(NULL != windowState && NULL != param)
+ {
+ ifc_window *window = (ifc_window*)param;
+ if (NULL != window)
+ {
+ RECT clientRect;
+ window->getClientRect(&clientRect);
+ MapWindowPoints(window->gethWnd(), HWND_DESKTOP, (POINT*)&clientRect, 2);
+ BrowserPopup_PushRect(windowState->me, &clientRect, FALSE);
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+
+static BOOL BrowserPopup_SkinWindow(HWND hwnd, const GUID *windowGuid)
+{
+ GUID windowId;
+
+ if (NULL == windowGuid || IsEqualGUID(*windowGuid, GUID_NULL))
+ {
+ static ULONG counter = 0L;
+ windowId = SkinClass_BrowserPopup;
+ windowId.Data1 += counter;
+ counter++;
+ }
+ else
+ CopyMemory(&windowId, windowGuid, sizeof(GUID));
+
+ BrwoserPopup_PushClientRect(hwnd, FALSE);
+
+ ifc_skinhelper *skinHelper;
+ HRESULT hr = Plugin_GetSkinHelper(&skinHelper);
+ if (SUCCEEDED(hr))
+ {
+ hr = skinHelper->SkinWindow(hwnd, &windowId, SWF_NOWINDOWMENU, BrowserPopup_FFCallback);
+ if (SUCCEEDED(hr))
+ {
+ SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
+ }
+
+ skinHelper->Release();
+ }
+
+ return SUCCEEDED(hr);
+}
+
+static BOOL BrowserPopup_SwitchToFullscreen(HWND hwnd)
+{
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup) return FALSE;
+
+ RECT clientRect;
+ GetClientRect(hwnd, &clientRect);
+ MapWindowPoints(hwnd, HWND_DESKTOP, (POINT*)&clientRect, 2);
+
+ HMONITOR hMonitor = MonitorFromRect(&clientRect, MONITOR_DEFAULTTONEAREST);
+ MONITORINFO mi;
+ ZeroMemory(&mi, sizeof(MONITORINFO));
+ mi.cbSize = sizeof(MONITORINFO);
+ if (!GetMonitorInfo(hMonitor, &mi)) return FALSE;
+
+ POPUPRESTORE *restore = popup->restore;
+ if (NULL == restore)
+ {
+ restore = (POPUPRESTORE*)calloc(1, sizeof(POPUPRESTORE));
+ if (NULL == restore) return FALSE;
+ popup->restore = restore;
+ }
+
+ popup->flags |= BPF_MODECHANGELOCK;
+
+ CopyRect(&restore->rect, &clientRect);
+
+ restore->embedStyle = (UINT)SENDWAIPC(hwnd, IPC_SKINWINDOW_GETEXSTYLE, 0);
+ restore->embedFlags = (UINT)SENDWAIPC(hwnd, IPC_SKINWINDOW_GETEMBEDFLAGS, 0);
+ if (FALSE == SENDWAIPC(hwnd, IPC_SKINWINDOW_GETEMBEDFLAGS, &restore->embedGuid))
+ ZeroMemory(&restore->embedGuid, sizeof(GUID));
+
+ HWND hFrame = BrowserPopup_GetFrame(hwnd);
+ BOOL fTopmost = (NULL != hFrame && 0 != (WS_EX_TOPMOST & GetWindowStyleEx(hFrame)));
+
+ SENDWAIPC(hwnd, IPC_SKINWINDOW_UNSKIN, 0);
+
+ restore->hOwner = (HWND)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_HWNDPARENT);
+
+ HWND hWinamp;
+ if (FAILED(Plugin_GetWinampWnd(&hWinamp)))
+ hWinamp = NULL;
+
+ HWND hDlgParent = (HWND)SENDWAIPC(hWinamp, IPC_GETDIALOGBOXPARENT, 0);
+ if (NULL != hDlgParent && restore->hOwner == hDlgParent)
+ restore->hOwner = NULL;
+
+ HWND hDesktop = GetDesktopWindow();
+ SetWindowLongPtr(hwnd, GWLP_HWNDPARENT, (LONGX86)(LONG_PTR)hDesktop);
+
+ DWORD style = GetWindowStyle(hwnd);
+ restore->style = (FULLSCREEN_STYLE_FILTER & style);
+ SetWindowLongPtr(hwnd, GWL_STYLE, style & ~FULLSCREEN_STYLE_FILTER);
+
+ style = GetWindowStyleEx(hwnd);
+ restore->exStyle = (FULLSCREEN_EXSTYLE_FILTER & style);
+ SetWindowLongPtr(hwnd, GWL_EXSTYLE, style & ~FULLSCREEN_EXSTYLE_FILTER);
+
+ if (FALSE == fTopmost)
+ {
+ SetWindowPos(hwnd, HWND_TOPMOST, mi.rcMonitor.left, mi.rcMonitor.top,
+ mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top, SWP_NOACTIVATE | SWP_FRAMECHANGED);
+
+ SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW);
+ }
+ else
+ {
+ SetWindowPos(hwnd, HWND_TOPMOST, mi.rcMonitor.left, mi.rcMonitor.top,
+ mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top, SWP_FRAMECHANGED);
+ }
+
+ popup->flags &= ~BPF_MODECHANGELOCK;
+ return TRUE;
+}
+
+static BOOL BrowserPopup_Restore(HWND hwnd)
+{
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup || NULL == popup->restore) return FALSE;
+
+ POPUPRESTORE *restore = popup->restore;
+ popup->restore = NULL;
+ popup->flags |= BPF_MODECHANGELOCK;
+
+ ShowWindow(hwnd, SW_HIDE);
+
+ if (NULL == restore->hOwner)
+ {
+ HWND hWinamp;
+ if (SUCCEEDED(Plugin_GetWinampWnd(&hWinamp)))
+ {
+ restore->hOwner = (HWND)SENDWAIPC(hWinamp, IPC_GETDIALOGBOXPARENT, 0);
+ }
+ }
+
+ SetWindowLongPtr(hwnd, GWLP_HWNDPARENT, (LONGX86)(LONG_PTR)restore->hOwner);
+
+ DWORD style;
+ style = GetWindowStyleEx(hwnd);
+ SetWindowLongPtr(hwnd, GWL_EXSTYLE, style | restore->exStyle);
+
+ style = GetWindowStyle(hwnd);
+ SetWindowLongPtr(hwnd, GWL_STYLE, style | restore->style);
+
+ BrowserPopup_SkinWindow(hwnd, &restore->embedGuid);
+ SENDWAIPC(hwnd, IPC_SKINWINDOW_SETEXSTYLE, restore->embedStyle);
+ SENDWAIPC(hwnd, IPC_SKINWINDOW_SETEMBEDFLAGS, restore->embedFlags);
+
+ BrowserPopup_PushRect(hwnd, &restore->rect, TRUE);
+ BrowserPopup_ClientToFrame(hwnd, &restore->rect);
+ SetWindowPos(hwnd, NULL, restore->rect.left, restore->rect.top,
+ restore->rect.right - restore->rect.left, restore->rect.bottom - restore->rect.top, SWP_NOACTIVATE | SWP_NOZORDER);
+
+ popup->flags &= ~BPF_MODECHANGELOCK;
+
+ ShowWindow(hwnd, SW_SHOWNA);
+ BrowserPopup_ActivateFrame(hwnd);
+
+ free(restore);
+ return TRUE;
+}
+
+static void BrowserPopup_CloseWindow(HWND hwnd)
+{
+ POINT pt;
+ GetCursorPos(&pt);
+ SendMessage(hwnd, WM_SYSCOMMAND, (WPARAM)SC_CLOSE, MAKELPARAM(pt.x, pt.y));
+}
+
+static BOOL BrowserPopup_SetStatusText(HWND hwnd, LPCWSTR pszText)
+{
+ HWND hStatusbar = GetDlgItem(hwnd, IDC_STATUSBAR);
+ if (NULL == hStatusbar) return FALSE;
+
+ Statusbar_Update(hStatusbar, pszText);
+ return TRUE;
+}
+
+static BOOL BrowserPopup_SetStatusTextRes(HWND hwnd, LPCWSTR pszText)
+{
+ if (NULL != pszText && IS_INTRESOURCE(pszText))
+ {
+ WCHAR szBuffer[512] = {0};
+ pszText = Plugin_LoadString((INT)(INT_PTR)pszText, szBuffer, ARRAYSIZE(szBuffer));
+ }
+ return BrowserPopup_SetStatusText(hwnd, pszText);
+}
+
+static BOOL BrowserPopup_ToggleFullscreen(HWND hwnd)
+{
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup) return FALSE;
+
+ HWND hBrowser = GetDlgItem(hwnd, IDC_BROWSER);
+ if (NULL == hBrowser) return FALSE;
+
+ UINT embedFlags = 0;
+ if (0 == (NBCS_EX_FULLSCREEN & popup->extendedStyle))
+ {
+ UINT windowStyle = GetWindowStyle(hwnd);
+ if (0 != (NBCS_DISABLEFULLSCREEN & windowStyle))
+ return FALSE;
+ embedFlags = (UINT)SENDWAIPC(hwnd, IPC_SKINWINDOW_GETEMBEDFLAGS, 0);
+ }
+ else
+ {
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL != popup && NULL != popup->restore)
+ embedFlags = popup->restore->embedFlags;
+ }
+
+ if (0 != (SWF_NORESIZE & embedFlags))
+ return FALSE;
+
+ return PostMessage(hBrowser, NBHM_TOGGLEFULLSCREEN, 0, 0L);
+}
+
+static void BrowserPopup_RegisterUiHook(HWND hwnd)
+{
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup || NULL != popup->browserHook) return;
+
+ if (FAILED(BrowserUiHook::CreateInstance(hwnd, TRUE, &popup->browserHook)))
+ return;
+
+ popup->browserHook->Register(popup->browserManager, popup->service);
+}
+
+static LRESULT BrowserPopup_OnCreate(HWND hwnd, CREATESTRUCT *pcs)
+{
+ BROWSERPOPUPCREATEPARAM *createParam = (BROWSERPOPUPCREATEPARAM*)pcs->lpCreateParams;
+ BROWSERPOPUP *popup = (BROWSERPOPUP*)calloc(1, sizeof(BROWSERPOPUP));
+
+ if (NULL != popup)
+ {
+ SetLastError(ERROR_SUCCESS);
+ if (!SetWindowLongPtr(hwnd, 0, (LONGX86)(LONG_PTR)popup) && ERROR_SUCCESS != GetLastError())
+ {
+ free(popup);
+ popup = NULL;
+ }
+ }
+
+ if (NULL == popup)
+ {
+ DestroyWindow(hwnd);
+ return -1;
+ }
+
+ if (NULL != createParam)
+ {
+ popup->browserManager = createParam->browserManager;
+ if (NULL != popup->browserManager)
+ popup->browserManager->AddRef();
+
+ popup->service = createParam->service;
+ if (NULL != popup->service)
+ popup->service->AddRef();
+
+ popup->callback = createParam->callback;
+ popup->callbackParam = createParam->callbackParam;
+ popup->hOwner = createParam->hOwner;
+ }
+
+ BrowserPopup_RegisterUiHook(hwnd);
+
+ SendMessage(hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_SET, UISF_HIDEACCEL | UISF_HIDEFOCUS), 0L);
+
+ HWND hToolbar = BrowserPopup_CreateToolbar(hwnd);
+ HWND hStatusbar = BrowserPopup_CreateStatusbar(hwnd);
+
+ RECT clientRect;
+ GetClientRect(hwnd, &clientRect);
+
+ UINT hostStyle = NBHS_POPUP;
+ if (0 != (NBCS_DISABLECONTEXTMENU & pcs->style)) hostStyle |= NBHS_DISABLECONTEXTMENU;
+ if (0 != (NBCS_DIALOGMODE & pcs->style)) hostStyle |= NBHS_DIALOGMODE;
+ if (0 != (NBCS_DISABLEHOSTCSS & pcs->style)) hostStyle |= NBHS_DISABLEHOSTCSS;
+
+ HACCEL hAccel = BrowserControl_GetAccelTable(ACCELTABLE_POPUP);
+
+ HWND hHost = BrowserHost_CreateWindow(popup->browserManager, hwnd, hostStyle, clientRect.left, clientRect.top,
+ clientRect.right - clientRect.left, clientRect.bottom - clientRect.top, IDC_BROWSER, hAccel);
+
+ if (NULL == hHost)
+ {
+ DestroyWindow(hwnd);
+ return -1;
+ }
+
+ if (NULL != hToolbar)
+ {
+ Toolbar_SetBrowserHost(hToolbar, hHost);
+ }
+
+ if (NULL != hStatusbar)
+ {
+ Statusbar_SetBrowserHost(hStatusbar, hHost);
+ Statusbar_SetActive(hStatusbar, (0 == (WS_DISABLED & GetWindowLongPtr(hStatusbar, GWL_STYLE))));
+ }
+
+ ifc_wasabihelper *wasabiHelper;
+ if (SUCCEEDED(Plugin_GetWasabiHelper(&wasabiHelper)))
+ {
+ api_application *app;
+ if (SUCCEEDED(wasabiHelper->GetApplicationApi(&app)))
+ {
+ app->app_registerGlobalWindow(hwnd);
+
+ if (NULL != hAccel)
+ app->app_addAccelerators(hwnd, &hAccel, 1, TRANSLATE_MODE_CHILD);
+
+ app->Release();
+ }
+ wasabiHelper->Release();
+ }
+
+ BrowserPopup_UpdateTitle(hwnd, NULL);
+ BrowserPopup_SkinWindow(hwnd, NULL);
+
+ if (NULL != popup->browserManager)
+ {
+ ifc_ombrowserwndmngr *windowManager;
+ if (SUCCEEDED(popup->browserManager->QueryInterface(IFC_OmBrowserWindowManager, (void**)&windowManager)))
+ {
+ windowManager->RegisterWindow(hwnd, &WTID_BrowserPopup);
+ windowManager->Release();
+ }
+
+ ifc_ombrowsereventmngr *eventManager;
+ if (SUCCEEDED(popup->browserManager->QueryInterface(IFC_OmBrowserEventManager, (void**)&eventManager)))
+ {
+ eventManager->Signal_WindowCreate(hwnd, &WTID_BrowserPopup);
+ eventManager->Release();
+ }
+ }
+ return 0;
+}
+
+static void BrowserPopup_OnDestroy(HWND hwnd)
+{
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ SetWindowLongPtr(hwnd, 0, 0L);
+
+ HWND hBrowser = GetDlgItem(hwnd, IDC_BROWSER);
+ if (NULL != hBrowser)
+ {
+ DWORD browserStyle = GetWindowStyle(hBrowser);
+ if (0 != (WS_VISIBLE & browserStyle))
+ SetWindowLongPtr(hBrowser, GWL_STYLE, browserStyle & ~WS_VISIBLE);
+
+ HWND hWinamp = NULL;
+ if (Plugin_GetWinampWnd(&hWinamp))
+ hWinamp = NULL;
+
+ SetWindowLongPtr(hBrowser, GWLP_HWNDPARENT, (LONGX86)(LONG_PTR)hWinamp);
+
+ if (NULL == popup || NULL == popup->browserManager ||
+ S_OK == popup->browserManager->IsFinishing() ||
+ 0 == PostMessage(hBrowser, NBHM_DESTROY, 0, 0L))
+ {
+ DWORD_PTR result;
+ SendMessageTimeout(hBrowser, NBHM_DESTROY, TRUE, 0L, SMTO_NOTIMEOUTIFNOTHUNG | SMTO_BLOCK, 500, &result);
+
+ }
+ }
+
+ BrowserPopup_PopRect(hwnd, NULL, FALSE);
+
+ if (NULL != popup)
+ {
+ popup->extendedStyle &= ~(NBCS_EX_BROWSERREADY | NBCS_EX_NAVCOMPLETED);
+ popup->extendedStyle |= NBCS_EX_BLOCKNAVIGATION;
+
+ if (NULL != popup->browserHook)
+ {
+ popup->browserHook->Unregister(popup->browserManager, popup->service);
+ popup->browserHook->Release();
+ }
+
+ if (NULL != popup->service)
+ {
+ popup->service->Release();
+ popup->service = NULL;
+ }
+
+ if (NULL != popup->restore)
+ {
+ free(popup->restore);
+ }
+
+ Plugin_FreeResString(popup->storedUrl);
+ popup->storedUrl = NULL;
+
+ SysFreeString(popup->storedData);
+ popup->storedData = NULL;
+
+ if (NULL != popup->browserManager)
+ {
+ ifc_ombrowserwndmngr *windowManager;
+ if (SUCCEEDED(popup->browserManager->QueryInterface(IFC_OmBrowserWindowManager, (void**)&windowManager)))
+ {
+ windowManager->UnregisterWindow(hwnd);
+ windowManager->Release();
+ }
+
+ ifc_ombrowsereventmngr *eventManager = NULL;
+ if (SUCCEEDED(popup->browserManager->QueryInterface(IFC_OmBrowserEventManager, (void**)&eventManager)))
+ {
+ eventManager->Signal_WindowClose(hwnd, &WTID_BrowserPopup);
+ eventManager->Release();
+ }
+
+ popup->browserManager->Release();
+ popup->browserManager = NULL;
+ }
+
+ free(popup);
+ }
+
+ ifc_wasabihelper *wasabiHelper = NULL;
+ if (SUCCEEDED(Plugin_GetWasabiHelper(&wasabiHelper)))
+ {
+ api_application *app;
+ if (SUCCEEDED(wasabiHelper->GetApplicationApi(&app)))
+ {
+ app->app_unregisterGlobalWindow(hwnd);
+ app->app_removeAccelerators(hwnd);
+ app->Release();
+ }
+ wasabiHelper->Release();
+ }
+}
+
+static void BrowserPopup_OnPaint(HWND hwnd)
+{
+ PAINTSTRUCT ps;
+ if (BeginPaint(hwnd, &ps))
+ {
+ if (ps.rcPaint.left != ps.rcPaint.right)
+ BrowserPopup_Paint(hwnd, ps.hdc, &ps.rcPaint, ps.fErase);
+ EndPaint(hwnd, &ps);
+ }
+}
+
+static void BrowserPopup_OnPrintClient(HWND hwnd, HDC hdc, UINT options)
+{
+ RECT clientRect;
+ if (GetClientRect(hwnd, &clientRect))
+ BrowserPopup_Paint(hwnd, hdc, &clientRect, 0 != (PRF_ERASEBKGND & options));
+}
+
+static void BrowserPopup_OnWindowPosChanging(HWND hwnd, WINDOWPOS *pwp)
+{
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL != popup && 0 != (BPF_LOCKRESIZE & popup->flags))
+ {
+ HWND hWinamp = NULL;
+ if (FAILED(Plugin_GetWinampWnd(&hWinamp)))
+ hWinamp = NULL;
+
+ if (NULL != hWinamp && hWinamp == (HWND)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_HWNDPARENT))
+ {
+ RECT rect;
+ if (BrowserPopup_PopRect(hwnd, &rect, TRUE))
+ {
+ BrowserPopup_ClientToFrame(hwnd, &rect);
+ pwp->x = rect.left;
+ pwp->y = rect.top;
+ pwp->cx = rect.right - rect.left;
+ pwp->cy = rect.bottom - rect.top;
+ }
+ }
+ }
+}
+
+static void BrowserPopup_OnWindowPosChanged(HWND hwnd, WINDOWPOS *pwp)
+{
+ if (SWP_NOSIZE == ((SWP_NOSIZE | SWP_FRAMECHANGED) & pwp->flags))
+ return;
+
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL != popup)
+ {
+ BrowserControl_UpdateLayout(hwnd, 0 == (SWP_NOREDRAW & pwp->flags),
+ 0 != (SWP_FRAMECHANGED & pwp->flags), NULL, NULL);
+ }
+}
+
+static void BrowserPopup_OnCommand(HWND hwnd, INT commandId, INT eventId, HWND hControl)
+{
+ switch(commandId)
+ {
+ case IDC_TOOLBAR: BrowserControl_ProcessToolbarCommand(hwnd, eventId); break;
+ case IDC_STATUSBAR: BrowserControl_ProcessStatusbarCommand(hwnd, eventId); break;
+ default:
+ if (FALSE == BrowserControl_ProcessCommonCommand(hwnd, commandId))
+ {
+ switch(commandId)
+ {
+ case ID_WINDOW_CLOSE: BrowserPopup_CloseWindow(hwnd); break;
+ case ID_WINDOW_FULLSCREEN: BrowserPopup_ToggleFullscreen(hwnd); break;
+ }
+ }
+ break;
+ }
+}
+
+static LRESULT BrowserPopup_OnAppCommand(HWND hwnd, HWND hTarget, INT commandId, INT deviceId, INT keys)
+{
+ return BrowserControl_ProcessAppCommand(hwnd, commandId);
+}
+
+static void BrowserPopup_OnBrowserReady(HWND hwnd)
+{
+ ReplyMessage(0);
+
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup) return;
+
+ popup->extendedStyle |= NBCS_EX_BROWSERREADY;
+
+ BrowserControl_UpdateLayout(hwnd, FALSE, FALSE, NULL, NULL);
+
+ HWND hToolbar = BrowserControl_GetToolbar(hwnd);
+ if (NULL != hToolbar)
+ Toolbar_EnableItem(hToolbar, TOOLITEM_ADDRESSBAR, TRUE);
+
+ if (NULL != popup->callback)
+ {
+ HWND hBrowser = GetDlgItem(hwnd, IDC_BROWSER);
+ if (NULL == hBrowser ||
+ FALSE == PostMessage(hBrowser, NBHM_GETDISPATCHAPC, (WPARAM)popup->callbackParam, (LPARAM)popup->callback))
+ {
+ // sucks
+ popup->callback(NULL, popup->callbackParam);
+ }
+
+ popup->callback = NULL;
+ return;
+ }
+
+ if (NULL != popup->storedUrl)
+ {
+ LPWSTR pszUrl = popup->storedUrl;
+ popup->storedUrl = NULL;
+ BrowserPopup_Navigate(hwnd, pszUrl, TRUE);
+ Plugin_FreeResString(pszUrl);
+ }
+ else
+ {
+ BrowserPopup_NavigateHome(hwnd, TRUE);
+ }
+}
+
+
+
+static void CALLBACK BrowserPopup_ActivateTimer(HWND hwnd, UINT uMsg, UINT_PTR eventId, DWORD time)
+{
+ KillTimer(hwnd, eventId);
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup) return;
+
+ HWND hFrame = BrowserPopup_GetFrame(hwnd);
+ if (NULL != hFrame)
+ {
+ DWORD frameStyle = GetWindowStyleEx(hFrame);
+
+ if (0 != (WS_EX_TOPMOST & frameStyle) && 0 != (BPF_FORCEDTOPMOST & popup->flags))
+ {
+ popup->flags &= ~BPF_FORCEDTOPMOST;
+ SetWindowPos(hFrame, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE| SWP_NOMOVE | SWP_NOOWNERZORDER);
+ }
+
+ SetWindowPos(hFrame, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE| SWP_NOMOVE | SWP_NOOWNERZORDER);
+ }
+
+ PostMessage(hwnd, NBPM_ACTIVATEFRAME, 0, 0L);
+
+ HWND hBrowser = GetDlgItem(hwnd, IDC_BROWSER);
+ if (NULL != hBrowser)
+ PostMessage(hBrowser, NBHM_ACTIVATE, 0, 0L);
+}
+
+static void BrowserPopup_OnNavigateComplete(HWND hwnd, IDispatch *pDispath, VARIANT *URL, BOOL fTopFrame)
+{
+ if (FALSE == fTopFrame)
+ return;
+
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup) return;
+
+ popup->extendedStyle |= NBCS_EX_NAVIGATEDONCE;
+
+ LPWSTR pszUrl = NULL;
+ if (NULL != URL && VT_BSTR == URL->vt && NULL != URL->bstrVal)
+ pszUrl = Plugin_CopyString(URL->bstrVal);
+
+ ReplyMessage(0);
+
+ if (NULL != pszUrl)
+ {
+ HWND hToolbar = GetDlgItem(hwnd, IDC_TOOLBAR);
+ if (NULL != hToolbar)
+ {
+ INT itemId = Toolbar_FindItem(hToolbar, TOOLITEM_ADDRESSBAR);
+ if (ITEM_ERR != itemId)
+ Toolbar_SetItemString(hToolbar, MAKEINTRESOURCE(itemId), pszUrl);
+ }
+ Plugin_FreeString(pszUrl);
+ }
+}
+
+static void BrowserPopup_OnDocumentReady(HWND hwnd, IDispatch *pDispath, VARIANT *URL, BOOL fTopFrame)
+{
+ ReplyMessage(0);
+
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup) return;
+
+ if (0 == (NBCS_EX_NAVCOMPLETED & popup->extendedStyle))
+ {
+ popup->extendedStyle |= NBCS_EX_NAVCOMPLETED;
+
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL != popup && NULL != popup->storedData)
+ {
+ BrowserPopup_WriteDocument(hwnd, popup->storedData, FALSE);
+ }
+
+ if(0 == (NBCS_EX_SCRIPTMODE & popup->extendedStyle))
+ {
+ HWND hHost = GetDlgItem(hwnd, IDC_BROWSER);
+ if (NULL != hHost &&
+ 0 == (WS_VISIBLE & GetWindowLongPtr(hHost, GWL_STYLE)))
+ {
+ ShowWindowAsync(hHost, SW_SHOWNA);
+ }
+ }
+
+ }
+
+
+}
+
+static void BrowserPopup_OnBrowserActive(HWND hwnd, BOOL fActive)
+{
+ ReplyMessage(0);
+
+ HWND hToolbar = GetDlgItem(hwnd, IDC_TOOLBAR);
+ if (NULL != hToolbar)
+ {
+ Toolbar_EnableItem(hToolbar, TOOLITEM_DOWNLOADPROGRESS, fActive);
+ }
+
+ HWND hStatusbar = GetDlgItem(hwnd, IDC_STATUSBAR);
+ if (NULL != hStatusbar)
+ {
+ if (FALSE != fActive && (0 != (WS_DISABLED & GetWindowLongPtr(hStatusbar, GWL_STYLE))))
+ fActive = FALSE;
+ Statusbar_SetActive(hStatusbar, fActive);
+ }
+}
+
+static void BrowserPopup_OnCommandStateChange(HWND hwnd, UINT commandId, BOOL fEnable)
+{
+ ReplyMessage(0);
+
+ HWND hToolbar = GetDlgItem(hwnd, IDC_TOOLBAR);
+ if (NULL != hToolbar)
+ {
+ switch(commandId)
+ {
+ case Browser::commandBack:
+ Toolbar_EnableItem(hToolbar, TOOLITEM_BUTTON_BACK, fEnable);
+ Toolbar_EnableItem(hToolbar, TOOLITEM_BUTTON_HISTORY, (FALSE != fEnable) ?
+ TRUE :
+ (0 == Toolbar_GetItemStyle(hToolbar, TOOLITEM_BUTTON_FORWARD, TBIS_DISABLED)));
+ break;
+
+ case Browser::commandForward:
+ Toolbar_EnableItem(hToolbar, TOOLITEM_BUTTON_FORWARD, fEnable);
+ Toolbar_EnableItem(hToolbar, TOOLITEM_BUTTON_HISTORY, (FALSE != fEnable) ?
+ TRUE :
+ (0 == Toolbar_GetItemStyle(hToolbar, TOOLITEM_BUTTON_BACK, TBIS_DISABLED)));
+ break;
+ case Browser::commandStop: Toolbar_EnableItem(hToolbar, TOOLITEM_BUTTON_STOP, fEnable); break;
+ case Browser::commandRefresh:
+ Toolbar_EnableItem(hToolbar, TOOLITEM_BUTTON_REFRESH, fEnable);
+ Toolbar_EnableItem(hToolbar, TOOLITEM_BUTTON_HOME, fEnable);
+ break;
+ }
+ }
+
+}
+
+static void BrowserPopup_OnStatusChange(HWND hwnd, LPCWSTR pszText)
+{
+ HWND hStatusbar = GetDlgItem(hwnd, IDC_STATUSBAR);
+ if (NULL == hStatusbar) return;
+
+ WCHAR szBuffer[512] = {0};
+ if (NULL == pszText || L'\0' == *pszText) szBuffer[0] = L'\0';
+ else StringCchCopy(szBuffer, ARRAYSIZE(szBuffer), pszText);
+
+ ReplyMessage(0);
+
+ Statusbar_Update(hStatusbar, szBuffer);
+}
+
+static void BrowserPopup_OnTitleChange(HWND hwnd, LPCWSTR pszText)
+{
+ WCHAR szBuffer[256] = {0};
+ if (NULL == pszText || L'\0' == *pszText) szBuffer[0] = L'\0';
+ else StringCchCopy(szBuffer, ARRAYSIZE(szBuffer), pszText);
+
+ ReplyMessage(0);
+
+ BrowserPopup_UpdateTitle(hwnd, szBuffer);
+
+ HWND hToolbar = GetDlgItem(hwnd, IDC_TOOLBAR);
+ if (NULL != hToolbar)
+ {
+ INT itemId = Toolbar_FindItem(hToolbar, TOOLITEM_ADDRESSBAR);
+ if (ITEM_ERR != itemId)
+ Toolbar_SetItemDescription(hToolbar, MAKEINTRESOURCE(itemId), szBuffer);
+ }
+}
+
+static void BrowserPopup_OnSecureIconChange(HWND hwnd, UINT iconId)
+{
+ ReplyMessage(0);
+
+ HWND hToolbar = GetDlgItem(hwnd, IDC_TOOLBAR);
+ if (NULL != hToolbar)
+ {
+ INT itemId = Toolbar_FindItem(hToolbar, TOOLITEM_BUTTON_SECURECONNECTION);
+ if (ITEM_ERR != itemId)
+ {
+ WCHAR szBuffer[256] = {0};
+
+ if(FAILED(FormatEncryptionString(iconId, szBuffer, ARRAYSIZE(szBuffer))))
+ szBuffer[0] = L'\0';
+
+ Toolbar_ShowItem(hToolbar, MAKEINTRESOURCE(itemId), (secureLockIconUnsecure != iconId));
+ Toolbar_SetItemDescription(hToolbar, MAKEINTRESOURCE(itemId), szBuffer);
+ }
+ }
+}
+
+
+
+static LRESULT BrowserPopup_OnCreatePopup(HWND hwnd, DISPATCHAPC callback, ULONG_PTR param)
+{
+ ReplyMessage(TRUE);
+
+ HWND hPopup = NULL;
+
+ UINT windowStyle = GetWindowStyle(hwnd);
+ if (0 == (NBCS_BLOCKPOPUP & windowStyle))
+ {
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL != popup)
+ {
+ RECT windowRect;
+ GetWindowRect(hwnd, &windowRect);
+
+ UINT popupStyle = NBCS_NOSERVICECOMMANDS | NBCS_DISABLEHOSTCSS;
+ popupStyle |= (NBCS_POPUPOWNER & GetWindowStyle(hwnd));
+
+ HWND hOwner = NULL;
+ if (0 != (NBCS_POPUPOWNER & popupStyle))
+ hOwner = popup->hOwner;
+
+ hPopup = BrowserPopup_Create(popup->browserManager, popup->service, popupStyle,
+ windowRect.left + 12, windowRect.top + 12, 640, 480, hOwner, callback, param);
+ }
+ }
+
+ if (NULL == hPopup)
+ {
+ if (NULL != callback)
+ callback(NULL, param);
+ return FALSE;
+ }
+
+ BrowserControl_SetExtendedStyle(hPopup, NBCS_EX_SCRIPTMODE, NBCS_EX_SCRIPTMODE);
+ BrowserPopup_UpdateSkin(hPopup, FALSE);
+ return TRUE;
+}
+static void BrowserPopup_OnVisibleChange(HWND hwnd, BOOL fVisible)
+{
+ ReplyMessage(0);
+
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup) return;
+
+ HWND hFrame = BrowserPopup_GetFrame(hwnd);
+ if (NULL == hFrame) hFrame = hwnd;
+
+ if (FALSE != fVisible)
+ {
+ ShowWindow(hFrame, (0 == (WS_VISIBLE & GetWindowLongPtr(hFrame, GWL_STYLE))) ? SW_SHOWNOACTIVATE : SW_SHOW);
+
+ HWND hWinamp;
+ if (FAILED(Plugin_GetWinampWnd(&hWinamp)))
+ hWinamp = NULL;
+
+ HWND hFrame = BrowserPopup_GetFrame(hwnd);
+ HWND hDlgParent = (HWND)SENDWAIPC(hWinamp, IPC_GETDIALOGBOXPARENT, 0);
+ if (NULL != hFrame && NULL != hDlgParent && hFrame != hDlgParent)
+ {
+ DWORD frameStyle = GetWindowStyleEx(hFrame);
+ if (0 == (WS_EX_TOPMOST & frameStyle))
+ {
+ popup->flags |= BPF_FORCEDTOPMOST;
+ SetWindowPos(hFrame, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE| SWP_NOMOVE | SWP_NOOWNERZORDER);
+ }
+ SetWindowPos(hFrame, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE| SWP_NOMOVE | SWP_NOOWNERZORDER);
+ }
+
+ HWND hBrowser = GetDlgItem(hwnd, IDC_BROWSER);
+ if (NULL != hBrowser)
+ {
+ ShowWindowAsync(hBrowser, SW_SHOWNA);
+ }
+
+ SetTimer(hwnd, BPT_ACTIVATEFRAME, BPT_ACTIVATEFRAME_DELAY, BrowserPopup_ActivateTimer);
+ }
+ else
+ {
+ ShowWindow(hFrame, SW_HIDE);
+ }
+}
+
+static void BrowserPopup_OnSetResizable(HWND hwnd, BOOL fEnabled)
+{
+ ReplyMessage(0);
+
+ UINT flags = (UINT)SENDWAIPC(hwnd, IPC_SKINWINDOW_GETEMBEDFLAGS, 0);
+ if ((0 != (SWF_NORESIZE & flags)) != (FALSE == fEnabled))
+ {
+ if (FALSE == fEnabled) flags |= SWF_NORESIZE;
+ else flags &= ~EMBED_FLAGS_NORESIZE;
+ SENDWAIPC(hwnd, IPC_SKINWINDOW_SETEMBEDFLAGS, (WPARAM)flags);
+
+ HWND hFrame = BrowserPopup_GetFrame(hwnd);
+ if (NULL != hFrame)
+ {
+ SetWindowPos(hFrame, NULL, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE| SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
+ }
+ }
+}
+
+static void BrowserPopup_OnBrowserClosing(HWND hwnd, BOOL isChild, BOOL *fCancel)
+{
+ // we telling ie to cancel in order to skip user prompt
+ *fCancel = TRUE;
+ ReplyMessage(0);
+
+ HWND hFrame = BrowserPopup_GetFrame(hwnd);
+ if (NULL != hFrame)
+ {
+ ShowWindow(hFrame, SW_HIDE);
+ DestroyWindow(hFrame);
+ }
+}
+
+static void BrowserPopup_OnShowUiElement(HWND hwnd, UINT elementId, BOOL fShow)
+{
+ ReplyMessage(0);
+
+ HWND hControl;
+ UINT fStyle = GetWindowStyle(hwnd);
+ switch(elementId)
+ {
+ case HTMLContainer2::uiToolbar:
+ hControl = GetDlgItem(hwnd, IDC_TOOLBAR);
+ if (NULL != hControl && 0 == (NBCS_NOTOOLBAR & fStyle))
+ {
+ ShowWindow(hControl, (FALSE != fShow) ? SW_SHOW : SW_HIDE);
+ BrowserControl_UpdateLayout(hwnd, TRUE, FALSE, NULL, NULL);
+ }
+ break;
+
+ case HTMLContainer2::uiStatusbar:
+ hControl = GetDlgItem(hwnd, IDC_STATUSBAR);
+ if (NULL != hControl && 0 == (NBCS_NOSTATUSBAR & fStyle))
+ {
+ EnableWindow(hControl, fShow);
+ BrowserControl_UpdateLayout(hwnd, TRUE, FALSE, NULL, NULL);
+ }
+ break;
+ }
+}
+
+static void BrowserPopup_OnClientToHost(HWND hwnd, LONG *cx, LONG *cy)
+{
+ RECT frameRect, browserRect;
+
+ HWND hFrame = BrowserPopup_GetFrame(hwnd);
+ if (NULL == hFrame || !GetWindowRect(hFrame, &frameRect))
+ return;
+
+ HWND hBrowser = GetDlgItem(hwnd, IDC_BROWSER);
+ if (NULL == hBrowser || !GetClientRect(hBrowser, &browserRect))
+ return;
+
+ *cx += ((frameRect.right - frameRect.left) - (browserRect.right - browserRect.left));
+ *cy += ((frameRect.bottom - frameRect.top) - (browserRect.bottom - browserRect.top));
+}
+
+static void BrowserPopup_OnSetWindowPos(HWND hwnd, UINT flags, LONG x, LONG y, LONG cx, LONG cy)
+{
+ ReplyMessage(0);
+
+ RECT frameRect;
+ HWND hFrame = BrowserPopup_GetFrame(hwnd);
+ if (NULL == hFrame || !GetWindowRect(hFrame, &frameRect)) return;
+
+ UINT swpFlags = SWP_NOACTIVATE | SWP_NOZORDER;
+
+ if (0 == ((HTMLContainer2::wndLeft | HTMLContainer2::wndTop) & flags))
+ {
+ swpFlags |= SWP_NOMOVE;
+ }
+ else
+ {
+ if (0 == (HTMLContainer2::wndLeft & flags)) x = frameRect.left;
+ else if (0 != (HTMLContainer2::wndRelative & flags)) x += frameRect.left;
+
+ if (0 == (HTMLContainer2::wndTop & flags)) y = frameRect.top;
+ else if (0 != (HTMLContainer2::wndRelative & flags)) y += frameRect.top;
+ }
+
+ if (0 == ((HTMLContainer2::wndWidth | HTMLContainer2::wndHeight) & flags))
+ {
+ swpFlags |= SWP_NOSIZE;
+ }
+ else
+ {
+ if (0 == (HTMLContainer2::wndWidth & flags)) cx = (frameRect.right - frameRect.left);
+ else if (0 != (HTMLContainer2::wndRelative & flags)) cx += (frameRect.right - frameRect.left);
+
+ if (0 == (HTMLContainer2::wndHeight & flags)) cy = (frameRect.bottom - frameRect.top);
+ else if (0 != (HTMLContainer2::wndRelative & flags)) cy += (frameRect.bottom - frameRect.top);
+ }
+
+ BrowserPopup_SetFramePos(hwnd, NULL, x, y, cx, cy, swpFlags);
+
+}
+static void BrowserPopup_OnAllowFocusChange(HWND hwnd, BOOL *fAllow)
+{
+ *fAllow = TRUE;
+}
+
+static void BrowserPopup_OnSetFullscreen(HWND hwnd, BOOL fEnable)
+{
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup) return;
+
+
+ if (0 != (NBCS_EX_FULLSCREEN & popup->extendedStyle) == (FALSE != fEnable))
+ return;
+
+ if (FALSE == fEnable)
+ popup->extendedStyle &= ~NBCS_EX_FULLSCREEN;
+ else
+ {
+ UINT windowStyle = GetWindowStyle(hwnd);
+ if (0 != (NBCS_DISABLEFULLSCREEN & windowStyle))
+ return;
+
+ popup->extendedStyle |= NBCS_EX_FULLSCREEN;
+ }
+
+ SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
+}
+
+static void BrowserPopup_OnClosePopup(HWND hwnd)
+{
+ ReplyMessage(0);
+
+ HWND hFrame = BrowserPopup_GetFrame(hwnd);
+ if (NULL != hFrame)
+ {
+ ShowWindow(hFrame, SW_HIDE);
+ DestroyWindow(hFrame);
+ }
+}
+
+static LRESULT BrowserPopup_OnBrowserNotify(HWND hwnd, NMHDR *pnmh)
+{
+ switch(pnmh->code)
+ {
+ case NBHN_READY:
+ BrowserPopup_OnBrowserReady(hwnd);
+ break;
+ case NBHN_NAVIGATECOMPLETE:
+ BrowserPopup_OnNavigateComplete(hwnd, ((BHNNAVCOMPLETE*)pnmh)->pDispatch, ((BHNNAVCOMPLETE*)pnmh)->URL, ((BHNNAVCOMPLETE*)pnmh)->fTopFrame);
+ break;
+ case NBHN_DOCUMENTREADY:
+ BrowserPopup_OnDocumentReady(hwnd, ((BHNNAVCOMPLETE*)pnmh)->pDispatch, ((BHNNAVCOMPLETE*)pnmh)->URL, ((BHNNAVCOMPLETE*)pnmh)->fTopFrame);
+ break;
+ case NBHN_BROWSERACTIVE:
+ BrowserPopup_OnBrowserActive(hwnd, ((BHNACTIVE*)pnmh)->fActive);
+ break;
+ case NBHN_COMMANDSTATECHANGE:
+ BrowserPopup_OnCommandStateChange(hwnd, ((BHNCMDSTATE*)pnmh)->commandId, ((BHNCMDSTATE*)pnmh)->fEnabled);
+ break;
+ case NBHN_STATUSCHANGE:
+ BrowserPopup_OnStatusChange(hwnd, ((BHNTEXTCHANGE*)pnmh)->pszText);
+ break;
+ case NBHN_TITLECHANGE:
+ BrowserPopup_OnTitleChange(hwnd, ((BHNTEXTCHANGE*)pnmh)->pszText);
+ break;
+ case NBHN_SECUREICONCHANGE:
+ BrowserPopup_OnSecureIconChange(hwnd, ((BHNSECUREICON*)pnmh)->iconId);
+ break;
+ case NBHN_GETOMSERVICE:
+ return BrowserPopup_GetService(hwnd, &((BHNSERVICE*)pnmh)->instance);
+ case NBHN_CREATEPOPUP:
+ return BrowserPopup_OnCreatePopup(hwnd, ((BHNCREATEPOPUP*)pnmh)->callback, ((BHNCREATEPOPUP*)pnmh)->param);
+ case NBHN_VISIBLECHANGE:
+ BrowserPopup_OnVisibleChange(hwnd, ((BHNVISIBLE*)pnmh)->fVisible);
+ break;
+ case NBHN_RESIZABLE:
+ BrowserPopup_OnSetResizable(hwnd, ((BHNRESIZABLE*)pnmh)->fEnabled);
+ break;
+ case NBHN_CLOSING:
+ BrowserPopup_OnBrowserClosing(hwnd, ((BHNCLOSING*)pnmh)->isChild, &((BHNCLOSING*)pnmh)->cancel);
+ break;
+ case NBHN_SHOWUI:
+ BrowserPopup_OnShowUiElement(hwnd, ((BHNSHOWUI*)pnmh)->elementId, ((BHNSHOWUI*)pnmh)->fShow);
+ break;
+ case NBHN_CLIENTTOHOST:
+ BrowserPopup_OnClientToHost(hwnd, &((BHNCLIENTTOHOST*)pnmh)->cx, &((BHNCLIENTTOHOST*)pnmh)->cy);
+ break;
+ case NBHN_SETWINDOWPOS:
+ BrowserPopup_OnSetWindowPos(hwnd, ((BHNSETWINDOWPOS*)pnmh)->flags, ((BHNSETWINDOWPOS*)pnmh)->x,
+ ((BHNSETWINDOWPOS*)pnmh)->y, ((BHNSETWINDOWPOS*)pnmh)->cx, ((BHNSETWINDOWPOS*)pnmh)->cy);
+ break;
+ case NBHN_FOCUSCHANGE:
+ BrowserPopup_OnAllowFocusChange(hwnd, &((BHNFOCUSCHANGE*)pnmh)->fAllow);
+ break;
+ case NBHN_FULLSCREEN:
+ BrowserPopup_OnSetFullscreen(hwnd, ((BHNFULLSCREEN*)pnmh)->fEnable);
+ break;
+ case NBHN_CLOSEPOPUP:
+ BrowserPopup_OnClosePopup(hwnd);
+ break;
+
+ }
+ return 0;
+}
+
+static LRESULT BrowserPopup_OnNotify(HWND hwnd, INT controlId, NMHDR *pnmh)
+{
+ switch(controlId)
+ {
+ case IDC_BROWSER:
+ return BrowserPopup_OnBrowserNotify(hwnd, pnmh);
+ }
+
+ return 0;
+}
+
+static void BrowserPopup_OnSetFocus(HWND hwnd, HWND hLost)
+{
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ HWND hChild, hTab;
+ hChild = FindWindowEx(hwnd, NULL, NULL, NULL);
+ hTab = NULL;
+
+ if (NULL != popup)
+ {
+ while(popup->lastFocus && IsChild(hwnd, popup->lastFocus))
+ {
+ if (IsWindowEnabled(popup->lastFocus) && IsWindowVisible(popup->lastFocus) &&
+ 0 != (WS_TABSTOP & GetWindowLongPtrW(popup->lastFocus, GWL_STYLE)))
+ {
+ hTab = popup->lastFocus;
+ break;
+ }
+ popup->lastFocus = GetParent(popup->lastFocus);
+ }
+ }
+
+ if (NULL == hTab)
+ {
+ hTab = (hChild) ? GetNextDlgTabItem(hwnd, hChild, FALSE) : hwnd;
+ }
+
+ if (NULL != hTab && hwnd != hTab &&
+ IsWindowEnabled(hTab) &&
+ IsWindowVisible(hTab))
+ {
+ TCHAR szName[128] = {0};
+ if (NULL != hChild &&
+ GetClassName(hChild, szName, ARRAYSIZE(szName)) &&
+ CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, szName, -1, TEXT("#32770"), -1))
+ {
+ if (IsWindowEnabled(hChild))
+ PostMessage(hChild, WM_NEXTDLGCTL, (WPARAM)hTab, TRUE);
+ else
+ DefWindowProc(hwnd, WM_SETFOCUS, (WPARAM)hLost, 0L);
+ }
+ else
+ {
+ SetFocus(hTab);
+ }
+ return;
+ }
+
+ DefWindowProc(hwnd, WM_SETFOCUS, (WPARAM)hLost, 0L);
+}
+
+static void BrowserPopup_OnActivate(HWND hwnd, UINT uActivate, HWND hwndOther, BOOL bMinimized)
+{
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup) return;
+
+ POINT pt;
+
+ switch(uActivate)
+ {
+ case WA_INACTIVE:
+ popup->lastFocus = GetFocus();
+ if (!IsChild(hwnd, popup->lastFocus))
+ popup->lastFocus = NULL;
+ break;
+
+ case WA_CLICKACTIVE:
+ if (GetCursorPos(&pt))
+ {
+ MapWindowPoints(HWND_DESKTOP, hwnd, &pt, 1);
+ HWND hTarget = ChildWindowFromPointEx(hwnd, pt, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED | CWP_SKIPTRANSPARENT);
+ if (hTarget && hTarget != hwnd && hTarget != GetDlgItem(hwnd, IDC_TOOLBAR))
+ {
+
+ popup->lastFocus = hTarget;
+ }
+ }
+ break;
+ }
+}
+
+static void BrowserPopup_OnStyleChanged(HWND hwnd, UINT nStyleType, STYLESTRUCT *pss)
+{
+ #define ISSTYLECHANGED(__style) ((__style) & pss->styleOld) != ((__style) & pss->styleNew)
+
+ if (GWL_STYLE == nStyleType)
+ {
+ if (ISSTYLECHANGED(WS_CHILD) && 0 != pss->styleNew && 0 != pss->styleOld)
+ {
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL != popup && 0 == (BPF_MODECHANGELOCK & popup->flags))
+ {
+ popup->flags |= BPF_LOCKRESIZE;
+ PostMessage(hwnd, NBPM_PARENTCHANGED, 0, 0L);
+ }
+ }
+ }
+}
+
+static void BrowserPopup_OnGetMinMaxInfo(HWND hwnd, MINMAXINFO *minMax)
+{
+ minMax->ptMinTrackSize.x = 275;
+ minMax->ptMinTrackSize.y = 116;
+}
+
+static LRESULT BrowserPopup_OnNavigate(HWND hwnd, LPCWSTR navigateUrl, BOOL fScheduleBlocked)
+{
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup) return FALSE;
+
+ UINT windowStyle = GetWindowStyle(hwnd);
+
+ if (NULL != popup->browserHook)
+ popup->browserHook->CheckBlockedState(popup->service);
+
+ SysFreeString(popup->storedData);
+ popup->storedData = NULL;
+
+ Plugin_FreeResString(popup->storedUrl);
+ popup->storedUrl = NULL;
+
+ if (NBCS_EX_BROWSERREADY != ((NBCS_EX_BROWSERREADY | NBCS_EX_BLOCKNAVIGATION) & popup->extendedStyle))
+ {
+ if (FALSE == fScheduleBlocked)
+ return FALSE;
+
+ popup->storedUrl = Plugin_DuplicateResString(navigateUrl);
+ return TRUE;
+ }
+
+ HWND hHost = GetDlgItem(hwnd, IDC_BROWSER);
+ if (NULL == hHost) return FALSE;
+
+ LPWSTR pszDescription = NULL;
+ BSTR url = NULL;
+ if (IS_INTRESOURCE(navigateUrl))
+ {
+ switch((INT_PTR)navigateUrl)
+ {
+ case NAVIGATE_BLANK:
+ BrowserPopup_SetStatusText(hwnd, NULL);
+ url = SysAllocString(L"about:blank");
+ break;
+
+ case NAVIGATE_HOME:
+ if (0 == (NBCS_NOSERVICECOMMANDS & windowStyle) && NULL != popup->service)
+ {
+ WCHAR szBuffer[8192] = {0};
+ if (SUCCEEDED(popup->service->GetUrl(szBuffer, ARRAYSIZE(szBuffer))))
+ {
+ BrowserPopup_SetStatusTextRes(hwnd, MAKEINTRESOURCE(IDS_HOME_DESCRIPTION));
+ url = SysAllocString(szBuffer);
+ }
+
+ if (SUCCEEDED(popup->service->GetName(szBuffer, ARRAYSIZE(szBuffer))))
+ pszDescription = Plugin_CopyString(szBuffer);
+ }
+ break;
+ case NAVIGATE_BACK:
+ BrowserPopup_SetStatusTextRes(hwnd, MAKEINTRESOURCE(IDS_BACK_DESCRIPTION));
+ return PostMessage(hHost, NBHM_CONTAINERCOMMAND, (WPARAM)Browser::commandBack, 0L);
+ case NAVIGATE_FORWARD:
+ BrowserPopup_SetStatusTextRes(hwnd, MAKEINTRESOURCE(IDS_FORWARD_DESCRIPTION));
+ return PostMessage(hHost, NBHM_CONTAINERCOMMAND, (WPARAM)Browser::commandForward, 0L);
+ case NAVIGATE_STOP:
+ BrowserPopup_SetStatusTextRes(hwnd, MAKEINTRESOURCE(IDS_STOP_DESCRIPTION));
+ return PostMessage(hHost, NBHM_CONTAINERCOMMAND, (WPARAM)Browser::commandStop, 0L);
+ case NAVIGATE_REFRESH:
+ BrowserPopup_SetStatusTextRes(hwnd, MAKEINTRESOURCE(IDS_REFRESH_DESCRIPTION));
+ return PostMessage(hHost, NBHM_CONTAINERCOMMAND, (WPARAM)Browser::commandRefresh, 0L);
+ case NAVIGATE_REFRESH_COMPLETELY:
+ BrowserPopup_SetStatusTextRes(hwnd, MAKEINTRESOURCE(IDS_REFRESH_DESCRIPTION));
+ return PostMessage(hHost, NBHM_CONTAINERCOMMAND, (WPARAM)Browser::commandRefreshCompletely, 0L);
+ }
+ }
+ else
+ {
+ BrowserPopup_SetStatusTextRes(hwnd, MAKEINTRESOURCE(IDS_NAVIGATING));
+ url = SysAllocString(navigateUrl);
+ }
+
+ if (NULL == url)
+ return FALSE;
+
+ HWND hToolbar = GetDlgItem(hwnd, IDC_TOOLBAR);
+ INT addressbarId = (NULL != hToolbar) ? Toolbar_FindItem(hToolbar, TOOLITEM_ADDRESSBAR) : ITEM_ERR;
+ if (ITEM_ERR != addressbarId)
+ {
+ Toolbar_SetItemString(hToolbar, MAKEINTRESOURCE(addressbarId), url);
+ Toolbar_SetItemDescription(hToolbar, MAKEINTRESOURCE(addressbarId), pszDescription);
+ }
+
+ if (!PostMessage(hHost, NBHM_NAVIGATE, 0, (LPARAM)url))
+ {
+ SysFreeString(url);
+ return FALSE;
+ }
+
+ Plugin_FreeString(pszDescription);
+
+ return TRUE;
+}
+
+static LRESULT BrowserPopup_OnWriteDocument(HWND hwnd, BSTR documentData, BOOL fScheduleBlocked)
+{
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup) return FALSE;
+
+ SysFreeString(popup->storedData);
+ popup->storedData = NULL;
+
+ Plugin_FreeResString(popup->storedUrl);
+ popup->storedUrl = NULL;
+
+ if (0 == (NBCS_EX_NAVCOMPLETED & popup->extendedStyle))
+ {
+ if (FALSE == fScheduleBlocked)
+ return FALSE;
+ popup->storedData = documentData;
+ return TRUE;
+ }
+
+ HWND hHost = GetDlgItem(hwnd, IDC_BROWSER);
+ if (NULL == hHost) return FALSE;
+
+ return PostMessage(hHost, NBHM_WRITEDOCUMENT, 0, (LPARAM)documentData);
+}
+
+static void BrowserPopup_OnParentChanged(HWND hwnd)
+{
+ HWND hRoot = GetAncestor(hwnd, GA_ROOT);
+ DWORD oldStyleEx, newStyleEx;
+
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup) return;
+
+ popup->flags &= ~BPF_LOCKRESIZE;
+
+ HWND hWinamp;
+ if (FAILED(Plugin_GetWinampWnd(&hWinamp)))
+ hWinamp = NULL;
+
+ oldStyleEx = GetWindowStyleEx(hwnd);
+ newStyleEx = oldStyleEx;
+
+ if (hRoot != hwnd)
+ {
+ HWND hDlgParent = (HWND)SENDWAIPC(hWinamp, IPC_GETDIALOGBOXPARENT, 0);
+ if (hRoot != hWinamp && hRoot != hDlgParent)
+ {
+ if (NULL != hDlgParent && hWinamp == (HWND)(LONG_PTR)GetWindowLongPtr(hRoot, GWLP_HWNDPARENT))
+ {
+ SetWindowLongPtr(hRoot, GWLP_HWNDPARENT, (LONGX86)(LONG_PTR)hDlgParent);
+ }
+ }
+ newStyleEx |= WS_EX_CONTROLPARENT;
+ }
+ else
+ {
+ newStyleEx &= ~WS_EX_CONTROLPARENT;
+
+
+ if (NULL != hWinamp && hWinamp != (HWND)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_HWNDPARENT))
+ SetWindowLongPtr(hwnd, GWLP_HWNDPARENT, (LONGX86)(LONG_PTR)hWinamp);
+
+ RECT rect;
+ if (BrowserPopup_PopRect(hwnd, &rect, FALSE))
+ {
+ BrowserPopup_ClientToFrame(hwnd, &rect);
+ BrowserPopup_SetFramePos(hwnd, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW);
+ }
+
+ }
+
+ if (newStyleEx != oldStyleEx)
+ SetWindowLongPtr(hwnd, GWL_EXSTYLE, newStyleEx);
+
+ BrowserPopup_RefreshTitle(hwnd);
+ SendMessage(hRoot, WM_UPDATEUISTATE, MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEACCEL | UISF_HIDEFOCUS), 0L);
+}
+
+
+static void BrowserPopup_OnUpdateSkin(HWND hwnd, BOOL fRedraw)
+{
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup) return;
+
+ DWORD windowStyle = GetWindowStyle(hwnd);
+
+ if (0 != (WS_VISIBLE & windowStyle))
+ SetWindowLongPtr(hwnd, GWL_STYLE, ~WS_VISIBLE & windowStyle);
+
+ ifc_skinnedbrowser *skinnedBrowser;
+ if (SUCCEEDED(Plugin_GetBrowserSkin(&skinnedBrowser)))
+ {
+ popup->rgbBack = skinnedBrowser->GetBackColor();
+ skinnedBrowser->Release();
+ }
+ else
+ popup->rgbBack = GetSysColor(COLOR_WINDOW);
+
+
+ HWND hControl;
+
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_BROWSER)))
+ PostMessage(hControl, NBHM_UPDATESKIN, 0, 0L);
+
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_STATUSBAR)))
+ Statusbar_UpdateSkin(hControl, FALSE);
+
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_TOOLBAR)))
+ Toolbar_UpdateSkin(hControl, FALSE);
+
+ if (NULL != (hControl = BrowserControl_GetOperationWidget(hwnd)))
+ Curtain_UpdateSkin(hControl, FALSE);
+
+ BrowserControl_UpdateLayout(hwnd, FALSE, TRUE, NULL, NULL);
+
+ if (0 != (WS_VISIBLE & windowStyle))
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle);
+
+ if (FALSE != fRedraw)
+ {
+ RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_FRAME);
+ }
+}
+
+static LRESULT BrowserPopup_OnSkinRefreshing(HWND hwnd)
+{
+
+ BrwoserPopup_PushClientRect(hwnd, FALSE);
+
+ HWND hRoot = GetAncestor(hwnd, GA_ROOT);
+ if (hRoot != hwnd)
+ {
+ HWND hWinamp;
+ if (FAILED(Plugin_GetWinampWnd(&hWinamp)))
+ hWinamp = NULL;
+
+ HWND hDlgParent = (HWND)SENDWAIPC(hWinamp, IPC_GETDIALOGBOXPARENT, 0);
+ if (NULL != hDlgParent && hDlgParent == (HWND)(LONG_PTR)GetWindowLongPtr(hRoot, GWLP_HWNDPARENT))
+ {
+ SetWindowLongPtr(hRoot, GWLP_HWNDPARENT, (LONGX86)(LONG_PTR)hWinamp);
+ }
+ }
+ return 0;
+}
+
+static void BrowserPopup_OnSkinRefreshed(HWND hwnd)
+{
+ BrowserPopup_PopRect(hwnd, NULL, FALSE);
+
+ HWND hFrame = BrowserPopup_GetFrame(hwnd);
+ if (hwnd != hFrame)
+ {
+ UINT state = (IsWindowVisible(hwnd) && IsWindowEnabled(hwnd) && (hFrame == GetActiveWindow())) ? WA_ACTIVE : WA_INACTIVE;
+ SendMessage(hwnd, WM_ACTIVATE, state, 0L);
+ }
+}
+
+static LRESULT BrowserPopup_OnSetFramePos(HWND hwnd, WINDOWPOS *pwp)
+{
+ if (NULL == pwp) return FALSE;
+
+ HWND hFrame;
+
+ ifc_window *wasabiWnd = (ifc_window*)SENDWAIPC(hwnd, IPC_SKINWINDOW_GETWASABIWND, 0);
+ if (NULL != wasabiWnd)
+ {
+ ifc_window *wasabiParent = wasabiWnd->getDesktopParent();
+ if (NULL == wasabiParent) wasabiParent = wasabiWnd;
+
+ hFrame = wasabiParent->gethWnd();
+ if (NULL == hFrame) return FALSE;
+
+ HWND hWinamp;
+ if (FAILED(Plugin_GetWinampWnd(&hWinamp)))
+ hWinamp = NULL;
+
+ HWND hDlgParent = (HWND)SENDWAIPC(hWinamp, IPC_GETDIALOGBOXPARENT, 0);
+ if (hDlgParent == hFrame)
+ return FALSE; // do not change size/pos if we are part of the sui
+
+ if (0 == (SWP_NOSIZE & pwp->flags))
+ {
+ RECT windowRect;
+ wasabiParent->getWindowRect(&windowRect);
+ if (pwp->cx != (windowRect.right - windowRect.left) || pwp->cy != (windowRect.bottom - windowRect.top))
+ {
+ if (0 == SendMessage(wasabiWnd->gethWnd(), OSWNDHOST_REQUEST_IDEAL_SIZE, pwp->cx, pwp->cy))
+ {
+ return FALSE; // hmm,
+ }
+ }
+ pwp->flags |= SWP_NOSIZE;
+ }
+
+ if (0 == (SWP_NOMOVE & pwp->flags))
+ {
+ RECT windowRect;
+ wasabiParent->getWindowRect(&windowRect);
+ wasabiParent->resize(pwp->x, pwp->y, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top);
+ pwp->flags |= SWP_NOMOVE;
+ }
+ }
+ else
+ {
+ hFrame = BrowserPopup_GetFrame(hwnd);
+ if (NULL == hFrame) return FALSE;
+ }
+
+ BOOL result = SetWindowPos(hFrame, pwp->hwndInsertAfter, pwp->x, pwp->y, pwp->cx, pwp->cy, pwp->flags);
+ BrwoserPopup_PushClientRect(hwnd, TRUE);
+ return result;
+}
+
+
+
+static void BrowserPopup_OnActivateFrame(HWND hwnd)
+{
+ ifc_window *wasabiWnd = (ifc_window*)SENDWAIPC(hwnd, IPC_SKINWINDOW_GETWASABIWND, 0);
+ if (NULL != wasabiWnd)
+ {
+ wasabiWnd->activate();
+ }
+ else
+ {
+ HWND hFrame = BrowserPopup_GetFrame(hwnd);
+ if (NULL == hFrame) hFrame = hwnd;
+
+ BringWindowToTop(hFrame);
+ SetActiveWindow(hFrame);
+ }
+}
+
+static LRESULT BrowserPopup_OnGetService(HWND hwnd, ifc_omservice **serviceOut)
+{
+ if (NULL == serviceOut) return FALSE;
+
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup || NULL == popup->service)
+ {
+ *serviceOut = NULL;
+ return FALSE;
+ }
+
+ *serviceOut = popup->service;
+ (*serviceOut)->AddRef();
+ return TRUE;
+}
+
+static LRESULT BrowserPopup_OnGetBrowserObject(HWND hwnd, obj_ombrowser **browserOut)
+{
+ if (NULL == browserOut) return FALSE;
+
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup || NULL == popup->browserManager)
+ {
+ *browserOut = NULL;
+ return FALSE;
+ }
+
+ *browserOut = popup->browserManager;
+ (*browserOut)->AddRef();
+ return TRUE;
+}
+static LRESULT BrowserPopup_OnRefreshTitle(HWND hwnd)
+{
+ HWND hBrowser = GetDlgItem(hwnd, IDC_BROWSER);
+ if (NULL == hBrowser || FALSE == PostMessage(hBrowser, NBHM_QUERYTITLE, 0, 0L))
+ BrowserPopup_UpdateTitle(hwnd, NULL);
+ return TRUE;
+}
+
+static LRESULT BrowserPopup_OnGetToolbar(HWND hwnd)
+{
+ if (0 != (NBCS_NOTOOLBAR & GetWindowLongPtr(hwnd, GWL_STYLE)))
+ return 0;
+
+ HWND hToolbar = GetDlgItem(hwnd, IDC_TOOLBAR);
+ return (LRESULT)hToolbar;
+}
+
+static LRESULT BrowserPopup_OnGetStatusbar(HWND hwnd)
+{
+ if (0 != (NBCS_NOSTATUSBAR & GetWindowLongPtr(hwnd, GWL_STYLE)))
+ return 0;
+
+ HWND hStatusbar = GetDlgItem(hwnd, IDC_STATUSBAR);
+ return (LRESULT)hStatusbar;
+}
+
+static LRESULT BrowserPopup_OnGetHost(HWND hwnd)
+{
+ return (LRESULT)GetDlgItem(hwnd, IDC_BROWSER);
+}
+
+static LRESULT BrowserPopup_OnNavigateStoredUrl(HWND hwnd)
+{
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup || NULL == popup->storedUrl)
+ return FALSE;
+
+ LPWSTR url = popup->storedUrl;
+ popup->storedUrl = NULL;
+ BOOL result = BrowserPopup_Navigate(hwnd, url, TRUE);
+ Plugin_FreeResString(url);
+ return result;
+}
+
+static LRESULT BrowserPopup_OnSetExtendedStyle(HWND hwnd, UINT extMask, UINT extStyle)
+{
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ if (NULL == popup) return 0;
+
+ UINT currentStyle = popup->extendedStyle;
+ popup->extendedStyle = (currentStyle & ~extMask) | (extStyle & extMask);
+
+ if ((NBCS_EX_SCRIPTMODE & currentStyle) != (NBCS_EX_SCRIPTMODE & popup->extendedStyle))
+ {
+ HWND hBrowser = GetDlgItem(hwnd, IDC_BROWSER);
+ if (NULL != hBrowser)
+ {
+ UINT browserStyle = GetWindowStyle(hBrowser);
+
+ if (0 != (NBCS_EX_SCRIPTMODE & popup->extendedStyle))
+ browserStyle |= NBHS_SCRIPTMODE;
+ else
+ browserStyle &= ~ NBHS_SCRIPTMODE;
+
+ SetWindowLongPtr(hBrowser, GWL_STYLE, browserStyle);
+ }
+ }
+
+ if ((NBCS_EX_FULLSCREEN & currentStyle) != (NBCS_EX_FULLSCREEN & popup->extendedStyle))
+ {
+ if (0 != (NBCS_EX_FULLSCREEN & popup->extendedStyle))
+ BrowserPopup_SwitchToFullscreen(hwnd);
+ else
+ BrowserPopup_Restore(hwnd);
+ }
+
+ return currentStyle;
+}
+
+static LRESULT BrowserPopup_OnGetExtendedStyle(HWND hwnd)
+{
+ BROWSERPOPUP *popup = GetPopup(hwnd);
+ return (NULL != popup) ? popup->extendedStyle : 0;
+}
+
+static LRESULT CALLBACK BrowserPopup_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_CREATE: return BrowserPopup_OnCreate(hwnd, (CREATESTRUCT*)lParam);
+ case WM_DESTROY: BrowserPopup_OnDestroy(hwnd); break;
+ case WM_ERASEBKGND: return 0;
+ case WM_PAINT: BrowserPopup_OnPaint(hwnd); return 0;
+ case WM_PRINTCLIENT: BrowserPopup_OnPrintClient(hwnd, (HDC)wParam, (UINT)lParam); return 0;
+ case WM_WINDOWPOSCHANGING: BrowserPopup_OnWindowPosChanging(hwnd, (WINDOWPOS*)lParam); return 0;
+ case WM_WINDOWPOSCHANGED: BrowserPopup_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); return 0;
+ case WM_COMMAND: BrowserPopup_OnCommand(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break;
+ case WM_APPCOMMAND: return BrowserPopup_OnAppCommand(hwnd, (HWND)wParam, GET_APPCOMMAND_LPARAM(lParam), GET_DEVICE_LPARAM(lParam), GET_KEYSTATE_LPARAM(lParam));
+ case WM_NOTIFY: return BrowserPopup_OnNotify(hwnd, (INT)wParam, (NMHDR*)lParam);
+ case WM_SETFOCUS: BrowserPopup_OnSetFocus(hwnd, (HWND)wParam); return 0;
+ case WM_ACTIVATE: BrowserPopup_OnActivate(hwnd, LOWORD(wParam), (HWND)lParam, HIWORD(wParam)); break;
+ case WM_STYLECHANGED: BrowserPopup_OnStyleChanged(hwnd, (UINT)wParam, (STYLESTRUCT*)lParam); break;
+ case WM_GETMINMAXINFO: BrowserPopup_OnGetMinMaxInfo(hwnd, (MINMAXINFO*)lParam); return 0;
+
+ case NBCM_GETTOOLBAR: return BrowserPopup_OnGetToolbar(hwnd);
+ case NBCM_GETSTATUSBAR: return BrowserPopup_OnGetStatusbar(hwnd);
+ case NBCM_GETHOST: return BrowserPopup_OnGetHost(hwnd);
+ case NBCM_GETSERVICE: return BrowserPopup_OnGetService(hwnd, (ifc_omservice**)lParam);
+ case NBCM_UPDATESKIN: BrowserPopup_OnUpdateSkin(hwnd, (BOOL)lParam); return 0;
+ case NBCM_NAVIGATE: return BrowserPopup_OnNavigate(hwnd, (LPCWSTR)lParam, (BOOL)wParam);
+ case NBCM_WRITEDOCUMENT: return BrowserPopup_OnWriteDocument(hwnd, (BSTR)lParam, (BOOL)wParam);
+ case NBCM_GETBROWSEROBJECT: return BrowserPopup_OnGetBrowserObject(hwnd, (obj_ombrowser**)lParam);
+ case NBCM_SHOWOPERATION: return BrowserControl_OnShowOperation(hwnd, (OPERATIONINFO*)lParam);
+ case NBCM_NAVSTOREDURL: return BrowserPopup_OnNavigateStoredUrl(hwnd);
+ case NBCM_BLOCK: BrowserControl_SetBlockedState(hwnd, (BOOL)lParam); return 0;
+ case NBCM_SETEXTSTYLE: return BrowserPopup_OnSetExtendedStyle(hwnd, (UINT)wParam, (UINT)lParam);
+ case NBCM_GETEXTSTYLE: return BrowserPopup_OnGetExtendedStyle(hwnd);
+
+ case NBPM_PARENTCHANGED: BrowserPopup_OnParentChanged(hwnd); return 0;
+ case NBPM_SKINREFRESHING: return BrowserPopup_OnSkinRefreshing(hwnd);
+ case NBPM_SKINREFRESHED: BrowserPopup_OnSkinRefreshed(hwnd); return 0;
+ case NBPM_SETFRAMEPOS: return BrowserPopup_OnSetFramePos(hwnd, (WINDOWPOS*)lParam);
+ case NBPM_ACTIVATEFRAME: BrowserPopup_OnActivateFrame(hwnd); return 0;
+ case NBPM_REFRESHTITLE: return BrowserPopup_OnRefreshTitle(hwnd);
+ }
+
+ if (FALSE != Plugin_IsDirectMouseWheelMessage(uMsg))
+ {
+ SendMessage(hwnd, WM_MOUSEWHEEL, wParam, lParam);
+ return TRUE;
+ }
+
+ return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+} \ No newline at end of file
diff --git a/Src/omBrowser/browserPopup.h b/Src/omBrowser/browserPopup.h
new file mode 100644
index 00000000..48f247e3
--- /dev/null
+++ b/Src/omBrowser/browserPopup.h
@@ -0,0 +1,77 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_POPUP_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_POPUP_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./browserUiCommon.h"
+
+#define NWC_OMBROWSERPOPUP L"Nullsoft_omBrowserPopup"
+
+// {6EFB8AF7-C54F-43fb-B1DD-DF2EE7E67703}
+static const GUID WTID_BrowserPopup =
+{ 0x6efb8af7, 0xc54f, 0x43fb, { 0xb1, 0xdd, 0xdf, 0x2e, 0xe7, 0xe6, 0x77, 0x3 } };
+
+// {00000010-0000-00FF-8000-C5E2FB8CD50B} // guid will be incremented for each instance
+static const GUID SkinClass_BrowserPopup =
+{ 0x00000010, 0x0000, 0x00FF, { 0x80, 0x00, 0xc5, 0xe2, 0xfb, 0x8c, 0xd5, 0xb } };
+
+
+typedef void (CALLBACK *DISPATCHAPC)(IDispatch *pDisp, ULONG_PTR /*param*/);
+
+HWND BrowserPopup_Create(obj_ombrowser *browserManager, ifc_omservice *service, UINT fStyle, INT x, INT y, INT cx, INT cy, HWND hOwner, DISPATCHAPC callback, ULONG_PTR param);
+
+// browser common messages
+#define BrowserPopup_GetToolbar(/*HWND*/ __hwndPopup)\
+ BrowserControl_GetToolbar(__hwndPopup)
+
+#define BrowserPopup_GetStatusbar(/*HWND*/ __hwndPopup)\
+ BrowserControl_GetStatusbar(__hwndPopup)
+
+#define BrowserPopup_GetHost(/*HWND*/ __hwndPopup)\
+ BrowserControl_GetHost(__hwndPopup)
+
+#define BrowserPopup_UpdateSkin(/*HWND*/ __hwndPopup, /*BOOL*/ __fRedraw)\
+ BrowserControl_UpdateSkin(__hwndPopup, __fRedraw)
+
+#define BrowserPopup_GetService(/*HWND*/ __hwndPopup, /*ifc_omservice** */ __serviceOut)\
+ BrowserControl_GetService(__hwndPopup, __serviceOut)
+
+#define BrowserPopup_Navigate(/*HWND*/ __hwndPopup, /*LPCWSTR*/ __navigateUrl, /*BOOL*/ __scheduleBlocked)\
+ BrowserControl_Navigate(__hwndPopup, __navigateUrl, __scheduleBlocked)
+
+#define BrowserPopup_NavigateHome(/*HWND*/ __hwndPopup, /*BOOL*/ __scheduleBlocked)\
+ BrowserPopup_Navigate((__hwndPopup), NAVIGATE_HOME, (__scheduleBlocked))
+
+#define BrowserPopup_WriteDocument(/*HWND*/ __hwndPopup, /*BSTR*/ __documentData, /*BOOL*/ __scheduleBlocked)\
+ BrowserControl_WriteDocument(__hwndPopup, __documentData, __scheduleBlocked)
+
+#define BrowserPopup_ShowOperation(/*HWND*/ __hwndView, /*const OPERATIONINFO* */ __pOperationInfo)\
+ BrowserControl_ShowOperation(__hwndView, __pOperationInfo)
+
+// browser popup messages
+#define NBPM_PARENTCHANGED (NBPM_FIRST + 1) // wParam = not used, lParam = not used
+
+#define NBPM_SKINREFRESHING (NBPM_FIRST + 2) // wParam = not used, lParam = not used. Return 0 to allow, non zero to prevent.
+#define BrowserPopup_SkinRefreshing(/*HWND*/ __hwndPopup)\
+ SENDMSG((__hwndPopup), NBPM_SKINREFRESHING, 0, 0L)
+
+#define NBPM_SKINREFRESHED (NBPM_FIRST + 3) // wParam = not used, lParam = not used.
+#define BrowserPopup_SkinRefreshed(/*HWND*/ __hwndPopup)\
+ SENDMSG((__hwndPopup), NBPM_SKINREFRESHED, 0, 0L)
+
+#define NBPM_SETFRAMEPOS (NBPM_FIRST + 4) // wParam = not used, lParam = (LPARAM)(WINDOWPOS*)pwp;
+#define BrowserPopup_SetFramePos(/*HWND*/ __hwndPopup, /*HWND*/__hwndInsertAfter, /*INT*/ __x, /*INT*/ __y, /*INT*/__cx, /*INT*/ __cy, /*UINT*/ __flags)\
+ { WINDOWPOS wp; wp.hwndInsertAfter = (__hwndInsertAfter); wp.x = (__x); wp.y = (__y); wp.cx = (__cx); wp.cy = (__cy); wp.flags = (__flags);\
+ SENDMSG((__hwndPopup), NBPM_SETFRAMEPOS, 0, (LPARAM)(&wp));}
+
+#define NBPM_ACTIVATEFRAME (NBPM_FIRST + 5) // wParam = not used, lParam = not used.
+#define BrowserPopup_ActivateFrame(/*HWND*/ __hwndPopup)\
+ SENDMSG((__hwndPopup), NBPM_ACTIVATEFRAME, 0, 0L)
+
+#define NBPM_REFRESHTITLE (NBPM_FIRST + 6) // wParam - not used, lParam - not used, return TRUE on success
+#define BrowserPopup_RefreshTitle(/*HWND*/ __hwndPopup)\
+ ((BOOL)SENDMSG((__hwndPopup), NBPM_REFRESHTITLE, 0, 0L))
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_POPUP_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/browserRegistry.cpp b/Src/omBrowser/browserRegistry.cpp
new file mode 100644
index 00000000..9c231f7d
--- /dev/null
+++ b/Src/omBrowser/browserRegistry.cpp
@@ -0,0 +1,356 @@
+#include "main.h"
+#include "./browserRegistry.h"
+#include "./obj_ombrowser.h"
+#include "./ifc_wasabihelper.h"
+#include "./ifc_skinhelper.h"
+#include "./ifc_skinnedbrowser.h"
+#include "./ifc_ombrowserclass.h"
+#include "./ifc_omconfig.h"
+#include "./ifc_omdebugconfig.h"
+
+#include "../Plugins/General/gen_ml/colors.h"
+
+#include <shlwapi.h>
+#include <strsafe.h>
+
+#define YES L"yes"
+#define NO L"no"
+
+#define REGVAL_DWORD(__regKey, __valueName, __data) { DWORD __iVal = (__data); RegSetValueExW((__regKey), (__valueName), NULL, REG_DWORD, (LPCBYTE)&__iVal, sizeof(DWORD)); }
+#define REGVAL_STR(__regKey, __valueName, __data, __cbData) RegSetValueExW((__regKey), (__valueName), NULL, REG_SZ, (LPCBYTE)(__data), (__cbData))
+
+#define REGVAL_ONE(__regKey, __valueName) REGVAL_DWORD(__regKey, __valueName, 1)
+#define REGVAL_ZERO(__regKey, __valueName) REGVAL_DWORD(__regKey, __valueName, 0)
+#define REGVAL_YES(__regKey, __valueName) REGVAL_STR(__regKey, __valueName, YES, sizeof(YES))
+#define REGVAL_NO(__regKey, __valueName) REGVAL_STR(__regKey, __valueName, NO, sizeof(NO))
+#define REGVAL_YESNO(__regKey, __valueName, __condition) ((0 != (__condition)) ? REGVAL_YES(__regKey, __valueName) : REGVAL_NO(__regKey, __valueName))
+#define REGVAL_RGB(__regKey, __valueName, __rgb)\
+ { WCHAR szRGB[64] = {0}; COLORREF c = (__rgb);\
+ StringCchPrintfW(szRGB, ARRAYSIZE(szRGB), L"%d,%d,%d", GetRValue(c), GetGValue(c), GetBValue(c));\
+ INT cbLen = lstrlenW(szRGB) * sizeof(WCHAR);\
+ REGVAL_STR(__regKey, __valueName, szRGB, cbLen);}
+
+
+OmBrowserRegistry::OmBrowserRegistry(LPCWSTR pszName)
+ : ref(1), name(NULL), path(NULL)
+{
+ name = Plugin_CopyString(pszName);
+}
+
+OmBrowserRegistry::~OmBrowserRegistry()
+{
+ Plugin_FreeString(name);
+ Plugin_FreeString(path);
+}
+
+HRESULT OmBrowserRegistry::CreateInstance(LPCWSTR pszName, OmBrowserRegistry **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ *instance = NULL;
+
+ if (NULL == pszName || L'\0' == *pszName)
+ pszName = OMBROWSER_NAME;
+
+ *instance = new OmBrowserRegistry(pszName);
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t OmBrowserRegistry::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t OmBrowserRegistry::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int OmBrowserRegistry::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmBrowserRegistry))
+ *object = static_cast<ifc_ombrowserregistry*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT OmBrowserRegistry::Write()
+{
+ HKEY hKey = NULL;
+ HKEY hKey2 = NULL;
+
+ LONG result;
+ DWORD disposition;
+
+ if (FAILED(CreateRoot(&hKey, NULL)))
+ return E_FAIL;
+
+ result = RegCreateKeyExW(hKey, L"Main", NULL, NULL, REG_OPTION_VOLATILE, KEY_SET_VALUE, NULL, &hKey2, &disposition);
+ if (ERROR_SUCCESS == result)
+ {
+ REGVAL_ONE(hKey2, L"AllowWindowReuse");
+
+
+ HRESULT hr(S_FALSE);
+
+
+ ifc_ombrowserclass *browserClass;
+ if (SUCCEEDED(Plugin_GetBrowserClass(name, &browserClass)))
+ {
+ ifc_omconfig *config;
+ if (SUCCEEDED(browserClass->GetConfig(&config)))
+ {
+ ifc_omdebugconfig *debugConfig;
+ if (SUCCEEDED(config->QueryInterface(IFC_OmDebugConfig, (void**)&debugConfig)))
+ {
+ hr = debugConfig->GetScriptDebuggerEnabled();
+ debugConfig->Release();
+ }
+ config->Release();
+ }
+ browserClass->Release();
+ }
+
+ REGVAL_YESNO(hKey2, L"Disable Script Debugger", (S_FALSE == hr));
+
+
+ REGVAL_NO(hKey2, L"Check_Associations");
+ REGVAL_ZERO(hKey2, L"EnableSearchPane");
+ REGVAL_NO(hKey2, L"Friendly http errors");
+ REGVAL_NO(hKey2, L"FullScreen");
+ REGVAL_NO(hKey2, L"Save_Session_History_On_Exit");
+ REGVAL_NO(hKey2, L"Use_DlgBox_Colors");
+ REGVAL_YES(hKey2, L"ShowedCheckBrowser");
+ REGVAL_STR(hKey2, L"Start Page", L"", sizeof(L""));
+ REGVAL_STR(hKey2, L"Default_Page_URL", L"about:blank", sizeof(L"about:blank"));
+ REGVAL_STR(hKey2, L"Default_Search_URL", L"about:blank", sizeof(L"about:blank"));
+ REGVAL_NO(hKey2, L"Enable Browser Extensions");
+ REGVAL_NO(hKey2, L"Error Dlg Details Pane Open");
+ REGVAL_NO(hKey2, L"Error Dlg Displayed On Every Error");
+ REGVAL_ONE(hKey2, L"NoUpdateCheck");
+ REGVAL_NO(hKey2, L"Save_Session_History_On_Exit");
+ REGVAL_ONE(hKey2, L"NoJITSetup");
+ REGVAL_ONE(hKey2, L"NoWebJITSetup");
+ REGVAL_ONE(hKey2, L"RunOnceComplete");
+ REGVAL_ONE(hKey2, L"RunOnceHasShown");
+ REGVAL_ONE(hKey2, L"SearchMigrated");
+
+ RegCloseKey(hKey2);
+ }
+
+ result = RegCreateKeyExW(hKey, L"MenuExt", NULL, NULL, REG_OPTION_VOLATILE, KEY_SET_VALUE, NULL, &hKey2, &disposition);
+ if (ERROR_SUCCESS == result)
+ {
+ RegCloseKey(hKey2);
+ }
+
+ result = RegCreateKeyExW(hKey, L"New Windows", NULL, NULL, REG_OPTION_VOLATILE, KEY_SET_VALUE, NULL, &hKey2, &disposition);
+ if (ERROR_SUCCESS == result)
+ {
+ REGVAL_ZERO(hKey2, L"PlaySound");
+ REGVAL_ONE(hKey2, L"PopupMgr");
+ RegCloseKey(hKey2);
+ }
+
+ result = RegCreateKeyExW(hKey, L"SearchScopes", NULL, NULL, REG_OPTION_VOLATILE, KEY_SET_VALUE, NULL, &hKey2, &disposition);
+ if (ERROR_SUCCESS == result)
+ {
+ RegCloseKey(hKey2);
+ }
+
+ result = RegCreateKeyExW(hKey, L"SearchUrl", NULL, NULL, REG_OPTION_VOLATILE, KEY_SET_VALUE, NULL, &hKey2, &disposition);
+ if (ERROR_SUCCESS == result)
+ {
+ RegCloseKey(hKey2);
+ }
+
+ result = RegCreateKeyExW(hKey, L"URLSearchHooks", NULL, NULL, REG_OPTION_VOLATILE, KEY_SET_VALUE, NULL, &hKey2, &disposition);
+ if (ERROR_SUCCESS == result)
+ {
+ RegCloseKey(hKey2);
+ }
+
+ HRESULT hr = WriteColors(hKey);
+
+ RegCloseKey(hKey);
+ return hr;
+}
+
+HRESULT OmBrowserRegistry::Delete()
+{
+ HRESULT hr;
+ WCHAR szBuffer[512] = {0};
+ hr = GetPath(szBuffer, ARRAYSIZE(szBuffer));
+ if (FAILED(hr)) return hr;
+
+ LONG result = SHDeleteKey(HKEY_CURRENT_USER, szBuffer);
+ hr = (ERROR_SUCCESS != result) ? E_FAIL : S_OK;
+ return hr;
+}
+
+HRESULT OmBrowserRegistry::UpdateColors()
+{
+ HKEY hKey;
+
+ HRESULT hr = CreateRoot(&hKey, NULL);
+ if (FAILED(hr)) return hr;
+
+ hr = WriteColors(hKey);
+
+ RegCloseKey(hKey);
+ return hr;
+}
+
+HRESULT OmBrowserRegistry::GetPath(LPWSTR pszBuffer, INT cchBufferMax)
+{
+ if (NULL == pszBuffer)
+ return E_POINTER;
+
+ if (NULL == path)
+ {
+ HRESULT hr = CreatePath(pszBuffer, cchBufferMax);
+ if (FAILED(hr)) return hr;
+
+ path = Plugin_CopyString(pszBuffer);
+ }
+
+ return StringCchPrintfW(pszBuffer, cchBufferMax, path);
+}
+
+HRESULT OmBrowserRegistry::CreatePath(LPWSTR pszBuffer, INT cchBufferMax)
+{
+ if (NULL == pszBuffer) return E_POINTER;
+ if (NULL == name || L'\0' == *name) return E_INVALIDARG;
+
+ HRESULT hr;
+ WCHAR szApp[128] = {0}, szSessionId[128] = {0};
+
+ ifc_wasabihelper *wasabi;
+ hr = Plugin_GetWasabiHelper(&wasabi);
+ if (SUCCEEDED(hr))
+ {
+ api_application *app;
+ hr = wasabi->GetApplicationApi(&app);
+ if (SUCCEEDED(hr))
+ {
+ if (FAILED(StringCchCopyEx(szApp, ARRAYSIZE(szApp), app->main_getAppName(), NULL, NULL, STRSAFE_IGNORE_NULLS)))
+ szApp[0] = L'\0';
+
+ UUID uid;
+ if (API_APPLICATION_SUCCESS == app->GetSessionID(&uid))
+ {
+ RPC_WSTR pszUid;
+ if (RPC_S_OK == UuidToString(&uid, &pszUid))
+ {
+ if(FAILED(StringCchCopy(szSessionId, ARRAYSIZE(szSessionId), (LPCWSTR)pszUid)))
+ szSessionId[0] = L'\0';
+ RpcStringFree(&pszUid);
+ }
+ }
+
+ app->Release();
+ }
+ wasabi->Release();
+ }
+
+ if (L'\0' == szApp[0])
+ hr = StringCchCopy(szApp, ARRAYSIZE(szApp), L"Winamp");
+
+ if (L'\0' == szSessionId[0])
+ hr = StringCchPrintf(szSessionId, ARRAYSIZE(szSessionId), L"%u", GetCurrentProcessId());
+
+ if (SUCCEEDED(hr))
+ hr = StringCchPrintfW(pszBuffer, cchBufferMax, L"Software\\%s\\%s\\%s", szApp, name, szSessionId);
+
+ if (FAILED(hr))
+ *pszBuffer = L'\0';
+
+ return hr;
+}
+HRESULT OmBrowserRegistry::CreateRoot(HKEY *hKey, DWORD *pDisposition)
+{
+ if (NULL == path)
+ {
+ WCHAR szBuffer[2048] = {0};
+ HRESULT hr = CreatePath(szBuffer, ARRAYSIZE(szBuffer));
+ if (FAILED(hr)) return hr;
+
+ path = Plugin_CopyString(szBuffer);
+ if (NULL == path) return E_OUTOFMEMORY;
+ }
+
+ if (NULL == path || L'\0' == *path)
+ return E_UNEXPECTED;
+
+ DWORD disposition;
+ LONG result = RegCreateKeyExW(HKEY_CURRENT_USER, path, NULL, NULL, REG_OPTION_VOLATILE, KEY_SET_VALUE, NULL, hKey, &disposition);
+ if (ERROR_SUCCESS != result)
+ {
+ return E_FAIL;
+ }
+
+ if (NULL != pDisposition)
+ *pDisposition = disposition;
+
+ return S_OK;
+}
+
+HRESULT OmBrowserRegistry::WriteColors(HKEY hKey)
+{
+ return S_OK;
+
+ ifc_skinnedbrowser *skinnedBrowser;
+ HRESULT hr = Plugin_GetBrowserSkin(&skinnedBrowser);
+ if (FAILED(hr)) return E_FAIL;
+
+ LONG result;
+ DWORD disposition;
+ HKEY hKey2 = NULL;
+
+ result = RegCreateKeyExW(hKey, L"Settings", NULL, NULL, REG_OPTION_VOLATILE, KEY_SET_VALUE, NULL, &hKey2, &disposition);
+ if (ERROR_SUCCESS == result)
+ {
+ REGVAL_RGB(hKey2, L"Text Color", skinnedBrowser->GetTextColor());
+ REGVAL_RGB(hKey2, L"Background Color", skinnedBrowser->GetBackColor());
+ REGVAL_RGB(hKey2, L"Anchor Color", skinnedBrowser->GetLinkColor());
+ REGVAL_RGB(hKey2, L"Anchor Color Hover", skinnedBrowser->GetHoveredLinkColor());
+ REGVAL_YES(hKey2, L"Use Anchor Hover Color");
+ REGVAL_RGB(hKey2, L"Anchor Color Visited", skinnedBrowser->GetVisitedLinkColor());
+
+ RegCloseKey(hKey2);
+ }
+
+ skinnedBrowser->Release();
+ return hr;
+}
+
+#define CBCLASS OmBrowserRegistry
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_GETPATH, GetPath)
+CB(API_WRITE, Write)
+CB(API_DELETE, Delete)
+CB(API_UPDATECOLORS, UpdateColors)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/browserRegistry.h b/Src/omBrowser/browserRegistry.h
new file mode 100644
index 00000000..1ca113d0
--- /dev/null
+++ b/Src/omBrowser/browserRegistry.h
@@ -0,0 +1,49 @@
+#ifndef NULLSOFT_WINAMP_BROWSER_REGISTRY_HEADER
+#define NULLSOFT_WINAMP_BROWSER_REGISTRY_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_ombrowserregistry.h"
+
+class obj_ombrowser;
+
+class OmBrowserRegistry : public ifc_ombrowserregistry
+{
+protected:
+ OmBrowserRegistry(LPCWSTR pszName);
+ ~OmBrowserRegistry();
+
+public:
+ static HRESULT CreateInstance(LPCWSTR pszName, OmBrowserRegistry **instance);
+
+public:
+
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_ombrowserregistry */
+ HRESULT GetPath(LPWSTR pszBuffer, INT cchBufferMax);
+ HRESULT Write(void);
+ HRESULT Delete(void);
+ HRESULT UpdateColors(void);
+
+protected:
+ HRESULT CreatePath(LPWSTR pszBuffer, INT cchBufferMax);
+ HRESULT CreateRoot(HKEY *hKey, DWORD *pDisposition);
+ HRESULT WriteColors(HKEY hKey);
+
+protected:
+ RECVS_DISPATCH;
+
+protected:
+ ULONG ref;
+ LPWSTR name;
+ LPWSTR path;
+
+};
+
+#endif //NULLSOFT_WINAMP_BROWSER_REGISTRY_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/browserThread.cpp b/Src/omBrowser/browserThread.cpp
new file mode 100644
index 00000000..36de9e80
--- /dev/null
+++ b/Src/omBrowser/browserThread.cpp
@@ -0,0 +1,413 @@
+#include "main.h"
+#include "./browserThread.h"
+#include "../nu/threadname.h"
+
+#include <exdisp.h>
+
+typedef struct __BROWSERTHREADCRAEATEPARAM
+{
+ BTCREATEWNDPROC fnCreateWnd;
+ BTKEYFILTERPROC fnKeyFilter;
+ ULONG_PTR user;
+ HANDLE readyEvent;
+ HWND hHost;
+ HWND hWinamp;
+} BROWSERTHREADCREATEPARAM;
+
+typedef struct __BROWSERTHREAD
+{
+ HHOOK messageHook;
+ HANDLE wakeupEvent;
+ UINT flags;
+} BROWSERTHREAD;
+
+#define NAVIGATE_WAITTIMEOUT 30
+
+static size_t tlsIndex = TLS_OUT_OF_INDEXES;
+static UINT BHTM_DESTROY = 0xFEFE;
+
+static DWORD CALLBACK BrowserThread_MainLoop(LPVOID param);
+
+#define GetThreadInstance() ((TLS_OUT_OF_INDEXES != tlsIndex) ? (BROWSERTHREAD*)Plugin_TlsGetValue(tlsIndex) : NULL)
+
+BOOL BrowserThread_IsQuiting()
+{
+ BROWSERTHREAD *thread = GetThreadInstance();
+ return (NULL == thread || 0 != ((BHTF_BEGINDESTROY | BHTF_QUITLOOP) & thread->flags));
+}
+
+BOOL BrowserThread_SetFlags(UINT flags, UINT flagsMask, BOOL fAlarm)
+{
+ BROWSERTHREAD *thread = GetThreadInstance();
+ if (NULL == thread) return FALSE;
+
+ thread->flags = ((thread->flags & flagsMask) | flags);
+ if (FALSE == fAlarm)
+ return TRUE;
+
+ return (NULL != thread->wakeupEvent && SetEvent(thread->wakeupEvent));
+}
+
+
+HANDLE BrowserThread_Create(HWND hWinamp, BTCREATEWNDPROC fnCreateWnd, ULONG_PTR user, BTKEYFILTERPROC fnKeyFilter, HWND *pWnd, DWORD *pThreadId)
+{
+ if (NULL == fnCreateWnd)
+ return NULL;
+
+ if (TLS_OUT_OF_INDEXES == tlsIndex)
+ {
+ tlsIndex = Plugin_TlsAlloc();
+ if (TLS_OUT_OF_INDEXES == tlsIndex)
+ return NULL;
+ }
+
+ DWORD threadId;
+
+ BROWSERTHREADCREATEPARAM param;
+ ZeroMemory(&param, sizeof(BROWSERTHREADCREATEPARAM));
+
+ param.fnCreateWnd = fnCreateWnd;
+ param.fnKeyFilter = fnKeyFilter;
+ param.user = user;
+ param.readyEvent = CreateEvent(0, TRUE, FALSE, 0);
+ param.hWinamp = hWinamp;
+
+ HANDLE hThread = CreateThread(NULL, 0, BrowserThread_MainLoop, (LPVOID)&param, 0, &threadId);
+
+ if (NULL != hThread)
+ {
+ if (NULL != param.readyEvent)
+ WaitForSingleObject(param.readyEvent, INFINITE);
+ }
+ else
+ {
+ if (NULL != param.hHost)
+ {
+ DestroyWindow(param.hHost);
+ param.hHost = NULL;
+ }
+ threadId = 0;
+ }
+
+ if (NULL != param.readyEvent)
+ CloseHandle(param.readyEvent);
+
+
+ if (NULL != pThreadId)
+ *pThreadId = threadId;
+
+ if (NULL != pWnd)
+ *pWnd = param.hHost;
+
+ return hThread;
+}
+
+
+
+BOOL BrowserThread_PostDestroyEx(DWORD threadId, HWND hHost)
+{
+ if (0 == BHTM_DESTROY)
+ BHTM_DESTROY = RegisterWindowMessage(L"omBrowserDestroyMsg");
+
+ if (0 == BHTM_DESTROY ||
+ FALSE == PostThreadMessage(threadId, BHTM_DESTROY, 0, (LPARAM)hHost))
+ {
+ return FALSE;
+ }
+
+ BrowserThread_SetFlags(BHTF_BEGINDESTROY, BHTF_BEGINDESTROY, FALSE);
+ return TRUE;
+}
+
+BOOL BrowserThread_PostDestroy(HWND hHost)
+{
+ return BrowserThread_PostDestroyEx(GetCurrentThreadId(), hHost);
+}
+
+BOOL BrowserThread_WaitNavigateComplete(IWebBrowser2 *pWeb2, UINT waitMax)
+{
+ MSG msg;
+ READYSTATE state;
+ if (NULL == pWeb2)
+ return FALSE;
+
+ BOOL resultOk = FALSE;
+ DWORD tickStart = GetTickCount();
+
+ for(;;)
+ {
+ if (FAILED(pWeb2->get_ReadyState(&state)))
+ break;
+
+ if (READYSTATE_INTERACTIVE <= state)
+ {
+ resultOk = TRUE;
+ break;
+ }
+ else
+ {
+ DWORD tickNow = GetTickCount();
+ if (tickNow < tickStart || (tickNow - tickStart) >= waitMax)
+ {
+ break; // time out
+ }
+ }
+
+ DWORD status = MsgWaitForMultipleObjectsEx(0, NULL, NAVIGATE_WAITTIMEOUT, QS_POSTMESSAGE | QS_TIMER | QS_SENDMESSAGE, MWMO_ALERTABLE);
+ switch(status)
+ {
+ case (WAIT_OBJECT_0 + 0):
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ if (!CallMsgFilter(&msg, MSGF_BROWSERLOOP))
+ {
+ DispatchMessageW(&msg);
+ }
+ }
+ break;
+ }
+ }
+ return resultOk;
+}
+
+static BOOL BrowserThread_HandleMessage(MSG *pMsg)
+{
+ switch(pMsg->message)
+ {
+ case WM_QUIT:
+ BrowserThread_SetFlags(BHTF_QUITLOOP, BHTF_QUITLOOP, TRUE);
+ return TRUE;
+ }
+
+ if (0 != BHTM_DESTROY && BHTM_DESTROY == pMsg->message)
+ {
+ HWND hHost = (HWND)pMsg->lParam;
+ if (NULL != hHost)
+ {
+ BrowserThread_SetFlags(BHTF_BEGINDESTROY, BHTF_BEGINDESTROY, FALSE);
+ SendMessage(hHost, BTM_RELEASECONTAINER, 0, 0L);
+ DestroyWindow(hHost);
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static LRESULT CALLBACK BrowserThread_MessageFilterProc(INT code, WPARAM wParam, LPARAM lParam)
+{
+ BROWSERTHREAD *thread = GetThreadInstance();
+ if (code >= 0)
+ {
+ if (BrowserThread_HandleMessage((MSG*)lParam))
+ {
+ return TRUE;
+ }
+ }
+
+ return (NULL != thread && NULL != thread->messageHook) ?
+ CallNextHookEx(thread->messageHook, code, wParam, lParam) :
+ FALSE;
+}
+
+static BOOL CALLBACK BrowserThread_DefaultKeyFilter(HWND hwnd, MSG *pMsg)
+{
+ return FALSE;
+}
+
+
+inline static BOOL BrowserThread_ProcessMessage(HWND hHost, HWND hWinamp, MSG *pMsg, BTKEYFILTERPROC IsHostMessage)
+{
+ if (hHost != pMsg->hwnd && FALSE == IsChild(hHost, pMsg->hwnd))
+ return FALSE;
+
+ if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
+ {
+ if (FALSE != IsHostMessage(hHost, pMsg))
+ return TRUE;
+
+ switch(pMsg->wParam)
+ {
+ case VK_TAB:
+ {
+ HWND hOwner = (HWND)(LONG_PTR)GetWindowLongPtr(hHost, GWLP_HWNDPARENT);
+ if (NULL == hOwner || hWinamp == hOwner)
+ hOwner = hHost;
+ return IsDialogMessageW(hOwner, pMsg);
+ }
+ break;
+ }
+ }
+
+ if (pMsg->message == WM_MOUSEWHEEL)
+ {
+ POINT cursor;
+ HWND targetWindow;
+
+ POINTSTOPOINT(cursor, pMsg->lParam);
+ targetWindow = WindowFromPoint(cursor);
+
+ if (NULL != targetWindow &&
+ FALSE == IsChild(hHost, targetWindow ) &&
+ GetWindowThreadProcessId(targetWindow, NULL) != GetWindowThreadProcessId(hHost, NULL))
+ {
+ PostMessage(hWinamp, pMsg->message, pMsg->wParam, pMsg->lParam);
+ return TRUE;
+ }
+
+ }
+
+ return FALSE;
+}
+
+static void BrowserThread_FinishThread(BROWSERTHREAD *thread)
+{
+ if (NULL != thread)
+ {
+ if (NULL != thread->messageHook)
+ {
+ UnhookWindowsHookEx(thread->messageHook);
+ thread->messageHook = NULL;
+ }
+
+ if (NULL != thread->wakeupEvent)
+ {
+ CloseHandle(thread->wakeupEvent);
+ thread->wakeupEvent = NULL;
+ }
+ }
+
+ if (TLS_OUT_OF_INDEXES != tlsIndex)
+ Plugin_TlsSetValue(tlsIndex, NULL);
+
+ OleUninitialize();
+
+ #ifdef _DEBUG
+ aTRACE_FMT("[%d] %S: thread exit\r\n", GetCurrentThreadId(), OMBROWSER_NAME);
+ #endif // _DEBUG
+}
+
+static DWORD CALLBACK BrowserThread_MainLoop(LPVOID param)
+{
+
+#ifdef _DEBUG
+ SetThreadName(GetCurrentThreadId(), "omBrowserThread");
+ aTRACE_FMT("[%d] %S: thread created\r\n", GetCurrentThreadId(), OMBROWSER_NAME);
+#endif //_DEBUG
+
+ BROWSERTHREADCREATEPARAM *createParam = (BROWSERTHREADCREATEPARAM*)param;
+
+ HWND hWinamp = createParam->hWinamp;
+
+ BROWSERTHREAD thread;
+ ZeroMemory(&thread, sizeof(BROWSERTHREAD));
+
+ if (TLS_OUT_OF_INDEXES != tlsIndex)
+ Plugin_TlsSetValue(tlsIndex, &thread);
+
+ MSG msg;
+ PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
+
+ BTKEYFILTERPROC IsHostMessage = (NULL != createParam->fnKeyFilter) ? createParam->fnKeyFilter : BrowserThread_DefaultKeyFilter;
+
+ thread.messageHook = SetWindowsHookEx(WH_MSGFILTER, BrowserThread_MessageFilterProc, NULL, GetCurrentThreadId());
+ thread.wakeupEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ HWND hHost = createParam->fnCreateWnd(createParam->user);
+
+ createParam->hHost = hHost;
+
+#ifdef _DEBUG
+ if (NULL != hHost)
+ aTRACE_FMT("[%d] %S: host created\r\n", GetCurrentThreadId(), OMBROWSER_NAME);
+ else
+ aTRACE_FMT("[%d] %S: host creation fialed\r\n", GetCurrentThreadId(), OMBROWSER_NAME);
+#endif //_DEBUG
+
+ if (NULL != createParam->readyEvent)
+ SetEvent(createParam->readyEvent);
+
+
+ if (NULL != hHost && FAILED(OleInitialize(0)))
+ {
+ DestroyWindow(hHost);
+ hHost = NULL;
+ }
+
+ if (NULL == hHost)
+ {
+ BrowserThread_FinishThread(&thread);
+ return -1;
+ }
+
+ SendMessage(hHost, BTM_INITCONTAINER, (WPARAM)hWinamp, 0L);
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
+
+ while (0 == (BHTF_QUITLOOP & thread.flags))
+ {
+ DWORD status = MsgWaitForMultipleObjectsEx(1, &thread.wakeupEvent, INFINITE,
+ QS_ALLPOSTMESSAGE | QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
+
+ switch(status)
+ {
+ case (WAIT_OBJECT_0 + 0):
+ // wake up!!!
+ break;
+
+ case (WAIT_OBJECT_0 + 1):
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ if (!CallMsgFilter(&msg, MSGF_BROWSERLOOP) && NULL != msg.hwnd)
+ {
+ if (0 == (BHTF_BEGINDESTROY & thread.flags))
+ {
+ if (FALSE == BrowserThread_ProcessMessage(hHost, hWinamp, &msg, IsHostMessage))
+ {
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
+ }
+ else
+ {
+ DispatchMessageW(&msg);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ BrowserThread_FinishThread(&thread);
+ return 0;
+}
+
+INT BrowserThread_ModalLoop(HWND hwnd, HANDLE hCancel, DWORD timeout)
+{
+ MSG msg;
+ for (;;)
+ {
+ DWORD status = MsgWaitForMultipleObjectsEx(1, &hCancel, timeout, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
+ if (WAIT_OBJECT_0 == status)
+ {
+ return 0;
+ }
+ else if ((WAIT_OBJECT_0 + 1) == status)
+ {
+ while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ if (msg.message == WM_QUIT)
+ {
+ PostQuitMessage((INT)msg.wParam);
+ return (INT)msg.wParam;
+ }
+
+ if (!IsDialogMessageW(hwnd, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
+ }
+ }
+ }
+
+ return 0;
+} \ No newline at end of file
diff --git a/Src/omBrowser/browserThread.h b/Src/omBrowser/browserThread.h
new file mode 100644
index 00000000..b80704f6
--- /dev/null
+++ b/Src/omBrowser/browserThread.h
@@ -0,0 +1,34 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_BROWSERTHREAD_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_BROWSERTHREAD_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+interface IWebBrowser2;
+
+#define MSGF_BROWSERLOOP (MSGF_USER + 1)
+
+#define BHTF_QUITLOOP 0x00000001
+#define BHTF_BEGINDESTROY 0x00000002
+
+typedef HWND (CALLBACK *BTCREATEWNDPROC)(ULONG_PTR /*user*/);
+typedef BOOL (CALLBACK *BTKEYFILTERPROC)(HWND /*hwnd*/, MSG* /*pMsg*/);
+
+HANDLE BrowserThread_Create(HWND hWinamp, BTCREATEWNDPROC fnCreateWnd, ULONG_PTR user, BTKEYFILTERPROC fnKeyFilter, HWND *pWnd, DWORD *pThreadId);
+
+BOOL BrowserThread_IsQuiting();
+BOOL BrowserThread_SetFlags(UINT flags, UINT flagsMask, BOOL fAlarm);
+BOOL BrowserThread_WaitNavigateComplete(IWebBrowser2 *pWeb2, UINT waitMax);
+BOOL BrowserThread_PostDestroy(HWND hHost);
+BOOL BrowserThread_PostDestroyEx(DWORD threadId, HWND hHost);
+INT BrowserThread_ModalLoop(HWND hwnd, HANDLE hCancel, DWORD timeout);
+
+
+#define BTM_FIRST (WM_APP - 10)
+#define BTM_INITCONTAINER (BTM_FIRST + 0) // wParam - not used, lParam - not used, return - ignored
+#define BTM_RELEASECONTAINER (BTM_FIRST + 1) // wParam - not used, lParam - not used; return - ignored;
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_BROWSERTHREAD_HEADER
diff --git a/Src/omBrowser/browserUiCommon.cpp b/Src/omBrowser/browserUiCommon.cpp
new file mode 100644
index 00000000..7dc59c69
--- /dev/null
+++ b/Src/omBrowser/browserUiCommon.cpp
@@ -0,0 +1,694 @@
+#include "main.h"
+#include "./browserUiCommon.h"
+#include "./browserUiInternal.h"
+
+#include "./toolbar.h"
+#include "./statusbar.h"
+#include "./curtain.h"
+#include "./browserHost.h"
+
+#include "./obj_ombrowser.h"
+#include "./ifc_omservice.h"
+#include "./ifc_omservicecommand.h"
+#include "./ifc_omtoolbarconfig.h"
+#include "./ifc_omstatusbarconfig.h"
+
+#include "./resource.h"
+
+#define IDC_OPERATIONWIDGET 0x1010
+
+static HACCEL commonTable = NULL;
+static HACCEL popupTable = NULL;
+static BOOL regiterUnload = TRUE;
+
+static void CALLBACK BrowserControl_OnPluginUnload()
+{
+ if (NULL != commonTable)
+ {
+ DestroyAcceleratorTable(commonTable);
+ commonTable = NULL;
+ }
+
+ if (NULL != popupTable)
+ {
+ DestroyAcceleratorTable(popupTable);
+ popupTable = NULL;
+ }
+}
+
+static HACCEL BrowserControl_LoadCommonAccel()
+{
+ if (NULL != commonTable)
+ return commonTable;
+
+ commonTable = Plugin_LoadAccelerators(MAKEINTRESOURCE(IDR_BROWSERACCEL));
+
+ if (FALSE != regiterUnload && NULL != commonTable)
+ {
+ Plugin_RegisterUnloadCallback(BrowserControl_OnPluginUnload);
+ regiterUnload = FALSE;
+ }
+
+ return commonTable;
+
+}
+
+static HACCEL BrowserControl_LoadPoppupAccel()
+{
+ if (NULL != popupTable)
+ return popupTable;
+
+ UINT cCommon, cPopup, cTotal = 0;
+
+ HACCEL hCommon = Plugin_LoadAccelerators(MAKEINTRESOURCE(IDR_BROWSERACCEL));
+ cCommon = (NULL != hCommon) ? CopyAcceleratorTable(hCommon, NULL, 0) : 0;
+
+ HACCEL hPopup = Plugin_LoadAccelerators(MAKEINTRESOURCE(IDR_BROWSERPOPUPACCEL));
+ cPopup = (NULL != hPopup) ? CopyAcceleratorTable(hPopup, NULL, 0) : 0;
+
+ cTotal += (cCommon + cPopup);
+ if (0 != cTotal)
+ {
+ ACCEL *pAccel = (ACCEL*)calloc(cTotal, sizeof(ACCEL));
+ if (NULL != pAccel)
+ {
+ UINT copied = 0;
+ if (NULL != hCommon)
+ copied += CopyAcceleratorTable(hCommon, pAccel + copied, cTotal - copied);
+
+ if (NULL != hPopup)
+ copied += CopyAcceleratorTable(hPopup, pAccel + copied, cTotal - copied);
+
+ if (0 != copied)
+ popupTable = CreateAcceleratorTable(pAccel, copied);
+
+ free(pAccel);
+ }
+ }
+
+ if (NULL != hCommon)
+ DestroyAcceleratorTable(hCommon);
+
+ if (NULL != hPopup)
+ DestroyAcceleratorTable(hPopup);
+
+ if (FALSE != regiterUnload && NULL != popupTable)
+ {
+ Plugin_RegisterUnloadCallback(BrowserControl_OnPluginUnload);
+ regiterUnload = FALSE;
+ }
+
+ return popupTable;
+
+}
+
+HACCEL BrowserControl_GetAccelTable(UINT tableType)
+{
+ switch(tableType)
+ {
+ case ACCELTABLE_VIEW:
+ return BrowserControl_LoadCommonAccel();
+ case ACCELTABLE_POPUP:
+ return BrowserControl_LoadPoppupAccel();
+ }
+ return NULL;
+}
+
+static void BrowserControl_ShowHistoryPopup(HWND hControl)
+{
+ HWND hBrowser = BrowserControl_GetHost(hControl);
+ if (NULL == hBrowser) return;
+
+ UINT flags = TPM_LEFTALIGN;
+ POINT pt = {0, 0};
+
+ BOOL fUseHost = TRUE;;
+ HWND hToolbar = BrowserControl_GetToolbar(hControl);
+ DWORD toolbarStyle = (NULL != hToolbar) ? GetWindowStyle(hToolbar) : 0;
+
+ if (NULL != hToolbar && 0 != (WS_VISIBLE & toolbarStyle))
+ {
+ fUseHost = FALSE;
+ RECT toolbarRect;
+ GetWindowRect(hToolbar, &toolbarRect);
+ pt.x = toolbarRect.left + 2;
+ if (0 != (TBS_BOTTOMDOCK & toolbarStyle))
+ {
+ pt.y = toolbarRect.top + 1;
+ flags |= TPM_VERNEGANIMATION | TPM_BOTTOMALIGN;
+ }
+ else
+ {
+ pt.y = toolbarRect.bottom - 1;
+ flags |= TPM_VERPOSANIMATION | TPM_TOPALIGN;
+ }
+ }
+
+ if (FALSE != fUseHost)
+ {
+ RECT windowRect;
+ GetClientRect(hControl, &windowRect);
+ pt.x = windowRect.left;
+ pt.y = windowRect.top;
+ MapWindowPoints(hControl, HWND_DESKTOP, &pt, 1);
+ flags |= TPM_VERPOSANIMATION | TPM_TOPALIGN;
+ }
+
+ if (NULL != hToolbar && 0 != (TBS_AUTOHIDE & toolbarStyle))
+ SetWindowLongPtr(hToolbar, GWL_STYLE, toolbarStyle & ~TBS_AUTOHIDE);
+
+ HWND hStatusbar = BrowserControl_GetStatusbar(hControl);
+ DWORD statusStyle = (NULL != hStatusbar) ? GetWindowStyle(hStatusbar) : 0;
+ if (NULL != hStatusbar && 0 == (WS_DISABLED & statusStyle))
+ SetWindowLongPtr(hStatusbar, GWL_STYLE, WS_DISABLED | statusStyle);
+
+ SendMessage(hBrowser, NBHM_SHOWHISTORYPOPUP, (WPARAM)flags, MAKELPARAM(pt.x, pt.y));
+
+ if (NULL != hToolbar && 0 != (TBS_AUTOHIDE & toolbarStyle))
+ {
+ SetWindowLongPtr(hToolbar, GWL_STYLE, toolbarStyle);
+ TRACKMOUSEEVENT tm;
+ tm.cbSize = sizeof(TRACKMOUSEEVENT);
+ tm.dwFlags = TME_LEAVE;
+ tm.hwndTrack = hToolbar;
+ TrackMouseEvent(&tm);
+ }
+
+ if (NULL != hStatusbar && 0 == (WS_DISABLED & statusStyle))
+ SetWindowLongPtr(hStatusbar, GWL_STYLE, statusStyle);
+}
+
+static BOOL BrowserControl_ExecServiceCommand(HWND hControl, ifc_omservicecommand *command, const GUID *group, UINT id, ULONG_PTR arg)
+{
+ if (NULL == command) return FALSE;
+
+ HRESULT state = command->QueryState(hControl, group, id);
+ if (CMDSTATE_ENABLED == state)
+ {
+ command->Exec(hControl, group, id, arg);
+ return TRUE;
+ }
+ return (CMDSTATE_DISABLED == state) ? TRUE : FALSE;
+}
+
+BOOL BrowserControl_ProcessCommonCommand(HWND hControl, INT commandId)
+{
+ if (NULL == hControl)
+ return FALSE;
+
+ UINT controlStyle = GetWindowStyle(hControl);
+ ifc_omservice *service;
+ if (0 != (NBCS_NOSERVICECOMMANDS & controlStyle) ||
+ FALSE == BrowserControl_GetService(hControl, &service))
+ {
+ service = NULL;
+ }
+
+ ifc_omservicecommand *serviceCommand;
+ if (NULL == service ||
+ FAILED(service->QueryInterface(IFC_OmServiceCommand, (void**)&serviceCommand)))
+ {
+ serviceCommand = NULL;
+ }
+
+ BOOL fProcessed = FALSE;
+
+ switch(commandId)
+ {
+ case ID_NAVIGATION_HOME:
+ if (FALSE == BrowserControl_ExecServiceCommand(hControl, serviceCommand, &CMDGROUP_NAVIGATION, NAVCOMMAND_HOME, 0))
+ BrowserControl_Navigate(hControl, NAVIGATE_HOME, 0L);
+ fProcessed = TRUE;
+ break;
+
+ case ID_NAVIGATION_BACK:
+ if (FALSE == BrowserControl_ExecServiceCommand(hControl, serviceCommand, &CMDGROUP_NAVIGATION, NAVCOMMAND_BACKFORWARD, FALSE))
+ BrowserControl_Navigate(hControl, NAVIGATE_BACK, 0L);
+ fProcessed = TRUE;
+ break;
+
+ case ID_NAVIGATION_FORWARD:
+ if (FALSE == BrowserControl_ExecServiceCommand(hControl, serviceCommand, &CMDGROUP_NAVIGATION, NAVCOMMAND_BACKFORWARD, TRUE))
+ BrowserControl_Navigate(hControl, NAVIGATE_FORWARD, 0L);
+ fProcessed = TRUE;
+ break;
+
+ case ID_NAVIGATION_REFRESH:
+ if (FALSE == BrowserControl_ExecServiceCommand(hControl, serviceCommand, &CMDGROUP_NAVIGATION, NAVCOMMAND_REFRESH, FALSE))
+ BrowserControl_Navigate(hControl, NAVIGATE_REFRESH, 0L);
+ fProcessed = TRUE;
+ break;
+
+ case ID_NAVIGATION_REFRESH_COMPLETELY:
+ if (FALSE == BrowserControl_ExecServiceCommand(hControl, serviceCommand, &CMDGROUP_NAVIGATION, NAVCOMMAND_REFRESH, TRUE))
+ BrowserControl_Navigate(hControl, NAVIGATE_REFRESH_COMPLETELY, 0L);
+ fProcessed = TRUE;
+ break;
+
+ case ID_NAVIGATION_STOP:
+ if (FALSE == BrowserControl_ExecServiceCommand(hControl, serviceCommand, &CMDGROUP_NAVIGATION, NAVCOMMAND_STOP, 0L))
+ BrowserControl_Navigate(hControl, NAVIGATE_STOP, 0L);
+ fProcessed = TRUE;
+ break;
+
+ case ID_NAVIGATION_HISTORY:
+ if (FALSE == BrowserControl_ExecServiceCommand(hControl, serviceCommand, &CMDGROUP_NAVIGATION, NAVCOMMAND_HISTORY, 0L))
+ BrowserControl_ShowHistoryPopup(hControl);
+ fProcessed = TRUE;
+ break;
+
+ case ID_SERVICE_GETINFO:
+ BrowserControl_ExecServiceCommand(hControl, serviceCommand, &CMDGROUP_SERVICE, SVCCOMMAND_SHOWINFO, 0);
+ fProcessed = TRUE;
+ break;
+
+ case ID_SERVICE_REPORT:
+ BrowserControl_ExecServiceCommand(hControl, serviceCommand, &CMDGROUP_SERVICE, SVCCOMMAND_REPORT, 0);
+ fProcessed = TRUE;
+ break;
+
+ case ID_SERVICE_UNSUBSCRIBE:
+ BrowserControl_ExecServiceCommand(hControl, serviceCommand, &CMDGROUP_SERVICE, SVCCOMMAND_UNSUBSCRIBE, 0);
+ fProcessed = TRUE;
+ break;
+
+ case ID_RATING_VALUE_1:
+ BrowserControl_ExecServiceCommand(hControl, serviceCommand, &CMDGROUP_SERVICE, SVCCOMMAND_RATE, 1);
+ fProcessed = TRUE;
+ break;
+
+ case ID_RATING_VALUE_2:
+ BrowserControl_ExecServiceCommand(hControl, serviceCommand, &CMDGROUP_SERVICE, SVCCOMMAND_RATE, 2);
+ fProcessed = TRUE;
+ break;
+
+ case ID_RATING_VALUE_3:
+ BrowserControl_ExecServiceCommand(hControl, serviceCommand, &CMDGROUP_SERVICE, SVCCOMMAND_RATE, 3);
+ fProcessed = TRUE;
+ break;
+
+ case ID_RATING_VALUE_4:
+ BrowserControl_ExecServiceCommand(hControl, serviceCommand, &CMDGROUP_SERVICE, SVCCOMMAND_RATE, 4);
+ fProcessed = TRUE;
+ break;
+
+ case ID_RATING_VALUE_5:
+ BrowserControl_ExecServiceCommand(hControl, serviceCommand, &CMDGROUP_SERVICE, SVCCOMMAND_RATE, 5);
+ fProcessed = TRUE;
+ break;
+
+ case ID_WINDOW_CLOSE:
+ if (FALSE != BrowserControl_ExecServiceCommand(hControl, serviceCommand, &CMDGROUP_WINDOW, WNDCOMMAND_CLOSE, 0))
+ fProcessed = TRUE;
+ break;
+
+ case ID_WINDOW_FULLSCREEN:
+ if (FALSE != BrowserControl_ExecServiceCommand(hControl, serviceCommand, &CMDGROUP_WINDOW, WNDCOMMAND_FULLSCREEN, 0))
+ fProcessed = TRUE;
+ break;
+ case ID_ADDRESSBAR_ACTIVATE:
+ {
+ HWND hToolbar = BrowserControl_GetToolbar(hControl);
+ if(NULL != hToolbar)
+ {
+ Toolbar_NextItem(hToolbar, TOOLITEM_ADDRESSBAR, TRUE);
+ }
+ }
+ fProcessed = TRUE;
+ break;
+ case ID_ADDRESSBAR_CHANGED:
+ {
+ HWND hToolbar = BrowserControl_GetToolbar(hControl);
+ if(NULL != hToolbar)
+ {
+ INT itemId = Toolbar_FindItem(hToolbar, TOOLITEM_ADDRESSBAR);
+ if (ITEM_ERR != itemId)
+ {
+ size_t cchBufferMax;
+ if (FALSE == Toolbar_GetTextLength(hToolbar, MAKEINTRESOURCE(itemId), &cchBufferMax))
+ cchBufferMax = 8192;
+
+ cchBufferMax++;
+ LPWSTR pszBuffer = Plugin_MallocString(cchBufferMax);
+ if (NULL != pszBuffer)
+ {
+ TBITEMINFO itemInfo;
+ ZeroMemory(&itemInfo, sizeof(itemInfo));
+
+
+ itemInfo.pszText = pszBuffer;
+ itemInfo.cchText = (INT)cchBufferMax;
+ if (FALSE != Toolbar_GetItemInfo(hToolbar, MAKEINTRESOURCE(itemId), &itemInfo))
+ {
+ if (FALSE == BrowserControl_ExecServiceCommand(hControl, serviceCommand,
+ &CMDGROUP_ADDRESSBAR, ADDRESSCOMMAND_EXECUTE, (ULONG_PTR)itemInfo.pszText))
+ {
+ BrowserControl_Navigate(hControl, NAVIGATE_STOP, 0L);
+ BrowserControl_Navigate(hControl, itemInfo.pszText, 0L);
+ }
+ }
+
+ Plugin_FreeString(pszBuffer);
+ }
+ }
+ }
+ }
+ fProcessed = TRUE;
+ break;
+ }
+
+ if (NULL != serviceCommand)
+ serviceCommand->Release();
+
+ if (NULL != service)
+ service->Release();
+
+ return fProcessed;
+}
+
+BOOL BrowserControl_ProcessStatusbarCommand(HWND hControl, INT commandId)
+{
+ HWND hStatusbar = BrowserControl_GetStatusbar(hControl);
+ if (NULL == hStatusbar) return FALSE;
+
+ BOOL fProcessed = FALSE;
+ obj_ombrowser *browserManager;
+ if (FALSE != BrowserControl_GetBrowserObject(hControl, &browserManager) && NULL != browserManager)
+ {
+ ifc_omstatusbarconfig *statusbarConfig;
+
+ if (SUCCEEDED(browserManager->GetConfig(&IFC_OmStatusbarConfig, (void**)&statusbarConfig)))
+ {
+ UINT statusbarStyle = GetWindowStyle(hStatusbar);
+ switch(commandId)
+ {
+ case SBN_ENABLECHANGED:
+ statusbarConfig->EnableStatusbar(0 == (WS_DISABLED & statusbarStyle));
+ fProcessed = TRUE;
+ break;
+ }
+ statusbarConfig->Release();
+ }
+ browserManager->Release();
+ }
+ return fProcessed;
+}
+
+BOOL BrowserControl_ProcessToolbarCommand(HWND hControl, INT commandId)
+{
+ HWND hToolbar = BrowserControl_GetToolbar(hControl);
+ if (NULL == hToolbar) return FALSE;
+
+ BOOL fProcessed = FALSE;
+ obj_ombrowser *browserManager;
+ if (FALSE != BrowserControl_GetBrowserObject(hControl, &browserManager) && NULL != browserManager)
+ {
+ ifc_omtoolbarconfig *toolbarConfig;
+
+ if (SUCCEEDED(browserManager->GetConfig(&IFC_OmToolbarConfig, (void**)&toolbarConfig)))
+ {
+ UINT toolbarStyle = GetWindowStyle(hToolbar);
+ switch(commandId)
+ {
+ case TBN_DOCKCHANGED:
+ toolbarConfig->EnableBottomDock(0 != (TBS_BOTTOMDOCK & toolbarStyle));
+ fProcessed = TRUE;
+ break;
+ case TBN_AUTOHIDECHANGED:
+ toolbarConfig->EnableAutoHide(0 != (TBS_AUTOHIDE & toolbarStyle));
+ fProcessed = TRUE;
+ break;
+ case TBN_TABSTOPCHANGED:
+ toolbarConfig->EnableTabStop(0 != (TBS_TABSTOP & toolbarStyle));
+ fProcessed = TRUE;
+ break;
+ }
+ toolbarConfig->Release();
+ }
+ browserManager->Release();
+ }
+ return fProcessed;
+}
+
+BOOL BrowserControl_ProcessAppCommand(HWND hControl, INT commandId)
+{
+ if (NULL == hControl)
+ return FALSE;
+
+ switch(commandId)
+ {
+ case APPCOMMAND_BROWSER_BACKWARD: BrowserControl_ProcessCommonCommand(hControl, ID_NAVIGATION_BACK); return TRUE;
+ case APPCOMMAND_BROWSER_FORWARD: BrowserControl_ProcessCommonCommand(hControl, ID_NAVIGATION_FORWARD); return TRUE;
+ case APPCOMMAND_BROWSER_HOME: BrowserControl_ProcessCommonCommand(hControl, ID_NAVIGATION_HOME); return TRUE;
+ case APPCOMMAND_BROWSER_REFRESH: BrowserControl_ProcessCommonCommand(hControl, ID_NAVIGATION_REFRESH); return TRUE;
+ case APPCOMMAND_BROWSER_STOP: BrowserControl_ProcessCommonCommand(hControl, ID_NAVIGATION_STOP); return TRUE;
+ case APPCOMMAND_BROWSER_FAVORITES: return TRUE;
+ case APPCOMMAND_BROWSER_SEARCH: return TRUE;
+ }
+
+ return FALSE;
+}
+
+HWND BrowserControl_GetOperationWidget(HWND hControl)
+{
+ return GetDlgItem(hControl, IDC_OPERATIONWIDGET);
+}
+
+HWND BrowserControl_CreateOperationWidget(HWND hControl)
+{
+ if (FALSE == Curtain_RegisterClass(Plugin_GetInstance()))
+ return NULL;
+
+ RECT rc;
+ HWND hTarget = BrowserControl_GetHost(hControl);
+ if (NULL == hTarget) hTarget = hControl;
+
+ if (FALSE == GetWindowRect(hTarget, &rc))
+ return NULL;
+
+ MapWindowPoints(HWND_DESKTOP, hControl, (POINT*)&rc, 2);
+
+
+ HWND hWidget = CreateWindowEx(WS_EX_NOPARENTNOTIFY | WS_EX_CONTROLPARENT,
+ NWC_ONLINEMEDIACURTAIN, NULL, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS /*| WS_VISIBLE*/,
+ rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hControl,
+ (HMENU)IDC_OPERATIONWIDGET, Plugin_GetInstance(), NULL);
+
+
+ return hWidget;
+
+}
+
+BOOL BrowserControl_OnShowOperation(HWND hControl, OPERATIONINFO *poi)
+{
+ if (NULL == poi) return FALSE;
+ if (poi->cbSize != sizeof(OPERATIONINFO))
+ return FALSE;
+
+ BOOL updateSkin = FALSE;
+ HWND hWidget = BrowserControl_GetOperationWidget(hControl);
+
+ if (0 != (NBCOM_FLAGS & poi->mask))
+ {
+ if (0 != (NBCOF_SHOWWIDGET & poi->flags))
+ {
+ if (NULL == hWidget)
+ {
+ hWidget = BrowserControl_CreateOperationWidget(hControl);
+ if (NULL != hWidget)
+ updateSkin = TRUE;
+ }
+ }
+
+ if (0 != (NBCOF_HIDEWIDGET & poi->flags))
+ {
+ if (NULL != hWidget)
+ {
+ DestroyWindow(hWidget);
+ hWidget = NULL;
+
+ SetWindowPos(hControl, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE |
+ SWP_FRAMECHANGED | SWP_ASYNCWINDOWPOS | SWP_DEFERERASE);
+ }
+ }
+ }
+
+
+ if (0 != (NBCOM_TITLE & poi->mask))
+ {
+ if (NULL != hWidget)
+ SetWindowText(hWidget, poi->title);
+ }
+
+ if (0 != (NBCOM_TEXT & poi->mask))
+ {
+ if (NULL != hWidget)
+ Curtain_SetOperationText(hWidget, poi->text);
+ }
+
+ if (NULL != hWidget && 0 != (NBCOM_FLAGS & poi->mask) && 0 != (NBCOF_SHOWWIDGET & poi->flags))
+ {
+ if (FALSE != updateSkin)
+ {
+ PostMessage(hWidget, CWM_UPDATESKIN, 0, 0L);
+ SetWindowPos(hControl, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE |
+ SWP_FRAMECHANGED | SWP_ASYNCWINDOWPOS | SWP_DEFERERASE);
+ }
+
+ ShowWindowAsync(hWidget, SW_SHOWNA);
+ }
+
+ return TRUE;
+}
+
+
+BOOL BrowserControl_UpdateLayout(HWND hControl, BOOL fRedraw, BOOL fFrame, HRGN updateRegion, const POINT *updateOffset)
+{
+ RECT clientRect;
+ if (!GetClientRect(hControl, &clientRect))
+ return FALSE;
+
+ UINT uFlags = SWP_NOZORDER | SWP_NOACTIVATE;
+ if (FALSE == fRedraw) uFlags |= SWP_NOREDRAW;
+ if (FALSE != fFrame) uFlags |= SWP_FRAMECHANGED;
+
+ HWND hToolbar, hBrowser, hStatusbar, hWidget;
+
+ BOOL toolbarSet = FALSE;
+ TOOLBARLAYOUT layout;
+ layout.prcParent = &clientRect;
+
+ HDWP hdwp = BeginDeferWindowPos(2);
+ if (NULL == hdwp) return FALSE;
+
+ if (NULL != (hToolbar = BrowserControl_GetToolbar(hControl)))
+ {
+ if (Toolbar_Layout(hToolbar, &layout))
+ {
+ toolbarSet = TRUE;
+ hdwp = DeferWindowPos(hdwp, hToolbar, layout.insertAfter, layout.toolbarRect.left, layout.toolbarRect.top,
+ layout.toolbarRect.right - layout.toolbarRect.left,
+ layout.toolbarRect.bottom - layout.toolbarRect.top, uFlags & ~SWP_NOZORDER);
+ if (NULL == hdwp) return FALSE;
+ }
+ }
+
+ if (FALSE == toolbarSet)
+ CopyRect(&layout.clientRect, layout.prcParent);
+
+ if (NULL != (hBrowser = BrowserControl_GetHost(hControl)))
+ {
+ if (0 != (NBHS_BROWSERREADY & GetWindowStyle(hBrowser)))
+ {
+ SetWindowPos(hBrowser, NULL, layout.clientRect.left, layout.clientRect.top,
+ layout.clientRect.right - layout.clientRect.left, layout.clientRect.bottom - layout.clientRect.top,
+ uFlags | SWP_ASYNCWINDOWPOS | SWP_DEFERERASE);
+ }
+ }
+
+ if (NULL != (hWidget = BrowserControl_GetOperationWidget(hControl)))
+ {
+ HWND hInsertAfter;
+ if (NULL != hBrowser) hInsertAfter = GetWindow(hBrowser, GW_HWNDPREV);
+ else if( NULL != hToolbar) hInsertAfter = GetWindow(hBrowser, GW_HWNDPREV);
+ else hInsertAfter = HWND_TOP;
+
+ UINT flags;
+ flags = uFlags;
+ if (hInsertAfter != hWidget)
+ flags &= ~SWP_NOZORDER;
+
+ hdwp = DeferWindowPos(hdwp, hWidget, hInsertAfter, layout.clientRect.left, layout.clientRect.top,
+ layout.clientRect.right - layout.clientRect.left, layout.clientRect.bottom - layout.clientRect.top, flags);
+
+ if (NULL == hdwp) return FALSE;
+ }
+
+ EndDeferWindowPos(hdwp);
+
+
+ if (NULL != (hStatusbar = BrowserControl_GetStatusbar(hControl)))
+ Statusbar_SetParentRect(hStatusbar, &layout.clientRect);
+
+////////////////////////////////////
+
+ if (NULL != updateRegion)
+ {
+ RECT rect;
+ HRGN rgnValid = NULL;
+
+ if (NULL != hBrowser && 0 != (WS_VISIBLE & GetWindowStyle(hBrowser)) &&
+ FALSE != GetWindowRect(hBrowser, &rect))
+ {
+ MapWindowPoints(HWND_DESKTOP, hControl, (POINT*)&rect, 2);
+ rgnValid = CreateRectRgnIndirect(&rect);
+ }
+
+ if (NULL != rgnValid)
+ {
+ HRGN rgn = NULL;
+ HWND szControls[] = {hToolbar, hStatusbar, hWidget};
+ for (INT i = 0; i < ARRAYSIZE(szControls); i++)
+ {
+ if (NULL != szControls[i] && 0 != (WS_VISIBLE & GetWindowStyle(szControls[i])) &&
+ FALSE != GetWindowRect(szControls[i], &rect))
+ {
+ MapWindowPoints(HWND_DESKTOP, hControl, (POINT*)&rect, 2);
+ if (NULL == rgn) rgn = CreateRectRgnIndirect(&rect);
+ else SetRectRgn(rgn, rect.left, rect.top, rect.right, rect.bottom);
+
+ if (NULL != rgn)
+ CombineRgn(rgnValid, rgnValid, rgn, RGN_DIFF);
+ }
+ }
+
+ if (NULL != updateOffset)
+ OffsetRgn(rgnValid, -updateOffset->x, -updateOffset->y);
+
+ CombineRgn(updateRegion, updateRegion, rgnValid, RGN_DIFF);
+ if (NULL != rgn) DeleteObject(rgn);
+ DeleteObject(rgnValid);
+ }
+ }
+
+ return TRUE;
+}
+
+BOOL BrowserControl_EnableChildren(HWND hControl, BOOL fEnable)
+{
+ HWND hChild;
+ if (NULL != (hChild = BrowserControl_GetHost(hControl)))
+ PostMessage(hChild, NBHM_ENABLEWINDOW, 0, fEnable);
+
+ if (NULL != (hChild = BrowserControl_GetToolbar(hControl)))
+ EnableWindow(hChild, fEnable);
+
+ if (NULL != (hChild = BrowserControl_GetStatusbar(hControl)))
+ EnableWindow(hChild, fEnable);
+
+ return TRUE;
+}
+
+BOOL BrowserControl_SetBlockedState(HWND hControl, BOOL fBlocked)
+{
+ if (NULL == hControl)
+ return FALSE;
+
+ UINT prevStyle = BrowserControl_SetExtendedStyle(hControl, NBCS_EX_BLOCKNAVIGATION, (FALSE != fBlocked) ? NBCS_EX_BLOCKNAVIGATION : 0);
+ if (FALSE != fBlocked)
+ {
+ if (0 == (NBCS_EX_BLOCKNAVIGATION & prevStyle))
+ {
+ BrowserControl_EnableChildren(hControl, FALSE);
+ }
+ }
+ else
+ {
+ if (0 != (NBCS_EX_BLOCKNAVIGATION & prevStyle))
+ {
+ BrowserControl_EnableChildren(hControl, TRUE);
+ }
+ BrowserControl_NavigateStoredUrl(hControl);
+ }
+ return TRUE;
+} \ No newline at end of file
diff --git a/Src/omBrowser/browserUiCommon.h b/Src/omBrowser/browserUiCommon.h
new file mode 100644
index 00000000..5a29ea49
--- /dev/null
+++ b/Src/omBrowser/browserUiCommon.h
@@ -0,0 +1,111 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_UI_COMMON_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_UI_COMMON_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+class ifc_omservice;
+
+
+// styles
+#define NBCS_DISABLEHOSTCSS 0x00000001 // no coloring
+#define NBCS_POPUPOWNER 0x00000002 // every created popup owner by window
+#define NBCS_DISABLEFULLSCREEN 0x00000004 // disable fullscreen mode (popup only)
+#define NBCS_NOTOOLBAR 0x00000100 // force no toolbar
+#define NBCS_NOSTATUSBAR 0x00000200 // force no statusbar
+#define NBCS_NOSERVICECOMMANDS 0x00000400 // force disable service commands
+#define NBCS_DISABLECONTEXTMENU 0x00001000 // disable context menu
+#define NBCS_DIALOGMODE 0x00002000 // enable dialog mode
+#define NBCS_BLOCKPOPUP 0x00004000 // block any popup creation
+
+
+
+// messages
+#define NBCM_FIRST (WM_USER + 20)
+#define NBVM_FIRST (NBCM_FIRST + 100)
+#define NBPM_FIRST (NBCM_FIRST + 200)
+
+#define NBCM_GETTOOLBAR (NBCM_FIRST + 1) // wParam - not used; lParam - not used; Return: toolbar hwnd.
+#define BrowserControl_GetToolbar(/*HWND*/ __hwndControl)\
+ ((HWND)SENDMSG((__hwndControl), NBCM_GETTOOLBAR, 0, 0L))
+
+#define NBCM_GETSTATUSBAR (NBCM_FIRST + 2) // wParam - not used; lParam - not used; Return: statusbar hwnd.
+#define BrowserControl_GetStatusbar(/*HWND*/ __hwndControl)\
+ ((HWND)SENDMSG((__hwndControl), NBCM_GETSTATUSBAR, 0, 0L))
+
+#define NBCM_UPDATESKIN (NBCM_FIRST + 3) // wParam - not used; lParam - (LPARAM)(BOOL)fRedraw; Return: not used.
+#define BrowserControl_UpdateSkin(/*HWND*/ __hwndControl, /*BOOL*/ __fRedraw)\
+ (SENDMSG((__hwndControl), NBCM_UPDATESKIN, 0, (LPARAM)(__fRedraw)))
+
+#define NBCM_GETSERVICE (NBCM_FIRST + 4) // wParam - not used; lParam = (LPARAM)(ifc_omservice**)serviceOut; Return: TRUE on success.
+#define BrowserControl_GetService(/*HWND*/ __hwndControl, /*ifc_omservice** */ __serviceOut)\
+ ((BOOL)SENDMSG((__hwndControl), NBCM_GETSERVICE, 0, (LPARAM)(__serviceOut)))
+
+#define NAVIGATE_BLANK MAKEINTRESOURCEW(0)
+#define NAVIGATE_HOME MAKEINTRESOURCEW(1)
+#define NAVIGATE_BACK MAKEINTRESOURCEW(2)
+#define NAVIGATE_FORWARD MAKEINTRESOURCEW(3)
+#define NAVIGATE_REFRESH MAKEINTRESOURCEW(4)
+#define NAVIGATE_STOP MAKEINTRESOURCEW(5)
+#define NAVIGATE_REFRESH_COMPLETELY MAKEINTRESOURCEW(6)
+
+#define NBCM_NAVIGATE (NBCM_FIRST + 5) // wParam = (WPARAM)(BOOL)fScheduleIfBlocked; lParam = (LPARAM)(LPWSTR)navigateUrl; Return: TRUE on success.
+#define BrowserControl_Navigate(/*HWND*/ __hwndControl, /*LPCWSTR*/ __navigateUrl, /*BOOL*/ __scheduleBlocked)\
+ ((BOOL)SENDMSG((__hwndControl), NBCM_NAVIGATE, (WPARAM)__scheduleBlocked, (LPARAM)(__navigateUrl)))
+
+
+#define NBCM_WRITEDOCUMENT (NBCM_FIRST + 6) // wParam = (WPARAM)(BOOL)fScheduleIfBlocked; lParam = (LPARAM)(BSTR)documentData; Return: TRUE on success.
+#define BrowserControl_WriteDocument(/*HWND*/ __hwndControl, /*BSTR*/ __documentData, /*BOOL*/ __scheduleBlocked)\
+ ((BOOL)SENDMSG((__hwndControl), NBCM_WRITEDOCUMENT, (WPARAM)__scheduleBlocked, (LPARAM)(__documentData)))
+
+#define NBCM_GETHOST (NBCM_FIRST + 7) // wParam - not used; lParam - not used; Return: host hwnd.
+#define BrowserControl_GetHost(/*HWND*/ __hwndControl)\
+ ((HWND)SENDMSG((__hwndControl), NBCM_GETHOST, 0, 0L))
+
+#define NBCM_GETBROWSEROBJECT (NBCM_FIRST + 8) // wParam - not used; lParam = (LPARAM)(obj_ombrowser**)browserOut; Return: TRUE on success.
+#define BrowserControl_GetBrowserObject(/*HWND*/ __hwndControl, /*obj_ombrowser** */ __browserOut)\
+ ((BOOL)SENDMSG((__hwndControl), NBCM_GETBROWSEROBJECT, 0, (LPARAM)(__browserOut)))
+
+// operation flags
+#define NBCOF_HIDEWIDGET 0x00000001
+#define NBCOF_SHOWWIDGET 0x00000002
+
+
+// operation valid fields mask
+#define NBCOM_FLAGS 0x00000001
+#define NBCOM_TITLE 0x00000002
+#define NBCOM_TEXT 0x00000004
+
+typedef struct __OPERATIONINFO
+{
+ UINT cbSize; //sizeof(OPERATIONINFO)
+ UINT mask; //
+ UINT flags; // show flags;
+ LPCWSTR title; // operation title
+ LPCWSTR text; // operation text
+} OPERATIONINFO;
+
+#define NBCM_SHOWOPERATION (NBCM_FIRST + 9) // wParam - not sued, lParam - (LPARAM)(OPERATIONINFO*)__pOperationInfo.
+#define BrowserControl_ShowOperation(/*HWND*/ __hwndControl, /*const OPERATIONINFO* */ __pOperationInfo)\
+ ((BOOL)SENDMSG((__hwndControl), NBCM_SHOWOPERATION, 0, (LPARAM)(__pOperationInfo)))
+
+#define NBCM_NAVSTOREDURL (NBCM_FIRST + 10) // wParam - not used, lParam - not used
+#define BrowserControl_NavigateStoredUrl(/*HWND*/ __hwndControl)\
+ ((BOOL)SNDMSG((__hwndControl), NBCM_NAVSTOREDURL, 0, 0L))
+
+#define NBCM_BLOCK (NBCM_FIRST + 11) //wParam - not used, lParam = (LPARAM)(BOOL)fBlock;
+#define BrowserControl_Block(/*HWND*/ __hwndControl, /*BOOL*/ __fBlock)\
+ (SNDMSG((__hwndControl), NBCM_BLOCK, 0, (LPARAM)(__fBlock)))
+
+#define NBCM_SETEXTSTYLE (NBCM_FIRST + 12) //wParam = (WPARAM)(UINT)extMask, lParam = (LPARAM)(UINT)extStyle; Return UINT with prevoius extended style
+#define BrowserControl_SetExtendedStyle(/*HWND*/ __hwndControl, /*UINT*/ __extMask, /*UINT*/__extStyle)\
+ ((UINT)SNDMSG((__hwndControl), NBCM_SETEXTSTYLE, (WPARAM)(__extMask), (LPARAM)(__extStyle)))
+
+#define NBCM_GETEXTSTYLE (NBCM_FIRST + 13) //wParam - not used, lParam - not used; Return UINT extended style.
+#define BrowserControl_GetExtendedStyle(/*HWND*/ __hwndControl)\
+ ((UINT)SNDMSG((__hwndControl), NBCM_GETTEXTSTYLE, 0, 0L))
+
+#endif // NULLSOFT_WINAMP_OMBROWSER_UI_COMMON_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/browserUiHook.cpp b/Src/omBrowser/browserUiHook.cpp
new file mode 100644
index 00000000..8d75c45a
--- /dev/null
+++ b/Src/omBrowser/browserUiHook.cpp
@@ -0,0 +1,321 @@
+#include "main.h"
+#include "./browserUiHook.h"
+#include "./browserUiCommon.h"
+#include "./browserUiInternal.h"
+#include "./browserPopup.h"
+#include "./browserHost.h"
+
+#include "./ifc_omservice.h"
+#include "./ifc_omserviceeventmngr.h"
+#include "./ifc_omservicecommand.h"
+#include "./ifc_omtoolbarconfig.h"
+#include "./ifc_omstatusbarconfig.h"
+#include "./ifc_omserviceeditor.h"
+#include "./ifc_omconfig.h"
+#include "./obj_ombrowser.h"
+
+#include "./toolbar.h"
+#include "./statusbar.h"
+
+#include "../winamp/IWasabiDispatchable.h"
+#include "../winamp/JSAPI_Info.h"
+
+#include <strsafe.h>
+
+BrowserUiHook::BrowserUiHook(HWND hTarget, BOOL fPopupMode)
+ : ref(1), popupMode(fPopupMode), hwnd(hTarget), winampCookie(NULL), configCookie(NULL)
+{
+}
+
+BrowserUiHook::~BrowserUiHook()
+{
+}
+
+HRESULT BrowserUiHook::CreateInstance(HWND hTarget, BOOL fPopupMode, BrowserUiHook **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ *instance = NULL;
+
+ if (NULL == hTarget || FALSE == IsWindow(hTarget))
+ return E_INVALIDARG;
+
+ *instance = new BrowserUiHook(hTarget, fPopupMode);
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t BrowserUiHook::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t BrowserUiHook::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int BrowserUiHook::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_WinampHook))
+ *object = static_cast<ifc_winamphook*>(this);
+ else if (IsEqualIID(interface_guid, IFC_OmServiceEvent))
+ *object = static_cast<ifc_omserviceevent*>(this);
+ else if (IsEqualIID(interface_guid, IFC_OmConfigCallback))
+ *object = static_cast<ifc_omconfigcallback*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+
+HRESULT BrowserUiHook::SkinChanging(void)
+{
+ if (FALSE != popupMode)
+ {
+ BrowserPopup_SkinRefreshing(hwnd);
+ PostMessage(hwnd, NBPM_SKINREFRESHED, 0, 0L);
+ }
+ return S_OK;
+}
+
+HRESULT BrowserUiHook::SkinChanged(const wchar_t *skinName)
+{
+ PostMessage(hwnd, NBCM_UPDATESKIN, 0, TRUE);
+ return S_OK;
+}
+
+HRESULT BrowserUiHook::SkinColorChange(const wchar_t *colorTheme)
+{
+ PostMessage(hwnd, NBCM_UPDATESKIN, 0, TRUE);
+ return S_OK;
+}
+
+HRESULT BrowserUiHook::ResetFont(void)
+{
+ PostMessage(hwnd, NBCM_UPDATESKIN, 0, TRUE);
+ return S_OK;
+}
+
+void BrowserUiHook::ServiceChange(ifc_omservice *service, UINT nModified)
+{
+ ifc_omservice *windowService;
+ if (FALSE == (BOOL)SendMessage(hwnd, NBCM_GETSERVICE, 0, (LPARAM)&windowService) || NULL == windowService)
+ return;
+
+ if (windowService != service) return;
+
+ if (0 != (ifc_omserviceeditor::modifiedName & nModified))
+ {
+ IDispatch *pDispatch;
+ if (SUCCEEDED(windowService->GetExternal(&pDispatch) && NULL != pDispatch))
+ {
+ IWasabiDispatchable *pWasabi;
+ if (SUCCEEDED(pDispatch->QueryInterface(IID_IWasabiDispatchable, (void**)&pWasabi)))
+ {
+ JSAPI::ifc_info *info = NULL;
+ if (SUCCEEDED(pWasabi->QueryDispatchable(JSAPI::IID_JSAPI_ifc_info, (Dispatchable**)&info)))
+ {
+ WCHAR szName[512] = {0};
+ if (FAILED(service->GetName(szName, ARRAYSIZE(szName))))
+ StringCchCopy(szName, ARRAYSIZE(szName), L"Unknown");
+
+ info->SetName(szName);
+ info->Release();
+ }
+ pWasabi->Release();
+ }
+ pDispatch->Release();
+ }
+
+ if (FALSE != popupMode)
+ PostMessage(hwnd, NBPM_REFRESHTITLE, 0, 0L);
+ }
+
+ if (0 != (ifc_omserviceeditor::modifiedRating & nModified))
+ {
+ HWND hToolbar = BrowserControl_GetToolbar(hwnd);
+ if (NULL != hToolbar)
+ {
+ UINT rating;
+ if(SUCCEEDED(service->GetRating(&rating)))
+ {
+ Toolbar_SetItemInt(hToolbar, TOOLITEM_USERRATING, rating);
+ }
+ }
+ }
+
+ if (0 != (ifc_omserviceeditor::modifiedGeneration & nModified))
+ {
+ HWND hHost = BrowserControl_GetHost(hwnd);
+ if (NULL != hHost) PostMessage(hHost, NBHM_UPDATEEXTERNAL, 0 , 0L);
+ }
+
+}
+
+void BrowserUiHook::CommandStateChange(ifc_omservice *service, const GUID *commandGroup, unsigned int commandId)
+{
+ if (NULL != commandGroup)
+ {
+ if (IsEqualGUID(CMDGROUP_SERVICE, *commandGroup))
+ {
+ switch(commandId)
+ {
+ case SVCCOMMAND_BLOCKNAV:
+ CheckBlockedState(service);
+ break;
+
+ }
+
+ }
+ }
+}
+
+HRESULT BrowserUiHook::ValueChanged(const GUID *configUid, UINT valueId, ULONG_PTR value)
+{
+ if (NULL == configUid)
+ return E_UNEXPECTED;
+
+ if (IsEqualIID(IFC_OmToolbarConfig, *configUid))
+ {
+ HWND hToolbar = (HWND)SendMessage(hwnd, NBCM_GETTOOLBAR, 0, 0L);
+ if (NULL == hToolbar) return S_FALSE;
+
+ switch(valueId)
+ {
+ case CFGID_TOOLBAR_BOTTOMDOCK: Toolbar_EnableBottomDock(hToolbar, (BOOL)value); break;
+ case CFGID_TOOLBAR_AUTOHIDE: Toolbar_EnableAutoHide(hToolbar, (BOOL)value); break;
+ case CFGID_TOOLBAR_TABSTOP: Toolbar_EnableTabStop(hToolbar, (BOOL)value); break;
+ case CFGID_TOOLBAR_FORCEADDRESS: Toolbar_EnableForceAddress(hToolbar, (BOOL)value); break;
+ case CFGID_TOOLBAR_FANCYADDRESS: Toolbar_EnableFancyAddress(hToolbar, (BOOL)value); break;
+ }
+ }
+ else if (IsEqualIID(IFC_OmStatusbarConfig, *configUid))
+ {
+ HWND hStatusbar = (HWND)SendMessage(hwnd, NBCM_GETSTATUSBAR, 0, 0L);
+ if (NULL == hStatusbar) return S_FALSE;
+
+ switch(valueId)
+ {
+ case CFGID_STATUSBAR_ENABLED: Statusbar_Enable(hStatusbar, (BOOL)value); break;
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT BrowserUiHook::Register(obj_ombrowser *browserManager, ifc_omservice *service)
+{
+
+ Plugin_RegisterWinampHook(this, &winampCookie);
+
+ ifc_omconfig *config;
+ if (NULL != browserManager && SUCCEEDED(browserManager->GetConfig(NULL, (void**)&config)))
+ {
+ config->RegisterCallback(this, &configCookie);
+ config->Release();
+ }
+
+ ifc_omserviceeventmngr *eventManager;
+ if (NULL != service && SUCCEEDED(service->QueryInterface(IFC_OmServiceEventMngr, (void**)&eventManager)))
+ {
+ eventManager->RegisterHandler(this);
+ eventManager->Release();
+ }
+
+ return S_OK;
+}
+
+HRESULT BrowserUiHook::Unregister(obj_ombrowser *browserManager, ifc_omservice *service)
+{
+ if (0 != configCookie)
+ {
+ ifc_omconfig *config;
+ if (NULL != browserManager && SUCCEEDED(browserManager->GetConfig(NULL, (void**)&config)))
+ {
+ config->UnregisterCallback(configCookie);
+ config->Release();
+ }
+ configCookie = 0;
+ }
+
+ ifc_omserviceeventmngr *eventManager;
+ if (NULL != service && SUCCEEDED(service->QueryInterface(IFC_OmServiceEventMngr, (void**)&eventManager)))
+ {
+ eventManager->UnregisterHandler(this);
+ eventManager->Release();
+ }
+
+
+ if (0 != winampCookie)
+ {
+ Plugin_UnregisterWinampHook(winampCookie);
+ winampCookie = 0;
+ }
+
+ return S_OK;
+}
+
+HRESULT BrowserUiHook::CheckBlockedState(ifc_omservice *service)
+{
+ if (NULL == service)
+ return E_INVALIDARG;
+
+ HRESULT hr;
+
+ ifc_omservicecommand *serviceCommand;
+ hr = service->QueryInterface(IFC_OmServiceCommand, (void**)&serviceCommand);
+ if (SUCCEEDED(hr))
+ {
+ HRESULT state = serviceCommand->QueryState(hwnd, &CMDGROUP_SERVICE, SVCCOMMAND_BLOCKNAV);
+ PostMessage(hwnd, NBCM_BLOCK, 0, (CMDSTATE_ENABLED == state));
+ serviceCommand->Release();
+ }
+ return hr;
+}
+
+#define CBCLASS BrowserUiHook
+START_MULTIPATCH;
+ START_PATCH(MPIID_WINAMPHOOK)
+ M_CB(MPIID_WINAMPHOOK, ifc_winamphook, ADDREF, AddRef);
+ M_CB(MPIID_WINAMPHOOK, ifc_winamphook, RELEASE, Release);
+ M_CB(MPIID_WINAMPHOOK, ifc_winamphook, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_WINAMPHOOK, ifc_winamphook, API_SKINCHANGING, SkinChanging);
+ M_CB(MPIID_WINAMPHOOK, ifc_winamphook, API_SKINCHANGED, SkinChanged);
+ M_CB(MPIID_WINAMPHOOK, ifc_winamphook, API_SKINCOLORCHANGE, SkinColorChange);
+ M_CB(MPIID_WINAMPHOOK, ifc_winamphook, API_RESETFONT, ResetFont);
+ NEXT_PATCH(MPIID_SERVICEEVENT)
+ M_CB(MPIID_SERVICEEVENT, ifc_omserviceevent, ADDREF, AddRef);
+ M_CB(MPIID_SERVICEEVENT, ifc_omserviceevent, RELEASE, Release);
+ M_CB(MPIID_SERVICEEVENT, ifc_omserviceevent, QUERYINTERFACE, QueryInterface);
+ M_VCB(MPIID_SERVICEEVENT, ifc_omserviceevent, API_SERVICECHANGE, ServiceChange);
+ M_VCB(MPIID_SERVICEEVENT, ifc_omserviceevent, API_COMMANDSTATECHANGE, CommandStateChange);
+
+ NEXT_PATCH(MPIID_CONFIGCALLBACK)
+ M_CB(MPIID_CONFIGCALLBACK, ifc_omconfigcallback, ADDREF, AddRef);
+ M_CB(MPIID_CONFIGCALLBACK, ifc_omconfigcallback, RELEASE, Release);
+ M_CB(MPIID_CONFIGCALLBACK, ifc_omconfigcallback, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_CONFIGCALLBACK, ifc_omconfigcallback, API_VALUECHANGED, ValueChanged);
+ END_PATCH
+END_MULTIPATCH;
+#undef CBCLASS
+
+
+
diff --git a/Src/omBrowser/browserUiHook.h b/Src/omBrowser/browserUiHook.h
new file mode 100644
index 00000000..6c7e251e
--- /dev/null
+++ b/Src/omBrowser/browserUiHook.h
@@ -0,0 +1,70 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_UI_HOOK_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_UI_HOOK_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_winamphook.h"
+#include "./ifc_omserviceevent.h"
+#include "./ifc_omconfigcallback.h"
+#include <bfc/multipatch.h>
+
+#define MPIID_WINAMPHOOK 10
+#define MPIID_SERVICEEVENT 20
+#define MPIID_CONFIGCALLBACK 30
+
+class ifc_omservice;
+class obj_ombrowser;
+
+class BrowserUiHook : public MultiPatch<MPIID_WINAMPHOOK, ifc_winamphook>,
+ public MultiPatch<MPIID_SERVICEEVENT, ifc_omserviceevent>,
+ public MultiPatch<MPIID_CONFIGCALLBACK, ifc_omconfigcallback>
+{
+protected:
+ BrowserUiHook(HWND hTarget, BOOL fPopupMode);
+ ~BrowserUiHook();
+
+public:
+ static HRESULT CreateInstance(HWND hTarget, BOOL fPopupMode, BrowserUiHook **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /*ifc_winamphook (partial) */
+ HRESULT SkinChanging(void);
+ HRESULT SkinChanged(const wchar_t *skinName);
+ HRESULT SkinColorChange(const wchar_t *colorTheme);
+ HRESULT ResetFont(void);
+
+ /* ifc_omserviceevent */
+ void ServiceChange(ifc_omservice *service, UINT nModified);
+ void CommandStateChange(ifc_omservice *service, const GUID *commandGroup, unsigned int commandId);
+
+
+ /* ifc_omconfigcallback */
+ HRESULT ValueChanged(const GUID *configUid, UINT valueId, ULONG_PTR value);
+
+public:
+ HRESULT Register(obj_ombrowser *browserManager, ifc_omservice *service);
+ HRESULT Unregister(obj_ombrowser *browserManager, ifc_omservice *service);
+
+ HRESULT CheckBlockedState(ifc_omservice *service);
+
+protected:
+ ULONG ref;
+ BOOL popupMode;
+ HWND hwnd;
+ UINT winampCookie;
+ UINT configCookie;
+
+protected:
+ RECVS_MULTIPATCH;
+
+};
+
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_UI_HOOK_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/browserUiInternal.h b/Src/omBrowser/browserUiInternal.h
new file mode 100644
index 00000000..2f379c81
--- /dev/null
+++ b/Src/omBrowser/browserUiInternal.h
@@ -0,0 +1,37 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_UI_INTERNAL_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_UI_INTERNAL_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+//styles ex
+#define NBCS_EX_BROWSERREADY 0x00000001
+#define NBCS_EX_NAVCOMPLETED 0x00000002
+#define NBCS_EX_BLOCKNAVIGATION 0x00000004
+
+// popup only
+#define NBCS_EX_NAVIGATEDONCE 0x00000100
+#define NBCS_EX_FULLSCREEN 0x00000200
+#define NBCS_EX_SCRIPTMODE 0x00000400
+
+#define ACCELTABLE_VIEW 0
+#define ACCELTABLE_POPUP 1
+
+HACCEL BrowserControl_GetAccelTable(UINT tableType);
+
+BOOL BrowserControl_ProcessCommonCommand(HWND hControl, INT commandId);
+BOOL BrowserControl_ProcessToolbarCommand(HWND hControl, INT commandId);
+BOOL BrowserControl_ProcessStatusbarCommand(HWND hControl, INT commandId);
+BOOL BrowserControl_ProcessAppCommand(HWND hControl, INT commandId);
+
+typedef struct __OPERATIONINFO OPERATIONINFO;
+BOOL BrowserControl_OnShowOperation(HWND hControl, OPERATIONINFO *poi);
+HWND BrowserControl_GetOperationWidget(HWND hControl);
+
+BOOL BrowserControl_UpdateLayout(HWND hControl, BOOL fRedraw, BOOL fFrame, HRGN updateRegion,const POINT *updateOffset);
+BOOL BrowserControl_EnableChildren(HWND hControl, BOOL fEnable);
+BOOL BrowserControl_SetBlockedState(HWND hControl, BOOL fBlocked);
+#endif // NULLSOFT_WINAMP_OMBROWSER_UI_INTERNAL_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/browserView.cpp b/Src/omBrowser/browserView.cpp
new file mode 100644
index 00000000..a66849e1
--- /dev/null
+++ b/Src/omBrowser/browserView.cpp
@@ -0,0 +1,1131 @@
+#include "main.h"
+#include "./browserView.h"
+#include "./browserUiInternal.h"
+#include "./graphics.h"
+#include "./resource.h"
+#include "./browser.h"
+#include "./browserHost.h"
+#include "./browserPopup.h"
+#include "./toolbar.h"
+#include "./statusbar.h"
+#include "./curtain.h"
+#include "../winamp/wa_dlg.h"
+
+#include "../Plugins/General/gen_ml/colors.h"
+
+#include "./ifc_omservice.h"
+#include "./obj_ombrowser.h"
+#include "./ifc_wasabihelper.h"
+#include "./ifc_skinhelper.h"
+#include "./ifc_skinnedbrowser.h"
+#include "./ifc_omserviceeventmngr.h"
+#include "./ifc_omserviceevent.h"
+#include "./ifc_ombrowserwndmngr.h"
+#include "./ifc_ombrowsereventmngr.h"
+
+#include "./ifc_omconfig.h"
+#include "./ifc_omtoolbarconfig.h"
+#include "./ifc_omstatusbarconfig.h"
+
+#include "./browserUiHook.h"
+
+#include <shlwapi.h>
+#include <strsafe.h>
+
+
+typedef struct __BROWSERVIEWCREATEPARAM
+{
+ obj_ombrowser *browserManager;
+ ifc_omservice *service;
+ LPCWSTR redirectUrl;
+} BROWSERVIEWCREATEPARAM;
+
+typedef struct __BROWSERVIEW
+{
+ UINT extendedStyle;
+ obj_ombrowser *browserManager;
+ ifc_omservice *service;
+ LPWSTR storedUrl;
+ BSTR storedData;
+ HRGN updateRegion;
+ POINT regionOffset;
+ COLORREF rgbBack;
+ BrowserUiHook *browserHook;
+} BROWSERVIEW;
+
+#define IDC_BROWSER 0x1000
+#define IDC_TOOLBAR 0x1001
+#define IDC_STATUSBAR 0x1002
+
+static BOOL BrowserView_RegisterClass(HINSTANCE hInstance);
+static LRESULT CALLBACK BrowserView_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+#define GetView(__hwnd) ((BROWSERVIEW*)(LONG_PTR)(LONGX86)GetWindowLongPtr((__hwnd), 0))
+
+HWND BrowserView_Create(obj_ombrowser *browserManager, ifc_omservice *service, HWND hParent, LPCWSTR redirectUrl, UINT style)
+{
+ HINSTANCE hInstance = Plugin_GetInstance();
+ if (!BrowserView_RegisterClass(hInstance) ||
+ !Toolbar_RegisterClass(hInstance) ||
+ !Statusbar_RegisterClass(hInstance))
+ {
+ return NULL;
+ }
+
+ BROWSERVIEWCREATEPARAM createParam;
+ ZeroMemory(&createParam, sizeof(BROWSERVIEWCREATEPARAM));
+
+ createParam.browserManager = browserManager;
+ createParam.service = service;
+ createParam.redirectUrl = redirectUrl;
+
+ HWND hwnd = CreateWindowEx(WS_EX_NOPARENTNOTIFY | WS_EX_CONTROLPARENT,
+ NWC_OMBROWSERVIEW, NULL,
+ WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | style,
+ 0, 0, 0, 0, hParent, NULL, hInstance, &createParam);
+
+ return hwnd;
+}
+
+static void BrowserView_Paint(HWND hwnd, HDC hdc, const RECT *prcPaint, BOOL fErase)
+{
+ BROWSERVIEW *view = GetView(hwnd);
+ if (NULL == view) return;
+
+ SetBkColor(hdc, view->rgbBack);
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, prcPaint, NULL, 0, NULL);
+}
+
+
+static BOOL BrowserView_PreformNavigation(HWND hwnd)
+{
+ BROWSERVIEW *view = GetView(hwnd);
+ if (NULL == view) return FALSE;
+
+ if (NULL != view->storedUrl)
+ {
+ LPWSTR url = view->storedUrl;
+ view->storedUrl = NULL;
+ BrowserView_Navigate(hwnd, url, TRUE);
+ Plugin_FreeResString(url);
+ }
+ else
+ {
+ BrowserView_NavigateHome(hwnd, TRUE);
+ }
+ return TRUE;
+}
+
+static HWND BrowserView_CreateToolbar(HWND hwnd)
+{
+ HWND hToolbar = GetDlgItem(hwnd, IDC_TOOLBAR);
+ if (NULL != hToolbar) return hToolbar;
+
+ BROWSERVIEW *view = GetView(hwnd);
+ if (NULL == view) return NULL;
+
+ UINT fStyle = GetWindowStyle(hwnd);
+
+ UINT toolbarStyle = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBS_LOCKUPDATE;
+ if (0 == (NBCS_NOTOOLBAR & fStyle))
+ toolbarStyle |= WS_VISIBLE;
+
+ ifc_omtoolbarconfig *toolbarConfig;
+ if (NULL != view->browserManager && SUCCEEDED(view->browserManager->GetConfig(&IFC_OmToolbarConfig, (void**)&toolbarConfig)))
+ {
+ if (S_OK == toolbarConfig->GetBottomDockEnabled())
+ toolbarStyle |= TBS_BOTTOMDOCK;
+ if (S_OK == toolbarConfig->GetAutoHideEnabled())
+ toolbarStyle |= TBS_AUTOHIDE;
+ if (S_OK == toolbarConfig->GetTabStopEnabled())
+ toolbarStyle |= TBS_TABSTOP;
+ if (S_OK == toolbarConfig->GetForceAddressbarEnabled())
+ toolbarStyle |= TBS_FORCEADDRESS;
+ if (S_OK == toolbarConfig->GetFancyAddressbarEnabled())
+ toolbarStyle |= TBS_FANCYADDRESS;
+
+ toolbarConfig->Release();
+ }
+
+ HINSTANCE hInstance = (HINSTANCE)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
+
+ hToolbar = CreateWindowEx(WS_EX_NOPARENTNOTIFY,
+ NWC_ONLINEMEDIATOOLBAR, NULL, toolbarStyle,
+ 0, 0, 0, 0, hwnd, (HMENU)IDC_TOOLBAR, hInstance, NULL);
+
+ if (NULL == hToolbar)
+ return NULL;
+
+ UINT populateStyle = TBPF_NORMAL | TBPF_READONLYADDRESS;
+ if (0 != (NBCS_NOSERVICECOMMANDS & fStyle))
+ populateStyle |= TBPF_NOSERVICECOMMANDS;
+
+ Toolbar_AutoPopulate(hToolbar, view->service, populateStyle);
+
+ toolbarStyle = GetWindowStyle(hToolbar);
+ if (0 != (TBS_LOCKUPDATE & toolbarStyle))
+ Toolbar_LockUpdate(hToolbar, FALSE);
+
+ return hToolbar;
+}
+
+static HWND BrowserView_CreateStatusbar(HWND hwnd)
+{
+ HWND hStatusbar = GetDlgItem(hwnd, IDC_STATUSBAR);
+ if (NULL != hStatusbar) return hStatusbar;
+
+ BROWSERVIEW *view = GetView(hwnd);
+ if (NULL == view) return NULL;
+
+ UINT fStyle = GetWindowStyle(hwnd);
+
+ UINT statusbarStyle = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_DISABLED;
+ if (0 == (NBCS_NOSTATUSBAR & fStyle))
+ {
+ ifc_omstatusbarconfig *statusbarConfig;
+ if (NULL != view->browserManager && SUCCEEDED(view->browserManager->GetConfig(&IFC_OmStatusbarConfig, (void**)&statusbarConfig)))
+ {
+ if (S_OK == statusbarConfig->GetEnabled())
+ statusbarStyle &= ~WS_DISABLED;
+ statusbarConfig->Release();
+ }
+ }
+
+ HINSTANCE hInstance = (HINSTANCE)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
+
+ hStatusbar = CreateWindowEx(WS_EX_NOPARENTNOTIFY,
+ NWC_ONLINEMEDIASTATUSBAR, NULL, statusbarStyle,
+ 0, 0, 0, 0, hwnd, (HMENU)IDC_STATUSBAR, hInstance, NULL);
+
+ return hStatusbar;
+}
+
+static LRESULT BrowserView_ShowHistory(HWND hwnd, BOOL fButtonPressd)
+{
+ HWND hBrowser = GetDlgItem(hwnd, IDC_BROWSER);
+ if (NULL == hBrowser) return FALSE;
+
+ UINT flags = TPM_LEFTALIGN;
+ POINT pt = {0, 0};
+
+ BOOL fUseHost = TRUE;;
+ HWND hToolbar = GetDlgItem(hwnd, IDC_TOOLBAR);
+ DWORD toolbarStyle = (NULL != hToolbar) ? GetWindowStyle(hToolbar) : 0;
+
+ if (NULL != hToolbar && 0 != (WS_VISIBLE & toolbarStyle))
+ {
+ fUseHost = FALSE;
+ RECT toolbarRect;
+ GetWindowRect(hToolbar, &toolbarRect);
+ pt.x = toolbarRect.left + 2;
+ if (0 != (TBS_BOTTOMDOCK & toolbarStyle))
+ {
+ pt.y = toolbarRect.top + 1;
+ flags |= TPM_VERNEGANIMATION | TPM_BOTTOMALIGN;
+ }
+ else
+ {
+ pt.y = toolbarRect.bottom - 1;
+ flags |= TPM_VERPOSANIMATION | TPM_TOPALIGN;
+ }
+ }
+
+ if (FALSE != fUseHost)
+ {
+ RECT windowRect;
+ GetClientRect(hwnd, &windowRect);
+ pt.x = windowRect.left;
+ pt.y = windowRect.top;
+ MapWindowPoints(hwnd, HWND_DESKTOP, &pt, 1);
+ flags |= TPM_VERPOSANIMATION | TPM_TOPALIGN;
+ }
+
+ if (NULL != hToolbar && 0 != (TBS_AUTOHIDE & toolbarStyle))
+ SetWindowLongPtr(hToolbar, GWL_STYLE, toolbarStyle & ~TBS_AUTOHIDE);
+
+ HWND hStatusbar = GetDlgItem(hwnd, IDC_STATUSBAR);
+ DWORD statusStyle = (NULL != hStatusbar) ? GetWindowStyle(hStatusbar) : 0;
+ if (NULL != hStatusbar && 0 == (WS_DISABLED & statusStyle))
+ SetWindowLongPtr(hStatusbar, GWL_STYLE, WS_DISABLED | statusStyle);
+
+ LRESULT result = SendMessage(hBrowser, NBHM_SHOWHISTORYPOPUP, (WPARAM)flags, MAKELPARAM(pt.x, pt.y));
+
+ if (NULL != hToolbar && 0 != (TBS_AUTOHIDE & toolbarStyle))
+ {
+ SetWindowLongPtr(hToolbar, GWL_STYLE, toolbarStyle);
+ TRACKMOUSEEVENT tm;
+ tm.cbSize = sizeof(TRACKMOUSEEVENT);
+ tm.dwFlags = TME_LEAVE;
+ tm.hwndTrack = hToolbar;
+ TrackMouseEvent(&tm);
+ }
+
+ if (NULL != hStatusbar && 0 == (WS_DISABLED & statusStyle))
+ SetWindowLongPtr(hStatusbar, GWL_STYLE, statusStyle);
+
+ return result;
+}
+
+static BOOL BrowserView_SetStatusText(HWND hwnd, LPCWSTR pszText)
+{
+ HWND hStatusbar = GetDlgItem(hwnd, IDC_STATUSBAR);
+ if (NULL == hStatusbar) return FALSE;
+
+ Statusbar_Update(hStatusbar, pszText);
+ return TRUE;
+}
+
+static BOOL BrowserView_SetStatusTextRes(HWND hwnd, LPCWSTR pszText)
+{
+ if (NULL != pszText && IS_INTRESOURCE(pszText))
+ {
+ WCHAR szBuffer[512] = {0};
+ pszText = Plugin_LoadString((INT)(INT_PTR)pszText, szBuffer, ARRAYSIZE(szBuffer));
+ }
+ return BrowserView_SetStatusText(hwnd, pszText);
+}
+
+static void BrowserView_RegisterUiHook(HWND hwnd)
+{
+ BROWSERVIEW *view = GetView(hwnd);
+ if (NULL == view || NULL != view->browserHook) return;
+
+ if (FAILED(BrowserUiHook::CreateInstance(hwnd, FALSE, &view->browserHook)))
+ return;
+
+ view->browserHook->Register(view->browserManager, view->service);
+}
+
+static LRESULT BrowserView_OnCreate(HWND hwnd, CREATESTRUCT *pcs)
+{
+ BROWSERVIEWCREATEPARAM *createParam = (BROWSERVIEWCREATEPARAM*)pcs->lpCreateParams;
+
+ BROWSERVIEW *view = (BROWSERVIEW*)calloc(1, sizeof(BROWSERVIEW));
+ if (NULL != view)
+ {
+ SetLastError(ERROR_SUCCESS);
+ if (!SetWindowLongPtr(hwnd, 0, (LONGX86)(LONG_PTR)view) && ERROR_SUCCESS != GetLastError())
+ {
+ free(view);
+ view = NULL;
+ }
+ }
+
+ if (NULL == view)
+ {
+ DestroyWindow(hwnd);
+ return -1;
+ }
+
+ if (NULL != createParam)
+ {
+ view->browserManager = createParam->browserManager;
+ if (NULL != view->browserManager)
+ view->browserManager->AddRef();
+
+ view->service = createParam->service;
+ if (NULL != view->service)
+ view->service->AddRef();
+
+ if (NULL != createParam->redirectUrl)
+ view->storedUrl = Plugin_DuplicateResString(createParam->redirectUrl);
+ }
+
+ BrowserView_RegisterUiHook(hwnd);
+
+ BrowserView_CreateToolbar(hwnd);
+ BrowserView_CreateStatusbar(hwnd);
+
+ UINT hostStyle = 0;
+ if (0 != (NBCS_DISABLECONTEXTMENU & pcs->style)) hostStyle |= NBHS_DISABLECONTEXTMENU;
+ if (0 != (NBCS_DIALOGMODE & pcs->style)) hostStyle |= NBHS_DIALOGMODE;
+ if (0 != (NBCS_DISABLEHOSTCSS & pcs->style))
+ hostStyle |= NBHS_DISABLEHOSTCSS;
+
+ HACCEL hAccel = BrowserControl_GetAccelTable(ACCELTABLE_VIEW);
+
+ HWND hHost = BrowserHost_CreateWindow(view->browserManager, hwnd, hostStyle, 0, 0, 0, 0, IDC_BROWSER, hAccel);
+
+ HWND hControl;
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_TOOLBAR)))
+ {
+ Toolbar_SetBrowserHost(hControl, hHost);
+ }
+
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_STATUSBAR)))
+ {
+ Statusbar_SetBrowserHost(hControl, hHost);
+ Statusbar_SetActive(hControl, (0 == (WS_DISABLED & GetWindowLongPtr(hControl, GWL_STYLE))));
+ }
+
+ if (NULL != hAccel)
+ {
+ ifc_wasabihelper *wasabiHelper;
+ if (SUCCEEDED(Plugin_GetWasabiHelper(&wasabiHelper)))
+ {
+ api_application *app;
+ if (SUCCEEDED(wasabiHelper->GetApplicationApi(&app)))
+ {
+ app->app_addAccelerators(hwnd, &hAccel, 1, TRANSLATE_MODE_CHILD);
+
+ app->Release();
+ }
+ wasabiHelper->Release();
+ }
+ }
+
+ if(NULL != view->browserManager)
+ {
+ ifc_ombrowserwndmngr *windowManager;
+ if (SUCCEEDED(view->browserManager->QueryInterface(IFC_OmBrowserWindowManager, (void**)&windowManager)))
+ {
+ windowManager->RegisterWindow(hwnd, &WTID_BrowserView);
+ windowManager->Release();
+ }
+
+ ifc_ombrowsereventmngr *eventManager;
+ if (SUCCEEDED(view->browserManager->QueryInterface(IFC_OmBrowserEventManager, (void**)&eventManager)))
+ {
+ eventManager->Signal_WindowCreate(hwnd, &WTID_BrowserView);
+ eventManager->Release();
+ }
+ }
+ return 0;
+}
+
+static void BrowserView_OnDestroy(HWND hwnd)
+{
+ BROWSERVIEW *view = GetView(hwnd);
+ SetWindowLongPtr(hwnd, 0, 0L);
+
+ HWND hHost = GetDlgItem(hwnd, IDC_BROWSER);
+ if (NULL != hHost)
+ {
+ DWORD hostStyle = GetWindowStyle(hHost);
+ if (0 != (WS_VISIBLE & hostStyle))
+ SetWindowLongPtr(hHost, GWL_STYLE, hostStyle & ~WS_VISIBLE);
+
+ HWND hWinamp;
+ if (SUCCEEDED(Plugin_GetWinampWnd(&hWinamp)))
+ {
+ SetWindowLongPtr(hHost, GWLP_HWNDPARENT, (LONGX86)(LONG_PTR)hWinamp);
+ }
+
+ if (NULL == view->browserManager ||
+ S_OK == view->browserManager->IsFinishing() ||
+ 0 == PostMessage(hHost, NBHM_DESTROY, 0, 0L))
+ {
+ DWORD_PTR result;
+ SendMessageTimeout(hHost, NBHM_DESTROY, TRUE, 0L, SMTO_NOTIMEOUTIFNOTHUNG | SMTO_BLOCK, 500, &result);
+ }
+ }
+ else
+ {
+ aTRACE_LINE("browser control not created");
+ }
+
+ if (NULL != view)
+ {
+ view->extendedStyle &= ~(NBCS_EX_BROWSERREADY | NBCS_EX_NAVCOMPLETED );
+ view->extendedStyle |= NBCS_EX_BLOCKNAVIGATION;
+
+ if (NULL != view->browserHook)
+ {
+ view->browserHook->Unregister(view->browserManager, view->service);
+ view->browserHook->Release();
+ }
+
+ if (NULL != view->service)
+ {
+ view->service->Release();
+ view->service = NULL;
+ }
+
+ Plugin_FreeResString(view->storedUrl);
+ view->storedUrl = NULL;
+
+ SysFreeString(view->storedData);
+ view->storedData = NULL;
+
+ if (NULL != view->browserManager)
+ {
+ ifc_ombrowserwndmngr *windowManager;
+ if (SUCCEEDED(view->browserManager->QueryInterface(IFC_OmBrowserWindowManager, (void**)&windowManager)))
+ {
+ windowManager->UnregisterWindow(hwnd);
+ windowManager->Release();
+ }
+
+ ifc_ombrowsereventmngr *eventManager;
+ if (SUCCEEDED(view->browserManager->QueryInterface(IFC_OmBrowserEventManager, (void**)&eventManager)))
+ {
+ eventManager->Signal_WindowClose(hwnd, &WTID_BrowserPopup);
+ eventManager->Release();
+ }
+
+ view->browserManager->Release();
+ view->browserManager = NULL;
+ }
+ free(view);
+ }
+
+ ifc_wasabihelper *wasabiHelper;
+ if (SUCCEEDED(Plugin_GetWasabiHelper(&wasabiHelper)))
+ {
+ api_application *app;
+ if (SUCCEEDED(wasabiHelper->GetApplicationApi(&app)))
+ {
+ app->app_removeAccelerators(hwnd);
+ app->Release();
+ }
+ wasabiHelper->Release();
+ }
+}
+
+static void BrowserView_OnPaint(HWND hwnd)
+{
+ PAINTSTRUCT ps;
+ if (BeginPaint(hwnd, &ps))
+ {
+ if (ps.rcPaint.left != ps.rcPaint.right)
+ BrowserView_Paint(hwnd, ps.hdc, &ps.rcPaint, ps.fErase);
+ EndPaint(hwnd, &ps);
+ }
+}
+
+static void BrowserView_OnPrintClient(HWND hwnd, HDC hdc, UINT options)
+{
+ RECT clientRect;
+ if (GetClientRect(hwnd, &clientRect))
+ BrowserView_Paint(hwnd, hdc, &clientRect, 0 != (PRF_ERASEBKGND & options));
+}
+
+static void BrowserView_OnWindowPosChanged(HWND hwnd, WINDOWPOS *pwp)
+{
+ if (SWP_NOSIZE == ((SWP_NOSIZE | SWP_FRAMECHANGED) & pwp->flags))
+ return;
+
+ BROWSERVIEW *view = GetView(hwnd);
+ if (NULL != view)
+ {
+
+ BrowserControl_UpdateLayout(hwnd, 0 == (SWP_NOREDRAW & pwp->flags),
+ 0 != (SWP_FRAMECHANGED & pwp->flags), view->updateRegion, &view->regionOffset);
+ }
+}
+
+
+
+static void BrowserView_OnCommand(HWND hwnd, INT commandId, INT eventId, HWND hControl)
+{
+ switch(commandId)
+ {
+ case IDC_TOOLBAR: BrowserControl_ProcessToolbarCommand(hwnd, eventId); break;
+ case IDC_STATUSBAR: BrowserControl_ProcessStatusbarCommand(hwnd, eventId); break;
+ default: BrowserControl_ProcessCommonCommand(hwnd, commandId); break;
+ }
+
+
+}
+
+static void BrowserView_OnUpdateSkin(HWND hwnd)
+{
+ BROWSERVIEW *view = GetView(hwnd);
+ if (NULL == view) return;
+
+ ifc_skinnedbrowser *skinnedBrowser;
+ if (SUCCEEDED(Plugin_GetBrowserSkin(&skinnedBrowser)))
+ {
+ view->rgbBack = skinnedBrowser->GetBackColor();
+ skinnedBrowser->Release();
+ }
+ else
+ view->rgbBack = GetSysColor(COLOR_WINDOW);
+
+ HWND hControl;
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_BROWSER)))
+ PostMessage(hControl, NBHM_UPDATESKIN, 0, 0L);
+
+ if (NULL != (hControl = BrowserControl_GetOperationWidget(hwnd)))
+ Curtain_UpdateSkin(hControl, FALSE);
+
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_STATUSBAR)))
+ Statusbar_UpdateSkin(hControl, FALSE);
+
+ if (NULL != (hControl = GetDlgItem(hwnd, IDC_TOOLBAR)))
+ Toolbar_UpdateSkin(hControl, FALSE);
+
+ BrowserControl_UpdateLayout(hwnd, TRUE, TRUE, NULL, NULL);
+}
+
+static void BrowserView_OnBrowserReady(HWND hwnd)
+{
+ ReplyMessage(0);
+
+ BROWSERVIEW *view = GetView(hwnd);
+ if (NULL == view) return;
+
+ view->extendedStyle |= NBCS_EX_BROWSERREADY;
+
+ BrowserControl_UpdateLayout(hwnd, FALSE, FALSE, NULL, NULL);
+ BrowserView_PreformNavigation(hwnd);
+
+ HWND hToolbar = BrowserControl_GetToolbar(hwnd);
+ if (NULL != hToolbar)
+ Toolbar_EnableItem(hToolbar, TOOLITEM_ADDRESSBAR, TRUE);
+}
+
+static void BrowserView_OnDocumentReady(HWND hwnd)
+{
+ BROWSERVIEW *view = GetView(hwnd);
+ if (NULL == view) return;
+
+ if (0 == (NBCS_EX_NAVCOMPLETED & view->extendedStyle))
+ {
+ view->extendedStyle |= NBCS_EX_NAVCOMPLETED;
+ if (NULL != view->storedData)
+ {
+ BSTR documentData = view->storedData;
+ view->storedData = NULL;
+ if (FALSE == BrowserView_WriteDocument(hwnd, documentData, FALSE))
+ SysFreeString(documentData);
+ }
+
+ HWND hHost = GetDlgItem(hwnd, IDC_BROWSER);
+ if (NULL != hHost &&
+ 0 == (WS_VISIBLE & GetWindowStyle(hHost)))
+ {
+ ShowWindowAsync(hHost, SW_SHOWNA);
+ }
+
+ }
+}
+
+static void BrowserView_OnBrowserActive(HWND hwnd, BOOL fActive)
+{
+ ReplyMessage(0);
+
+ HWND hToolbar = GetDlgItem(hwnd, IDC_TOOLBAR);
+ if (NULL != hToolbar)
+ {
+ Toolbar_EnableItem(hToolbar, TOOLITEM_DOWNLOADPROGRESS, fActive);
+ }
+
+ HWND hStatusbar = GetDlgItem(hwnd, IDC_STATUSBAR);
+ if (NULL != hStatusbar )
+ {
+ if (FALSE != fActive && (0 != (WS_DISABLED & GetWindowLongPtr(hStatusbar, GWL_STYLE))))
+ fActive = FALSE;
+ Statusbar_SetActive(hStatusbar, fActive);
+ }
+}
+
+static void BrowserView_OnCommandStateChange(HWND hwnd, UINT commandId, BOOL fEnable)
+{
+ ReplyMessage(0);
+
+ HWND hToolbar = GetDlgItem(hwnd, IDC_TOOLBAR);
+ if (NULL != hToolbar)
+ {
+ switch(commandId)
+ {
+ case Browser::commandBack:
+ Toolbar_EnableItem(hToolbar, TOOLITEM_BUTTON_BACK, fEnable);
+ Toolbar_EnableItem(hToolbar, TOOLITEM_BUTTON_HISTORY, (FALSE != fEnable) ?
+ TRUE :
+ (0 == Toolbar_GetItemStyle(hToolbar, TOOLITEM_BUTTON_FORWARD, TBIS_DISABLED)));
+ break;
+
+ case Browser::commandForward:
+ Toolbar_EnableItem(hToolbar, TOOLITEM_BUTTON_FORWARD, fEnable);
+ Toolbar_EnableItem(hToolbar, TOOLITEM_BUTTON_HISTORY, (FALSE != fEnable) ?
+ TRUE :
+ (0 == Toolbar_GetItemStyle(hToolbar, TOOLITEM_BUTTON_BACK, TBIS_DISABLED)));
+ break;
+ case Browser::commandStop: Toolbar_EnableItem(hToolbar, TOOLITEM_BUTTON_STOP, fEnable); break;
+ case Browser::commandRefresh:
+ Toolbar_EnableItem(hToolbar, TOOLITEM_BUTTON_REFRESH, fEnable);
+ Toolbar_EnableItem(hToolbar, TOOLITEM_BUTTON_HOME, fEnable);
+ break;
+ }
+ }
+
+}
+static void BrowserView_OnStatusChange(HWND hwnd, LPCWSTR pszText)
+{
+ WCHAR szBuffer[512] = {0};
+ if (NULL == pszText || L'\0' == *pszText)
+ szBuffer[0] = L'\0';
+ else
+ StringCchCopy(szBuffer, ARRAYSIZE(szBuffer), pszText);
+
+ ReplyMessage(0);
+
+ BrowserView_SetStatusText(hwnd, szBuffer);
+}
+
+
+
+static void BrowserView_OnSecureIconChange(HWND hwnd, UINT iconId)
+{
+ ReplyMessage(0);
+
+ HWND hToolbar = GetDlgItem(hwnd, IDC_TOOLBAR);
+ if (NULL != hToolbar)
+ {
+ INT itemId = Toolbar_FindItem(hToolbar, TOOLITEM_BUTTON_SECURECONNECTION);
+ if (ITEM_ERR != itemId)
+ {
+ WCHAR szBuffer[256] = {0};
+
+ if(FAILED(FormatEncryptionString(iconId, szBuffer, ARRAYSIZE(szBuffer))))
+ szBuffer[0] = L'\0';
+
+ Toolbar_ShowItem(hToolbar, MAKEINTRESOURCE(itemId), (secureLockIconUnsecure != iconId));
+ Toolbar_SetItemDescription(hToolbar, MAKEINTRESOURCE(itemId), szBuffer);
+ }
+ }
+}
+
+static BOOL BrowserView_OnGetOmService(HWND hwnd, void **serviceInstance)
+{
+ if (NULL == serviceInstance)
+ return FALSE;
+
+ *serviceInstance = NULL;
+
+ BROWSERVIEW *view = GetView(hwnd);
+ if (NULL == view || NULL == view->service) return FALSE;
+
+ *serviceInstance = view->service;
+ view->service->AddRef();
+ return TRUE;
+}
+
+static LRESULT BrowserView_OnCreatePopup(HWND hwnd, DISPATCHAPC callback, ULONG_PTR param)
+{
+ ReplyMessage(TRUE);
+
+ HWND hPopup = NULL;
+
+ UINT windowStyle = GetWindowStyle(hwnd);
+ if (0 == (NBCS_BLOCKPOPUP & windowStyle))
+ {
+ BROWSERVIEW *view = GetView(hwnd);
+ if (NULL != view)
+ {
+ RECT windowRect;
+ GetWindowRect(hwnd, &windowRect);
+
+ UINT popupStyle = NBCS_NOSERVICECOMMANDS | NBCS_DISABLEHOSTCSS;
+ popupStyle |= (NBCS_POPUPOWNER & GetWindowStyle(hwnd));
+
+ HWND hOwner = NULL;
+ if (0 != (NBCS_POPUPOWNER & popupStyle))
+ hOwner = hwnd;
+
+ hPopup = BrowserPopup_Create(view->browserManager, view->service, popupStyle,
+ windowRect.left + 12, windowRect.top + 12, 640, 480, hOwner, callback, param);
+ }
+
+ }
+ if (NULL == hPopup)
+ {
+ if (NULL != callback)
+ callback(NULL, param);
+ return FALSE;
+ }
+
+ BrowserControl_SetExtendedStyle(hPopup, NBCS_EX_SCRIPTMODE, NBCS_EX_SCRIPTMODE);
+ BrowserPopup_UpdateSkin(hPopup, FALSE);
+
+ return TRUE;
+
+}
+
+static void BrowserView_OnAllowFocusChange(HWND hwnd, BOOL *fAllow)
+{
+ *fAllow = FALSE;
+}
+
+static void BrowserView_OnNavigateComplete(HWND hwnd, IDispatch *pDispath, VARIANT *URL, BOOL fTopFrame)
+{
+ if (FALSE == fTopFrame)
+ return;
+
+ LPWSTR pszUrl = NULL;
+ if (NULL != URL && VT_BSTR == URL->vt && NULL != URL->bstrVal)
+ pszUrl = Plugin_CopyString(URL->bstrVal);
+
+ ReplyMessage(0);
+
+ if (NULL != pszUrl)
+ {
+ HWND hToolbar = GetDlgItem(hwnd, IDC_TOOLBAR);
+ if (NULL != hToolbar)
+ {
+ INT itemId = Toolbar_FindItem(hToolbar, TOOLITEM_ADDRESSBAR);
+ if (ITEM_ERR != itemId)
+ Toolbar_SetItemString(hToolbar, MAKEINTRESOURCE(itemId), pszUrl);
+ }
+ Plugin_FreeString(pszUrl);
+ }
+}
+
+static void BrowserView_OnTitleChange(HWND hwnd, LPCWSTR pszText)
+{
+ WCHAR szBuffer[256] = {0};
+ if (NULL == pszText || L'\0' == *pszText) szBuffer[0] = L'\0';
+ else StringCchCopy(szBuffer, ARRAYSIZE(szBuffer), pszText);
+
+ ReplyMessage(0);
+
+ HWND hToolbar = GetDlgItem(hwnd, IDC_TOOLBAR);
+ if (NULL != hToolbar)
+ {
+ INT itemId = Toolbar_FindItem(hToolbar, TOOLITEM_ADDRESSBAR);
+ if (ITEM_ERR != itemId)
+ Toolbar_SetItemDescription(hToolbar, MAKEINTRESOURCE(itemId), szBuffer);
+ }
+}
+
+static void BrowserView_OnBrowserClosing(HWND hwnd, BOOL isChild, BOOL *fCancel)
+{
+ *fCancel = TRUE;
+ ReplyMessage(0);
+}
+
+static LRESULT BrowserView_OnBrowserNotify(HWND hwnd, NMHDR *pnmh)
+{
+ switch(pnmh->code)
+ {
+ case NBHN_READY:
+ BrowserView_OnBrowserReady(hwnd);
+ break;
+ case NBHN_DOCUMENTREADY:
+ BrowserView_OnDocumentReady(hwnd);
+ break;
+ case NBHN_BROWSERACTIVE:
+ BrowserView_OnBrowserActive(hwnd, ((BHNACTIVE*)pnmh)->fActive);
+ break;
+ case NBHN_COMMANDSTATECHANGE:
+ BrowserView_OnCommandStateChange(hwnd, ((BHNCMDSTATE*)pnmh)->commandId, ((BHNCMDSTATE*)pnmh)->fEnabled);
+ break;
+ case NBHN_STATUSCHANGE:
+ BrowserView_OnStatusChange(hwnd, ((BHNTEXTCHANGE*)pnmh)->pszText);
+ break;
+ case NBHN_SECUREICONCHANGE:
+ BrowserView_OnSecureIconChange(hwnd, ((BHNSECUREICON*)pnmh)->iconId);
+ break;
+ case NBHN_GETOMSERVICE:
+ return BrowserView_OnGetOmService(hwnd, &((BHNSERVICE*)pnmh)->instance);
+ case NBHN_CREATEPOPUP:
+ return BrowserView_OnCreatePopup(hwnd, ((BHNCREATEPOPUP*)pnmh)->callback, ((BHNCREATEPOPUP*)pnmh)->param);
+ case NBHN_FOCUSCHANGE:
+ BrowserView_OnAllowFocusChange(hwnd, &((BHNFOCUSCHANGE*)pnmh)->fAllow);
+ break;
+ case NBHN_NAVIGATECOMPLETE:
+ BrowserView_OnNavigateComplete(hwnd, ((BHNNAVCOMPLETE*)pnmh)->pDispatch, ((BHNNAVCOMPLETE*)pnmh)->URL, ((BHNNAVCOMPLETE*)pnmh)->fTopFrame);
+ break;
+ case NBHN_TITLECHANGE:
+ BrowserView_OnTitleChange(hwnd, ((BHNTEXTCHANGE*)pnmh)->pszText);
+ break;
+ case NBHN_CLOSING:
+ BrowserView_OnBrowserClosing(hwnd, ((BHNCLOSING*)pnmh)->isChild, &((BHNCLOSING*)pnmh)->cancel);
+ break;
+ }
+ return 0;
+}
+
+static LRESULT BrowserView_OnNotify(HWND hwnd, INT controlId, NMHDR *pnmh)
+{
+ switch(controlId)
+ {
+ case IDC_BROWSER:
+ return BrowserView_OnBrowserNotify(hwnd, pnmh);
+ }
+
+ return 0;
+}
+
+
+
+static LRESULT BrowserView_OnNavigate(HWND hwnd, LPCWSTR navigateUrl, BOOL fScheduleBlocked)
+{
+ BROWSERVIEW *view = GetView(hwnd);
+ if (NULL == view) return FALSE;
+
+ UINT windowStyle = GetWindowStyle(hwnd);
+
+ if (NULL != view->browserHook)
+ view->browserHook->CheckBlockedState(view->service);
+
+ Plugin_FreeResString(view->storedUrl);
+ view->storedUrl = NULL;
+
+ if (NBCS_EX_BROWSERREADY != ((NBCS_EX_BROWSERREADY | NBCS_EX_BLOCKNAVIGATION) & view->extendedStyle))
+ {
+ if (FALSE == fScheduleBlocked)
+ return FALSE;
+
+ view->storedUrl = Plugin_DuplicateResString(navigateUrl);
+ return TRUE;
+ }
+
+ HWND hHost = GetDlgItem(hwnd, IDC_BROWSER);
+ if (NULL == hHost) return FALSE;
+
+
+ LPWSTR pszDescription = NULL;
+ BSTR url = NULL;
+ if (IS_INTRESOURCE(navigateUrl))
+ {
+ switch((INT_PTR)navigateUrl)
+ {
+ case NAVIGATE_BLANK:
+ BrowserView_SetStatusText(hwnd, NULL);
+ url = SysAllocString(L"about:blank");
+ break;
+
+ case NAVIGATE_HOME:
+ if (0 == (NBCS_NOSERVICECOMMANDS & windowStyle) && NULL != view->service)
+ {
+ WCHAR szBuffer[8192] = {0};
+ if (SUCCEEDED(view->service->GetUrl(szBuffer, ARRAYSIZE(szBuffer))))
+ {
+ BrowserView_SetStatusTextRes(hwnd, MAKEINTRESOURCE(IDS_HOME_DESCRIPTION));
+ url = SysAllocString(szBuffer);
+ }
+
+ if (SUCCEEDED(view->service->GetName(szBuffer, ARRAYSIZE(szBuffer))))
+ pszDescription = Plugin_CopyString(szBuffer);
+ }
+
+ break;
+ case NAVIGATE_BACK:
+ BrowserView_SetStatusTextRes(hwnd, MAKEINTRESOURCE(IDS_BACK_DESCRIPTION));
+ return PostMessage(hHost, NBHM_CONTAINERCOMMAND, (WPARAM)Browser::commandBack, 0L);
+ case NAVIGATE_FORWARD:
+ BrowserView_SetStatusTextRes(hwnd, MAKEINTRESOURCE(IDS_FORWARD_DESCRIPTION));
+ return PostMessage(hHost, NBHM_CONTAINERCOMMAND, (WPARAM)Browser::commandForward, 0L);
+ case NAVIGATE_STOP:
+ BrowserView_SetStatusTextRes(hwnd, MAKEINTRESOURCE(IDS_STOP_DESCRIPTION));
+ return PostMessage(hHost, NBHM_CONTAINERCOMMAND, (WPARAM)Browser::commandStop, 0L);
+ case NAVIGATE_REFRESH:
+ BrowserView_SetStatusTextRes(hwnd, MAKEINTRESOURCE(IDS_REFRESH_DESCRIPTION));
+ return PostMessage(hHost, NBHM_CONTAINERCOMMAND, (WPARAM)Browser::commandRefresh, 0L);
+ case NAVIGATE_REFRESH_COMPLETELY:
+ BrowserView_SetStatusTextRes(hwnd, MAKEINTRESOURCE(IDS_REFRESH_DESCRIPTION));
+ return PostMessage(hHost, NBHM_CONTAINERCOMMAND, (WPARAM)Browser::commandRefreshCompletely, 0L);
+ }
+ }
+ else
+ {
+ BrowserView_SetStatusTextRes(hwnd, MAKEINTRESOURCE(IDS_NAVIGATING));
+ url = SysAllocString(navigateUrl);
+ }
+
+ if (NULL == url)
+ return FALSE;
+
+ HWND hToolbar = GetDlgItem(hwnd, IDC_TOOLBAR);
+ INT addressbarId = (NULL != hToolbar) ? Toolbar_FindItem(hToolbar, TOOLITEM_ADDRESSBAR) : ITEM_ERR;
+ if (ITEM_ERR != addressbarId)
+ {
+ Toolbar_SetItemString(hToolbar, MAKEINTRESOURCE(addressbarId), url);
+ Toolbar_SetItemDescription(hToolbar, MAKEINTRESOURCE(addressbarId), pszDescription);
+ }
+
+ if (!PostMessage(hHost, NBHM_NAVIGATE, 0, (LPARAM)url))
+ {
+ SysFreeString(url);
+ return FALSE;
+ }
+
+ Plugin_FreeString(pszDescription);
+
+ return TRUE;
+}
+
+static LRESULT BrowserView_OnWriteDocument(HWND hwnd, BSTR documentData, BOOL fScheduleBlocked)
+{
+ BROWSERVIEW *view = GetView(hwnd);
+ if (NULL == view) return FALSE;
+
+ SysFreeString(view->storedData);
+ view->storedData = NULL;
+
+ Plugin_FreeResString(view->storedUrl);
+ view->storedUrl = NULL;
+
+ if (0 == (NBCS_EX_NAVCOMPLETED & view->extendedStyle))
+ {
+ if (FALSE == fScheduleBlocked)
+ return FALSE;
+ view->storedData = documentData;
+ return TRUE;
+ }
+
+ HWND hHost = GetDlgItem(hwnd, IDC_BROWSER);
+ if (NULL == hHost) return FALSE;
+
+ return PostMessage(hHost, NBHM_WRITEDOCUMENT, 0, (LPARAM)documentData);
+}
+
+static void BrowserView_OnSetUpdateRegion(HWND hwnd, HRGN updateRegion, POINTS regionOffset)
+{
+ BROWSERVIEW *view = GetView(hwnd);
+ if (NULL == view) return;
+
+ view->updateRegion = updateRegion;
+
+
+ view->regionOffset.x = regionOffset.x;
+ view->regionOffset.y = regionOffset.y;
+}
+
+static LRESULT BrowserView_OnGetService(HWND hwnd, ifc_omservice **serviceOut)
+{
+ if (NULL == serviceOut) return FALSE;
+
+ BROWSERVIEW *view = GetView(hwnd);
+ if (NULL == view || NULL == view->service)
+ {
+ *serviceOut = NULL;
+ return FALSE;
+ }
+
+ *serviceOut = view->service;
+ (*serviceOut)->AddRef();
+ return TRUE;
+}
+
+
+static LRESULT BrowserView_OnGetBrowserObject(HWND hwnd, obj_ombrowser **browserOut)
+{
+ if (NULL == browserOut) return FALSE;
+
+ BROWSERVIEW *view = GetView(hwnd);
+ if (NULL == view || NULL == view->browserManager)
+ {
+ *browserOut = NULL;
+ return FALSE;
+ }
+
+ *browserOut = view->browserManager;
+ (*browserOut)->AddRef();
+ return TRUE;
+}
+static LRESULT BrowserView_OnGetToolbar(HWND hwnd)
+{
+ if (0 != (NBCS_NOTOOLBAR & GetWindowStyle(hwnd)))
+ return 0;
+
+ return (LRESULT)GetDlgItem(hwnd, IDC_TOOLBAR);
+}
+
+static LRESULT BrowserView_OnGetStatusbar(HWND hwnd)
+{
+ if (0 != (NBCS_NOSTATUSBAR & GetWindowStyle(hwnd)))
+ return 0;
+
+ return (LRESULT)GetDlgItem(hwnd, IDC_STATUSBAR);
+}
+
+static LRESULT BrowserView_OnGetHost(HWND hwnd)
+{
+ return (LRESULT)GetDlgItem(hwnd, IDC_BROWSER);
+}
+
+static LRESULT BrowserView_OnAppCommand(HWND hwnd, HWND hTarget, INT commandId, INT deviceId, INT keys)
+{
+ return BrowserControl_ProcessAppCommand(hwnd, commandId);
+}
+static LRESULT BrowserView_OnNavigateStoredUrl(HWND hwnd)
+{
+ BROWSERVIEW *view = GetView(hwnd);
+ if (NULL == view || NULL == view->storedUrl)
+ return FALSE;
+
+ LPWSTR url = view->storedUrl;
+ view->storedUrl = NULL;
+ BOOL result = BrowserView_Navigate(hwnd, url, TRUE);
+ Plugin_FreeResString(url);
+ return result;
+}
+
+static LRESULT BrowserView_OnSetExtendedStyle(HWND hwnd, UINT extMask, UINT extStyle)
+{
+ BROWSERVIEW *view = GetView(hwnd);
+ if (NULL == view) return 0;
+
+ UINT currentStyle = view->extendedStyle;
+ view->extendedStyle = (currentStyle & ~extMask) | (extStyle & extMask);
+ return currentStyle;
+}
+
+static LRESULT BrowserView_OnGetExtendedStyle(HWND hwnd)
+{
+ BROWSERVIEW *view = GetView(hwnd);
+ return (NULL != view) ? view->extendedStyle : 0;
+}
+
+static LRESULT CALLBACK BrowserView_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_CREATE: return BrowserView_OnCreate(hwnd, (CREATESTRUCT*)lParam);
+ case WM_DESTROY: BrowserView_OnDestroy(hwnd); break;
+ case WM_ERASEBKGND: return 0;
+ case WM_PAINT: BrowserView_OnPaint(hwnd); return 0;
+ case WM_PRINTCLIENT: BrowserView_OnPrintClient(hwnd, (HDC)wParam, (UINT)lParam); return 0;
+ case WM_WINDOWPOSCHANGED: BrowserView_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); return 0;
+ case WM_COMMAND: BrowserView_OnCommand(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break;
+ case WM_NOTIFY: return BrowserView_OnNotify(hwnd, (INT)wParam, (NMHDR*)lParam);
+ case WM_APPCOMMAND: return BrowserView_OnAppCommand(hwnd, (HWND)wParam, GET_APPCOMMAND_LPARAM(lParam), GET_DEVICE_LPARAM(lParam), GET_KEYSTATE_LPARAM(lParam));
+
+ case NBCM_GETTOOLBAR: return BrowserView_OnGetToolbar(hwnd);
+ case NBCM_GETSTATUSBAR: return BrowserView_OnGetStatusbar(hwnd);
+ case NBCM_GETHOST: return BrowserView_OnGetHost(hwnd);
+ case NBCM_UPDATESKIN: BrowserView_OnUpdateSkin(hwnd); return 0;
+ case NBCM_GETSERVICE: return BrowserView_OnGetService(hwnd, (ifc_omservice**)lParam);
+ case NBCM_NAVIGATE: return BrowserView_OnNavigate(hwnd, (LPCWSTR)lParam, (BOOL)wParam);
+ case NBCM_WRITEDOCUMENT: return BrowserView_OnWriteDocument(hwnd, (BSTR)lParam, (BOOL)wParam);
+ case NBCM_GETBROWSEROBJECT: return BrowserView_OnGetBrowserObject(hwnd, (obj_ombrowser**)lParam);
+ case NBCM_SHOWOPERATION: return BrowserControl_OnShowOperation(hwnd, (OPERATIONINFO*)lParam);
+ case NBCM_NAVSTOREDURL: return BrowserView_OnNavigateStoredUrl(hwnd);
+ case NBCM_BLOCK: BrowserControl_SetBlockedState(hwnd, (BOOL)lParam); return 0;
+ case NBCM_SETEXTSTYLE: return BrowserView_OnSetExtendedStyle(hwnd, (UINT)wParam, (UINT)lParam);
+ case NBCM_GETEXTSTYLE: return BrowserView_OnGetExtendedStyle(hwnd);
+
+ // gen_ml flickerless drawing
+ case WM_USER + 0x200: return 1;
+ case WM_USER + 0x201: BrowserView_OnSetUpdateRegion(hwnd, (HRGN)lParam, MAKEPOINTS(wParam)); return 0;
+ }
+
+ if (FALSE != Plugin_IsDirectMouseWheelMessage(uMsg))
+ {
+ SendMessage(hwnd, WM_MOUSEWHEEL, wParam, lParam);
+ return TRUE;
+ }
+
+ return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+}
+
+static BOOL BrowserView_RegisterClass(HINSTANCE hInstance)
+{
+ WNDCLASS wc;
+ if (GetClassInfo(hInstance, NWC_OMBROWSERVIEW, &wc)) return TRUE;
+
+ ZeroMemory(&wc, sizeof(WNDCLASS));
+
+ wc.hInstance = hInstance;
+ wc.lpszClassName = NWC_OMBROWSERVIEW;
+ wc.lpfnWndProc = BrowserView_WindowProc;
+ wc.style = CS_DBLCLKS;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = NULL;
+ wc.cbWndExtra = sizeof(BROWSERVIEW*);
+
+ return ( 0 != RegisterClassW(&wc));
+} \ No newline at end of file
diff --git a/Src/omBrowser/browserView.h b/Src/omBrowser/browserView.h
new file mode 100644
index 00000000..d8eca0cc
--- /dev/null
+++ b/Src/omBrowser/browserView.h
@@ -0,0 +1,48 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_VIEW_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_VIEW_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./browserUiCommon.h"
+
+#define NWC_OMBROWSERVIEW L"Nullsoft_omBrowserView"
+
+// {13A6B4C7-1881-4a55-B375-26DF2A830825}
+static const GUID WTID_BrowserView =
+{ 0x13a6b4c7, 0x1881, 0x4a55, { 0xb3, 0x75, 0x26, 0xdf, 0x2a, 0x83, 0x8, 0x25 } };
+
+
+class obj_ombrowser;
+HWND BrowserView_Create(obj_ombrowser *browserManager, ifc_omservice *service, HWND hParent, LPCWSTR redirectUrl, UINT style);
+
+// browser common messages
+#define BrowserView_GetToolbar(/*HWND*/ __hwndView)\
+ BrowserControl_GetToolbar(__hwndView)
+
+#define BrowserView_GetStatusbar(/*HWND*/ __hwndView)\
+ BrowserControl_GetStatusbar(__hwndView)
+
+#define BrowserView_GetHost(/*HWND*/ __hwndView)\
+ BrowserControl_GetHost(__hwndView)
+
+#define BrowserView_UpdateSkin(/*HWND*/ __hwndView, /*BOOL*/ __fRedraw)\
+ BrowserControl_UpdateSkin(__hwndView, __fRedraw)
+
+#define BrowserView_GetService(/*HWND*/ __hwndView, /*ifc_omservice** */ __serviceOut)\
+ BrowserControl_GetService(__hwndView, __serviceOut)
+
+#define BrowserView_Navigate(/*HWND*/ __hwndView, /*LPCWSTR*/ __navigateUrl, /*BOOL*/ __scheduleBlocked)\
+ BrowserControl_Navigate(__hwndView, __navigateUrl, __scheduleBlocked)
+
+#define BrowserView_NavigateHome(/*HWND*/ __hwndView, /*BOOL*/ __scheduleBlocked)\
+ BrowserView_Navigate((__hwndView), NAVIGATE_HOME, (__scheduleBlocked))
+
+#define BrowserView_WriteDocument(/*HWND*/ __hwndView, /*BSTR*/ __documentData, /*BOOL*/ __scheduleBlocked)\
+ BrowserControl_WriteDocument(__hwndView, __documentData, __scheduleBlocked)
+
+#define BrowserView_ShowOperation(/*HWND*/ __hwndView, /*const OPERATIONINFO* */ __pOperationInfo)\
+ BrowserControl_ShowOperation(__hwndView, __pOperationInfo)
+
+#endif // NULLSOFT_WINAMP_OMBROWSER_VIEW_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/browserWndEnum.cpp b/Src/omBrowser/browserWndEnum.cpp
new file mode 100644
index 00000000..24759772
--- /dev/null
+++ b/Src/omBrowser/browserWndEnum.cpp
@@ -0,0 +1,179 @@
+#include "main.h"
+#include "./browserWndEnum.h"
+#include "./browserWndRecord.h"
+#include "./browserView.h"
+#include "./browserPopup.h"
+#include "./ifc_omservice.h"
+
+
+OmBrowserWndEnumerator::OmBrowserWndEnumerator(const GUID *windowTypeFilter, const UINT *serviceIdFilter, OmBrowserWndRecord * const *windowList, size_t windowListSize)
+ : ref(1), index(0), list(NULL), size(0), filterId(FALSE), filterType(FALSE)
+{
+ if (NULL != serviceIdFilter)
+ {
+ serviceId = *serviceIdFilter;
+ filterId = TRUE;
+ }
+ else
+ serviceId = 0;
+
+ if (NULL != windowTypeFilter)
+ {
+ windowType = *windowTypeFilter;
+ filterType = TRUE;
+ }
+ else
+ windowType = GUID_NULL;
+
+ if (NULL != windowList && 0 != windowListSize)
+ {
+ list = (OmBrowserWndRecord**)calloc(windowListSize, sizeof(OmBrowserWndRecord*));
+ if (NULL != list)
+ {
+ for (size_t i = 0; i < windowListSize; i++)
+ {
+ list[i] = windowList[i];
+ list[i]->AddRef();
+ }
+ size = windowListSize;
+ }
+ }
+
+}
+
+OmBrowserWndEnumerator::~OmBrowserWndEnumerator()
+{
+ if (NULL != list)
+ {
+ for (size_t i = 0; i < size; i++)
+ {
+ list[i]->Release();
+ }
+ free(list);
+ }
+}
+
+HRESULT OmBrowserWndEnumerator::CreateInstance(const GUID *windowTypeFilter, const UINT *serviceIdFilter, OmBrowserWndRecord * const* windowList, size_t windowListSize, OmBrowserWndEnumerator **instance)
+{
+ if (NULL == instance) return E_POINTER;
+
+ *instance = new OmBrowserWndEnumerator(windowTypeFilter, serviceIdFilter, windowList, windowListSize);
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t OmBrowserWndEnumerator::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t OmBrowserWndEnumerator::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int OmBrowserWndEnumerator::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmBrowserWindowEnumerator))
+ *object = static_cast<ifc_ombrowserwndenum*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT OmBrowserWndEnumerator::Next(ULONG listSize, HWND *elementList, ULONG *elementCount)
+{
+ if (NULL == elementList || 0 == listSize) return E_INVALIDARG;
+ if (index >= size)
+ {
+ if (NULL != elementCount) *elementCount = 0;
+ return S_FALSE;
+ }
+
+ ULONG count = 0;
+
+ for (;index < size && count < listSize; index++)
+ {
+ OmBrowserWndRecord *r = list[index];
+
+ if (FALSE != filterType)
+ {
+ if (S_OK != r->IsEqualType(&windowType))
+ continue;
+ }
+
+ if (FALSE != filterId)
+ {
+ BOOL passOk = FALSE;
+ if (S_OK == r->IsEqualType(&WTID_BrowserView) ||
+ S_OK == r->IsEqualType(&WTID_BrowserPopup))
+ {
+ ifc_omservice *service;
+ if (FALSE != SendMessage(r->GetHwnd(), NBCM_GETSERVICE, 0, (LPARAM)&service) && NULL != service)
+ {
+ if (serviceId == service->GetId())
+ passOk = TRUE;
+
+ service->Release();
+ }
+ }
+
+ if (FALSE == passOk)
+ continue;
+ }
+
+ elementList[count] = r->GetHwnd();
+ count++;
+
+ }
+
+ if (NULL != elementCount) *elementCount = count;
+
+ return (count == listSize) ? S_OK : S_FALSE;
+}
+
+HRESULT OmBrowserWndEnumerator::Reset(void)
+{
+ index = 0;
+ return S_OK;
+}
+
+HRESULT OmBrowserWndEnumerator::Skip(ULONG elementCount)
+{
+ index += elementCount;
+ if (index >= size)
+ {
+ index = (size - 1);
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
+#define CBCLASS OmBrowserWndEnumerator
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_NEXT, Next)
+CB(API_RESET, Reset)
+CB(API_SKIP, Skip)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/browserWndEnum.h b/Src/omBrowser/browserWndEnum.h
new file mode 100644
index 00000000..977c731e
--- /dev/null
+++ b/Src/omBrowser/browserWndEnum.h
@@ -0,0 +1,48 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_WINDOW_ENUMERATOR_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_WINDOW_ENUMERATOR_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_ombrowserwndenum.h"
+
+class OmBrowserWndRecord;
+
+class OmBrowserWndEnumerator : public ifc_ombrowserwndenum
+{
+
+protected:
+ OmBrowserWndEnumerator(const GUID *windowTypeFilter, const UINT *serviceIdFilter, OmBrowserWndRecord * const *windowList, size_t windowListSize);
+ ~OmBrowserWndEnumerator();
+
+public:
+ static HRESULT CreateInstance(const GUID *windowTypeFilter, const UINT *serviceIdFilter, OmBrowserWndRecord * const *windowList, size_t windowListSize, OmBrowserWndEnumerator **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_ombrowserwndenum */
+ HRESULT Next(ULONG listSize, HWND *elementList, ULONG *elementCount);
+ HRESULT Reset(void);
+ HRESULT Skip(ULONG elementCount);
+
+protected:
+ ULONG ref;
+ size_t index;
+ OmBrowserWndRecord **list;
+ size_t size;
+ UINT serviceId;
+ GUID windowType;
+ BOOL filterId;
+ BOOL filterType;
+
+protected:
+ RECVS_DISPATCH;
+
+};
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_WINDOW_ENUMERATOR_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/browserWndRecord.cpp b/Src/omBrowser/browserWndRecord.cpp
new file mode 100644
index 00000000..b8fae1a1
--- /dev/null
+++ b/Src/omBrowser/browserWndRecord.cpp
@@ -0,0 +1,67 @@
+#include "main.h"
+#include "./browserWndRecord.h"
+
+OmBrowserWndRecord::OmBrowserWndRecord(HWND hwnd, const GUID *type)
+ : ref(1)
+{
+ this->hwnd = hwnd;
+ this->type = (NULL != type) ? *type : GUID_NULL;
+}
+
+OmBrowserWndRecord::~OmBrowserWndRecord()
+{
+
+}
+
+HRESULT OmBrowserWndRecord::CreateInstance(HWND hwnd, const GUID *type, OmBrowserWndRecord **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ if (NULL == hwnd)
+ {
+ *instance = NULL;
+ return E_INVALIDARG;
+ }
+ *instance = new OmBrowserWndRecord(hwnd, type);
+ if (NULL == *instance) return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+ULONG OmBrowserWndRecord::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+ULONG OmBrowserWndRecord::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+HWND OmBrowserWndRecord::GetHwnd()
+{
+ return hwnd;
+}
+
+HRESULT OmBrowserWndRecord::GetType(GUID *windowType)
+{
+ if (NULL == windowType) return E_POINTER;
+ *windowType = type;
+ return S_OK;
+}
+
+HRESULT OmBrowserWndRecord::IsEqualType(const GUID *windowType)
+{
+ if (NULL == windowType)
+ {
+ return (FALSE != IsEqualGUID(GUID_NULL, type)) ? S_OK : S_FALSE;
+ }
+
+ return (FALSE != IsEqualGUID(*windowType, type)) ? S_OK : S_FALSE;
+}
+
diff --git a/Src/omBrowser/browserWndRecord.h b/Src/omBrowser/browserWndRecord.h
new file mode 100644
index 00000000..6d5ce699
--- /dev/null
+++ b/Src/omBrowser/browserWndRecord.h
@@ -0,0 +1,33 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_WINDOW_RECORD_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_WINDOW_RECORD_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+class OmBrowserWndRecord
+{
+protected:
+ OmBrowserWndRecord(HWND hwnd, const GUID *type);
+ ~OmBrowserWndRecord();
+public:
+ static HRESULT CreateInstance(HWND hwnd, const GUID *type, OmBrowserWndRecord **instance);
+
+public:
+ ULONG AddRef();
+ ULONG Release();
+
+ HWND GetHwnd();
+ HRESULT GetType(GUID *windowType);
+ HRESULT IsEqualType(const GUID *windowType);
+
+protected:
+ ULONG ref;
+ HWND hwnd;
+ GUID type;
+};
+
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_WINDOW_RECORD_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/cacheDownloader.cpp b/Src/omBrowser/cacheDownloader.cpp
new file mode 100644
index 00000000..44f3af70
--- /dev/null
+++ b/Src/omBrowser/cacheDownloader.cpp
@@ -0,0 +1,274 @@
+#include "main.h"
+
+#include "./cacheDownloader.h"
+#include "./cacheRecord.h"
+#include "./ifc_wasabihelper.h"
+
+#include "..\Components\wac_network\wac_network_http_receiver_api.h"
+
+#include <strsafe.h>
+
+CacheDownloader::CacheDownloader(CacheRecord *record, BOOL fEnableCompression)
+ : ref(1), manager(NULL), cookie(NULL), owner(record), state(stateReady), enableCompression(fEnableCompression)
+{
+ InitializeCriticalSection(&lock);
+}
+
+CacheDownloader::~CacheDownloader()
+{
+ EnterCriticalSection( &lock );
+
+ if ( manager != NULL )
+ {
+ if ( NULL != cookie )
+ {
+ Abort();
+ }
+
+ ifc_wasabihelper *wasabi;
+ if ( SUCCEEDED( Plugin_GetWasabiHelper( &wasabi ) ) )
+ {
+ wasabi->ReleaseWasabiInterface( &DownloadManagerGUID, (void **)&manager );
+ wasabi->Release();
+ }
+ manager = NULL;
+ }
+
+ LeaveCriticalSection( &lock );
+ DeleteCriticalSection( &lock );
+}
+
+HRESULT CacheDownloader::CreateInstance(CacheRecord *record, LPCWSTR pszAddress, BOOL fEnableCompression, CacheDownloader **instance)
+{
+
+ if (NULL == instance) return E_POINTER;
+ *instance = NULL;
+
+ if (NULL == record || NULL == pszAddress || L'\0' == *pszAddress)
+ return E_INVALIDARG;
+
+ HRESULT hr;
+
+ *instance = new CacheDownloader(record, fEnableCompression);
+ if (NULL == *instance)
+ {
+ hr = E_OUTOFMEMORY;
+ }
+ else
+ {
+ hr = (*instance)->Start(pszAddress);
+ if (FAILED(hr))
+ {
+ (*instance)->Release();
+ *instance = NULL;
+ }
+ }
+
+ return hr;
+
+}
+
+size_t CacheDownloader::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t CacheDownloader::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int CacheDownloader::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ *object = NULL;
+ return E_NOINTERFACE;
+
+}
+
+HRESULT CacheDownloader::Start(LPCWSTR pszAddress)
+{
+ HRESULT hr = S_OK;
+
+ LPSTR address = Plugin_WideCharToMultiByte(CP_ACP, 0, pszAddress, -1, NULL, NULL);
+ if (NULL == address) return E_OUTOFMEMORY;
+
+
+ EnterCriticalSection(&lock);
+ state = stateInitializing;
+ LeaveCriticalSection(&lock);
+
+ if ( manager == NULL )
+ {
+ ifc_wasabihelper *wasabi;
+ hr = Plugin_GetWasabiHelper(&wasabi);
+ if (SUCCEEDED(hr))
+ {
+ hr = wasabi->QueryWasabiInterface(&DownloadManagerGUID, (void**)&manager);
+ wasabi->Release();
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ cookie = manager->DownloadEx(address, this, api_downloadManager::DOWNLOADEX_TEMPFILE);
+ if (NULL == cookie)
+ {
+ hr = E_FAIL;
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ EnterCriticalSection(&lock);
+ state = stateCompleted;
+ LeaveCriticalSection(&lock);
+ }
+
+ Plugin_FreeAnsiString(address);
+ return hr;
+}
+
+HRESULT CacheDownloader::Abort()
+{
+ HRESULT hr;
+ EnterCriticalSection(&lock);
+
+ if (NULL == manager || NULL == cookie)
+ {
+ hr = E_UNEXPECTED;
+ }
+ else if (stateCompleted == state)
+ {
+ hr = S_FALSE;
+ }
+ else
+ {
+ state = stateAborting;
+ manager->CancelDownload(cookie);
+ hr = S_OK;
+ }
+
+ LeaveCriticalSection(&lock);
+ return hr;
+}
+
+UINT CacheDownloader::GetState()
+{
+ return state;
+}
+
+HRESULT CacheDownloader::SetOwner(CacheRecord *record)
+{
+ owner = record;
+ return S_OK;
+}
+
+HRESULT CacheDownloader::DownloadCompleted(INT errorCode)
+{
+ AddRef();
+ EnterCriticalSection(&lock);
+
+ state = stateCompleted;
+
+ if (NULL != owner)
+ {
+ LPCWSTR pszFile = (api_downloadManager::TICK_SUCCESS == errorCode) ? manager->GetLocation(cookie) : NULL;
+
+ owner->DownloadCompleted(pszFile, errorCode);
+ owner = NULL;
+ }
+
+ manager->ReleaseDownload(cookie);
+ cookie = NULL;
+
+ ifc_wasabihelper *wasabi;
+ if (SUCCEEDED(Plugin_GetWasabiHelper(&wasabi)))
+ {
+ wasabi->ReleaseWasabiInterface(&DownloadManagerGUID, (void**)&manager);
+ wasabi->Release();
+ manager = NULL;
+ }
+
+ LeaveCriticalSection(&lock);
+
+ Release();
+ return S_OK;
+}
+
+void CacheDownloader::OnInit(DownloadToken token)
+{
+ EnterCriticalSection(&lock);
+
+ cookie = token;
+ if (NULL != cookie)
+ {
+ manager->RetainDownload(cookie);
+ }
+
+ state = stateConnecting;
+
+ if (FALSE != enableCompression)
+ {
+ api_httpreceiver *receiver = manager->GetReceiver(token);
+ if (NULL != receiver)
+ receiver->AllowCompression();
+ }
+
+ LeaveCriticalSection(&lock);
+}
+
+void CacheDownloader::OnFinish(DownloadToken token)
+{
+ DownloadCompleted(api_downloadManager::TICK_SUCCESS);
+}
+
+void CacheDownloader::OnError(DownloadToken token, int errorCode)
+{
+ DownloadCompleted(errorCode);
+}
+
+void CacheDownloader::OnCancel(DownloadToken token)
+{
+ DownloadCompleted(api_downloadManager::TICK_NODATA);
+}
+
+void CacheDownloader::OnTick(DownloadToken token)
+{
+ EnterCriticalSection(&lock);
+
+ if (stateConnecting == state)
+ state = stateReceiving;
+ LeaveCriticalSection(&lock);
+
+}
+
+void CacheDownloader::OnConnect(DownloadToken dlToken)
+{
+ EnterCriticalSection(&lock);
+ state = stateReceiving;
+ LeaveCriticalSection(&lock);
+}
+
+
+#define CBCLASS CacheDownloader
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+VCB(IFC_DOWNLOADMANAGERCALLBACK_ONFINISH, OnFinish)
+VCB(IFC_DOWNLOADMANAGERCALLBACK_ONTICK, OnTick)
+VCB(IFC_DOWNLOADMANAGERCALLBACK_ONERROR, OnError)
+VCB(IFC_DOWNLOADMANAGERCALLBACK_ONCANCEL, OnCancel)
+VCB(IFC_DOWNLOADMANAGERCALLBACK_ONCONNECT, OnConnect)
+VCB(IFC_DOWNLOADMANAGERCALLBACK_ONINIT, OnInit)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/cacheDownloader.h b/Src/omBrowser/cacheDownloader.h
new file mode 100644
index 00000000..380180c4
--- /dev/null
+++ b/Src/omBrowser/cacheDownloader.h
@@ -0,0 +1,73 @@
+#ifndef NULLSOFT_WINAMP_CACHE_DOWNLOADER_HEADER
+#define NULLSOFT_WINAMP_CACHE_DOWNLOADER_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+#include "../Components/wac_downloadManager/wac_downloadManager_api.h"
+
+class CacheCallback;
+class CacheRecord;
+
+
+class CacheDownloader : public ifc_downloadManagerCallback
+{
+public:
+ typedef enum
+ {
+ stateReady = 0,
+ stateInitializing = 1,
+ stateConnecting = 2,
+ stateReceiving = 3,
+ stateCompleted = 4,
+ stateAborting = 5,
+ } States;
+
+protected:
+ CacheDownloader(CacheRecord *record, BOOL fEnableCompression);
+ ~CacheDownloader();
+
+public:
+ static HRESULT CreateInstance(CacheRecord *record, LPCWSTR pszAddress, BOOL fEnableCompression, CacheDownloader **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ HRESULT Abort();
+ UINT GetState();
+
+ HRESULT SetOwner(CacheRecord *record);
+
+protected:
+ HRESULT Start(LPCWSTR pszAddress);
+ HRESULT DownloadCompleted(INT errorCode);
+
+ /* ifc_downloadManagerCallback */
+ void OnFinish(DownloadToken token);
+ void OnTick(DownloadToken token);
+ void OnError(DownloadToken token, int errorCode);
+ void OnCancel(DownloadToken token);
+ void OnConnect(DownloadToken token);
+ void OnInit(DownloadToken token);
+
+protected:
+ RECVS_DISPATCH;
+
+protected:
+ ULONG ref;
+ api_downloadManager *manager;
+ DownloadToken cookie;
+ CacheRecord *owner; // owner not ref counted
+ UINT state;
+ BOOL enableCompression;
+ CRITICAL_SECTION lock;
+};
+
+
+#endif //NULLSOFT_WINAMP_CACHE_DOWNLOADER_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/cacheGroup.cpp b/Src/omBrowser/cacheGroup.cpp
new file mode 100644
index 00000000..dab4d5d8
--- /dev/null
+++ b/Src/omBrowser/cacheGroup.cpp
@@ -0,0 +1,472 @@
+#include "main.h"
+#include "./cacheGroup.h"
+#include "./cacheRecord.h"
+#include "./cacheManager.h"
+
+#include <wininet.h>
+#include <shlwapi.h>
+#include <strsafe.h>
+#include <algorithm>
+
+CacheGroup::CacheGroup(LPCWSTR pszName)
+ : ref(1), name(NULL), owner(NULL)
+{
+ name = Plugin_CopyString(pszName);
+}
+
+CacheGroup::~CacheGroup()
+{
+ Clear();
+
+ Plugin_FreeString(name);
+}
+
+HRESULT CacheGroup::CreateInstance(LPCWSTR pszName, CacheGroup **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ *instance = NULL;
+
+ *instance = new CacheGroup(pszName);
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+
+}
+
+size_t CacheGroup::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t CacheGroup::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int CacheGroup::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmCacheGroup))
+ *object = static_cast<ifc_omcachegroup*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT CacheGroup::SetOwner(CacheManager *group)
+{
+ owner = group;
+ return S_OK;
+}
+
+HRESULT CacheGroup::GetName(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ if (NULL == pszBuffer || 0 == cchBufferMax)
+ return E_INVALIDARG;
+
+ return StringCchCopyEx(pszBuffer, cchBufferMax, name, NULL, NULL, STRSAFE_IGNORE_NULLS);
+}
+
+HRESULT CacheGroup::IsEqualName(LPCWSTR pszGroup)
+{
+ if (NULL == pszGroup)
+ return (NULL == name) ? S_OK : S_FALSE;
+
+ if (NULL == name) return S_FALSE;
+
+ INT result = CompareString(CSTR_INVARIANT, NORM_IGNORECASE, pszGroup, -1, name, -1);
+ if (0 == result)
+ {
+ DWORD error = GetLastError();
+ return HRESULT_FROM_WIN32(error);
+ }
+ return (CSTR_EQUAL == result) ? S_OK : S_FALSE;
+}
+
+HRESULT CacheGroup::IsEqual(CacheGroup *group)
+{
+ return (NULL != group) ? IsEqualName(group->name) : E_INVALIDARG;
+}
+
+HRESULT CacheGroup::IsEmpty()
+{
+ return (0 == recordList.size()) ? S_OK : S_FALSE;
+}
+
+HRESULT CacheGroup::Delete(LPCWSTR pszName)
+{
+ HRESULT hr = S_FALSE;
+ size_t index = recordList.size();
+
+ while(index--)
+ {
+ CacheRecord *record = recordList[index];
+ if (NULL != record && S_OK == record->IsEqualName(pszName))
+ {
+ recordList.erase(recordList.begin() + index);
+ record->Release();
+ hr = S_OK;
+ break;
+ }
+ }
+
+ return hr;
+}
+
+HRESULT CacheGroup::Clear()
+{
+ size_t index = recordList.size();
+
+ while(index--)
+ {
+ CacheRecord *record = recordList[index];
+ if (NULL != record) record->Release();
+ }
+
+ recordList.clear();
+
+ return S_OK;
+}
+
+__inline static int __cdecl CacheGroup_RecordSearch(const void *elem1, const void *elem2)
+{
+ int r = ((CacheRecord*)elem2)->CompareTo((LPCWSTR)elem1);
+ return -r;
+}
+
+HRESULT CacheGroup::Find(LPCWSTR pszName, BOOL fInsertMissing, CacheRecord **recordOut, BOOL *created)
+{
+ if (NULL != created)
+ *created = FALSE;
+
+ if (NULL == recordOut)
+ return E_POINTER;
+
+ HRESULT hr = S_FALSE;
+ size_t index = recordList.size();
+ if (0 != index)
+ {
+ //CacheRecord *rec = (CacheRecord*)bsearch(pszName, recordList.at(0), recordList.size(), sizeof(CacheRecord*), CacheGroup_RecordSearch);
+ auto it = std::find_if(recordList.begin(), recordList.end(),
+ [&](CacheRecord* upT) -> bool
+ {
+ return upT->CompareTo(pszName) == 0;
+ }
+ );
+ if (it != recordList.end())
+ {
+ *recordOut = *it;
+ (*recordOut)->AddRef();
+ hr = S_OK;
+ }
+ }
+
+ if (S_FALSE == hr && FALSE != fInsertMissing)
+ {
+ hr = CacheRecord::CreateInstance(pszName, NULL, 0, recordOut);
+ if (SUCCEEDED(hr))
+ {
+ recordList.push_back(*recordOut);
+ Sort();
+
+ (*recordOut)->AddRef();
+ (*recordOut)->SetOwner(this);
+
+ if (NULL != created)
+ *created = TRUE;
+ }
+ }
+
+ if (S_OK != hr)
+ *recordOut = NULL;
+
+ return hr;
+}
+
+HRESULT CacheGroup::GetPath(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ if (NULL == pszBuffer || 0 == cchBufferMax)
+ return E_INVALIDARG;
+
+ HRESULT hr;
+
+ if (NULL != owner)
+ {
+ hr = owner->GetPath(pszBuffer, cchBufferMax);
+ if (SUCCEEDED(hr) && NULL != name)
+ {
+ if (FALSE == PathAppend(pszBuffer, name))
+ hr = E_OUTOFMEMORY;
+ }
+ }
+ else
+ {
+ *pszBuffer = L'\0';
+ hr = E_UNEXPECTED;
+ }
+
+ return hr;
+}
+
+static HRESULT CacheGroup_FormatStoreData(LPWSTR pszBuffer, size_t cchBufferMax, LPCWSTR pszPath, UINT *cchLength)
+{
+ if (NULL == pszBuffer)
+ return E_INVALIDARG;
+
+ size_t remaining = cchBufferMax;
+ HRESULT hr;
+ hr = StringCchCopyEx(pszBuffer, remaining, L"path=", &pszBuffer, &remaining, 0);
+ if (FAILED(hr)) return hr;
+
+ hr = StringCchCopyEx(pszBuffer, remaining, pszPath, &pszBuffer, &remaining, 0);
+ if (FAILED(hr)) return hr;
+
+ if (0 == remaining)
+ return E_OUTOFMEMORY;
+
+ remaining--;
+ pszBuffer++;
+ *pszBuffer = L'\0';
+
+ if (NULL != cchLength)
+ *cchLength = (UINT)(cchBufferMax - remaining) + 1;
+
+ return S_OK;
+}
+
+HRESULT CacheGroup::Store(LPCWSTR pszName, LPCWSTR pszPath)
+{
+ HRESULT hr;
+ WCHAR szBuffer[2048] = {0};
+
+ hr = GetPath(szBuffer, ARRAYSIZE(szBuffer));
+ if (FAILED(hr)) return hr;
+
+ Plugin_EnsurePathExist(szBuffer);
+
+ if (FALSE == PathAppend(szBuffer, L"cache.ini"))
+ return E_OUTOFMEMORY;
+
+ LPSTR pathAnsi = Plugin_WideCharToMultiByte(CP_UTF8, 0, szBuffer, -1, NULL, NULL);
+ if (NULL == pathAnsi) return E_OUTOFMEMORY;
+
+ LPSTR nameAnsi = Plugin_WideCharToMultiByte(CP_UTF8, 0, pszName, -1, NULL, NULL);
+ if (NULL == nameAnsi) return E_OUTOFMEMORY;
+
+ LPSTR dataAnsi = NULL;
+ if (NULL != pszPath)
+ {
+ UINT cchData;
+ hr = CacheGroup_FormatStoreData(szBuffer, ARRAYSIZE(szBuffer), pszPath, &cchData);
+ if (SUCCEEDED(hr))
+ {
+ dataAnsi = Plugin_WideCharToMultiByte(CP_UTF8, 0, szBuffer, cchData, NULL, NULL);
+ if (NULL == dataAnsi)
+ hr = E_OUTOFMEMORY;
+ }
+ }
+
+ if (SUCCEEDED(hr) && 0 == WritePrivateProfileSectionA(nameAnsi, dataAnsi, pathAnsi))
+ {
+ DWORD error = GetLastError();
+ hr = HRESULT_FROM_WIN32(error);
+ }
+
+ Plugin_FreeAnsiString(dataAnsi);
+ Plugin_FreeAnsiString(nameAnsi);
+ Plugin_FreeAnsiString(pathAnsi);
+
+ return hr;
+}
+
+HRESULT CacheGroup::Load()
+{
+ HRESULT hr;
+ WCHAR szBuffer[4096] = {0};
+
+ hr = GetPath(szBuffer, ARRAYSIZE(szBuffer));
+ if (FAILED(hr)) return hr;
+
+ if (FALSE == PathAppend(szBuffer, L"cache.ini"))
+ return E_OUTOFMEMORY;
+
+ HANDLE hFile = CreateFile(szBuffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
+ if (INVALID_HANDLE_VALUE == hFile)
+ {
+ DWORD error = GetLastError();
+ return HRESULT_FROM_WIN32(error);
+ }
+
+ DWORD read = 0;
+ CHAR szLine[INTERNET_MAX_URL_LENGTH + 3] = {0};
+ WCHAR szUnicode[ARRAYSIZE(szLine)] = {0};
+ UINT lineIndex = 0;
+ CacheRecord *record = NULL;
+ UINT recordSet = 0;
+ size_t inserted = 0;
+
+ RecordList cleanupList;
+
+ while (0 != ReadFile(hFile, szBuffer, sizeof(szBuffer), &read, NULL))
+ {
+ LPCSTR cursor = (LPCSTR)szBuffer;
+ LPCSTR end = cursor + read;
+
+ for(;;)
+ {
+ if (cursor >= end)
+ break;
+
+ if (cursor == end || ('\r' == *cursor && '\n' == *(cursor+1)))
+ {
+ szLine[lineIndex] = '\0';
+
+ if (lineIndex > 0)
+ {
+ if ('[' == szLine[0] && ']' == szLine[lineIndex-1])
+ {
+ if (NULL != record)
+ {
+ if (0 != (0x00000001 & recordSet))
+ {
+ recordList.push_back(record);
+ inserted++;
+ }
+ else
+ {
+ cleanupList.push_back(record);
+ }
+
+ record = NULL;
+ }
+
+ szLine[lineIndex-1] = '\0';
+ if (0 != MultiByteToWideChar(CP_UTF8, 0, szLine + 1, -1, szUnicode, ARRAYSIZE(szUnicode)) &&
+ SUCCEEDED(CacheRecord::CreateInstance(szUnicode, NULL, 0, &record)))
+ {
+ record->SetOwner(this);
+ recordSet = 0;
+ }
+ }
+ else
+ {
+ const char kw_path[] = "path=";
+ UINT cchKey = ARRAYSIZE(kw_path) - 1;
+ if (NULL != record &&
+ lineIndex > cchKey &&
+ CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, NORM_IGNORECASE, kw_path, cchKey, szLine, cchKey) &&
+ 0 != MultiByteToWideChar(CP_UTF8, 0, szLine + cchKey, -1, szUnicode, ARRAYSIZE(szUnicode)))
+ {
+ if(SUCCEEDED(record->SetPath(szUnicode)) &&
+ SUCCEEDED(record->GetPath(szUnicode, ARRAYSIZE(szUnicode))) &&
+ FALSE != PathFileExists(szUnicode))
+ {
+ recordSet |= 0x00000001;
+ }
+ }
+ }
+
+ }
+
+ lineIndex = 0;
+ cursor += 2;
+ continue;
+ }
+
+ if (lineIndex < ARRAYSIZE(szLine) - 2)
+ {
+ szLine[lineIndex++] = *cursor;
+ }
+
+ cursor++;
+ }
+
+ if (0 == read)
+ {
+ if (NULL != record)
+ {
+ if (0 != (0x00000001 & recordSet))
+ {
+ recordList.push_back(record);
+ inserted++;
+ }
+ else
+ record->Release();
+ }
+ break;
+ }
+ }
+ CloseHandle(hFile);
+
+ if (0 != inserted)
+ {
+ Sort();
+ }
+
+ size_t i = cleanupList.size();
+ if (0 != i)
+ {
+ while (i--)
+ {
+ aTRACE_LINE("ADD CACHE CLEANUP!!!!");
+ cleanupList[i]->Release();
+ }
+ }
+ return S_OK;
+}
+
+__inline static int __cdecl CacheGroup_RecordComparer(const void *elem1, const void *elem2)
+{
+ return CacheRecord::Compare((CacheRecord*)elem1, (CacheRecord*)elem2);
+}
+
+__inline static bool __cdecl CacheGroup_RecordComparer_V2(const void* elem1, const void* elem2)
+{
+ return CacheGroup_RecordComparer(elem1, elem2) < 0;
+}
+
+HRESULT CacheGroup::Sort()
+{
+ HRESULT hr;
+ if (0 == recordList.size())
+ {
+ hr = S_FALSE;
+ }
+ else
+ {
+ //qsort(recordList.first(), recordList.size(), sizeof(CacheRecord*), CacheGroup_RecordComparer);
+ std::sort(recordList.begin(), recordList.end(), CacheGroup_RecordComparer_V2);
+ hr = S_OK;
+ }
+
+ return hr;
+
+}
+
+#define CBCLASS CacheGroup
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_GETNAME, GetName)
+CB(API_FIND, Find)
+CB(API_DELETE, Delete)
+CB(API_CLEAR, Clear)
+
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/cacheGroup.h b/Src/omBrowser/cacheGroup.h
new file mode 100644
index 00000000..c8428fb1
--- /dev/null
+++ b/Src/omBrowser/cacheGroup.h
@@ -0,0 +1,63 @@
+#ifndef NULLSOFT_WINAMP_CACHE_GROUP_HEADER
+#define NULLSOFT_WINAMP_CACHE_GROUP_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+#include "./ifc_omcachegroup.h"
+#include <vector>
+
+
+class CacheRecord;
+class CacheManager;
+
+class CacheGroup : public ifc_omcachegroup
+{
+
+protected:
+ CacheGroup(LPCWSTR pszName);
+ ~CacheGroup();
+
+public:
+ static HRESULT CreateInstance(LPCWSTR pszName, CacheGroup **instace);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ HRESULT SetOwner(CacheManager *group);
+ HRESULT IsEqual(CacheGroup *group);
+ HRESULT IsEqualName(LPCWSTR pszGroup);
+ HRESULT IsEmpty();
+
+ HRESULT GetName(LPWSTR pszBuffer, UINT cchBufferMax);
+
+ HRESULT Find(LPCWSTR pszName, BOOL fInsertMissing, CacheRecord **recordOut, BOOL *created);
+ HRESULT Delete(LPCWSTR pszName);
+ HRESULT Clear();
+
+ HRESULT Store(LPCWSTR pszName, LPCWSTR pszPath);
+ HRESULT Load();
+
+ HRESULT GetPath(LPWSTR pszBuffer, UINT cchBufferMax);
+
+protected:
+ HRESULT Sort();
+
+protected:
+
+ RECVS_DISPATCH;
+ typedef std::vector<CacheRecord*> RecordList;
+
+protected:
+ size_t ref;
+ LPWSTR name;
+ CacheManager *owner;
+ RecordList recordList;
+};
+
+#endif //NULLSOFT_WINAMP_CACHE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/cacheManager.cpp b/Src/omBrowser/cacheManager.cpp
new file mode 100644
index 00000000..babe35de
--- /dev/null
+++ b/Src/omBrowser/cacheManager.cpp
@@ -0,0 +1,192 @@
+#include "main.h"
+#include "./cacheManager.h"
+#include "./cacheGroup.h"
+
+#include "./ifc_wasabihelper.h"
+
+#include <shlwapi.h>
+#include <strsafe.h>
+
+CacheManager::CacheManager()
+ : ref(1)
+{
+
+}
+
+CacheManager::~CacheManager()
+{
+ Clear();
+}
+
+HRESULT CacheManager::CreateInstance(CacheManager **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ *instance = NULL;
+
+ *instance = new CacheManager();
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+
+}
+
+size_t CacheManager::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t CacheManager::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int CacheManager::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmCacheManager))
+ *object = static_cast<ifc_omcachemanager*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+
+HRESULT CacheManager::Clear()
+{
+ size_t index = groupList.size();
+
+ while(index--)
+ {
+ CacheGroup *group = groupList[index];
+ if (NULL != group) group->Release();
+ }
+
+ groupList.clear();
+ return S_OK;
+}
+
+HRESULT CacheManager::Delete(LPCWSTR pszGroup)
+{
+ HRESULT hr = S_FALSE;
+ size_t index = groupList.size();
+
+ while(index--)
+ {
+ CacheGroup *group = groupList[index];
+ if (NULL != group && S_OK == group->IsEqualName(pszGroup))
+ {
+ groupList.erase(groupList.begin() + index);
+ group->Release();
+ hr = S_OK;
+ break;
+ }
+ }
+
+ return hr;
+}
+
+HRESULT CacheManager::Find(LPCWSTR pszGroup, BOOL fInsertMissing, CacheGroup **groupOut, BOOL *created)
+{
+ if (NULL != created) *created = FALSE;
+ if (NULL == groupOut) return E_POINTER;
+
+
+ HRESULT hr = S_FALSE;
+ size_t index = groupList.size();
+ CacheGroup *group;
+
+ while(index--)
+ {
+ group = groupList[index];
+ if (NULL != group && S_OK == group->IsEqualName(pszGroup))
+ {
+ *groupOut = group;
+ group->AddRef();
+ hr = S_OK;
+ break;
+ }
+ }
+
+ if (S_FALSE == hr && FALSE != fInsertMissing)
+ {
+ hr = CacheGroup::CreateInstance(pszGroup, &group);
+ if (SUCCEEDED(hr))
+ {
+ groupList.push_back(group);
+ group->SetOwner(this);
+ group->Load();
+ group->AddRef();
+ *groupOut = group;
+ if (NULL != created) *created = TRUE;
+ }
+ }
+
+ if (S_OK != hr)
+ *groupOut = NULL;
+
+ return hr;
+}
+HRESULT CacheManager::Load()
+{
+ return S_OK;
+}
+
+
+HRESULT CacheManager::GetPath(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ if (NULL == pszBuffer || 0 == cchBufferMax)
+ return E_INVALIDARG;
+
+ HRESULT hr;
+ ifc_wasabihelper *wasabi;
+ hr = Plugin_GetWasabiHelper(&wasabi);
+ if (SUCCEEDED(hr))
+ {
+ api_application *application;
+ hr = wasabi->GetApplicationApi(&application);
+ if (SUCCEEDED(hr))
+ {
+ LPCWSTR pszUser = application->path_getUserSettingsPath();
+ if (NULL != pszUser)
+ {
+ if (NULL == PathCombine(pszBuffer, pszUser, L"Plugins\\omBrowser\\cache"))
+ hr = E_OUTOFMEMORY;
+ }
+ else
+ {
+ hr = E_UNEXPECTED;
+ }
+ application->Release();
+ }
+ wasabi->Release();
+
+ }
+ return hr;
+}
+
+#define CBCLASS CacheManager
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_FIND, Find)
+CB(API_DELETE, Delete)
+CB(API_CLEAR, Clear)
+
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/cacheManager.h b/Src/omBrowser/cacheManager.h
new file mode 100644
index 00000000..2ba3c94b
--- /dev/null
+++ b/Src/omBrowser/cacheManager.h
@@ -0,0 +1,47 @@
+#ifndef NULLSOFT_WINAMP_CACHE_MANAGER_HEADER
+#define NULLSOFT_WINAMP_CACHE_MANAGER_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+#include "./ifc_omcachemanager.h"
+#include <vector>
+
+class CacheGroup;
+
+class CacheManager : public ifc_omcachemanager
+{
+protected:
+ CacheManager();
+ ~CacheManager();
+
+public:
+ static HRESULT CreateInstance(CacheManager **instace);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ HRESULT Load();
+
+ /* group managment */
+ HRESULT Find(LPCWSTR pszGroup, BOOL fInsertMissing, CacheGroup **groupOut, BOOL *created);
+ HRESULT Delete(LPCWSTR pszGroup);
+ HRESULT Clear();
+
+ HRESULT GetPath(LPWSTR pszBuffer, UINT cchBufferMax);
+
+protected:
+ RECVS_DISPATCH;
+ typedef std::vector<CacheGroup*> GroupList;
+
+protected:
+ size_t ref;
+ GroupList groupList;
+};
+
+#endif //NULLSOFT_WINAMP_CACHE_MANAGER_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/cacheRecord.cpp b/Src/omBrowser/cacheRecord.cpp
new file mode 100644
index 00000000..3b11cf46
--- /dev/null
+++ b/Src/omBrowser/cacheRecord.cpp
@@ -0,0 +1,496 @@
+#include "main.h"
+#include "./cacheRecord.h"
+#include "./cacheDownloader.h"
+#include "./cacheGroup.h"
+#include "./ifc_omcachecallback.h"
+
+#include <shlwapi.h>
+#include <strsafe.h>
+
+CacheRecord::CacheRecord(LPCWSTR pszName, LPCWSTR pszAddress, UINT uFlags)
+ : ref(1), owner(NULL), name(NULL), path(NULL), flags(uFlags), downloader(NULL), callbackList(NULL)
+{
+ name = Plugin_CopyString(pszName);
+ path = Plugin_CopyString(pszAddress);
+
+ InitializeCriticalSection(&lock);
+}
+
+CacheRecord::~CacheRecord()
+{
+ Plugin_FreeString(name);
+ Plugin_FreeString(path);
+
+ EnterCriticalSection(&lock);
+
+ if (NULL != downloader)
+ {
+ downloader->SetOwner(NULL);
+ downloader->Release();
+ }
+
+ if (NULL != callbackList)
+ {
+ size_t index = callbackList->size();
+ while(index--)
+ {
+ ifc_omcachecallback *callback = callbackList->at(index);
+ if (NULL != callback) callback->Release();
+ }
+ delete(callbackList);
+ }
+
+ LeaveCriticalSection(&lock);
+
+ DeleteCriticalSection(&lock);
+}
+
+HRESULT CacheRecord::CreateInstance(LPCWSTR pszName, LPCWSTR pszAddress, UINT uFlags, CacheRecord **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ *instance = NULL;
+
+ if (NULL == pszName || L'\0' == *pszName) return E_INVALIDARG;
+
+ *instance = new CacheRecord(pszName, pszAddress, uFlags);
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+
+}
+
+INT CacheRecord::Compare(CacheRecord *record1, CacheRecord *record2)
+{
+ if (NULL == record1 || NULL == record2)
+ return (INT)(INT_PTR)(record1 - record2);
+
+ return record1->CompareTo(record2->name);
+}
+size_t CacheRecord::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t CacheRecord::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int CacheRecord::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmCacheRecord))
+ *object = static_cast<ifc_omcacherecord*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT CacheRecord::SetOwner(CacheGroup *group)
+{
+ EnterCriticalSection(&lock);
+ owner = group;
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+HRESULT CacheRecord::GetName(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ if (NULL == pszBuffer || 0 == cchBufferMax)
+ return E_INVALIDARG;
+
+ return StringCchCopyEx(pszBuffer, cchBufferMax, name, NULL, NULL, STRSAFE_IGNORE_NULLS);
+}
+
+HRESULT CacheRecord::GetPath(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ if (NULL == pszBuffer || 0 == cchBufferMax)
+ return E_INVALIDARG;
+
+ HRESULT hr;
+ EnterCriticalSection(&lock);
+
+ if (NULL == path)
+ {
+ *pszBuffer = L'\0';
+
+ if (NULL != downloader)
+ {
+ hr = E_PENDING;
+ }
+ else if (0 != (flagDownloadFailed & flags))
+ {
+ hr = E_FAIL;
+ }
+ else if (NULL != name && L'\0' != *name && PathIsURL(name) &&
+ CSTR_EQUAL != CompareString(CSTR_INVARIANT, NORM_IGNORECASE, name, 6, L"res://", 6))
+ {
+ hr = Download();
+ if (SUCCEEDED(hr)) hr = E_PENDING;
+ }
+ else
+ {
+ hr = E_FAIL;
+ }
+ }
+ else if (FALSE == PathIsRelative(path))
+ {
+ hr = StringCchCopy(pszBuffer, cchBufferMax, path);
+ }
+ else
+ {
+ if (NULL == owner)
+ {
+ hr = E_FAIL;
+ }
+ else if (FAILED(owner->GetPath(pszBuffer, cchBufferMax)) ||
+ FALSE == PathAppend(pszBuffer, path))
+ {
+ hr = E_OUTOFMEMORY;
+ }
+ else
+ {
+ hr = S_OK;
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+ return hr;
+}
+
+HRESULT CacheRecord::SetPath(LPCWSTR pszPath)
+{
+ EnterCriticalSection(&lock);
+
+ if (NULL != downloader)
+ {
+ downloader->Abort();
+ downloader->Release();
+ downloader = NULL;
+ }
+
+ Plugin_FreeString(path);
+ if (NULL == pszPath)
+ {
+ path = NULL;
+ }
+ else
+ {
+ INT cchCommon = 0;
+ if (0 != owner)
+ {
+ WCHAR szBase[MAX_PATH*2] = {0};
+ if (SUCCEEDED(owner->GetPath(szBase, ARRAYSIZE(szBase))))
+ cchCommon = PathCommonPrefix(szBase, pszPath, NULL);
+ }
+
+ if (0 != cchCommon)
+ {
+ LPCWSTR p = pszPath + cchCommon;
+ INT cchSource = lstrlenW(p) + 1/* \0 */;
+ path = Plugin_MallocString(cchSource + 1 /*to add '.'*/);
+ if (NULL != path)
+ {
+ *path = L'.';
+ CopyMemory(path + 1, p, sizeof(WCHAR) * cchSource);
+ }
+ }
+ else
+ {
+ path = Plugin_CopyString(pszPath);
+ }
+
+ if (NULL == path) return E_OUTOFMEMORY;
+ }
+
+ if (0 == (flagNoStore & flags) && NULL != owner)
+ owner->Store(name, path);
+
+ if (NULL != callbackList)
+ {
+ size_t index = callbackList->size();
+ while(index--)
+ {
+ ifc_omcachecallback *cb = callbackList->at(index);
+ if (NULL != cb) cb->PathChanged(this);
+ }
+ }
+ LeaveCriticalSection(&lock);
+ return S_OK;
+}
+
+HRESULT CacheRecord::Download()
+{
+ HRESULT hr;
+ EnterCriticalSection(&lock);
+
+ if (NULL != downloader)
+ hr = E_PENDING;
+ else
+ {
+ flags &= ~flagDownloadFailed;
+ hr = CacheDownloader::CreateInstance(this, name, FALSE, &downloader);
+ }
+
+ LeaveCriticalSection(&lock);
+ return hr;
+}
+
+HRESULT CacheRecord::DownloadCompleted(LPCWSTR pszFile, INT errorCode)
+{
+ HRESULT hr = S_OK;
+
+ EnterCriticalSection(&lock);
+
+ CacheDownloader *temp = downloader;
+ downloader = NULL;
+
+ if (api_downloadManager::TICK_SUCCESS == errorCode)
+ {
+ WCHAR szTarget[MAX_PATH] = {0};
+ hr = GetBasePath(szTarget, ARRAYSIZE(szTarget));
+ if(SUCCEEDED(hr))
+ {
+ Plugin_EnsurePathExist(szTarget);
+ LPCWSTR fileName = PathFindFileName(name);
+ if (NULL == fileName)
+ {
+ WCHAR szTemp[32] = {0};
+ StringCchPrintf(szTemp, ARRAYSIZE(szTemp), L"%08u.cache", GetTickCount());
+ PathAppend(szTarget, szTemp);
+ }
+ else
+ {
+ PathAppend(szTarget, fileName);
+ }
+
+ WCHAR szExt[64] = {0};
+ UINT attempt = 0;
+ UINT pExtMax = 0;
+ LPWSTR pExt = PathFindExtension(szTarget);
+ if (pExt == szTarget || L'.' != *pExt || FAILED(StringCchCopy(szExt, ARRAYSIZE(szExt), pExt)))
+ {
+ szExt[0] = L'\0';
+ }
+ else
+ {
+ pExtMax = ARRAYSIZE(szTarget) - (UINT)(pExt - szTarget);
+ }
+
+ while(FALSE == CopyFile(pszFile, szTarget, TRUE))
+ {
+ DWORD error = GetLastError();
+ if (ERROR_FILE_EXISTS != error)
+ {
+ hr = HRESULT_FROM_WIN32(error);
+ break;
+ }
+
+ hr = StringCchPrintf(pExt, pExtMax, L"(%u)%s", ++attempt, szExt);
+ if (FAILED(hr)) break;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ SetPath(szTarget);
+ }
+ }
+ else
+ {
+ flags |= flagDownloadFailed;
+ }
+
+ if (NULL != temp)
+ temp->Release();
+
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+INT CacheRecord::CompareTo(LPCWSTR pszName)
+{
+ if (NULL == pszName || NULL == name)
+ return (INT)(INT_PTR)(name - pszName);
+
+ return CompareString(CSTR_INVARIANT, NORM_IGNORECASE, name, -1, pszName, -1) - 2;
+}
+
+HRESULT CacheRecord::IsEqualName(LPCWSTR pszName)
+{
+ HRESULT hr;
+ EnterCriticalSection(&lock);
+ if (NULL == pszName)
+ {
+ hr = (NULL == name) ? S_OK : S_FALSE;
+ }
+ else if (NULL == name)
+ {
+ hr = S_FALSE;
+ }
+ else
+ {
+ INT result = CompareString(CSTR_INVARIANT, NORM_IGNORECASE, pszName, -1, name, -1);
+ if (0 == result)
+ {
+ DWORD error = GetLastError();
+ hr = HRESULT_FROM_WIN32(error);
+ }
+ else
+ {
+ hr = (CSTR_EQUAL == result) ? S_OK : S_FALSE;
+ }
+ }
+ LeaveCriticalSection(&lock);
+ return hr;
+}
+
+HRESULT CacheRecord::IsEqual(CacheRecord *record)
+{
+ if (NULL == record) return E_INVALIDARG;
+
+ HRESULT hr;
+
+ EnterCriticalSection(&record->lock);
+ hr = IsEqualName(record->name);
+ LeaveCriticalSection(&record->lock);
+
+ return hr;
+}
+
+HRESULT CacheRecord::RegisterCallback(ifc_omcachecallback *callback)
+{
+ if (NULL == callback)
+ return E_INVALIDARG;
+
+ HRESULT hr = S_OK;
+
+ EnterCriticalSection(&lock);
+
+ if (NULL == callbackList)
+ {
+ callbackList = new CallbackList();
+ if (NULL == callbackList) hr = E_OUTOFMEMORY;
+ }
+ else
+ {
+ size_t index = callbackList->size();
+ while(index--)
+ {
+ if (callbackList->at(index) == callback)
+ hr = E_FAIL;
+ }
+ }
+
+ if (SUCCEEDED(hr) && NULL != callbackList)
+ {
+ callbackList->push_back(callback);
+ callback->AddRef();
+ }
+ LeaveCriticalSection(&lock);
+ return hr;
+}
+
+HRESULT CacheRecord::UnregisterCallback(ifc_omcachecallback *callback)
+{
+ if (NULL == callback)
+ return E_INVALIDARG;
+
+ HRESULT hr = S_FALSE;
+
+ EnterCriticalSection(&lock);
+
+ if (NULL != callbackList)
+ {
+ size_t index = callbackList->size();
+ while(index--)
+ {
+ ifc_omcachecallback *test = callbackList->at(index);
+ if (test == callback)
+ {
+ callbackList->erase(callbackList->begin() + index);
+ test->Release();
+ hr = S_OK;
+
+ if (0 == callbackList->size())
+ {
+ delete(callbackList);
+ callbackList = NULL;
+ }
+ }
+ }
+ }
+ LeaveCriticalSection(&lock);
+ return hr;
+}
+
+HRESULT CacheRecord::GetFlags(UINT *puFlags)
+{
+ if (NULL == puFlags) return E_POINTER;
+ *puFlags = flags;
+ return S_OK;
+}
+
+HRESULT CacheRecord::SetFlags(UINT uFlags, UINT uMask)
+{
+ EnterCriticalSection(&lock);
+ flags = (flags & ~uMask) | (uFlags & uMask);
+ LeaveCriticalSection(&lock);
+ return S_OK;
+}
+
+HRESULT CacheRecord::GetBasePath(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ if (NULL == pszBuffer || 0 == cchBufferMax)
+ return E_INVALIDARG;
+
+ HRESULT hr;
+ EnterCriticalSection(&lock);
+
+ if (NULL != owner)
+ {
+ hr = owner->GetPath(pszBuffer, cchBufferMax);
+ }
+ else
+ {
+ *pszBuffer = L'\0';
+ hr = E_UNEXPECTED;
+ }
+ LeaveCriticalSection(&lock);
+
+ return hr;
+}
+
+#define CBCLASS CacheRecord
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_GETNAME, GetName)
+CB(API_GETPATH, GetPath)
+CB(API_SETPATH, SetPath)
+CB(API_GETFLAGS, GetFlags)
+CB(API_SETFLAGS, SetFlags)
+CB(API_DOWNLOAD, Download)
+CB(API_REGISTERCALLBACK, RegisterCallback)
+CB(API_UNREGISTERCALLBACK, UnregisterCallback)
+
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/cacheRecord.h b/Src/omBrowser/cacheRecord.h
new file mode 100644
index 00000000..764600ee
--- /dev/null
+++ b/Src/omBrowser/cacheRecord.h
@@ -0,0 +1,73 @@
+#ifndef NULLSOFT_WINAMP_CACHE_RECORD_HEADER
+#define NULLSOFT_WINAMP_CACHE_RECORD_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+#include "./ifc_omcacherecord.h"
+#include <vector>
+
+class CacheGroup;
+class CacheDownloader;
+
+class CacheRecord : public ifc_omcacherecord
+{
+public:
+ typedef enum
+ {
+ flagDownloadFailed = 0x80000000,
+ } Flags;
+
+
+protected:
+ CacheRecord(LPCWSTR pszName, LPCWSTR pszAddress, UINT uFlags);
+ ~CacheRecord();
+
+public:
+ static HRESULT CreateInstance(LPCWSTR pszName, LPCWSTR pszAddress, UINT uFlags, CacheRecord **instance);
+ static INT Compare(CacheRecord *record1, CacheRecord *record2);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ HRESULT SetOwner(CacheGroup *group);
+ HRESULT IsEqual(CacheRecord *record);
+ HRESULT IsEqualName(LPCWSTR pszName);
+ INT CompareTo(LPCWSTR pszName);
+
+ HRESULT GetName(LPWSTR pszBuffer, UINT cchBufferMax);
+ HRESULT GetPath(LPWSTR pszBuffer, UINT cchBufferMax);
+ HRESULT SetPath(LPCWSTR pszPath);
+ HRESULT GetFlags(UINT *puFlags);
+ HRESULT SetFlags(UINT uFlags, UINT uMask);
+
+ HRESULT Download();
+
+ HRESULT RegisterCallback(ifc_omcachecallback *callback);
+ HRESULT UnregisterCallback(ifc_omcachecallback *callback);
+
+ HRESULT DownloadCompleted(LPCWSTR pszFile, INT errorCode);
+
+ HRESULT GetBasePath(LPWSTR pszBuffer, UINT cchBufferMax);
+
+protected:
+ RECVS_DISPATCH;
+ typedef std::vector<ifc_omcachecallback*> CallbackList;
+
+protected:
+ size_t ref;
+ CacheGroup *owner;
+ LPWSTR name;
+ LPWSTR path;
+ UINT flags;
+ CacheDownloader *downloader;
+ CallbackList *callbackList;
+ CRITICAL_SECTION lock;
+};
+
+#endif //NULLSOFT_WINAMP_CACHE_RECORD_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/common.h b/Src/omBrowser/common.h
new file mode 100644
index 00000000..33412512
--- /dev/null
+++ b/Src/omBrowser/common.h
@@ -0,0 +1,53 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_COMMON_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_COMMON_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#ifndef _WIN32_IE_IE70
+#define _WIN32_IE_IE70 0x0700
+#endif //_WIN32_IE_IE70
+
+#include <wtypes.h>
+#include "../nu/trace.h"
+
+#define CSTR_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)
+
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(blah) (sizeof(blah)/sizeof(*blah))
+#endif
+
+#ifndef LONGX86
+#ifdef _WIN64
+ #define LONGX86 LONG_PTR
+#else /*_WIN64*/
+ #define LONGX86 LONG
+#endif /*_WIN64*/
+#endif // LONGX86
+
+#define __WTEXT(quote) L##quote
+#define WTEXT(quote) __WTEXT(quote)
+
+#ifdef __cplusplus
+ #define SENDMSG(__hwnd, __msgId, __wParam, __lParam) ::SendMessageW((__hwnd), (__msgId), (__wParam), (__lParam))
+#else
+ #define SENDMSG(__hwnd, __msgId, __wParam, __lParam) SendMessageW((__hwnd), (__msgId), (__wParam), (__lParam))
+#endif // __cplusplus
+
+#define SENDMLIPC(__hwndML, __ipcMsgId, __param) SENDMSG((__hwndML), WM_ML_IPC, (WPARAM)(__param), (LPARAM)(__ipcMsgId))
+#define SENDWAIPC(__hwndWA, __ipcMsgId, __param) SENDMSG((__hwndWA), WM_WA_IPC, (WPARAM)(__param), (LPARAM)(__ipcMsgId))
+
+#define MSGRESULT(__hwnd, __result) { SetWindowLongPtrW((__hwnd), DWLP_MSGRESULT, ((LONGX86)(LONG_PTR)(__result))); return TRUE; }
+
+#define SENDCMD(__hwnd, __ctrlId, __eventId, __hctrl) (SENDMSG((__hwnd), WM_COMMAND, MAKEWPARAM(__ctrlId, __eventId), (LPARAM)(__hctrl)))
+
+#ifndef GetWindowStyle
+#define GetWindowStyle(__hwnd) ((UINT)GetWindowLongPtr((__hwnd), GWL_STYLE))
+#endif //GetWindowStyle
+
+#ifndef GetWindowStyleEx
+#define GetWindowStyleEx(__hwnd) ((UINT)GetWindowLongPtr((__hwnd), GWL_EXSTYLE))
+#endif // GetWindowStyleEx
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_COMMON_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/component.cpp b/Src/omBrowser/component.cpp
new file mode 100644
index 00000000..4ec89e02
--- /dev/null
+++ b/Src/omBrowser/component.cpp
@@ -0,0 +1,549 @@
+#include "./main.h"
+#include "./component.h"
+#include "./browserFactory.h"
+#include "./serviceFactory.h"
+#include "./utilityFactory.h"
+#include "./wasabiHelper.h"
+#include "./winampHook.h"
+#include "./skinHelper.h"
+#include "./browserClass.h"
+#include "./internetFeatures.h"
+#include "./ieVersion.h"
+
+#include <wininet.h>
+#include <strsafe.h>
+
+static OmBrowserFactory browserFactory;
+static OmServiceFactory serviceFactory;
+static OmUtilityFactory utilityFactory;
+
+OmBrowserComponent::OmBrowserComponent()
+ : wasabiHelper(NULL), winampHook(NULL), skinHelper(NULL), hookCookie(0), internetFeatures(NULL)
+{
+ InitializeCriticalSection(&lock);
+}
+
+OmBrowserComponent::~OmBrowserComponent()
+{
+ ReleaseServices();
+
+ if (NULL != internetFeatures)
+ {
+ delete(internetFeatures);
+ internetFeatures = NULL;
+
+ InternetSetOption(NULL, INTERNET_OPTION_END_BROWSER_SESSION, NULL, 0);
+ }
+
+ DeleteCriticalSection(&lock);
+}
+
+size_t OmBrowserComponent::AddRef()
+{
+ return 1;
+}
+
+size_t OmBrowserComponent::Release()
+{
+ return 1;
+}
+
+int OmBrowserComponent::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_WinampHook))
+ *object = static_cast<ifc_winamphook*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+void OmBrowserComponent::RegisterServices(api_service *service)
+{
+ EnterCriticalSection(&lock);
+
+ if (NULL == wasabiHelper)
+ WasabiHelper::CreateInstance(service, &wasabiHelper);
+
+ aTRACE_LINE("omBrowser Registered");
+ browserFactory.Register(service);
+ serviceFactory.Register(service);
+ utilityFactory.Register(service);
+
+ LeaveCriticalSection(&lock);
+}
+
+void OmBrowserComponent::ReleaseServices()
+{
+ EnterCriticalSection(&lock);
+
+ if (NULL != wasabiHelper)
+ {
+ wasabiHelper->Release();
+ wasabiHelper = NULL;
+ }
+
+ if (NULL != winampHook)
+ {
+ winampHook->Release();
+ winampHook = NULL;
+ }
+
+ if (0 != hookCookie)
+ {
+ UnregisterWinampHook(hookCookie);
+ hookCookie = 0;
+ }
+
+ if (NULL != skinHelper)
+ {
+ skinHelper->Release();
+ skinHelper = NULL;
+ }
+
+ LeaveCriticalSection(&lock);
+}
+
+int OmBrowserComponent::RegisterServicesSafeModeOk()
+{
+ return 1;
+}
+
+void OmBrowserComponent::DeregisterServices(api_service *service)
+{
+ browserFactory.Unregister(service);
+ serviceFactory.Unregister(service);
+ utilityFactory.Unregister(service);
+
+ ReleaseServices();
+
+ size_t index = unloadCallbacks.size();
+ while(index--)
+ {
+ PLUGINUNLOADCALLBACK callback = unloadCallbacks[index];
+ if (NULL != callback) callback();
+ }
+ unloadCallbacks.clear();
+}
+
+HRESULT OmBrowserComponent::InitializeComponent(HWND hwndWinamp)
+{
+ HRESULT hr(S_FALSE);
+
+ EnterCriticalSection(&lock);
+
+ if(NULL == winampHook)
+ {
+ HRESULT hookResult = WinampHook::CreateInstance(hwndWinamp, &winampHook);
+ if (FAILED(hookResult) && SUCCEEDED(hr)) hr = hookResult;
+ }
+
+ if (SUCCEEDED(hr) && 0 == hookCookie)
+ {
+ hr = winampHook->RegisterCallback(this, &hookCookie);
+ }
+
+ if (NULL == skinHelper)
+ {
+ HRESULT skinResult = SkinHelper::CreateInstance(hwndWinamp, &skinHelper);
+ if (FAILED(skinResult) && SUCCEEDED(hr)) hr = skinResult;
+ }
+
+ LeaveCriticalSection(&lock);
+
+ return hr;
+}
+
+HRESULT OmBrowserComponent::GetWasabiHelper( ifc_wasabihelper **wasabiOut )
+{
+ if ( NULL == wasabiOut ) return E_POINTER;
+
+ EnterCriticalSection( &lock );
+
+ *wasabiOut = wasabiHelper;
+ if ( NULL != wasabiHelper )
+ wasabiHelper->AddRef();
+
+ LeaveCriticalSection( &lock );
+
+ return ( NULL != *wasabiOut ) ? S_OK : E_NOINTERFACE;
+}
+
+HRESULT OmBrowserComponent::GetSkinHelper(ifc_skinhelper **skinOut)
+{
+ if (NULL == skinOut) return E_POINTER;
+
+ EnterCriticalSection(&lock);
+
+ *skinOut = skinHelper;
+ if (NULL != skinHelper)
+ skinHelper->AddRef();
+
+ LeaveCriticalSection(&lock);
+
+ return (NULL != *skinOut) ? S_OK : E_NOINTERFACE;
+}
+
+HRESULT OmBrowserComponent::RegisterWinampHook(ifc_winamphook *hook, UINT *cookieOut)
+{
+ if (NULL == cookieOut) return E_POINTER;
+ *cookieOut = NULL;
+
+ EnterCriticalSection(&lock);
+ HRESULT hr = (NULL != winampHook) ? winampHook->RegisterCallback(hook, cookieOut) : E_FAIL;
+ LeaveCriticalSection(&lock);
+
+ return hr;
+}
+
+HRESULT OmBrowserComponent::UnregisterWinampHook(UINT cookie)
+{
+ EnterCriticalSection(&lock);
+ HRESULT hr = (NULL != winampHook) ? winampHook->UnregisterCallback(cookie) : E_FAIL;
+ LeaveCriticalSection(&lock);
+
+ return hr;
+}
+
+HRESULT OmBrowserComponent::GetWinampWnd(HWND *hwndWinamp)
+{
+ if (NULL == hwndWinamp) return E_POINTER;
+
+ EnterCriticalSection(&lock);
+ *hwndWinamp = (NULL != winampHook) ? winampHook->GetWinamp() : NULL;
+ LeaveCriticalSection(&lock);
+
+ HRESULT hr;
+ if (NULL == *hwndWinamp)
+ hr = E_FAIL;
+ else
+ hr = S_OK;
+
+ return hr;
+}
+
+HRESULT OmBrowserComponent::ResetFont(void)
+{
+ if (NULL != skinHelper)
+ skinHelper->ResetFontCache();
+ return S_OK;
+}
+
+HRESULT OmBrowserComponent::SkinChanged(const wchar_t *skinName)
+{
+ UpdateColors();
+ return S_OK;
+}
+
+HRESULT OmBrowserComponent::SkinColorChange(const wchar_t *colorTheme)
+{
+ UpdateColors();
+ return S_OK;
+}
+
+HRESULT OmBrowserComponent::RegisterUnloadCallback(PLUGINUNLOADCALLBACK callback)
+{
+ if(NULL == callback) return E_INVALIDARG;
+ unloadCallbacks.push_back(callback);
+ return S_OK;
+}
+
+HRESULT OmBrowserComponent::GetBrowserClass(LPCWSTR pszName, ifc_ombrowserclass **instance)
+{
+ if (NULL == instance) return E_POINTER;
+
+ HRESULT hr(S_OK);
+ ifc_ombrowserclass *browserClass = NULL;
+
+ EnterCriticalSection(&lock);
+
+ size_t index = browserClasses.size();
+ while(index--)
+ {
+ browserClass = browserClasses[index];
+ if (S_OK == browserClass->IsEqual(pszName))
+ {
+ browserClass->AddRef();
+ break;
+ }
+ }
+
+ if (((size_t)-1) == index)
+ {
+ hr = OmBrowserClass::CreateInstance(pszName, (OmBrowserClass**)&browserClass);
+ if (SUCCEEDED(hr) && browserClass != NULL)
+ {
+ if (0 == browserClasses.size())
+ {
+ SetUserAgent();
+ SetInternetFeautures();
+ }
+
+ browserClasses.push_back(browserClass);
+ }
+ }
+
+ *instance = (SUCCEEDED(hr) && browserClass != NULL) ? browserClass : NULL;
+
+ LeaveCriticalSection(&lock);
+
+ return hr;
+}
+
+HRESULT OmBrowserComponent::UnregisterBrowserClass(LPCWSTR pszName)
+{
+ HRESULT hr(S_FALSE);
+
+ EnterCriticalSection(&lock);
+
+ size_t index = browserClasses.size();
+ while(index--)
+ {
+ ifc_ombrowserclass *browserClass = browserClasses[index];
+ if (S_OK == browserClass->IsEqual(pszName))
+ {
+ browserClasses.erase(browserClasses.begin() + index);
+ hr = S_OK;
+ break;
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+ return hr;
+}
+
+void OmBrowserComponent::UpdateColors()
+{
+ if (NULL != skinHelper)
+ skinHelper->ResetColorCache();
+
+ EnterCriticalSection(&lock);
+
+ size_t index = browserClasses.size();
+ while(index--)
+ {
+ browserClasses[index]->UpdateRegColors();
+ }
+
+ LeaveCriticalSection(&lock);
+
+ InternetSetOption(NULL, INTERNET_OPTION_SETTINGS_CHANGED, NULL, 0 );
+}
+
+typedef struct __INTERNETFEATUREREC
+{
+ INTERNETFEATURELIST entry;
+ DWORD flags;
+ BOOL enabled;
+} INTERNETFEATUREREC;
+
+void OmBrowserComponent::SetInternetFeautures()
+{
+ const INTERNETFEATUREREC szFeatures[] =
+ {
+ { FEATURE_DISABLE_NAVIGATION_SOUNDS, SET_FEATURE_ON_PROCESS, TRUE },
+ { FEATURE_TABBED_BROWSING, SET_FEATURE_ON_PROCESS, TRUE },
+ { FEATURE_WINDOW_RESTRICTIONS, SET_FEATURE_ON_PROCESS, FALSE },
+ { FEATURE_SSLUX, SET_FEATURE_ON_PROCESS, TRUE },
+ { FEATURE_FORCE_ADDR_AND_STATUS, SET_FEATURE_ON_PROCESS, FALSE },
+ { FEATURE_BLOCK_INPUT_PROMPTS, SET_FEATURE_ON_PROCESS, FALSE },
+ { FEATURE_MIME_HANDLING, SET_FEATURE_ON_PROCESS, TRUE },
+ { FEATURE_LOCALMACHINE_LOCKDOWN, SET_FEATURE_ON_PROCESS, TRUE },
+ };
+
+ EnterCriticalSection(&lock);
+
+ if (NULL == internetFeatures)
+ {
+ internetFeatures = new InternetFeatures();
+ if (NULL == internetFeatures)
+ {
+ LeaveCriticalSection(&lock);
+ return;
+ }
+ }
+
+ UINT modified = 0;
+ HRESULT hr;
+
+ for (INT i = 0; i < ARRAYSIZE(szFeatures); i++)
+ {
+ const INTERNETFEATUREREC *rec = &szFeatures[i];
+ hr = internetFeatures->IsEnabled(rec->entry, rec->flags);
+ if ((S_OK == hr && FALSE == rec->enabled) || (S_FALSE == hr && FALSE != rec->enabled))
+ {
+ if (SUCCEEDED(internetFeatures->SetEnabled(rec->entry, rec->flags, rec->enabled)))
+ modified++;
+ }
+ }
+
+ int majorVersion = 0;
+ if (SUCCEEDED(MSIE_GetVersion(&majorVersion, NULL, NULL, NULL)))
+ {
+ unsigned long browserEmulation = 0;
+ if (8 == majorVersion)
+ browserEmulation = 8000;
+ else if (9 == majorVersion)
+ browserEmulation = 9000;
+ else if (10 <= majorVersion)
+ browserEmulation = 10000;
+ else
+ browserEmulation = 0;
+
+ unsigned long valueAlreadySet = 0;
+ hr = internetFeatures->GetDWORDFeature(L"FEATURE_BROWSER_EMULATION", TRUE, &valueAlreadySet);
+ if (FAILED(hr) || valueAlreadySet != browserEmulation)
+ {
+ if (0 == browserEmulation)
+ {
+ if (0x80070002 /*ERROR_FILE_NOT_FOUND */ != hr)
+ internetFeatures->DeleteFeature(L"FEATURE_BROWSER_EMULATION", TRUE);
+ }
+ else
+ {
+ if (SUCCEEDED(internetFeatures->SetDWORDFeature(L"FEATURE_BROWSER_EMULATION", TRUE, browserEmulation)))
+ modified++;
+ }
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+
+ if (0 != modified)
+ InternetSetOption(NULL, INTERNET_OPTION_SETTINGS_CHANGED, NULL, 0 );
+}
+
+static HRESULT
+Component_PrintWinampUA(char *buffer, size_t bufferMax)
+{
+ char *cursor = buffer;
+ size_t remaining = bufferMax;
+
+ HRESULT hr = StringCchPrintfExA(cursor, remaining,
+ &cursor, &remaining,
+ STRSAFE_NULL_ON_FAILURE,
+ "%S/%d.%d",
+ OMBROWSER_NAME,
+ OMBROWSER_VERSION_MAJOR,
+ OMBROWSER_VERSION_MINOR);
+
+ if (SUCCEEDED(hr))
+ {
+ ifc_wasabihelper *wasabi = NULL;
+ if (SUCCEEDED(Plugin_GetWasabiHelper(&wasabi)) && wasabi != NULL)
+ {
+ api_application *app = NULL;
+ if (SUCCEEDED(wasabi->GetApplicationApi(&app)) && app != NULL)
+ {
+ char *rollback = cursor;
+ hr = StringCchPrintfExA(cursor, remaining,
+ &cursor, &remaining,
+ STRSAFE_NULL_ON_FAILURE,
+ " (%S)",
+ app->main_getVersionString());
+
+ if (FAILED(hr))
+ *rollback = '\0';
+
+ app->Release();
+ }
+ wasabi->Release();
+ }
+ }
+
+ if (FAILED(hr))
+ buffer[0] = '\0';
+
+ return hr;
+}
+
+BOOL OmBrowserComponent::SetUserAgent(void)
+{
+ unsigned long bufferSize = 0;
+
+ HRESULT hr = UrlMkGetSessionOption(URLMON_OPTION_USERAGENT,
+ NULL,
+ 0,
+ &bufferSize,
+ 0);
+ if(E_OUTOFMEMORY == hr)
+ hr = S_OK;
+
+ if (FAILED(hr))
+ return FALSE;
+
+ bufferSize += 512;
+
+ char *buffer = (char *)calloc(bufferSize, sizeof(char));
+ if (NULL == buffer)
+ return FALSE;
+
+ unsigned long bufferLength = 0;
+ hr = UrlMkGetSessionOption(URLMON_OPTION_USERAGENT,
+ buffer,
+ bufferSize,
+ &bufferLength,
+ 0);
+ if (E_OUTOFMEMORY == hr
+ && bufferLength <= bufferSize)
+ {
+ hr = S_OK;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (bufferLength > 0
+ && bufferLength < bufferSize)
+ {
+ buffer[bufferLength - 1] = ' ';
+ }
+ hr = Component_PrintWinampUA(buffer + bufferLength,
+ bufferSize - bufferLength);
+ if (FAILED(hr))
+ {
+ if (bufferLength > 0)
+ buffer[bufferLength - 1] = '\0';
+ }
+ else
+ {
+ bufferLength = lstrlenA(buffer);
+
+ hr = UrlMkSetSessionOption(URLMON_OPTION_USERAGENT,
+ buffer,
+ bufferLength,
+ 0);
+ }
+ }
+
+ free(buffer);
+ return SUCCEEDED(hr);
+}
+
+#define CBCLASS OmBrowserComponent
+START_MULTIPATCH;
+ START_PATCH(MPIID_WA5COMPONENT)
+ M_CB(MPIID_WA5COMPONENT, ifc_wa5component, ADDREF, AddRef);
+ M_CB(MPIID_WA5COMPONENT, ifc_wa5component, RELEASE, Release);
+ M_CB(MPIID_WA5COMPONENT, ifc_wa5component, QUERYINTERFACE, QueryInterface);
+ M_VCB(MPIID_WA5COMPONENT, ifc_wa5component, API_WA5COMPONENT_REGISTERSERVICES, RegisterServices);
+ M_CB(MPIID_WA5COMPONENT, ifc_wa5component, 15, RegisterServicesSafeModeOk)
+ M_VCB(MPIID_WA5COMPONENT, ifc_wa5component, API_WA5COMPONENT_DEREEGISTERSERVICES, DeregisterServices);
+ NEXT_PATCH(MPIID_WINAMPHOOK)
+ M_CB(MPIID_WINAMPHOOK, ifc_winamphook, ADDREF, AddRef);
+ M_CB(MPIID_WINAMPHOOK, ifc_winamphook, RELEASE, Release);
+ M_CB(MPIID_WINAMPHOOK, ifc_winamphook, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_WINAMPHOOK, ifc_winamphook, API_RESETFONT, ResetFont);
+ M_CB(MPIID_WINAMPHOOK, ifc_winamphook, API_SKINCHANGED, SkinChanged);
+ M_CB(MPIID_WINAMPHOOK, ifc_winamphook, API_SKINCOLORCHANGE, SkinColorChange);
+ END_PATCH
+END_MULTIPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/component.h b/Src/omBrowser/component.h
new file mode 100644
index 00000000..e7512f50
--- /dev/null
+++ b/Src/omBrowser/component.h
@@ -0,0 +1,84 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_COMPONENT_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_COMPONENT_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+#include "../Agave/Component/ifc_wa5component.h"
+#include "./ifc_winamphook.h"
+#include <bfc/multipatch.h>
+#include <vector>
+
+class WasabiHelper;
+class WinampHook;
+class SkinHelper;
+class ifc_wasabihelper;
+class ifc_skinhelper;
+class ifc_ombrowserclass;
+class InternetFeatures;
+
+#define MPIID_WA5COMPONENT 10
+#define MPIID_WINAMPHOOK 20
+
+class OmBrowserComponent : public MultiPatch<MPIID_WA5COMPONENT, ifc_wa5component>,
+ public MultiPatch<MPIID_WINAMPHOOK, ifc_winamphook>
+{
+public:
+ OmBrowserComponent();
+ ~OmBrowserComponent();
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_wa5component */
+ void RegisterServices(api_service *service);
+ int RegisterServicesSafeModeOk();
+ void DeregisterServices(api_service *service);
+
+ /* ifc_winamphook (partial) */
+ HRESULT ResetFont(void);
+ HRESULT SkinChanged(const wchar_t *skinName);
+ HRESULT SkinColorChange(const wchar_t *colorTheme);
+
+public:
+ HRESULT InitializeComponent(HWND hwndWinamp);
+ HRESULT GetWasabiHelper(ifc_wasabihelper **wasabiOut);
+ HRESULT GetSkinHelper(ifc_skinhelper **skinOut);
+ HRESULT RegisterWinampHook(ifc_winamphook *hook, UINT *cookieOut);
+ HRESULT UnregisterWinampHook(UINT cookie);
+ HRESULT GetWinampWnd(HWND *hwndWinamp);
+ HRESULT RegisterUnloadCallback(PLUGINUNLOADCALLBACK callback);
+ HRESULT GetBrowserClass(LPCWSTR pszName, ifc_ombrowserclass **instance);
+ HRESULT UnregisterBrowserClass(LPCWSTR pszName);
+
+protected:
+ void ReleaseServices(void);
+ void UpdateColors(void);
+ void SetInternetFeautures(void);
+ BOOL SetUserAgent(void);
+
+protected:
+ RECVS_MULTIPATCH;
+
+private:
+ typedef std::vector<PLUGINUNLOADCALLBACK> UnloadCallbackList;
+ typedef std::vector<ifc_ombrowserclass*> BrowserClassList;
+
+
+private:
+ WasabiHelper *wasabiHelper;
+ WinampHook *winampHook;
+ SkinHelper *skinHelper;
+ UINT hookCookie;
+ CRITICAL_SECTION lock;
+ UnloadCallbackList unloadCallbacks;
+ BrowserClassList browserClasses;
+ InternetFeatures *internetFeatures;
+};
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_COMPONENT_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/configIni.cpp b/Src/omBrowser/configIni.cpp
new file mode 100644
index 00000000..1c27c575
--- /dev/null
+++ b/Src/omBrowser/configIni.cpp
@@ -0,0 +1,704 @@
+#include "./main.h"
+#include "./configIni.h"
+#include "./ifc_wasabihelper.h"
+#include "./ifc_omconfigcallback.h"
+#include <api/application/api_application.h>
+
+#include <shlwapi.h>
+#include <strsafe.h>
+
+#define BROWSER_SECTION L"OmBrowser"
+#define BROWSER_CLIENTID L"clientId"
+#define BROWSER_XPOS L"x"
+#define BROWSER_YPOS L"y"
+
+#define DEBUG_SECTION L"Debug"
+#define DEBUG_BROWSERPATH L"browserPath"
+#define DEBUG_FILTERCONTEXTMENU L"filterContextMenu"
+#define DEBUG_SHOWSCRIPTDEBUGGER L"showScriptDebugger"
+#define DEBUG_SHOWSCRIPTERROR L"showScriptErrors"
+
+#define TOOLBAR_SECTION L"Toolbar"
+#define TOOLBAR_BOTTOMDOCK L"bottomDock"
+#define TOOLBAR_AUTOHIDE L"autoHide"
+#define TOOLBAR_TABSTOP L"tabStop"
+#define TOOLBAR_FORCEADDRESSBAR L"addressbarForce"
+#define TOOLBAR_FANCYADDRESSBAR L"addressbarFancy"
+
+#define STATUSBAR_SECTION L"Statusbar"
+#define STATUSBAR_ENABLED L"enabled"
+
+#define BOOL2HRESULT(__result) ((FALSE != (__result)) ? S_OK : S_FALSE)
+
+OmConfigIni::OmConfigIni(LPCWSTR pszPath)
+ : ref(1), configPath(NULL), lastCookie(0),
+ pathValidated(FALSE)
+{
+ InitializeCriticalSection(&lock);
+ configPath = Plugin_CopyString(pszPath);
+}
+
+OmConfigIni::~OmConfigIni()
+{
+ EnterCriticalSection(&lock);
+
+ for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
+ {
+ ifc_omconfigcallback *callback = iter->second;
+ if (NULL != callback) callback->Release();
+ }
+
+ LeaveCriticalSection(&lock);
+
+ Plugin_FreeString(configPath);
+ DeleteCriticalSection(&lock);
+}
+
+static HRESULT OmConfigIni_MakeFileName(LPWSTR pszBuffer, INT cchBufferMax, LPCWSTR pszName)
+{
+ if (NULL == pszBuffer)
+ return E_POINTER;
+
+ if (NULL == pszName || L'\0' == *pszName ||
+ FAILED(StringCchCopy(pszBuffer, cchBufferMax, pszName)))
+ {
+ return E_INVALIDARG;
+ }
+
+ PathRemoveBlanks(pszBuffer);
+ INT cchBuffer = lstrlen(pszBuffer);
+
+ if (0 == cchBuffer)
+ return E_INVALIDARG;
+
+ if (FAILED(StringCchCopy(pszBuffer + cchBuffer, cchBufferMax - cchBuffer, L".ini")))
+ return E_FAIL;
+
+ return S_OK;
+}
+
+HRESULT OmConfigIni::CreateInstance(LPCWSTR pszName, OmConfigIni **instanceOut)
+{
+ if (NULL == instanceOut) return E_POINTER;
+ *instanceOut = NULL;
+
+ WCHAR szFile[MAX_PATH] = {0};
+ HRESULT hr = OmConfigIni_MakeFileName(szFile, ARRAYSIZE(szFile), pszName);
+ if (FAILED(hr)) return hr;
+
+ ifc_wasabihelper *wasabi = NULL;
+ hr = Plugin_GetWasabiHelper(&wasabi);
+ if (SUCCEEDED(hr) && wasabi != NULL)
+ {
+ api_application *app = NULL;
+ hr = wasabi->GetApplicationApi(&app);
+ if (SUCCEEDED(hr) && app != NULL)
+ {
+ WCHAR szBuffer[1024] = {0};
+ LPCWSTR userPath = app->path_getUserSettingsPath();
+ if (NULL == userPath || L'\0' == *userPath ||
+ NULL == PathCombine(szBuffer, userPath, L"Plugins\\omBrowser") ||
+ FALSE == PathAppend(szBuffer, szFile))
+ {
+ hr = E_UNEXPECTED;
+ }
+ else
+ {
+ *instanceOut = new OmConfigIni(szBuffer);
+ if (NULL == *instanceOut) hr = E_OUTOFMEMORY;
+ }
+
+ app->Release();
+ }
+ wasabi->Release();
+ }
+ return hr;
+}
+
+size_t OmConfigIni::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t OmConfigIni::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int OmConfigIni::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmConfig))
+ *object = static_cast<ifc_omconfig*>(this);
+ else if (IsEqualIID(interface_guid, IFC_OmBrowserConfig))
+ *object = static_cast<ifc_ombrowserconfig*>(this);
+ else if (IsEqualIID(interface_guid, IFC_OmDebugConfig))
+ *object = static_cast<ifc_omdebugconfig*>(this);
+ else if (IsEqualIID(interface_guid, IFC_OmToolbarConfig))
+ *object = static_cast<ifc_omtoolbarconfig*>(this);
+ else if (IsEqualIID(interface_guid, IFC_OmStatusbarConfig))
+ *object = static_cast<ifc_omstatusbarconfig*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT OmConfigIni::GetPath(LPWSTR pszBuffer, INT cchBufferMax)
+{
+ if (NULL == pszBuffer) return E_POINTER;
+ return StringCchCopy(pszBuffer, cchBufferMax, configPath);
+}
+
+DWORD OmConfigIni::ReadStr(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, LPWSTR lpReturnedString, DWORD nSize)
+{
+ return GetPrivateProfileStringW(lpSectionName, lpKeyName, lpDefault, lpReturnedString, nSize, configPath);
+}
+
+UINT OmConfigIni::ReadInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, INT nDefault)
+{
+ return GetPrivateProfileIntW(lpSectionName, lpKeyName, nDefault, configPath);
+}
+
+BOOL OmConfigIni::ReadBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, BOOL bDefault)
+{
+ WCHAR szBuffer[32] = {0};
+ INT cchLen = ReadStr(lpSectionName, lpKeyName, NULL, szBuffer, ARRAYSIZE(szBuffer));
+ if (0 == cchLen) return bDefault;
+
+ if (1 == cchLen)
+ {
+ switch(*szBuffer)
+ {
+ case L'0':
+ case L'n':
+ case L'f':
+ return FALSE;
+ case L'1':
+ case L'y':
+ case L't':
+ return TRUE;
+ }
+ }
+ else
+ {
+ if (CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, L"yes", -1, szBuffer, cchLen) ||
+ CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, L"true", -1, szBuffer, cchLen))
+ {
+ return TRUE;
+ }
+
+ if (CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, L"no", -1, szBuffer, cchLen) ||
+ CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, L"false", -1, szBuffer, cchLen))
+ {
+ return FALSE;
+ }
+ }
+
+ INT v = 0;
+ if (FALSE != StrToIntEx(szBuffer, STIF_SUPPORT_HEX, &v))
+ return (0 != v);
+
+ return bDefault;
+
+}
+
+HRESULT OmConfigIni::WriteStr(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ if (NULL == configPath || L'\0' == *configPath)
+ return E_UNEXPECTED;
+
+ if (FALSE == pathValidated)
+ {
+ WCHAR szDirectory[MAX_PATH*2] = {0};
+ if (SUCCEEDED(StringCchCopy(szDirectory, ARRAYSIZE(szDirectory), configPath)))
+ {
+ PathRemoveFileSpec(szDirectory);
+ Plugin_EnsurePathExist(szDirectory);
+ pathValidated = TRUE;
+ }
+ }
+
+ if (0 != WritePrivateProfileStringW(lpSectionName, lpKeyName, lpString, configPath))
+ return S_OK;
+
+ DWORD errorCode = GetLastError();
+ return HRESULT_FROM_WIN32(errorCode);
+}
+
+HRESULT OmConfigIni::WriteInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, INT nValue)
+{
+ wchar_t szBuffer[32] = {0};
+ HRESULT hr = StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), L"%d", nValue);
+ if (FAILED(hr)) return hr;
+
+ return WriteStr(lpSectionName, lpKeyName, szBuffer);
+}
+
+HRESULT OmConfigIni::WriteBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, BOOL bValue)
+{
+ return WriteStr(lpSectionName, lpKeyName, (0 != bValue) ? L"yes" : L"no");
+}
+
+HRESULT OmConfigIni::GetClientId(LPWSTR pszBuffer, INT cchBufferMax)
+{
+ if (NULL == pszBuffer) return E_POINTER;
+ INT cchLen = ReadStr(BROWSER_SECTION, BROWSER_CLIENTID, NULL, pszBuffer, cchBufferMax);
+ if (0 == cchLen) return S_FALSE;
+
+ INT cchPrefix = lstrlen(L"WA-");
+ if (cchLen <= cchPrefix ||
+ CSTR_EQUAL != CompareString(CSTR_INVARIANT, NORM_IGNORECASE, pszBuffer, cchPrefix, L"WA-", cchPrefix))
+ {
+ pszBuffer[0] = L'\0';
+ return E_INVALIDARG;
+ }
+
+ return S_OK;
+}
+
+HRESULT OmConfigIni::SetClientId(LPWSTR pszClientId)
+{
+ EnterCriticalSection(&lock);
+
+ WCHAR szBuffer[128] = {0};
+ HRESULT hr = GetClientId(szBuffer, ARRAYSIZE(szBuffer));
+ if (FAILED(hr) || CSTR_EQUAL != CompareString(CSTR_INVARIANT, NORM_IGNORECASE, pszClientId, -1, szBuffer, -1))
+ {
+ hr = WriteStr(BROWSER_SECTION, BROWSER_CLIENTID, pszClientId);
+ if (SUCCEEDED(hr))
+ {
+ NotifyChange(&IFC_OmBrowserConfig, CFGID_BROWSER_CLIENTID, (ULONG_PTR)pszClientId);
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+ return hr;
+}
+
+HRESULT OmConfigIni::GetMenuFilterEnabled(void)
+{
+ BOOL result = ReadBool(DEBUG_SECTION, DEBUG_FILTERCONTEXTMENU, TRUE);
+ return BOOL2HRESULT(result);
+}
+
+HRESULT OmConfigIni::GetScriptErrorEnabled(void)
+{
+ BOOL result = ReadBool(DEBUG_SECTION, DEBUG_SHOWSCRIPTERROR, FALSE);
+ return BOOL2HRESULT(result);
+}
+
+HRESULT OmConfigIni::GetScriptDebuggerEnabled(void)
+{
+ BOOL result = ReadBool(DEBUG_SECTION, DEBUG_SHOWSCRIPTDEBUGGER, FALSE);
+ return BOOL2HRESULT(result);
+}
+
+HRESULT OmConfigIni::GetBrowserPath(LPWSTR pszBuffer, INT cchBufferMax)
+{
+ if (NULL == pszBuffer) return E_POINTER;
+
+ INT cchLen = ReadStr(DEBUG_SECTION, DEBUG_BROWSERPATH, NULL, pszBuffer, cchBufferMax);
+ if (0 == cchLen) return S_FALSE;
+
+ if ((L'.' == pszBuffer[0] && L'\\' == pszBuffer[1]) ||
+ (L'.' == pszBuffer[0] && L'.' == pszBuffer[1] && L'\\' == pszBuffer[2]))
+ {
+ WCHAR szTemp[2*MAX_PATH] = {0};
+ StringCchCopy(szTemp, ARRAYSIZE(szTemp), configPath);
+ PathRemoveFileSpec(szTemp);
+
+ if (FALSE == PathAppend(szTemp, pszBuffer) ||
+ FAILED(StringCchCopy(pszBuffer, cchBufferMax, szTemp)))
+ {
+ pszBuffer[0] = L'\0';
+ return E_FAIL;
+ }
+ }
+ return S_OK;
+}
+
+HRESULT OmConfigIni::EnableMenuFilter(BOOL fEnable)
+{
+ EnterCriticalSection(&lock);
+
+ HRESULT hr = GetMenuFilterEnabled();
+ if (FAILED(hr) || ((S_OK == hr) != (FALSE != fEnable)))
+ {
+ hr = WriteBool(DEBUG_SECTION, DEBUG_FILTERCONTEXTMENU, fEnable);
+ if (SUCCEEDED(hr))
+ {
+ NotifyChange(&IFC_OmDebugConfig, CFGID_DEBUG_FILTERMENU, (ULONG_PTR)fEnable);
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+
+ return hr;
+}
+
+HRESULT OmConfigIni::EnableScriptError(BOOL fEnable)
+{
+ HRESULT hr;
+
+ EnterCriticalSection(&lock);
+
+ hr = GetScriptErrorEnabled();
+ if (FAILED(hr) || ((S_OK == hr) != (FALSE != fEnable)))
+ {
+ hr = WriteBool(DEBUG_SECTION, DEBUG_SHOWSCRIPTERROR, fEnable);
+ if (SUCCEEDED(hr))
+ {
+ NotifyChange(&IFC_OmDebugConfig, CFGID_DEBUG_SCRIPTERROR, (ULONG_PTR)fEnable);
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+
+ return hr;
+}
+
+HRESULT OmConfigIni::EnableScriptDebugger(BOOL fEnable)
+{
+ EnterCriticalSection(&lock);
+
+ HRESULT hr = GetScriptDebuggerEnabled();
+ if (FAILED(hr) || ((S_OK == hr) != (FALSE != fEnable)))
+ {
+ hr = WriteBool(DEBUG_SECTION, DEBUG_SHOWSCRIPTDEBUGGER, fEnable);
+ if (SUCCEEDED(hr))
+ {
+ NotifyChange(&IFC_OmDebugConfig, CFGID_DEBUG_SCRIPTDEBUGGER, (ULONG_PTR)fEnable);
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+ return hr;
+}
+
+HRESULT OmConfigIni::SetBrowserPath(LPCWSTR pszPath)
+{
+ EnterCriticalSection(&lock);
+
+ WCHAR szBuffer[MAX_PATH * 2] = {0};
+ HRESULT hr = GetBrowserPath(szBuffer, ARRAYSIZE(szBuffer));
+ if (FAILED(hr) ||
+ CSTR_EQUAL != CompareString(CSTR_INVARIANT, 0, szBuffer, -1, pszPath, -1))
+ {
+ hr = WriteString(DEBUG_SECTION, DEBUG_SHOWSCRIPTDEBUGGER, pszPath);
+ if (SUCCEEDED(hr))
+ {
+ NotifyChange(&IFC_OmDebugConfig, CFGID_DEBUG_BROWSERPATH, (ULONG_PTR)pszPath);
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+ return hr;
+}
+
+HRESULT OmConfigIni::Toolbar_GetBottomDockEnabled(void)
+{
+ BOOL result = ReadBool(TOOLBAR_SECTION, TOOLBAR_BOTTOMDOCK, FALSE);
+ return BOOL2HRESULT(result);
+}
+
+HRESULT OmConfigIni::Toolbar_GetAutoHideEnabled(void)
+{
+ BOOL result = ReadBool(TOOLBAR_SECTION, TOOLBAR_AUTOHIDE, FALSE);
+ return BOOL2HRESULT(result);
+}
+
+HRESULT OmConfigIni::Toolbar_GetTabStopEnabled(void)
+{
+ BOOL result = ReadBool(TOOLBAR_SECTION, TOOLBAR_TABSTOP, FALSE);
+ return BOOL2HRESULT(result);
+}
+
+HRESULT OmConfigIni::Toolbar_GetForceAddressbarEnabled(void)
+{
+ BOOL result = ReadBool(TOOLBAR_SECTION, TOOLBAR_FORCEADDRESSBAR, FALSE);
+ return BOOL2HRESULT(result);
+}
+
+HRESULT OmConfigIni::Toolbar_GetFancyAddressbarEnabled(void)
+{
+ BOOL result = ReadBool(TOOLBAR_SECTION, TOOLBAR_FANCYADDRESSBAR, TRUE);
+ return BOOL2HRESULT(result);
+}
+
+HRESULT OmConfigIni::Toolbar_EnableBottomDock(BOOL fEnable)
+{
+ EnterCriticalSection(&lock);
+
+ HRESULT hr = Toolbar_GetBottomDockEnabled();
+ if (FAILED(hr) || ((S_OK == hr) != (FALSE != fEnable)))
+ {
+ hr = WriteBool(TOOLBAR_SECTION, TOOLBAR_BOTTOMDOCK, fEnable);
+ if (SUCCEEDED(hr))
+ {
+ NotifyChange(&IFC_OmToolbarConfig, CFGID_TOOLBAR_BOTTOMDOCK, (ULONG_PTR)fEnable);
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+
+ return hr;
+}
+
+HRESULT OmConfigIni::Toolbar_EnableAutoHide(BOOL fEnable)
+{
+ EnterCriticalSection(&lock);
+
+ HRESULT hr = Toolbar_GetAutoHideEnabled();
+ if (FAILED(hr) || ((S_OK == hr) != (FALSE != fEnable)))
+ {
+ hr = WriteBool(TOOLBAR_SECTION, TOOLBAR_AUTOHIDE, fEnable);
+ if (SUCCEEDED(hr))
+ {
+ NotifyChange(&IFC_OmToolbarConfig, CFGID_TOOLBAR_AUTOHIDE, (ULONG_PTR)fEnable);
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+
+ return hr;
+}
+
+HRESULT OmConfigIni::Toolbar_EnableTabStop(BOOL fEnable)
+{
+ EnterCriticalSection(&lock);
+
+ HRESULT hr = Toolbar_GetTabStopEnabled();
+ if (FAILED(hr) || ((S_OK == hr) != (FALSE != fEnable)))
+ {
+ hr = WriteBool(TOOLBAR_SECTION, TOOLBAR_TABSTOP, fEnable);
+ if (SUCCEEDED(hr))
+ {
+ NotifyChange(&IFC_OmToolbarConfig, CFGID_TOOLBAR_TABSTOP, (ULONG_PTR)fEnable);
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+
+ return hr;
+}
+
+HRESULT OmConfigIni::Toolbar_EnableForceAddressbar(BOOL fEnable)
+{
+ EnterCriticalSection(&lock);
+
+ HRESULT hr = Toolbar_GetForceAddressbarEnabled();
+ if (FAILED(hr) || ((S_OK == hr) != (FALSE != fEnable)))
+ {
+ hr = WriteBool(TOOLBAR_SECTION, TOOLBAR_FORCEADDRESSBAR, fEnable);
+ if (SUCCEEDED(hr))
+ {
+ NotifyChange(&IFC_OmToolbarConfig, CFGID_TOOLBAR_FORCEADDRESS, (ULONG_PTR)fEnable);
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+
+ return hr;
+}
+
+HRESULT OmConfigIni::Toolbar_EnableFancyAddressbar(BOOL fEnable)
+{
+ EnterCriticalSection(&lock);
+
+ HRESULT hr = Toolbar_GetFancyAddressbarEnabled();
+ if (FAILED(hr) || ((S_OK == hr) != (FALSE != fEnable)))
+ {
+ hr = WriteBool(TOOLBAR_SECTION, TOOLBAR_FANCYADDRESSBAR, fEnable);
+ if (SUCCEEDED(hr))
+ {
+ NotifyChange(&IFC_OmToolbarConfig, CFGID_TOOLBAR_FANCYADDRESS, (ULONG_PTR)fEnable);
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+
+ return hr;
+}
+
+HRESULT OmConfigIni::Statusbar_GetEnabled(void)
+{
+ BOOL result = ReadBool(STATUSBAR_SECTION, STATUSBAR_ENABLED, FALSE);
+ return BOOL2HRESULT(result);
+}
+
+HRESULT OmConfigIni::Statusbar_EnableStatusbar(BOOL fEnable)
+{
+ EnterCriticalSection(&lock);
+
+ HRESULT hr = Statusbar_GetEnabled();
+ if (FAILED(hr) || ((S_OK == hr) != (FALSE != fEnable)))
+ {
+ hr = WriteBool(STATUSBAR_SECTION, STATUSBAR_ENABLED, fEnable);
+ if (SUCCEEDED(hr))
+ {
+ NotifyChange(&IFC_OmStatusbarConfig, CFGID_STATUSBAR_ENABLED, (ULONG_PTR)fEnable);
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+
+ return hr;
+}
+
+HRESULT OmConfigIni::RegisterCallback(ifc_omconfigcallback *callback, UINT *cookie)
+{
+ if (NULL == cookie) return E_POINTER;
+ *cookie = 0;
+
+ if (NULL == callback)
+ return E_INVALIDARG;
+
+ EnterCriticalSection(&lock);
+
+ *cookie = ++lastCookie;
+
+ callbackMap.insert({ *cookie, callback });
+ callback->AddRef();
+
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+HRESULT OmConfigIni::UnregisterCallback(UINT cookie)
+{
+ if (0 == cookie) return E_INVALIDARG;
+
+ ifc_omconfigcallback *callback = NULL;
+ EnterCriticalSection(&lock);
+
+ for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
+ {
+ if (cookie == iter->first)
+ {
+ callback = iter->second;
+ callbackMap.erase(iter);
+ break;
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+
+ if (NULL != callback)
+ {
+ callback->Release();
+ return S_OK;
+ }
+
+ return S_FALSE;
+}
+
+void OmConfigIni::NotifyChange(const GUID *configUid, UINT valueId, ULONG_PTR value)
+{
+ EnterCriticalSection(&lock);
+
+ for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
+ {
+ ifc_omconfigcallback *callback = iter->second;
+ callback->ValueChanged(configUid, valueId, value);
+ }
+
+ LeaveCriticalSection(&lock);
+}
+
+UINT OmConfigIni::GetX(void)
+{
+ return ReadInt(BROWSER_SECTION, BROWSER_XPOS, -1);
+}
+
+UINT OmConfigIni::GetY(void)
+{
+ return ReadInt(BROWSER_SECTION, BROWSER_YPOS, -1);
+}
+
+HRESULT OmConfigIni::SetX(UINT x)
+{
+ return WriteInt(BROWSER_SECTION, BROWSER_XPOS, x);
+}
+
+HRESULT OmConfigIni::SetY(UINT y)
+{
+ return WriteInt(BROWSER_SECTION, BROWSER_YPOS, y);
+}
+
+#define CBCLASS OmConfigIni
+START_MULTIPATCH
+ START_PATCH(MPIID_OMCONFIG)
+ M_CB(MPIID_OMCONFIG, ifc_omconfig, ADDREF, AddRef);
+ M_CB(MPIID_OMCONFIG, ifc_omconfig, RELEASE, Release);
+ M_CB(MPIID_OMCONFIG, ifc_omconfig, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMCONFIG, ifc_omconfig, API_GETPATH, GetPath);
+ M_CB(MPIID_OMCONFIG, ifc_omconfig, API_READSTRING, ReadStr);
+ M_CB(MPIID_OMCONFIG, ifc_omconfig, API_READINT, ReadInt);
+ M_CB(MPIID_OMCONFIG, ifc_omconfig, API_READBOOL, ReadBool);
+ M_CB(MPIID_OMCONFIG, ifc_omconfig, API_WRITESTRING, WriteStr);
+ M_CB(MPIID_OMCONFIG, ifc_omconfig, API_WRITEINT, WriteInt);
+ M_CB(MPIID_OMCONFIG, ifc_omconfig, API_WRITEBOOL, WriteBool);
+ M_CB(MPIID_OMCONFIG, ifc_omconfig, API_REGISTERCALLBACK, RegisterCallback);
+ M_CB(MPIID_OMCONFIG, ifc_omconfig, API_UNREGISTERCALLBACK, UnregisterCallback);
+ NEXT_PATCH(MPIID_OMBROWSERCONFIG)
+ M_CB(MPIID_OMBROWSERCONFIG, ifc_ombrowserconfig, ADDREF, AddRef);
+ M_CB(MPIID_OMBROWSERCONFIG, ifc_ombrowserconfig, RELEASE, Release);
+ M_CB(MPIID_OMBROWSERCONFIG, ifc_ombrowserconfig, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMBROWSERCONFIG, ifc_ombrowserconfig, API_GETCLIENTID, GetClientId);
+ M_CB(MPIID_OMBROWSERCONFIG, ifc_ombrowserconfig, API_SETCLIENTID, SetClientId);
+ M_CB(MPIID_OMBROWSERCONFIG, ifc_ombrowserconfig, API_GETX, GetX);
+ M_CB(MPIID_OMBROWSERCONFIG, ifc_ombrowserconfig, API_SETX, SetX);
+ M_CB(MPIID_OMBROWSERCONFIG, ifc_ombrowserconfig, API_GETY, GetY);
+ M_CB(MPIID_OMBROWSERCONFIG, ifc_ombrowserconfig, API_SETY, SetY);
+ NEXT_PATCH(MPIID_OMDEBUGCONFIG)
+ M_CB(MPIID_OMDEBUGCONFIG, ifc_omdebugconfig, ADDREF, AddRef);
+ M_CB(MPIID_OMDEBUGCONFIG, ifc_omdebugconfig, RELEASE, Release);
+ M_CB(MPIID_OMDEBUGCONFIG, ifc_omdebugconfig, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMDEBUGCONFIG, ifc_omdebugconfig, API_GETMENUFILTERENABLED, GetMenuFilterEnabled);
+ M_CB(MPIID_OMDEBUGCONFIG, ifc_omdebugconfig, API_GETSCRIPTERRORENABLED, GetScriptErrorEnabled);
+ M_CB(MPIID_OMDEBUGCONFIG, ifc_omdebugconfig, API_GETSCRIPTDEBUGGERENABLED, GetScriptDebuggerEnabled);
+ M_CB(MPIID_OMDEBUGCONFIG, ifc_omdebugconfig, API_GETBROWSERPATH, GetBrowserPath);
+ M_CB(MPIID_OMDEBUGCONFIG, ifc_omdebugconfig, API_ENABLEMENUFILTER, EnableMenuFilter);
+ M_CB(MPIID_OMDEBUGCONFIG, ifc_omdebugconfig, API_ENABLESCRIPTERROR, EnableScriptError);
+ M_CB(MPIID_OMDEBUGCONFIG, ifc_omdebugconfig, API_ENABLESCRIPTDEBUGGER, EnableScriptDebugger);
+ M_CB(MPIID_OMDEBUGCONFIG, ifc_omdebugconfig, API_SETBROWSERPATH, SetBrowserPath);
+ NEXT_PATCH(MPIID_OMTOOLBARCONFIG)
+ M_CB(MPIID_OMTOOLBARCONFIG, ifc_omtoolbarconfig, ADDREF, AddRef);
+ M_CB(MPIID_OMTOOLBARCONFIG, ifc_omtoolbarconfig, RELEASE, Release);
+ M_CB(MPIID_OMTOOLBARCONFIG, ifc_omtoolbarconfig, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMTOOLBARCONFIG, ifc_omtoolbarconfig, API_GETBOTTOMDOCKENABLED, Toolbar_GetBottomDockEnabled);
+ M_CB(MPIID_OMTOOLBARCONFIG, ifc_omtoolbarconfig, API_ENABLEBOTTOMDOCK, Toolbar_EnableBottomDock);
+ M_CB(MPIID_OMTOOLBARCONFIG, ifc_omtoolbarconfig, API_GETAUTOHIDEENABLED, Toolbar_GetAutoHideEnabled);
+ M_CB(MPIID_OMTOOLBARCONFIG, ifc_omtoolbarconfig, API_ENABLEAUTOHIDE, Toolbar_EnableAutoHide);
+ M_CB(MPIID_OMTOOLBARCONFIG, ifc_omtoolbarconfig, API_GETTABSTOPENABLED, Toolbar_GetTabStopEnabled);
+ M_CB(MPIID_OMTOOLBARCONFIG, ifc_omtoolbarconfig, API_ENABLETABSTOP, Toolbar_EnableTabStop);
+ M_CB(MPIID_OMTOOLBARCONFIG, ifc_omtoolbarconfig, API_GETFORCEADDRESSBARENABLED, Toolbar_GetForceAddressbarEnabled);
+ M_CB(MPIID_OMTOOLBARCONFIG, ifc_omtoolbarconfig, API_ENABLEFORCEADDRESSBAR, Toolbar_EnableForceAddressbar);
+ M_CB(MPIID_OMTOOLBARCONFIG, ifc_omtoolbarconfig, API_GETFANCYADDRESSBARENABLED, Toolbar_GetFancyAddressbarEnabled);
+ M_CB(MPIID_OMTOOLBARCONFIG, ifc_omtoolbarconfig, API_ENABLEFANCYADDRESSBAR, Toolbar_EnableFancyAddressbar);
+ NEXT_PATCH(MPIID_OMSTATUSBARCONFIG)
+ M_CB(MPIID_OMSTATUSBARCONFIG, ifc_omstatusbarconfig, ADDREF, AddRef);
+ M_CB(MPIID_OMSTATUSBARCONFIG, ifc_omstatusbarconfig, RELEASE, Release);
+ M_CB(MPIID_OMSTATUSBARCONFIG, ifc_omstatusbarconfig, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMSTATUSBARCONFIG, ifc_omstatusbarconfig, API_GETENABLED, Statusbar_GetEnabled);
+ M_CB(MPIID_OMSTATUSBARCONFIG, ifc_omstatusbarconfig, API_ENABLESTATUSBAR, Statusbar_EnableStatusbar);
+ END_PATCH
+END_MULTIPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/configIni.h b/Src/omBrowser/configIni.h
new file mode 100644
index 00000000..c1a23c6c
--- /dev/null
+++ b/Src/omBrowser/configIni.h
@@ -0,0 +1,106 @@
+#ifndef NULLSOFT_WINAMP_OMCONFIG_INI_HEADER
+#define NULLSOFT_WINAMP_OMCONFIG_INI_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_omconfig.h"
+#include "./ifc_ombrowserconfig.h"
+#include "./ifc_omdebugconfig.h"
+#include "./ifc_omtoolbarconfig.h"
+#include "./ifc_omstatusbarconfig.h"
+#include <bfc/multipatch.h>
+#include <map>
+
+class api_application;
+
+#define MPIID_OMCONFIG 10
+#define MPIID_OMBROWSERCONFIG 20
+#define MPIID_OMDEBUGCONFIG 30
+#define MPIID_OMTOOLBARCONFIG 40
+#define MPIID_OMSTATUSBARCONFIG 50
+
+class OmConfigIni : public MultiPatch<MPIID_OMCONFIG, ifc_omconfig>,
+ public MultiPatch<MPIID_OMBROWSERCONFIG, ifc_ombrowserconfig>,
+ public MultiPatch<MPIID_OMDEBUGCONFIG, ifc_omdebugconfig>,
+ public MultiPatch<MPIID_OMTOOLBARCONFIG, ifc_omtoolbarconfig>,
+ public MultiPatch<MPIID_OMSTATUSBARCONFIG, ifc_omstatusbarconfig>
+{
+protected:
+ OmConfigIni(LPCWSTR pszPath);
+ ~OmConfigIni();
+
+public:
+ static HRESULT CreateInstance(LPCWSTR pszName, OmConfigIni **instanceOut);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_omconfig */
+ HRESULT GetPath(LPWSTR pszBuffer, INT cchBufferMax);
+ DWORD ReadStr(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, LPWSTR lpReturnedString, DWORD nSize);
+ UINT ReadInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, INT nDefault);
+ BOOL ReadBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, BOOL bDefault);
+ HRESULT WriteStr(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString);
+ HRESULT WriteInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, INT nValue);
+ HRESULT WriteBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, BOOL bValue);
+ HRESULT RegisterCallback(ifc_omconfigcallback *callback, UINT *cookie);
+ HRESULT UnregisterCallback(UINT cookie);
+
+ /* ifc_ombrowserconfig */
+ HRESULT GetClientId(LPWSTR pszBuffer, INT cchBufferMax);
+ HRESULT SetClientId(LPWSTR pszClientId);
+ UINT GetX(void);
+ UINT GetY(void);
+ HRESULT SetX(UINT x);
+ HRESULT SetY(UINT y);
+
+ /* ifc_omdebugconfig */
+ HRESULT GetMenuFilterEnabled(void);
+ HRESULT GetScriptErrorEnabled(void);
+ HRESULT GetScriptDebuggerEnabled(void);
+ HRESULT GetBrowserPath(LPWSTR pszBuffer, INT cchBufferMax);
+ HRESULT EnableMenuFilter(BOOL fEnable);
+ HRESULT EnableScriptError(BOOL fEnable);
+ HRESULT EnableScriptDebugger(BOOL fEnable);
+ HRESULT SetBrowserPath(LPCWSTR pszPath);
+
+ /* ifc_omtoolbarconfig */
+ HRESULT Toolbar_GetBottomDockEnabled(void);
+ HRESULT Toolbar_GetAutoHideEnabled(void);
+ HRESULT Toolbar_GetTabStopEnabled(void);
+ HRESULT Toolbar_GetForceAddressbarEnabled(void);
+ HRESULT Toolbar_GetFancyAddressbarEnabled(void);
+ HRESULT Toolbar_EnableBottomDock(BOOL fEnable);
+ HRESULT Toolbar_EnableAutoHide(BOOL fEnable);
+ HRESULT Toolbar_EnableTabStop(BOOL fEnable);
+ HRESULT Toolbar_EnableForceAddressbar(BOOL fEnable);
+ HRESULT Toolbar_EnableFancyAddressbar(BOOL fEnable);
+
+ /* ifc_omstatusbarconfig */
+ HRESULT Statusbar_GetEnabled(void);
+ HRESULT Statusbar_EnableStatusbar(BOOL fEnable);
+
+public:
+ void NotifyChange(const GUID *configUid, UINT valueId, ULONG_PTR value);
+
+protected:
+ typedef std::map<UINT, ifc_omconfigcallback*> CallbackMap;
+
+protected:
+ RECVS_MULTIPATCH;
+
+protected:
+ ULONG ref;
+ LPWSTR configPath;
+ UINT lastCookie;
+ CallbackMap callbackMap;
+ CRITICAL_SECTION lock;
+ BOOL pathValidated;
+};
+
+#endif //NULLSOFT_WINAMP_OMCONFIG_INI_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/curtain.cpp b/Src/omBrowser/curtain.cpp
new file mode 100644
index 00000000..4057fcc3
--- /dev/null
+++ b/Src/omBrowser/curtain.cpp
@@ -0,0 +1,758 @@
+#include "main.h"
+#include "./curtain.h"
+#include "./graphics.h"
+#include "./resource.h"
+
+#include "../winamp/wa_dlg.h"
+#include "../Plugins/General/gen_ml/ml_ipc_0313.h"
+
+#include "./ifc_imageloader.h"
+#include "./ifc_skinhelper.h"
+
+#include <strsafe.h>
+#include <windows.h>
+
+#define WIDGET_MINWIDTH_UNITS 60
+#define WIDGET_MAXWIDTH_UNITS 200
+
+#define WIDGET_FRAMECX 1
+#define WIDGET_FRAMECY 1
+#define WIDGET_SPACECX_UNITS 8
+#define WIDGET_SPACECY_UNITS 8
+#define WIDGET_CONTROLSPACE_UNITS 6
+
+#define PROGRESS_FRAMECOUNT 24
+#define ANIMATETIMER_ID 64
+#define ANIMATETIMER_INTERVAL 1000 / PROGRESS_FRAMECOUNT
+
+typedef struct __CURTAIN
+{
+ LPWSTR pszTitle;
+ LPWSTR pszOperation;
+ HFONT textFont;
+ RECT widgetRect;
+ HBRUSH backBrush;
+ HBRUSH widgetBrush;
+ HBRUSH frameBrush;
+ HBITMAP progressBitmap;
+ INT frameNumber;
+ SIZE titleSize;
+ SIZE operationSize;
+ SIZE imageSize;
+ COLORREF rgbBk;
+ COLORREF rgbFg;
+} CURTAIN;
+
+#define GetCurtain(__hwnd) ((CURTAIN*)(LONG_PTR)(LONGX86)GetWindowLongPtr((__hwnd), 0))
+
+static LRESULT CALLBACK Curtain_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+BOOL Curtain_RegisterClass(HINSTANCE hInstance)
+{
+ WNDCLASS wc = {0};
+ if (GetClassInfo(hInstance, NWC_ONLINEMEDIACURTAIN, &wc)) return TRUE;
+
+ ZeroMemory(&wc, sizeof(WNDCLASS));
+
+ wc.hInstance = hInstance;
+ wc.lpszClassName = NWC_ONLINEMEDIACURTAIN;
+ wc.lpfnWndProc = Curtain_WindowProc;
+ wc.style = CS_DBLCLKS;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = NULL;
+ wc.cbWndExtra = sizeof(CURTAIN*);
+
+ return ( 0 != RegisterClassW(&wc));
+}
+
+#define RA_LEFT 0x0001
+#define RA_RIGHT 0x0002
+#define RA_HCENTER 0x0003
+#define RA_TOP 0x0010
+#define RA_BOTTOM 0x0020
+#define RA_VCENTER 0x0030
+#define RA_FITHORZ 0x0100
+#define RA_FITVERT 0x0200
+
+static COLORREF Curtain_GetColor(INT skinColor, INT sysColor)
+{
+ COLORREF rgb;
+ ifc_skinhelper *skinHelper = NULL;
+ HRESULT hr = Plugin_GetSkinHelper(&skinHelper);
+ if (SUCCEEDED(hr) && skinHelper != NULL)
+ {
+ hr = skinHelper->GetColor(skinColor, &rgb);
+ skinHelper->Release();
+ }
+
+ if (FAILED(hr))
+ rgb = GetSysColor(sysColor);
+
+ return rgb;
+}
+
+static void Curtain_RectAlign(RECT *prcTarget, const RECT *prcBounds, UINT flags)
+{
+ if (0 != (0x0F & flags)) // horz
+ {
+ LONG targetWidth = prcTarget->right - prcTarget->left;
+ LONG boundsWidth = prcBounds->right - prcBounds->left;
+
+ if (0 != (RA_FITHORZ & flags) && targetWidth > boundsWidth)
+ targetWidth = boundsWidth;
+
+ if (targetWidth == boundsWidth)
+ {
+ prcTarget->left = prcBounds->left;
+ prcTarget->right = prcBounds->right;
+ }
+ else
+ {
+ switch(0x0F & flags)
+ {
+ case RA_HCENTER: prcTarget->left = prcBounds->left + (boundsWidth - targetWidth)/2; break;
+ case RA_LEFT: prcTarget->left = prcBounds->left; break;
+ case RA_RIGHT: prcTarget->left = prcBounds->right - targetWidth; break;
+ }
+ prcTarget->right = prcTarget->left + targetWidth;
+ }
+ }
+
+ if (0 != (0xF0 & flags)) // horz
+ {
+ LONG targetHeight = prcTarget->bottom - prcTarget->top;
+ LONG boundsHeight = prcBounds->bottom - prcBounds->top;
+
+ if (0 != (RA_FITVERT & flags) && targetHeight > boundsHeight)
+ targetHeight = boundsHeight;
+
+ if (targetHeight == boundsHeight)
+ {
+ prcTarget->top = prcBounds->top;
+ prcTarget->bottom = prcBounds->bottom;
+ }
+ else
+ {
+ switch(0xF0 & flags)
+ {
+ case RA_VCENTER: prcTarget->top = prcBounds->top + (boundsHeight - targetHeight)/2; break;
+ case RA_TOP: prcTarget->top = prcBounds->top; break;
+ case RA_BOTTOM: prcTarget->top = prcBounds->bottom - targetHeight; break;
+ }
+ prcTarget->bottom = prcTarget->top + targetHeight;
+ }
+ }
+}
+
+static BOOL Curtain_SetPluginString(LPWSTR *ppDest, LPCWSTR pszSource)
+{
+ if (NULL != *ppDest)
+ Plugin_FreeString(*ppDest);
+
+ if(NULL == pszSource)
+ {
+ *ppDest = NULL;
+ }
+ else
+ {
+ WCHAR szBuffer[1024] = {0};
+ if (IS_INTRESOURCE(pszSource))
+ {
+ Plugin_LoadString((INT)(INT_PTR)pszSource, szBuffer, ARRAYSIZE(szBuffer));
+ pszSource = szBuffer;
+ }
+ *ppDest = Plugin_CopyString(pszSource);
+ }
+
+ return TRUE;
+}
+
+static BOOL Curtain_GetTextSize(LPCWSTR pszText, HWND hwnd, SIZE *textSize)
+{
+ if (NULL == hwnd || NULL == textSize)
+ return FALSE;
+
+ HFONT font = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L);
+
+ HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE);
+ if (NULL == hdc) return FALSE;
+ HFONT originalFont = (HFONT)SelectObject(hdc, font);
+
+ INT cchText = (NULL != pszText) ? lstrlen(pszText) : 0;
+ BOOL result = FALSE;
+
+ if ( 0 == cchText)
+ {
+ TEXTMETRIC tm = {0};
+ if (GetTextMetrics(hdc, &tm))
+ {
+ textSize->cy = tm.tmHeight;
+ textSize->cx = 0;
+ result = TRUE;
+ }
+ }
+ else
+ {
+ if (GetTextExtentPoint32(hdc, pszText, cchText, textSize))
+ result = TRUE;
+ }
+
+ SelectObject(hdc, originalFont);
+ ReleaseDC(hwnd, hdc);
+
+ return result;
+}
+
+static BOOL Curtain_MapDialogRectHdc(HDC hdc, RECT *prc)
+{
+ TEXTMETRIC tm;
+ if (NULL == prc || !GetTextMetrics(hdc, &tm))
+ return FALSE;
+
+ prc->left = MulDiv(prc->left, tm.tmAveCharWidth, 4);
+ prc->right = MulDiv(prc->right, tm.tmAveCharWidth, 4);
+ prc->top = MulDiv(prc->top, tm.tmHeight, 8);
+ prc->bottom = MulDiv(prc->bottom, tm.tmHeight, 8);
+
+ return TRUE;
+}
+
+static BOOL Curtain_MapDialogRect(HWND hwnd, RECT *prc)
+{
+ HFONT font = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L);
+
+ HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE);
+ if (NULL == hdc) return FALSE;
+ HFONT originalFont = (HFONT)SelectObject(hdc, font);
+
+ BOOL result = Curtain_MapDialogRectHdc(hdc, prc);
+
+ SelectObject(hdc, originalFont);
+ ReleaseDC(hwnd, hdc);
+ return result;
+}
+
+static BOOL Curtain_GetImageSize(HBITMAP bitmap, INT frameCount, SIZE *imageSize)
+{
+ if (NULL == bitmap || 0 == frameCount || NULL == imageSize)
+ return FALSE;
+
+ BITMAP bm;
+ if (sizeof(BITMAP) != GetObject(bitmap, sizeof(BITMAP), &bm))
+ return FALSE;
+
+ imageSize->cx = bm.bmWidth;
+ imageSize->cy = bm.bmHeight / frameCount;
+
+ return TRUE;
+}
+
+HBITMAP Curtain_LoadImage(HWND hwnd, INT frameCount, COLORREF rgbBk, COLORREF rgbFg)
+{
+ HBITMAP frameBitmap = NULL;
+ BITMAPINFOHEADER header = {0};
+ BYTE *pixelData = NULL;
+ ifc_omimageloader *loader = NULL;
+
+ if (SUCCEEDED(Plugin_QueryImageLoader(Plugin_GetInstance(), MAKEINTRESOURCE(IDR_CURTAINPROGRESS_IMAGE), FALSE, &loader)) && loader != NULL)
+ {
+ loader->LoadBitmapEx(&frameBitmap, &header, (void**)&pixelData);
+ loader->Release();
+ }
+
+ if (NULL == frameBitmap)
+ return NULL;
+
+ if (header.biHeight < 0) header.biHeight = - header.biHeight;
+
+ Image_Colorize(pixelData, header.biWidth, header.biHeight, header.biBitCount, rgbBk, rgbFg, TRUE);
+
+ HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE);
+
+ HBITMAP bitmap = Image_AnimateRotation(hdc, frameBitmap, frameCount, rgbBk, FALSE);
+
+ ReleaseDC(hwnd, hdc);
+ DeleteObject(frameBitmap);
+
+ return bitmap;
+}
+
+static void Curtain_UpdateLayout(HWND hwnd, BOOL fRedraw)
+{
+ CURTAIN *curtain = GetCurtain(hwnd);
+ if (NULL == curtain) return;
+
+ RECT clientRect;
+ if (!GetClientRect(hwnd, &clientRect))
+ return;
+
+ InflateRect(&clientRect, -8, -8);
+
+ if (!Curtain_GetImageSize(curtain->progressBitmap, PROGRESS_FRAMECOUNT, &curtain->imageSize))
+ ZeroMemory(&curtain->imageSize, sizeof(SIZE));
+
+ if (!Curtain_GetTextSize(curtain->pszTitle, hwnd, &curtain->titleSize))
+ ZeroMemory(&curtain->titleSize, sizeof(SIZE));
+
+ if (!Curtain_GetTextSize(curtain->pszOperation, hwnd, &curtain->operationSize))
+ ZeroMemory(&curtain->operationSize, sizeof(SIZE));
+
+ RECT spaceRect;
+ SetRect(&spaceRect, WIDGET_SPACECX_UNITS, WIDGET_SPACECY_UNITS, 0, WIDGET_CONTROLSPACE_UNITS);
+ Curtain_MapDialogRect(hwnd, &spaceRect);
+ INT spaceCY = spaceRect.top;
+ INT intervalCY = spaceRect.bottom;
+
+ INT widgetHeight = 2 * spaceCY + curtain->titleSize.cy;
+ if (widgetHeight > (clientRect.bottom - clientRect.top))
+ {
+ widgetHeight = 0;
+ ZeroMemory(&curtain->titleSize, sizeof(SIZE));
+ }
+
+ if (0 != widgetHeight && curtain->operationSize.cy > 0 &&
+ (widgetHeight + curtain->operationSize.cy + intervalCY) < (clientRect.bottom - clientRect.top))
+ widgetHeight += curtain->operationSize.cy + intervalCY;
+ else
+ ZeroMemory(&curtain->operationSize, sizeof(SIZE));
+
+ if (0 != widgetHeight && curtain->imageSize.cy > 0 &&
+ (widgetHeight + curtain->imageSize.cy + intervalCY) < (clientRect.bottom - clientRect.top))
+ widgetHeight += curtain->imageSize.cy + intervalCY;
+ else
+ ZeroMemory(&curtain->imageSize, sizeof(SIZE));
+
+ RECT limitRect, prevRect;
+ CopyRect(&prevRect, &curtain->widgetRect);
+
+ SetRect(&limitRect, WIDGET_MINWIDTH_UNITS, 0, WIDGET_MAXWIDTH_UNITS, 0);
+ Curtain_MapDialogRect(hwnd, &limitRect);
+ if ( 0 != widgetHeight && (clientRect.right - clientRect.left) >= limitRect.left)
+ {
+ curtain->widgetRect.left = clientRect.left;
+ curtain->widgetRect.top = clientRect.top;
+
+ curtain->widgetRect.right = ((clientRect.right - clientRect.left) >= limitRect.right) ?
+ (curtain->widgetRect.left + limitRect.right) :
+ (clientRect.right - clientRect.left);
+
+ curtain->widgetRect.bottom = clientRect.top + widgetHeight;
+ Curtain_RectAlign(&curtain->widgetRect, &clientRect, RA_HCENTER | RA_VCENTER);
+ }
+ else
+ {
+ SetRectEmpty(&curtain->widgetRect);
+ ZeroMemory(&curtain->titleSize, sizeof(SIZE));
+ ZeroMemory(&curtain->operationSize, sizeof(SIZE));
+ ZeroMemory(&curtain->imageSize, sizeof(SIZE));
+ }
+
+ if (FALSE != fRedraw && FALSE == EqualRect(&curtain->widgetRect, &prevRect))
+ {
+ InvalidateRect(hwnd, &prevRect, TRUE);
+ InvalidateRect(hwnd, &curtain->widgetRect, FALSE);
+ }
+}
+
+static HRGN Curtain_GetFrameRgn(RECT *prcWidget)
+{
+ HRGN regionFrame, regionPart;
+
+ regionFrame = CreateRectRgn(prcWidget->left, prcWidget->top, prcWidget->right, prcWidget->top + WIDGET_FRAMECY);
+
+ regionPart = CreateRectRgn(prcWidget->left, prcWidget->bottom - WIDGET_FRAMECY, prcWidget->right, prcWidget->bottom);
+ CombineRgn(regionFrame, regionFrame, regionPart, RGN_OR);
+ SetRectRgn(regionPart, prcWidget->left, prcWidget->top + WIDGET_FRAMECY, prcWidget->left + WIDGET_FRAMECX, prcWidget->bottom - WIDGET_FRAMECY);
+ CombineRgn(regionFrame, regionFrame, regionPart, RGN_OR);
+ SetRectRgn(regionPart, prcWidget->right - WIDGET_FRAMECX, prcWidget->top + WIDGET_FRAMECY, prcWidget->right, prcWidget->bottom - WIDGET_FRAMECY);
+ CombineRgn(regionFrame, regionFrame, regionPart, RGN_OR);
+
+ DeleteObject(regionPart);
+ return regionFrame;
+}
+
+static void Curtain_PaintWidgetBack(CURTAIN *curtain, HDC hdc, HRGN regionPaint)
+{
+ HRGN regionFrame = Curtain_GetFrameRgn(&curtain->widgetRect);
+
+ if (NULL == curtain->frameBrush)
+ curtain->frameBrush = CreateSolidBrush(Curtain_GetColor(WADLG_HILITE, COLOR_3DHILIGHT));
+
+ if (FillRgn(hdc, regionFrame, curtain->frameBrush))
+ CombineRgn(regionPaint, regionPaint, regionFrame, RGN_DIFF);
+
+ DeleteObject(regionFrame);
+
+ if (NULL == curtain->widgetBrush)
+ curtain->widgetBrush = CreateSolidBrush(Curtain_GetColor(WADLG_WNDBG, COLOR_WINDOW));
+
+ FillRgn(hdc, regionPaint, curtain->widgetBrush);
+}
+
+static BOOL Curtain_PaintImage(HBITMAP bitmap, INT frame, const RECT *bitmapRect, HDC hdc, const RECT *paintRect)
+{
+ RECT blitRect;
+ if (!IntersectRect(&blitRect, bitmapRect, paintRect))
+ return TRUE;
+
+ BOOL success = FALSE;
+ HDC hdcSrc = CreateCompatibleDC(hdc);
+ if (NULL != hdcSrc)
+ {
+ HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcSrc, bitmap);
+
+ success = BitBlt(hdc, blitRect.left, blitRect.top,
+ blitRect.right - blitRect.left, blitRect.bottom - blitRect.top,
+ hdcSrc,
+ blitRect.left - bitmapRect->left,
+ (bitmapRect->bottom - bitmapRect->top)*frame + blitRect.top - bitmapRect->top,
+ SRCCOPY);
+
+ SelectObject(hdcSrc, hbmpOld);
+ DeleteDC(hdcSrc);
+ }
+
+ return success;
+}
+
+static BOOL Curtain_PaintWidget(CURTAIN *curtain, HDC hdc, RECT *prcPaint, BOOL fErase)
+{
+ HRGN regionPaint = CreateRectRgnIndirect(prcPaint);
+ HRGN regionPart = CreateRectRgn(0,0,0,0);
+
+ COLORREF originalBk = SetBkColor(hdc, curtain->rgbBk);
+ COLORREF originalFg = SetTextColor(hdc, curtain->rgbFg);
+
+ RECT clientRect;
+ CopyRect(&clientRect, &curtain->widgetRect);
+
+ HFONT originalFont = (HFONT)SelectObject(hdc, (NULL != curtain->textFont) ?
+ curtain->textFont :
+ (HFONT)GetStockObject(DEFAULT_GUI_FONT));
+
+ RECT spaceRect;
+ SetRect(&spaceRect, WIDGET_SPACECX_UNITS, WIDGET_SPACECY_UNITS, 0, 0);
+ Curtain_MapDialogRectHdc(hdc, &spaceRect);
+
+ InflateRect(&clientRect, -spaceRect.left, -spaceRect.top);
+
+ if (NULL != curtain->progressBitmap && 0 != curtain->imageSize.cx && 0 != curtain->imageSize.cy)
+ {
+ RECT imageRect;
+ SetRect(&imageRect, 0, 0, curtain->imageSize.cx, curtain->imageSize.cy);
+ Curtain_RectAlign(&imageRect, &clientRect, RA_HCENTER | RA_VCENTER);
+
+ if (Curtain_PaintImage(curtain->progressBitmap, curtain->frameNumber, &imageRect, hdc,prcPaint))
+ {
+ SetRectRgn(regionPart, imageRect.left, imageRect.top, imageRect.right, imageRect.bottom);
+ CombineRgn(regionPaint, regionPaint, regionPart, RGN_DIFF);
+ }
+ }
+
+ if (NULL != curtain->pszTitle && 0 != curtain->titleSize.cx && 0 != curtain->titleSize.cy)
+ {
+ RECT textRect, paintRect;;
+ SetRect(&textRect, 0, 0, curtain->titleSize.cx, curtain->titleSize.cy);
+ Curtain_RectAlign(&textRect, &clientRect, RA_HCENTER | RA_TOP | RA_FITHORZ);
+ if (IntersectRect(&paintRect, &textRect, prcPaint))
+ {
+ INT cchText = lstrlen(curtain->pszTitle);
+ if (ExtTextOut(hdc, textRect.left, textRect.top, ETO_CLIPPED | ETO_OPAQUE, &paintRect, curtain->pszTitle, cchText, NULL))
+ {
+ SetRectRgn(regionPart, paintRect.left, paintRect.top, paintRect.right, paintRect.bottom);
+ CombineRgn(regionPaint, regionPaint, regionPart, RGN_DIFF);
+ }
+ }
+ }
+
+ if (NULL != curtain->pszOperation && 0 != curtain->operationSize.cx && 0 != curtain->operationSize.cy)
+ {
+ RECT textRect, paintRect;
+ SetRect(&textRect, 0, 0, curtain->operationSize.cx, curtain->operationSize.cy);
+ Curtain_RectAlign(&textRect, &clientRect, RA_HCENTER | RA_BOTTOM | RA_FITHORZ);
+ if (IntersectRect(&paintRect, &textRect, prcPaint))
+ {
+ INT cchText = lstrlen(curtain->pszOperation);
+ if (ExtTextOut(hdc, textRect.left, textRect.top, ETO_CLIPPED | ETO_OPAQUE, &paintRect, curtain->pszOperation, cchText, NULL))
+ {
+ SetRectRgn(regionPart, paintRect.left, paintRect.top, paintRect.right, paintRect.bottom);
+ CombineRgn(regionPaint, regionPaint, regionPart, RGN_DIFF);
+ }
+ }
+ }
+
+ SelectObject(hdc, originalFont);
+
+ if (originalBk != curtain->rgbBk) SetBkColor(hdc, originalBk);
+ if (originalFg != curtain->rgbFg) SetTextColor(hdc, originalFg);
+
+ if (NULL != fErase)
+ Curtain_PaintWidgetBack(curtain, hdc, regionPaint);
+
+ DeleteObject(regionPaint);
+ DeleteObject(regionPart);
+ return TRUE;
+}
+
+static void Curtain_Paint(HWND hwnd, HDC hdc, const RECT *prcPaint, BOOL fErase)
+{
+ CURTAIN *curtain = GetCurtain(hwnd);
+ if (NULL == curtain) return;
+
+ HRGN regionPaint = CreateRectRgnIndirect(prcPaint);
+
+ if (!IsRectEmpty(&curtain->widgetRect))
+ {
+ RECT widgetPaintRect;
+ if (IntersectRect(&widgetPaintRect, &curtain->widgetRect, prcPaint) &&
+ FALSE != Curtain_PaintWidget(curtain, hdc, &widgetPaintRect, fErase))
+ {
+ HRGN regionWidget = CreateRectRgnIndirect(&widgetPaintRect);
+ CombineRgn(regionPaint, regionPaint, regionWidget, RGN_DIFF);
+ DeleteObject(regionWidget);
+ }
+ }
+
+ if (FALSE != fErase)
+ {
+ if (NULL == curtain->backBrush)
+ {
+ curtain->backBrush = CreateSolidBrush(Curtain_GetColor(WADLG_ITEMBG, COLOR_WINDOW));
+ }
+ FillRgn(hdc, regionPaint, curtain->backBrush);
+ }
+
+ DeleteObject(regionPaint);
+}
+
+static void CALLBACK Curtain_AnimateTimerElpased(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+ CURTAIN *curtain = GetCurtain(hwnd);
+ if (NULL == curtain)
+ {
+ KillTimer(hwnd, idEvent);
+ return;
+ }
+
+ if (NULL != curtain->progressBitmap && 0 != curtain->imageSize.cx && 0 != curtain->imageSize.cy)
+ {
+ curtain->frameNumber++;
+ if (curtain->frameNumber >= PROGRESS_FRAMECOUNT)
+ curtain->frameNumber = 0;
+
+ RECT imageRect;
+ SetRect(&imageRect, 0, 0, curtain->imageSize.cx, curtain->imageSize.cy);
+ Curtain_RectAlign(&imageRect, &curtain->widgetRect, RA_HCENTER | RA_VCENTER);
+ InvalidateRect(hwnd, &imageRect, FALSE);
+ }
+}
+
+static LRESULT Curtain_OnCreate(HWND hwnd, CREATESTRUCT *pcs)
+{
+ CURTAIN *curtain = (CURTAIN*)calloc(1, sizeof(CURTAIN));
+ if (NULL != curtain)
+ {
+ SetLastError(ERROR_SUCCESS);
+ if (!SetWindowLongPtr(hwnd, 0, (LONGX86)(LONG_PTR)curtain) && ERROR_SUCCESS != GetLastError())
+ {
+ free(curtain);
+ curtain = NULL;
+ }
+ }
+
+ if (NULL == curtain)
+ {
+ DestroyWindow(hwnd);
+ return -1;
+ }
+
+ SetTimer(hwnd, ANIMATETIMER_ID, ANIMATETIMER_INTERVAL, Curtain_AnimateTimerElpased);
+ return 0;
+}
+
+static void Curtain_OnDestroy(HWND hwnd)
+{
+ CURTAIN *curtain = GetCurtain(hwnd);
+ SetWindowLongPtr(hwnd, 0, 0L);
+
+ if (NULL != curtain)
+ {
+ if (NULL != curtain->pszTitle)
+ Plugin_FreeString(curtain->pszTitle);
+
+ if (NULL != curtain->pszOperation)
+ Plugin_FreeString(curtain->pszOperation);
+
+ if (NULL != curtain->backBrush)
+ DeleteObject(curtain->backBrush);
+ if (NULL != curtain->widgetBrush)
+ DeleteObject(curtain->widgetBrush);
+ if (NULL != curtain->frameBrush)
+ DeleteObject(curtain->frameBrush);
+ if (NULL != curtain->progressBitmap)
+ DeleteObject(curtain->progressBitmap);
+
+ free(curtain);
+ }
+}
+
+static void Curtain_OnPaint(HWND hwnd)
+{
+ PAINTSTRUCT ps = {0};
+ if (BeginPaint(hwnd, &ps))
+ {
+ if (ps.rcPaint.left != ps.rcPaint.right)
+ Curtain_Paint(hwnd, ps.hdc, &ps.rcPaint, ps.fErase);
+ EndPaint(hwnd, &ps);
+ }
+}
+
+static void Curtain_OnPrintClient(HWND hwnd, HDC hdc, UINT options)
+{
+ RECT clientRect;
+ if (GetClientRect(hwnd, &clientRect))
+ Curtain_Paint(hwnd, hdc, &clientRect, 0 != (PRF_ERASEBKGND & options));
+}
+
+static void Curtain_OnWindowPosChanged(HWND hwnd, WINDOWPOS *pwp)
+{
+ if (SWP_NOSIZE == ((SWP_NOSIZE | SWP_FRAMECHANGED) & pwp->flags))
+ return;
+
+ Curtain_UpdateLayout(hwnd, 0 == (SWP_NOREDRAW & pwp->flags));
+}
+
+static void Curtain_OnCommand(HWND hwnd, INT controlId, INT eventId, HWND hControl)
+{
+}
+
+static BOOL Curtain_OnSetText(HWND hwnd, LPCWSTR pszText)
+{
+ CURTAIN *curtain = GetCurtain(hwnd);
+ if (NULL == curtain) return FALSE;
+
+ Curtain_SetPluginString(&curtain->pszTitle, pszText);
+
+ InvalidateRect(hwnd, &curtain->widgetRect, FALSE);
+ return TRUE;
+}
+
+static INT Curtain_OnGetText(HWND hwnd, LPWSTR pszBuffer, INT cchBufferMax)
+{
+ if (NULL == pszBuffer || cchBufferMax)
+ return 0;
+
+ pszBuffer[0] = L'\0';
+
+ CURTAIN *curtain = GetCurtain(hwnd);
+ if (NULL == curtain || NULL == curtain->pszTitle) return FALSE;
+
+ INT cchTitle = lstrlenW(curtain->pszTitle);
+ if (cchTitle > 0)
+ {
+ if (cchTitle >= cchBufferMax)
+ cchTitle = (cchBufferMax - 1);
+ StringCchCopyN(pszBuffer, cchBufferMax, curtain->pszTitle, cchTitle);
+ }
+ return cchTitle;
+}
+
+static INT Curtain_OnGetTextLength(HWND hwnd)
+{
+ CURTAIN *curtain = GetCurtain(hwnd);
+ if (NULL == curtain || NULL == curtain->pszTitle) return FALSE;
+ return lstrlenW(curtain->pszTitle);
+}
+
+static BOOL Curtain_OnSetOperationText(HWND hwnd, LPCWSTR pszText)
+{
+ CURTAIN *curtain = GetCurtain(hwnd);
+ if (NULL == curtain) return FALSE;
+
+ Curtain_SetPluginString(&curtain->pszOperation, pszText);
+
+ InvalidateRect(hwnd, &curtain->widgetRect, FALSE);
+ return TRUE;
+}
+
+static void Curtain_OnUpdateSkin(HWND hwnd, BOOL fRedraw)
+{
+ CURTAIN *curtain = GetCurtain(hwnd);
+ if (NULL == curtain) return;
+
+ ifc_skinhelper *skinHelper = NULL;
+ if (FAILED(Plugin_GetSkinHelper(&skinHelper)))
+ skinHelper = NULL;
+
+ curtain->textFont = (NULL != skinHelper) ? skinHelper->GetFont() : NULL;
+
+ if (NULL != curtain->backBrush)
+ {
+ DeleteObject(curtain->backBrush);
+ curtain->backBrush = NULL;
+ }
+ if (NULL != curtain->widgetBrush)
+ {
+ DeleteObject(curtain->widgetBrush);
+ curtain->widgetBrush = NULL;
+ }
+ if (NULL != curtain->frameBrush)
+ {
+ DeleteObject(curtain->frameBrush);
+ curtain->frameBrush = NULL;
+ }
+ if (NULL != curtain->progressBitmap)
+ DeleteObject(curtain->progressBitmap);
+
+ if (NULL == skinHelper || FAILED(skinHelper->GetColor(WADLG_WNDBG, &curtain->rgbBk)))
+ curtain->rgbBk = GetSysColor(COLOR_WINDOW);
+
+ if (NULL == skinHelper || FAILED(skinHelper->GetColor(WADLG_WNDFG, &curtain->rgbFg)))
+ curtain->rgbFg = GetSysColor(COLOR_WINDOWTEXT);
+
+ if (NULL != skinHelper)
+ skinHelper->Release();
+
+ curtain->progressBitmap = Curtain_LoadImage(hwnd, PROGRESS_FRAMECOUNT, curtain->rgbBk, curtain->rgbFg);
+ Curtain_UpdateLayout(hwnd, fRedraw);
+}
+
+static LRESULT Curtain_OnGetFont(HWND hwnd)
+{
+ CURTAIN *curtain = GetCurtain(hwnd);
+ if (NULL == curtain) return NULL;
+ return (LRESULT)curtain->textFont;
+}
+
+static void Curtain_OnSetFont(HWND hwnd, HFONT hFont, BOOL fRedraw)
+{
+ CURTAIN *curtain = GetCurtain(hwnd);
+ if (NULL == curtain) return;
+
+ curtain->textFont = hFont;
+ if (FALSE != fRedraw)
+ InvalidateRect(hwnd, &curtain->widgetRect, FALSE);
+}
+
+static LRESULT CALLBACK Curtain_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_CREATE: return Curtain_OnCreate(hwnd, (CREATESTRUCT*)lParam);
+ case WM_DESTROY: Curtain_OnDestroy(hwnd); break;
+ case WM_PAINT: Curtain_OnPaint(hwnd); return 0;
+ case WM_PRINTCLIENT: Curtain_OnPrintClient(hwnd, (HDC)wParam, (UINT)lParam); return 0;
+ case WM_ERASEBKGND: return 0;
+ case WM_WINDOWPOSCHANGED: Curtain_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); return 0;
+ case WM_SETTEXT: return Curtain_OnSetText(hwnd, (LPCWSTR)lParam);
+ case WM_GETTEXT: return Curtain_OnGetText(hwnd, (LPWSTR)lParam, (INT)wParam);
+ case WM_GETTEXTLENGTH: return Curtain_OnGetTextLength(hwnd);
+ case WM_GETFONT: return Curtain_OnGetFont(hwnd);
+ case WM_SETFONT: Curtain_OnSetFont(hwnd, (HFONT)wParam, (BOOL)LOWORD(lParam));
+ case WM_COMMAND: Curtain_OnCommand(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break;
+
+ case CWM_SETOPERATIONTEXT: return Curtain_OnSetOperationText(hwnd, (LPCWSTR)lParam);
+ case CWM_UPDATESKIN: Curtain_OnUpdateSkin(hwnd, (BOOL)lParam); return 0;
+ }
+ return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+} \ No newline at end of file
diff --git a/Src/omBrowser/curtain.h b/Src/omBrowser/curtain.h
new file mode 100644
index 00000000..c298bd67
--- /dev/null
+++ b/Src/omBrowser/curtain.h
@@ -0,0 +1,24 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_CURTAIN_CONTROL_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_CURTAIN_CONTROL_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+#define NWC_ONLINEMEDIACURTAIN L"Nullsoft_omBrowserCurtain"
+
+BOOL Curtain_RegisterClass(HINSTANCE hInstance);
+
+#define CWM_FIRST (WM_USER + 20)
+
+#define CWM_SETOPERATIONTEXT (CWM_FIRST + 0) //wParam = not used, lParam = (LPARAM)(LPCWSTR)pszOperationText.
+#define Curtain_SetOperationText(/*HWND*/ __hCurtain, /*LPCWSTR*/__operationText)\
+ ((BOOL)SENDMSG(__hCurtain, CWM_SETOPERATIONTEXT, 0, (LPARAM)(__operationText)))
+
+#define CWM_UPDATESKIN (CWM_FIRST + 1) //wParam = not used, lParam = (LPARAM)(BOOL)fRedraw.
+#define Curtain_UpdateSkin(/*HWND*/ __hCurtain, /*BOOL*/ __fRedraw)\
+ (SENDMSG(__hCurtain, CWM_UPDATESKIN, 0, (LPARAM)(__fRedraw)))
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_CURTAIN_CONTROL_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/enumAsync.cpp b/Src/omBrowser/enumAsync.cpp
new file mode 100644
index 00000000..7d90174a
--- /dev/null
+++ b/Src/omBrowser/enumAsync.cpp
@@ -0,0 +1,347 @@
+#include "main.h"
+#include "./enumAsync.h"
+#include "./ifc_omservice.h"
+#include "./ifc_omserviceenum.h"
+#include "./ifc_wasabihelper.h"
+#include "./serviceList.h"
+
+EnumAsyncWrapper::EnumAsyncWrapper(ifc_omserviceenum *enumerator)
+ : ref(1), enumerator(enumerator), userCallback(NULL), userData(NULL),
+ completed(NULL), state(stateReady), resultCode(E_PENDING), serviceList(NULL)
+{
+ if (NULL != enumerator)
+ enumerator->AddRef();
+
+ InitializeCriticalSection(&lock);
+}
+
+EnumAsyncWrapper::~EnumAsyncWrapper()
+{
+ EnterCriticalSection(&lock);
+
+ if (NULL != enumerator)
+ enumerator->Release();
+
+ if (NULL != completed)
+ CloseHandle(completed);
+
+ if (NULL != serviceList)
+ serviceList->Release();
+
+ LeaveCriticalSection(&lock);
+
+ DeleteCriticalSection(&lock);
+}
+
+HRESULT EnumAsyncWrapper::CreateInstance(ifc_omserviceenum *enumerator, EnumAsyncWrapper **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ *instance = NULL;
+
+ if (NULL == enumerator)
+ return E_INVALIDARG;
+
+ *instance = new EnumAsyncWrapper(enumerator);
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t EnumAsyncWrapper::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t EnumAsyncWrapper::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int EnumAsyncWrapper::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmStorageAsync))
+ *object = static_cast<ifc_omstorageasync*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT EnumAsyncWrapper::GetState(UINT *state)
+{
+ if (NULL == state)
+ return E_POINTER;
+
+ EnterCriticalSection(&lock);
+ *state = this->state;
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+HRESULT EnumAsyncWrapper::GetWaitHandle(HANDLE *handle)
+{
+ if (NULL == handle)
+ return E_POINTER;
+
+ HRESULT hr = S_OK;
+
+ EnterCriticalSection(&lock);
+
+ if (NULL == completed)
+ {
+ completed = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (NULL == completed)
+ {
+ *handle = NULL;
+ DWORD error = GetLastError();
+ hr = HRESULT_FROM_WIN32(error);
+ }
+ }
+
+ if (SUCCEEDED(hr) && FALSE == DuplicateHandle(GetCurrentProcess(), completed,
+ GetCurrentProcess(), handle, 0, FALSE, DUPLICATE_SAME_ACCESS))
+ {
+ *handle = NULL;
+ DWORD error = GetLastError();
+ hr = HRESULT_FROM_WIN32(error);
+ }
+
+ LeaveCriticalSection(&lock);
+
+ return hr;
+}
+
+HRESULT EnumAsyncWrapper::GetData(void **data)
+{
+ if (NULL == data)
+ return E_POINTER;
+
+ EnterCriticalSection(&lock);
+ *data = userData;
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+HRESULT EnumAsyncWrapper::GetCallback(AsyncCallback *callback)
+{
+ if (NULL == callback)
+ return E_POINTER;
+
+ EnterCriticalSection(&lock);
+ *callback = userCallback;
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+HRESULT EnumAsyncWrapper::SetData(void *data)
+{
+ EnterCriticalSection(&lock);
+ userData = data;
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+HRESULT EnumAsyncWrapper::SetCallback(AsyncCallback callback)
+{
+ EnterCriticalSection(&lock);
+ userCallback = callback;
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+HRESULT EnumAsyncWrapper::RequestAbort(BOOL fDrop)
+{
+ HRESULT hr = S_FALSE;
+
+ EnterCriticalSection(&lock);
+
+ if (stateInitializing == state || stateReceiving == state)
+ {
+ state = stateAborting;
+ if (FALSE != fDrop)
+ {
+ userCallback = NULL;
+ userData = NULL;
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+
+ return hr;
+}
+
+static int EnumAsyncWrapper_ThreadFunc(HANDLE handle, void *user_data, intptr_t id)
+{
+ EnumAsyncWrapper *instance = (EnumAsyncWrapper*)user_data;
+ if (NULL != instance) instance->Enumerate();
+ return 0;
+}
+
+HRESULT EnumAsyncWrapper::BeginEnumerate()
+{
+ ifc_wasabihelper *wasabi = NULL;
+ HRESULT hr;
+
+ EnterCriticalSection(&lock);
+
+ if (stateReady != state && stateCompleted != state)
+ {
+ hr = E_PENDING;
+ }
+ else
+ {
+ state = stateInitializing;
+
+ if (NULL != serviceList)
+ {
+ serviceList->Release();
+ serviceList = NULL;
+ }
+
+ hr = Plugin_GetWasabiHelper(&wasabi);
+ if (SUCCEEDED(hr) && wasabi != NULL)
+ {
+ api_threadpool *threadpool;
+ hr = wasabi->GetThreadpoolApi(&threadpool);
+ if (SUCCEEDED(hr))
+ {
+ if (0 != threadpool->RunFunction(NULL, EnumAsyncWrapper_ThreadFunc, this, 0, 0))
+ {
+ hr = E_FAIL;
+ }
+ else
+ {
+ AddRef();
+ }
+ threadpool->Release();
+ }
+ else
+ {
+ hr = E_NOINTERFACE;
+ }
+
+ wasabi->Release();
+ }
+
+ if (FAILED(hr))
+ state = stateCompleted;
+ }
+
+ LeaveCriticalSection(&lock);
+ return hr;
+}
+
+HRESULT EnumAsyncWrapper::Enumerate()
+{
+ EnterCriticalSection(&lock);
+ state = stateReceiving;
+ resultCode = OmServiceList::CreateInstance(&serviceList);
+ LeaveCriticalSection(&lock);
+
+ if (SUCCEEDED(resultCode))
+ {
+ if (NULL == enumerator)
+ {
+ resultCode = E_UNEXPECTED;
+ }
+ else
+ {
+ ifc_omservice *service;
+ while(S_OK == enumerator->Next(1, &service, NULL))
+ {
+ if (stateAborting == state)
+ {
+ resultCode = E_ABORT;
+ break;
+ }
+
+ if (NULL != service)
+ {
+ serviceList->Add(service);
+ service->Release();
+ }
+ }
+ }
+ }
+
+ EnterCriticalSection(&lock);
+ state = stateCompleted;
+ HANDLE event = completed;
+ LeaveCriticalSection(&lock);
+
+ if (NULL != event)
+ {
+ SetEvent(event);
+ }
+
+ EnterCriticalSection(&lock);
+ AsyncCallback cb = userCallback;
+ LeaveCriticalSection(&lock);
+
+ if (NULL != cb)
+ {
+ cb(this);
+ }
+
+ Release();
+
+ return resultCode;
+}
+
+HRESULT EnumAsyncWrapper::GetResultCode()
+{
+ return resultCode;
+}
+
+HRESULT EnumAsyncWrapper::GetServiceList(ifc_omserviceenum **list)
+{
+ if (NULL == list)
+ return E_POINTER;
+
+ if (NULL == serviceList)
+ {
+ *list = NULL;
+ return E_UNEXPECTED;
+ }
+
+ EnterCriticalSection(&lock);
+
+ *list = serviceList;
+ serviceList->AddRef();
+
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+#define CBCLASS EnumAsyncWrapper
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_GETSTATE, GetState)
+CB(API_GETWAITHANDLE, GetWaitHandle)
+CB(API_GETDATA, GetData)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/enumAsync.h b/Src/omBrowser/enumAsync.h
new file mode 100644
index 00000000..bc513e11
--- /dev/null
+++ b/Src/omBrowser/enumAsync.h
@@ -0,0 +1,63 @@
+#ifndef NULLSOFT_WINAMP_OMSTORAGE_ASYNC_ENUMERATOR_WRAPPER_HEADER
+#define NULLSOFT_WINAMP_OMSTORAGE_ASYNC_ENUMERATOR_WRAPPER_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+#include "./ifc_omstorageasync.h"
+
+class ifc_omservicehost;
+class ifc_omserviceenum;
+class ifc_omservice;
+class OmServiceList;
+
+class EnumAsyncWrapper : public ifc_omstorageasync
+{
+protected:
+ EnumAsyncWrapper(ifc_omserviceenum *enumerator);
+ ~EnumAsyncWrapper();
+
+public:
+ static HRESULT CreateInstance(ifc_omserviceenum *enumerator, EnumAsyncWrapper **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_omstorageasync */
+ HRESULT GetState(UINT *state);
+ HRESULT GetWaitHandle(HANDLE *handle);
+ HRESULT GetData(void **data);
+
+public:
+ HRESULT SetData(void *data);
+ HRESULT SetCallback(AsyncCallback callback);
+ HRESULT GetCallback(AsyncCallback *callback);
+ HRESULT RequestAbort(BOOL fDrop);
+
+ HRESULT BeginEnumerate();
+ HRESULT Enumerate();
+
+ HRESULT GetResultCode();
+ HRESULT GetServiceList(ifc_omserviceenum **list);
+
+protected:
+ size_t ref;
+ ifc_omserviceenum *enumerator;
+ AsyncCallback userCallback;
+ void *userData;
+ HANDLE completed;
+ UINT state;
+ HRESULT resultCode;
+ CRITICAL_SECTION lock;
+ OmServiceList *serviceList;
+
+protected:
+ RECVS_DISPATCH;
+};
+
+#endif //NULLSOFT_WINAMP_OMSTORAGE_ASYNC_ENUMERATOR_WRAPPER_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/enumIniFile.cpp b/Src/omBrowser/enumIniFile.cpp
new file mode 100644
index 00000000..33b5e47e
--- /dev/null
+++ b/Src/omBrowser/enumIniFile.cpp
@@ -0,0 +1,215 @@
+#include "main.h"
+#include "./enumIniFile.h"
+#include "./service.h"
+#include "./ifc_omservicehost.h"
+#include "./ifc_omstorage.h"
+#include "./ifc_omstoragehandlerenum.h"
+#include "./ifc_omstorageext.h"
+#include "./ifc_omfilestorage.h"
+
+#include <shlwapi.h>
+#include <strsafe.h>
+
+#define OMS_GROUP "OnlineService"
+
+#define OMS_ID "id"
+#define OMS_NAME "name"
+#define OMS_URL "url"
+#define OMS_ICON "icon"
+#define OMS_FLAGS "flags"
+#define OMS_RATING "rating"
+#define OMS_VERSION "version"
+#define OMS_DESCRIPTION "description"
+#define OMS_AUTHORFIRST "authorFirst"
+#define OMS_AUTHORLAST "authorLast"
+#define OMS_PUBLISHED "publishedDate"
+#define OMS_UPDATED "updatedDate"
+#define OMS_THUMBNAIL "thumbnail"
+#define OMS_SCREENSHOT "screenshot"
+#define OMS_GENERATION "generation"
+
+EnumIniFile::EnumIniFile(LPCWSTR pszAddress, ifc_omservicehost *serviceHost)
+ : ref(1), address(NULL), host(serviceHost), hFind(NULL)
+{
+ address = Plugin_CopyString(pszAddress);
+
+ if (NULL != host)
+ {
+ host->AddRef();
+
+ ifc_omstorageext *storageExt = NULL;
+ if (SUCCEEDED(host->QueryInterface(IFC_OmStorageExt, (void**)&storageExt)) && storageExt != NULL)
+ {
+ ifc_omstoragehandlerenum *handlerEnum = NULL;
+ if (SUCCEEDED(storageExt->Enumerate(&SUID_OmStorageIni, &handlerEnum)) && handlerEnum != NULL)
+ {
+ reader.RegisterHandlers(handlerEnum);
+ handlerEnum->Release();
+ }
+ storageExt->Release();
+ }
+ }
+}
+
+EnumIniFile::~EnumIniFile()
+{
+ Plugin_FreeString(address);
+
+ if (NULL != host)
+ host->Release();
+
+ if (NULL != hFind)
+ FindClose(hFind);
+}
+
+HRESULT EnumIniFile::CreateInstance(LPCWSTR pszAddress, ifc_omservicehost *host, EnumIniFile **instance)
+{
+ if (NULL == instance)
+ return E_POINTER;
+
+ WCHAR szBuffer[MAX_PATH * 2] = {0};
+ HRESULT hr = Plugin_ResolveRelativePath(pszAddress, host, szBuffer, ARRAYSIZE(szBuffer));
+ if (FAILED(hr)) return hr;
+
+ // test if we can load this one
+ if (FALSE == PathIsDirectory(szBuffer) && PathFileExists(szBuffer))
+ {
+ UINT id = GetPrivateProfileInt(TEXT(OMS_GROUP), WTEXT(OMS_ID), 0, pszAddress);
+ if (0 == id) return OMSTORAGE_E_UNKNOWN_FORMAT;
+ }
+
+ *instance = new EnumIniFile(szBuffer, host);
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t EnumIniFile::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t EnumIniFile::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int EnumIniFile::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmServiceEnum))
+ *object = static_cast<ifc_omserviceenum*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT EnumIniFile::Next(ULONG listSize, ifc_omservice **elementList, ULONG *elementCount)
+{
+ if(NULL != elementCount)
+ *elementCount = 0;
+
+ if (0 == listSize || NULL == elementList)
+ return E_INVALIDARG;
+
+ ULONG counter = 0;
+ BOOL bFoundNext = FALSE;
+ HRESULT hr = S_OK;
+
+ if (NULL == hFind)
+ {
+ hFind = FindFirstFile(address, &fData);
+ if (INVALID_HANDLE_VALUE == hFind)
+ {
+ DWORD error = GetLastError();
+ return HRESULT_FROM_WIN32(error);
+ }
+ bFoundNext = TRUE;
+ }
+ else
+ {
+ bFoundNext = FindNextFile(hFind, &fData);
+ }
+
+ if (bFoundNext)
+ {
+ do
+ {
+ LPCWSTR p = address;
+ while(p && L'.' == *p && L'\0' != *p) p++;
+ if (p && L'\0' != *p)
+ {
+ WCHAR base[MAX_PATH] = {0};
+ StringCchCopy(base, MAX_PATH, address);
+ PathRemoveFileSpec(base);
+
+ int baseLen = lstrlen(base);
+ base[baseLen] = L'\0';
+
+ if (!PathAppend(base, fData.cFileName))
+ {
+ base[baseLen] = L'\0';
+ PathAppend(base, fData.cAlternateFileName);
+ }
+
+ hr = reader.Load(base, host, &elementList[counter]);
+ if (S_OK == hr)
+ {
+ listSize--;
+ counter++;
+ if (0 == listSize) break;
+ }
+ }
+ bFoundNext = FindNextFile(hFind, &fData);
+
+ } while(bFoundNext);
+ }
+
+ if(NULL != elementCount)
+ *elementCount = counter;
+
+ return (counter > 0) ? S_OK : S_FALSE;
+}
+
+HRESULT EnumIniFile::Reset(void)
+{
+ if (NULL != hFind)
+ {
+ FindClose(hFind);
+ hFind = NULL;
+ }
+
+ return S_OK;
+}
+
+HRESULT EnumIniFile::Skip(ULONG elementCount)
+{
+ return E_NOTIMPL;
+}
+
+#define CBCLASS EnumIniFile
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_NEXT, Next)
+CB(API_RESET, Reset)
+CB(API_SKIP, Skip)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/enumIniFile.h b/Src/omBrowser/enumIniFile.h
new file mode 100644
index 00000000..dbd707ba
--- /dev/null
+++ b/Src/omBrowser/enumIniFile.h
@@ -0,0 +1,44 @@
+#ifndef NULLSOFT_WINAMP_ENUMERATOR_INI_HEADER
+#define NULLSOFT_WINAMP_ENUMERATOR_INI_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_omserviceenum.h"
+#include "./loaderIni.h"
+
+class ifc_omservicehost;
+
+class EnumIniFile : public ifc_omserviceenum
+{
+protected:
+ EnumIniFile(LPCWSTR pszAddress, ifc_omservicehost *serviceHost);
+ ~EnumIniFile();
+public:
+ static HRESULT CreateInstance(LPCWSTR pszAddress, ifc_omservicehost *host, EnumIniFile **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_omserviceenum */
+ HRESULT Next(ULONG listSize, ifc_omservice **elementList, ULONG *elementCount);
+ HRESULT Reset(void);
+ HRESULT Skip(ULONG elementCount);
+
+protected:
+ RECVS_DISPATCH;
+
+protected:
+ ULONG ref;
+ LPWSTR address;
+ ifc_omservicehost *host;
+ LoaderIni reader;
+ WIN32_FIND_DATA fData;
+ HANDLE hFind;
+};
+
+#endif //NULLSOFT_WINAMP_ENUMERATOR_INI_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/enumXmlBuffer.cpp b/Src/omBrowser/enumXmlBuffer.cpp
new file mode 100644
index 00000000..9e782a0b
--- /dev/null
+++ b/Src/omBrowser/enumXmlBuffer.cpp
@@ -0,0 +1,243 @@
+#include "main.h"
+#include "./enumXmlBuffer.h"
+#include "./service.h"
+#include "./ifc_omservicehost.h"
+#include "./ifc_omstorage.h"
+#include "./ifc_wasabihelper.h"
+#include "../xml/obj_xml.h"
+
+#include <shlwapi.h>
+#include <strsafe.h>
+
+#define XMLSIG "<?xml"
+#define XMLSIG_LEN 5
+
+ ULONG ref;
+ const void *buffer;
+ size_t bufferSize;
+ size_t cursor;
+ obj_xml *reader;
+ INT readerError;
+ XmlResponseParser parser;
+ Dispatchable *bufferOwner;
+
+EnumXmlBuffer::EnumXmlBuffer(obj_xml *xmlReader, const void *buffer, size_t bufferSize, Dispatchable *bufferOwner, ifc_omservicehost *serviceHost)
+ : ref(1), buffer(buffer), bufferSize(bufferSize), cursor(0), reader(xmlReader), readerError(OBJ_XML_SUCCESS), bufferOwner(bufferOwner)
+{
+ if (NULL != reader)
+ reader->AddRef();
+
+ if (NULL != bufferOwner)
+ bufferOwner->AddRef();
+
+ parser.Initialize(reader, serviceHost);
+}
+
+EnumXmlBuffer::~EnumXmlBuffer()
+{
+ parser.Finish();
+
+ if (NULL != reader)
+ {
+ if (OBJ_XML_SUCCESS == readerError)
+ {
+ reader->xmlreader_feed(0, 0);
+ }
+ reader->xmlreader_close();
+ ifc_wasabihelper *wasabi;
+ if (SUCCEEDED(Plugin_GetWasabiHelper(&wasabi)))
+ {
+ wasabi->ReleaseWasabiInterface(&obj_xmlGUID, reader);
+ wasabi->Release();
+ }
+ }
+
+ if (NULL != bufferOwner)
+ bufferOwner->Release();
+}
+
+HRESULT EnumXmlBuffer::CheckXmlHeader(const void *buffer, size_t bufferSize)
+{
+ if (NULL == buffer)
+ return E_INVALIDARG;
+
+ if (bufferSize >= XMLSIG_LEN)
+ {
+ if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, NORM_IGNORECASE, XMLSIG, XMLSIG_LEN, (LPSTR)buffer, XMLSIG_LEN) ||
+ CSTR_EQUAL == CompareStringW(CSTR_INVARIANT, NORM_IGNORECASE, WTEXT(XMLSIG), XMLSIG_LEN, (LPWSTR)buffer, XMLSIG_LEN))
+ {
+ return S_OK;
+ }
+ }
+ return OMSTORAGE_E_UNKNOWN_FORMAT;
+}
+
+HRESULT EnumXmlBuffer::CreateInstance(const void *buffer, size_t bufferSize, Dispatchable *bufferOwner, ifc_omservicehost *host, EnumXmlBuffer **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ *instance = NULL;
+
+
+ HRESULT hr = CheckXmlHeader(buffer, bufferSize);
+
+ if (SUCCEEDED(hr))
+ {
+ ifc_wasabihelper *wasabi;
+ hr = Plugin_GetWasabiHelper(&wasabi);
+ if (SUCCEEDED(hr))
+ {
+ obj_xml *reader;
+ wasabi->QueryWasabiInterface(&obj_xmlGUID, (void**)&reader);
+
+ if (NULL != reader && OBJ_XML_SUCCESS == reader->xmlreader_open())
+ {
+ *instance = new EnumXmlBuffer(reader, buffer, bufferSize, bufferOwner, host);
+ if (NULL == *instance)
+ {
+ hr = E_OUTOFMEMORY;
+ // reader stil has no support for AddRef()/Release()
+ wasabi->ReleaseWasabiInterface(&obj_xmlGUID, reader);
+
+ }
+ reader->Release();
+ }
+ else
+ {
+ hr = E_UNEXPECTED;
+ }
+ wasabi->Release();
+ }
+ }
+ return hr;
+}
+
+size_t EnumXmlBuffer::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t EnumXmlBuffer::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int EnumXmlBuffer::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmServiceEnum))
+ *object = static_cast<ifc_omserviceenum*>(this);
+ else if (IsEqualIID(interface_guid, IFC_OmXmlServiceEnum))
+ *object = static_cast<ifc_omxmlserviceenum*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT EnumXmlBuffer::Next(ULONG listSize, ifc_omservice **elementList, ULONG *elementCount)
+{
+ if(NULL != elementCount)
+ *elementCount = 0;
+
+ if (0 == listSize || NULL == elementList)
+ return E_INVALIDARG;
+
+ ULONG counter = 0;
+ HRESULT hr = S_OK;
+ ifc_omservice *service;
+
+ while(counter < listSize)
+ {
+ hr = parser.PeekService(&service);
+ if (FAILED(hr)) return hr;
+ if (S_OK == hr)
+ {
+ elementList[counter] = service;
+ counter++;
+ }
+ else
+ {
+ if (cursor < bufferSize)
+ {
+ readerError = reader->xmlreader_feed((BYTE*)buffer + cursor, bufferSize - cursor);
+ if (OBJ_XML_SUCCESS != readerError) return E_FAIL;
+ cursor = bufferSize;
+ }
+ else
+ {
+ if (OBJ_XML_SUCCESS == readerError)
+ reader->xmlreader_feed(0, 0);
+ break;
+ }
+
+
+ }
+
+ }
+
+ if(NULL != elementCount)
+ *elementCount = counter;
+
+ return (counter > 0) ? S_OK : S_FALSE;
+}
+
+HRESULT EnumXmlBuffer::Reset(void)
+{
+ cursor = 0;
+ readerError = OBJ_XML_SUCCESS;
+ reader->xmlreader_reset();
+ parser.Reset();
+ return E_NOTIMPL;
+}
+
+HRESULT EnumXmlBuffer::Skip(ULONG elementCount)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT EnumXmlBuffer::GetStatusCode(UINT *code)
+{
+ return parser.GetCode(code);
+}
+
+HRESULT EnumXmlBuffer::GetStatusText(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ return parser.GetText(pszBuffer, cchBufferMax);
+}
+
+#define CBCLASS EnumXmlBuffer
+START_MULTIPATCH;
+ START_PATCH(MPIID_OMSERVICEENUM)
+
+ M_CB(MPIID_OMSERVICEENUM, ifc_omserviceenum, ADDREF, AddRef);
+ M_CB(MPIID_OMSERVICEENUM, ifc_omserviceenum, RELEASE, Release);
+ M_CB(MPIID_OMSERVICEENUM, ifc_omserviceenum, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMSERVICEENUM, ifc_omserviceenum, API_NEXT, Next);
+ M_CB(MPIID_OMSERVICEENUM, ifc_omserviceenum, API_RESET, Reset);
+ M_CB(MPIID_OMSERVICEENUM, ifc_omserviceenum, API_SKIP, Skip);
+
+ NEXT_PATCH(MPIID_OMXMLSERVICEENUM)
+ M_CB(MPIID_OMXMLSERVICEENUM, ifc_omxmlserviceenum, ADDREF, AddRef);
+ M_CB(MPIID_OMXMLSERVICEENUM, ifc_omxmlserviceenum, RELEASE, Release);
+ M_CB(MPIID_OMXMLSERVICEENUM, ifc_omxmlserviceenum, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMXMLSERVICEENUM, ifc_omxmlserviceenum, API_GETSTATUSCODE, GetStatusCode);
+ M_CB(MPIID_OMXMLSERVICEENUM, ifc_omxmlserviceenum, API_GETSTATUSTEXT, GetStatusText);
+
+ END_PATCH
+END_MULTIPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/enumXmlBuffer.h b/Src/omBrowser/enumXmlBuffer.h
new file mode 100644
index 00000000..599ba143
--- /dev/null
+++ b/Src/omBrowser/enumXmlBuffer.h
@@ -0,0 +1,62 @@
+#ifndef NULLSOFT_WINAMP_ENUMERATOR_XML_BUFFER_HEADER
+#define NULLSOFT_WINAMP_ENUMERATOR_XML_BUFFER_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_omserviceenum.h"
+#include "./ifc_omxmlserviceenum.h"
+#include "./xmlResponseParser.h"
+
+#include <bfc/multipatch.h>
+
+class ifc_omservicehost;
+class obj_xml;
+
+#define MPIID_OMSERVICEENUM 10
+#define MPIID_OMXMLSERVICEENUM 20
+
+class EnumXmlBuffer : public MultiPatch<MPIID_OMSERVICEENUM, ifc_omserviceenum>,
+ public MultiPatch<MPIID_OMXMLSERVICEENUM, ifc_omxmlserviceenum>
+{
+
+protected:
+ EnumXmlBuffer(obj_xml *xmlReader, const void *buffer, size_t bufferSize, Dispatchable *bufferOwner, ifc_omservicehost *serviceHost);
+ ~EnumXmlBuffer();
+
+public:
+ static HRESULT CreateInstance(const void *buffer, size_t bufferSize, Dispatchable *bufferOwner, ifc_omservicehost *host, EnumXmlBuffer **instance);
+ static HRESULT CheckXmlHeader(const void *buffer, size_t bufferSize);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_omserviceenum */
+ HRESULT Next(ULONG listSize, ifc_omservice **elementList, ULONG *elementCount);
+ HRESULT Reset(void);
+ HRESULT Skip(ULONG elementCount);
+
+ /* ifc_omxmlserviceenum */
+ HRESULT GetStatusCode(UINT *code);
+ HRESULT GetStatusText(LPWSTR pszBuffer, UINT cchBufferMax);
+
+
+protected:
+ ULONG ref;
+ const void *buffer;
+ size_t bufferSize;
+ size_t cursor;
+ obj_xml *reader;
+ INT readerError;
+ XmlResponseParser parser;
+ Dispatchable *bufferOwner;
+
+protected:
+ RECVS_MULTIPATCH;
+};
+
+#endif //NULLSOFT_WINAMP_ENUMERATOR_XML_BUFFER_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/enumXmlFile.cpp b/Src/omBrowser/enumXmlFile.cpp
new file mode 100644
index 00000000..0ee0ac66
--- /dev/null
+++ b/Src/omBrowser/enumXmlFile.cpp
@@ -0,0 +1,275 @@
+#include "main.h"
+#include "./enumXmlFile.h"
+#include "./service.h"
+#include "./ifc_omservicehost.h"
+#include "./ifc_omstorage.h"
+#include "./ifc_wasabihelper.h"
+#include "../xml/obj_xml.h"
+
+#include <shlwapi.h>
+#include <strsafe.h>
+
+#define XMLSIG "<?xml"
+#define XMLSIG_LEN 5
+
+EnumXmlFile::EnumXmlFile(HANDLE xmlHandle, obj_xml *xmlReader, LPCWSTR pszAddress, ifc_omservicehost *serviceHost)
+ : ref(1), address(NULL), hFile(xmlHandle), reader(xmlReader), readerError(OBJ_XML_SUCCESS),
+ buffer(NULL), bufferMax(4096)
+{
+ address = Plugin_CopyString(pszAddress);
+
+ if (NULL != reader)
+ reader->AddRef();
+
+ parser.Initialize(reader, serviceHost);
+}
+
+EnumXmlFile::~EnumXmlFile()
+{
+ Plugin_FreeString(address);
+
+ if (NULL != hFile)
+ CloseHandle(hFile);
+
+ parser.Finish();
+
+ if (NULL != reader)
+ {
+ if (OBJ_XML_SUCCESS == readerError)
+ {
+ reader->xmlreader_feed(0, 0);
+ }
+ reader->xmlreader_close();
+ ifc_wasabihelper *wasabi;
+ if (SUCCEEDED(Plugin_GetWasabiHelper(&wasabi)))
+ {
+ wasabi->ReleaseWasabiInterface(&obj_xmlGUID, reader);
+ wasabi->Release();
+ }
+ }
+
+ if (NULL != buffer)
+ free(buffer);
+}
+
+HRESULT EnumXmlFile::CheckXmlHeader(HANDLE hFile)
+{
+ DWORD read = 0;
+ BYTE szBuffer[XMLSIG_LEN * 2] = {0};
+
+ SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
+
+ if (FALSE == ReadFile(hFile, (void*)szBuffer, sizeof(szBuffer), &read, NULL))
+ {
+ DWORD error = GetLastError();
+ return HRESULT_FROM_WIN32(error);
+ }
+
+ SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
+
+ if (read >= XMLSIG_LEN)
+ {
+ if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, NORM_IGNORECASE, XMLSIG, XMLSIG_LEN, (LPSTR)szBuffer, XMLSIG_LEN) ||
+ CSTR_EQUAL == CompareStringW(CSTR_INVARIANT, NORM_IGNORECASE, WTEXT(XMLSIG), XMLSIG_LEN, (LPWSTR)szBuffer, XMLSIG_LEN))
+ {
+ return S_OK;
+ }
+ }
+
+ return OMSTORAGE_E_UNKNOWN_FORMAT;
+}
+
+HRESULT EnumXmlFile::CreateInstance(LPCWSTR pszAddress, ifc_omservicehost *host, EnumXmlFile **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ *instance = NULL;
+
+ HRESULT hr;
+ WCHAR szBuffer[MAX_PATH * 2] = {0};
+ hr = Plugin_ResolveRelativePath(pszAddress, host, szBuffer, ARRAYSIZE(szBuffer));
+ if (FAILED(hr)) return hr;
+
+ HANDLE hFile = CreateFile(szBuffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
+ if (INVALID_HANDLE_VALUE == hFile)
+ {
+ DWORD error = GetLastError();
+ return HRESULT_FROM_WIN32(error);
+ }
+
+ hr = CheckXmlHeader(hFile);
+
+ if (SUCCEEDED(hr))
+ {
+ ifc_wasabihelper *wasabi;
+ hr = Plugin_GetWasabiHelper(&wasabi);
+ if (SUCCEEDED(hr))
+ {
+ obj_xml *reader;
+ wasabi->QueryWasabiInterface(&obj_xmlGUID, (void**)&reader);
+
+ if (NULL != reader && OBJ_XML_SUCCESS == reader->xmlreader_open())
+ {
+ *instance = new EnumXmlFile(hFile, reader, szBuffer, host);
+ if (NULL == *instance)
+ {
+ hr = E_OUTOFMEMORY;
+ // reader stil has no support for AddRef()/Release()
+ wasabi->ReleaseWasabiInterface(&obj_xmlGUID, reader);
+
+ }
+ reader->Release();
+ }
+ else
+ {
+ hr = E_UNEXPECTED;
+ }
+ wasabi->Release();
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (NULL != hFile) CloseHandle(hFile);
+ }
+
+ return hr;
+}
+
+size_t EnumXmlFile::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t EnumXmlFile::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int EnumXmlFile::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmServiceEnum))
+ *object = static_cast<ifc_omserviceenum*>(this);
+ else if (IsEqualIID(interface_guid, IFC_OmXmlServiceEnum))
+ *object = static_cast<ifc_omxmlserviceenum*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT EnumXmlFile::Next(ULONG listSize, ifc_omservice **elementList, ULONG *elementCount)
+{
+ if(NULL != elementCount)
+ *elementCount = 0;
+
+ if (0 == listSize || NULL == elementList)
+ return E_INVALIDARG;
+
+ ULONG counter = 0;
+ HRESULT hr = S_OK;
+ ifc_omservice *service;
+
+ while(counter < listSize)
+ {
+ hr = parser.PeekService(&service);
+ if (FAILED(hr)) return hr;
+ if (S_OK == hr)
+ {
+ elementList[counter] = service;
+ counter++;
+ }
+ else
+ {
+ if (NULL == buffer)
+ {
+ buffer = (BYTE*)calloc(bufferMax, sizeof(BYTE));
+ if (NULL == buffer) return E_OUTOFMEMORY;
+ }
+
+ DWORD read = 0;
+ if (FALSE == ReadFile(hFile, buffer, bufferMax, &read, NULL))
+ {
+ DWORD error = GetLastError();
+ return HRESULT_FROM_WIN32(error);
+ }
+
+ if (0 == read)
+ {
+ if (OBJ_XML_SUCCESS == readerError)
+ reader->xmlreader_feed(0, 0);
+ break;
+ }
+
+ readerError = reader->xmlreader_feed(buffer, read);
+ if (OBJ_XML_SUCCESS != readerError) return E_FAIL;
+ }
+
+ }
+
+ if(NULL != elementCount)
+ *elementCount = counter;
+
+ return (counter > 0) ? S_OK : S_FALSE;
+}
+
+HRESULT EnumXmlFile::Reset(void)
+{
+ SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
+ readerError = OBJ_XML_SUCCESS;
+ reader->xmlreader_reset();
+ parser.Reset();
+ return E_NOTIMPL;
+}
+
+HRESULT EnumXmlFile::Skip(ULONG elementCount)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT EnumXmlFile::GetStatusCode(UINT *code)
+{
+ return parser.GetCode(code);
+}
+
+HRESULT EnumXmlFile::GetStatusText(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ return parser.GetText(pszBuffer, cchBufferMax);
+}
+
+#define CBCLASS EnumXmlFile
+START_MULTIPATCH;
+ START_PATCH(MPIID_OMSERVICEENUM)
+
+ M_CB(MPIID_OMSERVICEENUM, ifc_omserviceenum, ADDREF, AddRef);
+ M_CB(MPIID_OMSERVICEENUM, ifc_omserviceenum, RELEASE, Release);
+ M_CB(MPIID_OMSERVICEENUM, ifc_omserviceenum, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMSERVICEENUM, ifc_omserviceenum, API_NEXT, Next);
+ M_CB(MPIID_OMSERVICEENUM, ifc_omserviceenum, API_RESET, Reset);
+ M_CB(MPIID_OMSERVICEENUM, ifc_omserviceenum, API_SKIP, Skip);
+
+ NEXT_PATCH(MPIID_OMXMLSERVICEENUM)
+ M_CB(MPIID_OMXMLSERVICEENUM, ifc_omxmlserviceenum, ADDREF, AddRef);
+ M_CB(MPIID_OMXMLSERVICEENUM, ifc_omxmlserviceenum, RELEASE, Release);
+ M_CB(MPIID_OMXMLSERVICEENUM, ifc_omxmlserviceenum, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMXMLSERVICEENUM, ifc_omxmlserviceenum, API_GETSTATUSCODE, GetStatusCode);
+ M_CB(MPIID_OMXMLSERVICEENUM, ifc_omxmlserviceenum, API_GETSTATUSTEXT, GetStatusText);
+
+ END_PATCH
+END_MULTIPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/enumXmlFile.h b/Src/omBrowser/enumXmlFile.h
new file mode 100644
index 00000000..11f2fbd8
--- /dev/null
+++ b/Src/omBrowser/enumXmlFile.h
@@ -0,0 +1,61 @@
+#ifndef NULLSOFT_WINAMP_ENUMERATOR_XML_HEADER
+#define NULLSOFT_WINAMP_ENUMERATOR_XML_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_omserviceenum.h"
+#include "./ifc_omxmlserviceenum.h"
+#include "./xmlResponseParser.h"
+
+#include <bfc/multipatch.h>
+
+class ifc_omservicehost;
+class obj_xml;
+
+#define MPIID_OMSERVICEENUM 10
+#define MPIID_OMXMLSERVICEENUM 20
+
+class EnumXmlFile : public MultiPatch<MPIID_OMSERVICEENUM, ifc_omserviceenum>,
+ public MultiPatch<MPIID_OMXMLSERVICEENUM, ifc_omxmlserviceenum>
+{
+
+protected:
+ EnumXmlFile(HANDLE xmlHandle, obj_xml *xmlReader, LPCWSTR pszAddress, ifc_omservicehost *serviceHost);
+ ~EnumXmlFile();
+
+public:
+ static HRESULT CreateInstance(LPCWSTR pszAddress, ifc_omservicehost *host, EnumXmlFile **instance);
+ static HRESULT CheckXmlHeader(HANDLE hFile);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_omserviceenum */
+ HRESULT Next(ULONG listSize, ifc_omservice **elementList, ULONG *elementCount);
+ HRESULT Reset(void);
+ HRESULT Skip(ULONG elementCount);
+
+ /* ifc_omxmlserviceenum */
+ HRESULT GetStatusCode(UINT *code);
+ HRESULT GetStatusText(LPWSTR pszBuffer, UINT cchBufferMax);
+
+protected:
+ RECVS_MULTIPATCH;
+
+protected:
+ ULONG ref;
+ LPWSTR address;
+ HANDLE hFile;
+ obj_xml *reader;
+ INT readerError;
+ XmlResponseParser parser;
+ BYTE *buffer;
+ UINT bufferMax;
+};
+
+#endif //NULLSOFT_WINAMP_ENUMERATOR_XML_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/errorPages.rc b/Src/omBrowser/errorPages.rc
new file mode 100644
index 00000000..4bcac120
--- /dev/null
+++ b/Src/omBrowser/errorPages.rc
@@ -0,0 +1,20 @@
+/////////////////////////////////////////////////////////////////////////////
+//
+// Data
+//
+DNSERROR.HTM HTML
+".\\resources\\pages\\dnsError.htm"
+ERRORPAGEFUNCTIONS.JS HTML
+".\\resources\\pages\\errorPageFunctions.js"
+ERRORPAGESTRINGS.JS HTML
+".\\resources\\pages\\errorPageStrings.js"
+HTTPERROR.HTM HTML
+".\\resources\\pages\\httpError.htm"
+ERRORICON.PNG 2110
+".\\resources\\pages\\errorIcon.png"
+NAVCANCEL.HTM HTML
+".\\resources\\pages\\navCancel.htm"
+WINAMPERROR.CSS HTML
+".\\resources\\pages\\winampError.css"
+INETDISABLED.HTM HTML
+".\\resources\\pages\\inetDisabled.htm" \ No newline at end of file
diff --git a/Src/omBrowser/flagTracker.cpp b/Src/omBrowser/flagTracker.cpp
new file mode 100644
index 00000000..2073fd76
--- /dev/null
+++ b/Src/omBrowser/flagTracker.cpp
@@ -0,0 +1,96 @@
+#include "main.h"
+#include "./flagTracker.h"
+
+FlagTracker::FlagTracker()
+ : flags(0), cache(0), updateRef(0), eventHandler(NULL), eventParam(0)
+{
+ InitializeCriticalSection(&lock);
+}
+
+FlagTracker::~FlagTracker()
+{
+ DeleteCriticalSection(&lock);
+}
+
+void FlagTracker::Set(UINT nFlags, UINT nMask)
+{
+ EnterCriticalSection(&lock);
+
+ nFlags &= nMask;
+
+ UINT clearMask = ~(nFlags ^ nMask);
+ flags &= clearMask;
+ cache &= clearMask;
+
+ if (0 != nFlags)
+ {
+ Mark(nFlags);
+ }
+
+ LeaveCriticalSection(&lock);
+}
+
+UINT FlagTracker::Get()
+{
+ return flags;
+}
+
+void FlagTracker::Mark(UINT nFlags)
+{
+ EnterCriticalSection(&lock);
+
+ flags |= nFlags;
+
+ if (0 == updateRef)
+ {
+ if (NULL != eventHandler && 0 != nFlags)
+ {
+ eventHandler(nFlags, this, eventParam);
+ }
+ }
+ else
+ {
+ cache |= nFlags;
+ }
+ LeaveCriticalSection(&lock);
+}
+
+ULONG FlagTracker::BeginUpdate()
+{
+ EnterCriticalSection(&lock);
+ ULONG r = InterlockedIncrement((LONG*)&updateRef);
+ LeaveCriticalSection(&lock);
+ return r;
+}
+
+ULONG FlagTracker::EndUpdate()
+{
+ EnterCriticalSection(&lock);
+
+ ULONG r;
+ if (0 == updateRef)
+ {
+ r = 0;
+ }
+ else
+ {
+ r = InterlockedDecrement((LONG*)&updateRef);
+ if (0 == r && 0 != cache)
+ {
+ Mark(cache);
+ cache = 0;
+ }
+ }
+ LeaveCriticalSection(&lock);
+ return r;
+}
+
+void FlagTracker::SetEventHandler(EventHandler handler, ULONG_PTR user)
+{
+ EnterCriticalSection(&lock);
+
+ eventHandler = handler;
+ eventParam = user;
+
+ LeaveCriticalSection(&lock);
+} \ No newline at end of file
diff --git a/Src/omBrowser/flagTracker.h b/Src/omBrowser/flagTracker.h
new file mode 100644
index 00000000..eea515bc
--- /dev/null
+++ b/Src/omBrowser/flagTracker.h
@@ -0,0 +1,37 @@
+#ifndef NULLSOFT_WINAMP_FLAG_TRACKER_HEADER
+#define NULLSOFT_WINAMP_FLAG_TRACKER_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+class FlagTracker
+{
+public:
+ typedef void (CALLBACK *EventHandler)(UINT /*nMarked*/, FlagTracker* /*instance*/, ULONG_PTR /*user*/);
+
+public:
+ FlagTracker();
+ ~FlagTracker();
+public:
+ void Set(UINT nFlags, UINT nMask);
+ UINT Get();
+ void Mark(UINT nFlags);
+
+ ULONG BeginUpdate();
+ ULONG EndUpdate();
+
+ void SetEventHandler(EventHandler handler, ULONG_PTR user);
+
+protected:
+ UINT flags;
+ UINT cache;
+ ULONG updateRef;
+ CRITICAL_SECTION lock;
+ EventHandler eventHandler;
+ ULONG_PTR eventParam;
+};
+
+#endif //NULLSOFT_WINAMP_MODIFY_TRACKER_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/graphics.cpp b/Src/omBrowser/graphics.cpp
new file mode 100644
index 00000000..33de4fbf
--- /dev/null
+++ b/Src/omBrowser/graphics.cpp
@@ -0,0 +1,309 @@
+#include "./main.h"
+#include "./graphics.h"
+
+#include <math.h>
+#include <strsafe.h>
+
+
+INT GetColorDistance(COLORREF rgb1, COLORREF rgb2)
+{
+ return (1000 * ((GetRValue(rgb1) - GetRValue(rgb2)) +
+ (GetGValue(rgb1) - GetGValue(rgb2)) +
+ (GetBValue(rgb1) - GetBValue(rgb2))))/ (3 * 255);
+}
+
+COLORREF GetDarkerColor(COLORREF rgb1, COLORREF rgb2)
+{
+ INT g1 = (GetRValue(rgb1)*299 + GetGValue(rgb1)*587 + GetBValue(rgb1)*114);
+ INT g2 = (GetRValue(rgb2)*299 + GetGValue(rgb2)*587 + GetBValue(rgb2)*114);
+ return (g1 < g2) ? rgb1 : rgb2;
+}
+
+COLORREF BlendColors(COLORREF rgbTop, COLORREF rgbBottom, INT alpha)
+{
+ if (alpha > 254) return rgbTop;
+ if (alpha < 0) return rgbBottom;
+
+ WORD k = (((255 - alpha)*255 + 127)/255);
+
+ return RGB( (GetRValue(rgbTop)*alpha + k*GetRValue(rgbBottom) + 127)/255,
+ (GetGValue(rgbTop)*alpha + k*GetGValue(rgbBottom) + 127)/255,
+ (GetBValue(rgbTop)*alpha + k*GetBValue(rgbBottom) + 127)/255);
+}
+
+BOOL Image_Colorize(BYTE *pPixels, LONG cx, LONG cy, WORD bpp, COLORREF rgbBk, COLORREF rgbFg, BOOL removeAlpha)
+{
+ LONG pitch, x;
+ INT step;
+ BYTE rFg, gFg, bFg;
+ LPBYTE cursor, line;
+
+ if (bpp < 24) return FALSE;
+
+ step = (bpp>>3);
+ pitch = cx*step;
+ while (pitch%4) pitch++;
+
+ rFg = GetRValue(rgbFg); gFg = GetGValue(rgbFg); bFg = GetBValue(rgbFg);
+
+ INT bK = (bFg - GetBValue(rgbBk));
+ INT gK = (gFg - GetGValue(rgbBk));
+ INT rK = (rFg - GetRValue(rgbBk));
+
+ if (24 == bpp)
+ {
+ for (line = pPixels; cy-- != 0; line += pitch )
+ {
+ for (x = cx, cursor = line; x-- != 0; cursor += 3)
+ {
+ cursor[0] = bFg - (bK*(255 - cursor[0])>>8);
+ cursor[1] = gFg - (gK*(255 - cursor[1])>>8);
+ cursor[2] = rFg - (rK*(255 - cursor[2])>>8);
+ }
+ }
+ }
+ else if (32 == bpp)
+ {
+ if (removeAlpha)
+ {
+ BYTE rBk, gBk, bBk;
+ rBk = GetRValue(rgbBk); gBk = GetGValue(rgbBk); bBk = GetBValue(rgbBk);
+ for (line = pPixels; cy-- != 0; line += pitch )
+ {
+ for (x = cx, cursor = line; x-- != 0; cursor += 4)
+ {
+ if (0x00 == cursor[3])
+ {
+ cursor[0] = bBk;
+ cursor[1] = gBk;
+ cursor[2] = rBk;
+ cursor[3] = 0xFF;
+ }
+ else if (0xFF == cursor[3])
+ {
+ cursor[0] = bFg - (bK*(255 - cursor[0])>>8);
+ cursor[1] = gFg - (gK*(255 - cursor[1])>>8);
+ cursor[2] = rFg - (rK*(255 - cursor[2])>>8);
+ }
+ else
+ {
+ cursor[0] = ((bFg - (bK*(255 - cursor[0])>>8))*cursor[3] + (((255 - cursor[3])*255 + 127)/255)*bBk + 127)/255;
+ cursor[1] = ((gFg - (gK*(255 - cursor[1])>>8))*cursor[3] + (((255 - cursor[3])*255 + 127)/255)*gBk + 127)/255;
+ cursor[2] = ((rFg - (rK*(255 - cursor[2])>>8))*cursor[3] + (((255 - cursor[3])*255 + 127)/255)*rBk + 127)/255;
+ cursor[3] = 0xFF;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (line = pPixels; cy-- != 0; line += pitch )
+ {
+ for (x = cx, cursor = line; x-- != 0; cursor += 4)
+ {
+ cursor[0] = bFg - (bK*(255 - cursor[0])>>8);
+ cursor[1] = gFg - (gK*(255 - cursor[1])>>8);
+ cursor[2] = rFg - (rK*(255 - cursor[2])>>8);
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+BOOL Image_BlendOnColorEx(BYTE *pPixels, INT bitmapCX, INT bitmapCY, LONG x, LONG y, LONG cx, LONG cy, WORD bpp, BOOL premult, COLORREF rgb)
+{
+ LONG pitch;
+ WORD r, g, b;
+ INT step = (bpp>>3);
+ LPBYTE line, cursor;
+ pitch = bitmapCX * step;
+ while (pitch%4) pitch++;
+
+ if (bpp != 32)
+ return TRUE;
+
+ if (cy < 0) cy -= cy;
+
+ r = GetRValue(rgb); g = GetGValue(rgb); b = GetBValue(rgb);
+
+ INT ofs = (bitmapCY > 0) ? (bitmapCY - (y + cy)) : y;
+ line = pPixels + pitch * ofs + x*step;
+
+ if (premult)
+ {
+ for (; cy-- != 0; line += pitch)
+ {
+ for (x = cx, cursor = line; x-- != 0; cursor += 4)
+ {
+ if (0x00 == cursor[3])
+ {
+ cursor[0] = (BYTE)b;
+ cursor[1] = (BYTE)g;
+ cursor[2] = (BYTE)r;
+ cursor[3] = 0xFF;
+ }
+ else if (cursor[3] != 0xFF)
+ {
+ WORD a = 255 - cursor[3];
+ WORD destB = (cursor[0] * 255 + a * b + 127) / 255;
+ WORD destG = (cursor[1] * 255 + a * g + 127) / 255;
+ WORD destR = (cursor[2] * 255 + a * r + 127) / 255;
+
+ cursor[0] = (destB > 0xFF) ? 0xFF : destB;
+ cursor[1] = (destG > 0xFF) ? 0xFF : destG;
+ cursor[2] = (destR > 0xFF) ? 0xFF : destR;
+ cursor[3] = 0xFF;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (; cy-- != 0; line += pitch)
+ {
+ for (x = cx, cursor = line; x-- != 0; cursor += 4)
+ {
+ if (0x00 == cursor[3])
+ {
+ cursor[0] = (BYTE)b;
+ cursor[1] = (BYTE)g;
+ cursor[2] = (BYTE)r;
+ cursor[3] = 0xFF;
+ }
+ else if (cursor[3] != 0xFF)
+ {
+ WORD a = (((255 - cursor[3])*255 + 127)/255);
+ cursor[0] = (cursor[0]*cursor[3] + a*b + 127)/255;
+ cursor[1] = (cursor[1]*cursor[3] + a*g + 127)/255;
+ cursor[2] = (cursor[2]*cursor[3] + a*r + 127)/255;
+ cursor[3] = 0xFF;
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+BOOL Image_BlendOnColor(HBITMAP hbmp, RECT *prcPart, BOOL premult, COLORREF rgb)
+{
+ DIBSECTION dibsec;
+ if (!hbmp || sizeof(DIBSECTION) != GetObject(hbmp, sizeof(DIBSECTION), &dibsec) ||
+ BI_RGB != dibsec.dsBmih.biCompression || 1 != dibsec.dsBmih.biPlanes || dibsec.dsBm.bmBitsPixel != 32)
+ return FALSE;
+
+ return Image_BlendOnColorEx((BYTE*)dibsec.dsBm.bmBits, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight,
+ prcPart->left, prcPart->top,
+ prcPart->right - prcPart->left, prcPart->bottom - prcPart->top,
+ dibsec.dsBm.bmBitsPixel, premult, rgb);
+}
+
+HBITMAP Image_AnimateRotation(HDC hdc, HBITMAP bitmapFrame, INT frameCount, COLORREF rgbBk, BOOL fKeepSize)
+{
+ if (NULL == bitmapFrame)
+ return NULL;
+
+ BITMAP bm;
+ if (sizeof(BITMAP) != GetObject(bitmapFrame, sizeof(BITMAP), &bm))
+ return NULL;
+
+ if (bm.bmHeight < 0) bm.bmHeight = -bm.bmHeight;
+
+ HBITMAP hbmp = NULL;
+
+ HDC hdcDst = CreateCompatibleDC(hdc);
+ HDC hdcSrc = CreateCompatibleDC(hdc);
+ if (NULL != hdcDst && NULL != hdcSrc)
+ {
+ INT side;
+ if (FALSE == fKeepSize)
+ side = (INT)ceil(_hypot(bm.bmWidth, bm.bmHeight));
+ else
+ {
+ side = bm.bmWidth;
+ if (bm.bmHeight > side)
+ side = bm.bmHeight;
+ }
+ hbmp = CreateCompatibleBitmap(hdc, side, side * frameCount);
+ if (NULL != hbmp)
+ {
+ LONG centerX, centerY;
+ centerX = side/2;
+ centerY = side/2;
+
+ XFORM xForm;
+ ZeroMemory(&xForm, sizeof(XFORM));
+
+ HBITMAP hbmpFrameOld = (HBITMAP)SelectObject(hdcSrc, bitmapFrame);
+ HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcDst, hbmp);
+
+ RECT rcFill;
+ SetRect(&rcFill, 0, 0, side, side * frameCount);
+ SetBkColor(hdcDst, rgbBk);
+ ExtTextOut(hdcDst, 0, 0, ETO_OPAQUE, &rcFill, NULL, 0, NULL);
+ INT graphicsMode = SetGraphicsMode(hdcDst, GM_ADVANCED);
+ INT top = (side - bm.bmHeight)/2;
+ INT left = (side - bm.bmWidth)/2;
+
+ for (INT i = 0; i < frameCount; i++)
+ {
+ double fangle = (double)(360/frameCount * i)/180. * 3.1415926;
+ xForm.eM11 = (float)cos(fangle);
+ xForm.eM12 = (float)sin(fangle);
+ xForm.eM21 = (float)-sin(fangle);
+ xForm.eM22 = (float)cos(fangle);
+ xForm.eDx = (float)(centerX - cos(fangle)*centerX + sin(fangle)*centerY);
+ xForm.eDy = (float)(centerY - cos(fangle)*centerY - sin(fangle)*centerX);
+ SetWorldTransform(hdcDst, &xForm);
+ BitBlt(hdcDst, left, top, bm.bmWidth, bm.bmHeight, hdcSrc, 0, 0, SRCCOPY);
+ centerY += side;
+ top += side;
+
+ }
+
+ SetGraphicsMode(hdcDst, graphicsMode);
+ ModifyWorldTransform(hdcDst, NULL, MWT_IDENTITY);
+
+ SelectObject(hdcSrc, hbmpFrameOld);
+ SelectObject(hdcDst, hbmpOld);
+
+ }
+ }
+ if (NULL != hdcDst) DeleteDC(hdcDst);
+ if (NULL != hdcSrc) DeleteDC(hdcSrc);
+
+ return hbmp;
+}
+
+BOOL Image_Premultiply(BYTE *pPixels, LONG cx, LONG cy)
+{
+ LONG pitch, x;
+ pitch = cx* 4;
+ LPBYTE cursor, line;
+
+ for (line = pPixels; cy-- != 0; line += pitch )
+ {
+ for (x = cx, cursor = line; x-- != 0; cursor += 4)
+ {
+ if (0x00 == cursor[3])
+ {
+ cursor[0] = 0x00;
+ cursor[1] = 0x00;
+ cursor[2] = 0x00;
+ }
+ else if (0xFF != cursor[3])
+ {
+ cursor[0] = (cursor[0] * cursor[3]) >> 8;
+ cursor[1] = (cursor[1] * cursor[3]) >> 8;
+ cursor[2] = (cursor[2] * cursor[3]) >> 8;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+BOOL Image_AlphaBlend(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, BLENDFUNCTION blendFunction)
+{
+ return AlphaBlend(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, blendFunction);
+} \ No newline at end of file
diff --git a/Src/omBrowser/graphics.h b/Src/omBrowser/graphics.h
new file mode 100644
index 00000000..43f4affc
--- /dev/null
+++ b/Src/omBrowser/graphics.h
@@ -0,0 +1,23 @@
+#ifndef NULLOSFT_ONLINEMEDIA_GRAPHICS_HEADER
+#define NULLOSFT_ONLINEMEDIA_GRAPHICS_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+INT GetColorDistance(COLORREF rgb1, COLORREF rgb2);
+COLORREF GetDarkerColor(COLORREF rgb1, COLORREF rgb2);
+COLORREF BlendColors(COLORREF rgbTop, COLORREF rgbBottom, INT alpha);
+
+BOOL Image_Colorize(BYTE *pPixels, LONG cx, LONG cy, WORD bpp, COLORREF rgbBk, COLORREF rgbFg, BOOL removeAlpha);
+BOOL Image_BlendOnColorEx(BYTE *pPixels, INT bitmapCX, INT bitmapCY, LONG x, LONG y, LONG cx, LONG cy, WORD bpp, BOOL premult, COLORREF rgb);
+BOOL Image_BlendOnColor(HBITMAP hbmp, RECT *prcPart, BOOL premult, COLORREF rgb);
+BOOL Image_Premultiply(BYTE *pPixels, LONG cx, LONG cy);
+BOOL Image_AlphaBlend(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, BLENDFUNCTION blendFunction);
+
+HBITMAP Image_AnimateRotation(HDC hdc, HBITMAP bitmapFrame, INT frameCount, COLORREF rgbBk, BOOL fKeepSize);
+
+
+#endif //NULLOSFT_ONLINEMEDIA_GRAPHICS_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/graphicsObject.cpp b/Src/omBrowser/graphicsObject.cpp
new file mode 100644
index 00000000..8025921b
--- /dev/null
+++ b/Src/omBrowser/graphicsObject.cpp
@@ -0,0 +1,135 @@
+#include "./common.h"
+#include "./graphicsObject.h"
+#include "./graphics.h"
+
+GraphicsObject::GraphicsObject()
+ : ref(1)
+{
+}
+
+GraphicsObject::~GraphicsObject()
+{
+}
+
+HRESULT GraphicsObject::CreateInstance(GraphicsObject **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ *instance = new GraphicsObject();
+ if (NULL == *instance) return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+size_t GraphicsObject::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t GraphicsObject::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int GraphicsObject::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmGrpahics))
+ *object = static_cast<ifc_omgraphics*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT GraphicsObject::GetDistance(COLORREF rgb1, COLORREF rgb2, int *distance)
+{
+ if (NULL == distance) return E_POINTER;
+ *distance = GetColorDistance(rgb1, rgb2);
+ return S_OK;
+}
+
+HRESULT GraphicsObject::GetDarker(COLORREF rgb1, COLORREF rgb2, COLORREF *result)
+{
+ if (NULL == result) return E_POINTER;
+ *result = GetDarkerColor(rgb1, rgb2);
+ return S_OK;
+}
+
+HRESULT GraphicsObject::BlendColor(COLORREF rgbTop, COLORREF rgbBottom, int alpha, COLORREF *result)
+{
+ if (NULL == result) return E_POINTER;
+ *result = BlendColors(rgbTop, rgbBottom, alpha);
+ return S_OK;
+}
+
+HRESULT GraphicsObject::Colorize(BYTE *pixels, long cx, long cy, WORD bpp, COLORREF rgbBk, COLORREF rgbFg, BOOL removeAlpha)
+{
+ BOOL result = Image_Colorize(pixels, cx, cy, bpp, rgbBk, rgbFg, removeAlpha);
+ return (FALSE != result) ? S_OK : S_FALSE;
+}
+
+HRESULT GraphicsObject::BlendOnColor(HBITMAP hbmp, RECT *prcPart, BOOL premult, COLORREF rgb)
+{
+ BOOL result = Image_BlendOnColor(hbmp, prcPart, premult, rgb);
+ return (FALSE != result) ? S_OK : S_FALSE;
+}
+
+HRESULT GraphicsObject::BlendOnColor2(BYTE *pixels, int bitmapCX, int bitmapCY, long x, long y, long cx, long cy, WORD bpp, BOOL premult, COLORREF rgb)
+{
+ BOOL result = Image_BlendOnColorEx(pixels, bitmapCX, bitmapCY, x, y, cx, cy, bpp, premult, rgb);
+ return (FALSE != result) ? S_OK : S_FALSE;
+}
+
+HRESULT GraphicsObject::Premultiply(BYTE *pixels, long cx, long cy)
+{
+ BOOL result = Image_Premultiply(pixels, cx, cy);
+ return (FALSE != result) ? S_OK : S_FALSE;
+}
+
+HRESULT GraphicsObject::AlphaBlend(HDC hdcDest, const RECT *rectDest, HDC hdcSrc, const RECT *rectSrc, BLENDFUNCTION blendFunction)
+{
+ if (NULL == rectDest || NULL == rectSrc)
+ return E_INVALIDARG;
+
+ BOOL result = Image_AlphaBlend(hdcDest, rectDest->left, rectDest->top, rectDest->right, rectDest->bottom, hdcSrc, rectSrc->left, rectSrc->top, rectSrc->right, rectSrc->bottom, blendFunction);
+ return (FALSE != result) ? S_OK : S_FALSE;
+}
+
+HRESULT GraphicsObject::AnimateRotation(HDC hdc, HBITMAP bitmapFrame, int frameCount, COLORREF rgbBk, BOOL fKeepSize, HBITMAP *result)
+{
+ if (NULL == result) return E_POINTER;
+ *result = Image_AnimateRotation(hdc, bitmapFrame, frameCount, rgbBk, fKeepSize);
+ if (NULL == *result) return E_FAIL;
+ return S_OK;
+}
+
+#define CBCLASS GraphicsObject
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_GETDISTANCE, GetDistance)
+CB(API_GETDARKER, GetDarker)
+CB(API_BLENDCOLOR, BlendColor)
+CB(API_COLORIZE, Colorize)
+CB(API_BLENDONCOLOR, BlendOnColor)
+CB(API_BLENDONCOLOR2, BlendOnColor2)
+CB(API_PREMULTIPLY, Premultiply)
+CB(API_ALPHABLEND, AlphaBlend)
+CB(API_ANIMATEROTATION, AnimateRotation)
+END_DISPATCH;
+#undef CBCLASS
diff --git a/Src/omBrowser/graphicsObject.h b/Src/omBrowser/graphicsObject.h
new file mode 100644
index 00000000..9ce94cf2
--- /dev/null
+++ b/Src/omBrowser/graphicsObject.h
@@ -0,0 +1,45 @@
+#ifndef NULLSOFT_WINAMP_UTILITY_GRAPHICS_OBJECT_HEADER
+#define NULLSOFT_WINAMP_UTILITY_GRAPHICS_OBJECT_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_omgraphics.h"
+
+
+class GraphicsObject : public ifc_omgraphics
+{
+protected:
+ GraphicsObject();
+ ~GraphicsObject();
+
+public:
+ static HRESULT CreateInstance(GraphicsObject **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_omgraphics */
+ HRESULT GetDistance(COLORREF rgb1, COLORREF rgb2, int *distance);
+ HRESULT GetDarker(COLORREF rgb1, COLORREF rgb2, COLORREF *result);
+ HRESULT BlendColor(COLORREF rgbTop, COLORREF rgbBottom, int alpha, COLORREF *result);
+ HRESULT Colorize(BYTE *pixels, long cx, long cy, WORD bpp, COLORREF rgbBk, COLORREF rgbFg, BOOL removeAlpha);
+ HRESULT BlendOnColor(HBITMAP hbmp, RECT *prcPart, BOOL premult, COLORREF rgb);
+ HRESULT BlendOnColor2(BYTE *pixels, int bitmapCX, int bitmapCY, long x, long y, long cx, long cy, WORD bpp, BOOL premult, COLORREF rgb);
+ HRESULT Premultiply(BYTE *pixels, long cx, long cy);
+ HRESULT AlphaBlend(HDC hdcDest, const RECT *rectDest, HDC hdcSrc, const RECT *rectSrc, BLENDFUNCTION blendFunction);
+ HRESULT AnimateRotation(HDC hdc, HBITMAP bitmapFrame, int frameCount, COLORREF rgbBk, BOOL fKeepSize, HBITMAP *result);
+
+protected:
+ size_t ref;
+
+protected:
+ RECVS_DISPATCH;
+};
+
+
+#endif // NULLSOFT_WINAMP_UTILITY_GRAPHICS_OBJECT_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ieversion.cpp b/Src/omBrowser/ieversion.cpp
new file mode 100644
index 00000000..dc4cb9a4
--- /dev/null
+++ b/Src/omBrowser/ieversion.cpp
@@ -0,0 +1,81 @@
+#include "main.h"
+#include "./ieversion.h"
+
+#include <shlwapi.h>
+#include <strsafe.h>
+
+HRESULT MSIE_GetVersionString(LPWSTR pszBuffer, INT cchBufferMax)
+{
+ if (NULL == pszBuffer) return E_INVALIDARG;
+
+ HKEY hKey = NULL;
+ LONG result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Internet Explorer", 0,
+ STANDARD_RIGHTS_READ | KEY_QUERY_VALUE, &hKey);
+
+ if (ERROR_SUCCESS == result)
+ {
+ DWORD cbBuffer = sizeof(WCHAR) * cchBufferMax;
+ result = RegQueryValueEx(hKey, L"svcVersion", NULL, NULL, (BYTE*)pszBuffer, &cbBuffer);
+ if (ERROR_SUCCESS != result
+ || L'\0' == *pszBuffer)
+ {
+ cbBuffer = sizeof(WCHAR) * cchBufferMax;
+ result = RegQueryValueEx(hKey, L"Version", NULL, NULL, (BYTE*)pszBuffer, &cbBuffer);
+ }
+ RegCloseKey(hKey);
+ }
+
+ if (ERROR_SUCCESS != result)
+ {
+ *pszBuffer = L'\0';
+ return HRESULT_FROM_WIN32(result);
+ }
+
+ return S_OK;
+}
+
+HRESULT MSIE_GetVersion(INT *majorOut, INT *minorOut, INT *buildOut, INT *subBuildOut)
+{
+ INT szVersion[4] = { 0, 0, 0, 0};
+ WCHAR szBuffer[64] = {0};
+ HRESULT hr = MSIE_GetVersionString(szBuffer, ARRAYSIZE(szBuffer));
+ if (SUCCEEDED(hr))
+ {
+ INT index = 0;
+ LPWSTR block = szBuffer;
+ LPWSTR cursor = block;
+
+ for(;;)
+ {
+ if (L'\0' == *cursor)
+ {
+ if (block != cursor && FALSE != StrToIntEx(block,STIF_DEFAULT, &szVersion[index]))
+ index++;
+ break;
+ }
+ else if (L'.' == *cursor)
+ {
+ *cursor = L'\0';
+ if (block != cursor && FALSE != StrToIntEx(block,STIF_DEFAULT, &szVersion[index]))
+ {
+ index++;
+ if (index == ARRAYSIZE(szVersion))
+ break; // too many numbers
+ }
+ cursor++;
+ block = cursor;
+ }
+ cursor++;
+ }
+
+ if (index < ARRAYSIZE(szVersion))
+ hr = E_FAIL;
+ }
+
+ if (NULL != majorOut) *majorOut = szVersion[0];
+ if (NULL != minorOut) *minorOut = szVersion[1];
+ if (NULL != buildOut) *buildOut = szVersion[2];
+ if (NULL != subBuildOut) *subBuildOut = szVersion[3];
+
+ return hr;
+} \ No newline at end of file
diff --git a/Src/omBrowser/ieversion.h b/Src/omBrowser/ieversion.h
new file mode 100644
index 00000000..01980c38
--- /dev/null
+++ b/Src/omBrowser/ieversion.h
@@ -0,0 +1,11 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_IEVERSION_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_IEVERSION_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+HRESULT MSIE_GetVersionString(LPWSTR pszBuffer, INT cchBufferMax);
+HRESULT MSIE_GetVersion(INT *majorOut, INT *minorOut, INT *buildOut, INT *subBuildOut);
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_IEVERSION_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_imageloader.h b/Src/omBrowser/ifc_imageloader.h
new file mode 100644
index 00000000..22bcdd4a
--- /dev/null
+++ b/Src/omBrowser/ifc_imageloader.h
@@ -0,0 +1,53 @@
+#ifndef NULLSOFT_WINAMP_OMIMAGELOADER_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMIMAGELOADER_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+class __declspec(novtable) ifc_omimageloader : public Dispatchable
+{
+protected:
+ ifc_omimageloader() {}
+ ~ifc_omimageloader() {}
+
+public:
+ HRESULT LoadData(int *widthOut, int *heightOut, void **dataOut);
+ HRESULT FreeData(void *data);
+
+ HRESULT LoadBitmapEx(HBITMAP *bitmapOut, BITMAPINFOHEADER *headerInfo, void **dataOut);
+ HRESULT LoadBitmap(HBITMAP *bitmapOut, int *widthOut, int *heightOut);
+
+public:
+ DISPATCH_CODES
+ {
+ API_LOADDATA = 10,
+ API_FREEDATA = 20,
+ API_LOADBITMAP = 30,
+ API_LOADBITMAPEX = 40,
+ };
+};
+
+inline HRESULT ifc_omimageloader::LoadData(int *widthOut, int *heightOut, void **dataOut)
+{
+ return _call(API_LOADDATA, (HRESULT)E_NOTIMPL, widthOut, heightOut, dataOut);
+}
+
+inline HRESULT ifc_omimageloader::FreeData(void *data)
+{
+ return _call(API_FREEDATA, (HRESULT)E_NOTIMPL, data);
+}
+
+inline HRESULT ifc_omimageloader::LoadBitmapEx(HBITMAP *bitmapOut, BITMAPINFOHEADER *headerInfo, void **dataOut)
+{
+ return _call(API_LOADBITMAPEX, (HRESULT)E_NOTIMPL, bitmapOut, headerInfo, dataOut, bitmapOut);
+}
+
+inline HRESULT ifc_omimageloader::LoadBitmap(HBITMAP *bitmapOut, int *widthOut, int *heightOut)
+{
+ return _call(API_LOADBITMAP, (HRESULT)E_NOTIMPL, bitmapOut, widthOut, heightOut);
+}
+
+#endif //NULLSOFT_WINAMP_OMIMAGELOADER_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_menucustomizer.h b/Src/omBrowser/ifc_menucustomizer.h
new file mode 100644
index 00000000..50e8cdd7
--- /dev/null
+++ b/Src/omBrowser/ifc_menucustomizer.h
@@ -0,0 +1,60 @@
+#ifndef NULLSOFT_WINAMP_MENU_CUSTOMIZER_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_MENU_CUSTOMIZER_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {780C1929-76FD-4a06-934B-C85CC285A4DE}
+static const GUID IFC_MenuCustomizer =
+{ 0x780c1929, 0x76fd, 0x4a06, { 0x93, 0x4b, 0xc8, 0x5c, 0xc2, 0x85, 0xa4, 0xde } };
+
+
+#include "main.h"
+#include <bfc/dispatch.h>
+
+typedef LPVOID HMLIMGLST;
+
+class __declspec(novtable) ifc_menucustomizer : public Dispatchable
+{
+protected:
+ ifc_menucustomizer() {}
+ ~ifc_menucustomizer() {}
+
+public:
+ HMLIMGLST GetImageList(void);
+ UINT GetSkinStyle(void);
+ HRESULT GetWidth(INT *widthOut);
+ INT CustomDraw(HMENU menuInstance, INT action, HDC hdc, LPARAM param);
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETIMAGELIST = 10,
+ API_GETSKINSTYLE = 20,
+ API_GETWIDTH = 30,
+ API_CUSTOMDRAW = 40,
+ };
+};
+
+inline HMLIMGLST ifc_menucustomizer::GetImageList(void)
+{
+ return _call(API_GETIMAGELIST, (HMLIMGLST)NULL);
+}
+
+inline UINT ifc_menucustomizer::GetSkinStyle(void)
+{
+ return (UINT)_call(API_GETSKINSTYLE, (UINT)/*SMS_USESKINFONT*/0x00000001);
+}
+
+inline HRESULT ifc_menucustomizer::GetWidth(INT *widthOut)
+{
+ return _call(API_GETWIDTH, (HRESULT)E_NOTIMPL, widthOut);
+}
+
+inline INT ifc_menucustomizer::CustomDraw(HMENU menuInstance, INT action, HDC hdc, LPARAM param)
+{
+ return _call(API_CUSTOMDRAW, (INT)FALSE, menuInstance, action, hdc, param);
+}
+
+#endif // NULLSOFT_WINAMP_MENU_CUSTOMIZER_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_mlnavigationcallback.h b/Src/omBrowser/ifc_mlnavigationcallback.h
new file mode 100644
index 00000000..0616337e
--- /dev/null
+++ b/Src/omBrowser/ifc_mlnavigationcallback.h
@@ -0,0 +1,35 @@
+#ifndef NULLSOFT_WINAMP_ML_NAVIGATION_CALLBACK_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_ML_NAVIGATION_CALLBACK_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {9CBB5A7C-CEC9-4f12-9615-49BC7BEFE8CB}
+static const GUID IFC_MlNavigationCallback =
+{ 0x9cbb5a7c, 0xcec9, 0x4f12, { 0x96, 0x15, 0x49, 0xbc, 0x7b, 0xef, 0xe8, 0xcb } };
+
+#include <bfc/dispatch.h>
+
+class __declspec(novtable) ifc_mlnavigationcallback : public Dispatchable
+{
+protected:
+ ifc_mlnavigationcallback() {}
+ ~ifc_mlnavigationcallback() {}
+
+public:
+ void ImageChanged(const wchar_t *name, int index);
+
+public:
+ DISPATCH_CODES
+ {
+ API_IMAGECHANGED = 10,
+ };
+};
+
+inline void ifc_mlnavigationcallback::ImageChanged(const wchar_t *name, int index)
+{
+ _voidcall(API_IMAGECHANGED, name, index);
+}
+
+#endif // NULLSOFT_WINAMP_ML_NAVIGATION_CALLBACK_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_mlnavigationhelper.h b/Src/omBrowser/ifc_mlnavigationhelper.h
new file mode 100644
index 00000000..ef57151f
--- /dev/null
+++ b/Src/omBrowser/ifc_mlnavigationhelper.h
@@ -0,0 +1,76 @@
+#ifndef NULLSOFT_WINAMP_ML_NAVIGATION_HELPER_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_ML_NAVIGATION_HELPER_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+// {816290AB-A249-4b64-A192-C643D0AD68CA}
+static const GUID IFC_MlNavigationHelper =
+{ 0x816290ab, 0xa249, 0x4b64, { 0xa1, 0x92, 0xc6, 0x43, 0xd0, 0xad, 0x68, 0xca } };
+
+class ifc_mlnavigationcallback;
+
+class __declspec(novtable) ifc_mlnavigationhelper : public Dispatchable
+{
+
+protected:
+ ifc_mlnavigationhelper() {}
+ ~ifc_mlnavigationhelper() {}
+
+public:
+ HRESULT GetDefaultIndex(int *index);
+ HRESULT QueryIndex(const wchar_t *name, int *index, BOOL *defaultUsed);
+ HRESULT ReleaseIndex(const wchar_t *name);
+
+ HRESULT RegisterAlias(const wchar_t *name, const wchar_t *address);
+
+ HRESULT RegisterCallback(ifc_mlnavigationcallback *callback, unsigned int *cookie);
+ HRESULT UnregisterCallback(unsigned int cookie);
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETDEFAULTINDEX = 10,
+ API_QUERYINDEX = 20,
+ API_RELEASEINDEX = 30,
+ API_REGISTERALIAS = 40,
+
+ API_REGISTERCALLBACK = 50,
+ API_UNREGISTERCALLBACK = 60,
+ };
+};
+
+inline HRESULT ifc_mlnavigationhelper::GetDefaultIndex(int *index)
+{
+ return _call(API_GETDEFAULTINDEX, (HRESULT)E_NOTIMPL, index);
+}
+
+inline HRESULT ifc_mlnavigationhelper::QueryIndex(const wchar_t *name, int *index, BOOL *defaultUsed)
+{
+ return _call(API_QUERYINDEX, (HRESULT)E_NOTIMPL, name, index, defaultUsed);
+}
+
+inline HRESULT ifc_mlnavigationhelper::ReleaseIndex(const wchar_t *name)
+{
+ return _call(API_RELEASEINDEX, (HRESULT)E_NOTIMPL, name);
+}
+
+inline HRESULT ifc_mlnavigationhelper::RegisterAlias(const wchar_t *name, const wchar_t *address)
+{
+ return _call(API_REGISTERALIAS, (HRESULT)E_NOTIMPL, name, address);
+}
+
+inline HRESULT ifc_mlnavigationhelper::RegisterCallback(ifc_mlnavigationcallback *callback, UINT *cookie)
+{
+ return _call(API_REGISTERCALLBACK, (HRESULT)API_REGISTERCALLBACK, callback, cookie);
+}
+
+inline HRESULT ifc_mlnavigationhelper::UnregisterCallback(UINT cookie)
+{
+ return _call(API_UNREGISTERCALLBACK, (HRESULT)E_NOTIMPL, cookie);
+}
+
+#endif //NULLSOFT_WINAMP_ML_NAVIGATION_HELPER_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_ombrowserclass.h b/Src/omBrowser/ifc_ombrowserclass.h
new file mode 100644
index 00000000..37b63be1
--- /dev/null
+++ b/Src/omBrowser/ifc_ombrowserclass.h
@@ -0,0 +1,66 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_CLASS_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_CLASS_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+// {1B06FE2B-A1E7-43b5-B470-573CDF5D54F9}
+static const GUID IFC_OmBrowserClass =
+{ 0x1b06fe2b, 0xa1e7, 0x43b5, { 0xb4, 0x70, 0x57, 0x3c, 0xdf, 0x5d, 0x54, 0xf9 } };
+
+class ifc_omconfig;
+class ifc_ombrowserregistry;
+
+class __declspec(novtable) ifc_ombrowserclass : public Dispatchable
+{
+protected:
+ ifc_ombrowserclass() {}
+ ~ifc_ombrowserclass() {}
+
+public:
+ HRESULT GetName(wchar_t *pszBuffer, int cchBufferLen);
+ HRESULT IsEqual(const wchar_t *pszName);
+ HRESULT GetConfig(ifc_omconfig **instance);
+ HRESULT GetRegistry(ifc_ombrowserregistry **instance);
+ HRESULT UpdateRegColors(void);
+
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETNAME = 10,
+ API_ISEQUAL = 20,
+ API_GETCONFIG = 30,
+ API_GETREGISTRY = 40,
+ API_UPDATEREGCOLORS = 50,
+ };
+};
+
+inline HRESULT ifc_ombrowserclass::GetName(wchar_t *pszBuffer, int cchBufferLen)
+{
+ return _call(API_GETNAME, (HRESULT)E_NOTIMPL, pszBuffer, cchBufferLen);
+}
+
+inline HRESULT ifc_ombrowserclass::IsEqual(const wchar_t *pszName)
+{
+ return _call(API_ISEQUAL, (HRESULT)E_NOTIMPL, pszName);
+}
+
+inline HRESULT ifc_ombrowserclass::GetConfig(ifc_omconfig **instance)
+{
+ return _call(API_GETCONFIG, (HRESULT)E_NOTIMPL, instance);
+}
+
+inline HRESULT ifc_ombrowserclass::GetRegistry(ifc_ombrowserregistry **instance)
+{
+ return _call(API_GETREGISTRY, (HRESULT)E_NOTIMPL, instance);
+}
+
+inline HRESULT ifc_ombrowserclass::UpdateRegColors(void)
+{
+ return _call(API_UPDATEREGCOLORS, (HRESULT)E_NOTIMPL);
+}
+#endif //NULLSOFT_WINAMP_OMBROWSER_CLASS_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_ombrowserconfig.h b/Src/omBrowser/ifc_ombrowserconfig.h
new file mode 100644
index 00000000..21300df6
--- /dev/null
+++ b/Src/omBrowser/ifc_ombrowserconfig.h
@@ -0,0 +1,72 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_BROWSER_CONFIG_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_BROWSER_CONFIG_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {41660B13-0547-4b8f-934B-A688306F0D4A}
+static const GUID IFC_OmBrowserConfig =
+{ 0x41660b13, 0x547, 0x4b8f, { 0x93, 0x4b, 0xa6, 0x88, 0x30, 0x6f, 0xd, 0x4a } };
+
+#define CFGID_BROWSER_CLIENTID 0 //param = (LPCWSTR)pszClientId
+
+#include <bfc/dispatch.h>
+
+class __declspec(novtable) ifc_ombrowserconfig : public Dispatchable
+{
+protected:
+ ifc_ombrowserconfig() {}
+ ~ifc_ombrowserconfig() {}
+
+public:
+ HRESULT GetClientId(LPWSTR pszBuffer, INT cchBufferMax);
+ HRESULT SetClientId(LPWSTR pszClientId);
+ UINT GetX();
+ HRESULT SetX(UINT x);
+ UINT GetY();
+ HRESULT SetY(UINT y);
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETCLIENTID = 10,
+ API_SETCLIENTID = 20,
+ API_GETX = 30,
+ API_SETX = 40,
+ API_GETY = 50,
+ API_SETY = 60,
+ };
+};
+
+inline HRESULT ifc_ombrowserconfig::GetClientId(LPWSTR pszBuffer, INT cchBufferMax)
+{
+ return _call(API_GETCLIENTID, (HRESULT)E_NOTIMPL, pszBuffer, cchBufferMax);
+}
+
+inline HRESULT ifc_ombrowserconfig::SetClientId(LPWSTR pszClientId)
+{
+ return _call(API_SETCLIENTID, (HRESULT)E_NOTIMPL, pszClientId);
+}
+
+inline UINT ifc_ombrowserconfig::GetX(void)
+{
+ return _call(API_GETX, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_ombrowserconfig::SetX(UINT x)
+{
+ return _call(API_SETX, (HRESULT)E_NOTIMPL, x);
+}
+
+inline UINT ifc_ombrowserconfig::GetY(void)
+{
+ return _call(API_GETY, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_ombrowserconfig::SetY(UINT y)
+{
+ return _call(API_SETY, (HRESULT)E_NOTIMPL, y);
+}
+
+#endif // NULLSOFT_WINAMP_OMBROWSER_BROWSER_CONFIG_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_ombrowserevent.h b/Src/omBrowser/ifc_ombrowserevent.h
new file mode 100644
index 00000000..843fadc5
--- /dev/null
+++ b/Src/omBrowser/ifc_ombrowserevent.h
@@ -0,0 +1,44 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_EVENTHANDLER_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_EVENTHANDLER_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+// {900AD92F-E2B9-4615-B1DB-ACC37FCD676C}
+static const GUID IFC_OmBrowserEvent =
+{ 0x900ad92f, 0xe2b9, 0x4615, { 0xb1, 0xdb, 0xac, 0xc3, 0x7f, 0xcd, 0x67, 0x6c } };
+
+
+class __declspec(novtable) ifc_ombrowserevent : public Dispatchable
+{
+
+protected:
+ ifc_ombrowserevent() {}
+ ~ifc_ombrowserevent() {}
+
+public:
+ void WindowCreate(HWND hwnd, const GUID *windowType);
+ void WindowClose(HWND hwnd, const GUID *windowType);
+
+public:
+ DISPATCH_CODES
+ {
+ API_WINDOWCREATE = 10,
+ API_WINDOWCLOSE = 20,
+ };
+};
+
+inline void ifc_ombrowserevent::WindowCreate(HWND hwnd, const GUID *windowType)
+{
+ _voidcall(API_WINDOWCREATE, hwnd, windowType);
+}
+
+inline void ifc_ombrowserevent::WindowClose(HWND hwnd, const GUID *windowType)
+{
+ _voidcall(API_WINDOWCLOSE, hwnd, windowType);
+}
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_EVENTHANDLER_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_ombrowsereventmngr.h b/Src/omBrowser/ifc_ombrowsereventmngr.h
new file mode 100644
index 00000000..93fb504f
--- /dev/null
+++ b/Src/omBrowser/ifc_ombrowsereventmngr.h
@@ -0,0 +1,61 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_EVENTMANAGER_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_EVENTMANAGER_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+// {EF73F304-7730-4e80-B938-A80B5C971CC5}
+static const GUID IFC_OmBrowserEventManager =
+{ 0xef73f304, 0x7730, 0x4e80, { 0xb9, 0x38, 0xa8, 0xb, 0x5c, 0x97, 0x1c, 0xc5 } };
+
+
+class obj_ombrowser;
+class ifc_ombrowserevent;
+
+class __declspec(novtable) ifc_ombrowsereventmngr : public Dispatchable
+{
+
+protected:
+ ifc_ombrowsereventmngr() {}
+ ~ifc_ombrowsereventmngr() {}
+
+public:
+ HRESULT RegisterHandler(ifc_ombrowserevent *handler);
+ HRESULT UnregisterHandler(ifc_ombrowserevent *handler);
+ HRESULT Signal_WindowCreate(HWND hwnd, const GUID *windowType);
+ HRESULT Signal_WindowClose(HWND hwnd, const GUID *windowType);
+
+public:
+ DISPATCH_CODES
+ {
+ API_REGISTERHANDLER = 10,
+ API_UNREGISTERHANDLER = 20,
+ API_SIGNAL_WINDOWCREATE = 30,
+ API_SIGNAL_WINDOWCLOSE = 40,
+ };
+};
+
+inline HRESULT ifc_ombrowsereventmngr::RegisterHandler(ifc_ombrowserevent *handler)
+{
+ return _call(API_REGISTERHANDLER, (HRESULT)E_NOTIMPL, handler);
+}
+
+inline HRESULT ifc_ombrowsereventmngr::UnregisterHandler(ifc_ombrowserevent *handler)
+{
+ return _call(API_UNREGISTERHANDLER, (HRESULT)E_NOTIMPL, handler);
+}
+
+inline HRESULT ifc_ombrowsereventmngr::Signal_WindowCreate(HWND hwnd, const GUID *windowType)
+{
+ return _call(API_SIGNAL_WINDOWCREATE, (HRESULT)E_NOTIMPL, hwnd, windowType);
+}
+
+inline HRESULT ifc_ombrowsereventmngr::Signal_WindowClose(HWND hwnd, const GUID *windowType)
+{
+ return _call(API_SIGNAL_WINDOWCLOSE, (HRESULT)E_NOTIMPL, hwnd, windowType);
+}
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_EVENTMANAGER_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_ombrowserregistry.h b/Src/omBrowser/ifc_ombrowserregistry.h
new file mode 100644
index 00000000..c7ab0e72
--- /dev/null
+++ b/Src/omBrowser/ifc_ombrowserregistry.h
@@ -0,0 +1,57 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_REGISTRY_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_REGISTRY_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {F6415954-AB16-4283-B530-EE94AB29E968}
+static const GUID IFC_OmBrowserRegistry =
+{ 0xf6415954, 0xab16, 0x4283, { 0xb5, 0x30, 0xee, 0x94, 0xab, 0x29, 0xe9, 0x68 } };
+
+#include <bfc/dispatch.h>
+
+class __declspec(novtable) ifc_ombrowserregistry : public Dispatchable
+{
+protected:
+ ifc_ombrowserregistry() {}
+ ~ifc_ombrowserregistry() {}
+
+public:
+ HRESULT GetPath(LPWSTR pszBuffer, INT cchBufferMax);
+
+ HRESULT Write(void);
+ HRESULT Delete(void);
+ HRESULT UpdateColors(void);
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETPATH = 10,
+ API_WRITE = 20,
+ API_DELETE = 30,
+ API_UPDATECOLORS = 40,
+ };
+};
+
+inline HRESULT ifc_ombrowserregistry::GetPath(LPWSTR pszBuffer, INT cchBufferMax)
+{
+ return _call(API_GETPATH, (HRESULT)E_NOTIMPL, pszBuffer, cchBufferMax);
+}
+
+inline HRESULT ifc_ombrowserregistry::Write(void)
+{
+ return _call(API_WRITE, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_ombrowserregistry::Delete(void)
+{
+ return _call(API_DELETE, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_ombrowserregistry::UpdateColors(void)
+{
+ return _call(API_UPDATECOLORS, (HRESULT)E_NOTIMPL);
+}
+
+#endif // NULLSOFT_WINAMP_OMBROWSER_CONFIG_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_ombrowserwndenum.h b/Src/omBrowser/ifc_ombrowserwndenum.h
new file mode 100644
index 00000000..ad62cbb8
--- /dev/null
+++ b/Src/omBrowser/ifc_ombrowserwndenum.h
@@ -0,0 +1,50 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_WINDOW_ENUMERATOR_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_WINDOW_ENUMERATOR_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {8B184E07-1DC6-4d76-8FB3-A793FF4A062B}
+static const GUID IFC_OmBrowserWindowEnumerator =
+{ 0x8b184e07, 0x1dc6, 0x4d76, { 0x8f, 0xb3, 0xa7, 0x93, 0xff, 0x4a, 0x6, 0x2b } };
+
+#include <bfc/dispatch.h>
+
+class __declspec(novtable) ifc_ombrowserwndenum : public Dispatchable
+{
+
+protected:
+ ifc_ombrowserwndenum() {}
+ ~ifc_ombrowserwndenum() {}
+
+public:
+ HRESULT Next(unsigned long listSize, HWND *elementList, unsigned long *elementCount);
+ HRESULT Reset(void);
+ HRESULT Skip(unsigned long elementCount);
+
+public:
+ DISPATCH_CODES
+ {
+ API_NEXT = 10,
+ API_RESET = 20,
+ API_SKIP = 30,
+ };
+};
+
+inline HRESULT ifc_ombrowserwndenum::Next(unsigned long listSize, HWND *elementList, unsigned long *elementCount)
+{
+ return _call(API_NEXT, (HRESULT)E_NOTIMPL, listSize, elementList, elementCount);
+}
+
+inline HRESULT ifc_ombrowserwndenum::Reset(void)
+{
+ return _call(API_RESET, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_ombrowserwndenum::Skip(unsigned long elementCount)
+{
+ return _call(API_SKIP, (HRESULT)E_NOTIMPL, elementCount);
+}
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_WINDOW_ENUMERATOR_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_ombrowserwndmngr.h b/Src/omBrowser/ifc_ombrowserwndmngr.h
new file mode 100644
index 00000000..e333ae0d
--- /dev/null
+++ b/Src/omBrowser/ifc_ombrowserwndmngr.h
@@ -0,0 +1,51 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_WINDOW_MANAGER_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_WINDOW_MANAGER_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {81E8333B-388F-444e-8233-138E15ACC761}
+static const GUID IFC_OmBrowserWindowManager =
+{ 0x81e8333b, 0x388f, 0x444e, { 0x82, 0x33, 0x13, 0x8e, 0x15, 0xac, 0xc7, 0x61 } };
+
+#include <bfc/dispatch.h>
+
+class ifc_ombrowserwndenum;
+
+class __declspec(novtable) ifc_ombrowserwndmngr : public Dispatchable
+{
+protected:
+ ifc_ombrowserwndmngr() {}
+ ~ifc_ombrowserwndmngr() {}
+
+public:
+ HRESULT RegisterWindow(HWND hwnd, const GUID *windowType);
+ HRESULT UnregisterWindow(HWND hwnd);
+ HRESULT Enumerate(const GUID *windowType, unsigned int *serviceIdFilter, ifc_ombrowserwndenum **enumerator); // serviceIdFilter can be NULL if you want to get all windows
+
+public:
+ DISPATCH_CODES
+ {
+ API_REGISTERWINDOW = 10,
+ API_UNREGISTERWINDOW = 20,
+ API_ENUMERATE = 30,
+ };
+};
+
+inline HRESULT ifc_ombrowserwndmngr::RegisterWindow(HWND hwnd, const GUID *windowType)
+{
+ return _call(API_REGISTERWINDOW, (HRESULT)E_NOTIMPL, hwnd, windowType);
+}
+
+inline HRESULT ifc_ombrowserwndmngr::UnregisterWindow(HWND hwnd)
+{
+ return _call(API_UNREGISTERWINDOW, (HRESULT)E_NOTIMPL, hwnd);
+}
+
+inline HRESULT ifc_ombrowserwndmngr::Enumerate(const GUID *windowType, unsigned int *serviceIdFilter, ifc_ombrowserwndenum **enumerator)
+{
+ return _call(API_ENUMERATE, (HRESULT)E_NOTIMPL, windowType, serviceIdFilter, enumerator);
+}
+
+#endif // NULLSOFT_WINAMP_OMBROWSER_WINDOW_MANAGER_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omcachecallback.h b/Src/omBrowser/ifc_omcachecallback.h
new file mode 100644
index 00000000..9940cf80
--- /dev/null
+++ b/Src/omBrowser/ifc_omcachecallback.h
@@ -0,0 +1,39 @@
+#ifndef NULLSOFT_WINAMP_OMCACHE_CALLBACK_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMCACHE_CALLBACK_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+// {A82E94C9-38BA-44ba-9879-0F3CAFCB3527}
+static const GUID IFC_OmCacheCallback =
+{ 0xa82e94c9, 0x38ba, 0x44ba, { 0x98, 0x79, 0xf, 0x3c, 0xaf, 0xcb, 0x35, 0x27 } };
+
+class ifc_omcacherecord;
+
+class __declspec(novtable) ifc_omcachecallback: public Dispatchable
+{
+
+protected:
+ ifc_omcachecallback() {}
+ ~ifc_omcachecallback() {}
+
+public:
+ void PathChanged(ifc_omcacherecord *record);
+
+
+public:
+ DISPATCH_CODES
+ {
+ API_PATHCHANGED = 10,
+ };
+};
+
+inline void ifc_omcachecallback::PathChanged(ifc_omcacherecord *record)
+{
+ _voidcall(API_PATHCHANGED, record);
+}
+
+#endif //NULLSOFT_WINAMP_OMCACHE_CALLBACK_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omcachegroup.h b/Src/omBrowser/ifc_omcachegroup.h
new file mode 100644
index 00000000..c423581f
--- /dev/null
+++ b/Src/omBrowser/ifc_omcachegroup.h
@@ -0,0 +1,60 @@
+#ifndef NULLSOFT_WINAMP_OMCACHE_GROUP_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMCACHE_GROUP_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+// {3249BCBE-A169-4051-8C36-2E355E63C27B}
+static const GUID IFC_OmCacheGroup =
+{ 0x3249bcbe, 0xa169, 0x4051, { 0x8c, 0x36, 0x2e, 0x35, 0x5e, 0x63, 0xc2, 0x7b } };
+
+class ifc_omcacherecord;
+
+class __declspec(novtable) ifc_omcachegroup: public Dispatchable
+{
+
+protected:
+ ifc_omcachegroup() {}
+ ~ifc_omcachegroup() {}
+
+public:
+ HRESULT GetName(wchar_t *buffer, unsigned int bufferMax);
+
+ HRESULT Find(const wchar_t *name, BOOL registerMissing, ifc_omcacherecord **recordOut, BOOL *created);
+ HRESULT Delete(const wchar_t *name);
+ HRESULT Clear();
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETNAME = 10,
+ API_FIND = 20,
+ API_DELETE = 30,
+ API_CLEAR = 40,
+ };
+};
+
+inline HRESULT ifc_omcachegroup::GetName(wchar_t *buffer, unsigned int bufferMax)
+{
+ return _call(API_GETNAME, (HRESULT)E_NOTIMPL, buffer, bufferMax);
+}
+
+inline HRESULT ifc_omcachegroup::Find(const wchar_t *name, BOOL registerMissing, ifc_omcacherecord **recordOut, BOOL *created)
+{
+ return _call(API_FIND, (HRESULT)E_NOTIMPL, name, registerMissing, recordOut, created);
+}
+
+inline HRESULT ifc_omcachegroup::Delete(const wchar_t *name)
+{
+ return _call(API_DELETE, (HRESULT)E_NOTIMPL, name);
+}
+
+inline HRESULT ifc_omcachegroup::Clear()
+{
+ return _call(API_CLEAR, (HRESULT)E_NOTIMPL);
+}
+
+#endif //NULLSOFT_WINAMP_OMCACHE_GROUP_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omcachemanager.h b/Src/omBrowser/ifc_omcachemanager.h
new file mode 100644
index 00000000..30defe30
--- /dev/null
+++ b/Src/omBrowser/ifc_omcachemanager.h
@@ -0,0 +1,52 @@
+#ifndef NULLSOFT_WINAMP_OMCACHE_MANAGER_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMCACHE_MANAGER_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+// {95673D91-A7D3-4797-A599-2CE0E4CD2A20}
+static const GUID IFC_OmCacheManager =
+{ 0x95673d91, 0xa7d3, 0x4797, { 0xa5, 0x99, 0x2c, 0xe0, 0xe4, 0xcd, 0x2a, 0x20 } };
+
+class ifc_omcachegroup;
+
+class __declspec(novtable) ifc_omcachemanager: public Dispatchable
+{
+
+protected:
+ ifc_omcachemanager() {}
+ ~ifc_omcachemanager() {}
+
+public:
+ HRESULT Find(const wchar_t *group, BOOL registerMissing, ifc_omcachegroup **groupOut, BOOL *created);
+ HRESULT Delete(const wchar_t *group);
+ HRESULT Clear();
+
+public:
+ DISPATCH_CODES
+ {
+ API_FIND = 10,
+ API_DELETE = 20,
+ API_CLEAR = 30,
+ };
+};
+
+inline HRESULT ifc_omcachemanager::Find(const wchar_t *group, BOOL registerMissing, ifc_omcachegroup **groupOut, BOOL *created)
+{
+ return _call(API_FIND, (HRESULT)E_NOTIMPL, group, registerMissing, groupOut, created);
+}
+
+inline HRESULT ifc_omcachemanager::Delete(const wchar_t *group)
+{
+ return _call(API_DELETE, (HRESULT)E_NOTIMPL, group);
+}
+
+inline HRESULT ifc_omcachemanager::Clear()
+{
+ return _call(API_CLEAR, (HRESULT)E_NOTIMPL);
+}
+
+#endif //NULLSOFT_WINAMP_OMCACHE_MANAGER_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omcacherecord.h b/Src/omBrowser/ifc_omcacherecord.h
new file mode 100644
index 00000000..c8542f5e
--- /dev/null
+++ b/Src/omBrowser/ifc_omcacherecord.h
@@ -0,0 +1,99 @@
+#ifndef NULLSOFT_WINAMP_OMCACHE_RECORD_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMCACHE_RECORD_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+// {50C4A9E1-0F31-4692-8084-3A7835647EAE}
+static const GUID IFC_OmCacheRecord =
+{ 0x50c4a9e1, 0xf31, 0x4692, { 0x80, 0x84, 0x3a, 0x78, 0x35, 0x64, 0x7e, 0xae } };
+
+class ifc_omcachecallback;
+
+class __declspec(novtable) ifc_omcacherecord : public Dispatchable
+{
+public:
+ typedef enum
+ {
+ flagNoStore = 0x00000001,
+ } Flags;
+
+protected:
+ ifc_omcacherecord() {}
+ ~ifc_omcacherecord() {}
+
+public:
+ HRESULT GetName(wchar_t *buffer, unsigned int bufferMax);
+ HRESULT GetPath(wchar_t *buffer, unsigned int bufferMax);
+ HRESULT SetPath(const wchar_t *path);
+ HRESULT SetFlags(unsigned int flags, unsigned int mask);
+ HRESULT GetFlags(unsigned int *flags);
+
+ HRESULT Download();
+
+ HRESULT RegisterCallback(ifc_omcachecallback *callback);
+ HRESULT UnregisterCallback(ifc_omcachecallback *callback);
+
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETNAME = 10,
+ API_GETPATH = 20,
+ API_SETPATH = 30,
+ API_SETFLAGS = 40,
+ API_GETFLAGS = 50,
+
+ API_DOWNLOAD = 60,
+
+ API_REGISTERCALLBACK = 70,
+ API_UNREGISTERCALLBACK = 80,
+
+ };
+};
+
+inline HRESULT ifc_omcacherecord::GetName(wchar_t *buffer, unsigned int bufferMax)
+{
+ return _call(API_GETNAME, (HRESULT)E_NOTIMPL, buffer, bufferMax);
+}
+
+inline HRESULT ifc_omcacherecord::GetPath(wchar_t *buffer, unsigned int bufferMax)
+{
+ return _call(API_GETPATH, (HRESULT)E_NOTIMPL, buffer, bufferMax);
+}
+
+inline HRESULT ifc_omcacherecord::SetPath(const wchar_t *path)
+{
+ return _call(API_SETPATH, (HRESULT)E_NOTIMPL, path);
+}
+
+inline HRESULT ifc_omcacherecord::SetFlags(unsigned int flags, unsigned int mask)
+{
+ return _call(API_SETFLAGS, (HRESULT)E_NOTIMPL, flags, mask);
+}
+
+inline HRESULT ifc_omcacherecord::GetFlags(unsigned int *flags)
+{
+ return _call(API_GETFLAGS, (HRESULT)E_NOTIMPL, flags);
+}
+
+inline HRESULT ifc_omcacherecord::Download()
+{
+ return _call(API_DOWNLOAD, (HRESULT)E_NOTIMPL);
+}
+
+
+inline HRESULT ifc_omcacherecord::RegisterCallback(ifc_omcachecallback *callback)
+{
+ return _call(API_REGISTERCALLBACK, (HRESULT)E_NOTIMPL, callback);
+}
+
+inline HRESULT ifc_omcacherecord::UnregisterCallback(ifc_omcachecallback *callback)
+{
+ return _call(API_UNREGISTERCALLBACK, (HRESULT)E_NOTIMPL, callback);
+}
+
+#endif //NULLSOFT_WINAMP_OMCACHE_RECORD_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omconfig.h b/Src/omBrowser/ifc_omconfig.h
new file mode 100644
index 00000000..2bd42089
--- /dev/null
+++ b/Src/omBrowser/ifc_omconfig.h
@@ -0,0 +1,94 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_CONFIG_INI_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_CONFIG_INI_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {73661787-0ACC-4692-B6A2-41D14E81A8CE}
+static const GUID IFC_OmConfig =
+{ 0x73661787, 0xacc, 0x4692, { 0xb6, 0xa2, 0x41, 0xd1, 0x4e, 0x81, 0xa8, 0xce } };
+
+#include <bfc/dispatch.h>
+
+class ifc_omconfigcallback;
+
+class __declspec(novtable) ifc_omconfig : public Dispatchable
+{
+protected:
+ ifc_omconfig() {}
+ ~ifc_omconfig() {}
+
+public:
+ HRESULT GetPath(wchar_t *pszBuffer, int cchBufferMax);
+ DWORD ReadString(const wchar_t *lpSectionName, const wchar_t *lpKeyName, const wchar_t *lpDefault, wchar_t *lpReturnedString, DWORD nSize);
+ UINT ReadInt(const wchar_t *lpSectionName, const wchar_t *lpKeyName, int nDefault);
+ BOOL ReadBool(const wchar_t *lpSectionName, const wchar_t *lpKeyName, BOOL bDefault);
+ HRESULT WriteString(const wchar_t *lpSectionName, const wchar_t *lpKeyName, const wchar_t * lpString);
+ HRESULT WriteInt(const wchar_t *lpSectionName, const wchar_t *lpKeyName, int nValue);
+ HRESULT WriteBool(const wchar_t *lpSectionName, const wchar_t *lpKeyName, BOOL bValue);
+
+ HRESULT RegisterCallback(ifc_omconfigcallback *callback, unsigned int *cookie);
+ HRESULT UnregisterCallback(unsigned int cookie);
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETPATH = 10,
+ API_READSTRING = 20,
+ API_READINT = 30,
+ API_READBOOL = 40,
+ API_WRITESTRING = 50,
+ API_WRITEINT = 60,
+ API_WRITEBOOL = 70,
+ API_REGISTERCALLBACK = 80,
+ API_UNREGISTERCALLBACK = 90,
+ };
+};
+
+inline HRESULT ifc_omconfig::GetPath(LPWSTR pszBuffer, INT cchBufferMax)
+{
+ return _call(API_GETPATH, (HRESULT)E_NOTIMPL, pszBuffer, cchBufferMax);
+}
+
+inline DWORD ifc_omconfig::ReadString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpDefault, LPWSTR lpReturnedString, DWORD nSize)
+{
+ return _call(API_READSTRING, (DWORD)0, lpSectionName, lpKeyName, lpDefault, lpReturnedString, nSize);
+}
+
+inline UINT ifc_omconfig::ReadInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, INT nDefault)
+{
+ return _call(API_READINT, (UINT)0, lpSectionName, lpKeyName, nDefault);
+}
+
+inline BOOL ifc_omconfig::ReadBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, BOOL bDefault)
+{
+ return _call(API_READBOOL, (BOOL)FALSE, lpSectionName, lpKeyName, bDefault);
+}
+
+inline HRESULT ifc_omconfig::WriteString(LPCWSTR lpSectionName, LPCWSTR lpKeyName, LPCWSTR lpString)
+{
+ return _call(API_WRITESTRING, (HRESULT)E_NOTIMPL, lpSectionName, lpKeyName, lpString);
+}
+
+inline HRESULT ifc_omconfig::WriteInt(LPCWSTR lpSectionName, LPCWSTR lpKeyName, INT nValue)
+{
+ return _call(API_WRITEINT, (HRESULT)E_NOTIMPL, lpSectionName, lpKeyName, nValue);
+}
+
+inline HRESULT ifc_omconfig::WriteBool(LPCWSTR lpSectionName, LPCWSTR lpKeyName, BOOL bValue)
+{
+ return _call(API_WRITEBOOL, (HRESULT)E_NOTIMPL, lpSectionName, lpKeyName, bValue);
+}
+
+inline HRESULT ifc_omconfig::RegisterCallback(ifc_omconfigcallback *callback, unsigned int *cookie)
+{
+ return _call(API_REGISTERCALLBACK, (HRESULT)API_REGISTERCALLBACK, callback, cookie);
+}
+
+inline HRESULT ifc_omconfig::UnregisterCallback(unsigned int cookie)
+{
+ return _call(API_UNREGISTERCALLBACK, (HRESULT)E_NOTIMPL, cookie);
+}
+
+#endif // NULLSOFT_WINAMP_OMBROWSER_CONFIG_INI_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omconfigcallback.h b/Src/omBrowser/ifc_omconfigcallback.h
new file mode 100644
index 00000000..35752429
--- /dev/null
+++ b/Src/omBrowser/ifc_omconfigcallback.h
@@ -0,0 +1,36 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_CONFIG_CALLBACK_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_CONFIG_CALLBACK_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {FF6CA21B-FF24-4e51-B594-60BD9D9E7C3D}
+static const GUID IFC_OmConfigCallback =
+{ 0xff6ca21b, 0xff24, 0x4e51, { 0xb5, 0x94, 0x60, 0xbd, 0x9d, 0x9e, 0x7c, 0x3d } };
+
+#include <bfc/dispatch.h>
+
+class __declspec(novtable) ifc_omconfigcallback : public Dispatchable
+{
+protected:
+ ifc_omconfigcallback() {}
+ ~ifc_omconfigcallback() {}
+
+public:
+ HRESULT ValueChanged(const GUID *configUid, UINT valueId, ULONG_PTR value);
+
+
+public:
+ DISPATCH_CODES
+ {
+ API_VALUECHANGED = 10,
+ };
+};
+
+inline HRESULT ifc_omconfigcallback::ValueChanged(const GUID *configUid, UINT valueId, ULONG_PTR value)
+{
+ return _call(API_VALUECHANGED, (HRESULT)E_NOTIMPL, configUid, valueId, value);
+}
+
+#endif // NULLSOFT_WINAMP_OMBROWSER_CONFIG_CALLBACK_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omdebugconfig.h b/Src/omBrowser/ifc_omdebugconfig.h
new file mode 100644
index 00000000..0c2fd4b0
--- /dev/null
+++ b/Src/omBrowser/ifc_omdebugconfig.h
@@ -0,0 +1,92 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_DEBUG_CONFIG_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_DEBUG_CONFIG_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {07057926-4DCD-4686-AE81-F74AE36B931B}
+static const GUID IFC_OmDebugConfig =
+{ 0x7057926, 0x4dcd, 0x4686, { 0xae, 0x81, 0xf7, 0x4a, 0xe3, 0x6b, 0x93, 0x1b } };
+
+#define CFGID_DEBUG_FILTERMENU 0 // param = (ULONG_PTR)(BOOL)fFilter
+#define CFGID_DEBUG_SCRIPTERROR 1 // param = (ULONG_PTR)(BOOL)fShow
+#define CFGID_DEBUG_SCRIPTDEBUGGER 2 // param = (ULONG_PTR)(BOOL)fShow
+#define CFGID_DEBUG_BROWSERPATH 3 // param = (ULONG_PTR)(LPCWSTR)pszPath
+
+#include <bfc/dispatch.h>
+
+class __declspec(novtable) ifc_omdebugconfig : public Dispatchable
+{
+protected:
+ ifc_omdebugconfig() {}
+ ~ifc_omdebugconfig() {}
+
+public:
+
+ HRESULT GetMenuFilterEnabled(void);
+ HRESULT GetScriptErrorEnabled(void);
+ HRESULT GetScriptDebuggerEnabled(void);
+ HRESULT GetBrowserPath(LPWSTR pszBuffer, INT cchBufferMax);
+
+ HRESULT EnableMenuFilter(BOOL fEnable);
+ HRESULT EnableScriptError(BOOL fEnable);
+ HRESULT EnableScriptDebugger(BOOL fEnable);
+ HRESULT SetBrowserPath(LPCWSTR pszPath);
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETMENUFILTERENABLED = 10,
+ API_GETSCRIPTERRORENABLED = 20,
+ API_GETSCRIPTDEBUGGERENABLED = 30,
+ API_GETBROWSERPATH = 40,
+
+ API_ENABLEMENUFILTER = 110,
+ API_ENABLESCRIPTERROR = 120,
+ API_ENABLESCRIPTDEBUGGER = 130,
+ API_SETBROWSERPATH = 140,
+ };
+};
+
+inline HRESULT ifc_omdebugconfig::GetMenuFilterEnabled(void)
+{
+ return _call(API_GETMENUFILTERENABLED, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_omdebugconfig::GetScriptErrorEnabled(void)
+{
+ return _call(API_GETSCRIPTERRORENABLED, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_omdebugconfig::GetScriptDebuggerEnabled(void)
+{
+ return _call(API_GETSCRIPTDEBUGGERENABLED, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_omdebugconfig::GetBrowserPath(LPWSTR pszBuffer, INT cchBufferMax)
+{
+ return _call(API_GETBROWSERPATH, (HRESULT)E_NOTIMPL, pszBuffer, cchBufferMax);
+}
+
+inline HRESULT ifc_omdebugconfig::EnableMenuFilter(BOOL fEnable)
+{
+ return _call(API_ENABLEMENUFILTER, (HRESULT)E_NOTIMPL, fEnable);
+}
+
+inline HRESULT ifc_omdebugconfig::EnableScriptError(BOOL fEnable)
+{
+ return _call(API_ENABLESCRIPTERROR, (HRESULT)E_NOTIMPL, fEnable);
+}
+
+inline HRESULT ifc_omdebugconfig::EnableScriptDebugger(BOOL fEnable)
+{
+ return _call(API_ENABLESCRIPTDEBUGGER, (HRESULT)E_NOTIMPL, fEnable);
+}
+
+inline HRESULT ifc_omdebugconfig::SetBrowserPath(LPCWSTR pszPath)
+{
+ return _call(API_SETBROWSERPATH, (HRESULT)E_NOTIMPL, pszPath);
+}
+
+#endif // NULLSOFT_WINAMP_OMBROWSER_DEBUG_CONFIG_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omfilestorage.h b/Src/omBrowser/ifc_omfilestorage.h
new file mode 100644
index 00000000..a0b2e849
--- /dev/null
+++ b/Src/omBrowser/ifc_omfilestorage.h
@@ -0,0 +1,45 @@
+#ifndef NULLSOFT_WINAMP_OMSTORAGETYPE_FILE_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSTORAGETYPE_FILE_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {E49678EB-9DA4-43c3-8A80-18AA5EE369BF}
+static const GUID STID_OmFileStorage =
+{ 0xe49678eb, 0x9da4, 0x43c3, { 0x8a, 0x80, 0x18, 0xaa, 0x5e, 0xe3, 0x69, 0xbf } };
+#define IFC_OmFileStorage STID_OmFileStorage
+
+// {E6D3D527-4721-4fb6-BAB2-304D17C549B2}
+static const GUID SUID_OmStorageIni =
+{ 0xe6d3d527, 0x4721, 0x4fb6, { 0xba, 0xb2, 0x30, 0x4d, 0x17, 0xc5, 0x49, 0xb2 } };
+
+// {0F356A24-114D-4582-9005-A59E08B3164A}
+static const GUID SUID_OmStorageXml =
+{ 0xf356a24, 0x114d, 0x4582, { 0x90, 0x5, 0xa5, 0x9e, 0x8, 0xb3, 0x16, 0x4a } };
+
+#include <bfc/dispatch.h>
+#include <ifc_omstorage.h>
+
+class __declspec(novtable) ifc_omfilestorage : public Dispatchable
+{
+protected:
+ ifc_omfilestorage() {}
+ ~ifc_omfilestorage() {}
+
+public:
+ HRESULT GetFilter(wchar_t *buffer, unsigned int bufferMax);
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETFILTER = 10,
+ };
+};
+
+inline HRESULT ifc_omfilestorage::GetFilter(wchar_t *buffer, unsigned int bufferMax)
+{
+ return _call(API_GETFILTER, (HRESULT)E_NOTIMPL, buffer, bufferMax);
+}
+
+#endif //NULLSOFT_WINAMP_OMSTORAGETYPE_FILE_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omgraphics.h b/Src/omBrowser/ifc_omgraphics.h
new file mode 100644
index 00000000..fea4ebe6
--- /dev/null
+++ b/Src/omBrowser/ifc_omgraphics.h
@@ -0,0 +1,97 @@
+#ifndef NULLSOFT_WINAMP_OMGRAPHICS_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMGRAPHICS_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+
+
+#include <bfc/dispatch.h>
+
+
+// {0CE26A63-B611-468b-A679-810AAD0FB124}
+static const GUID IFC_OmGrpahics =
+{ 0xce26a63, 0xb611, 0x468b, { 0xa6, 0x79, 0x81, 0xa, 0xad, 0xf, 0xb1, 0x24 } };
+
+class __declspec(novtable) ifc_omgraphics: public Dispatchable
+{
+
+protected:
+ ifc_omgraphics() {}
+ ~ifc_omgraphics() {}
+
+public:
+ HRESULT GetDistance(COLORREF rgb1, COLORREF rgb2, int *distance);
+ HRESULT GetDarker(COLORREF rgb1, COLORREF rgb2, COLORREF *result);
+ HRESULT BlendColor(COLORREF rgbTop, COLORREF rgbBottom, int alpha, COLORREF *result);
+
+ HRESULT Colorize(BYTE *pixels, long cx, long cy, WORD bpp, COLORREF rgbBk, COLORREF rgbFg, BOOL removeAlpha);
+ HRESULT BlendOnColor(HBITMAP hbmp, RECT *prcPart, BOOL premult, COLORREF rgb);
+ HRESULT BlendOnColor2(BYTE *pixels, int bitmapCX, int bitmapCY, long x, long y, long cx, long cy, WORD bpp, BOOL premult, COLORREF rgb);
+ HRESULT Premultiply(BYTE *pixels, long cx, long cy);
+ HRESULT AlphaBlend(HDC hdcDest, const RECT *rectDest, HDC hdcSrc, const RECT *rectSrc, BLENDFUNCTION blendFunction);
+ HRESULT AnimateRotation(HDC hdc, HBITMAP bitmapFrame, int frameCount, COLORREF rgbBk, BOOL fKeepSize, HBITMAP *result);
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETDISTANCE = 10,
+ API_GETDARKER = 20,
+ API_BLENDCOLOR = 30,
+ API_COLORIZE = 40,
+ API_BLENDONCOLOR = 50,
+ API_BLENDONCOLOR2 = 60,
+ API_PREMULTIPLY = 70,
+ API_ALPHABLEND = 80,
+ API_ANIMATEROTATION = 90,
+ };
+};
+
+inline HRESULT ifc_omgraphics::GetDistance(COLORREF rgb1, COLORREF rgb2, int *distance)
+{
+ return _call(API_GETDISTANCE, (HRESULT)E_NOTIMPL, rgb1, rgb2, distance);
+}
+
+inline HRESULT ifc_omgraphics::GetDarker(COLORREF rgb1, COLORREF rgb2, COLORREF *result)
+{
+ return _call(API_GETDARKER, (HRESULT)E_NOTIMPL, rgb1, rgb2, result);
+}
+
+inline HRESULT ifc_omgraphics::BlendColor(COLORREF rgbTop, COLORREF rgbBottom, int alpha, COLORREF *result)
+{
+ return _call(API_BLENDCOLOR, (HRESULT)E_NOTIMPL, rgbTop, rgbBottom, alpha, result);
+}
+
+inline HRESULT ifc_omgraphics::Colorize(BYTE *pixels, long cx, long cy, WORD bpp, COLORREF rgbBk, COLORREF rgbFg, BOOL removeAlpha)
+{
+ return _call(API_COLORIZE, (HRESULT)E_NOTIMPL, pixels, cx, cy, bpp, rgbBk, rgbFg, removeAlpha);
+}
+
+inline HRESULT ifc_omgraphics::BlendOnColor(HBITMAP hbmp, RECT *prcPart, BOOL premult, COLORREF rgb)
+{
+ return _call(API_BLENDONCOLOR, (HRESULT)E_NOTIMPL, hbmp, prcPart, premult, rgb);
+}
+
+inline HRESULT ifc_omgraphics::BlendOnColor2(BYTE *pixels, int bitmapCX, int bitmapCY, long x, long y, long cx, long cy, WORD bpp, BOOL premult, COLORREF rgb)
+{
+ return _call(API_BLENDONCOLOR2, (HRESULT)E_NOTIMPL, pixels, bitmapCX, bitmapCY, x, y, cx, cy, bpp, premult, rgb);
+}
+
+inline HRESULT ifc_omgraphics::Premultiply(BYTE *pixels, long cx, long cy)
+{
+ return _call(API_PREMULTIPLY, (HRESULT)E_NOTIMPL, pixels, cx, cy);
+}
+
+inline HRESULT ifc_omgraphics::AlphaBlend(HDC hdcDest, const RECT *rectDest, HDC hdcSrc, const RECT *rectSrc, BLENDFUNCTION blendFunction)
+{
+ return _call(API_ALPHABLEND, (HRESULT)E_NOTIMPL, hdcDest, rectDest, hdcSrc, rectSrc, blendFunction);
+}
+
+inline HRESULT ifc_omgraphics::AnimateRotation(HDC hdc, HBITMAP bitmapFrame, int frameCount, COLORREF rgBk, BOOL fKeepSize, HBITMAP *result)
+{
+ return _call(API_ANIMATEROTATION, (HRESULT)E_NOTIMPL, bitmapFrame, frameCount, rgBk, fKeepSize, result);
+}
+
+
+#endif //NULLSOFT_WINAMP_OMGRAPHICS_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omservice.h b/Src/omBrowser/ifc_omservice.h
new file mode 100644
index 00000000..c3bfec2a
--- /dev/null
+++ b/Src/omBrowser/ifc_omservice.h
@@ -0,0 +1,135 @@
+#ifndef NULLSOFT_WINAMP_OMSERVICE_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSERVICE_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+
+// {2999A8B2-7780-4542-9257-02D4E89310B8}
+static const GUID IFC_OmService =
+{ 0x2999a8b2, 0x7780, 0x4542, { 0x92, 0x57, 0x2, 0xd4, 0xe8, 0x93, 0x10, 0xb8 } };
+
+
+interface IDispatch;
+class ifc_omservicehost;
+
+#define OMSVC_E_INSUFFICIENT_BUFFER MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_INSUFFICIENT_BUFFER) //same as STRSAFE_E_INSUFFICIENT_BUFFER
+
+
+// supports AddRef(), Release(), QueryInterface()
+class __declspec(novtable) ifc_omservice : public Dispatchable
+{
+public:
+ typedef enum
+ {
+ RuntimeFlagsMask = 0xFFFF0000,
+ } FlagsMask;
+
+protected:
+ ifc_omservice() {}
+ ~ifc_omservice() {}
+
+public:
+ unsigned int GetId();
+ HRESULT GetName(wchar_t *pszBuffer, unsigned int cchBufferMax);
+ HRESULT GetUrl(wchar_t *pszBuffer, unsigned int cchBufferMax);
+ HRESULT GetUrlDirect(wchar_t *pszBuffer, unsigned int cchBufferMax);
+ HRESULT GetIcon(wchar_t *pszBuffer, unsigned int cchBufferMax);
+ HRESULT GetExternal(IDispatch **ppDispatch);
+ HRESULT GetRating(unsigned int *rating);
+ HRESULT GetVersion(unsigned int *version);
+ HRESULT GetFlags(unsigned int *flags);
+ HRESULT SetAddress(const wchar_t *pszAddress);
+ HRESULT GetAddress(wchar_t *pszBuffer, unsigned int cchBufferMax);
+ HRESULT GetGeneration(unsigned int *generation);
+ HRESULT UpdateFlags(unsigned int flags);
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETID = 10,
+ API_GETNAME = 20,
+ API_GETURL = 30,
+ API_GETICON = 40,
+ API_GETEXTERNAL = 50,
+ API_GETRATING = 60,
+ API_GETVERSION = 70,
+ API_GETFLAGS = 80,
+ API_SETADDRESS = 90,
+ API_GETADDRESS = 100,
+ API_GETGENERATION = 110,
+ API_GETURLDIRECT = 120,
+ API_UPDATEFLAGS = 130,
+ };
+};
+
+
+inline unsigned int ifc_omservice::GetId()
+{
+ return _call(API_GETID, 0);
+}
+
+inline HRESULT ifc_omservice::GetName(wchar_t *pszBuffer, unsigned int cchBufferMax)
+{
+ return _call(API_GETNAME, (HRESULT)E_NOTIMPL, pszBuffer, cchBufferMax);
+}
+
+inline HRESULT ifc_omservice::GetUrl(wchar_t *pszBuffer, unsigned int cchBufferMax)
+{
+ return _call(API_GETURL, E_NOTIMPL, pszBuffer, cchBufferMax);
+}
+
+inline HRESULT ifc_omservice::GetUrlDirect(wchar_t *pszBuffer, unsigned int cchBufferMax)
+{
+ return _call(API_GETURLDIRECT, E_NOTIMPL, pszBuffer, cchBufferMax);
+}
+
+inline HRESULT ifc_omservice::GetIcon(wchar_t *pszBuffer, unsigned int cchBufferMax)
+{
+ return _call(API_GETICON, (HRESULT)E_NOTIMPL, pszBuffer, cchBufferMax);
+}
+
+inline HRESULT ifc_omservice::GetExternal(IDispatch **ppDispatch)
+{
+ return _call(API_GETEXTERNAL, (HRESULT)E_NOTIMPL, ppDispatch);
+}
+
+inline HRESULT ifc_omservice::GetRating(unsigned int *rating)
+{
+ return _call(API_GETRATING, (HRESULT)E_NOTIMPL, rating);
+}
+
+inline HRESULT ifc_omservice::GetVersion(unsigned int *version)
+{
+ return _call(API_GETVERSION, (HRESULT)E_NOTIMPL, version);
+}
+
+inline HRESULT ifc_omservice::GetFlags(unsigned int *flags)
+{
+ return _call(API_GETFLAGS, (HRESULT)E_NOTIMPL, flags);
+}
+
+inline HRESULT ifc_omservice::SetAddress(const wchar_t *pszAddress)
+{
+ return _call(API_SETADDRESS, (HRESULT)E_NOTIMPL, pszAddress);
+}
+
+inline HRESULT ifc_omservice::GetAddress(wchar_t *pszBuffer, unsigned int cchBufferMax)
+{
+ return _call(API_GETADDRESS, (HRESULT)E_NOTIMPL, pszBuffer, cchBufferMax);
+}
+
+inline HRESULT ifc_omservice::GetGeneration(unsigned int *generation)
+{
+ return _call(API_GETGENERATION, (HRESULT)E_NOTIMPL, generation);
+}
+
+inline HRESULT ifc_omservice::UpdateFlags(unsigned int flags)
+{
+ return _call(API_UPDATEFLAGS, (HRESULT)E_NOTIMPL, flags);
+}
+
+#endif //NULLSOFT_WINAMP_OMSERVICE_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omservicecommand.h b/Src/omBrowser/ifc_omservicecommand.h
new file mode 100644
index 00000000..c9c1e42a
--- /dev/null
+++ b/Src/omBrowser/ifc_omservicecommand.h
@@ -0,0 +1,81 @@
+#ifndef NULLSOFT_WINAMP_OMSERVICE_COMMAND_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSERVICE_COMMAND_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+// {CA77030B-DF0F-4610-B01E-4A406A2FCD67}
+static const GUID IFC_OmServiceCommand =
+{ 0xca77030b, 0xdf0f, 0x4610, { 0xb0, 0x1e, 0x4a, 0x40, 0x6a, 0x2f, 0xcd, 0x67 } };
+
+// {8E4F3281-37CA-4cbe-8753-BA7531690D07}
+static const GUID CMDGROUP_SERVICE =
+{ 0x8e4f3281, 0x37ca, 0x4cbe, { 0x87, 0x53, 0xba, 0x75, 0x31, 0x69, 0xd, 0x7 } };
+#define SVCCOMMAND_SHOWINFO 1
+#define SVCCOMMAND_REPORT 2
+#define SVCCOMMAND_UNSUBSCRIBE 3
+#define SVCCOMMAND_RATE 4 // commandArg = (UINT)ratingValue
+#define SVCCOMMAND_BLOCKNAV 5 //used with query state
+
+// {FA32FE7D-848D-4813-8BDE-27E19CC835B5}
+static const GUID CMDGROUP_NAVIGATION =
+{ 0xfa32fe7d, 0x848d, 0x4813, { 0x8b, 0xde, 0x27, 0xe1, 0x9c, 0xc8, 0x35, 0xb5 } };
+#define NAVCOMMAND_BACKFORWARD 1 // arg = FALSE - backward, arg = TRUE - rofward
+#define NAVCOMMAND_HISTORY 2
+#define NAVCOMMAND_HOME 3
+#define NAVCOMMAND_REFRESH 4 // arg = TRUE - full refresh
+#define NAVCOMMAND_STOP 5
+
+
+// {C04A2400-8D0D-4b3c-9271-0E042AF8C363}
+static const GUID CMDGROUP_WINDOW =
+{ 0xc04a2400, 0x8d0d, 0x4b3c, { 0x92, 0x71, 0xe, 0x4, 0x2a, 0xf8, 0xc3, 0x63 } };
+#define WNDCOMMAND_FULLSCREEN 1 //
+#define WNDCOMMAND_CLOSE 2 //
+
+
+// {6A730612-A7CE-4a45-9898-2F0A807A3BB4}
+static const GUID CMDGROUP_ADDRESSBAR =
+{ 0x6a730612, 0xa7ce, 0x4a45, { 0x98, 0x98, 0x2f, 0xa, 0x80, 0x7a, 0x3b, 0xb4 } };
+#define ADDRESSCOMMAND_EXECUTE 1 // arg = address string
+#define ADDRESSCOMMAND_VISIBLE 2 // used to check state
+#define ADDRESSCOMMAND_READONLY 3 // used to check state
+
+// QueryStatus() return values
+#define CMDSTATE_ENABLED S_OK
+#define CMDSTATE_DISABLED S_FALSE
+#define CMDSTATE_UNKNOWN E_NOINTERFACE
+
+class __declspec(novtable) ifc_omservicecommand : public Dispatchable
+{
+
+protected:
+ ifc_omservicecommand() {}
+ ~ifc_omservicecommand() {}
+
+public:
+ HRESULT QueryState(HWND hBrowser, const GUID *commandGroup, unsigned int commandId); // return CMDSTATE_XXX or E_NOTIMPL if you ok with default
+ HRESULT Exec(HWND hBrowser, const GUID *commandGroup, unsigned int commandId, ULONG_PTR commandArg); // return SUCCEEDED() if command handled
+
+public:
+ DISPATCH_CODES
+ {
+ API_QUERYSTATE = 10,
+ API_EXEC = 20,
+ };
+};
+
+inline HRESULT ifc_omservicecommand::QueryState(HWND hBrowser, const GUID *commandGroup, unsigned int commandId)
+{
+ return _call(API_QUERYSTATE, (HRESULT)E_NOTIMPL, hBrowser, commandGroup, commandId);
+}
+
+inline HRESULT ifc_omservicecommand::Exec(HWND hBrowser, const GUID *commandGroup, unsigned int commandId, ULONG_PTR commandArg)
+{
+ return _call(API_EXEC, (HRESULT)E_NOTIMPL, hBrowser, commandGroup, commandId, commandArg);
+}
+
+#endif //NULLSOFT_WINAMP_OMSERVICE_COMMAND_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omservicecopier.h b/Src/omBrowser/ifc_omservicecopier.h
new file mode 100644
index 00000000..2d65b67d
--- /dev/null
+++ b/Src/omBrowser/ifc_omservicecopier.h
@@ -0,0 +1,40 @@
+#ifndef NULLSOFT_WINAMP_OMSERVICE_COPIER_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSERVICE_COPIER_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+// {24E24C55-0A9D-4c54-9589-95FE07FC1FB2}
+static const GUID IFC_OmServiceCopier =
+{ 0x24e24c55, 0xa9d, 0x4c54, { 0x95, 0x89, 0x95, 0xfe, 0x7, 0xfc, 0x1f, 0xb2 } };
+
+
+class ifc_omservice;
+
+// supports AddRef(), Release(), QueryInterface()
+class __declspec(novtable) ifc_omservicecopier: public Dispatchable
+{
+protected:
+ ifc_omservicecopier() {}
+ ~ifc_omservicecopier() {}
+
+public:
+ HRESULT CopyTo(ifc_omservice *service, unsigned int *modifiedFlags);
+
+public:
+ DISPATCH_CODES
+ {
+ API_COPYTO = 10,
+ };
+};
+
+
+inline HRESULT ifc_omservicecopier::CopyTo(ifc_omservice *service, unsigned int *modifiedFlags)
+{
+ return _call(API_COPYTO, (HRESULT)E_NOTIMPL, service, modifiedFlags);
+}
+
+#endif //NULLSOFT_WINAMP_OMSERVICE_COPIER_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omservicedetails.h b/Src/omBrowser/ifc_omservicedetails.h
new file mode 100644
index 00000000..050ab383
--- /dev/null
+++ b/Src/omBrowser/ifc_omservicedetails.h
@@ -0,0 +1,78 @@
+#ifndef NULLSOFT_WINAMP_OMSERVICE_DETAILS_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSERVICE_DETAILS_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {74C85447-B11A-47ea-95CB-B2ED54E8029E}
+static const GUID IFC_OmServiceDetails =
+{ 0x74c85447, 0xb11a, 0x47ea, { 0x95, 0xcb, 0xb2, 0xed, 0x54, 0xe8, 0x2, 0x9e } };
+
+#include <bfc/dispatch.h>
+
+class __declspec(novtable) ifc_omservicedetails : public Dispatchable
+{
+protected:
+ ifc_omservicedetails() {}
+ ~ifc_omservicedetails() {}
+
+public:
+ HRESULT GetDescription(wchar_t *pszBuffer, unsigned int cchBufferMax);
+ HRESULT GetAuthorFirst(wchar_t *pszBuffer, unsigned int cchBufferMax);
+ HRESULT GetAuthorLast(wchar_t *pszBuffer, unsigned int cchBufferMax);
+ HRESULT GetUpdated(wchar_t *pszBuffer, unsigned int cchBufferMax);
+ HRESULT GetPublished(wchar_t *pszBuffer, unsigned int cchBufferMax);
+ HRESULT GetThumbnail(wchar_t *pszBuffer, unsigned int cchBufferMax);
+ HRESULT GetScreenshot(wchar_t *pszBuffer, unsigned int cchBufferMax);
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETDESCRIPTION = 10,
+ API_GETAUTHORFIRST = 20,
+ API_GETAUTHORLAST = 30,
+ API_GETUPDATED = 40,
+ API_GETPUBLISHED = 50,
+ API_GETTHUMBNAIL = 60,
+ API_GETSCREENSHOT = 70,
+ };
+};
+
+
+inline HRESULT ifc_omservicedetails::GetDescription(wchar_t *pszBuffer, unsigned int cchBufferMax)
+{
+ return _call(API_GETDESCRIPTION, E_NOTIMPL, pszBuffer, cchBufferMax);
+}
+
+inline HRESULT ifc_omservicedetails::GetAuthorFirst(wchar_t *pszBuffer, unsigned int cchBufferMax)
+{
+ return _call(API_GETAUTHORFIRST, E_NOTIMPL, pszBuffer, cchBufferMax);
+}
+
+inline HRESULT ifc_omservicedetails::GetAuthorLast(wchar_t *pszBuffer, unsigned int cchBufferMax)
+{
+ return _call(API_GETAUTHORLAST, E_NOTIMPL, pszBuffer, cchBufferMax);
+}
+
+inline HRESULT ifc_omservicedetails::GetUpdated(wchar_t *pszBuffer, unsigned int cchBufferMax)
+{
+ return _call(API_GETUPDATED, E_NOTIMPL, pszBuffer, cchBufferMax);
+}
+
+inline HRESULT ifc_omservicedetails::GetPublished(wchar_t *pszBuffer, unsigned int cchBufferMax)
+{
+ return _call(API_GETPUBLISHED, E_NOTIMPL, pszBuffer, cchBufferMax);
+}
+
+inline HRESULT ifc_omservicedetails::GetThumbnail(wchar_t *pszBuffer, unsigned int cchBufferMax)
+{
+ return _call(API_GETTHUMBNAIL, E_NOTIMPL, pszBuffer, cchBufferMax);
+}
+
+inline HRESULT ifc_omservicedetails::GetScreenshot(wchar_t *pszBuffer, unsigned int cchBufferMax)
+{
+ return _call(API_GETSCREENSHOT, E_NOTIMPL, pszBuffer, cchBufferMax);
+}
+
+#endif //NULLSOFT_WINAMP_OMSERVICE_DETAILS_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omserviceeditor.h b/Src/omBrowser/ifc_omserviceeditor.h
new file mode 100644
index 00000000..3c0ff61b
--- /dev/null
+++ b/Src/omBrowser/ifc_omserviceeditor.h
@@ -0,0 +1,177 @@
+#ifndef NULLSOFT_WINAMP_OMSERVICE_EDITOR_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSERVICE_EDITOR_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {D0EC78E6-3115-4171-BD99-C500CC66DDAC}
+static const GUID IFC_OmServiceEditor =
+{ 0xd0ec78e6, 0x3115, 0x4171, { 0xbd, 0x99, 0xc5, 0x0, 0xcc, 0x66, 0xdd, 0xac } };
+
+#include <bfc/dispatch.h>
+
+class __declspec(novtable) ifc_omserviceeditor : public Dispatchable
+{
+public:
+ typedef enum
+ {
+ modifiedName = 0x00000001,
+ modifiedUrl = 0x00000002,
+ modifiedIcon = 0x00000004,
+ modifiedRating = 0x00000008,
+ modifiedVersion = 0x00000010,
+ modifiedFlags = 0x00000020,
+ modifiedDescription = 0x00000040,
+ modifiedAuthorFirst = 0x00000080,
+ modifiedAuthorLast = 0x00000100,
+ modifiedUpdated = 0x00000200,
+ modifiedPublished = 0x00000400,
+ modifiedThumbnail = 0x00000800,
+ modifiedScreenshot = 0x00001000,
+ modifiedGeneration = 0x00002000,
+ } ModifiedFlags;
+
+protected:
+ ifc_omserviceeditor() {}
+ ~ifc_omserviceeditor() {}
+
+public:
+ HRESULT SetName(const wchar_t *name, BOOL utf8);
+ HRESULT SetUrl(const wchar_t *url, BOOL utf8);
+ HRESULT SetIcon(const wchar_t *imagePath, BOOL utf8);
+ HRESULT SetRating(unsigned int rating);
+ HRESULT SetVersion(unsigned int version);
+ HRESULT SetFlags(unsigned int flags, unsigned int flagMask);
+ HRESULT SetDescription(const wchar_t *description, BOOL utf8);
+ HRESULT SetAuthorFirst(const wchar_t *authorName, BOOL utf8);
+ HRESULT SetAuthorLast(const wchar_t *authorName, BOOL utf8);
+ HRESULT SetUpdated(const wchar_t *date, BOOL utf8);
+ HRESULT SetPublished(const wchar_t *date, BOOL utf8);
+ HRESULT SetThumbnail(const wchar_t *imagePath, BOOL utf8);
+ HRESULT SetScreenshot(const wchar_t *imagePath, BOOL utf8);
+ HRESULT SetGeneration(unsigned int generation);
+
+ HRESULT SetModified(unsigned int modifiedFlag, unsigned int modifiedMask);
+ HRESULT GetModified(unsigned int *modifiedFlags);
+
+ HRESULT BeginUpdate();
+ HRESULT EndUpdate();
+
+public:
+ DISPATCH_CODES
+ {
+ API_SETNAME = 10,
+ API_SETURL = 20,
+ API_SETICON = 30,
+ API_SETRATING = 40,
+ API_SETVERSION = 50,
+ API_SETFLAGS = 60,
+ API_SETDESCRIPTION = 70,
+ API_SETAUTHORFIRST = 80,
+ API_SETAUTHORLAST = 90,
+ API_SETUPDATED = 100,
+ API_SETPUBLISHED = 110,
+ API_SETTHUMBNAIL = 120,
+ API_SETSCREENSHOT = 130,
+ API_SETGENERATION = 140,
+
+ API_SETMODIFIED = 400,
+ API_GETMODIFIED = 410,
+ API_BEGINUPDATE = 420,
+ API_ENDUPDATE = 430,
+ };
+};
+
+
+inline HRESULT ifc_omserviceeditor::SetName(const wchar_t *name, BOOL utf8)
+{
+ return _call(API_SETNAME, (HRESULT)E_NOTIMPL, name, utf8);
+}
+
+inline HRESULT ifc_omserviceeditor::SetUrl(const wchar_t *url, BOOL utf8)
+{
+ return _call(API_SETURL, (HRESULT)E_NOTIMPL, url, utf8);
+}
+
+inline HRESULT ifc_omserviceeditor::SetIcon(const wchar_t *imagePath, BOOL utf8)
+{
+ return _call(API_SETICON, (HRESULT)E_NOTIMPL, imagePath, utf8);
+}
+
+inline HRESULT ifc_omserviceeditor::SetRating(unsigned int rating)
+{
+ return _call(API_SETRATING, (HRESULT)E_NOTIMPL, rating);
+}
+
+inline HRESULT ifc_omserviceeditor::SetVersion(unsigned int version)
+{
+ return _call(API_SETVERSION, (HRESULT)E_NOTIMPL, version);
+}
+
+inline HRESULT ifc_omserviceeditor::SetFlags(unsigned int flags, unsigned int flagMask)
+{
+ return _call(API_SETFLAGS, (HRESULT)E_NOTIMPL, flags, flagMask);
+}
+
+inline HRESULT ifc_omserviceeditor::SetDescription(const wchar_t *description, BOOL utf8)
+{
+ return _call(API_SETDESCRIPTION, (HRESULT)E_NOTIMPL, description, utf8);
+}
+
+inline HRESULT ifc_omserviceeditor::SetAuthorFirst(const wchar_t *authorName, BOOL utf8)
+{
+ return _call(API_SETAUTHORFIRST, (HRESULT)E_NOTIMPL, authorName, utf8);
+}
+
+inline HRESULT ifc_omserviceeditor::SetAuthorLast(const wchar_t *authorName, BOOL utf8)
+{
+ return _call(API_SETAUTHORLAST, (HRESULT)E_NOTIMPL, authorName, utf8);
+}
+
+inline HRESULT ifc_omserviceeditor::SetUpdated(const wchar_t *date, BOOL utf8)
+{
+ return _call(API_SETUPDATED, (HRESULT)E_NOTIMPL, date, utf8);
+}
+
+inline HRESULT ifc_omserviceeditor::SetPublished(const wchar_t *date, BOOL utf8)
+{
+ return _call(API_SETPUBLISHED, (HRESULT)E_NOTIMPL, date, utf8);
+}
+
+inline HRESULT ifc_omserviceeditor::SetThumbnail(const wchar_t *imagePath, BOOL utf8)
+{
+ return _call(API_SETTHUMBNAIL, (HRESULT)E_NOTIMPL, imagePath, utf8);
+}
+
+inline HRESULT ifc_omserviceeditor::SetScreenshot(const wchar_t *imagePath, BOOL utf8)
+{
+ return _call(API_SETSCREENSHOT, (HRESULT)E_NOTIMPL, imagePath, utf8);
+}
+
+inline HRESULT ifc_omserviceeditor::SetModified(unsigned int modifiedFlag, unsigned int modifiedMask)
+{
+ return _call(API_SETMODIFIED, (HRESULT)E_NOTIMPL, modifiedFlag, modifiedMask);
+}
+
+inline HRESULT ifc_omserviceeditor::GetModified(unsigned int *modifiedFlags)
+{
+ return _call(API_GETMODIFIED, (HRESULT)E_NOTIMPL, modifiedFlags);
+}
+
+inline HRESULT ifc_omserviceeditor::BeginUpdate()
+{
+ return _call(API_BEGINUPDATE, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_omserviceeditor::EndUpdate()
+{
+ return _call(API_ENDUPDATE, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_omserviceeditor::SetGeneration(unsigned int generation)
+{
+ return _call(API_SETGENERATION, (HRESULT)E_NOTIMPL, generation);
+}
+
+#endif //NULLSOFT_WINAMP_OMSERVICE_EDITOR_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omserviceenum.h b/Src/omBrowser/ifc_omserviceenum.h
new file mode 100644
index 00000000..6fcad75b
--- /dev/null
+++ b/Src/omBrowser/ifc_omserviceenum.h
@@ -0,0 +1,52 @@
+#ifndef NULLSOFT_WINAMP_OMSERVICE_ENUMERATOR_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSERVICE_ENUMERATOR_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {27E67F83-2E2B-4b5b-A029-2CDDFF28BD41}
+static const GUID IFC_OmServiceEnum =
+{ 0x27e67f83, 0x2e2b, 0x4b5b, { 0xa0, 0x29, 0x2c, 0xdd, 0xff, 0x28, 0xbd, 0x41 } };
+
+
+#include <bfc/dispatch.h>
+class ifc_omservice;
+
+class __declspec(novtable) ifc_omserviceenum : public Dispatchable
+{
+
+protected:
+ ifc_omserviceenum() {}
+ ~ifc_omserviceenum() {}
+
+public:
+ HRESULT Next(unsigned long listSize, ifc_omservice **elementList, unsigned long *elementCount);
+ HRESULT Reset(void);
+ HRESULT Skip(unsigned long elementCount);
+
+public:
+ DISPATCH_CODES
+ {
+ API_NEXT = 10,
+ API_RESET = 20,
+ API_SKIP = 30,
+ };
+};
+
+inline HRESULT ifc_omserviceenum::Next(unsigned long listSize, ifc_omservice **elementList, unsigned long *elementCount)
+{
+ return _call(API_NEXT, (HRESULT)E_NOTIMPL, listSize, elementList, elementCount);
+}
+
+inline HRESULT ifc_omserviceenum::Reset(void)
+{
+ return _call(API_RESET, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_omserviceenum::Skip(unsigned long elementCount)
+{
+ return _call(API_SKIP, (HRESULT)E_NOTIMPL, elementCount);
+}
+
+#endif //NULLSOFT_WINAMP_OMSERVICE_ENUMERATOR_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omserviceevent.h b/Src/omBrowser/ifc_omserviceevent.h
new file mode 100644
index 00000000..8da6d86d
--- /dev/null
+++ b/Src/omBrowser/ifc_omserviceevent.h
@@ -0,0 +1,45 @@
+#ifndef NULLSOFT_WINAMP_OMSERVICE_EVENTHANDLER_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSERVICE_EVENTHANDLER_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+// {82B3DD14-A2B3-4f80-A4E1-C8702E0AF70E}
+static const GUID IFC_OmServiceEvent =
+{ 0x82b3dd14, 0xa2b3, 0x4f80, { 0xa4, 0xe1, 0xc8, 0x70, 0x2e, 0xa, 0xf7, 0xe } };
+
+class ifc_omservice;
+
+class __declspec(novtable) ifc_omserviceevent : public Dispatchable
+{
+
+protected:
+ ifc_omserviceevent() {}
+ ~ifc_omserviceevent() {}
+
+public:
+ void ServiceChange(ifc_omservice *service, unsigned int modifiedFlags);
+ void CommandStateChange(ifc_omservice *service, const GUID *commandGroup, unsigned int commandId);
+
+public:
+ DISPATCH_CODES
+ {
+ API_SERVICECHANGE = 10,
+ API_COMMANDSTATECHANGE = 20,
+ };
+};
+
+inline void ifc_omserviceevent::ServiceChange(ifc_omservice *service, unsigned int modifiedFlags)
+{
+ _voidcall(API_SERVICECHANGE, service, modifiedFlags);
+}
+
+inline void ifc_omserviceevent::CommandStateChange(ifc_omservice *service, const GUID *commandGroup, unsigned int commandId)
+{
+ _voidcall(API_COMMANDSTATECHANGE, service, commandGroup, commandId);
+}
+
+#endif //NULLSOFT_WINAMP_OMSERVICE_EVENTHANDLER_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omserviceeventmngr.h b/Src/omBrowser/ifc_omserviceeventmngr.h
new file mode 100644
index 00000000..2afa4bb8
--- /dev/null
+++ b/Src/omBrowser/ifc_omserviceeventmngr.h
@@ -0,0 +1,62 @@
+#ifndef NULLSOFT_WINAMP_OMSERVICE_EVENTMANAGER_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSERVICE_EVENTMANAGER_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+
+// {2ED54062-1442-4dfb-B0AE-C43846BE4FCE}
+static const GUID IFC_OmServiceEventMngr =
+{ 0x2ed54062, 0x1442, 0x4dfb, { 0xb0, 0xae, 0xc4, 0x38, 0x46, 0xbe, 0x4f, 0xce } };
+
+class ifc_omservice;
+class ifc_omserviceevent;
+
+class __declspec(novtable) ifc_omserviceeventmngr : public Dispatchable
+{
+
+protected:
+ ifc_omserviceeventmngr() {}
+ ~ifc_omserviceeventmngr() {}
+
+public:
+ HRESULT RegisterHandler(ifc_omserviceevent *handler);
+ HRESULT UnregisterHandler(ifc_omserviceevent *handler);
+
+ HRESULT Signal_ServiceChange(unsigned int modifiedFlags);
+ HRESULT Signal_CommandStateChange(const GUID *commandGroup, unsigned int commandId);
+
+public:
+ DISPATCH_CODES
+ {
+ API_REGISTERHANDLER = 10,
+ API_UNREGISTERHANDLER = 20,
+ API_SIGNAL_SERVICECHANGE = 30,
+ API_SIGNAL_COMMANDSTATECHANGE = 40,
+ };
+};
+
+inline HRESULT ifc_omserviceeventmngr::RegisterHandler(ifc_omserviceevent *handler)
+{
+ return _call(API_REGISTERHANDLER, (HRESULT)E_NOTIMPL, handler);
+}
+
+inline HRESULT ifc_omserviceeventmngr::UnregisterHandler(ifc_omserviceevent *handler)
+{
+ return _call(API_UNREGISTERHANDLER, (HRESULT)E_NOTIMPL, handler);
+}
+
+inline HRESULT ifc_omserviceeventmngr::Signal_ServiceChange(unsigned int modifiedFlags)
+{
+ return _call(API_SIGNAL_SERVICECHANGE, (HRESULT)E_NOTIMPL, modifiedFlags);
+}
+
+inline HRESULT ifc_omserviceeventmngr::Signal_CommandStateChange( const GUID *commandGroup, unsigned int commandId)
+{
+ return _call(API_SIGNAL_COMMANDSTATECHANGE, (HRESULT)E_NOTIMPL, commandGroup, commandId);
+}
+
+#endif //NULLSOFT_WINAMP_OMSERVICE_EVENTMANAGER_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omservicehost.h b/Src/omBrowser/ifc_omservicehost.h
new file mode 100644
index 00000000..5d525c02
--- /dev/null
+++ b/Src/omBrowser/ifc_omservicehost.h
@@ -0,0 +1,75 @@
+#ifndef NULLSOFT_WINAMP_OMSERVICE_HOST_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSERVICE_HOST_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+// {75339603-8A3A-490d-84B1-DD493004AAE2}
+static const GUID IFC_OmServiceHost =
+{ 0x75339603, 0x8a3a, 0x490d, { 0x84, 0xb1, 0xdd, 0x49, 0x30, 0x4, 0xaa, 0xe2 } };
+
+interface IDispatch;
+class ifc_omservice;
+
+// supports AddRef(), Release(), QueryInterface()
+class __declspec(novtable) ifc_omservicehost : public Dispatchable
+{
+protected:
+ ifc_omservicehost() {}
+ ~ifc_omservicehost() {}
+
+public:
+ HRESULT GetExternal(ifc_omservice *service, IDispatch **ppDispatch); // ppDispatch probably will be already set with JSAPI according to generation
+ HRESULT GetBasePath(ifc_omservice *service, wchar_t *buffer, unsigned int bufferMax);
+ HRESULT GetDefaultName(ifc_omservice *service, wchar_t *buffer, unsigned int bufferMax);
+ HRESULT GetUrl(ifc_omservice *service, wchar_t *buffer, unsigned int bufferMax); // buffer will be set with ifc_omservice->GetUrl() you can modify it if you want. Return: S_OK on success, E_NOTIMPL - if do not care or E_XXX for errror
+
+ HRESULT QueryCommandState(ifc_omservice *service, HWND hBrowser, const GUID *commandGroup, UINT commandId);
+ HRESULT ExecuteCommand(ifc_omservice *service, HWND hBrowser, const GUID *commandGroup, UINT commandId, ULONG_PTR commandArg);
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETEXTERNAL = 10,
+ API_GETBASEPATH = 20,
+ API_GETDEFAULTNAME = 30,
+ API_QUERYCOMMANDSTATE = 40,
+ API_EXECUTECOMMAND = 50,
+ API_GETURL = 60,
+ };
+};
+
+inline HRESULT ifc_omservicehost::GetExternal(ifc_omservice *service, IDispatch **ppDispatch)
+{
+ return _call(API_GETEXTERNAL, (HRESULT)E_NOTIMPL, service, ppDispatch);
+}
+
+inline HRESULT ifc_omservicehost::GetBasePath(ifc_omservice *service, wchar_t *buffer, unsigned int bufferMax)
+{
+ return _call(API_GETBASEPATH, (HRESULT)E_NOTIMPL, service, buffer, bufferMax);
+}
+
+inline HRESULT ifc_omservicehost::GetDefaultName(ifc_omservice *service, wchar_t *buffer, unsigned int bufferMax)
+{
+ return _call(API_GETDEFAULTNAME, (HRESULT)E_NOTIMPL, service, buffer, bufferMax);
+}
+
+inline HRESULT ifc_omservicehost::QueryCommandState(ifc_omservice *service, HWND hBrowser, const GUID *commandGroup, UINT commandId)
+{
+ return _call(API_QUERYCOMMANDSTATE, (HRESULT)E_NOTIMPL, service, hBrowser, commandGroup, commandId);
+}
+
+inline HRESULT ifc_omservicehost::ExecuteCommand(ifc_omservice *service, HWND hBrowser, const GUID *commandGroup, UINT commandId, ULONG_PTR commandArg)
+{
+ return _call(API_EXECUTECOMMAND, (HRESULT)E_NOTIMPL, service, hBrowser, commandGroup, commandId, commandArg);
+}
+
+inline HRESULT ifc_omservicehost::GetUrl(ifc_omservice *service, wchar_t *buffer, unsigned int bufferMax)
+{
+ return _call(API_GETURL, (HRESULT)E_NOTIMPL, service, buffer, bufferMax);
+}
+
+#endif //NULLSOFT_WINAMP_OMSERVICE_HOST_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omservicehostext.h b/Src/omBrowser/ifc_omservicehostext.h
new file mode 100644
index 00000000..77181039
--- /dev/null
+++ b/Src/omBrowser/ifc_omservicehostext.h
@@ -0,0 +1,44 @@
+#ifndef NULLSOFT_WINAMP_OMSERVICE_HOST_EXTENSION_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSERVICE_HOST_EXTENSION_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+// {0DBA9261-79B5-4803-BB29-6246DE6C92C9}
+static const GUID IFC_OmServiceHostExt =
+{ 0xdba9261, 0x79b5, 0x4803, { 0xbb, 0x29, 0x62, 0x46, 0xde, 0x6c, 0x92, 0xc9 } };
+
+
+// supports AddRef(), Release(), QueryInterface()
+class __declspec(novtable) ifc_omservicehostext : public Dispatchable
+{
+protected:
+ ifc_omservicehostext() {}
+ ~ifc_omservicehostext() {}
+
+public:
+ HRESULT GetHost(ifc_omservicehost **ppHost);
+ HRESULT SetHost(ifc_omservicehost *host);
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETHOST = 10,
+ API_SETHOST = 20,
+ };
+};
+
+inline HRESULT ifc_omservicehostext::GetHost(ifc_omservicehost **ppHost)
+{
+ return _call(API_GETHOST, (HRESULT)E_NOTIMPL, ppHost);
+}
+
+inline HRESULT ifc_omservicehostext::SetHost(ifc_omservicehost *host)
+{
+ return _call(API_SETHOST, (HRESULT)E_NOTIMPL, host);
+}
+
+#endif //NULLSOFT_WINAMP_OMSERVICE_HOST_EXTENSION_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omservicemanager.h b/Src/omBrowser/ifc_omservicemanager.h
new file mode 100644
index 00000000..ba76f600
--- /dev/null
+++ b/Src/omBrowser/ifc_omservicemanager.h
@@ -0,0 +1,73 @@
+#ifndef NULLSOFT_WINAMP_OMSERVICE_MANAGER_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSERVICE_MANAGER_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+// {BB0A9154-6D31-413b-96FB-9466E535E0C4}
+static const GUID IFC_OmServiceManager =
+{ 0xbb0a9154, 0x6d31, 0x413b, { 0x96, 0xfb, 0x94, 0x66, 0xe5, 0x35, 0xe0, 0xc4 } };
+
+class ifc_omservice;
+class ifc_omstorage;
+class ifc_omstorageenumerator;
+class ifc_omservicehost;
+class ifc_omserviceeventmngr;
+
+class __declspec(novtable) ifc_omservicemanager : public Dispatchable
+{
+protected:
+ ifc_omservicemanager() {}
+ ~ifc_omservicemanager() {}
+
+public:
+ HRESULT RegisterStorage(ifc_omstorage *storage);
+ HRESULT UnregisterStorage(const GUID *storageId);
+ HRESULT QueryStorage(const GUID *storageId, ifc_omstorage **storageOut);
+ HRESULT EnumStorage(const GUID *filterType, UINT filterCapabilities, ifc_omstorageenumerator **enumOut);
+
+ HRESULT CreateService(unsigned int serviceId, ifc_omservicehost *host, ifc_omservice **serviceOut);
+
+
+public:
+ DISPATCH_CODES
+ {
+ API_REGISTERSTORAGE = 10,
+ API_UNREGISTERSTORAGE = 20,
+ API_QUERYSTORAGE = 30,
+ API_ENUMSTORAGE = 40,
+
+ API_CREATESERVICE = 100,
+
+ };
+};
+
+inline HRESULT ifc_omservicemanager::RegisterStorage(ifc_omstorage *storage)
+{
+ return _call(API_REGISTERSTORAGE, (HRESULT)E_NOTIMPL, storage);
+}
+
+inline HRESULT ifc_omservicemanager::UnregisterStorage(const GUID *storageId)
+{
+ return _call(API_UNREGISTERSTORAGE, (HRESULT)E_NOTIMPL, storageId);
+}
+
+inline HRESULT ifc_omservicemanager::QueryStorage(const GUID *storageId, ifc_omstorage **storageOut)
+{
+ return _call(API_QUERYSTORAGE, (HRESULT)E_NOTIMPL, storageId, storageOut);
+}
+
+inline HRESULT ifc_omservicemanager::EnumStorage(const GUID *filterType, UINT filterCapabilities, ifc_omstorageenumerator **enumOut)
+{
+ return _call(API_ENUMSTORAGE, (HRESULT)E_NOTIMPL, filterType, filterCapabilities, enumOut);
+}
+
+inline HRESULT ifc_omservicemanager::CreateService(UINT serviceId, ifc_omservicehost *host, ifc_omservice **serviceOut)
+{
+ return _call(API_CREATESERVICE, (HRESULT)E_NOTIMPL, serviceId, host, serviceOut);
+}
+
+#endif //NULLSOFT_WINAMP_OMSERVICE_MANAGER_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omstatusbarconfig.h b/Src/omBrowser/ifc_omstatusbarconfig.h
new file mode 100644
index 00000000..cf9e8473
--- /dev/null
+++ b/Src/omBrowser/ifc_omstatusbarconfig.h
@@ -0,0 +1,46 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_STATUSBAR_CONFIG_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_STATUSBAR_CONFIG_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#define CFGID_STATUSBAR_ENABLED 0 // param = (ULONG_PTR)(BOOL)fEnabled
+
+// {98ABEE7F-06F4-4652-886D-58E1769E2592}
+static const GUID IFC_OmStatusbarConfig =
+{ 0x98abee7f, 0x6f4, 0x4652, { 0x88, 0x6d, 0x58, 0xe1, 0x76, 0x9e, 0x25, 0x92 } };
+
+#include <bfc/dispatch.h>
+
+class __declspec(novtable) ifc_omstatusbarconfig : public Dispatchable
+{
+protected:
+ ifc_omstatusbarconfig() {}
+ ~ifc_omstatusbarconfig() {}
+
+public:
+ HRESULT GetEnabled(void);
+ HRESULT EnableStatusbar(BOOL fEnable);
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETENABLED = 10,
+ API_ENABLESTATUSBAR = 20,
+ };
+};
+
+inline HRESULT ifc_omstatusbarconfig::GetEnabled(void)
+{
+ return _call(API_GETENABLED, (HRESULT)E_NOTIMPL);
+}
+
+
+inline HRESULT ifc_omstatusbarconfig::EnableStatusbar(BOOL fEnable)
+{
+ return _call(API_ENABLESTATUSBAR, (HRESULT)E_NOTIMPL, fEnable);
+}
+
+
+#endif // NULLSOFT_WINAMP_OMBROWSER_STATUSBAR_CONFIG_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omstorage.h b/Src/omBrowser/ifc_omstorage.h
new file mode 100644
index 00000000..b7917c2c
--- /dev/null
+++ b/Src/omBrowser/ifc_omstorage.h
@@ -0,0 +1,131 @@
+#ifndef NULLSOFT_WINAMP_OMSTORAGE_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSTORAGE_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {DEE1FCCD-8FFC-4ed2-8104-323382670BE0}
+static const GUID IFC_OmStorage =
+{ 0xdee1fccd, 0x8ffc, 0x4ed2, { 0x81, 0x4, 0x32, 0x33, 0x82, 0x67, 0xb, 0xe0 } };
+
+#include <ifc_omstorageasync.h>
+#include <bfc/dispatch.h>
+
+class ifc_omservice;
+class ifc_omservicehost;
+class ifc_omserviceenum;
+
+#define OMSTORAGE_E_UNKNOWN_FORMAT MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, ERROR_INVALID_DATA)
+
+class __declspec(novtable) ifc_omstorage : public Dispatchable
+{
+public:
+ typedef enum
+ {
+ capLoad = 0x00000001,
+ capSave = 0x00000002,
+ capDelete = 0x00000004,
+ capReload = 0x00000008,
+ capPublic = 0x00001000,
+ } Capabilities;
+
+ typedef enum
+ {
+ saveModifiedOnly = 0x00000001,
+ saveClearModified = 0x00000002,
+ } SaveFlags;
+
+protected:
+ ifc_omstorage() {}
+ ~ifc_omstorage() {}
+
+public:
+ HRESULT GetId(GUID *storageUid);
+ HRESULT GetType(GUID *storageType);
+ UINT GetCapabilities();
+ HRESULT GetDescription(wchar_t *buffer, unsigned int bufferMax);
+
+ HRESULT Load(const wchar_t *address, ifc_omservicehost *host, ifc_omserviceenum **ppEnum);
+ HRESULT Save(ifc_omservice **serviceList, unsigned long listCount, unsigned int saveFlags, unsigned long *savedCount);
+ HRESULT Delete(ifc_omservice **serviceList, unsigned long listCount, unsigned long *deletedCount);
+ HRESULT Reload(ifc_omservice **serviceList, unsigned long listCount, unsigned long *reloadedCount);
+
+ /* async calls */
+ HRESULT BeginLoad(const wchar_t *address, ifc_omservicehost *host, ifc_omstorageasync::AsyncCallback callback, void *data, ifc_omstorageasync **async);
+ HRESULT EndLoad(ifc_omstorageasync *async, ifc_omserviceenum **ppEnum);
+ HRESULT RequestAbort(ifc_omstorageasync *async, BOOL drop);
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETID = 10,
+ API_GETTYPE = 20,
+ API_GETCAPABILITIES = 30,
+ API_GETDESCRIPTION = 40,
+ API_LOAD = 60,
+ API_SAVE = 70,
+ API_DELETE = 80,
+ API_RELOAD = 90,
+ API_BEGINLOAD = 100,
+ API_ENDLOAD = 110,
+ API_REQUESTABORT = 120,
+ };
+};
+
+inline HRESULT ifc_omstorage::GetId(GUID *storageUid)
+{
+ return _call(API_GETID, (HRESULT)E_NOTIMPL, storageUid);
+}
+
+inline HRESULT ifc_omstorage::GetType(GUID *storageType)
+{
+ return _call(API_GETTYPE, (HRESULT)E_NOTIMPL, storageType);
+}
+
+inline UINT ifc_omstorage::GetCapabilities()
+{
+ return (UINT)_call(API_GETCAPABILITIES, (UINT)0);
+}
+
+inline HRESULT ifc_omstorage::GetDescription(wchar_t *buffer, unsigned int bufferMax)
+{
+ return _call(API_GETDESCRIPTION, (HRESULT)E_NOTIMPL, buffer, bufferMax);
+}
+
+inline HRESULT ifc_omstorage::Load(const wchar_t *address, ifc_omservicehost *host, ifc_omserviceenum **ppEnum)
+{
+ return _call(API_LOAD, (HRESULT)E_NOTIMPL, address, host, ppEnum);
+}
+
+inline HRESULT ifc_omstorage::Save(ifc_omservice **serviceList, unsigned long listCount, unsigned int saveFlags, unsigned long *savedCount)
+{
+ return _call(API_SAVE, (HRESULT)E_NOTIMPL, serviceList, listCount, saveFlags, savedCount);
+}
+
+inline HRESULT ifc_omstorage::Delete(ifc_omservice **serviceList, unsigned long listCount, unsigned long *deletedCount)
+{
+ return _call(API_DELETE, (HRESULT)E_NOTIMPL, serviceList, listCount, deletedCount);
+}
+
+inline HRESULT ifc_omstorage::Reload(ifc_omservice **serviceList, unsigned long listCount, unsigned long *reloadedCount)
+{
+ return _call(API_RELOAD, (HRESULT)E_NOTIMPL, serviceList, listCount, reloadedCount);
+}
+
+inline HRESULT ifc_omstorage::BeginLoad(const wchar_t *address, ifc_omservicehost *host, ifc_omstorageasync::AsyncCallback callback, void *data, ifc_omstorageasync **async)
+{
+ return _call(API_BEGINLOAD, (HRESULT)E_NOTIMPL, address, host, callback, data, async);
+}
+
+inline HRESULT ifc_omstorage::EndLoad(ifc_omstorageasync *async, ifc_omserviceenum **ppEnum)
+{
+ return _call(API_ENDLOAD, (HRESULT)E_NOTIMPL, async, ppEnum);
+}
+
+inline HRESULT ifc_omstorage::RequestAbort(ifc_omstorageasync *async, BOOL drop)
+{
+ return _call(API_REQUESTABORT, (HRESULT)E_NOTIMPL, async, drop);
+}
+
+#endif //NULLSOFT_WINAMP_OMSTORAGE_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omstorageasync.h b/Src/omBrowser/ifc_omstorageasync.h
new file mode 100644
index 00000000..9246294a
--- /dev/null
+++ b/Src/omBrowser/ifc_omstorageasync.h
@@ -0,0 +1,62 @@
+#ifndef NULLSOFT_WINAMP_OMSTORAGE_ASYNC_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSTORAGE_ASYNC_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+// {5D6C5C55-E744-4936-A31D-B9D8C0F4EF86}
+static const GUID IFC_OmStorageAsync =
+{ 0x5d6c5c55, 0xe744, 0x4936, { 0xa3, 0x1d, 0xb9, 0xd8, 0xc0, 0xf4, 0xef, 0x86 } };
+
+class __declspec(novtable) ifc_omstorageasync : public Dispatchable
+{
+public:
+ typedef void (CALLBACK *AsyncCallback)(ifc_omstorageasync *result);
+
+ typedef enum
+ {
+ stateReady = 0,
+ stateInitializing = 1,
+ stateConnecting = 2,
+ stateReceiving = 3,
+ stateCompleted = 4,
+ stateAborting = 5,
+ } States;
+
+protected:
+ ifc_omstorageasync() {}
+ ~ifc_omstorageasync() {}
+
+public:
+ HRESULT GetState(unsigned int *state);
+ HRESULT GetWaitHandle(HANDLE *handle);
+ HRESULT GetData(void **data);
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETSTATE = 10,
+ API_GETWAITHANDLE = 20,
+ API_GETDATA = 30,
+ };
+};
+
+inline HRESULT ifc_omstorageasync::GetWaitHandle(HANDLE *handle)
+{
+ return _call(API_GETWAITHANDLE, (HRESULT)E_NOTIMPL, handle);
+}
+
+inline HRESULT ifc_omstorageasync::GetData(void **data)
+{
+ return _call(API_GETDATA, (HRESULT)E_NOTIMPL, data);
+}
+
+inline HRESULT ifc_omstorageasync::GetState(unsigned int *state)
+{
+ return _call(API_GETSTATE, (HRESULT)E_NOTIMPL, state);
+}
+
+#endif //NULLSOFT_WINAMP_OMSTORAGE_ASYNC_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omstorageenum.h b/Src/omBrowser/ifc_omstorageenum.h
new file mode 100644
index 00000000..0c2661d1
--- /dev/null
+++ b/Src/omBrowser/ifc_omstorageenum.h
@@ -0,0 +1,50 @@
+#ifndef NULLSOFT_WINAMP_OMSTORAGE_ENUMERATOR_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSTORAGE_ENUMERATOR_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {31BF2BEF-4362-4277-A4E1-0589336BC55C}
+static const GUID IFC_OmStorageEnumerator =
+{ 0x31bf2bef, 0x4362, 0x4277, { 0xa4, 0xe1, 0x5, 0x89, 0x33, 0x6b, 0xc5, 0x5c } };
+
+#include <bfc/dispatch.h>
+class ifc_omstorage;
+
+class __declspec(novtable) ifc_omstorageenumerator : public Dispatchable
+{
+protected:
+ ifc_omstorageenumerator() {}
+ ~ifc_omstorageenumerator() {}
+
+public:
+ HRESULT Next(unsigned long listSize, ifc_omstorage **elementList, unsigned long *elementCount);
+ HRESULT Reset(void);
+ HRESULT Skip(unsigned long elementCount);
+
+public:
+ DISPATCH_CODES
+ {
+ API_NEXT = 10,
+ API_RESET = 20,
+ API_SKIP = 30,
+ };
+};
+
+inline HRESULT ifc_omstorageenumerator::Next(unsigned long listSize, ifc_omstorage **elementList, unsigned long *elementCount)
+{
+ return _call(API_NEXT, (HRESULT)E_NOTIMPL, listSize, elementList, elementCount);
+}
+
+inline HRESULT ifc_omstorageenumerator::Reset(void)
+{
+ return _call(API_RESET, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_omstorageenumerator::Skip(unsigned long elementCount)
+{
+ return _call(API_SKIP, (HRESULT)E_NOTIMPL, elementCount);
+}
+
+#endif //NULLSOFT_WINAMP_OMSTORAGE_ENUMERATOR_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omstorageext.h b/Src/omBrowser/ifc_omstorageext.h
new file mode 100644
index 00000000..119bf850
--- /dev/null
+++ b/Src/omBrowser/ifc_omstorageext.h
@@ -0,0 +1,37 @@
+#ifndef NULLSOFT_WINAMP_OMSTORAGE_EXTENDER_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSTORAGE_EXTENDER_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {8D1915C0-7925-49f1-A851-C230C634B7EE}
+static const GUID IFC_OmStorageExt =
+{ 0x8d1915c0, 0x7925, 0x49f1, { 0xa8, 0x51, 0xc2, 0x30, 0xc6, 0x34, 0xb7, 0xee } };
+
+#include <bfc/dispatch.h>
+class ifc_omstoragehandlerenum;
+class ifc_omstorage;
+
+class __declspec(novtable) ifc_omstorageext : public Dispatchable
+{
+protected:
+ ifc_omstorageext() {}
+ ~ifc_omstorageext() {}
+
+public:
+ HRESULT Enumerate(const GUID *storageId, ifc_omstoragehandlerenum **enumerator);
+
+public:
+ DISPATCH_CODES
+ {
+ API_ENUMERATE = 10,
+ };
+};
+
+inline HRESULT ifc_omstorageext::Enumerate(const GUID *storageId, ifc_omstoragehandlerenum **enumerator)
+{
+ return _call(API_ENUMERATE, (HRESULT)E_NOTIMPL, storageId, enumerator);
+}
+
+#endif //NULLSOFT_WINAMP_OMSTORAGE_EXTENDER_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omstoragehandler.h b/Src/omBrowser/ifc_omstoragehandler.h
new file mode 100644
index 00000000..748546b0
--- /dev/null
+++ b/Src/omBrowser/ifc_omstoragehandler.h
@@ -0,0 +1,45 @@
+#ifndef NULLSOFT_WINAMP_OMSTORAGE_HANDLER_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSTORAGE_HANDLER_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {9B37B560-CF31-41c6-BB35-14F16E290AFB}
+static const GUID IFC_OmStorageHandler =
+{ 0x9b37b560, 0xcf31, 0x41c6, { 0xbb, 0x35, 0x14, 0xf1, 0x6e, 0x29, 0xa, 0xfb } };
+
+#include <bfc/dispatch.h>
+
+class ifc_omstorage;
+class ifc_omservice;
+
+class __declspec(novtable) ifc_omstoragehandler : public Dispatchable
+{
+protected:
+ ifc_omstoragehandler() {}
+ ~ifc_omstoragehandler() {}
+
+public:
+ HRESULT GetKey(const wchar_t **ppKey);
+ void Invoke(ifc_omservice *service, const wchar_t *key, const wchar_t * value);
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETKEY = 10,
+ API_INVOKE = 20,
+ };
+};
+
+inline HRESULT ifc_omstoragehandler::GetKey(const wchar_t **ppKey)
+{
+ return _call(API_GETKEY, (HRESULT)E_NOTIMPL, ppKey);
+}
+
+inline void ifc_omstoragehandler::Invoke(ifc_omservice *service, const wchar_t *key, const wchar_t *value)
+{
+ _voidcall(API_INVOKE, service, key, value);
+}
+
+#endif //NULLSOFT_WINAMP_OMSTORAGE_HANDLER_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omstoragehandlerenum.h b/Src/omBrowser/ifc_omstoragehandlerenum.h
new file mode 100644
index 00000000..780d9e40
--- /dev/null
+++ b/Src/omBrowser/ifc_omstoragehandlerenum.h
@@ -0,0 +1,50 @@
+#ifndef NULLSOFT_WINAMP_OMSTORAGE_HANDLER_ENUMERATOR_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSTORAGE_HANDLER_ENUMERATOR_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {412877D7-0482-423d-87B9-975137588F6E}
+static const GUID IFC_OmStorageHandlerEnum =
+{ 0x412877d7, 0x482, 0x423d, { 0x87, 0xb9, 0x97, 0x51, 0x37, 0x58, 0x8f, 0x6e } };
+
+#include <bfc/dispatch.h>
+class ifc_omstoragehandler;
+
+class __declspec(novtable) ifc_omstoragehandlerenum : public Dispatchable
+{
+protected:
+ ifc_omstoragehandlerenum() {}
+ ~ifc_omstoragehandlerenum() {}
+
+public:
+ HRESULT Next(unsigned long listSize, ifc_omstoragehandler **elementList, unsigned long *elementCount);
+ HRESULT Reset(void);
+ HRESULT Skip(unsigned long elementCount);
+
+public:
+ DISPATCH_CODES
+ {
+ API_NEXT = 10,
+ API_RESET = 20,
+ API_SKIP = 30,
+ };
+};
+
+inline HRESULT ifc_omstoragehandlerenum::Next(unsigned long listSize, ifc_omstoragehandler **elementList, unsigned long *elementCount)
+{
+ return _call(API_NEXT, (HRESULT)E_NOTIMPL, listSize, elementList, elementCount);
+}
+
+inline HRESULT ifc_omstoragehandlerenum::Reset(void)
+{
+ return _call(API_RESET, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_omstoragehandlerenum::Skip(unsigned long elementCount)
+{
+ return _call(API_SKIP, (HRESULT)E_NOTIMPL, elementCount);
+}
+
+#endif //NULLSOFT_WINAMP_OMSTORAGE_HANDLER_ENUMERATOR_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omstoragehelper.h b/Src/omBrowser/ifc_omstoragehelper.h
new file mode 100644
index 00000000..06a839ed
--- /dev/null
+++ b/Src/omBrowser/ifc_omstoragehelper.h
@@ -0,0 +1,55 @@
+#ifndef NULLSOFT_WINAMP_OMSTORAGE_HELPER_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSTORAGE_HELPER_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+// {47243D54-37F3-4493-8643-BE75205E6CBF}
+static const GUID IFC_OmStorageHelper =
+{ 0x47243d54, 0x37f3, 0x4493, { 0x86, 0x43, 0xbe, 0x75, 0x20, 0x5e, 0x6c, 0xbf } };
+
+class ifc_omservice;
+class ifc_omstoragehandler;
+class ifc_omstoragehandlerenum;
+
+class __declspec(novtable) ifc_omstoragehelper : public Dispatchable
+{
+public:
+ typedef void (CALLBACK *HandlerProc)(ifc_omservice * /*service*/, const wchar_t * /*pszKey*/, const wchar_t * /*pszValue*/);
+
+ typedef struct __TemplateRecord
+ {
+ LPCWSTR key;
+ HandlerProc handler;
+ } TemplateRecord;
+
+protected:
+ ifc_omstoragehelper() {}
+ ~ifc_omstoragehelper() {}
+
+public:
+ HRESULT CreateHandler(const wchar_t *key, HandlerProc proc, ifc_omstoragehandler **handler);
+ HRESULT CreateEnumerator(const TemplateRecord *recordList, size_t recordCount, ifc_omstoragehandlerenum **enumerator);
+
+public:
+ DISPATCH_CODES
+ {
+ API_CREATEHANDLER = 10,
+ API_CREATEENUMERATOR = 20,
+ };
+};
+
+inline HRESULT ifc_omstoragehelper::CreateHandler(const wchar_t *key, HandlerProc proc, ifc_omstoragehandler **handler)
+{
+ return _call(API_CREATEHANDLER, (HRESULT)E_NOTIMPL, key, proc, handler);
+}
+
+inline HRESULT ifc_omstoragehelper::CreateEnumerator(const TemplateRecord *recordList, size_t recordCount, ifc_omstoragehandlerenum **enumerator)
+{
+ return _call(API_CREATEENUMERATOR, (HRESULT)E_NOTIMPL, recordList, recordCount, enumerator);
+}
+
+#endif //NULLSOFT_WINAMP_OMSTORAGE_HELPER_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omtoolbarconfig.h b/Src/omBrowser/ifc_omtoolbarconfig.h
new file mode 100644
index 00000000..f8c23e66
--- /dev/null
+++ b/Src/omBrowser/ifc_omtoolbarconfig.h
@@ -0,0 +1,105 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_CONFIG_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_CONFIG_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {40D85420-F7E6-4995-A4B9-6A00D4E64452}
+static const GUID IFC_OmToolbarConfig =
+{ 0x40d85420, 0xf7e6, 0x4995, { 0xa4, 0xb9, 0x6a, 0x0, 0xd4, 0xe6, 0x44, 0x52 } };
+
+#define CFGID_TOOLBAR_BOTTOMDOCK 0 // param = (ULONG_PTR)(BOOL)fBottomDock
+#define CFGID_TOOLBAR_AUTOHIDE 1 // param = (ULONG_PTR)(BOOL)fAutoHide
+#define CFGID_TOOLBAR_TABSTOP 2 // param = (ULONG_PTR)(BOOL)fTabStop
+#define CFGID_TOOLBAR_FORCEADDRESS 3 // param = (ULONG_PTR)(BOOL)fForce
+#define CFGID_TOOLBAR_FANCYADDRESS 4 // param = (ULONG_PTR)(BOOL)fFancy
+
+#include <bfc/dispatch.h>
+
+class __declspec(novtable) ifc_omtoolbarconfig : public Dispatchable
+{
+protected:
+ ifc_omtoolbarconfig() {}
+ ~ifc_omtoolbarconfig() {}
+
+public:
+ HRESULT GetBottomDockEnabled(void);
+ HRESULT GetAutoHideEnabled(void);
+ HRESULT GetTabStopEnabled(void);
+ HRESULT GetForceAddressbarEnabled(void);
+ HRESULT GetFancyAddressbarEnabled(void);
+
+ HRESULT EnableBottomDock(BOOL fEnable);
+ HRESULT EnableAutoHide(BOOL fEnable);
+ HRESULT EnableTabStop(BOOL fEnable);
+ HRESULT EnableForceAddressbar(BOOL fEnable);
+ HRESULT EnableFancyAddressbar(BOOL fEnable);
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETBOTTOMDOCKENABLED = 10,
+ API_ENABLEBOTTOMDOCK = 20,
+ API_GETAUTOHIDEENABLED = 30,
+ API_ENABLEAUTOHIDE = 40,
+ API_GETTABSTOPENABLED = 50,
+ API_ENABLETABSTOP = 60,
+ API_GETFORCEADDRESSBARENABLED = 70,
+ API_ENABLEFORCEADDRESSBAR = 80,
+ API_GETFANCYADDRESSBARENABLED = 90,
+ API_ENABLEFANCYADDRESSBAR = 100,
+ };
+};
+
+inline HRESULT ifc_omtoolbarconfig::GetBottomDockEnabled(void)
+{
+ return _call(API_GETBOTTOMDOCKENABLED, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_omtoolbarconfig::EnableBottomDock(BOOL fEnable)
+{
+ return _call(API_ENABLEBOTTOMDOCK, (HRESULT)E_NOTIMPL, fEnable);
+}
+
+inline HRESULT ifc_omtoolbarconfig::GetAutoHideEnabled(void)
+{
+ return _call(API_GETAUTOHIDEENABLED, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_omtoolbarconfig::EnableAutoHide(BOOL fEnable)
+{
+ return _call(API_ENABLEAUTOHIDE, (HRESULT)E_NOTIMPL, fEnable);
+}
+
+inline HRESULT ifc_omtoolbarconfig::GetTabStopEnabled(void)
+{
+ return _call(API_GETTABSTOPENABLED, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_omtoolbarconfig::EnableTabStop(BOOL fEnable)
+{
+ return _call(API_ENABLETABSTOP, (HRESULT)E_NOTIMPL, fEnable);
+}
+
+inline HRESULT ifc_omtoolbarconfig::GetForceAddressbarEnabled(void)
+{
+ return _call(API_GETFORCEADDRESSBARENABLED, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_omtoolbarconfig::EnableForceAddressbar(BOOL fEnable)
+{
+ return _call(API_ENABLEFORCEADDRESSBAR, (HRESULT)E_NOTIMPL, fEnable);
+}
+
+inline HRESULT ifc_omtoolbarconfig::GetFancyAddressbarEnabled(void)
+{
+ return _call(API_GETFANCYADDRESSBARENABLED, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_omtoolbarconfig::EnableFancyAddressbar(BOOL fEnable)
+{
+ return _call(API_ENABLEFANCYADDRESSBAR, (HRESULT)E_NOTIMPL, fEnable);
+}
+
+#endif // NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_CONFIG_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omutility.h b/Src/omBrowser/ifc_omutility.h
new file mode 100644
index 00000000..4903d6f5
--- /dev/null
+++ b/Src/omBrowser/ifc_omutility.h
@@ -0,0 +1,105 @@
+#ifndef NULLSOFT_WINAMP_OMUTILITY_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMUTILITY_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+
+// {14E8C9B6-1BA4-4e8d-AD26-FA848813CC5B}
+static const GUID IFC_OmUtility =
+{ 0x14e8c9b6, 0x1ba4, 0x4e8d, { 0xad, 0x26, 0xfa, 0x84, 0x88, 0x13, 0xcc, 0x5b } };
+
+#define RESPATH_TARGETIE 0x0001 // IE safe path
+#define RESPATH_COMPACT 0x0002 // compact path relative to winamp location if possible
+
+class ifc_omcachemanager;
+class ifc_mlnavigationhelper;
+class ifc_omimageloader;
+class ifc_omgraphics;
+class ifc_omstoragehelper;
+
+class __declspec(novtable) ifc_omutility : public Dispatchable
+{
+public:
+ typedef void ( CALLBACK *ThreadCallback )( ULONG_PTR /*param*/ );
+ typedef void ( CALLBACK *ThreadCallback2 )( Dispatchable *object, ULONG_PTR /*param1*/, ULONG_PTR /*param2*/ );
+
+protected:
+ ifc_omutility() {}
+ ~ifc_omutility() {}
+
+public:
+ HRESULT EnsurePathExist( const wchar_t *directory );
+ HRESULT MakeResourcePath( wchar_t *buffer, unsigned int bufferMax, HINSTANCE instance, const wchar_t *type, const wchar_t *name, unsigned int flags );
+
+ HRESULT GetCacheManager( ifc_omcachemanager **cacheManager );
+ HRESULT GetMlNavigationHelper( HWND hLibrary, ifc_mlnavigationhelper **helper );
+ HRESULT QueryImageLoader( HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply, ifc_omimageloader **imageLoader );
+ HRESULT GetGraphics( ifc_omgraphics **graphics );
+ HRESULT PostMainThreadCallback( ThreadCallback callback, ULONG_PTR param );
+ HRESULT PostMainThreadCallback2( ThreadCallback2 callback, Dispatchable *object, ULONG_PTR param1, ULONG_PTR param2 );
+ HRESULT GetStorageHelper( ifc_omstoragehelper **helper );
+
+public:
+ DISPATCH_CODES
+ {
+ API_ENSUREPATHEXIST = 10,
+ API_MAKERESPATH = 20,
+ API_GETCACHEMANAGER = 30,
+ API_GETMLNAVIGATIONHELPER = 40,
+ API_QUERYIMAGELOADER = 50,
+ API_GETGRAPHICS = 60,
+ API_POSTMAINTHREADCALLBACK = 70,
+ API_POSTMAINTHREADCALLBACK2 = 80,
+ API_GETSTORAGEHELPER = 90,
+ };
+};
+
+inline HRESULT ifc_omutility::EnsurePathExist(const wchar_t *directory)
+{
+ return _call(API_ENSUREPATHEXIST, (HRESULT)E_NOTIMPL, directory);
+}
+
+inline HRESULT ifc_omutility::MakeResourcePath(wchar_t *buffer, unsigned int bufferMax, HINSTANCE instance, const wchar_t *type, const wchar_t *name, unsigned int flags)
+{
+ return _call(API_MAKERESPATH, (HRESULT)E_NOTIMPL, buffer, bufferMax, instance, type, name, flags);
+}
+
+inline HRESULT ifc_omutility::GetCacheManager(ifc_omcachemanager **cacheManager)
+{
+ return _call(API_GETCACHEMANAGER, (HRESULT)E_NOTIMPL, cacheManager);
+}
+
+inline HRESULT ifc_omutility::GetMlNavigationHelper(HWND hLibrary, ifc_mlnavigationhelper **helper)
+{
+ return _call(API_GETMLNAVIGATIONHELPER, (HRESULT)E_NOTIMPL, hLibrary, helper);
+}
+
+inline HRESULT ifc_omutility::QueryImageLoader(HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply, ifc_omimageloader **imageLoader)
+{
+ return _call(API_QUERYIMAGELOADER, (HRESULT)E_NOTIMPL, hInstance, pszName, fPremultiply, imageLoader);
+}
+
+inline HRESULT ifc_omutility::GetGraphics(ifc_omgraphics **graphics)
+{
+ return _call(API_GETGRAPHICS, (HRESULT)E_NOTIMPL, graphics);
+}
+
+inline HRESULT ifc_omutility::PostMainThreadCallback(ThreadCallback callback, ULONG_PTR param)
+{
+ return _call(API_POSTMAINTHREADCALLBACK, (HRESULT)E_NOTIMPL, callback, param);
+}
+
+inline HRESULT ifc_omutility::PostMainThreadCallback2(ThreadCallback2 callback, Dispatchable *object, ULONG_PTR param1, ULONG_PTR param2)
+{
+ return _call(API_POSTMAINTHREADCALLBACK2, (HRESULT)E_NOTIMPL, callback, object, param1, param2);
+}
+
+inline HRESULT ifc_omutility::GetStorageHelper(ifc_omstoragehelper **helper)
+{
+ return _call(API_GETSTORAGEHELPER, (HRESULT)E_NOTIMPL, helper);
+}
+
+#endif //NULLSOFT_WINAMP_OMUTILITY_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omwebstorage.h b/Src/omBrowser/ifc_omwebstorage.h
new file mode 100644
index 00000000..91ca3849
--- /dev/null
+++ b/Src/omBrowser/ifc_omwebstorage.h
@@ -0,0 +1,28 @@
+#ifndef NULLSOFT_WINAMP_OMSTORAGETYPE_WEB_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSTORAGETYPE_WEB_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {FC4BD6AA-F2BD-46dd-B5AD-0F5B38950AEF}
+static const GUID STID_OmWebStorage =
+{ 0xfc4bd6aa, 0xf2bd, 0x46dd, { 0xb5, 0xad, 0xf, 0x5b, 0x38, 0x95, 0xa, 0xef } };
+
+// {BA2DB1CF-9056-41a3-A9E9-0D6015FFA159}
+static const GUID SUID_OmStorageUrl =
+{ 0xba2db1cf, 0x9056, 0x41a3, { 0xa9, 0xe9, 0xd, 0x60, 0x15, 0xff, 0xa1, 0x59 } };
+
+#include <ifc_omstorage.h>
+
+#define IFC_OmWebStorage STID_OmWebStorage
+
+#define E_DWNLD_OK S_OK
+#define E_DWNLD_BUSY E_PENDING
+#define E_DWNLD_FAIL E_FAIL
+#define E_DWNLD_ABORT E_ABORT
+#define E_DWNLD_TIMEOUT HRESULT_FROM_WIN32(ERROR_TIMEOUT)
+#define E_DWNLD_CANT_CONNECT HRESULT_FROM_WIN32(ERROR_NOT_CONNECTED)
+#define E_DWNLD_WRITE_ERROR HRESULT_FROM_WIN32(ERROR_WRITE_FAULT)
+
+#endif //NULLSOFT_WINAMP_OMSTORAGETYPE_WEB_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_omxmlserviceenum.h b/Src/omBrowser/ifc_omxmlserviceenum.h
new file mode 100644
index 00000000..b54247b5
--- /dev/null
+++ b/Src/omBrowser/ifc_omxmlserviceenum.h
@@ -0,0 +1,42 @@
+#ifndef NULLSOFT_WINAMP_OMSERVICE_XML_ENUMERATOR_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMSERVICE_XML_ENUMERATOR_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {E7105EE1-161B-4580-A8C0-6673FB59AB47}
+static const GUID IFC_OmXmlServiceEnum =
+{ 0xe7105ee1, 0x161b, 0x4580, { 0xa8, 0xc0, 0x66, 0x73, 0xfb, 0x59, 0xab, 0x47 } };
+
+#include <bfc/dispatch.h>
+
+class __declspec(novtable) ifc_omxmlserviceenum : public Dispatchable
+{
+protected:
+ ifc_omxmlserviceenum() {}
+ ~ifc_omxmlserviceenum() {}
+
+public:
+ HRESULT GetStatusCode(unsigned int *code);
+ HRESULT GetStatusText(wchar_t *buffer, unsigned int bufferMax);
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETSTATUSCODE = 10,
+ API_GETSTATUSTEXT = 20,
+ };
+};
+
+inline HRESULT ifc_omxmlserviceenum::GetStatusCode(unsigned int *code)
+{
+ return _call(API_GETSTATUSCODE, (HRESULT)E_NOTIMPL, code);
+}
+
+inline HRESULT ifc_omxmlserviceenum::GetStatusText(wchar_t *buffer, unsigned int bufferMax)
+{
+ return _call(API_GETSTATUSTEXT, (HRESULT)E_NOTIMPL, buffer, bufferMax);
+}
+
+#endif //NULLSOFT_WINAMP_OMSERVICE_XML_ENUMERATOR_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_skinhelper.h b/Src/omBrowser/ifc_skinhelper.h
new file mode 100644
index 00000000..40457dce
--- /dev/null
+++ b/Src/omBrowser/ifc_skinhelper.h
@@ -0,0 +1,85 @@
+#ifndef NULLSOFT_WINAMP_SKIN_HELPER_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_SKIN_HELPER_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {DC98C56E-F649-469e-82DC-234FAA8083C1}
+static const GUID IFC_SkinHelper =
+{ 0xdc98c56e, 0xf649, 0x469e, { 0x82, 0xdc, 0x23, 0x4f, 0xaa, 0x80, 0x83, 0xc1 } };
+
+#include <bfc/dispatch.h>
+
+typedef struct embedWindowState embedWindowState;
+typedef int (CALLBACK *FFCALLBACK)(embedWindowState* /*windowState*/, INT /*eventId*/, LPARAM /*param*/);
+
+class __declspec(novtable) ifc_skinhelper : public Dispatchable
+{
+
+protected:
+ ifc_skinhelper() {}
+ ~ifc_skinhelper() {}
+
+public:
+ HRESULT GetColor(UINT colorIndex, COLORREF *pColor);
+ HRESULT GetColorEx(UINT uObject, UINT uPart, UINT uState, COLORREF *pColor);
+ HRESULT GetBrush(UINT colorIndex, HBRUSH *pBrush);
+
+ HFONT GetFont(void);
+
+ HRESULT SkinWindow(HWND hwnd, const GUID *windowGuid, UINT flagsEx, FFCALLBACK callbackFF);
+ HRESULT SkinControl(HWND hwnd, UINT type, UINT style);
+ HRESULT UnskinWindow(HWND hwnd);
+
+ HRESULT GetHostCss(OLECHAR **ppchHostCss);
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETCOLOR = 10,
+ API_GETCOLOREX = 20,
+ API_GETBRUSH = 30,
+ API_GETFONT = 40,
+ API_SKINWINDOW = 50,
+ API_SKINCONTROL = 60,
+ API_UNSKINWINDOW = 70,
+ };
+};
+
+inline HRESULT ifc_skinhelper::GetColor(UINT colorIndex, COLORREF *pColor)
+{
+ return _call(API_GETCOLOR, (HRESULT)E_NOTIMPL, colorIndex, pColor);
+}
+
+inline HRESULT ifc_skinhelper::GetColorEx(UINT uObject, UINT uPart, UINT uState, COLORREF *pColor)
+{
+ return _call(API_GETCOLOREX, (HRESULT)E_NOTIMPL, uObject, uPart, uState, pColor);
+}
+
+inline HRESULT ifc_skinhelper::GetBrush(UINT colorIndex, HBRUSH *pBrush)
+{
+ return _call(API_GETBRUSH, (HRESULT)E_NOTIMPL, colorIndex, pBrush);
+}
+
+inline HFONT ifc_skinhelper::GetFont()
+{
+ return _call(API_GETFONT, (HFONT)NULL);
+}
+
+inline HRESULT ifc_skinhelper::SkinWindow(HWND hwnd, const GUID *windowGuid, UINT flagsEx, FFCALLBACK callbackFF)
+{
+ return _call(API_SKINWINDOW, (HRESULT)E_NOTIMPL, hwnd, windowGuid, flagsEx, callbackFF);
+}
+
+inline HRESULT ifc_skinhelper::SkinControl(HWND hwnd, UINT type, UINT style)
+{
+ return _call(API_SKINCONTROL, (HRESULT)E_NOTIMPL, hwnd, type, style);
+}
+
+inline HRESULT ifc_skinhelper::UnskinWindow(HWND hwnd)
+{
+ return _call(API_UNSKINWINDOW, (HRESULT)E_NOTIMPL);
+}
+
+#endif // NULLSOFT_WINAMP_SKIN_HELPER_INTERFACE_HEADER
diff --git a/Src/omBrowser/ifc_skinnedbrowser.h b/Src/omBrowser/ifc_skinnedbrowser.h
new file mode 100644
index 00000000..3ee05932
--- /dev/null
+++ b/Src/omBrowser/ifc_skinnedbrowser.h
@@ -0,0 +1,78 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_SKINNED_BROWSER_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_SKINNED_BROWSER_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {9E98C972-7C54-46e1-B265-21B343B2F226}
+static const GUID IFC_SkinnedBrowser =
+{ 0x9e98c972, 0x7c54, 0x46e1, { 0xb2, 0x65, 0x21, 0xb3, 0x43, 0xb2, 0xf2, 0x26 } };
+
+#include <bfc/dispatch.h>
+
+class __declspec(novtable) ifc_skinnedbrowser : public Dispatchable
+{
+
+protected:
+ ifc_skinnedbrowser() {}
+ ~ifc_skinnedbrowser() {}
+
+public:
+ HRESULT GetHostCss(wchar_t **ppchHostCss);
+ COLORREF GetBackColor(void);
+ COLORREF GetTextColor(void);
+ COLORREF GetLinkColor(void);
+ COLORREF GetActiveLinkColor(void);
+ COLORREF GetVisitedLinkColor(void);
+ COLORREF GetHoveredLinkColor(void);
+
+
+public:
+ DISPATCH_CODES
+ {
+ API_GETHOSTCSS = 10,
+ API_GETBACKCOLOR = 20,
+ API_GETTEXTCOLOR = 30,
+ API_GETLINKCOLOR = 40,
+ API_GETACTIVELINKCOLOR = 50,
+ API_GETVISITEDLINKCOLOR = 60,
+ API_GETHOVEREDLINKCOLOR = 70,
+ };
+};
+
+inline HRESULT ifc_skinnedbrowser::GetHostCss(wchar_t **ppchHostCss)
+{
+ return _call(API_GETHOSTCSS, (HRESULT)E_NOTIMPL, ppchHostCss);
+}
+
+inline COLORREF ifc_skinnedbrowser::GetBackColor(void)
+{
+ return _call(API_GETBACKCOLOR, (COLORREF)0x00FFFFFF);
+}
+
+inline COLORREF ifc_skinnedbrowser::GetTextColor(void)
+{
+ return _call(API_GETTEXTCOLOR, (COLORREF)0x00000000);
+}
+
+inline COLORREF ifc_skinnedbrowser::GetLinkColor(void)
+{
+ return _call(API_GETLINKCOLOR, (COLORREF)0x000000E0);
+}
+
+inline COLORREF ifc_skinnedbrowser::GetActiveLinkColor(void)
+{
+ return _call(API_GETACTIVELINKCOLOR, (COLORREF)0x000000FF);
+}
+
+inline COLORREF ifc_skinnedbrowser::GetVisitedLinkColor(void)
+{
+ return _call(API_GETVISITEDLINKCOLOR, (COLORREF)0x00FF00FF);
+}
+
+inline COLORREF ifc_skinnedbrowser::GetHoveredLinkColor(void)
+{
+ return _call(API_GETHOVEREDLINKCOLOR, (COLORREF)0x000000F0);
+}
+#endif // NULLSOFT_WINAMP_OMBROWSER_SKINNED_BROWSER_INTERFACE_HEADER
diff --git a/Src/omBrowser/ifc_skinnedmenu.h b/Src/omBrowser/ifc_skinnedmenu.h
new file mode 100644
index 00000000..67794346
--- /dev/null
+++ b/Src/omBrowser/ifc_skinnedmenu.h
@@ -0,0 +1,61 @@
+#ifndef NULLSOFT_WINAMP_SKINNED_MENU_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_SKINNED_MENU_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {6623F790-D4D9-43f4-9AFD-980360FB0EED}
+static const GUID IFC_SkinnedMenu =
+{ 0x6623f790, 0xd4d9, 0x43f4, { 0x9a, 0xfd, 0x98, 0x3, 0x60, 0xfb, 0xe, 0xed } };
+
+#include <bfc/dispatch.h>
+
+
+class ifc_menucustomizer;
+#define ForceNoSkinnedMenu ((ifc_menucustomizer*)1)
+
+class __declspec(novtable) ifc_skinnedmenu : public Dispatchable
+{
+
+protected:
+ ifc_skinnedmenu() {}
+ ~ifc_skinnedmenu() {}
+
+public:
+ BOOL TrackPopup(HMENU hMenu, UINT fuFlags, INT x, INT y, HWND hwnd, LPTPMPARAMS lptpm, ifc_menucustomizer *customizer);
+ HRESULT IsEnabled(void);
+ HANDLE InitPopupHook(HWND hwnd, ifc_menucustomizer *customizer);
+ HRESULT RemovePopupHook(HANDLE popupHook);
+
+public:
+ DISPATCH_CODES
+ {
+ API_TRACKPOPUP = 10,
+ API_ISENABLED = 20,
+ API_INITPOPUPHOOK = 30,
+ API_REMOVEPOPUPHOOK = 40,
+ };
+};
+
+inline BOOL ifc_skinnedmenu::TrackPopup(HMENU hMenu, UINT fuFlags, INT x, INT y, HWND hwnd, LPTPMPARAMS lptpm, ifc_menucustomizer *customizer)
+{
+ return _call(API_TRACKPOPUP, (BOOL)FALSE, hMenu, fuFlags, x, y, hwnd, lptpm, customizer);
+}
+
+inline HRESULT ifc_skinnedmenu::IsEnabled(void)
+{
+ return _call(API_ISENABLED, (BOOL)FALSE);
+}
+
+inline HANDLE ifc_skinnedmenu::InitPopupHook(HWND hwnd, ifc_menucustomizer *customizer)
+{
+ return _call(API_INITPOPUPHOOK, (HANDLE)NULL, hwnd, customizer);
+}
+
+inline HRESULT ifc_skinnedmenu::RemovePopupHook(HANDLE popupHook)
+{
+ return _call(API_REMOVEPOPUPHOOK, (HRESULT)E_NOTIMPL, popupHook);
+}
+
+#endif // NULLSOFT_WINAMP_SKINNED_MENU_INTERFACE_HEADER
diff --git a/Src/omBrowser/ifc_skinnedrating.h b/Src/omBrowser/ifc_skinnedrating.h
new file mode 100644
index 00000000..23ce135d
--- /dev/null
+++ b/Src/omBrowser/ifc_skinnedrating.h
@@ -0,0 +1,62 @@
+#ifndef NULLSOFT_WINAMP_SKINNED_RATING_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_SKINNED_RATING_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {9CF4F23F-1F50-4f12-9B0A-A7F129E21AB8}
+static const GUID IFC_SkinnedRating =
+{ 0x9cf4f23f, 0x1f50, 0x4f12, { 0x9b, 0xa, 0xa7, 0xf1, 0x29, 0xe2, 0x1a, 0xb8 } };
+
+
+#include <bfc/dispatch.h>
+
+class ifc_menucustomizer;
+
+class __declspec(novtable) ifc_skinnedrating : public Dispatchable
+{
+
+protected:
+ ifc_skinnedrating() {}
+ ~ifc_skinnedrating() {}
+
+public:
+
+ HRESULT Draw(HDC hdc, INT maxValue, INT value, INT trackingVal, RECT *prc, UINT fStyle);
+ HRESULT HitTest(POINT pt, INT maxValue, RECT *prc, UINT fStyle, LONG *result);
+ HRESULT CalcMinRect(INT maxValue, RECT *prc);
+ HRESULT CreateMenuCustomizer(HMENU hMenu, ifc_menucustomizer **customizer);
+
+public:
+ DISPATCH_CODES
+ {
+ API_DRAW = 10,
+ API_HITTEST = 20,
+ API_CALCMINRECT = 30,
+ API_CREATEMENUCUSTOMIZER = 40,
+ };
+};
+
+inline HRESULT ifc_skinnedrating::Draw(HDC hdc, INT maxValue, INT value, INT trackingVal, RECT *prc, UINT fStyle)
+{
+ return _call(API_DRAW, (HRESULT)E_NOTIMPL, hdc, maxValue, value, trackingVal, prc, fStyle);
+}
+
+inline HRESULT ifc_skinnedrating::HitTest(POINT pt, INT maxValue, RECT *prc, UINT fStyle, LONG *result)
+{
+ return _call(API_HITTEST, (HRESULT)E_NOTIMPL, pt, maxValue, prc, fStyle, result);
+}
+
+inline HRESULT ifc_skinnedrating::CalcMinRect(INT maxValue, RECT *prc)
+{
+ return _call(API_CALCMINRECT, (HRESULT)E_NOTIMPL, maxValue, prc);
+}
+
+inline HRESULT ifc_skinnedrating::CreateMenuCustomizer(HMENU hMenu, ifc_menucustomizer **customizer)
+{
+ return _call(API_CREATEMENUCUSTOMIZER, (HRESULT)E_NOTIMPL, hMenu, customizer);
+}
+
+
+#endif // NULLSOFT_WINAMP_SKINNED_RATING_INTERFACE_HEADER
diff --git a/Src/omBrowser/ifc_travelloghelper.h b/Src/omBrowser/ifc_travelloghelper.h
new file mode 100644
index 00000000..5d14df79
--- /dev/null
+++ b/Src/omBrowser/ifc_travelloghelper.h
@@ -0,0 +1,44 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_TRAVELLOG_HELPER_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_TRAVELLOG_HELPER_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {2C4913CF-D04A-402e-81B4-B5A1A392618C}
+static const GUID IFC_TravelLogHelper =
+{ 0x2c4913cf, 0xd04a, 0x402e, { 0x81, 0xb4, 0xb5, 0xa1, 0xa3, 0x92, 0x61, 0x8c } };
+
+#include <bfc/dispatch.h>
+
+interface ITravelLogStg;
+
+class __declspec(novtable) ifc_travelloghelper : public Dispatchable
+{
+protected:
+ ifc_travelloghelper() {}
+ ~ifc_travelloghelper() {}
+
+public:
+ HRESULT QueryStorage(ITravelLogStg **ppLog);
+ HRESULT ShowPopup(UINT fuFlags, INT x, INT y, HWND hwnd, LPTPMPARAMS lptpm);
+
+public:
+ DISPATCH_CODES
+ {
+ API_QUERYSTORAGE = 10,
+ API_SHOWPOPUP = 20,
+ };
+};
+
+inline HRESULT ifc_travelloghelper::QueryStorage(ITravelLogStg **ppLog)
+{
+ return _call(API_QUERYSTORAGE, (HRESULT)E_NOTIMPL, ppLog);
+}
+
+inline HRESULT ifc_travelloghelper::ShowPopup(UINT fuFlags, INT x, INT y, HWND hwnd, LPTPMPARAMS lptpm)
+{
+ return _call(API_SHOWPOPUP, (HRESULT)E_NOTIMPL, fuFlags, x, y, hwnd, lptpm);
+}
+
+#endif // NULLSOFT_WINAMP_OMBROWSER_TRAVELLOG_HELPER_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_wasabihelper.h b/Src/omBrowser/ifc_wasabihelper.h
new file mode 100644
index 00000000..697ce3db
--- /dev/null
+++ b/Src/omBrowser/ifc_wasabihelper.h
@@ -0,0 +1,124 @@
+#ifndef NULLSOFT_WINAMP_WASABI_HELPER_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_WASABI_HELPER_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+class api_service;
+
+#include <bfc/dispatch.h>
+
+#include <api/application/api_application.h>
+#include "../Agave/Config/api_config.h"
+#include "../Agave/Language/api_language.h"
+#include <api/memmgr/api_memmgr.h>
+#include <api/service/svcs/svc_imgload.h>
+#include "../Winamp/JSAPI2_api_security.h"
+#include "../Components/wac_downloadManager/wac_downloadManager_api.h"
+#include "../nu/threadpool/api_threadpool.h"
+
+// {CA8954C8-C15F-4a62-A592-86A9464DE9A5}
+static const GUID IFC_WasabiHelper =
+{ 0xca8954c8, 0xc15f, 0x4a62, { 0xa5, 0x92, 0x86, 0xa9, 0x46, 0x4d, 0xe9, 0xa5 } };
+
+class __declspec(novtable) ifc_wasabihelper : public Dispatchable
+{
+protected:
+ ifc_wasabihelper() {}
+ ~ifc_wasabihelper() {}
+
+public:
+ HRESULT QueryWasabiInterface(const GUID *iid, void **ppi);
+ HRESULT ReleaseWasabiInterface(const GUID *iid, void *pi);
+
+ HRESULT GetServiceManager(api_service **serviceManager);
+ HRESULT GetApplicationApi(api_application **application);
+ HRESULT GetConfigApi(api_config ** config);
+ HRESULT GetMemoryManager(api_memmgr **memoryManager);
+ HRESULT GetPngLoader(svc_imageLoader **pngLoader);
+ HRESULT GetLanguageManager(api_language **languageManager);
+ HRESULT GetLanguageModule(HINSTANCE *module);
+ HRESULT GetSecurityApi(JSAPI2::api_security **security);
+ HRESULT GetDownloadManager(api_downloadManager **downloadManager);
+ HRESULT GetThreadpoolApi(api_threadpool **threadpool);
+
+public:
+ DISPATCH_CODES
+ {
+ API_QUERYWASABIINTERFACE = 10,
+ API_RELEASEWASABIINTERFACE = 20,
+ API_GETSERVICEMANAGER = 30,
+ API_GETAPPLICATION = 40,
+ API_GETCONFIG = 50,
+ API_GETMEMORYMANAGER = 60,
+ API_GETPNGLOADER = 70,
+ API_GETLANGUAGEMANAGER = 80,
+ API_GETLANGUAGEMODULE = 90,
+ API_GETSECURITY = 100,
+ API_GETDOWNLOADMANAGER = 110,
+ API_GETTHREADPOOL = 120,
+ };
+};
+
+inline HRESULT ifc_wasabihelper::QueryWasabiInterface(const GUID *iid, void **ppi)
+{
+ return _call(API_QUERYWASABIINTERFACE, (HRESULT)E_NOTIMPL, iid, ppi);
+}
+
+inline HRESULT ifc_wasabihelper::ReleaseWasabiInterface(const GUID *iid, void *pi)
+{
+ return _call(API_RELEASEWASABIINTERFACE, (HRESULT)E_NOTIMPL, iid, pi);
+}
+
+inline HRESULT ifc_wasabihelper::GetServiceManager(api_service **serviceManager)
+{
+ return _call(API_GETSERVICEMANAGER, (HRESULT)E_NOTIMPL, serviceManager);
+}
+
+inline HRESULT ifc_wasabihelper::GetApplicationApi(api_application **application)
+{
+ return _call(API_GETAPPLICATION, (HRESULT)E_NOTIMPL, application);
+}
+
+inline HRESULT ifc_wasabihelper::GetConfigApi(api_config ** config)
+{
+ return _call(API_GETCONFIG, (HRESULT)E_NOTIMPL, config);
+}
+
+inline HRESULT ifc_wasabihelper::GetMemoryManager(api_memmgr **memoryManager)
+{
+ return _call(API_GETMEMORYMANAGER, (HRESULT)E_NOTIMPL, memoryManager);
+}
+
+inline HRESULT ifc_wasabihelper::GetPngLoader(svc_imageLoader **pngLoader)
+{
+ return _call(API_GETPNGLOADER, (HRESULT)E_NOTIMPL, pngLoader);
+}
+
+inline HRESULT ifc_wasabihelper::GetLanguageManager(api_language **languageManager)
+{
+ return _call(API_GETLANGUAGEMANAGER, (HRESULT)E_NOTIMPL, languageManager);
+}
+
+inline HRESULT ifc_wasabihelper::GetLanguageModule(HINSTANCE *module)
+{
+ return _call(API_GETLANGUAGEMODULE, (HRESULT)E_NOTIMPL, module);
+}
+
+inline HRESULT ifc_wasabihelper::GetSecurityApi(JSAPI2::api_security **security)
+{
+ return _call(API_GETSECURITY, (HRESULT)E_NOTIMPL, security);
+}
+
+inline HRESULT ifc_wasabihelper::GetDownloadManager(api_downloadManager **downloadManager)
+{
+ return _call(API_GETDOWNLOADMANAGER, (HRESULT)E_NOTIMPL, downloadManager);
+}
+
+inline HRESULT ifc_wasabihelper::GetThreadpoolApi(api_threadpool **threadpool)
+{
+ return _call(API_GETTHREADPOOL, (HRESULT)E_NOTIMPL, threadpool);
+}
+
+#endif // NULLSOFT_WINAMP_WASABI_HELPER_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ifc_winamphook.h b/Src/omBrowser/ifc_winamphook.h
new file mode 100644
index 00000000..3fd0d9f4
--- /dev/null
+++ b/Src/omBrowser/ifc_winamphook.h
@@ -0,0 +1,77 @@
+#ifndef NULLSOFT_WINAMP_HOOK_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_HOOK_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+// {EB225B60-14C1-424f-B8EA-A8EDE3AD82A9}
+static const GUID IFC_WinampHook =
+{ 0xeb225b60, 0x14c1, 0x424f, { 0xb8, 0xea, 0xa8, 0xed, 0xe3, 0xad, 0x82, 0xa9 } };
+
+#include <bfc/dispatch.h>
+
+class __declspec(novtable) ifc_winamphook: public Dispatchable
+{
+protected:
+ ifc_winamphook() {}
+ ~ifc_winamphook() {}
+
+public:
+ HRESULT IsQuitAllowed(void); // return S_FALSE to block
+ HRESULT ResetFont(void);
+ HRESULT SkinChanging(void);
+ HRESULT SkinChanged(const wchar_t *skinName);
+ HRESULT FileMetaChange(const wchar_t *fileName);
+ HRESULT SysColorChange(void);
+ HRESULT SkinColorChange(const wchar_t *colorTheme);
+
+public:
+ DISPATCH_CODES
+ {
+ API_ISQUITALLOWED = 10,
+ API_RESETFONT = 20,
+ API_SKINCHANGING = 30,
+ API_SKINCHANGED = 40,
+ API_FILEMETACHANGE = 50,
+ API_SYSCOLORCHANGE = 60,
+ API_SKINCOLORCHANGE = 70
+ };
+};
+
+inline HRESULT ifc_winamphook::IsQuitAllowed(void)
+{
+ return _call(API_ISQUITALLOWED, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_winamphook::ResetFont(void)
+{
+ return _call(API_RESETFONT, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_winamphook::SkinChanging(void)
+{
+ return _call(API_SKINCHANGING, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_winamphook::SkinChanged(const wchar_t *skinName)
+{
+ return _call(API_SKINCHANGED, (HRESULT)E_NOTIMPL, skinName);
+}
+
+inline HRESULT ifc_winamphook::FileMetaChange(const wchar_t *fileName)
+{
+ return _call(API_FILEMETACHANGE, (HRESULT)E_NOTIMPL, fileName);
+}
+
+inline HRESULT ifc_winamphook::SysColorChange(void)
+{
+ return _call(API_SYSCOLORCHANGE, (HRESULT)E_NOTIMPL);
+}
+
+inline HRESULT ifc_winamphook::SkinColorChange(const wchar_t *colorTheme)
+{
+ return _call(API_SKINCOLORCHANGE, (HRESULT)E_NOTIMPL, colorTheme);
+}
+
+#endif // NULLSOFT_WINAMP_HOOK_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/internetFeatures.cpp b/Src/omBrowser/internetFeatures.cpp
new file mode 100644
index 00000000..c2c7bd52
--- /dev/null
+++ b/Src/omBrowser/internetFeatures.cpp
@@ -0,0 +1,224 @@
+#include <main.h>
+#include <internetFeatures.h>
+#include <shlwapi.h>
+#include <strsafe.h>
+
+#define REGISTRY_FEATURE_CONTROL L"Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl"
+
+InternetFeatures::InternetFeatures()
+ : module(NULL), loadResult(S_FALSE),
+ CoInternetSetFeatureEnabled(NULL),
+ CoInternetIsFeatureEnabled(NULL),
+ processName_(NULL)
+{
+}
+
+InternetFeatures::~InternetFeatures()
+{
+ if (NULL != module)
+ {
+ FreeLibrary(module);
+ }
+
+ if (NULL != processName_)
+ free(processName_);
+}
+
+HRESULT InternetFeatures::LoadModule()
+{
+ if (S_FALSE != loadResult)
+ return loadResult;
+
+ module = LoadLibrary(L"UrlMon.dll");
+ if (NULL == module)
+ {
+ DWORD errorCode = GetLastError();
+ loadResult = HRESULT_FROM_WIN32(errorCode);
+ return loadResult;
+ }
+ else
+ {
+ loadResult = S_OK;
+ }
+
+ CoInternetSetFeatureEnabled = (COINTERNETSETFEATUREENABLED)GetProcAddress(module, "CoInternetSetFeatureEnabled");
+ CoInternetIsFeatureEnabled = (COINTERNETISFEATUREENABLED)GetProcAddress(module, "CoInternetIsFeatureEnabled");
+
+ return loadResult;
+}
+
+const wchar_t *InternetFeatures::GetProcessName()
+{
+ if (NULL == processName_)
+ {
+ wchar_t buffer[2*MAX_PATH] = {0};
+ unsigned long length = GetModuleFileNameW(NULL, buffer, ARRAYSIZE(buffer));
+ if (0 == length)
+ return NULL;
+
+ const wchar_t *fileName = PathFindFileName(buffer);
+ length = lstrlenW(fileName);
+ processName_ = (wchar_t *)calloc((length + 1), sizeof(wchar_t));
+ if (NULL == processName_)
+ return NULL;
+
+ memcpy(processName_, fileName, sizeof(wchar_t)*length);
+ processName_[length]=L'\0';
+ }
+
+ return processName_;
+}
+
+HRESULT InternetFeatures::SetEnabled(INTERNETFEATURELIST FeatureEntry, DWORD dwFlags, BOOL fEnable)
+{
+ HRESULT hr = LoadModule();
+ if (FAILED(hr)) return hr;
+ if (NULL == CoInternetSetFeatureEnabled) return E_NOINTERFACE;
+ return CoInternetSetFeatureEnabled(FeatureEntry, dwFlags, fEnable);
+}
+
+HRESULT InternetFeatures::IsEnabled(INTERNETFEATURELIST FeatureEntry, DWORD dwFlags)
+{
+ HRESULT hr = LoadModule();
+ if (FAILED(hr)) return hr;
+ if (NULL == CoInternetIsFeatureEnabled) return E_NOINTERFACE;
+ return CoInternetIsFeatureEnabled(FeatureEntry, dwFlags);
+}
+
+HRESULT InternetFeatures::SetDWORDFeature(const wchar_t *featureName, BOOL perUser, unsigned long value)
+{
+ if (NULL == featureName
+ || L'\0' == *featureName)
+ {
+ return E_INVALIDARG;
+ }
+
+ const wchar_t *processName = GetProcessName();
+ if (NULL == processName)
+ return E_UNEXPECTED;
+
+ HKEY rootKey = (FALSE != perUser) ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
+ HKEY key = NULL;
+ unsigned long disposition = 0;
+ long errorCode = 0;
+ HRESULT result = S_OK;
+
+ wchar_t buffer[MAX_PATH] = {0};
+ if (FAILED(StringCchPrintf(buffer, ARRAYSIZE(buffer),
+ REGISTRY_FEATURE_CONTROL L"\\" L"%s",
+ featureName)))
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ errorCode = RegCreateKeyEx(rootKey, buffer,
+ NULL, NULL, REG_OPTION_VOLATILE, KEY_WRITE,
+ NULL, &key, &disposition);
+
+ if (ERROR_SUCCESS != errorCode)
+ return HRESULT_FROM_WIN32(errorCode);
+
+ errorCode = RegSetValueEx(key, processName, 0, REG_DWORD, (const BYTE*)&value,
+ sizeof(unsigned long));
+
+ if (ERROR_SUCCESS != errorCode)
+ {
+ result = HRESULT_FROM_WIN32(errorCode);
+ }
+ else
+ {
+ result = S_OK;
+ }
+
+ RegCloseKey(key);
+
+ return result;
+}
+
+HRESULT InternetFeatures::GetDWORDFeature(const wchar_t *featureName, BOOL perUser, unsigned long *value)
+{
+ if (NULL == featureName
+ || L'\0' == *featureName)
+ {
+ return E_INVALIDARG;
+ }
+
+ if (NULL == value)
+ return E_POINTER;
+
+ const wchar_t *processName = GetProcessName();
+ if (NULL == processName)
+ return E_UNEXPECTED;
+
+ HKEY rootKey = (FALSE != perUser) ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
+ HKEY key = NULL;
+ long errorCode = 0;
+ HRESULT result = S_OK;
+ unsigned long valueType = 0;
+ unsigned long valueSize = 0;
+
+ wchar_t buffer[MAX_PATH] = {0};
+ if (FAILED(StringCchPrintf(buffer, ARRAYSIZE(buffer),
+ REGISTRY_FEATURE_CONTROL L"\\" L"%s",
+ featureName)))
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ errorCode = RegOpenKeyEx(rootKey, buffer, 0, KEY_READ, &key);
+ if (ERROR_SUCCESS != errorCode)
+ return HRESULT_FROM_WIN32(errorCode);
+
+ valueSize = sizeof(unsigned long);
+
+ errorCode = RegQueryValueEx(key, processName, 0, &valueType,
+ (BYTE*)value, &valueSize);
+
+ if (ERROR_SUCCESS != errorCode)
+ {
+ result = HRESULT_FROM_WIN32(errorCode);
+ }
+ else
+ {
+ if (REG_DWORD != valueType)
+ result = E_UNEXPECTED;
+ else
+ result = S_OK;
+ }
+
+ RegCloseKey(key);
+
+ return result;
+}
+
+void InternetFeatures::DeleteFeature(const wchar_t *featureName, BOOL perUser)
+{
+ if (NULL == featureName
+ || L'\0' == *featureName)
+ {
+ return;
+ }
+
+ const wchar_t *processName = GetProcessName();
+ if (NULL == processName)
+ return;
+
+ HKEY rootKey = (FALSE != perUser) ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
+ HKEY key = NULL;
+ long errorCode = 0;
+
+ wchar_t buffer[MAX_PATH] = {0};
+ if (FAILED(StringCchPrintf(buffer, ARRAYSIZE(buffer),
+ REGISTRY_FEATURE_CONTROL L"\\" L"%s",
+ featureName)))
+ {
+ return;
+ }
+
+ errorCode = RegOpenKeyEx(rootKey, buffer, 0, KEY_WRITE, &key);
+ if (ERROR_SUCCESS != errorCode)
+ return;
+
+ RegDeleteValue(key, processName);
+ RegCloseKey(key);
+} \ No newline at end of file
diff --git a/Src/omBrowser/internetFeatures.h b/Src/omBrowser/internetFeatures.h
new file mode 100644
index 00000000..922aa880
--- /dev/null
+++ b/Src/omBrowser/internetFeatures.h
@@ -0,0 +1,65 @@
+#ifndef NULLSOFT_WINAMP_INTERNET_FEATURES_HELPER_HEADER
+#define NULLSOFT_WINAMP_INTERNET_FEATURES_HELPER_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+#include <urlmon.h>
+
+#ifndef FEATURE_TABBED_BROWSING
+ #define FEATURE_TABBED_BROWSING ((INTERNETFEATURELIST)19)
+#endif //FEATURE_TABBED_BROWSING
+
+#ifndef FEATURE_SSLUX
+ #define FEATURE_SSLUX ((INTERNETFEATURELIST)20)
+#endif // FEATURE_SSLUX
+
+#ifndef FEATURE_DISABLE_NAVIGATION_SOUNDS
+ #define FEATURE_DISABLE_NAVIGATION_SOUNDS ((INTERNETFEATURELIST)21)
+#endif // FEATURE_DISABLE_NAVIGATION_SOUNDS
+
+#ifndef FEATURE_DISABLE_LEGACY_COMPRESSION
+ #define FEATURE_DISABLE_LEGACY_COMPRESSION ((INTERNETFEATURELIST)22)
+#endif // FEATURE_DISABLE_LEGACY_COMPRESSION
+
+#ifndef FEATURE_FORCE_ADDR_AND_STATUS
+ #define FEATURE_FORCE_ADDR_AND_STATUS ((INTERNETFEATURELIST)23)
+#endif //FEATURE_FORCE_ADDR_AND_STATUS
+
+#ifndef FEATURE_BLOCK_INPUT_PROMPTS
+ #define FEATURE_BLOCK_INPUT_PROMPTS ((INTERNETFEATURELIST)27)
+#endif //FEATURE_BLOCK_INPUT_PROMPTS
+
+class InternetFeatures
+{
+public:
+ InternetFeatures();
+ ~InternetFeatures();
+
+public:
+ HRESULT SetEnabled(INTERNETFEATURELIST FeatureEntry, DWORD dwFlags, BOOL fEnable);
+ HRESULT IsEnabled(INTERNETFEATURELIST FeatureEntry, DWORD dwFlags);
+
+ HRESULT SetDWORDFeature(const wchar_t *featureName, BOOL perUser, unsigned long value);
+ HRESULT GetDWORDFeature(const wchar_t *featureName, BOOL perUser, unsigned long *value);
+ void DeleteFeature(const wchar_t *featureName, BOOL perUser);
+
+protected:
+ HRESULT LoadModule();
+ const wchar_t *GetProcessName();
+
+private:
+ typedef HRESULT (WINAPI *COINTERNETSETFEATUREENABLED)(INTERNETFEATURELIST /*FeatureEntry*/, DWORD /*dwFlags*/, BOOL /*fEnable*/);
+ typedef HRESULT (WINAPI *COINTERNETISFEATUREENABLED)(INTERNETFEATURELIST /*FeatureEntry*/, DWORD /*dwFlags*/);
+
+private:
+ HMODULE module;
+ HRESULT loadResult;
+ COINTERNETSETFEATUREENABLED CoInternetSetFeatureEnabled;
+ COINTERNETISFEATUREENABLED CoInternetIsFeatureEnabled;
+ wchar_t *processName_;
+};
+
+#endif NULLSOFT_WINAMP_INTERNET_FEATURES_HELPER_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/loaderIni.cpp b/Src/omBrowser/loaderIni.cpp
new file mode 100644
index 00000000..63c55cad
--- /dev/null
+++ b/Src/omBrowser/loaderIni.cpp
@@ -0,0 +1,657 @@
+#include "main.h"
+#include "./loaderIni.h"
+#include "./service.h"
+#include "./ifc_wasabihelper.h"
+#include "./ifc_omservicehost.h"
+#include "./ifc_omstorage.h"
+#include "./ifc_omstoragehandler.h"
+#include "./ifc_omstoragehandlerenum.h"
+
+#include <shlwapi.h>
+#include <strsafe.h>
+
+#define OMS_GROUP "OnlineService"
+#define OMS_ID "id"
+#define OMS_NAME "name"
+#define OMS_URL "url"
+#define OMS_ICON "icon"
+#define OMS_FLAGS "flags"
+#define OMS_RATING "rating"
+#define OMS_VERSION "version"
+#define OMS_DESCRIPTION "description"
+#define OMS_AUTHORFIRST "authorFirst"
+#define OMS_AUTHORLAST "authorLast"
+#define OMS_PUBLISHED "publishedDate"
+#define OMS_UPDATED "updatedDate"
+#define OMS_THUMBNAIL "thumbnail"
+#define OMS_SCREENSHOT "screenshot"
+#define OMS_GENERATION "generation"
+
+typedef HRESULT (ifc_omservice::*SVCSTRGET)(LPWSTR, UINT);
+typedef HRESULT (ifc_omservice::*SVCUINTGET)(UINT*);
+typedef HRESULT (ifc_omservicedetails::*DETAILGET)(LPWSTR, UINT);
+
+#define WRITE_OBJECT_STR(__mofifiedFlag, __class, __getterType, __object, __getter, __key)\
+ {if (0 != (ifc_omserviceeditor::##__mofifiedFlag & modified)) {\
+ HRESULT r = WriteObjectStr<__class, __getterType>((__key), (__object), &##__class::##__getter);\
+ if (FAILED(r)) {hr = E_FAIL;} else { saved |= ifc_omserviceeditor::##__mofifiedFlag; }}}
+
+#define WRITE_OBJECT_STR_FALLBACK(__mofifiedFlag, __class, __getterType, __object, __getter1, __getter2, __key)\
+ {if (0 != (ifc_omserviceeditor::##__mofifiedFlag & modified)) {\
+ HRESULT r = WriteObjectStr<__class, __getterType>((__key), (__object), &##__class::##__getter1);\
+ if (S_FALSE == r) r = WriteObjectStr<__class, __getterType>((__key), (__object), &##__class::##__getter2);\
+ if (FAILED(r)) {hr = E_FAIL;} else { saved |= ifc_omserviceeditor::##__mofifiedFlag; }}}
+
+#define WRITE_OBJECT_UINT(__mofifiedFlag, __class, __getterType, __object, __getter, __key, __writeFlags)\
+ {if (0 != (ifc_omserviceeditor::##__mofifiedFlag & modified)) {\
+ HRESULT r = WriteObjectUInt<__class, __getterType>((__key), (__object), &##__class::##__getter, __writeFlags);\
+ if (FAILED(r)) {hr = E_FAIL;} else { saved |= ifc_omserviceeditor::##__mofifiedFlag; }}}
+
+#define WRITE_SERVICE_STR(__mofifiedFlag, __getter, __key) WRITE_OBJECT_STR(__mofifiedFlag, ifc_omservice, SVCSTRGET, service, __getter, __key)
+#define WRITE_SERVICE_STR_FALLBACK(__mofifiedFlag, __getter1, __getter2, __key) WRITE_OBJECT_STR_FALLBACK(__mofifiedFlag, ifc_omservice, SVCSTRGET, service, __getter1, __getter2, __key)
+#define WRITE_SERVICE_UINT(__mofifiedFlag, __getter, __key, __writeZero) WRITE_OBJECT_UINT(__mofifiedFlag, ifc_omservice, SVCUINTGET, service, __getter, __key, __writeZero)
+#define WRITE_DETAILS_STR(__mofifiedFlag, __getter, __key) WRITE_OBJECT_STR(__mofifiedFlag, ifc_omservicedetails, DETAILGET, details, __getter, __key)
+
+LoaderIni::LoaderIni()
+ : bufferAnsi(NULL), bufferAnsiMax(0), buffer(NULL), bufferMax(0), handlerEnum(NULL)
+{
+ memset(pathAnsi, 0, sizeof(pathAnsi));
+}
+
+LoaderIni::~LoaderIni()
+{
+ //Plugin_FreeAnsiString(pathAnsi);
+ Plugin_FreeAnsiString(bufferAnsi);
+ Plugin_FreeString(buffer);
+
+ if (NULL != handlerEnum)
+ handlerEnum->Release();
+}
+
+HRESULT LoaderIni::Load(LPCWSTR pszAddress, ifc_omservicehost *host, ifc_omservice **serviceOut)
+{
+ if (NULL == serviceOut)
+ return E_POINTER;
+
+ *serviceOut = NULL;
+
+ HRESULT hr = MakeAnsiPath(pszAddress);
+ if (FAILED(hr)) return hr;
+
+ UINT id = ReadInt(OMS_ID, 0);
+ if (0 == id) return E_UNEXPECTED;
+
+ OmService *service;
+
+ hr = OmService::CreateInstance(id, host, &service);
+ if (FAILED(hr)) return hr;
+
+ ifc_omserviceeditor *editor;
+ if (SUCCEEDED(service->QueryInterface(IFC_OmServiceEditor, (void**)&editor)))
+ editor->BeginUpdate();
+ else
+ editor = NULL;
+
+ service->SetAddress(pszAddress);
+
+ #define READ_SERVICE_STR(__key, __putter)\
+ { LPCSTR value; HRESULT r = ReadAnsi((__key), NULL, &value);\
+ if (SUCCEEDED(r)) { if ('\0' != *value) r = service->##__putter((LPCWSTR)value, TRUE); }\
+ if (FAILED(r)) hr = E_FAIL;}
+
+ READ_SERVICE_STR(OMS_NAME, SetName);
+ READ_SERVICE_STR(OMS_URL, SetUrl);
+ READ_SERVICE_STR(OMS_ICON, SetIcon);
+
+ UINT val = ReadInt(OMS_FLAGS, 0);
+ if (0 != val) service->SetFlags(val, val & ~ifc_omservice::RuntimeFlagsMask);
+
+ val = ReadInt(OMS_RATING, 0);
+ if (0 != val) service->SetRating(val);
+
+ val = ReadInt(OMS_VERSION, 0);
+ if (0 != val) service->SetVersion(val);
+
+ val = ReadInt(OMS_GENERATION, 0);
+ if (0 != val) service->SetGeneration(val);
+
+ READ_SERVICE_STR(OMS_DESCRIPTION, SetDescription);
+ READ_SERVICE_STR(OMS_AUTHORFIRST, SetAuthorFirst);
+ READ_SERVICE_STR(OMS_AUTHORLAST, SetAuthorLast);
+ READ_SERVICE_STR(OMS_PUBLISHED, SetPublished);
+ READ_SERVICE_STR(OMS_UPDATED, SetUpdated);
+ READ_SERVICE_STR(OMS_THUMBNAIL, SetThumbnail);
+ READ_SERVICE_STR(OMS_SCREENSHOT, SetScreenshot);
+
+ if (NULL != handlerEnum)
+ {
+ handlerEnum->Reset();
+ ifc_omstoragehandler *storageHandler;
+ while (S_OK == handlerEnum->Next(1, &storageHandler, NULL))
+ {
+ LPCWSTR pszKey;
+ if (SUCCEEDED(storageHandler->GetKey(&pszKey)))
+ {
+ if (SUCCEEDED(WideCharToAnsiBuffer(CP_UTF8, 0, pszKey, -1, NULL, NULL)))
+ {
+ LPCSTR keyAnsi = bufferAnsi;
+ LPCSTR valueAnsi;
+ if (SUCCEEDED(ReadAnsi(keyAnsi, NULL, &valueAnsi)) &&
+ NULL != valueAnsi && L'\0' != *valueAnsi)
+ {
+ if (SUCCEEDED(MultiByteToBuffer(CP_UTF8, 0, valueAnsi, -1)))
+ storageHandler->Invoke(service, pszKey, buffer);
+ }
+ }
+ }
+ storageHandler->Release();
+ }
+ }
+
+ if (NULL != editor)
+ {
+ editor->SetModified(0, ((UINT)-1));
+ editor->EndUpdate();
+ editor->Release();
+ }
+
+ *serviceOut = service;
+
+ return hr;
+}
+
+HRESULT LoaderIni::Reload(ifc_omservice *service)
+{
+ if (NULL == service)
+ return E_INVALIDARG;
+
+ HRESULT hr = RequestBuffer(&buffer, &bufferMax, MAX_PATH * 2);
+ if (FAILED(hr)) return hr;
+
+ hr = service->GetAddress(buffer, bufferMax);
+ if (FAILED(hr)) return hr;
+ if (L'\0' == *buffer) return E_UNEXPECTED;
+
+ hr = MakeAnsiPath(buffer);
+ if (FAILED(hr)) return hr;
+
+ UINT id = ReadInt(OMS_ID, 0);
+ if (id != service->GetId()) return E_UNEXPECTED;
+
+ ifc_omserviceeditor *editor;
+ hr = service->QueryInterface(IFC_OmServiceEditor, (void**)&editor);
+ if (SUCCEEDED(hr))
+ {
+ #define READ_EDITOR_STR(__key, __putter)\
+ { LPCSTR value; HRESULT r = ReadAnsi((__key), NULL, &value);\
+ if (SUCCEEDED(r)) { r = editor->##__putter((LPCWSTR)value, TRUE); }\
+ if (FAILED(r)) hr = E_FAIL;}
+
+ editor->BeginUpdate();
+
+ READ_EDITOR_STR(OMS_NAME, SetName);
+ READ_EDITOR_STR(OMS_URL, SetUrl);
+ READ_EDITOR_STR(OMS_ICON, SetIcon);
+
+ UINT val;
+ val = ReadInt(OMS_FLAGS, 0);
+ editor->SetFlags(val, val & ~ifc_omservice::RuntimeFlagsMask);
+
+ val = ReadInt(OMS_RATING, 0);
+ editor->SetRating(val);
+
+ val = ReadInt(OMS_VERSION, 0);
+ editor->SetVersion(val);
+
+ val = ReadInt(OMS_GENERATION, 0);
+ editor->SetGeneration(val);
+
+ READ_EDITOR_STR(OMS_DESCRIPTION, SetDescription);
+ READ_EDITOR_STR(OMS_AUTHORFIRST, SetAuthorFirst);
+ READ_EDITOR_STR(OMS_AUTHORLAST, SetAuthorLast);
+ READ_EDITOR_STR(OMS_PUBLISHED, SetPublished);
+ READ_EDITOR_STR(OMS_UPDATED, SetUpdated);
+ READ_EDITOR_STR(OMS_THUMBNAIL, SetThumbnail);
+ READ_EDITOR_STR(OMS_SCREENSHOT, SetScreenshot);
+ }
+ else
+ {
+ editor = NULL;
+ }
+
+ if (NULL != handlerEnum)
+ {
+ handlerEnum->Reset();
+ ifc_omstoragehandler *storageHandler;
+ while (S_OK == handlerEnum->Next(1, &storageHandler, NULL))
+ {
+ LPCWSTR pszKey;
+ if (SUCCEEDED(storageHandler->GetKey(&pszKey)))
+ {
+ if (SUCCEEDED(WideCharToAnsiBuffer(CP_UTF8, 0, pszKey, -1, NULL, NULL)))
+ {
+ LPCSTR keyAnsi = bufferAnsi;
+ LPCSTR valueAnsi;
+ if (SUCCEEDED(ReadAnsi(keyAnsi, NULL, &valueAnsi)) &&
+ NULL != valueAnsi && L'\0' != *valueAnsi)
+ {
+ if (SUCCEEDED(MultiByteToBuffer(CP_UTF8, 0, valueAnsi, -1)))
+ storageHandler->Invoke(service, pszKey, buffer);
+ }
+ }
+ }
+ storageHandler->Release();
+ }
+ }
+
+ if (NULL != editor)
+ {
+ editor->EndUpdate();
+ editor->Release();
+ }
+
+ return hr;
+}
+
+HRESULT LoaderIni::Save(ifc_omservice *service, UINT flags)
+{
+ if(NULL == service)
+ return E_INVALIDARG;
+
+ HRESULT hr;
+ BOOL generatedName;
+
+ hr = RequestBuffer(&buffer, &bufferMax, MAX_PATH * 2);
+ if (FAILED(hr)) return hr;
+
+ hr = GetServicePath(service, buffer, bufferMax, &generatedName);
+ if (FAILED(hr)) return hr;
+
+ if (FALSE != generatedName)
+ service->SetAddress(buffer);
+
+ hr = MakeAnsiPath(buffer);
+ if (FAILED(hr)) return hr;
+
+ if (0 == (ifc_omstorage::saveModifiedOnly & flags))
+ WritePrivateProfileSectionA(OMS_GROUP, NULL, pathAnsi);
+
+ UINT modified = ((UINT)-1);
+ UINT saved = 0;
+ if (0 != (ifc_omstorage::saveModifiedOnly & flags))
+ {
+ ifc_omserviceeditor *editor;
+ if (SUCCEEDED(service->QueryInterface(IFC_OmServiceEditor, (void**)&editor)))
+ {
+ editor->GetModified(&modified);
+ editor->Release();
+
+ if (0 == modified)
+ return S_FALSE;
+ }
+ }
+
+ if (FAILED(WriteUint(OMS_ID, service->GetId(), flagWriteZero)))
+ return E_FAIL;
+
+ WRITE_SERVICE_STR(modifiedName, GetName, OMS_NAME);
+ WRITE_SERVICE_STR_FALLBACK(modifiedUrl, GetUrlDirect, GetUrl, OMS_URL);
+ WRITE_SERVICE_STR(modifiedIcon, GetIcon, OMS_ICON);
+
+ if (0 != (ifc_omserviceeditor::modifiedFlags & modified))
+ {
+ UINT val;
+ if (SUCCEEDED(service->GetFlags(&val)) && SUCCEEDED(WriteUint(OMS_FLAGS, val & ~ifc_omservice::RuntimeFlagsMask, flagHexMode)))
+ saved |= ifc_omserviceeditor::modifiedFlags;
+ }
+
+ WRITE_SERVICE_UINT(modifiedRating, GetRating, OMS_RATING, flagWriteNormal);
+ WRITE_SERVICE_UINT(modifiedVersion, GetVersion, OMS_VERSION, flagWriteNormal);
+ WRITE_SERVICE_UINT(modifiedGeneration, GetGeneration, OMS_GENERATION, flagWriteNormal);
+
+ ifc_omservicedetails *details;
+ if (SUCCEEDED(service->QueryInterface(IFC_OmServiceDetails, (void**)&details)))
+ {
+ WRITE_DETAILS_STR(modifiedDescription, GetDescription, OMS_DESCRIPTION);
+ WRITE_DETAILS_STR(modifiedAuthorFirst, GetAuthorFirst, OMS_AUTHORFIRST);
+ WRITE_DETAILS_STR(modifiedAuthorLast, GetAuthorLast, OMS_AUTHORLAST);
+ WRITE_DETAILS_STR(modifiedPublished, GetPublished, OMS_PUBLISHED);
+ WRITE_DETAILS_STR(modifiedUpdated, GetUpdated, OMS_UPDATED);
+ WRITE_DETAILS_STR(modifiedThumbnail, GetThumbnail, OMS_THUMBNAIL);
+ WRITE_DETAILS_STR(modifiedScreenshot, GetScreenshot, OMS_SCREENSHOT);
+ details->Release();
+ }
+
+ if (0 != (ifc_omstorage::saveClearModified & flags) && 0 != saved)
+ {
+ ifc_omserviceeditor *editor;
+ if (SUCCEEDED(service->QueryInterface(IFC_OmServiceEditor, (void**)&editor)))
+ {
+ editor->SetModified(0, saved);
+ editor->Release();
+ }
+ }
+
+ return hr;
+}
+
+HRESULT LoaderIni::RegisterHandlers(ifc_omstoragehandlerenum *enumerator)
+{
+ if (NULL != handlerEnum)
+ handlerEnum->Release();
+
+ handlerEnum = enumerator;
+ if (NULL != handlerEnum)
+ handlerEnum->AddRef();
+
+ return S_OK;
+}
+
+HRESULT LoaderIni::RequestAnsiBuffer(LPSTR *ppBuffer, UINT *pBufferMax, UINT requestSize)
+{
+ if (*pBufferMax >= requestSize)
+ return S_OK;
+
+ UINT size = (0 != *pBufferMax) ? (*pBufferMax * 2) : 128;
+ while (size < requestSize) size = size*2;
+
+ Plugin_FreeAnsiString(*ppBuffer);
+ *ppBuffer = Plugin_MallocAnsiString(size);
+ if (NULL == *ppBuffer)
+ {
+ *ppBuffer = 0;
+ *pBufferMax = 0;
+ return E_OUTOFMEMORY;
+ }
+
+ *pBufferMax = size;
+ return S_OK;
+}
+
+HRESULT LoaderIni::RequestBuffer(LPWSTR *ppBuffer, UINT *pBufferMax, UINT requestSize)
+{
+ if (*pBufferMax >= requestSize)
+ return S_OK;
+
+ UINT size = (0 != *pBufferMax) ? (*pBufferMax * 2) : 128;
+ while (size < requestSize) size = size*2;
+
+ Plugin_FreeString(*ppBuffer);
+ *ppBuffer = Plugin_MallocString(size);
+ if (NULL == *ppBuffer)
+ {
+ *ppBuffer = 0;
+ *pBufferMax = 0;
+ return E_OUTOFMEMORY;
+ }
+
+ *pBufferMax = size;
+ return S_OK;
+}
+
+HRESULT LoaderIni::MakeAnsiPath(LPCWSTR pszAddress)
+{
+ BOOL fUsedDefaultChar = FALSE;
+ WCHAR szShort[MAX_PATH] = {0};
+
+ UINT cch = WideCharToMultiByte(CP_ACP, 0, pszAddress, -1, NULL, 0, NULL, &fUsedDefaultChar);
+ if (0 == cch || FALSE != fUsedDefaultChar)
+ {
+ cch = GetShortPathName(pszAddress, szShort, ARRAYSIZE(szShort));
+ if (0 != cch)
+ {
+ pszAddress = szShort;
+ cch = WideCharToMultiByte(CP_ACP, 0, pszAddress, -1, NULL, 0, NULL, &fUsedDefaultChar);
+ }
+
+ if (0 == cch || FALSE != fUsedDefaultChar)
+ {
+ if (NULL != pathAnsi) *pathAnsi = L'\0';
+ return E_FAIL;
+ }
+ }
+
+ cch = WideCharToMultiByte(CP_ACP, 0, pszAddress, cch, pathAnsi, MAX_PATH, NULL, NULL);
+ if (0 == cch)
+ {
+ DWORD errorCode = GetLastError();
+ *pathAnsi = L'\0';
+ return HRESULT_FROM_WIN32(errorCode);
+ }
+ pathAnsi[cch] = '\0';
+ return S_OK;
+}
+
+HRESULT LoaderIni::GetServicePath(ifc_omservice *service, LPWSTR pszBuffer, UINT cchBufferMax, BOOL *fGenerated)
+{
+ if (NULL == pszBuffer) return E_POINTER;
+ pszBuffer[0] = L'\0';
+
+ if (NULL == service) return E_INVALIDARG;
+
+ HRESULT hr;
+ WCHAR szPath[MAX_PATH * 2] = {0};
+ hr = service->GetAddress(szPath, ARRAYSIZE(szPath));
+ if (FAILED(hr)) return hr;
+
+ ifc_omservicehost *host = NULL;
+ ifc_omservicehostext *hostExt;
+ if (SUCCEEDED(service->QueryInterface(IFC_OmServiceHostExt, (void**)&hostExt)))
+ {
+ if (FAILED(hostExt->GetHost(&host)))
+ host = NULL;
+ hostExt->Release();
+ }
+
+ BOOL nameGenerated = FALSE;
+ if (L'\0' == *szPath)
+ {
+ hr = (NULL != host) ?
+ host->GetDefaultName(service, szPath, ARRAYSIZE(szPath)) :
+ StringCchPrintf(szPath, ARRAYSIZE(szPath), L"omService_{%010u}", service->GetId());
+
+ if (L'\0' == *szPath)
+ hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+
+ nameGenerated = TRUE;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = Plugin_ResolveRelativePath(szPath, host, pszBuffer, cchBufferMax);
+ if (SUCCEEDED(hr) && FALSE != nameGenerated)
+ {
+ LPWSTR pExt = PathFindExtension(pszBuffer);
+ if (pExt != pszBuffer && L'.' == *pExt && SUCCEEDED(StringCchCopy(szPath, ARRAYSIZE(szPath), pExt)))
+ {
+ UINT pExtMax = cchBufferMax - (UINT)(pExt - pszBuffer);
+ UINT attempt = 0;
+ while (FALSE != PathFileExists(pszBuffer))
+ {
+ if (FAILED(StringCchPrintf(pExt, pExtMax, L"(%u)%s", ++attempt, szPath)))
+ {
+ StringCchCopy(pExt, pExtMax, szPath);
+ break;
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) && SUCCEEDED(StringCchCopy(szPath, ARRAYSIZE(szPath), pszBuffer)))
+ {
+ PathRemoveFileSpec(szPath);
+ Plugin_EnsurePathExist(szPath);
+ }
+ }
+
+ if (FAILED(hr))
+ pszBuffer[0] = L'\0';
+
+ if (NULL != host)
+ host->Release();
+
+ if (NULL != fGenerated)
+ *fGenerated = nameGenerated;
+
+ return hr;
+}
+
+HRESULT LoaderIni::WideCharToAnsiBuffer(UINT codePage, DWORD flags, LPCWSTR pszWideChar, INT cchWideChar, LPCSTR pDefaultChar, BOOL *pUsedDefaultChar)
+{
+ UINT cch = WideCharToMultiByte(codePage, flags, pszWideChar, cchWideChar, NULL, 0, pDefaultChar, pUsedDefaultChar);
+ if (0 == cch)
+ {
+ DWORD errorCode = GetLastError();
+ return HRESULT_FROM_WIN32(errorCode);
+ }
+
+ HRESULT hr = RequestAnsiBuffer(&bufferAnsi, &bufferAnsiMax, cch);
+ if (FAILED(hr)) return hr;
+
+ if (0 == WideCharToMultiByte(codePage, flags, pszWideChar, cchWideChar, bufferAnsi, bufferAnsiMax, pDefaultChar, pUsedDefaultChar))
+ {
+ DWORD errorCode = GetLastError();
+ return HRESULT_FROM_WIN32(errorCode);
+ }
+
+ return S_OK;
+}
+
+HRESULT LoaderIni::MultiByteToBuffer(UINT codePage, DWORD flags, LPCSTR pszMultiByte, INT cbMultiByte)
+{
+ UINT cch = MultiByteToWideChar(codePage, flags, pszMultiByte, cbMultiByte, NULL, 0);
+ if (0 == cch)
+ {
+ DWORD errorCode = GetLastError();
+ return HRESULT_FROM_WIN32(errorCode);
+ }
+
+ HRESULT hr = RequestBuffer(&buffer, &bufferMax, cch);
+ if (FAILED(hr)) return hr;
+
+ if (0 == MultiByteToWideChar(codePage, flags, pszMultiByte, cbMultiByte, buffer, bufferMax))
+ {
+ DWORD errorCode = GetLastError();
+ return HRESULT_FROM_WIN32(errorCode);
+ }
+
+ return S_OK;
+}
+
+HRESULT LoaderIni::Write(LPCSTR pszKey, LPCWSTR pszValue)
+{
+ LPCSTR valueAnsi;
+ if (NULL == pszValue) valueAnsi = NULL;
+ else if (L'\0' == *pszValue) valueAnsi = '\0';
+ else
+ {
+ HRESULT hr = WideCharToAnsiBuffer(CP_UTF8, 0, pszValue, -1, NULL, NULL);
+ if (FAILED(hr)) return hr;
+ valueAnsi = bufferAnsi;
+ }
+
+ return WriteAnsi(pszKey, valueAnsi);
+}
+
+HRESULT LoaderIni::WriteAnsi(LPCSTR pszKey, LPCSTR pszValue)
+{
+ if (FALSE == WritePrivateProfileStringA(OMS_GROUP, pszKey, pszValue, pathAnsi))
+ {
+ DWORD errorCode = GetLastError();
+ return HRESULT_FROM_WIN32(errorCode);
+ }
+ return S_OK;
+}
+
+HRESULT LoaderIni::WriteUint(LPCSTR pszKey, UINT uValue, UINT flags)
+{
+ HRESULT hr;
+ CHAR szBuffer[16] = {0}, *pVal;
+
+ if (0 == uValue && 0 == (flagWriteZero & flags))
+ {
+ hr = S_OK;
+ pVal = NULL;
+ }
+ else
+ {
+ hr = StringCchPrintfA(szBuffer, ARRAYSIZE(szBuffer), ((0 == (flagHexMode & flags)) ? "%u" : "0x%08X"), uValue);
+ pVal = szBuffer;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = WriteAnsi(pszKey, pVal);
+ }
+ return hr;
+}
+
+HRESULT LoaderIni::ReadAnsi(LPCSTR pszKey, LPCSTR pszDefault, LPCSTR *ppszValue)
+{
+ HRESULT hr;
+ if (NULL == bufferAnsi)
+ {
+ hr = RequestAnsiBuffer(&bufferAnsi, &bufferAnsiMax, 2);
+ if (FAILED(hr))
+ {
+ *ppszValue = pszDefault;
+ return hr;
+ }
+ }
+
+ for(;;)
+ {
+ UINT copied = GetPrivateProfileStringA(OMS_GROUP, pszKey, pszDefault, bufferAnsi, bufferAnsiMax, pathAnsi);
+ if (copied != bufferAnsiMax - 1) break;
+
+ hr = RequestAnsiBuffer(&bufferAnsi, &bufferAnsiMax, bufferAnsiMax * 2);
+ if (FAILED(hr))
+ {
+ *ppszValue = pszDefault;
+ return hr;
+ }
+
+ }
+ *ppszValue = bufferAnsi;
+ return S_OK;
+}
+
+UINT LoaderIni::ReadInt(LPCSTR pszKey, UINT nDefault)
+{
+ return GetPrivateProfileIntA(OMS_GROUP, pszKey, nDefault, pathAnsi);
+}
+
+template <class Object, class Getter>
+HRESULT LoaderIni::WriteObjectStr(LPCSTR pszKey, Object *object, Getter getter)
+{
+ HRESULT hr;
+
+ if (NULL == buffer)
+ {
+ hr = RequestBuffer(&buffer, &bufferMax, 256);
+ if (FAILED(hr)) return hr;
+ }
+ for (;;)
+ {
+ hr = (object->*getter)(buffer, bufferMax);
+ if (SUCCEEDED(hr)) break;
+ if (E_NOTIMPL == hr) return S_FALSE;
+ if (OMSVC_E_INSUFFICIENT_BUFFER != hr) return hr;
+
+ hr = RequestBuffer(&buffer, &bufferMax, bufferMax * 2);
+ if (FAILED(hr)) return hr;
+ }
+ return Write(pszKey, buffer);
+}
+
+template <class Object, class Getter>
+HRESULT LoaderIni::WriteObjectUInt(LPCSTR pszKey, Object *object, Getter getter, UINT flags)
+{
+ UINT val;
+ HRESULT hr = (object->*getter)(&val);
+ if (FAILED(hr))
+ {
+ return (E_NOTIMPL == hr) ? S_FALSE : hr;
+ }
+ return WriteUint(pszKey, val, flags);
+} \ No newline at end of file
diff --git a/Src/omBrowser/loaderIni.h b/Src/omBrowser/loaderIni.h
new file mode 100644
index 00000000..d7a329a9
--- /dev/null
+++ b/Src/omBrowser/loaderIni.h
@@ -0,0 +1,63 @@
+#ifndef NULLSOFT_WINAMP_LOADER_INI_HEADER
+#define NULLSOFT_WINAMP_LOADER_INI_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <bfc/dispatch.h>
+class ifc_omservice;
+class ifc_omservicehost;
+class ifc_omstoragehandlerenum;
+
+class LoaderIni
+{
+public:
+ typedef enum
+ {
+ flagWriteNormal = 0x00000000,
+ flagWriteZero = 0x00000001,
+ flagHexMode = 0x00000002,
+ } WriteFlags;
+public:
+ LoaderIni();
+ ~LoaderIni();
+
+public:
+ HRESULT Load(LPCWSTR pszAddress, ifc_omservicehost *host, ifc_omservice **serviceOut);
+ HRESULT Reload(ifc_omservice *service);
+ HRESULT Save(ifc_omservice *service, UINT flags);
+ HRESULT RegisterHandlers(ifc_omstoragehandlerenum *enumerator);
+
+private:
+ HRESULT RequestAnsiBuffer(LPSTR *ppBuffer, UINT *pBufferMax, UINT requestSize);
+ HRESULT RequestBuffer(LPWSTR *ppBuffer, UINT *pBufferMax, UINT requestSize);
+ HRESULT MakeAnsiPath(LPCWSTR pszAddress);
+ HRESULT GetServicePath(ifc_omservice *service, LPWSTR pszBuffer, UINT cchBufferMax, BOOL *fGenerated);
+
+ HRESULT WideCharToAnsiBuffer(UINT codePage, DWORD flags, LPCWSTR pszWideChar, INT cchWideChar, LPCSTR pDefaultChar, BOOL *pUsedDefaultChar);
+ HRESULT MultiByteToBuffer( UINT codePage, DWORD flags, LPCSTR pszMultiByte, INT cbMultiByte);
+
+ HRESULT Write(LPCSTR pszKey, LPCWSTR pszValue);
+ HRESULT WriteAnsi(LPCSTR pszKey, LPCSTR pszValue);
+ HRESULT WriteUint(LPCSTR pszKey, UINT uValue, UINT flags);
+ HRESULT ReadAnsi(LPCSTR pszKey, LPCSTR pszDefault, LPCSTR *ppszValue);
+ UINT ReadInt(LPCSTR pszKey, UINT nDefault);
+
+private:
+ template <class Object, class Getter>
+ HRESULT WriteObjectStr(LPCSTR pszKey, Object *object, Getter getter);
+
+ template <class Object, class Getter>
+ HRESULT WriteObjectUInt(LPCSTR pszKey, Object *object, Getter getter, UINT flags);
+
+protected:
+ CHAR pathAnsi[MAX_PATH];
+ LPSTR bufferAnsi;
+ UINT bufferAnsiMax;
+ LPWSTR buffer;
+ UINT bufferMax;
+ ifc_omstoragehandlerenum *handlerEnum;
+};
+
+#endif //NULLSOFT_WINAMP_LOADER_INI_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/localization/localization.vcproj b/Src/omBrowser/localization/localization.vcproj
new file mode 100644
index 00000000..b20ee25c
--- /dev/null
+++ b/Src/omBrowser/localization/localization.vcproj
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="localization"
+ ProjectGUID="{F5D8D737-1C1E-4967-B7FC-74FABB806926}"
+ RootNamespace="localization"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(InputDir)\bin"
+ IntermediateDirectory="intermediate"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ LinkLibraryDependencies="false"
+ OutputFile="$(OutDir)\omBrowser.lng"
+ GenerateManifest="false"
+ IgnoreAllDefaultLibraries="true"
+ GenerateDebugInformation="false"
+ LargeAddressAware="1"
+ TerminalServerAware="0"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ LinkTimeCodeGeneration="0"
+ ResourceOnlyDLL="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="1"
+ TurnOffAssemblyGeneration="true"
+ TargetMachine="1"
+ CLRImageType="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath="..\errorPages.rc"
+ >
+ </File>
+ <File
+ RelativePath="..\omBrowser.rc"
+ >
+ </File>
+ <File
+ RelativePath="..\resource.h"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Src/omBrowser/localization/localization.vcxproj b/Src/omBrowser/localization/localization.vcxproj
new file mode 100644
index 00000000..dd9f9dde
--- /dev/null
+++ b/Src/omBrowser/localization/localization.vcxproj
@@ -0,0 +1,256 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{F5D8D737-1C1E-4967-B7FC-74FABB806926}</ProjectGuid>
+ <RootNamespace>localization</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\intermediate\</IntDir>
+ <IgnoreImportLibrary>true</IgnoreImportLibrary>
+ <GenerateManifest>false</GenerateManifest>
+ <TargetName>omBrowser</TargetName>
+ <TargetExt>.lng</TargetExt>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\intermediate\</IntDir>
+ <IgnoreImportLibrary>true</IgnoreImportLibrary>
+ <GenerateManifest>false</GenerateManifest>
+ <TargetName>omBrowser</TargetName>
+ <TargetExt>.lng</TargetExt>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\intermediate\</IntDir>
+ <IgnoreImportLibrary>true</IgnoreImportLibrary>
+ <GenerateManifest>false</GenerateManifest>
+ <TargetName>omBrowser</TargetName>
+ <TargetExt>.lng</TargetExt>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\intermediate\</IntDir>
+ <IgnoreImportLibrary>true</IgnoreImportLibrary>
+ <GenerateManifest>false</GenerateManifest>
+ <TargetName>omBrowser</TargetName>
+ <TargetExt>.lng</TargetExt>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg">
+ <VcpkgEnableManifest>false</VcpkgEnableManifest>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <ProjectReference>
+ <LinkLibraryDependencies>false</LinkLibraryDependencies>
+ </ProjectReference>
+ <Link>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <LargeAddressAware>false</LargeAddressAware>
+ <NoEntryPoint>true</NoEntryPoint>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>false</DataExecutionPrevention>
+ <TurnOffAssemblyGeneration>true</TurnOffAssemblyGeneration>
+ <TargetMachine>MachineX86</TargetMachine>
+ <CLRImageType>ForceIJWImage</CLRImageType>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <SubSystem>Windows</SubSystem>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <ProjectReference>
+ <LinkLibraryDependencies>false</LinkLibraryDependencies>
+ </ProjectReference>
+ <Link>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <LargeAddressAware>true</LargeAddressAware>
+ <NoEntryPoint>true</NoEntryPoint>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>false</DataExecutionPrevention>
+ <TurnOffAssemblyGeneration>true</TurnOffAssemblyGeneration>
+ <CLRImageType>ForceIJWImage</CLRImageType>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <SubSystem>Windows</SubSystem>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <ProjectReference>
+ <LinkLibraryDependencies>false</LinkLibraryDependencies>
+ </ProjectReference>
+ <Link>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <LargeAddressAware>false</LargeAddressAware>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <NoEntryPoint>true</NoEntryPoint>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>false</DataExecutionPrevention>
+ <TurnOffAssemblyGeneration>true</TurnOffAssemblyGeneration>
+ <TargetMachine>MachineX86</TargetMachine>
+ <CLRImageType>ForceIJWImage</CLRImageType>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <SubSystem>Windows</SubSystem>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <ProjectReference>
+ <LinkLibraryDependencies>false</LinkLibraryDependencies>
+ </ProjectReference>
+ <Link>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <LargeAddressAware>true</LargeAddressAware>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <NoEntryPoint>true</NoEntryPoint>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>false</DataExecutionPrevention>
+ <TurnOffAssemblyGeneration>true</TurnOffAssemblyGeneration>
+ <CLRImageType>ForceIJWImage</CLRImageType>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <SubSystem>Windows</SubSystem>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ResourceCompile Include="..\errorPages.rc" />
+ <ResourceCompile Include="..\omBrowser.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\resource.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/Src/omBrowser/localization/localization.vcxproj.filters b/Src/omBrowser/localization/localization.vcxproj.filters
new file mode 100644
index 00000000..5f4e00e6
--- /dev/null
+++ b/Src/omBrowser/localization/localization.vcxproj.filters
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ResourceCompile Include="..\errorPages.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ <ResourceCompile Include="..\omBrowser.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{4dc119ae-828b-48ee-93e4-b5fa4a6f67bd}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{46aec622-d9cd-417e-8107-3ab5f26d7345}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Src/omBrowser/main.cpp b/Src/omBrowser/main.cpp
new file mode 100644
index 00000000..693e0890
--- /dev/null
+++ b/Src/omBrowser/main.cpp
@@ -0,0 +1,662 @@
+#include "./main.h"
+#include "./component.h"
+#include "../nu/htmlcontainer2.h"
+#include "./ifc_wasabihelper.h"
+#include "./ifc_skinhelper.h"
+#include "./ifc_skinnedbrowser.h"
+#include "./pngLoader.h"
+#include "./ifc_omservicehost.h"
+
+#include <shlwapi.h>
+#include <strsafe.h>
+
+static HINSTANCE pluginInstance = NULL;
+static OmBrowserComponent component;
+
+LPWSTR Plugin_MallocString(size_t cchLen)
+{
+ return (LPWSTR)calloc(cchLen, sizeof(WCHAR));
+}
+
+void Plugin_FreeString(LPWSTR pszString)
+{
+ if (NULL != pszString)
+ {
+ free(pszString);
+ }
+}
+
+LPWSTR Plugin_ReAllocString(LPWSTR pszString, size_t cchLen)
+{
+ return (LPWSTR)realloc(pszString, sizeof(WCHAR) * cchLen);
+}
+
+LPWSTR Plugin_CopyString(LPCWSTR pszSource)
+{
+ if (NULL == pszSource)
+ return NULL;
+
+ INT cchSource = lstrlenW(pszSource) + 1;
+
+ LPWSTR copy = Plugin_MallocString(cchSource);
+ if (NULL != copy)
+ {
+ CopyMemory(copy, pszSource, sizeof(WCHAR) * cchSource);
+ }
+ return copy;
+}
+
+LPSTR Plugin_MallocAnsiString(size_t cchLen)
+{
+ return (LPSTR)calloc(cchLen, sizeof(CHAR));
+}
+
+LPSTR Plugin_CopyAnsiString(LPCSTR pszSource)
+{
+ if (NULL == pszSource)
+ return NULL;
+
+ INT cchSource = lstrlenA(pszSource) + 1;
+
+ LPSTR copy = Plugin_MallocAnsiString(cchSource);
+ if (NULL != copy)
+ {
+ CopyMemory(copy, pszSource, sizeof(CHAR) * cchSource);
+ }
+ return copy;
+}
+
+void Plugin_FreeAnsiString(LPSTR pszString)
+{
+ Plugin_FreeString((LPWSTR)pszString);
+}
+
+LPWSTR Plugin_DuplicateResString(LPCWSTR pszResource)
+{
+ return (IS_INTRESOURCE(pszResource)) ?
+ (LPWSTR)pszResource :
+ Plugin_CopyString(pszResource);
+}
+
+void Plugin_FreeResString(LPWSTR pszResource)
+{
+ if (!IS_INTRESOURCE(pszResource))
+ Plugin_FreeString(pszResource);
+}
+
+HRESULT Plugin_CopyResString(LPWSTR pszBuffer, INT cchBufferMax, LPCWSTR pszString)
+{
+ if (NULL == pszBuffer)
+ return E_INVALIDARG;
+
+ HRESULT hr = S_OK;
+
+ if (NULL == pszString)
+ {
+ pszBuffer[0] = L'\0';
+ }
+ else if (IS_INTRESOURCE(pszString))
+ {
+ Plugin_LoadString((INT)(INT_PTR)pszString, pszBuffer, cchBufferMax);
+ }
+ else
+ {
+ hr = StringCchCopy(pszBuffer, cchBufferMax, pszString);
+ }
+ return hr;
+}
+
+LPSTR Plugin_WideCharToMultiByte(UINT codePage, DWORD dwFlags, LPCWSTR lpWideCharStr, INT cchWideChar, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar)
+{
+ INT cchBuffer = WideCharToMultiByte(codePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar);
+ if (0 == cchBuffer) return NULL;
+
+ LPSTR buffer = Plugin_MallocAnsiString(cchBuffer);
+ if (NULL == buffer) return NULL;
+
+ if (0 == WideCharToMultiByte(codePage, dwFlags, lpWideCharStr, cchWideChar, buffer, cchBuffer, lpDefaultChar, lpUsedDefaultChar))
+ {
+ Plugin_FreeAnsiString(buffer);
+ return NULL;
+ }
+ return buffer;
+}
+
+LPWSTR Plugin_MultiByteToWideChar(UINT codePage, DWORD dwFlags, LPCSTR lpMultiByteStr, INT cbMultiByte)
+{
+ if (NULL == lpMultiByteStr) return NULL;
+ INT cchBuffer = MultiByteToWideChar(codePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0);
+ if (NULL == cchBuffer) return NULL;
+
+ if (cbMultiByte > 0) cchBuffer++;
+
+ LPWSTR buffer = Plugin_MallocString(cchBuffer);
+ if (NULL == buffer) return NULL;
+
+ if (0 == MultiByteToWideChar(codePage, dwFlags, lpMultiByteStr, cbMultiByte, buffer, cchBuffer))
+ {
+ Plugin_FreeString(buffer);
+ return NULL;
+ }
+
+ if (cbMultiByte > 0)
+ {
+ buffer[cchBuffer - 1] = L'\0';
+ }
+ return buffer;
+}
+
+HRESULT Plugin_Initialize(HWND hwndWinamp)
+{
+ return component.InitializeComponent(hwndWinamp);
+}
+
+HRESULT Plugin_GetWasabiHelper(ifc_wasabihelper **wasabiHelper)
+{
+ return component.GetWasabiHelper(wasabiHelper);
+}
+
+HRESULT Plugin_GetSkinHelper(ifc_skinhelper **skinHelper)
+{
+ return component.GetSkinHelper(skinHelper);
+}
+
+HRESULT Plugin_GetBrowserSkin(ifc_skinnedbrowser **skinnedBrowser)
+{
+ ifc_skinhelper *skin = NULL;
+ HRESULT hr = Plugin_GetSkinHelper(&skin);
+ if (FAILED(hr) || skin == NULL) return hr;
+
+ hr = skin->QueryInterface(IFC_SkinnedBrowser, (void**)skinnedBrowser);
+ skin->Release();
+ return hr;
+}
+
+HRESULT Plugin_GetWinampWnd(HWND *hwndWinamp)
+{
+ return component.GetWinampWnd(hwndWinamp);
+}
+
+
+HRESULT Plugin_RegisterWinampHook(ifc_winamphook *hook, UINT *cookieOut)
+{
+ return component.RegisterWinampHook(hook, cookieOut);
+}
+
+HRESULT Plugin_UnregisterWinampHook(UINT cookie)
+{
+ return component.UnregisterWinampHook(cookie);
+}
+
+
+HINSTANCE Plugin_GetInstance()
+{
+ return pluginInstance;
+}
+
+HINSTANCE Plugin_GetLangInstance()
+{
+ ifc_wasabihelper *wasabi = NULL;
+ if (FAILED(component.GetWasabiHelper(&wasabi)) || wasabi == NULL) return NULL;
+
+ HINSTANCE langModule = NULL;
+ if (FAILED(wasabi->GetLanguageModule(&langModule)))
+ langModule = NULL;
+
+ wasabi->Release();
+ return langModule;
+}
+
+HRESULT Plugin_FormatUuidString(UUID &uid, LPWSTR pszBuffer, size_t cchBufferMax)
+{
+ if (NULL == pszBuffer || cchBufferMax < 1)
+ return E_INVALIDARG;
+
+ pszBuffer[0] = L'\0';
+
+ RPC_WSTR pszUid;
+ if (RPC_S_OK != UuidToString(&uid, &pszUid))
+ {
+ DWORD errorCode = GetLastError();
+ return HRESULT_FROM_WIN32(errorCode);
+ }
+
+ UINT cchLen = lstrlen((LPCWSTR)pszUid);
+ UINT s = 0, d = 0;
+
+ for (; s < cchLen && d < cchBufferMax; s++)
+ {
+ if (pszUid[s] >= L'a' && pszUid[s] <= L'f')
+ {
+ pszBuffer[d++] = (0xDF & pszUid[s]);
+ }
+ else if (pszUid[s] >= L'0' && pszUid[s] <= L'9')
+ {
+ pszBuffer[d++] = pszUid[s];
+ }
+ }
+
+ if (d > cchBufferMax)
+ d = 0;
+
+ pszBuffer[d] = L'\0';
+ RpcStringFree(&pszUid);
+
+ return (L'\0' != pszBuffer[0]) ? S_OK : E_FAIL;
+}
+
+static HINSTANCE Plugin_GetLangHelper(api_language **langManager)
+{
+ ifc_wasabihelper *wasabi = NULL;
+ if (FAILED(component.GetWasabiHelper(&wasabi)) || wasabi == NULL)
+ {
+ *langManager = NULL;
+ return NULL;
+ }
+
+ if (FAILED(wasabi->GetLanguageManager(langManager)))
+ *langManager = NULL;
+
+ HINSTANCE langModule = NULL;
+ if (FAILED(wasabi->GetLanguageModule(&langModule)))
+ langModule = NULL;
+
+ wasabi->Release();
+
+ return langModule;
+}
+
+const wchar_t* Plugin_LoadString(UINT id, wchar_t *buffer, int bufferMax)
+{
+ const wchar_t* r = 0;
+ api_language *lang = NULL;
+ HINSTANCE langModule = Plugin_GetLangHelper(&lang);
+ if (NULL != lang)
+ {
+ r = lang->GetStringW(langModule, Plugin_GetInstance(), id, buffer, bufferMax);
+ lang->Release();
+ }
+ return r;
+}
+
+const char* Plugin_LoadStringAnsi(UINT id, char *buffer, int bufferMax)
+{
+ const char* r = 0;
+ api_language *lang = NULL;
+ HINSTANCE langModule = Plugin_GetLangHelper(&lang);
+ if (NULL != lang)
+ {
+ r = lang->GetString(langModule, Plugin_GetInstance(), id, buffer, bufferMax);
+ lang->Release();
+ }
+ return r;
+}
+
+HWND Plugin_CreateDialogParam(const wchar_t *templateName, HWND parent, DLGPROC proc, LPARAM param)
+{
+ HWND r = 0;
+ api_language *lang = NULL;
+ HINSTANCE langModule = Plugin_GetLangHelper(&lang);
+ if (NULL != lang)
+ {
+ r = lang->CreateLDialogParamW(langModule, Plugin_GetInstance(), (INT)(INT_PTR)templateName, parent, proc, param);
+ lang->Release();
+ }
+ return r;
+}
+
+INT_PTR Plugin_DialogBoxParam(const wchar_t *templateName, HWND parent, DLGPROC proc, LPARAM param)
+{
+ INT_PTR r = -1;
+ api_language *lang = NULL;
+ HINSTANCE langModule = Plugin_GetLangHelper(&lang);
+ if (NULL != lang)
+ {
+ r = lang->LDialogBoxParamW(langModule, Plugin_GetInstance(), (INT)(INT_PTR)templateName, parent, proc, param);
+ lang->Release();
+ }
+ return r;
+}
+
+HMENU Plugin_LoadMenu(const wchar_t *menuName)
+{
+ HMENU r = NULL;
+ api_language *lang = NULL;
+ HINSTANCE langModule = Plugin_GetLangHelper(&lang);
+ if (NULL != lang)
+ {
+ r = lang->LoadLMenuW(langModule, Plugin_GetInstance(), (INT)(INT_PTR)menuName);
+ lang->Release();
+ }
+ return r;
+}
+
+void *Plugin_LoadResource(const wchar_t *resourceType, const wchar_t *resourceName, unsigned long *size)
+{
+ void *r = NULL;
+ api_language *lang = NULL;
+ HINSTANCE langModule = Plugin_GetLangHelper(&lang);
+ if (NULL != lang)
+ {
+ r = lang->LoadResourceFromFileW(langModule, Plugin_GetInstance(), resourceType, resourceName, size);
+ lang->Release();
+ }
+ return r;
+}
+
+HACCEL Plugin_LoadAccelerators(const wchar_t *tableName)
+{
+ HACCEL r = NULL;
+ api_language *lang = NULL;
+ HINSTANCE langModule = Plugin_GetLangHelper(&lang);
+ if (NULL != lang)
+ {
+ r = lang->LoadAcceleratorsW(langModule, Plugin_GetInstance(), tableName);
+ lang->Release();
+ }
+ return r;
+}
+
+HRESULT Plugin_QueryImageLoader(HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply, ifc_omimageloader **imageLoader)
+{
+ if (NULL == imageLoader) return E_POINTER;
+ *imageLoader = NULL;
+
+ if (NULL == pszName) return E_INVALIDARG;
+
+ return PngLoader::CreateInstance(hInstance, pszName, fPremultiply, imageLoader);
+}
+
+size_t Plugin_TlsAlloc(void)
+{
+ size_t index = TLS_OUT_OF_INDEXES;
+ ifc_wasabihelper *wasabi = NULL;
+ if (SUCCEEDED(component.GetWasabiHelper(&wasabi)) && wasabi != NULL)
+ {
+ api_application *app = NULL;
+ if (SUCCEEDED(wasabi->GetApplicationApi(&app)) && app != NULL)
+ {
+ index = app->AllocateThreadStorage();
+ app->Release();
+ }
+ }
+ return index;
+}
+
+BOOL Plugin_TlsFree(size_t index)
+{
+ return FALSE;
+}
+
+void *Plugin_TlsGetValue(size_t index)
+{
+ void *result = NULL;
+ ifc_wasabihelper *wasabi = NULL;
+ if (SUCCEEDED(component.GetWasabiHelper(&wasabi)) && wasabi != NULL)
+ {
+ api_application *app = NULL;
+ if (SUCCEEDED(wasabi->GetApplicationApi(&app)) && app != NULL)
+ {
+ result = app->GetThreadStorage(index);
+ app->Release();
+ }
+ }
+ return result;
+}
+
+BOOL Plugin_TlsSetValue(size_t index, void* value)
+{
+ BOOL result = FALSE;
+ ifc_wasabihelper *wasabi = NULL;
+ if (SUCCEEDED(component.GetWasabiHelper(&wasabi)) && wasabi != NULL)
+ {
+ api_application *app = NULL;
+ if (SUCCEEDED(wasabi->GetApplicationApi(&app)) && app != NULL)
+ {
+ app->SetThreadStorage(index, value);
+ app->Release();
+ result = TRUE;
+ }
+ }
+ return result;
+}
+
+void Plugin_RegisterUnloadCallback(PLUGINUNLOADCALLBACK callback)
+{
+ component.RegisterUnloadCallback(callback);
+}
+
+HRESULT Plugin_GetBrowserClass(LPCWSTR pszName, ifc_ombrowserclass **instance)
+{
+ return component.GetBrowserClass(pszName, instance);
+}
+
+HRESULT Plugin_UnregisterBrowserClass(LPCWSTR pszName)
+{
+ return component.UnregisterBrowserClass(pszName);
+}
+
+HRESULT Plugin_EnsurePathExist(LPCWSTR pszDirectory)
+{
+ DWORD ec = ERROR_SUCCESS;
+ UINT errorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
+
+ if (0 == CreateDirectory(pszDirectory, NULL))
+ {
+ ec = GetLastError();
+ if (ERROR_PATH_NOT_FOUND == ec)
+ {
+ LPCWSTR pszBlock = pszDirectory;
+ WCHAR szBuffer[MAX_PATH] = {0};
+
+ LPCTSTR pszCursor = PathFindNextComponent(pszBlock);
+ ec = (pszCursor == pszBlock || S_OK != StringCchCopyN(szBuffer, ARRAYSIZE(szBuffer), pszBlock, (pszCursor - pszBlock))) ?
+ ERROR_INVALID_NAME : ERROR_SUCCESS;
+
+ pszBlock = pszCursor;
+
+ while (ERROR_SUCCESS == ec && NULL != (pszCursor = PathFindNextComponent(pszBlock)))
+ {
+ if (pszCursor == pszBlock || S_OK != StringCchCatN(szBuffer, ARRAYSIZE(szBuffer), pszBlock, (pszCursor - pszBlock)))
+ ec = ERROR_INVALID_NAME;
+
+ if (ERROR_SUCCESS == ec && !CreateDirectory(szBuffer, NULL))
+ {
+ ec = GetLastError();
+ if (ERROR_ALREADY_EXISTS == ec) ec = ERROR_SUCCESS;
+ }
+ pszBlock = pszCursor;
+ }
+ }
+
+ if (ERROR_ALREADY_EXISTS == ec)
+ ec = ERROR_SUCCESS;
+ }
+
+ SetErrorMode(errorMode);
+ SetLastError(ec);
+ return HRESULT_FROM_WIN32(ec);
+}
+
+HRESULT Plugin_MakeResourcePath(LPWSTR pszBuffer, UINT cchBufferMax, HINSTANCE hInstance, LPCWSTR pszType, LPCWSTR pszName, UINT uFlags)
+{
+ if (NULL == pszBuffer) return E_INVALIDARG;
+
+ if (NULL == hInstance || NULL == pszName)
+ {
+ pszBuffer[0] = L'\0';
+ return E_INVALIDARG;
+ }
+
+ LPWSTR cursor = pszBuffer;
+ size_t remaining = cchBufferMax;
+
+ HRESULT hr = StringCchCopyEx(cursor, remaining, L"res://", &cursor, &remaining, 0);
+ if (SUCCEEDED(hr))
+ {
+ DWORD cchPath = GetModuleFileName(hInstance, cursor, (DWORD)remaining);
+ if (0 == cchPath)
+ {
+ DWORD errorCode = GetLastError();
+ hr = HRESULT_FROM_WIN32(errorCode);
+ }
+ else
+ {
+ if (0 != (RESPATH_COMPACT & uFlags))
+ {
+ ifc_wasabihelper *wasabi = NULL;
+ if (SUCCEEDED(Plugin_GetWasabiHelper(&wasabi)) && wasabi != NULL)
+ {
+ api_application *application = NULL;
+ if (SUCCEEDED(wasabi->GetApplicationApi(&application)) && application != NULL)
+ {
+ WCHAR szPlugin[MAX_PATH] = {0};
+ HINSTANCE hWinamp = application->main_gethInstance();
+ if (NULL != hWinamp && 0 != GetModuleFileName(hWinamp, szPlugin, ARRAYSIZE(szPlugin)))
+ {
+ PathRemoveFileSpec(szPlugin);
+ INT cchCommon = PathCommonPrefix(cursor, szPlugin, NULL);
+ // prevents messing things up if on same drive and that's all that matches
+ if (cchCommon > 3)
+ {
+ cchCommon++;
+ cchPath -= cchCommon;
+ MoveMemory(cursor, cursor + cchCommon, cchPath * sizeof(WCHAR));
+ cursor[cchPath] = L'\0';
+ }
+ }
+ application->Release();
+ }
+ wasabi->Release();
+ }
+ }
+
+ remaining -= cchPath;
+ cursor += cchPath;
+ }
+
+ LPCWSTR pszTemplate = NULL;
+ if (SUCCEEDED(hr) && NULL != pszType)
+ {
+ if (IS_INTRESOURCE(pszType))
+ {
+ pszTemplate = (0 != (RESPATH_TARGETIE & uFlags)) ? L"/%d" : L"/#%d";
+ hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, 0, pszTemplate, pszType);
+ }
+ else if (L'\0' != *pszType)
+ {
+ hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, 0, L"/%s", pszType);
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (IS_INTRESOURCE(pszName))
+ pszTemplate = (0 != (RESPATH_TARGETIE & uFlags)) ? L"/%d" : L"/#%d";
+ else
+ pszTemplate = L"/%s";
+
+ hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, 0, pszTemplate, pszName);
+ }
+ }
+
+ if (FAILED(hr))
+ pszBuffer[0] = L'\0';
+
+ return hr;
+}
+
+HRESULT Plugin_ResolveRelativePath(LPCWSTR pszPath, ifc_omservicehost *host, LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ if (NULL == pszBuffer)
+ return E_POINTER;
+
+ HRESULT hr = S_OK;
+
+ if (NULL != pszPath && L'\0' == *pszPath)
+ pszPath = NULL;
+
+ if (NULL != pszPath && FALSE == PathIsRelative(pszPath))
+ {
+ hr = StringCchCopy(pszBuffer, cchBufferMax, pszPath);
+ return (FAILED(hr)) ? hr : S_FALSE;
+ }
+
+ WCHAR szBase[MAX_PATH] = {0};
+ if (NULL == host || FAILED(host->GetBasePath(NULL, szBase, ARRAYSIZE(szBase))))
+ szBase[0]= L'\0';
+
+ if (L'\0' == szBase[0] || PathIsRelative(szBase))
+ {
+ ifc_wasabihelper *wasabi = NULL;
+ if (SUCCEEDED(Plugin_GetWasabiHelper(&wasabi)) && wasabi != NULL)
+ {
+ api_application *application = NULL;
+ if (SUCCEEDED(wasabi->GetApplicationApi(&application)) && application != NULL)
+ {
+ LPCWSTR pszUser = application->path_getUserSettingsPath();
+ if (NULL != pszUser && L'\0' != *pszUser)
+ {
+ if (L'\0' != szBase[0])
+ hr = StringCchCopy(pszBuffer, cchBufferMax, szBase);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = StringCchCopy(szBase, ARRAYSIZE(szBase), pszUser);
+ if (SUCCEEDED(hr) && L'\0' != *pszBuffer && FALSE == PathAppend(szBase, pszBuffer))
+ hr = E_OUTOFMEMORY;
+ }
+ }
+ application->Release();
+ }
+ wasabi->Release();
+ }
+ }
+
+ if (SUCCEEDED(hr) && NULL != pszPath)
+ {
+ if (L'\0' == szBase[0])
+ hr = StringCchCopy(szBase, ARRAYSIZE(szBase), pszPath);
+ else if (FALSE == PathAppend(szBase, pszPath))
+ hr = E_OUTOFMEMORY;
+ }
+
+ if (SUCCEEDED(hr) && 0 == PathCanonicalize(pszBuffer, szBase))
+ hr = E_OUTOFMEMORY;
+
+ return hr;
+}
+
+BOOL Plugin_IsDirectMouseWheelMessage(const UINT uMsg)
+{
+ static UINT WINAMP_WM_DIRECT_MOUSE_WHEEL = WM_NULL;
+
+ if (WM_NULL == WINAMP_WM_DIRECT_MOUSE_WHEEL)
+ {
+ WINAMP_WM_DIRECT_MOUSE_WHEEL = RegisterWindowMessageW(L"WINAMP_WM_DIRECT_MOUSE_WHEEL");
+ if (WM_NULL == WINAMP_WM_DIRECT_MOUSE_WHEEL)
+ return FALSE;
+ }
+
+ return (WINAMP_WM_DIRECT_MOUSE_WHEEL == uMsg);
+}
+
+extern "C" __declspec(dllexport) ifc_wa5component *GetWinamp5SystemComponent()
+{
+ return &component;
+}
+
+BOOL APIENTRY DllMain(HANDLE hModule, DWORD uReason, void *reserved)
+{
+ switch(uReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ pluginInstance = (HINSTANCE)hModule;
+ HTMLContainer2_Initialize();
+ break;
+ case DLL_PROCESS_DETACH:
+ HTMLContainer2_Uninitialize();
+ break;
+ }
+ return TRUE;
+} \ No newline at end of file
diff --git a/Src/omBrowser/main.h b/Src/omBrowser/main.h
new file mode 100644
index 00000000..6ec89c50
--- /dev/null
+++ b/Src/omBrowser/main.h
@@ -0,0 +1,87 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_WA5SERVICE_MAIN_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_WA5SERVICE_MAIN_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#define OMBROWSER_VERSION_MAJOR 1
+#define OMBROWSER_VERSION_MINOR 5
+#define OMBROWSER_NAME L"omBrowser"
+
+#include "./common.h"
+
+/* string managment */
+LPWSTR Plugin_MallocString(size_t cchLen);
+LPWSTR Plugin_ReAllocString(LPWSTR pszString, size_t cchLen);
+void Plugin_FreeString(LPWSTR pszString);
+LPWSTR Plugin_CopyString(LPCWSTR pszSource);
+LPSTR Plugin_MallocAnsiString(size_t cchLen);
+LPSTR Plugin_CopyAnsiString(LPCSTR pszSource);
+void Plugin_FreeAnsiString(LPSTR pszString);
+LPWSTR Plugin_DuplicateResString(LPCWSTR pszResource);
+void Plugin_FreeResString(LPWSTR pszResource);
+HRESULT Plugin_CopyResString(LPWSTR pszBuffer, INT cchBufferMax, LPCWSTR pszString);
+
+LPSTR Plugin_WideCharToMultiByte(UINT codePage, DWORD dwFlags, LPCWSTR lpWideCharStr, INT cchWideChar, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar);
+LPWSTR Plugin_MultiByteToWideChar(UINT codePage, DWORD dwFlags, LPCSTR lpMultiByteStr, INT cbMultiByte);
+
+
+HRESULT Plugin_FormatUuidString(UUID &uid, LPWSTR pszBuffer, size_t cchBufferMax);
+
+
+HINSTANCE Plugin_GetInstance(void);
+HINSTANCE Plugin_GetLangInstance(void);
+
+HRESULT Plugin_Initialize(HWND hwndWinamp);
+
+class ifc_wasabihelper;
+HRESULT Plugin_GetWasabiHelper(ifc_wasabihelper **wasabiHelper);
+
+class ifc_skinhelper;
+HRESULT Plugin_GetSkinHelper(ifc_skinhelper **skinHelper);
+
+class ifc_skinnedbrowser;
+HRESULT Plugin_GetBrowserSkin(ifc_skinnedbrowser **skinnedBrowser);
+
+HRESULT Plugin_GetWinampWnd(HWND *hwndWinamp);
+
+class ifc_winamphook;
+HRESULT Plugin_RegisterWinampHook(ifc_winamphook *hook, UINT *cookieOut);
+HRESULT Plugin_UnregisterWinampHook(UINT cookie);
+
+const wchar_t* Plugin_LoadString(UINT id, wchar_t *buffer, int bufferMax);
+const char* Plugin_LoadStringAnsi(UINT id, char *buffer, int bufferMax);
+HWND Plugin_CreateDialogParam(const wchar_t *templateName, HWND parent, DLGPROC proc, LPARAM param);
+INT_PTR Plugin_DialogBoxParam(const wchar_t *templateName, HWND parent, DLGPROC proc, LPARAM param);
+HMENU Plugin_LoadMenu(const wchar_t *menuName);
+void *Plugin_LoadResource(const wchar_t *resourceType, const wchar_t *resourceName, unsigned long *size);
+HACCEL Plugin_LoadAccelerators(const wchar_t *tableName);
+
+class ifc_omimageloader;
+HRESULT Plugin_QueryImageLoader(HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply, ifc_omimageloader **imageLoader);
+
+size_t Plugin_TlsAlloc(void);
+BOOL Plugin_TlsFree(size_t index);
+void *Plugin_TlsGetValue(size_t index);
+BOOL Plugin_TlsSetValue(size_t index, void* value);
+
+typedef void (CALLBACK *PLUGINUNLOADCALLBACK)(void);
+void Plugin_RegisterUnloadCallback(PLUGINUNLOADCALLBACK callback);
+
+class ifc_ombrowserclass;
+HRESULT Plugin_GetBrowserClass(LPCWSTR pszName, ifc_ombrowserclass **instance);
+HRESULT Plugin_UnregisterBrowserClass(LPCWSTR pszName); // internal call
+
+HRESULT Plugin_EnsurePathExist(LPCWSTR pszDirectory);
+
+#define RESPATH_TARGETIE 0x0001 // IE safe path
+#define RESPATH_COMPACT 0x0002 // compact path relative to winamp location if possible
+HRESULT Plugin_MakeResourcePath(LPWSTR pszBuffer, UINT cchBufferMax, HINSTANCE hInstance, LPCWSTR pszType, LPCWSTR pszName, UINT uFlags);
+
+class ifc_omservicehost;
+HRESULT Plugin_ResolveRelativePath(LPCWSTR pszPath, ifc_omservicehost *host, LPWSTR pszBuffer, UINT cchBufferMax);
+
+BOOL Plugin_IsDirectMouseWheelMessage(const UINT uMsg);
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_WA5SERVICE_MAIN_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/menu.cpp b/Src/omBrowser/menu.cpp
new file mode 100644
index 00000000..ccdc4841
--- /dev/null
+++ b/Src/omBrowser/menu.cpp
@@ -0,0 +1,160 @@
+#include "main.h"
+#include "./menu.h"
+#include "./ratingMenu.h"
+#include "./ifc_skinhelper.h"
+#include "./ifc_skinnedmenu.h"
+#include "./ifc_menucustomizer.h"
+#include "./resource.h"
+#include "../nu/menuHelpers.h"
+
+#define SUBMENU_RATING 0
+#define SUBMENU_TOOLBAR 1
+#define SUBMENU_ADDRESSBAR 2
+
+static HRESULT Menu_GetSkinnedMenu(ifc_skinnedmenu **skinnedMenu)
+{
+ if (NULL == skinnedMenu) return E_POINTER;
+
+ ifc_skinhelper *skinHelper = NULL;
+ HRESULT hr = Plugin_GetSkinHelper(&skinHelper);
+ if (SUCCEEDED(hr) && skinHelper != NULL)
+ {
+ hr = skinHelper->QueryInterface(IFC_SkinnedMenu, (void**)skinnedMenu);
+ skinHelper->Release();
+ }
+ return hr;
+}
+
+static HMENU Menu_CreateRatingMenu(HMENU baseMenu, INT ratingValue)
+{
+ HMENU menu = GetSubMenu(baseMenu, SUBMENU_RATING);
+ if (NULL == menu) return NULL;
+
+ menu = MenuHelper_DuplcateMenu(menu);
+ if (NULL == menu) return NULL;
+
+ if (FALSE == RatingMenu_InitializeMenu(menu, ratingValue))
+ {
+ DestroyMenu(menu);
+ menu = NULL;
+ }
+
+ return menu;
+}
+
+static HMENU Menu_GetToolbarContext(HMENU baseMenu, UINT flags)
+{
+ HMENU hMenu = GetSubMenu(baseMenu, SUBMENU_TOOLBAR);
+ return hMenu;
+}
+
+static HMENU Menu_GetAddressbarContext(HMENU baseMenu, UINT flags)
+{
+ HMENU hMenu = GetSubMenu(baseMenu, SUBMENU_ADDRESSBAR);
+ return hMenu;
+}
+
+void Menu_ConvertRatingMenuStar(HMENU menu, UINT menu_id)
+{
+ MENUITEMINFOW mi = {sizeof(mi), MIIM_DATA | MIIM_TYPE, MFT_STRING};
+ wchar_t rateBuf[32] = {0}, *rateStr = rateBuf;
+ mi.dwTypeData = rateBuf;
+ mi.cch = 32;
+ if(GetMenuItemInfoW(menu, menu_id, FALSE, &mi))
+ {
+ while(rateStr && *rateStr)
+ {
+ if(*rateStr == L'*') *rateStr = L'\u2605';
+ rateStr=CharNextW(rateStr);
+ }
+ SetMenuItemInfoW(menu, menu_id, FALSE, &mi);
+ }
+}
+
+HMENU Menu_GetMenu(INT menuKind, UINT flags)
+{
+ HMENU baseMenu = Plugin_LoadMenu(MAKEINTRESOURCE(IDR_CONTEXTMENU));
+ if (NULL == baseMenu)
+ return NULL;
+
+ HMENU rate_hmenu = GetSubMenu(baseMenu,0);
+ Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATING_VALUE_5);
+ Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATING_VALUE_4);
+ Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATING_VALUE_3);
+ Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATING_VALUE_2);
+ Menu_ConvertRatingMenuStar(rate_hmenu, ID_RATING_VALUE_1);
+
+ switch(menuKind)
+ {
+ case MENU_RATING:
+ return Menu_CreateRatingMenu(baseMenu, RATINGFROMMCF(flags));
+ case MENU_TOOLBAR:
+ return Menu_GetToolbarContext(baseMenu, flags);
+ case MENU_ADDRESSBAR:
+ return Menu_GetAddressbarContext(baseMenu, flags);
+ }
+ return NULL;
+}
+
+void Menu_ReleaseMenu(HMENU hMenu, INT menuKind)
+{
+ if (NULL == hMenu)
+ return;
+
+ switch(menuKind)
+ {
+ case MENU_RATING:
+ DestroyMenu(hMenu);
+ break;
+ case MENU_TOOLBAR:
+ break;
+ case MENU_ADDRESSBAR:
+ break;
+ }
+}
+
+BOOL Menu_TrackPopup(HMENU hMenu, UINT fuFlags, INT x, INT y, HWND hwnd, LPTPMPARAMS lptpm)
+{
+ BOOL result = FALSE;
+
+ ifc_skinnedmenu *skinnedMenu = NULL;
+ if (SUCCEEDED(Menu_GetSkinnedMenu(&skinnedMenu)) && skinnedMenu != NULL)
+ {
+ ifc_menucustomizer *customizer = NULL;
+ if (FAILED(RatingMenu_GetCustomizer(hMenu, &customizer)))
+ customizer = NULL;
+
+ result = skinnedMenu->TrackPopup(hMenu, fuFlags, x, y, hwnd, lptpm, customizer);
+
+ if (NULL != customizer)
+ customizer->Release();
+
+ skinnedMenu->Release();
+ }
+
+ return result;
+}
+
+HANDLE Menu_InitializeHook(HWND hwnd, ifc_menucustomizer *customizer)
+{
+ ifc_skinnedmenu *skinnedMenu = NULL;
+ HANDLE hook = NULL;
+ if (SUCCEEDED(Menu_GetSkinnedMenu(&skinnedMenu)) && skinnedMenu != NULL)
+ {
+ hook = skinnedMenu->InitPopupHook(hwnd, customizer);
+ skinnedMenu->Release();
+ }
+ return hook;
+}
+
+HRESULT Menu_RemoveHook(HANDLE menuHook)
+{
+ ifc_skinnedmenu *skinnedMenu = NULL;
+ HRESULT hr = Menu_GetSkinnedMenu(&skinnedMenu);
+ if (SUCCEEDED(hr) && skinnedMenu != NULL)
+ {
+ hr = skinnedMenu->RemovePopupHook(menuHook);
+ skinnedMenu->Release();
+ }
+ return hr;
+} \ No newline at end of file
diff --git a/Src/omBrowser/menu.h b/Src/omBrowser/menu.h
new file mode 100644
index 00000000..67370c13
--- /dev/null
+++ b/Src/omBrowser/menu.h
@@ -0,0 +1,33 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_MENU_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_MENU_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+class ifc_menucustomizer;
+
+#define MENU_RATING 2
+#define MENU_TOOLBAR 3
+#define MENU_ADDRESSBAR 4
+
+#define MCF_RATINGMASK 0xF0000000
+#define MCF_RATING1 0x10000000
+#define MCF_RATING2 0x20000000
+#define MCF_RATING3 0x30000000
+#define MCF_RATING4 0x40000000
+#define MCF_RATING5 0x50000000
+
+#define RATINGTOMCF(__rating) ((0x0F & (__rating)) << 24)
+#define RATINGFROMMCF(__mcf) (0x0F & ((__mcf) >> 24))
+
+HMENU Menu_GetMenu(INT menuKind, UINT flags);
+void Menu_ReleaseMenu(HMENU hMenu, INT menuKind);
+
+BOOL Menu_TrackPopup(HMENU hMenu, UINT fuFlags, INT x, INT y, HWND hwnd, LPTPMPARAMS lptpm);
+HANDLE Menu_InitializeHook(HWND hwnd, ifc_menucustomizer *customizer);
+HRESULT Menu_RemoveHook(HANDLE menuHook);
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_MENU_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/mlNavigationHelper.cpp b/Src/omBrowser/mlNavigationHelper.cpp
new file mode 100644
index 00000000..cfa032b1
--- /dev/null
+++ b/Src/omBrowser/mlNavigationHelper.cpp
@@ -0,0 +1,599 @@
+#include "main.h"
+#include "./mlNavigationHelper.h"
+#include "./ifc_omcachemanager.h"
+#include "./ifc_omcachegroup.h"
+#include "./ifc_omcacherecord.h"
+#include "./ifc_mlnavigationcallback.h"
+#include "./resource.h"
+#include "./ifc_wasabihelper.h"
+
+#include "../Plugins/General/gen_ml/ml.h"
+
+#define _ML_HEADER_IMPMLEMENT
+#include "../Plugins/General/gen_ml/ml_ipc_0313.h"
+#undef _ML_HEADER_IMPMLEMENT
+
+#include <shlwapi.h>
+#include <strsafe.h>
+#include <algorithm>
+
+MlNavigationHelper::MlNavigationHelper(HWND hLibraryWnd, ifc_omcachegroup *cacheGroup)
+ : ref(1), hLibrary(hLibraryWnd), defaultIndex(-1), cacheGroup(cacheGroup), lastCookie(0)
+{
+ InitializeCriticalSection(&lock);
+
+ if (NULL != cacheGroup)
+ cacheGroup->AddRef();
+}
+
+MlNavigationHelper::~MlNavigationHelper()
+{
+ EnterCriticalSection(&lock);
+
+ for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
+ {
+ ifc_mlnavigationcallback *callback = iter->second;
+ if (NULL != callback) callback->Release();
+ }
+
+ size_t index = recordList.size();
+ while(index--)
+ {
+ Plugin_FreeString(recordList[index].name);
+ }
+
+ if (NULL != cacheGroup)
+ cacheGroup->Release();
+
+ LeaveCriticalSection(&lock);
+ DeleteCriticalSection(&lock);
+}
+
+HRESULT MlNavigationHelper::CreateInstance(HWND hLibrary, ifc_omcachemanager *cacheManager, MlNavigationHelper **instance)
+{
+ if (NULL == instance) return E_POINTER;
+
+ if (NULL == hLibrary || FALSE == IsWindow(hLibrary) || NULL == cacheManager)
+ {
+ *instance = NULL;
+ return E_INVALIDARG;
+ }
+
+ ifc_omcachegroup *group = NULL;
+ HRESULT hr = cacheManager->Find(L"icons", TRUE, &group, NULL);
+ if (SUCCEEDED(hr) && group != NULL)
+ {
+ *instance = new MlNavigationHelper(hLibrary, group);
+ if (NULL == *instance)
+ {
+ hr = E_OUTOFMEMORY;
+ }
+
+ group->Release();
+ }
+
+ return hr;
+}
+
+size_t MlNavigationHelper::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t MlNavigationHelper::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int MlNavigationHelper::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_MlNavigationHelper))
+ *object = static_cast<ifc_mlnavigationhelper*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT MlNavigationHelper::GetDefaultIndex(int *index)
+{
+ if (NULL == index)
+ return E_POINTER;
+
+ EnterCriticalSection(&lock);
+
+ if (-1 == defaultIndex)
+ {
+ WCHAR szPath[MAX_PATH] = {0};
+ HRESULT hr = Plugin_MakeResourcePath(szPath, ARRAYSIZE(szPath), Plugin_GetInstance(),
+ RT_RCDATA, MAKEINTRESOURCE(IDR_SERVICEICON_IMAGE), RESPATH_COMPACT);
+
+ if (SUCCEEDED(hr))
+ {
+ UpdateImageList(szPath, &defaultIndex);
+ }
+ }
+ *index = defaultIndex;
+
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+
+HRESULT MlNavigationHelper::UpdateImageList(LPCWSTR address, INT *index)
+{
+ if (NULL == address || NULL == index)
+ {
+ if (NULL != index) *index = -1;
+ return E_INVALIDARG;
+ }
+
+ HMLIMGLST hmlil = MLNavCtrl_GetImageList(hLibrary);
+ if (NULL == hmlil) return E_UNEXPECTED;
+
+ MLIMAGESOURCE source = {0};
+ source.cbSize = sizeof(source);
+ source.lpszName = address;
+ source.type = SRC_TYPE_PNG;
+ source.bpp = 24;
+ source.flags = ISF_LOADFROMFILE | ISF_FORCE_BPP | ISF_PREMULTIPLY;
+
+ MLIMAGELISTIMAGESIZE imageSize = {0};
+ imageSize.hmlil = hmlil;
+ if (FALSE != MLImageList_GetImageSize(hLibrary, &imageSize))
+ {
+ source.cxDst = imageSize.cx;
+ source.cyDst = imageSize.cy;
+ source.flags |= ISF_FORCE_SIZE | ISF_SCALE;
+ }
+
+ if (FALSE == MLImageLoader_CheckExist(hLibrary, &source))
+ return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
+
+ MLIMAGELISTITEM item = {0};
+ item.cbSize = sizeof(item);
+ item.hmlil = hmlil;
+ item.filterUID = MLIF_FILTER3_UID;
+ item.pmlImgSource = &source;
+
+ HRESULT hr = S_OK;
+ INT iImage = *index;
+ if (iImage >= 0)
+ {
+ INT imageCount = MLImageList_GetImageCount(hLibrary, item.hmlil);
+ if (iImage >= imageCount) iImage = -1;
+ }
+
+ if (iImage >=0)
+ {
+ item.mlilIndex = iImage;
+ if (FALSE == MLImageList_Replace(hLibrary, &item))
+ hr = E_FAIL;
+ }
+ else
+ {
+ iImage = MLImageList_Add(hLibrary, &item);
+ if (-1 == iImage) hr = E_FAIL;
+ }
+
+ *index = iImage;
+ return hr;
+}
+
+HRESULT MlNavigationHelper::ImageLocator(LPCWSTR address, INT *index)
+{
+ if (NULL == address) return E_INVALIDARG;
+
+ HRESULT hr;
+ BOOL runtimeOnly = TRUE;
+
+ if (PathIsURL(address) &&
+ CSTR_EQUAL != CompareString(CSTR_INVARIANT, NORM_IGNORECASE, address, 6, L"res://", -1))
+ {
+ runtimeOnly = FALSE;
+ }
+ else
+ {
+ hr = UpdateImageList(address, index);
+ if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) != hr)
+ return hr;
+ }
+
+ BOOL fCreated = FALSE;
+ ifc_omcacherecord *cacheRecord = NULL;
+ hr = cacheGroup->Find(address, TRUE, &cacheRecord, &fCreated);
+ if (SUCCEEDED(hr) && cacheRecord != NULL)
+ {
+ cacheRecord->RegisterCallback(this);
+
+ if (FALSE != fCreated && FALSE != runtimeOnly)
+ {
+ cacheRecord->SetFlags(ifc_omcacherecord::flagNoStore, ifc_omcacherecord::flagNoStore);
+ }
+
+ WCHAR szBuffer[MAX_PATH * 2] = {0};
+ if (SUCCEEDED(cacheRecord->GetPath(szBuffer, ARRAYSIZE(szBuffer))))
+ {
+ hr = UpdateImageList(szBuffer, index);
+ }
+
+ cacheRecord->Release();
+ }
+ return hr;
+}
+
+HRESULT MlNavigationHelper::QueryIndex(LPCWSTR pszName, INT *index, BOOL *defaultUsed)
+{
+ if (NULL == cacheGroup)
+ return E_UNEXPECTED;
+
+ if (NULL == index)
+ {
+ if (NULL != defaultUsed) *defaultUsed = FALSE;
+ return E_POINTER;
+ }
+
+ if (NULL == pszName || L'\0' == *pszName)
+ {
+ if (SUCCEEDED(GetDefaultIndex(index)))
+ {
+ if (NULL != defaultUsed) *defaultUsed = TRUE;
+ }
+ else
+ {
+ *index = 0;
+ if (NULL != defaultUsed) *defaultUsed = FALSE;
+ }
+ return S_OK;
+ }
+
+ EnterCriticalSection(&lock);
+
+ RECORD *record = Find(pszName);
+ if (NULL == record)
+ { // create new
+ RECORD rec = {0};
+
+ size_t index = recycledList.size();
+ if (0 != index)
+ {
+ rec.index = recycledList[index - 1];
+ recycledList.pop_back();
+ }
+ else
+ {
+ rec.index = -1;
+ }
+
+ rec.ref = 1;
+ rec.name = Plugin_CopyString(pszName);
+ recordList.push_back(rec);
+ Sort();
+ // locate record again;
+ record = Find(pszName);
+ ImageLocator(record->name, &record->index);
+ }
+ else
+ {
+ record->ref++;
+ if (-1 == record->index)
+ ImageLocator(record->name, &record->index);
+ }
+
+ if(-1 == record->index)
+ {
+ if (SUCCEEDED(GetDefaultIndex(index)) && NULL != defaultUsed)
+ *defaultUsed = TRUE;
+ }
+ else
+ {
+ *index = record->index;
+ }
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+HRESULT MlNavigationHelper::ReleaseIndex(LPCWSTR pszName)
+{
+ if(NULL == pszName || L'\0' == *pszName)
+ return E_INVALIDARG;
+
+ EnterCriticalSection(&lock);
+
+ RECORD *record = Find(pszName);
+ if (NULL != record)
+ {
+ record->ref--;
+ if (0 == record->ref)
+ {
+ if (-1 != record->index)
+ recycledList.push_back(record->index);
+
+ Plugin_FreeString(record->name);
+ record->name = NULL;
+
+ size_t index = recordList.size();
+ while(index--)
+ {
+ if (&recordList[index] == record)
+ {
+ recordList.erase(recordList.begin() + index);
+ break;
+ }
+ }
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+ return (NULL != record) ? S_OK : S_FALSE;
+}
+
+HRESULT MlNavigationHelper::RegisterAlias(LPCWSTR pszName, LPCWSTR pszAddress)
+{
+ if (NULL == cacheGroup)
+ return E_UNEXPECTED;
+
+ BOOL fCreated = FALSE;
+ ifc_omcacherecord *record = NULL;
+ HRESULT hr = cacheGroup->Find(pszName, TRUE, &record, &fCreated);
+ if (SUCCEEDED(hr) && record != NULL)
+ {
+ if (FALSE != fCreated)
+ {
+ record->SetFlags(ifc_omcacherecord::flagNoStore, ifc_omcacherecord::flagNoStore);
+ }
+
+ hr = record->SetPath(pszAddress);
+ record->RegisterCallback(this);
+ record->Release();
+ }
+ return hr;
+}
+
+HWND MlNavigationHelper::GetLibrary()
+{
+ return hLibrary;
+}
+
+typedef struct __CACHECHANGEAPCPARAM
+{
+ MlNavigationHelper *instance;
+ ifc_omcacherecord *record;
+} CACHECHANGEAPCPARAM;
+
+static void CALLBACK MlNavigationHelper_CacheRecordPathChangedApc(ULONG_PTR data)
+{
+ CACHECHANGEAPCPARAM *param = (CACHECHANGEAPCPARAM*)data;
+ if (NULL != param)
+ {
+ if (NULL != param->instance)
+ {
+ param->instance->CacheRecordPathChangedApc(param->record);
+ param->instance->Release();
+ }
+ if (NULL != param->record)
+ param->record->Release();
+
+ free(param);
+ }
+}
+
+void MlNavigationHelper::CacheRecordPathChanged(ifc_omcacherecord *cacheRecord)
+{
+ if (NULL == cacheRecord)
+ return;
+
+ HRESULT hr = E_FAIL;
+ CACHECHANGEAPCPARAM *param = (CACHECHANGEAPCPARAM*)calloc(1, sizeof(CACHECHANGEAPCPARAM));
+ if (NULL != param)
+ {
+ param->instance = this;
+ param->instance->AddRef();
+ param->record = cacheRecord;
+ param->record->AddRef();
+
+ ifc_wasabihelper *wasabi = NULL;
+ if (SUCCEEDED(Plugin_GetWasabiHelper(&wasabi)) && wasabi != NULL)
+ {
+ api_application *application = NULL;
+ if (SUCCEEDED(wasabi->GetApplicationApi(&application)) && application != NULL)
+ {
+ HANDLE hThread = application->main_getMainThreadHandle();
+ if (NULL != hThread &&
+ 0 != QueueUserAPC(MlNavigationHelper_CacheRecordPathChangedApc, hThread, (ULONG_PTR)param))
+ {
+ hr = S_OK;
+ }
+ application->Release();
+ }
+ wasabi->Release();
+ }
+
+ if (FAILED(hr))
+ {
+ if (NULL != param->instance) param->instance->Release();
+ if (NULL != param->record) param->record->Release();
+ free(param);
+ param = NULL;
+ }
+ }
+}
+
+void MlNavigationHelper::CacheRecordPathChangedApc(ifc_omcacherecord *cacheRecord)
+{
+ if (NULL == cacheRecord)
+ return;
+
+ WCHAR szBuffer[1024] = {0};
+ if (FAILED(cacheRecord->GetName(szBuffer, ARRAYSIZE(szBuffer))))
+ return;
+
+ EnterCriticalSection(&lock);
+
+ RECORD *record = Find(szBuffer);
+ if (NULL != record &&
+ SUCCEEDED(cacheRecord->GetPath(szBuffer, ARRAYSIZE(szBuffer))) &&
+ SUCCEEDED(UpdateImageList(szBuffer, &record->index)))
+ {
+ for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
+ {
+ ifc_mlnavigationcallback *callback = iter->second;
+ callback->ImageChanged(record->name, record->index);
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+}
+
+HRESULT MlNavigationHelper::RegisterCallback(ifc_mlnavigationcallback *callback, UINT *cookie)
+{
+ if (NULL == cookie) return E_POINTER;
+ *cookie = 0;
+
+ if (NULL == callback)
+ return E_INVALIDARG;
+
+ EnterCriticalSection(&lock);
+
+ *cookie = ++lastCookie;
+
+ callbackMap.insert({ *cookie, callback });
+ callback->AddRef();
+
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+HRESULT MlNavigationHelper::UnregisterCallback(UINT cookie)
+{
+ if (0 == cookie) return E_INVALIDARG;
+
+ ifc_mlnavigationcallback *callback = NULL;
+ EnterCriticalSection(&lock);
+
+ for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
+ {
+ if (cookie == iter->first)
+ {
+ callback = iter->second;
+ callbackMap.erase(iter);
+ break;
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+
+ if (NULL != callback)
+ {
+ callback->Release();
+ return S_OK;
+ }
+
+ return S_FALSE;
+}
+
+__inline static int __cdecl MlNavigationHelper_RecordComparer(const void *elem1, const void *elem2)
+{
+ LPCWSTR s1 = ((MlNavigationHelper::RECORD*)elem1)->name;
+ LPCWSTR s2 = ((MlNavigationHelper::RECORD*)elem2)->name;
+
+ if (NULL == s1 || NULL == s2) return ((INT)(ULONG_PTR)(s1 - s2));
+ return CompareString(CSTR_INVARIANT, NORM_IGNORECASE, s1, -1, s2, -1) - 2;
+}
+__inline static int __cdecl MlNavigationHelper_RecordComparer_V2(const void* elem1, const void* elem2)
+{
+ return MlNavigationHelper_RecordComparer(elem1, elem2) < 0;
+}
+
+__inline static int __cdecl MlNavigationHelper_RecordSearch(const void *elem1, const void *elem2)
+{
+ LPCWSTR s1 = (LPCWSTR)elem1;
+ LPCWSTR s2 = ((MlNavigationHelper::RECORD*)elem2)->name;
+
+ if (NULL == s1 || NULL == s2) return ((INT)(ULONG_PTR)(s1 - s2));
+ INT r = CompareString(CSTR_INVARIANT, NORM_IGNORECASE, s1, -1, s2, -1) - 2;
+ return r;
+}
+
+HRESULT MlNavigationHelper::Sort()
+{
+ HRESULT hr;
+ if (recordList.size() < 2)
+ {
+ hr = S_FALSE;
+ }
+ else
+ {
+ //qsort(recordList.begin(), recordList.size(), sizeof(RECORD), MlNavigationHelper_RecordComparer);
+ std::sort(recordList.begin(), recordList.end(),
+ [&](RECORD lhs, RECORD rhs) -> bool
+ {
+ return MlNavigationHelper_RecordComparer_V2(&lhs, &rhs);
+ }
+ );
+
+ hr = S_OK;
+ }
+ return hr;
+}
+
+MlNavigationHelper::RECORD *MlNavigationHelper::Find(LPCWSTR pszName)
+{
+ if (0 == recordList.size())
+ return NULL;
+
+ //return (RECORD*)bsearch(pszName, recordList.begin(), recordList.size(),
+ // sizeof(RECORD), MlNavigationHelper_RecordSearch);
+
+ auto it = std::find_if(recordList.begin(), recordList.end(),
+ [&](RECORD upT) -> bool
+ {
+ return MlNavigationHelper_RecordSearch(pszName, &upT) == 0;
+ }
+ );
+ if (it == recordList.end())
+ {
+ return NULL;
+ }
+
+ return &(* it);
+}
+
+#define CBCLASS MlNavigationHelper
+START_MULTIPATCH;
+ START_PATCH(MPIID_MLNAVIGATIONHELPER)
+ M_CB(MPIID_MLNAVIGATIONHELPER, ifc_mlnavigationhelper, ADDREF, AddRef);
+ M_CB(MPIID_MLNAVIGATIONHELPER, ifc_mlnavigationhelper, RELEASE, Release);
+ M_CB(MPIID_MLNAVIGATIONHELPER, ifc_mlnavigationhelper, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_MLNAVIGATIONHELPER, ifc_mlnavigationhelper, API_GETDEFAULTINDEX, GetDefaultIndex);
+ M_CB(MPIID_MLNAVIGATIONHELPER, ifc_mlnavigationhelper, API_QUERYINDEX, QueryIndex);
+ M_CB(MPIID_MLNAVIGATIONHELPER, ifc_mlnavigationhelper, API_RELEASEINDEX, ReleaseIndex);
+ M_CB(MPIID_MLNAVIGATIONHELPER, ifc_mlnavigationhelper, API_REGISTERALIAS, RegisterAlias);
+ M_CB(MPIID_MLNAVIGATIONHELPER, ifc_mlnavigationhelper, API_REGISTERCALLBACK, RegisterCallback);
+ M_CB(MPIID_MLNAVIGATIONHELPER, ifc_mlnavigationhelper, API_UNREGISTERCALLBACK, UnregisterCallback);
+ NEXT_PATCH(MPIID_OMCACHECALLBACK)
+ M_CB(MPIID_OMCACHECALLBACK, ifc_omcachecallback, ADDREF, AddRef);
+ M_CB(MPIID_OMCACHECALLBACK, ifc_omcachecallback, RELEASE, Release);
+ M_CB(MPIID_OMCACHECALLBACK, ifc_omcachecallback, QUERYINTERFACE, QueryInterface);
+ M_VCB(MPIID_OMCACHECALLBACK, ifc_omcachecallback, API_PATHCHANGED, CacheRecordPathChanged);
+ END_PATCH
+END_MULTIPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/mlNavigationHelper.h b/Src/omBrowser/mlNavigationHelper.h
new file mode 100644
index 00000000..5498d227
--- /dev/null
+++ b/Src/omBrowser/mlNavigationHelper.h
@@ -0,0 +1,93 @@
+#ifndef NULLSOFT_WINAMP_ML_NAVIGATION_HELPER_HEADER
+#define NULLSOFT_WINAMP_ML_NAVIGATION_HELPER_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_mlnavigationhelper.h"
+#include "./ifc_omcachecallback.h"
+#include <vector>
+#include <map>
+#include <bfc/multipatch.h>
+
+class ifc_omcachemanager;
+class ifc_omcachegroup;
+class ifc_mlnavigationcallback;
+
+#define MPIID_MLNAVIGATIONHELPER 10
+#define MPIID_OMCACHECALLBACK 20
+
+class MlNavigationHelper : public MultiPatch<MPIID_MLNAVIGATIONHELPER, ifc_mlnavigationhelper>,
+ public MultiPatch<MPIID_OMCACHECALLBACK, ifc_omcachecallback>
+{
+protected:
+ MlNavigationHelper(HWND hLibrary, ifc_omcachegroup *cacheGroup);
+ ~MlNavigationHelper();
+
+public:
+ static HRESULT CreateInstance(HWND hLibrary, ifc_omcachemanager *cacheManager, MlNavigationHelper **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_mlnavigationhelper */
+ HRESULT GetDefaultIndex(INT *index);
+ HRESULT QueryIndex(LPCWSTR pszName, INT *index, BOOL *defaultUsed);
+ HRESULT ReleaseIndex(LPCWSTR pszName);
+ HRESULT RegisterAlias(LPCWSTR pszName, LPCWSTR pszAddress);
+ HRESULT RegisterCallback(ifc_mlnavigationcallback *callback, UINT *cookie);
+ HRESULT UnregisterCallback(UINT cookie);
+
+ /* ifc_omcachecallback */
+ void CacheRecordPathChanged(ifc_omcacherecord *cacheRecord);
+
+protected:
+ void CacheRecordPathChangedApc(ifc_omcacherecord *cacheRecord);
+
+private:
+ friend static void CALLBACK MlNavigationHelper_CacheRecordPathChangedApc(ULONG_PTR data);
+
+public:
+ HWND GetLibrary();
+
+protected:
+ typedef struct __RECORD
+ {
+ LPWSTR name;
+ INT index;
+ UINT ref;
+ } RECORD;
+
+ typedef std::vector<RECORD> RecordList;
+ typedef std::vector<INT> RecycledList;
+ typedef std::map<UINT, ifc_mlnavigationcallback*> CallbackMap;
+
+private:
+ friend __inline static int __cdecl MlNavigationHelper_RecordComparer(const void *elem1, const void *elem2);
+ friend __inline static int __cdecl MlNavigationHelper_RecordSearch(const void *elem1, const void *elem2);
+
+ HRESULT ImageLocator(LPCWSTR address, INT *index);
+ HRESULT UpdateImageList(LPCWSTR address, INT *index);
+ HRESULT Sort();
+ RECORD *Find(LPCWSTR pszName);
+
+protected:
+ ULONG ref;
+ HWND hLibrary;
+ INT defaultIndex;
+ ifc_omcachegroup *cacheGroup;
+ RecordList recordList;
+ CallbackMap callbackMap;
+ RecycledList recycledList;
+ UINT lastCookie;
+ CRITICAL_SECTION lock;
+
+protected:
+ RECVS_MULTIPATCH;
+};
+
+#endif //NULLSOFT_WINAMP_ML_NAVIGATION_HELPER_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/obj_ombrowser.h b/Src/omBrowser/obj_ombrowser.h
new file mode 100644
index 00000000..96a10486
--- /dev/null
+++ b/Src/omBrowser/obj_ombrowser.h
@@ -0,0 +1,145 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_OBJECT_INTERFACE_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_OBJECT_INTERFACE_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "bfc/dispatch.h"
+
+// {D5325EAB-9BD7-4382-A31D-38EF603061B3}
+static const GUID OBJ_OmBrowser =
+{ 0xd5325eab, 0x9bd7, 0x4382, { 0xa3, 0x1d, 0x38, 0xef, 0x60, 0x30, 0x61, 0xb3 } };
+
+class ifc_ombrowserclass;
+class ifc_winamphook;
+class ifc_ombrowserregistry;
+class ifc_omservice;
+class ifc_ombrowserevent;
+
+#define BOSTYLE_NORMAL 0x0000
+#define BOSTYLE_SHOWDEBUG 0x0001
+
+#define BOCALLBACK_INIT 0
+typedef void (CALLBACK *BROWSEROPTIONSCALLBACK)(HWND /*hDialog*/, UINT /*type*/, ULONG_PTR /*user*/);
+
+class __declspec( novtable ) obj_ombrowser : public Dispatchable
+{
+protected:
+ obj_ombrowser() {}
+ ~obj_ombrowser() {}
+
+public:
+ HRESULT Initialize( const wchar_t *pszName, HWND hwndWinamp );
+ HRESULT Finish( void );
+ HRESULT RegisterWinampHook( ifc_winamphook *hook, UINT *cookieOut );
+ HRESULT UnregisterWinampHook( UINT cookie );
+ HRESULT GetConfig( const GUID *configIfc, void **configOut );
+ HRESULT GetSessionId( LPWSTR pszBuffer, INT cchBufferMax );
+ HRESULT GetClientId( LPWSTR pszBuffer, INT cchBufferMax );
+ HRESULT GetRegistry( ifc_ombrowserregistry **registryOut );
+ HRESULT CreateView( ifc_omservice *service, HWND hParent, LPCWSTR forceUrl, UINT viewStyle, HWND *hView );
+ HRESULT CreatePopup( ifc_omservice *service, INT x, INT y, INT cx, INT cy, HWND hOwner, LPCWSTR forceUrl, UINT viewStyle, HWND *hWindow );
+ HRESULT IsFinishing( void );
+ HRESULT GetClass( ifc_ombrowserclass **instance );
+ HRESULT GetVersion( int *major, int *minor );
+ HRESULT GetIEVersion( int *major, int *minor, int *build, int *subbuild );
+ HRESULT ShowOptions( HWND hOwner, UINT style, BROWSEROPTIONSCALLBACK callback, ULONG_PTR user );
+
+ DISPATCH_CODES
+ {
+ API_INITIALIZE = 10,
+ API_FINISH = 20,
+ API_REGISTERWINAMPHOOK = 30,
+ API_UNREGISTERWINAMPHOOK = 40,
+ API_GETLANGMODULE = 60,
+ API_GETCONFIG = 70,
+ API_GETSESSIONID = 80,
+ API_GETCLIENTID = 90,
+ API_GETREGISTRY = 100,
+ API_CREATEVIEW = 110,
+ API_CREATEPOPUP = 120,
+ API_ISFINISHING = 130,
+ API_GETCLASS = 140,
+ API_GETVERSION = 150,
+ API_GETIEVERSION = 160,
+ API_SHOWOPTIONS = 170,
+ };
+};
+
+inline HRESULT obj_ombrowser::Initialize( const wchar_t *pszName, HWND hwndWinamp )
+{
+ return _call( API_INITIALIZE, (HRESULT)E_NOTIMPL, pszName, hwndWinamp );
+}
+
+inline HRESULT obj_ombrowser::Finish( void )
+{
+ return _call( API_FINISH, (HRESULT)E_NOTIMPL );
+}
+
+inline HRESULT obj_ombrowser::RegisterWinampHook( ifc_winamphook *hook, UINT *hookCookie )
+{
+ return _call( API_REGISTERWINAMPHOOK, (HRESULT)E_NOTIMPL, hook, hookCookie );
+}
+
+inline HRESULT obj_ombrowser::UnregisterWinampHook( UINT hookCookie )
+{
+ return _call( API_UNREGISTERWINAMPHOOK, (HRESULT)E_NOTIMPL, hookCookie );
+}
+
+inline HRESULT obj_ombrowser::GetConfig( const GUID *configIfc, void **configOut )
+{
+ return _call( API_GETCONFIG, (HRESULT)E_NOTIMPL, configIfc, configOut );
+}
+
+inline HRESULT obj_ombrowser::GetSessionId( LPWSTR pszBuffer, INT cchBufferMax )
+{
+ return _call( API_GETSESSIONID, (HRESULT)E_NOTIMPL, pszBuffer, cchBufferMax );
+}
+
+inline HRESULT obj_ombrowser::GetClientId( LPWSTR pszBuffer, INT cchBufferMax )
+{
+ return _call( API_GETCLIENTID, (HRESULT)E_NOTIMPL, pszBuffer, cchBufferMax );
+}
+
+inline HRESULT obj_ombrowser::GetRegistry( ifc_ombrowserregistry **registryOut )
+{
+ return _call( API_GETREGISTRY, (HRESULT)E_NOTIMPL, registryOut );
+}
+
+inline HRESULT obj_ombrowser::CreateView( ifc_omservice *service, HWND hParent, LPCWSTR forceUrl, UINT viewStyle, HWND *hView )
+{
+ return _call( API_CREATEVIEW, (HRESULT)E_NOTIMPL, service, hParent, forceUrl, viewStyle, hView );
+}
+
+inline HRESULT obj_ombrowser::CreatePopup( ifc_omservice *service, INT x, INT y, INT cx, INT cy, HWND hOwner, LPCWSTR forceUrl, UINT viewStyle, HWND *hWindow )
+{
+ return _call( API_CREATEPOPUP, (HRESULT)E_NOTIMPL, service, x, y, cx, cy, hOwner, forceUrl, viewStyle, hWindow );
+}
+
+inline HRESULT obj_ombrowser::IsFinishing( void )
+{
+ return _call( API_ISFINISHING, (HRESULT)E_NOTIMPL );
+}
+
+inline HRESULT obj_ombrowser::GetClass( ifc_ombrowserclass **instance )
+{
+ return _call( API_GETCLASS, (HRESULT)E_NOTIMPL, instance );
+}
+
+inline HRESULT obj_ombrowser::GetVersion( int *major, int *minor )
+{
+ return _call( API_GETVERSION, (HRESULT)E_NOTIMPL, major, minor );
+}
+
+inline HRESULT obj_ombrowser::GetIEVersion( int *major, int *minor, int *build, int *subbuild )
+{
+ return _call( API_GETIEVERSION, (HRESULT)E_NOTIMPL, major, minor, build, subbuild );
+}
+
+inline HRESULT obj_ombrowser::ShowOptions( HWND hOwner, UINT style, BROWSEROPTIONSCALLBACK callback, ULONG_PTR user )
+{
+ return _call( API_SHOWOPTIONS, (HRESULT)E_NOTIMPL, hOwner, style, callback, user );
+}
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_OBJECT_INTERFACE_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/omBrowser.rc b/Src/omBrowser/omBrowser.rc
new file mode 100644
index 00000000..a72e99f0
--- /dev/null
+++ b/Src/omBrowser/omBrowser.rc
@@ -0,0 +1,315 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "#include ""version.rc2""\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_BROWSERACCEL ACCELERATORS
+BEGIN
+ VK_HOME, ID_NAVIGATION_HOME, VIRTKEY, ALT, NOINVERT
+ "R", ID_NAVIGATION_REFRESH, VIRTKEY, CONTROL, NOINVERT
+ VK_F5, ID_NAVIGATION_REFRESH, VIRTKEY, NOINVERT
+ "R", ID_NAVIGATION_REFRESH_COMPLETELY, VIRTKEY, SHIFT, CONTROL, NOINVERT
+ VK_F5, ID_NAVIGATION_REFRESH_COMPLETELY, VIRTKEY, CONTROL, NOINVERT
+ "D", ID_ADDRESSBAR_ACTIVATE, VIRTKEY, ALT, NOINVERT
+END
+
+IDR_BROWSERPOPUPACCEL ACCELERATORS
+BEGIN
+ VK_F4, ID_WINDOW_CLOSE, VIRTKEY, CONTROL, NOINVERT
+ VK_F11, ID_WINDOW_FULLSCREEN, VIRTKEY, NOINVERT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_CONTEXTMENU MENU
+BEGIN
+ POPUP "&Rate"
+ BEGIN
+ MENUITEM "*****", ID_RATING_VALUE_5
+ MENUITEM "****", ID_RATING_VALUE_4
+ MENUITEM "***", ID_RATING_VALUE_3
+ MENUITEM "**", ID_RATING_VALUE_2
+ MENUITEM "*", ID_RATING_VALUE_1
+ END
+ POPUP "Toolbar"
+ BEGIN
+ MENUITEM "&Top Dock", ID_TOOLBAR_DOCKTOP
+ MENUITEM "&Bottom Dock", ID_TOOLBAR_DOCKBOTTOM
+ MENUITEM SEPARATOR
+ MENUITEM "Auto-&Hide", ID_TOOLBAR_AUTOHIDE
+ MENUITEM "Enable &Tab Stop", ID_TOOLBAR_TABSTOP
+ END
+ POPUP "Addressbar"
+ BEGIN
+ MENUITEM "&Copy", ID_ADDRESSBAR_COPY
+ MENUITEM "Copy &address", ID_ADDRESSBAR_COPYADDRESS
+ MENUITEM "&Edit address", ID_ADDRESSBAR_EDITADDRESS
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_BROWSER_OPTIONS DIALOGEX 0, 0, 237, 170
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "omBrowser Options"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_TABFRAME,"SysTabControl32",WS_TABSTOP,5,4,227,144
+ DEFPUSHBUTTON "&Close",IDCANCEL,182,153,50,13
+END
+
+IDD_OPTIONS_UI DIALOGEX 0, 0, 220, 128
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Toolbar",IDC_STATIC,4,4,212,86,0,WS_EX_TRANSPARENT
+ LTEXT "&Location:",IDC_STATIC,11,19,30,9,SS_CENTERIMAGE
+ COMBOBOX IDC_TOOLBAR_LOCATION,47,17,109,40,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Automatically &hide toolbar when inactive",IDC_TOOLBAR_AUTOHIDE,
+ "Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,11,35,145,10
+ CONTROL "Include toolbar in tab stop &navigation",IDC_TOOLBAR_TABSTOP,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,48,135,10
+ CONTROL "Always show &addressbar",IDC_TOOLBAR_FORCEADDRESS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,61,95,10
+ CONTROL "Show page &title in addressbar",IDC_TOOLBAR_FANCYADDRESS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,74,111,10
+ GROUPBOX "Statusbar",IDC_STATIC,4,94,212,30,0,WS_EX_TRANSPARENT
+ CONTROL "Display &statusbar on page activity",IDC_STATUSBAR_ENABLED,
+ "Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,11,107,125,10
+END
+
+IDD_OPTIONS_DEBUG DIALOGEX 0, 0, 220, 128
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "",IDC_STATIC,4,4,212,78,0,WS_EX_TRANSPARENT
+ CONTROL "Disable context menu &filtering",IDC_FILTERMENU,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,15,111,10
+ CONTROL "Display a notification about every script &error",IDC_SHOWERROR,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,29,161,10
+ CONTROL "Enable script &debugging",IDC_SHOWDEBUGGER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,42,92,10
+ LTEXT "Note:",IDC_STATIC,11,57,19,8
+ LTEXT "Some changes made on this page will take affect only after Winamp restart.",IDC_STATIC,34,57,161,18
+END
+
+IDD_OPTIONS_INFO DIALOGEX 0, 0, 220, 128
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "",IDC_STATIC,4,4,212,107,0,WS_EX_TRANSPARENT
+ CTEXT "Nullsoft Winamp omBrowser Service",IDC_TITLE,17,14,189,13,SS_CENTERIMAGE
+ RTEXT "version:",IDC_STATIC,13,32,31,8
+ EDITTEXT IDC_VERSION,48,32,158,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ RTEXT "class:",IDC_STATIC,13,44,31,8
+ EDITTEXT IDC_CLASS,48,44,158,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ RTEXT "client:",IDC_STATIC,13,56,31,8
+ EDITTEXT IDC_CLIENTID,48,56,158,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ RTEXT "session:",IDC_STATIC,13,68,31,8
+ EDITTEXT IDC_SESSIONID,48,68,158,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ RTEXT "config:",IDC_STATIC,13,80,31,8
+ EDITTEXT IDC_CONFIGPATH,48,80,158,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ RTEXT "MSIE:",IDC_STATIC,13,92,31,8
+ EDITTEXT IDC_MSIEVERSION,48,92,158,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_BROWSER_OPTIONS, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 232
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 166
+ END
+
+ IDD_OPTIONS_UI, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 216
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 124
+ END
+
+ IDD_OPTIONS_DEBUG, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 216
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 124
+ END
+
+ IDD_OPTIONS_INFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 216
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 124
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ 65535 "{DCCF5A41-D16B-452b-8B7A-CFCA3360D8E8}"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_ENCRYPTION_MIXED "Mixed security"
+ IDS_ENCRYPTION_40BIT "40-bit security"
+ IDS_ENCRYPTION_56BIT "56-bit security"
+ IDS_ENCRYPTION_FORTEZZA "Fortezza security"
+ IDS_ENCRYPTION_128BIT "128-bit security"
+ IDS_CONNECTION_UNSECURE "Connection Not Encrypted"
+ IDS_CONNECTION_ENCRYPTED "Connection Encrypted"
+ IDS_CURRENT_PAGE "Current Page"
+ IDS_OMBROWSER_TITLE "Winamp Browser"
+ IDS_RATING_0 "not rated"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_RATING_1 "1 star"
+ IDS_RATING_2 "2 stars"
+ IDS_RATING_3 "3 stars"
+ IDS_RATING_4 "4 stars"
+ IDS_RATING_5 "5 stars"
+ IDS_RATING_CHANGETO "Set to:"
+ IDS_RATING_CURRENT "Rated:"
+ IDS_MORE "More..."
+ IDS_HOME "Home"
+ IDS_HOME_DESCRIPTION "Navigate to the main service page"
+ IDS_BACK "Back"
+ IDS_BACK_DESCRIPTION "Go back one page"
+ IDS_FORWARD "Forward"
+ IDS_FORWARD_DESCRIPTION "Go forward one page"
+ IDS_REFRESH "Refresh"
+ IDS_REFRESH_DESCRIPTION "Reload current page"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_STOP "Stop"
+ IDS_STOP_DESCRIPTION "Stop loading this page"
+ IDS_SEPARATOR "Separator"
+ IDS_SPACE "Space"
+ IDS_FLEXSPACE "Flexible Space"
+ IDS_MORE_DESCRIPTION "Show more items"
+ IDS_RATED "Rating:"
+ IDS_PLEASE_WAIT "Please wait..."
+ IDS_SERVICE_VERSIONCHECK "Checking service version"
+ IDS_SERVICE_GETINFO "Get Info..."
+ IDS_SERVICE_GETINFO_DESCRIPTION "Get service info"
+ IDS_SERVICE_REPORT "Report..."
+ IDS_SERVICE_REPORT_DESCRIPTION "Report service"
+ IDS_SERVICE_UNSUBSCRIBE "Remove"
+ IDS_SERVICE_UNSUBSCRIBE_DESCRIPTION "Remove service"
+ IDS_SECURE_CONNECTION "Show Page Identification"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_SCRIPT_ERROR "Show Script Errors"
+ IDS_SCRIPT_ERROR_DESCRIPTION "Page executed with some errors"
+ IDS_HISTORY "Recent pages"
+ IDS_HISTORY_DESCRIPTION "Recent pages"
+ IDS_NAVIGATING "Navigating..."
+ IDS_OPTIONS_UI "Look && Feel"
+ IDS_OPTIONS_DEBUG "Debug"
+ IDS_OPTIONS_INFO "Info"
+ IDS_TOOLBAR_TOPDOCK "Top Dock"
+ IDS_TOOLBAR_BOTTOMDOCK "Bottom Dock"
+ IDS_UNKNOWN "unknown"
+ IDS_STORAGE_INI "Online Service INI File"
+ IDS_STORAGE_XML "Online Service XML List"
+ IDS_STORAGE_URL "Server Published Service XML List"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "version.rc2"
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Src/omBrowser/omBrowser.sln b/Src/omBrowser/omBrowser.sln
new file mode 100644
index 00000000..775a33a3
--- /dev/null
+++ b/Src/omBrowser/omBrowser.sln
@@ -0,0 +1,44 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29509.3
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "omBrowser", "omBrowser.vcxproj", "{FC74DB95-5008-4D22-9147-1C052F43CDD3}"
+ ProjectSection(ProjectDependencies) = postProject
+ {F5D8D737-1C1E-4967-B7FC-74FABB806926} = {F5D8D737-1C1E-4967-B7FC-74FABB806926}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "localization", "localization\localization.vcxproj", "{F5D8D737-1C1E-4967-B7FC-74FABB806926}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {FC74DB95-5008-4D22-9147-1C052F43CDD3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FC74DB95-5008-4D22-9147-1C052F43CDD3}.Debug|Win32.Build.0 = Debug|Win32
+ {FC74DB95-5008-4D22-9147-1C052F43CDD3}.Release|Win32.ActiveCfg = Release|Win32
+ {FC74DB95-5008-4D22-9147-1C052F43CDD3}.Release|Win32.Build.0 = Release|Win32
+ {FC74DB95-5008-4D22-9147-1C052F43CDD3}.Debug|x64.ActiveCfg = Debug|x64
+ {FC74DB95-5008-4D22-9147-1C052F43CDD3}.Debug|x64.Build.0 = Debug|x64
+ {FC74DB95-5008-4D22-9147-1C052F43CDD3}.Release|x64.ActiveCfg = Release|x64
+ {FC74DB95-5008-4D22-9147-1C052F43CDD3}.Release|x64.Build.0 = Release|x64
+ {F5D8D737-1C1E-4967-B7FC-74FABB806926}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F5D8D737-1C1E-4967-B7FC-74FABB806926}.Debug|Win32.Build.0 = Debug|Win32
+ {F5D8D737-1C1E-4967-B7FC-74FABB806926}.Release|Win32.ActiveCfg = Release|Win32
+ {F5D8D737-1C1E-4967-B7FC-74FABB806926}.Release|Win32.Build.0 = Release|Win32
+ {F5D8D737-1C1E-4967-B7FC-74FABB806926}.Debug|x64.ActiveCfg = Debug|x64
+ {F5D8D737-1C1E-4967-B7FC-74FABB806926}.Debug|x64.Build.0 = Debug|x64
+ {F5D8D737-1C1E-4967-B7FC-74FABB806926}.Release|x64.ActiveCfg = Release|x64
+ {F5D8D737-1C1E-4967-B7FC-74FABB806926}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {0F28B553-AD13-46C5-9E6F-A54334B5B3B2}
+ EndGlobalSection
+EndGlobal
diff --git a/Src/omBrowser/omBrowser.vcxproj b/Src/omBrowser/omBrowser.vcxproj
new file mode 100644
index 00000000..b66a6ac9
--- /dev/null
+++ b/Src/omBrowser/omBrowser.vcxproj
@@ -0,0 +1,483 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{FC74DB95-5008-4D22-9147-1C052F43CDD3}</ProjectGuid>
+ <RootNamespace>omBrowser</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <TargetExt>.w5s</TargetExt>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <TargetExt>.w5s</TargetExt>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <TargetExt>.w5s</TargetExt>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <TargetExt>.w5s</TargetExt>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>.;..;../wasabi;../agave;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_WIN32_WINNT=0x0601;WINVER=0x0601;_WIN32_IE=0x0A00;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <ShowIncludes>false</ShowIncludes>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>shlwapi.lib;comctl32.lib;rpcrt4.lib;wininet.lib;msimg32.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(ProjectDir)x86_Debug\$(ProjectName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>.;..;../wasabi;../agave;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_USRDLL;_WIN32_WINNT=0x0601;WINVER=0x0601;_WIN32_IE=0x0A00;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <ShowIncludes>false</ShowIncludes>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>shlwapi.lib;comctl32.lib;rpcrt4.lib;wininet.lib;msimg32.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(ProjectDir)x64_Debug\$(ProjectName).lib</ImportLibrary>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
+ <AdditionalIncludeDirectories>.;..;../wasabi;../agave;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_WIN32_WINNT=0x0601;WINVER=0x0601;_WIN32_IE=0x0A00;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>shlwapi.lib;comctl32.lib;rpcrt4.lib;wininet.lib;msimg32.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(ProjectDir)x86_Release\$(ProjectName).lib</ImportLibrary>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
+ <AdditionalIncludeDirectories>.;..;../wasabi;../agave;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;_WIN32_WINNT=0x0601;WINVER=0x0601;_WIN32_IE=0x0A00;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>shlwapi.lib;comctl32.lib;rpcrt4.lib;wininet.lib;msimg32.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(ProjectDir)x64_Release\$(ProjectName).lib</ImportLibrary>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\nu\HTMLContainer2.cpp" />
+ <ClCompile Include="..\nu\menuHelpers.cpp" />
+ <ClCompile Include="..\nu\trace.cpp" />
+ <ClCompile Include="addressEncoder.cpp" />
+ <ClCompile Include="browser.cpp" />
+ <ClCompile Include="browserClass.cpp" />
+ <ClCompile Include="browserFactory.cpp" />
+ <ClCompile Include="browserHost.cpp" />
+ <ClCompile Include="browserInternal.cpp" />
+ <ClCompile Include="browserObject.cpp" />
+ <ClCompile Include="browserPopup.cpp" />
+ <ClCompile Include="browserRegistry.cpp" />
+ <ClCompile Include="browserThread.cpp" />
+ <ClCompile Include="browserUiCommon.cpp" />
+ <ClCompile Include="browserUiHook.cpp" />
+ <ClCompile Include="browserView.cpp" />
+ <ClCompile Include="browserWndEnum.cpp" />
+ <ClCompile Include="browserWndRecord.cpp" />
+ <ClCompile Include="cacheDownloader.cpp" />
+ <ClCompile Include="cacheGroup.cpp" />
+ <ClCompile Include="cacheManager.cpp" />
+ <ClCompile Include="cacheRecord.cpp" />
+ <ClCompile Include="component.cpp" />
+ <ClCompile Include="configIni.cpp" />
+ <ClCompile Include="curtain.cpp" />
+ <ClCompile Include="enumAsync.cpp" />
+ <ClCompile Include="enumIniFile.cpp" />
+ <ClCompile Include="enumXmlBuffer.cpp" />
+ <ClCompile Include="enumXmlFile.cpp" />
+ <ClCompile Include="flagTracker.cpp" />
+ <ClCompile Include="graphics.cpp" />
+ <ClCompile Include="graphicsObject.cpp" />
+ <ClCompile Include="ieversion.cpp" />
+ <ClCompile Include="internetFeatures.cpp" />
+ <ClCompile Include="loaderIni.cpp" />
+ <ClCompile Include="main.cpp" />
+ <ClCompile Include="menu.cpp" />
+ <ClCompile Include="mlNavigationHelper.cpp" />
+ <ClCompile Include="options.cpp" />
+ <ClCompile Include="optionsDebug.cpp" />
+ <ClCompile Include="optionsHook.cpp" />
+ <ClCompile Include="optionsInfo.cpp" />
+ <ClCompile Include="optionsUi.cpp" />
+ <ClCompile Include="pngLoader.cpp" />
+ <ClCompile Include="ratingMenu.cpp" />
+ <ClCompile Include="ratingMenuCustomizer.cpp" />
+ <ClCompile Include="service.cpp" />
+ <ClCompile Include="serviceDetails.cpp" />
+ <ClCompile Include="serviceDispatch.cpp" />
+ <ClCompile Include="serviceEditor.cpp" />
+ <ClCompile Include="serviceEventMngr.cpp" />
+ <ClCompile Include="serviceFactory.cpp" />
+ <ClCompile Include="serviceList.cpp" />
+ <ClCompile Include="serviceManager.cpp" />
+ <ClCompile Include="skinHelper.cpp" />
+ <ClCompile Include="statusbar.cpp" />
+ <ClCompile Include="storageDwnld.cpp" />
+ <ClCompile Include="storageEnum.cpp" />
+ <ClCompile Include="storageHandler.cpp" />
+ <ClCompile Include="storageHandlerEnum.cpp" />
+ <ClCompile Include="storageHelper.cpp" />
+ <ClCompile Include="storageIni.cpp" />
+ <ClCompile Include="storageUrl.cpp" />
+ <ClCompile Include="storageXml.cpp" />
+ <ClCompile Include="stringBuilder.cpp" />
+ <ClCompile Include="toolbar.cpp" />
+ <ClCompile Include="toolbarAddress.cpp" />
+ <ClCompile Include="toolbarButton.cpp" />
+ <ClCompile Include="toolbarEditbox.cpp" />
+ <ClCompile Include="toolbarItem.cpp" />
+ <ClCompile Include="toolbarProgress.cpp" />
+ <ClCompile Include="toolbarRating.cpp" />
+ <ClCompile Include="toolbarStatic.cpp" />
+ <ClCompile Include="travelLogHelper.cpp" />
+ <ClCompile Include="utility.cpp" />
+ <ClCompile Include="utilityFactory.cpp" />
+ <ClCompile Include="wasabiHelper.cpp" />
+ <ClCompile Include="winampHook.cpp" />
+ <ClCompile Include="xmlResponseParser.cpp" />
+ <ClCompile Include="xmlServiceParser.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="addressEncoder.h" />
+ <ClInclude Include="browser.h" />
+ <ClInclude Include="browserClass.h" />
+ <ClInclude Include="browserFactory.h" />
+ <ClInclude Include="browserHost.h" />
+ <ClInclude Include="browserInternal.h" />
+ <ClInclude Include="browserObject.h" />
+ <ClInclude Include="browserPopup.h" />
+ <ClInclude Include="browserRegistry.h" />
+ <ClInclude Include="browserThread.h" />
+ <ClInclude Include="browserUiCommon.h" />
+ <ClInclude Include="browserUiHook.h" />
+ <ClInclude Include="browserUiInternal.h" />
+ <ClInclude Include="browserView.h" />
+ <ClInclude Include="browserWndEnum.h" />
+ <ClInclude Include="browserWndRecord.h" />
+ <ClInclude Include="cacheDownloader.h" />
+ <ClInclude Include="cacheGroup.h" />
+ <ClInclude Include="cacheManager.h" />
+ <ClInclude Include="cacheRecord.h" />
+ <ClInclude Include="common.h" />
+ <ClInclude Include="component.h" />
+ <ClInclude Include="configIni.h" />
+ <ClInclude Include="curtain.h" />
+ <ClInclude Include="enumAsync.h" />
+ <ClInclude Include="enumIniFile.h" />
+ <ClInclude Include="enumXmlBuffer.h" />
+ <ClInclude Include="enumXmlFile.h" />
+ <ClInclude Include="flagTracker.h" />
+ <ClInclude Include="graphics.h" />
+ <ClInclude Include="graphicsObject.h" />
+ <ClInclude Include="ieversion.h" />
+ <ClInclude Include="ifc_imageloader.h" />
+ <ClInclude Include="ifc_menucustomizer.h" />
+ <ClInclude Include="ifc_mlnavigationcallback.h" />
+ <ClInclude Include="ifc_mlnavigationhelper.h" />
+ <ClInclude Include="ifc_ombrowserclass.h" />
+ <ClInclude Include="ifc_ombrowserconfig.h" />
+ <ClInclude Include="ifc_ombrowserevent.h" />
+ <ClInclude Include="ifc_ombrowsereventmngr.h" />
+ <ClInclude Include="ifc_ombrowserregistry.h" />
+ <ClInclude Include="ifc_ombrowserwndenum.h" />
+ <ClInclude Include="ifc_ombrowserwndmngr.h" />
+ <ClInclude Include="ifc_omcachecallback.h" />
+ <ClInclude Include="ifc_omcachegroup.h" />
+ <ClInclude Include="ifc_omcachemanager.h" />
+ <ClInclude Include="ifc_omcacherecord.h" />
+ <ClInclude Include="ifc_omconfig.h" />
+ <ClInclude Include="ifc_omconfigcallback.h" />
+ <ClInclude Include="ifc_omdebugconfig.h" />
+ <ClInclude Include="ifc_omfilestorage.h" />
+ <ClInclude Include="ifc_omgraphics.h" />
+ <ClInclude Include="ifc_omservice.h" />
+ <ClInclude Include="ifc_omservicecommand.h" />
+ <ClInclude Include="ifc_omservicecopier.h" />
+ <ClInclude Include="ifc_omservicedetails.h" />
+ <ClInclude Include="ifc_omserviceeditor.h" />
+ <ClInclude Include="ifc_omserviceenum.h" />
+ <ClInclude Include="ifc_omserviceevent.h" />
+ <ClInclude Include="ifc_omserviceeventmngr.h" />
+ <ClInclude Include="ifc_omservicehost.h" />
+ <ClInclude Include="ifc_omservicehostext.h" />
+ <ClInclude Include="ifc_omservicemanager.h" />
+ <ClInclude Include="ifc_omstatusbarconfig.h" />
+ <ClInclude Include="ifc_omstorage.h" />
+ <ClInclude Include="ifc_omstorageasync.h" />
+ <ClInclude Include="ifc_omstorageenum.h" />
+ <ClInclude Include="ifc_omstorageext.h" />
+ <ClInclude Include="ifc_omstoragehandler.h" />
+ <ClInclude Include="ifc_omstoragehandlerenum.h" />
+ <ClInclude Include="ifc_omstoragehelper.h" />
+ <ClInclude Include="ifc_omtoolbarconfig.h" />
+ <ClInclude Include="ifc_omutility.h" />
+ <ClInclude Include="ifc_omwebstorage.h" />
+ <ClInclude Include="ifc_omxmlserviceenum.h" />
+ <ClInclude Include="ifc_skinhelper.h" />
+ <ClInclude Include="ifc_skinnedbrowser.h" />
+ <ClInclude Include="ifc_skinnedmenu.h" />
+ <ClInclude Include="ifc_skinnedrating.h" />
+ <ClInclude Include="ifc_travelloghelper.h" />
+ <ClInclude Include="ifc_wasabihelper.h" />
+ <ClInclude Include="ifc_winamphook.h" />
+ <ClInclude Include="internetFeatures.h" />
+ <ClInclude Include="loaderIni.h" />
+ <ClInclude Include="main.h" />
+ <ClInclude Include="menu.h" />
+ <ClInclude Include="mlNavigationHelper.h" />
+ <ClInclude Include="obj_ombrowser.h" />
+ <ClInclude Include="options.h" />
+ <ClInclude Include="optionsHook.h" />
+ <ClInclude Include="pngLoader.h" />
+ <ClInclude Include="ratingMenu.h" />
+ <ClInclude Include="ratingMenuCustomizer.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="service.h" />
+ <ClInclude Include="serviceFactory.h" />
+ <ClInclude Include="serviceList.h" />
+ <ClInclude Include="serviceManager.h" />
+ <ClInclude Include="skinHelper.h" />
+ <ClInclude Include="statusbar.h" />
+ <ClInclude Include="storageDwnld.h" />
+ <ClInclude Include="storageEnum.h" />
+ <ClInclude Include="storageHandler.h" />
+ <ClInclude Include="storageHandlerEnum.h" />
+ <ClInclude Include="storageHelper.h" />
+ <ClInclude Include="storageIni.h" />
+ <ClInclude Include="storageUrl.h" />
+ <ClInclude Include="storageXml.h" />
+ <ClInclude Include="stringBuilder.h" />
+ <ClInclude Include="toolbar.h" />
+ <ClInclude Include="toolbarAddress.h" />
+ <ClInclude Include="toolbarButton.h" />
+ <ClInclude Include="toolbarEditbox.h" />
+ <ClInclude Include="toolbarItem.h" />
+ <ClInclude Include="toolbarProgress.h" />
+ <ClInclude Include="toolbarRating.h" />
+ <ClInclude Include="toolbarStatic.h" />
+ <ClInclude Include="travelLogHelper.h" />
+ <ClInclude Include="utility.h" />
+ <ClInclude Include="utilityFactory.h" />
+ <ClInclude Include="wasabiHelper.h" />
+ <ClInclude Include="winampHook.h" />
+ <ClInclude Include="xmlResponseParser.h" />
+ <ClInclude Include="xmlServiceParser.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <Image Include="resources\pages\errorIcon.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="errorPages.rc" />
+ <ResourceCompile Include="omBrowser.rc" />
+ <ResourceCompile Include="png.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="resources\pages\dnsError.htm">
+ <DeploymentContent>true</DeploymentContent>
+ </None>
+ <None Include="resources\pages\errorPageFunctions.js" />
+ <None Include="resources\pages\errorPageStrings.js" />
+ <None Include="resources\pages\httpError.htm">
+ <DeploymentContent>true</DeploymentContent>
+ </None>
+ <None Include="resources\pages\navCancel.htm">
+ <DeploymentContent>true</DeploymentContent>
+ </None>
+ <None Include="resources\pages\winampError.css" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Wasabi\Wasabi.vcxproj">
+ <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+ <ProjectExtensions>
+ <VisualStudio>
+ <UserProperties RESOURCE_FILE="errorPages.rc" />
+ </VisualStudio>
+ </ProjectExtensions>
+</Project> \ No newline at end of file
diff --git a/Src/omBrowser/omBrowser.vcxproj.filters b/Src/omBrowser/omBrowser.vcxproj.filters
new file mode 100644
index 00000000..d635724d
--- /dev/null
+++ b/Src/omBrowser/omBrowser.vcxproj.filters
@@ -0,0 +1,675 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="addressEncoder.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="browser.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="browserClass.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="browserFactory.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="browserHost.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="browserInternal.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="browserObject.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="browserPopup.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="browserRegistry.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="browserThread.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="browserUiCommon.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="browserUiHook.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="browserView.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="browserWndEnum.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="browserWndRecord.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="cacheDownloader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="cacheGroup.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="cacheManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="cacheRecord.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="component.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="configIni.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="curtain.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="enumAsync.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="enumIniFile.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="enumXmlBuffer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="enumXmlFile.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="flagTracker.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="graphics.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="graphicsObject.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ieversion.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="internetFeatures.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="loaderIni.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="menu.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="mlNavigationHelper.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="options.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="optionsDebug.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="optionsHook.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="optionsInfo.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="optionsUi.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="pngLoader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ratingMenu.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ratingMenuCustomizer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="service.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="serviceDetails.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="serviceDispatch.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="serviceEditor.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="serviceEventMngr.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="serviceFactory.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="serviceList.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="serviceManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="skinHelper.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="statusbar.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="storageDwnld.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="storageEnum.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="storageHandler.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="storageHandlerEnum.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="storageHelper.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="storageIni.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="storageUrl.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="storageXml.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="stringBuilder.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="toolbar.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="toolbarAddress.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="toolbarButton.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="toolbarEditbox.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="toolbarItem.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="toolbarProgress.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="toolbarRating.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="toolbarStatic.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="travelLogHelper.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="utility.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="utilityFactory.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="wasabiHelper.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="winampHook.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="xmlResponseParser.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="xmlServiceParser.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\nu\HTMLContainer2.cpp">
+ <Filter>Source Files\nu</Filter>
+ </ClCompile>
+ <ClCompile Include="..\nu\menuHelpers.cpp">
+ <Filter>Source Files\nu</Filter>
+ </ClCompile>
+ <ClCompile Include="..\nu\trace.cpp">
+ <Filter>Source Files\nu</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="addressEncoder.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="browser.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="browserClass.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="browserFactory.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="browserHost.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="browserInternal.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="browserObject.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="browserPopup.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="browserRegistry.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="browserThread.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="browserUiCommon.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="browserUiHook.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="browserUiInternal.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="browserView.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="browserWndEnum.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="browserWndRecord.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="cacheDownloader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="cacheGroup.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="cacheManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="cacheRecord.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="common.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="component.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="configIni.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="curtain.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="enumAsync.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="enumIniFile.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="enumXmlBuffer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="enumXmlFile.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="flagTracker.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="graphics.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="graphicsObject.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ieversion.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_imageloader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_menucustomizer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_mlnavigationcallback.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_mlnavigationhelper.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_ombrowserclass.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_ombrowserconfig.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_ombrowserevent.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_ombrowsereventmngr.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_ombrowserregistry.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_ombrowserwndenum.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_ombrowserwndmngr.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omcachecallback.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omcachegroup.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omcachemanager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omcacherecord.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omconfig.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omconfigcallback.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omdebugconfig.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omfilestorage.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omgraphics.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omservice.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omservicecommand.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omservicecopier.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omservicedetails.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omserviceeditor.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omserviceenum.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omserviceevent.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omserviceeventmngr.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omservicehost.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omservicehostext.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omservicemanager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omstatusbarconfig.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omstorage.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omstorageasync.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omstorageenum.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omstorageext.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omstoragehandler.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omstoragehandlerenum.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omstoragehelper.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omtoolbarconfig.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omutility.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omwebstorage.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_omxmlserviceenum.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_skinhelper.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_skinnedbrowser.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_skinnedrating.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_skinnedmenu.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_travelloghelper.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_wasabihelper.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ifc_winamphook.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="internetFeatures.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="loaderIni.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="main.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="menu.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="mlNavigationHelper.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="obj_ombrowser.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="options.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="optionsHook.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="pngLoader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ratingMenu.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ratingMenuCustomizer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="service.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="serviceFactory.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="serviceList.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="serviceManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="skinHelper.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="statusbar.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="storageDwnld.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="storageEnum.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="storageHandler.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="storageHandlerEnum.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="storageHelper.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="storageIni.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="storageUrl.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="storageXml.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="stringBuilder.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="toolbar.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="toolbarAddress.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="toolbarButton.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="toolbarEditbox.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="toolbarItem.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="toolbarProgress.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="toolbarRating.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="toolbarStatic.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="travelLogHelper.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="utility.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="utilityFactory.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="wasabiHelper.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="winampHook.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="xmlResponseParser.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="xmlServiceParser.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="errorPages.rc">
+ <Filter>Ressource Files</Filter>
+ </ResourceCompile>
+ <ResourceCompile Include="omBrowser.rc">
+ <Filter>Ressource Files</Filter>
+ </ResourceCompile>
+ <ResourceCompile Include="png.rc">
+ <Filter>Ressource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="resources\pages\dnsError.htm">
+ <Filter>HTM Files</Filter>
+ </None>
+ <None Include="resources\pages\errorPageFunctions.js">
+ <Filter>HTM Files</Filter>
+ </None>
+ <None Include="resources\pages\errorPageStrings.js">
+ <Filter>HTM Files</Filter>
+ </None>
+ <None Include="resources\pages\httpError.htm">
+ <Filter>HTM Files</Filter>
+ </None>
+ <None Include="resources\pages\navCancel.htm">
+ <Filter>HTM Files</Filter>
+ </None>
+ <None Include="resources\pages\winampError.css">
+ <Filter>HTM Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{cc18d279-4ba1-4e7e-95c4-52ce64ca80af}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Ressource Files">
+ <UniqueIdentifier>{c612c69b-09ef-4eec-aed6-7db087ce6658}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{f18b45de-cc4f-407d-860c-fbcdcb0cd89e}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="HTM Files">
+ <UniqueIdentifier>{bb0c9556-c35f-46d0-807e-23eff729fae4}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Image Files">
+ <UniqueIdentifier>{1149c02f-a8b2-4fd9-86d7-7b047edb9a51}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\nu">
+ <UniqueIdentifier>{f10c4fd3-1c66-4bea-baaf-40c6afc19661}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <Image Include="resources\pages\errorIcon.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Src/omBrowser/options.cpp b/Src/omBrowser/options.cpp
new file mode 100644
index 00000000..5a6f94a7
--- /dev/null
+++ b/Src/omBrowser/options.cpp
@@ -0,0 +1,399 @@
+#include "main.h"
+#include "./options.h"
+#include "./optionsHook.h"
+#include "./resource.h"
+
+#include "./ifc_omconfig.h"
+#include "./ifc_ombrowserconfig.h"
+#include "./ifc_omtoolbarconfig.h"
+#include "./ifc_omstatusbarconfig.h"
+
+#include "../winamp/wa_ipc.h"
+
+#include <windows.h>
+#include <commctrl.h>
+#include <shlwapi.h>
+#include <strsafe.h>
+
+HWND CALLBACK OptionsUI_CreatePage(HWND hParent, UINT style);
+HWND CALLBACK OptionsDebug_CreatePage(HWND hParent, UINT style);
+HWND CALLBACK OptionsInfo_CreatePage(HWND hParent, UINT style);
+
+static const OPTIONSPAGECREATOR szPageList[] =
+{
+ OptionsUI_CreatePage,
+ OptionsDebug_CreatePage,
+ OptionsInfo_CreatePage,
+};
+
+typedef struct __OPTIONSDATA
+{
+ obj_ombrowser *browserManager;
+ BROWSEROPTIONSCALLBACK callback;
+ ULONG_PTR user;
+ UINT configCookie;
+ UINT style;
+} OPTIONSDATA;
+
+#define OPTIONS_PROP L"OptionsDataProp"
+#define GetOptions(__hwnd) ((OPTIONSDATA*)GetProp(__hwnd, OPTIONS_PROP))
+
+#define IDC_ACTIVEPAGE 10001
+
+static INT_PTR CALLBACK OptionsFrame_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+HRESULT BrowserOptions_ShowDialog(obj_ombrowser *browserManager, HWND hOwner, UINT style, BROWSEROPTIONSCALLBACK callback, ULONG_PTR user)
+{
+ OPTIONSDATA optionsData = {0};
+ optionsData.browserManager = browserManager;
+ optionsData.callback = callback;
+ optionsData.user = user;
+ optionsData.style = style;
+
+ INT_PTR result = Plugin_DialogBoxParam(MAKEINTRESOURCE(IDD_BROWSER_OPTIONS), hOwner,
+ OptionsFrame_DialogProc, (LPARAM)&optionsData);
+
+ return (0 == result) ? S_OK : E_FAIL;
+}
+
+BOOL Options_SetCheckbox(HWND hwnd, UINT controlId, HRESULT checkedState)
+{
+ HWND hControl = GetDlgItem(hwnd, controlId);
+ if (NULL == hControl) return FALSE;
+
+ if (FAILED(checkedState))
+ {
+ EnableWindow(hControl, FALSE);
+ }
+ else
+ {
+ WPARAM wParam = (S_OK == checkedState) ? BST_CHECKED : BST_UNCHECKED;
+ SendMessage(hControl, BM_SETCHECK, wParam, 0L);
+ EnableWindow(hControl, TRUE);
+ }
+
+ return TRUE;
+}
+
+static void OptionsFrame_NotifyTabSelected(HWND hwnd)
+{
+ HWND hFrame = GetDlgItem(hwnd, IDC_TABFRAME);
+ if (NULL == hFrame) return;
+
+ NMHDR nmh = {0};
+ nmh.code = TCN_SELCHANGE;
+ nmh.hwndFrom = hFrame;
+ nmh.idFrom = GetDlgCtrlID(hFrame);
+ SendNotifyMessage(hwnd, WM_NOTIFY, (WPARAM)nmh.idFrom, (LPARAM)&nmh);
+}
+
+static void OptionsFrame_InitializePages(HWND hwnd, UINT style)
+{
+ HWND hFrame = GetDlgItem(hwnd, IDC_TABFRAME);
+ if (NULL == hFrame) return;
+
+ HWND hWinamp = NULL;
+ if (FAILED(Plugin_GetWinampWnd(&hWinamp)))
+ hWinamp = NULL;
+
+ INT pageCount = 0;
+ WCHAR szBuffer[256] = {0};
+ TCITEM tabItem = {0};
+
+ tabItem.mask = TCIF_TEXT | TCIF_PARAM;
+
+ for (size_t i = 0; i < ARRAYSIZE(szPageList); i++)
+ {
+ HWND hPage = szPageList[i](hwnd, style);
+ if (NULL == hPage) continue;
+
+ if (NULL != hWinamp && 0 == SENDWAIPC(hWinamp, IPC_USE_UXTHEME_FUNC, IPC_ISWINTHEMEPRESENT))
+ SENDWAIPC(hWinamp, IPC_USE_UXTHEME_FUNC, hPage);
+
+ if (0 == GetWindowText(hPage, szBuffer, ARRAYSIZE(szBuffer)))
+ StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), L"Page %d", pageCount + 1);
+
+ tabItem.lParam = (LPARAM)hPage;
+ tabItem.pszText = szBuffer;
+ tabItem.iImage = 0;
+
+ if (-1 != TabCtrl_InsertItem(hFrame, pageCount, &tabItem))
+ {
+ pageCount++;
+ }
+ }
+
+ TabCtrl_SetCurSel(hFrame, 0);
+}
+
+void getViewport(RECT *r, HWND wnd, int full, RECT *sr)
+{
+ POINT *p = NULL;
+ if (p || sr || wnd)
+ {
+ HMONITOR hm = NULL;
+ if (sr)
+ hm = MonitorFromRect(sr, MONITOR_DEFAULTTONEAREST);
+ else if (wnd)
+ hm = MonitorFromWindow(wnd, MONITOR_DEFAULTTONEAREST);
+ else if (p)
+ hm = MonitorFromPoint(*p, MONITOR_DEFAULTTONEAREST);
+
+ if (hm)
+ {
+ MONITORINFOEXW mi;
+ memset(&mi, 0, sizeof(mi));
+ mi.cbSize = sizeof(mi);
+
+ if (GetMonitorInfoW(hm, &mi))
+ {
+ if (!full)
+ *r = mi.rcWork;
+ else
+ *r = mi.rcMonitor;
+
+ return ;
+ }
+ }
+ }
+ if (full)
+ { // this might be borked =)
+ r->top = r->left = 0;
+ r->right = GetSystemMetrics(SM_CXSCREEN);
+ r->bottom = GetSystemMetrics(SM_CYSCREEN);
+ }
+ else
+ {
+ SystemParametersInfoW(SPI_GETWORKAREA, 0, r, 0);
+ }
+}
+
+BOOL windowOffScreen(HWND hwnd, POINT pt)
+{
+ RECT r = {0}, wnd = {0}, sr = {0};
+ GetWindowRect(hwnd, &wnd);
+ sr.left = pt.x;
+ sr.top = pt.y;
+ sr.right = sr.left + (wnd.right - wnd.left);
+ sr.bottom = sr.top + (wnd.bottom - wnd.top);
+ getViewport(&r, hwnd, 0, &sr);
+ return !PtInRect(&r, pt);
+}
+
+static INT_PTR OptionsFrame_OnInitDialog(HWND hwnd, HWND hFocus, LPARAM param)
+{
+ HWND hWinamp = NULL;
+ if (FAILED(Plugin_GetWinampWnd(&hWinamp)))
+ hWinamp = NULL;
+
+ OPTIONSDATA *optionsData = (OPTIONSDATA*)param;
+ SetProp(hwnd, OPTIONS_PROP, optionsData);
+
+ OptionsConfigHook *configHook;
+ if (SUCCEEDED(OptionsConfigHook::CreateInstance(hwnd, &configHook)))
+ {
+ ifc_omconfig *config;
+ if (NULL != optionsData->browserManager && SUCCEEDED(optionsData->browserManager->GetConfig(NULL, (void**)&config)))
+ {
+ config->RegisterCallback(configHook, &optionsData->configCookie);
+ config->Release();
+ }
+ configHook->Release();
+ }
+
+ HWND hFrame = GetDlgItem(hwnd, IDC_TABFRAME);
+ if (NULL != hFrame)
+ {
+ if (NULL != hWinamp && 0 == SENDWAIPC(hWinamp, IPC_USE_UXTHEME_FUNC, IPC_ISWINTHEMEPRESENT))
+ SENDWAIPC(hWinamp, IPC_USE_UXTHEME_FUNC, hFrame);
+
+ TabCtrl_SetMinTabWidth(hFrame, 60);
+ OptionsFrame_InitializePages(hwnd, optionsData->style);
+ OptionsFrame_NotifyTabSelected(hwnd);
+
+ UINT style = GetWindowStyle(hFrame);
+ style |= TCS_HOTTRACK | TCS_TABS | TCS_MULTILINE | TCS_RIGHTJUSTIFY;
+ SetWindowLongPtr(hFrame, GWL_STYLE, style);
+ }
+
+ PostMessage(hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEACCEL | UISF_HIDEFOCUS), 0L);
+
+ if (0 != optionsData->callback)
+ optionsData->callback(hwnd, BOCALLBACK_INIT, optionsData->user);
+
+ // show config window and restore last position as applicable
+ obj_ombrowser *browserManager;
+ if (FALSE != SendMessage(hwnd, BOM_GETBROWSER, 0, (LPARAM)&browserManager))
+ {
+ ifc_ombrowserconfig *browserConfig;
+ if (SUCCEEDED(browserManager->GetConfig(&IFC_OmBrowserConfig, (void**)&browserConfig)))
+ {
+ POINT pt = {-1, -1};
+
+ pt.x = browserConfig->GetX();
+ pt.y = browserConfig->GetY();
+ browserConfig->Release();
+
+ if (!windowOffScreen(hwnd, pt))
+ SetWindowPos(hwnd, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOSENDCHANGING);
+ }
+ browserManager->Release();
+ }
+
+ return 0;
+}
+
+static void OptionsFrame_OnDestroy(HWND hwnd)
+{
+ obj_ombrowser *browserManager;
+ if (FALSE != SendMessage(hwnd, BOM_GETBROWSER, 0, (LPARAM)&browserManager))
+ {
+ ifc_ombrowserconfig *browserConfig;
+ if (SUCCEEDED(browserManager->GetConfig(&IFC_OmBrowserConfig, (void**)&browserConfig)))
+ {
+ RECT rect = {0};
+ GetWindowRect(hwnd, &rect);
+
+ browserConfig->SetX(rect.left);
+ browserConfig->SetY(rect.top);
+ browserConfig->Release();
+ }
+ browserManager->Release();
+ }
+
+ OPTIONSDATA *optionsData = GetOptions(hwnd);
+ RemoveProp(hwnd, OPTIONS_PROP);
+
+ if (NULL == optionsData)
+ return;
+
+ if (0 != optionsData->configCookie)
+ {
+ ifc_omconfig *config;
+ if (NULL != optionsData->browserManager && SUCCEEDED(optionsData->browserManager->GetConfig(NULL, (void**)&config)))
+ {
+ config->UnregisterCallback(optionsData->configCookie);
+ config->Release();
+ }
+ optionsData->configCookie = 0;
+ }
+}
+
+static void OptionsFrame_OnWindowPosChanged(HWND hwnd, WINDOWPOS *pwp)
+{
+}
+
+static void OptionsFrame_OnTabSelected(HWND hwnd, HWND hFrame)
+{
+ if (NULL == hFrame) return;
+
+ HWND hPageOld = GetDlgItem(hwnd, IDC_ACTIVEPAGE);
+ if (NULL != hPageOld)
+ SetWindowLongPtr(hPageOld, GWLP_ID, 0);
+
+ INT iSelected = TabCtrl_GetCurSel(hFrame);
+ TCITEM tabItem;
+ tabItem.mask = TCIF_PARAM;
+
+ HWND hPage = (TRUE == TabCtrl_GetItem(hFrame, iSelected, &tabItem)) ? (HWND)tabItem.lParam : NULL;
+
+ if (NULL != hPage)
+ {
+ SetWindowLongPtr(hPage, GWLP_ID, IDC_ACTIVEPAGE);
+
+ RECT rcTab;
+ GetClientRect(hFrame, &rcTab);
+ MapWindowPoints(hFrame, hwnd, (POINT*)&rcTab, 2);
+ TabCtrl_AdjustRect(hFrame, FALSE, &rcTab);
+
+ SetWindowPos(hPage, HWND_TOP, rcTab.left, rcTab.top,
+ rcTab.right - rcTab.left, rcTab.bottom - rcTab.top,
+ SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOREDRAW);
+ }
+
+ if (NULL != hPage)
+ {
+ ShowWindow(hPage, SW_SHOWNA);
+ }
+
+ if (NULL != hPageOld)
+ {
+ ShowWindow(hPageOld, SW_HIDE);
+ if (NULL != hPage)
+ RedrawWindow(hPage, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_NOINTERNALPAINT | RDW_NOERASE);
+ }
+}
+
+static void OptionsFrame_OnCommand(HWND hwnd, INT commandId, INT eventId, HWND hControl)
+{
+ switch(commandId)
+ {
+ case IDOK:
+ case IDCANCEL:
+ EndDialog(hwnd, 0);
+ break;
+ }
+}
+
+static LRESULT OptionsFrame_OnNotify(HWND hwnd, INT controlId, NMHDR *pnmh)
+{
+ switch(controlId)
+ {
+ case IDC_TABFRAME:
+ switch(pnmh->code)
+ {
+ case TCN_SELCHANGE:
+ OptionsFrame_OnTabSelected(hwnd, pnmh->hwndFrom);
+ break;
+ }
+ break;
+ }
+ return 0;
+}
+
+static LRESULT OptionsFrame_OnGetBrowser(HWND hwnd, obj_ombrowser **ppBrowser)
+{
+ if (NULL == ppBrowser) return FALSE;
+
+ OPTIONSDATA *optionsData = GetOptions(hwnd);
+ if (NULL == optionsData || NULL == optionsData->browserManager)
+ return FALSE;
+
+ *ppBrowser = optionsData->browserManager;
+ (*ppBrowser)->AddRef();
+ return TRUE;
+}
+
+static void OptionsFrame_OnConfigChanged(HWND hwnd, BOMCONFIGCHANGED *configData)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_TABFRAME);
+ if (NULL == hControl) return;
+
+ TCITEM item = {0};
+ item.mask = TCIF_PARAM;
+
+ INT count = (INT)SendMessage(hControl, TCM_GETITEMCOUNT, 0, 0L);
+ for(INT i = 0; i < count; i++)
+ {
+ if (FALSE != (BOOL)SendMessage(hControl, TCM_GETITEM, (WPARAM)i, (LPARAM)&item) &&
+ NULL != item.lParam)
+ {
+ SendMessage((HWND)item.lParam, BOM_CONFIGCHANGED, 0, (LPARAM)configData);
+ }
+ }
+}
+
+static INT_PTR CALLBACK OptionsFrame_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG: return OptionsFrame_OnInitDialog(hwnd, (HWND)wParam, lParam);
+ case WM_DESTROY: OptionsFrame_OnDestroy(hwnd); return 0;
+ case WM_WINDOWPOSCHANGED: OptionsFrame_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); return TRUE;
+ case WM_COMMAND: OptionsFrame_OnCommand(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); return TRUE;
+ case WM_NOTIFY: MSGRESULT(hwnd, OptionsFrame_OnNotify(hwnd, (INT)wParam, (NMHDR*)lParam));
+ case BOM_GETBROWSER: MSGRESULT(hwnd, OptionsFrame_OnGetBrowser(hwnd, (obj_ombrowser**)lParam));
+ case BOM_CONFIGCHANGED: OptionsFrame_OnConfigChanged(hwnd, (BOMCONFIGCHANGED*)lParam); return TRUE;
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/Src/omBrowser/options.h b/Src/omBrowser/options.h
new file mode 100644
index 00000000..e2243c26
--- /dev/null
+++ b/Src/omBrowser/options.h
@@ -0,0 +1,37 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_OPTIONS_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_OPTIONS_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./browserUiCommon.h"
+#include "./obj_ombrowser.h"
+
+
+HRESULT BrowserOptions_ShowDialog(obj_ombrowser *browserManager, HWND hOwner, UINT style, BROWSEROPTIONSCALLBACK callback, ULONG_PTR user);
+
+typedef HWND (CALLBACK *OPTIONSPAGECREATOR)(HWND /*hParent*/, UINT /*style*/);
+HRESULT BrowserOptions_RegisterPage(OPTIONSPAGECREATOR creatorFn);
+HRESULT BrowserOptions_UnregisterPage(OPTIONSPAGECREATOR creatorFn);
+
+#define BOM_FIRST (WM_APP + 10)
+#define BOM_GETBROWSER (BOM_FIRST + 0) // wParam - not used; lParam = (LPARAM)(obj_ombrowser**)ppBrowser; Return TRUE on success;
+#define BrowserOptions_GetBrowser(/*HWND*/ __hOptions, /*obj_ombrowser** */ __ppBrowser)\
+ ((BOOL)SENDMSG((__hOptions), BOM_GETBROWSER, 0, (LPARAM)(__ppBrowser)))
+
+typedef struct __BOMCONFIGCHANGED
+{
+ const GUID *configUid;
+ UINT valueId;
+ ULONG_PTR value;
+} BOMCONFIGCHANGED;
+
+#define BOM_CONFIGCHANGED (BOM_FIRST + 1) // wParam - not used; lParam = (LPARAM)(BOMCONFIGCHANGED*)configData;
+#define BrowserOptions_ConfigChanged(/*HWND*/ __hOptions, /*BOM_CONFIGCHANGED* */ __configData)\
+ (SENDMSG((__hOptions), BOM_CONFIGCHANGED, 0, (LPARAM)(__ppBrowser)))
+
+// Internal Helpers
+BOOL Options_SetCheckbox(HWND hwnd, UINT controlId, HRESULT checkedState);
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_OPTIONS_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/optionsDebug.cpp b/Src/omBrowser/optionsDebug.cpp
new file mode 100644
index 00000000..2f798493
--- /dev/null
+++ b/Src/omBrowser/optionsDebug.cpp
@@ -0,0 +1,203 @@
+#include "main.h"
+#include "./options.h"
+#include "./resource.h"
+
+#include "./obj_ombrowser.h"
+#include "./ifc_omconfig.h"
+#include "./ifc_omdebugconfig.h"
+
+#include <windows.h>
+#include <commctrl.h>
+#include <shlwapi.h>
+#include <strsafe.h>
+
+
+#define INVERTHRESULT(__result)\
+ ((S_OK == (__result)) ? S_FALSE : ((S_FALSE == (__result)) ? S_OK : (__result)))
+
+#define BOOL2HRESULT(__result)\
+ ((FALSE != (__result)) ? S_OK : S_FALSE)
+
+static INT_PTR CALLBACK OptionsDebug_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+
+HWND CALLBACK OptionsDebug_CreatePage(HWND hParent, UINT style)
+{
+ if (0 == (BOSTYLE_SHOWDEBUG & style))
+ return NULL;
+
+ return Plugin_CreateDialogParam(MAKEINTRESOURCE(IDD_OPTIONS_DEBUG), hParent, OptionsDebug_DialogProc, 0L);
+}
+
+static void OptionsDebug_UpdateFilterMenu(HWND hwnd, HRESULT enable)
+{
+ Options_SetCheckbox(hwnd, IDC_FILTERMENU, INVERTHRESULT(enable));
+}
+
+static void OptionsDebug_UpdateShowError(HWND hwnd, HRESULT enable)
+{
+ Options_SetCheckbox(hwnd, IDC_SHOWERROR, enable);
+}
+
+static void OptionsDebug_UpdateShowDebugger(HWND hwnd, HRESULT enable)
+{
+ Options_SetCheckbox(hwnd, IDC_SHOWDEBUGGER, enable);
+}
+
+
+static INT_PTR OptionsDebug_OnInitDialog(HWND hwnd, HWND hFocus, LPARAM param)
+{
+ WCHAR szBuffer[512] = {0};
+ Plugin_LoadString(IDS_OPTIONS_DEBUG, szBuffer, ARRAYSIZE(szBuffer));
+ SetWindowText(hwnd, szBuffer);
+
+ HWND hParent = GetParent(hwnd);
+
+ obj_ombrowser *browserManager;
+ if (FALSE == SendMessage(hParent, BOM_GETBROWSER, 0, (LPARAM)&browserManager))
+ browserManager = NULL;
+
+ ifc_omdebugconfig *debugConfig;
+
+ if (NULL != browserManager &&
+ SUCCEEDED(browserManager->GetConfig(&IFC_OmDebugConfig, (void**)&debugConfig)))
+ {
+ OptionsDebug_UpdateFilterMenu(hwnd, debugConfig->GetMenuFilterEnabled());
+ OptionsDebug_UpdateShowError(hwnd, debugConfig->GetScriptErrorEnabled());
+ OptionsDebug_UpdateShowDebugger(hwnd, debugConfig->GetScriptDebuggerEnabled());
+ debugConfig->Release();
+ }
+ else
+ {
+ OptionsDebug_UpdateFilterMenu(hwnd, E_FAIL);
+ OptionsDebug_UpdateShowError(hwnd, E_FAIL);
+ OptionsDebug_UpdateShowDebugger(hwnd, E_FAIL);
+ }
+
+ return 0;
+}
+
+static void OptionsDebug_OnDestroy(HWND hwnd)
+{
+}
+
+static void OptionsDebug_OnFilterMenu(HWND hwnd)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_FILTERMENU);
+ if (NULL == hControl) return;
+
+ HWND hParent = GetParent(hwnd);
+ if (NULL == hParent) return;
+
+ BOOL checked = (BST_CHECKED == (UINT)SendMessage(hControl, BM_GETCHECK, 0, 0L));
+
+ obj_ombrowser *browserManager;
+ if (FALSE != SendMessage(hParent, BOM_GETBROWSER, 0, (LPARAM)&browserManager))
+ {
+ ifc_omdebugconfig *debugConfig;
+ if (SUCCEEDED(browserManager->GetConfig(&IFC_OmDebugConfig, (void**)&debugConfig)))
+ {
+ debugConfig->EnableMenuFilter(!checked);
+ debugConfig->Release();
+ }
+ browserManager->Release();
+ }
+}
+
+static void OptionsDebug_OnShowError(HWND hwnd)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_SHOWERROR);
+ if (NULL == hControl) return;
+
+ HWND hParent = GetParent(hwnd);
+ if (NULL == hParent) return;
+
+ BOOL checked = (BST_CHECKED == (UINT)SendMessage(hControl, BM_GETCHECK, 0, 0L));
+
+ obj_ombrowser *browserManager;
+ if (FALSE != SendMessage(hParent, BOM_GETBROWSER, 0, (LPARAM)&browserManager))
+ {
+ ifc_omdebugconfig *debugConfig;
+ if (SUCCEEDED(browserManager->GetConfig(&IFC_OmDebugConfig, (void**)&debugConfig)))
+ {
+ debugConfig->EnableScriptError(checked);
+ debugConfig->Release();
+ }
+ browserManager->Release();
+ }
+}
+
+static void OptionsDebug_OnShowDebugger(HWND hwnd)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_SHOWDEBUGGER);
+ if (NULL == hControl) return;
+
+ HWND hParent = GetParent(hwnd);
+ if (NULL == hParent) return;
+
+ BOOL checked = (BST_CHECKED == (UINT)SendMessage(hControl, BM_GETCHECK, 0, 0L));
+
+ obj_ombrowser *browserManager;
+ if (FALSE != SendMessage(hParent, BOM_GETBROWSER, 0, (LPARAM)&browserManager))
+ {
+ ifc_omdebugconfig *debugConfig;
+ if (SUCCEEDED(browserManager->GetConfig(&IFC_OmDebugConfig, (void**)&debugConfig)))
+ {
+ debugConfig->EnableScriptDebugger(checked);
+ debugConfig->Release();
+ }
+ browserManager->Release();
+ }
+}
+
+static void OptionsDebug_OnConfigChanged(HWND hwnd, BOMCONFIGCHANGED *configData)
+{
+ if (NULL == configData || NULL == configData->configUid ||
+ FALSE == IsEqualIID(IFC_OmDebugConfig, *configData->configUid))
+ {
+ return;
+ }
+
+
+ switch(configData->valueId)
+ {
+ case CFGID_DEBUG_FILTERMENU: OptionsDebug_UpdateFilterMenu(hwnd, BOOL2HRESULT(configData->value)); break;
+ case CFGID_DEBUG_SCRIPTERROR: OptionsDebug_UpdateShowError(hwnd, BOOL2HRESULT(configData->value)); break;
+ case CFGID_DEBUG_SCRIPTDEBUGGER: OptionsDebug_UpdateShowDebugger(hwnd, BOOL2HRESULT(configData->value)); break;
+ }
+
+}
+static void OptionsDebug_OnCommand(HWND hwnd, INT commandId, INT eventId, HWND hControl)
+{
+ switch(commandId)
+ {
+ case IDC_FILTERMENU:
+ if (BN_CLICKED == eventId)
+ OptionsDebug_OnFilterMenu(hwnd);
+ break;
+ case IDC_SHOWERROR:
+ if (BN_CLICKED == eventId)
+ OptionsDebug_OnShowError(hwnd);
+ break;
+ case IDC_SHOWDEBUGGER:
+ if (BN_CLICKED == eventId)
+ OptionsDebug_OnShowDebugger(hwnd);
+ break;
+ }
+
+}
+
+
+
+static INT_PTR CALLBACK OptionsDebug_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG: return OptionsDebug_OnInitDialog(hwnd, (HWND)wParam, lParam);
+ case WM_DESTROY: OptionsDebug_OnDestroy(hwnd); return 0;
+ case WM_COMMAND: OptionsDebug_OnCommand(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); return TRUE;
+
+ case BOM_CONFIGCHANGED: OptionsDebug_OnConfigChanged(hwnd, (BOMCONFIGCHANGED*)lParam); return TRUE;
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/Src/omBrowser/optionsHook.cpp b/Src/omBrowser/optionsHook.cpp
new file mode 100644
index 00000000..cc7c814f
--- /dev/null
+++ b/Src/omBrowser/optionsHook.cpp
@@ -0,0 +1,93 @@
+#include "main.h"
+#include "./optionsHook.h"
+#include "./options.h"
+
+#include "./ifc_omtoolbarconfig.h"
+#include "./ifc_omstatusbarconfig.h"
+
+#include <strsafe.h>
+
+OptionsConfigHook::OptionsConfigHook(HWND hTarget)
+ : ref(1), hwnd(hTarget)
+{
+}
+
+OptionsConfigHook::~OptionsConfigHook()
+{
+}
+
+HRESULT OptionsConfigHook::CreateInstance(HWND hTarget, OptionsConfigHook **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ *instance = NULL;
+
+ if (NULL == hTarget || FALSE == IsWindow(hTarget))
+ return E_INVALIDARG;
+
+ *instance = new OptionsConfigHook(hTarget);
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t OptionsConfigHook::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t OptionsConfigHook::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int OptionsConfigHook::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ else if (IsEqualIID(interface_guid, IFC_OmConfigCallback))
+ *object = static_cast<ifc_omconfigcallback*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT OptionsConfigHook::ValueChanged(const GUID *configUid, UINT valueId, ULONG_PTR value)
+{
+ if (NULL == configUid)
+ return E_UNEXPECTED;
+
+ BOMCONFIGCHANGED configData;
+ configData.configUid = configUid;
+ configData.valueId = valueId;
+ configData.value = value;
+
+ DWORD_PTR result;
+ SendMessageTimeout(hwnd, BOM_CONFIGCHANGED, 0, (LPARAM)&configData, SMTO_ABORTIFHUNG | SMTO_NORMAL, 2000, &result);
+ return S_OK;
+}
+
+#define CBCLASS OptionsConfigHook
+START_DISPATCH;
+ CB(ADDREF, AddRef);
+ CB(RELEASE, Release);
+ CB(QUERYINTERFACE, QueryInterface);
+ CB(API_VALUECHANGED, ValueChanged);
+END_DISPATCH;
+#undef CBCLASS
+
+
diff --git a/Src/omBrowser/optionsHook.h b/Src/omBrowser/optionsHook.h
new file mode 100644
index 00000000..10f83f6a
--- /dev/null
+++ b/Src/omBrowser/optionsHook.h
@@ -0,0 +1,39 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_OPTIONS_HOOK_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_OPTIONS_HOOK_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_omconfigcallback.h"
+
+class ifc_omservice;
+
+class OptionsConfigHook : public ifc_omconfigcallback
+{
+protected:
+ OptionsConfigHook(HWND hTarget);
+ ~OptionsConfigHook();
+
+public:
+ static HRESULT CreateInstance(HWND hTarget, OptionsConfigHook **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_omconfigcallback */
+ HRESULT ValueChanged(const GUID *configUid, UINT valueId, ULONG_PTR value);
+
+protected:
+ RECVS_DISPATCH;
+
+protected:
+ ULONG ref;
+ HWND hwnd;
+};
+
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_OPTIONS_HOOK_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/optionsInfo.cpp b/Src/omBrowser/optionsInfo.cpp
new file mode 100644
index 00000000..b92d9017
--- /dev/null
+++ b/Src/omBrowser/optionsInfo.cpp
@@ -0,0 +1,199 @@
+#include "main.h"
+#include "./options.h"
+#include "./resource.h"
+
+#include "./obj_ombrowser.h"
+#include "./ifc_omconfig.h"
+#include "./ifc_ombrowserclass.h"
+#include "./ieversion.h"
+
+#include <windows.h>
+#include <shlwapi.h>
+#include <strsafe.h>
+
+
+static INT_PTR CALLBACK OptionsInfo_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+HWND CALLBACK OptionsInfo_CreatePage(HWND hParent, UINT style)
+{
+ return Plugin_CreateDialogParam(MAKEINTRESOURCE(IDD_OPTIONS_INFO), hParent, OptionsInfo_DialogProc, 0L);
+}
+
+static void OptionsInfo_SetClassName(HWND hwnd, obj_ombrowser *browserManager)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_CLASS);
+ if (NULL == hControl) return;
+
+ WCHAR szBuffer[512] = {0};
+
+ BOOL valueInvalid = TRUE;
+ ifc_ombrowserclass *browserClass;
+ if (NULL != browserManager && SUCCEEDED(browserManager->GetClass(&browserClass)))
+ {
+ if (SUCCEEDED(browserClass->GetName(szBuffer, ARRAYSIZE(szBuffer))))
+ valueInvalid = FALSE;
+ browserClass->Release();
+ }
+
+ if (FALSE != valueInvalid)
+ Plugin_LoadString(IDS_UNKNOWN, szBuffer, ARRAYSIZE(szBuffer));
+
+ SetWindowText(hControl, szBuffer);
+}
+
+
+static void OptionsInfo_SetConfigPath(HWND hwnd, obj_ombrowser *browserManager)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_CONFIGPATH);
+ if (NULL == hControl) return;
+
+ WCHAR szBuffer[512] = {0};
+
+ BOOL valueInvalid = TRUE;
+ ifc_omconfig *browserConfig;
+ if (NULL != browserManager && SUCCEEDED(browserManager->GetConfig(NULL, (void**)&browserConfig)))
+ {
+ if (SUCCEEDED(browserConfig->GetPath(szBuffer, ARRAYSIZE(szBuffer))))
+ valueInvalid = FALSE;
+ browserConfig->Release();
+ }
+
+ if (FALSE != valueInvalid)
+ Plugin_LoadString(IDS_UNKNOWN, szBuffer, ARRAYSIZE(szBuffer));
+
+ SetWindowText(hControl, szBuffer);
+}
+
+
+static void OptionsInfo_SetIEVersion(HWND hwnd)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_MSIEVERSION);
+ if (NULL == hControl) return;
+
+ WCHAR szBuffer[128] = {0};
+ if (FAILED(MSIE_GetVersionString(szBuffer, ARRAYSIZE(szBuffer))))
+ Plugin_LoadString(IDS_UNKNOWN, szBuffer, ARRAYSIZE(szBuffer));
+
+ SetWindowText(hControl, szBuffer);
+}
+
+static void OptionsInfo_SetVersion(HWND hwnd, obj_ombrowser *browserManager)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_VERSION);
+ if (NULL == hControl) return;
+
+ WCHAR szBuffer[32] = {0};
+ INT major, minor;
+ if (NULL == browserManager ||
+ FAILED(browserManager->GetVersion(&major, &minor)) ||
+ FAILED(StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), L"%d.%d", major, minor)))
+ {
+ Plugin_LoadString(IDS_UNKNOWN, szBuffer, ARRAYSIZE(szBuffer));
+ }
+
+ SetWindowText(hControl, szBuffer);
+}
+
+static void OptionsInfo_SetClientId(HWND hwnd, obj_ombrowser *browserManager)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_CLIENTID);
+ if (NULL == hControl) return;
+
+ WCHAR szBuffer[256] = {0};
+ if (NULL == browserManager || FAILED(browserManager->GetClientId(szBuffer, ARRAYSIZE(szBuffer))))
+ Plugin_LoadString(IDS_UNKNOWN, szBuffer, ARRAYSIZE(szBuffer));
+
+ SetWindowText(hControl, szBuffer);
+}
+
+static void OptionsInfo_SetSessionId(HWND hwnd, obj_ombrowser *browserManager)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_SESSIONID);
+ if (NULL == hControl) return;
+
+ WCHAR szBuffer[256] = {0};
+ if (NULL == browserManager || FAILED(browserManager->GetSessionId(szBuffer, ARRAYSIZE(szBuffer))))
+ Plugin_LoadString(IDS_UNKNOWN, szBuffer, ARRAYSIZE(szBuffer));
+
+ SetWindowText(hControl, szBuffer);
+}
+
+static void OptionsInfo_SetTitleFont(HWND hwnd)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_TITLE);
+ if (NULL == hControl) return;
+
+ LOGFONT lfTitle;
+ HFONT hFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L);
+ INT fontHeight;
+ fontHeight = (NULL != hFont && 0 != GetObject(hFont, sizeof(lfTitle), &lfTitle)) ? lfTitle.lfHeight : -11;
+ fontHeight += (fontHeight > 0) ? 2 : -2;
+
+ ZeroMemory(&lfTitle, sizeof(lfTitle));
+ lfTitle.lfHeight = fontHeight;
+ lfTitle.lfWeight = FW_NORMAL;
+ lfTitle.lfItalic = FALSE;
+ lfTitle.lfUnderline = FALSE;
+ lfTitle.lfStrikeOut = FALSE;
+ lfTitle.lfCharSet = DEFAULT_CHARSET;
+ lfTitle.lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lfTitle.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lfTitle.lfQuality = CLEARTYPE_QUALITY;
+ lfTitle.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ StringCchCopy(lfTitle.lfFaceName, ARRAYSIZE(lfTitle.lfFaceName), L"Arial");
+
+ HFONT titleFont = CreateFontIndirect(&lfTitle);
+ if (NULL == titleFont) return;
+
+ SendMessage(hControl, WM_SETFONT, (WPARAM)titleFont, 0);
+}
+
+static INT_PTR OptionsInfo_OnInitDialog(HWND hwnd, HWND hFocus, LPARAM param)
+{
+ WCHAR szBuffer[512] = {0};
+ Plugin_LoadString(IDS_OPTIONS_INFO, szBuffer, ARRAYSIZE(szBuffer));
+ SetWindowText(hwnd, szBuffer);
+
+ HWND hParent = GetParent(hwnd);
+
+ obj_ombrowser *browserManager;
+ if (FALSE == SendMessage(hParent, BOM_GETBROWSER, 0, (LPARAM)&browserManager))
+ browserManager = NULL;
+
+ OptionsInfo_SetVersion(hwnd, browserManager);
+ OptionsInfo_SetClassName(hwnd, browserManager);
+ OptionsInfo_SetClientId(hwnd, browserManager);
+ OptionsInfo_SetSessionId(hwnd, browserManager);
+ OptionsInfo_SetConfigPath(hwnd, browserManager);
+ OptionsInfo_SetIEVersion(hwnd);
+
+ if (NULL != browserManager)
+ browserManager->Release();
+
+ OptionsInfo_SetTitleFont(hwnd);
+
+ return 0;
+}
+
+static void OptionsInfo_OnDestroy(HWND hwnd)
+{
+}
+
+static INT_PTR OptionsInfo_OnColorStatic(HWND hwnd, HDC hdc, HWND hControl)
+{
+ UINT controlId = (UINT)GetWindowLongPtr(hControl, GWLP_ID);
+ if (((UINT)-1) == controlId)
+ SetTextColor(hdc, GetSysColor(COLOR_HOTLIGHT));
+ return 0;
+}
+
+static INT_PTR CALLBACK OptionsInfo_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG: return OptionsInfo_OnInitDialog(hwnd, (HWND)wParam, lParam);
+ case WM_DESTROY: OptionsInfo_OnDestroy(hwnd); return 0;
+ case WM_CTLCOLORSTATIC: return OptionsInfo_OnColorStatic(hwnd, (HDC)wParam, (HWND)lParam);
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/Src/omBrowser/optionsUi.cpp b/Src/omBrowser/optionsUi.cpp
new file mode 100644
index 00000000..c0dd4f5a
--- /dev/null
+++ b/Src/omBrowser/optionsUi.cpp
@@ -0,0 +1,373 @@
+#include "main.h"
+#include "./options.h"
+#include "./resource.h"
+
+#include "./obj_ombrowser.h"
+#include "./ifc_omconfig.h"
+#include "./ifc_omtoolbarconfig.h"
+#include "./ifc_omstatusbarconfig.h"
+
+#include <windows.h>
+#include <commctrl.h>
+#include <shlwapi.h>
+#include <strsafe.h>
+
+#define TOOLBAR_TOPDOCK 0
+#define TOOLBAR_BOTTOMDOCK 1
+
+#define BOOL2HRESULT(__result) ((FALSE != (__result)) ? S_OK : S_FALSE)
+
+static INT_PTR CALLBACK OptionsUI_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+HWND CALLBACK OptionsUI_CreatePage(HWND hParent, UINT style)
+{
+ return Plugin_CreateDialogParam(MAKEINTRESOURCE(IDD_OPTIONS_UI), hParent, OptionsUI_DialogProc, 0L);
+}
+
+static INT OptionsUI_GetLocationIndex(HWND hwnd, UINT locationId)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_TOOLBAR_LOCATION);
+ if (NULL == hControl) return CB_ERR;
+
+ INT count = (INT)SendMessage(hControl, CB_GETCOUNT, 0, 0L);
+ for (INT i = 0; i < count; i++)
+ {
+ if (locationId == (UINT)SendMessage(hControl, CB_GETITEMDATA, i, 0L))
+ return i;
+ }
+ return CB_ERR;
+}
+
+static void OptionsUI_UpdateToolbarLocation(HWND hwnd, HRESULT bottomLocation)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_TOOLBAR_LOCATION);
+ if (NULL == hControl) return;
+
+ if (FAILED(bottomLocation))
+ {
+ EnableWindow(hControl, FALSE);
+ }
+ else
+ {
+ INT iIndex = OptionsUI_GetLocationIndex(hwnd, (S_OK == bottomLocation) ? TOOLBAR_BOTTOMDOCK : TOOLBAR_TOPDOCK);
+ if (CB_ERR != iIndex)
+ SendMessage(hControl, CB_SETCURSEL, iIndex, 0L);
+
+ EnableWindow(hControl, TRUE);
+ }
+}
+
+static void OptionsUI_UpdateToolbarAutoHide(HWND hwnd, HRESULT autoHide)
+{
+ Options_SetCheckbox(hwnd, IDC_TOOLBAR_AUTOHIDE, autoHide);
+}
+
+static void OptionsUI_UpdateToolbarTabStop(HWND hwnd, HRESULT tabStop)
+{
+ Options_SetCheckbox(hwnd, IDC_TOOLBAR_TABSTOP, tabStop);
+}
+
+static void OptionsUI_UpdateToolbarForceAddress(HWND hwnd, HRESULT enabled)
+{
+ Options_SetCheckbox(hwnd, IDC_TOOLBAR_FORCEADDRESS, enabled);
+}
+
+static void OptionsUI_UpdateToolbarFancyAddress(HWND hwnd, HRESULT enabled)
+{
+ Options_SetCheckbox(hwnd, IDC_TOOLBAR_FANCYADDRESS, enabled);
+}
+
+static void OptionsUI_UpdateStatusbarEnabled(HWND hwnd, HRESULT enabled)
+{
+ Options_SetCheckbox(hwnd, IDC_STATUSBAR_ENABLED, enabled);
+}
+
+static INT_PTR OptionsUI_OnInitDialog(HWND hwnd, HWND hFocus, LPARAM param)
+{
+ WCHAR szBuffer[512] = {0};
+ Plugin_LoadString(IDS_OPTIONS_UI, szBuffer, ARRAYSIZE(szBuffer));
+ SetWindowText(hwnd, szBuffer);
+
+ HWND hControl = GetDlgItem(hwnd, IDC_TOOLBAR_LOCATION);
+ if (NULL != hControl)
+ {
+ INT iItem;
+
+ Plugin_LoadString(IDS_TOOLBAR_TOPDOCK, szBuffer, ARRAYSIZE(szBuffer));
+ iItem = (INT)(INT_PTR)SendMessage(hControl, CB_ADDSTRING, 0, (LPARAM)szBuffer);
+ if (CB_ERR != iItem)
+ SendMessage(hControl, CB_SETITEMDATA, (WPARAM)iItem, (LPARAM)TOOLBAR_TOPDOCK);
+
+ Plugin_LoadString(IDS_TOOLBAR_BOTTOMDOCK, szBuffer, ARRAYSIZE(szBuffer));
+ iItem = (INT)(INT_PTR)SendMessage(hControl, CB_ADDSTRING, 0, (LPARAM)szBuffer);
+ if (CB_ERR != iItem)
+ SendMessage(hControl, CB_SETITEMDATA, (WPARAM)iItem, (LPARAM)TOOLBAR_BOTTOMDOCK);
+ }
+
+
+ HWND hParent = GetParent(hwnd);
+
+ obj_ombrowser *browserManager;
+ if (FALSE == SendMessage(hParent, BOM_GETBROWSER, 0, (LPARAM)&browserManager))
+ browserManager = NULL;
+
+ ifc_omtoolbarconfig *toolbarConfig;
+
+ if (NULL != browserManager &&
+ SUCCEEDED(browserManager->GetConfig(&IFC_OmToolbarConfig, (void**)&toolbarConfig)))
+ {
+ OptionsUI_UpdateToolbarLocation(hwnd, toolbarConfig->GetBottomDockEnabled());
+ OptionsUI_UpdateToolbarAutoHide(hwnd, toolbarConfig->GetAutoHideEnabled());
+ OptionsUI_UpdateToolbarTabStop(hwnd, toolbarConfig->GetTabStopEnabled());
+ OptionsUI_UpdateToolbarForceAddress(hwnd, toolbarConfig->GetForceAddressbarEnabled());
+ OptionsUI_UpdateToolbarFancyAddress(hwnd, toolbarConfig->GetFancyAddressbarEnabled());
+
+ toolbarConfig->Release();
+ }
+ else
+ {
+ OptionsUI_UpdateToolbarLocation(hwnd, E_FAIL);
+ OptionsUI_UpdateToolbarAutoHide(hwnd, E_FAIL);
+ OptionsUI_UpdateToolbarTabStop(hwnd, E_FAIL);
+ }
+
+ ifc_omstatusbarconfig *statusbarConfig;
+
+ if (NULL != browserManager &&
+ SUCCEEDED(browserManager->GetConfig(&IFC_OmStatusbarConfig, (void**)&statusbarConfig)))
+ {
+ OptionsUI_UpdateStatusbarEnabled(hwnd, statusbarConfig->GetEnabled());
+ statusbarConfig->Release();
+ }
+ else
+ {
+ OptionsUI_UpdateStatusbarEnabled(hwnd, E_FAIL);
+ }
+
+ if (NULL != browserManager)
+ browserManager->Release();
+
+ return 0;
+}
+
+static void OptionsUI_OnDestroy(HWND hwnd)
+{
+}
+
+static void OptionsUI_OnWindowPosChanged(HWND hwnd, WINDOWPOS *pwp)
+{
+}
+
+static void OptionsUI_OnToolbarLocation(HWND hwnd)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_TOOLBAR_LOCATION);
+ if (NULL == hControl) return;
+
+ HWND hParent = GetParent(hwnd);
+ if (NULL == hParent) return;
+
+ INT iIndex = (INT)SendMessage(hControl, CB_GETCURSEL, 0, 0L);
+ if (CB_ERR == iIndex) return;
+
+ INT dockType = (INT)SendMessage(hControl, CB_GETITEMDATA, iIndex, 0L);
+ if (TOOLBAR_TOPDOCK != dockType && TOOLBAR_BOTTOMDOCK != dockType)
+ return;
+
+ obj_ombrowser *browserManager;
+ if (FALSE != SendMessage(hParent, BOM_GETBROWSER, 0, (LPARAM)&browserManager))
+ {
+ ifc_omtoolbarconfig *toolbarConfig;
+ if (SUCCEEDED(browserManager->GetConfig(&IFC_OmToolbarConfig, (void**)&toolbarConfig)))
+ {
+ toolbarConfig->EnableBottomDock(TOOLBAR_BOTTOMDOCK == dockType);
+ toolbarConfig->Release();
+ }
+ browserManager->Release();
+ }
+}
+
+static void OptionsUI_OnToolbarAutoHide(HWND hwnd)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_TOOLBAR_AUTOHIDE);
+ if (NULL == hControl) return;
+
+ HWND hParent = GetParent(hwnd);
+ if (NULL == hParent) return;
+
+ BOOL checked = (BST_CHECKED == (UINT)SendMessage(hControl, BM_GETCHECK, 0, 0L));
+
+ obj_ombrowser *browserManager;
+ if (FALSE != SendMessage(hParent, BOM_GETBROWSER, 0, (LPARAM)&browserManager))
+ {
+ ifc_omtoolbarconfig *toolbarConfig;
+ if (SUCCEEDED(browserManager->GetConfig(&IFC_OmToolbarConfig, (void**)&toolbarConfig)))
+ {
+ toolbarConfig->EnableAutoHide(checked);
+ toolbarConfig->Release();
+ }
+ browserManager->Release();
+ }
+}
+
+static void OptionsUI_OnToolbarTabstop(HWND hwnd)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_TOOLBAR_TABSTOP);
+ if (NULL == hControl) return;
+
+ HWND hParent = GetParent(hwnd);
+ if (NULL == hParent) return;
+
+ BOOL checked = (BST_CHECKED == (UINT)SendMessage(hControl, BM_GETCHECK, 0, 0L));
+
+ obj_ombrowser *browserManager;
+ if (FALSE != SendMessage(hParent, BOM_GETBROWSER, 0, (LPARAM)&browserManager))
+ {
+ ifc_omtoolbarconfig *toolbarConfig;
+ if (SUCCEEDED(browserManager->GetConfig(&IFC_OmToolbarConfig, (void**)&toolbarConfig)))
+ {
+ toolbarConfig->EnableTabStop(checked);
+ toolbarConfig->Release();
+ }
+ browserManager->Release();
+ }
+}
+
+static void OptionsUI_OnToolbarForceAddress(HWND hwnd)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_TOOLBAR_FORCEADDRESS);
+ if (NULL == hControl) return;
+
+ HWND hParent = GetParent(hwnd);
+ if (NULL == hParent) return;
+
+ BOOL checked = (BST_CHECKED == (UINT)SendMessage(hControl, BM_GETCHECK, 0, 0L));
+
+ obj_ombrowser *browserManager;
+ if (FALSE != SendMessage(hParent, BOM_GETBROWSER, 0, (LPARAM)&browserManager))
+ {
+ ifc_omtoolbarconfig *toolbarConfig;
+ if (SUCCEEDED(browserManager->GetConfig(&IFC_OmToolbarConfig, (void**)&toolbarConfig)))
+ {
+ toolbarConfig->EnableForceAddressbar(checked);
+ toolbarConfig->Release();
+ }
+ browserManager->Release();
+ }
+}
+
+static void OptionsUI_OnToolbarFancyAddress(HWND hwnd)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_TOOLBAR_FANCYADDRESS);
+ if (NULL == hControl) return;
+
+ HWND hParent = GetParent(hwnd);
+ if (NULL == hParent) return;
+
+ BOOL checked = (BST_CHECKED == (UINT)SendMessage(hControl, BM_GETCHECK, 0, 0L));
+
+ obj_ombrowser *browserManager;
+ if (FALSE != SendMessage(hParent, BOM_GETBROWSER, 0, (LPARAM)&browserManager))
+ {
+ ifc_omtoolbarconfig *toolbarConfig;
+ if (SUCCEEDED(browserManager->GetConfig(&IFC_OmToolbarConfig, (void**)&toolbarConfig)))
+ {
+ toolbarConfig->EnableFancyAddressbar(checked);
+ toolbarConfig->Release();
+ }
+ browserManager->Release();
+ }
+}
+
+static void OptionsUI_OnStatusbarEnabled(HWND hwnd)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_STATUSBAR_ENABLED);
+ if (NULL == hControl) return;
+
+ HWND hParent = GetParent(hwnd);
+ if (NULL == hParent) return;
+
+ BOOL checked = (BST_CHECKED == (UINT)SendMessage(hControl, BM_GETCHECK, 0, 0L));
+
+ obj_ombrowser *browserManager;
+ if (FALSE != SendMessage(hParent, BOM_GETBROWSER, 0, (LPARAM)&browserManager))
+ {
+ ifc_omstatusbarconfig *statusbarConfig;
+ if (SUCCEEDED(browserManager->GetConfig(&IFC_OmStatusbarConfig, (void**)&statusbarConfig)))
+ {
+ statusbarConfig->EnableStatusbar(checked);
+ statusbarConfig->Release();
+ }
+ browserManager->Release();
+ }
+}
+
+static void OptionsUI_OnCommand(HWND hwnd, INT commandId, INT eventId, HWND hControl)
+{
+ switch(commandId)
+ {
+ case IDC_TOOLBAR_LOCATION:
+ if (CBN_SELCHANGE == eventId)
+ OptionsUI_OnToolbarLocation(hwnd);
+ break;
+ case IDC_TOOLBAR_AUTOHIDE:
+ if (BN_CLICKED == eventId)
+ OptionsUI_OnToolbarAutoHide(hwnd);
+ break;
+ case IDC_TOOLBAR_TABSTOP:
+ if (BN_CLICKED == eventId)
+ OptionsUI_OnToolbarTabstop(hwnd);
+ break;
+ case IDC_TOOLBAR_FORCEADDRESS:
+ if (BN_CLICKED == eventId)
+ OptionsUI_OnToolbarForceAddress(hwnd);
+ break;
+ case IDC_TOOLBAR_FANCYADDRESS:
+ if (BN_CLICKED == eventId)
+ OptionsUI_OnToolbarFancyAddress(hwnd);
+ break;
+ case IDC_STATUSBAR_ENABLED:
+ if (BN_CLICKED == eventId)
+ OptionsUI_OnStatusbarEnabled(hwnd);
+ break;
+ }
+}
+
+static void OptionsUI_OnConfigChanged(HWND hwnd, BOMCONFIGCHANGED *configData)
+{
+ if (NULL == configData || NULL == configData->configUid)
+ return;
+
+ if (IsEqualIID(IFC_OmToolbarConfig, *configData->configUid))
+ {
+ switch(configData->valueId)
+ {
+ case CFGID_TOOLBAR_BOTTOMDOCK: OptionsUI_UpdateToolbarLocation(hwnd, BOOL2HRESULT(configData->value)); break;
+ case CFGID_TOOLBAR_AUTOHIDE: OptionsUI_UpdateToolbarAutoHide(hwnd, BOOL2HRESULT(configData->value)); break;
+ case CFGID_TOOLBAR_TABSTOP: OptionsUI_UpdateToolbarTabStop(hwnd, BOOL2HRESULT(configData->value)); break;
+ case CFGID_TOOLBAR_FORCEADDRESS: OptionsUI_UpdateToolbarForceAddress(hwnd, BOOL2HRESULT(configData->value)); break;
+ case CFGID_TOOLBAR_FANCYADDRESS: OptionsUI_UpdateToolbarFancyAddress(hwnd, BOOL2HRESULT(configData->value)); break;
+ }
+ }
+ else if (IsEqualIID(IFC_OmStatusbarConfig, *configData->configUid))
+ {
+ switch(configData->valueId)
+ {
+ case CFGID_STATUSBAR_ENABLED: OptionsUI_UpdateStatusbarEnabled(hwnd, BOOL2HRESULT(configData->value)); break;
+ }
+ }
+}
+
+
+static INT_PTR CALLBACK OptionsUI_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG: return OptionsUI_OnInitDialog(hwnd, (HWND)wParam, lParam);
+ case WM_DESTROY: OptionsUI_OnDestroy(hwnd); return 0;
+ case WM_WINDOWPOSCHANGED: OptionsUI_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); return TRUE;
+ case WM_COMMAND: OptionsUI_OnCommand(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); return TRUE;
+
+ case BOM_CONFIGCHANGED: OptionsUI_OnConfigChanged(hwnd, (BOMCONFIGCHANGED*)lParam); return TRUE;
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/Src/omBrowser/png.rc b/Src/omBrowser/png.rc
new file mode 100644
index 00000000..74eed411
--- /dev/null
+++ b/Src/omBrowser/png.rc
@@ -0,0 +1,17 @@
+#include "resource.h"
+/////////////////////////////////////////////////////////////////////////////
+//
+// Data
+//
+IDR_CURTAINPROGRESS_IMAGE RCDATA
+".\\resources\\curtainProgress.png"
+IDR_TOOLBARLARGE_IMAGE RCDATA
+".\\resources\\toolbarLarge.png"
+IDR_TOOLBARPROGRESS_IMAGE RCDATA
+".\\resources\\toolbarProgress.png"
+IDR_MENUARROW_IMAGE RCDATA
+".\\resources\\menuArrow.png"
+IDR_SERVICEICON_IMAGE RCDATA
+".\\resources\\serviceIcon.png"
+IDR_TOOLBARADDRESS_IMAGE RCDATA
+".\\resources\\toolbarAddress.png" \ No newline at end of file
diff --git a/Src/omBrowser/pngLoader.cpp b/Src/omBrowser/pngLoader.cpp
new file mode 100644
index 00000000..abc1c288
--- /dev/null
+++ b/Src/omBrowser/pngLoader.cpp
@@ -0,0 +1,360 @@
+#include "main.h"
+#include "./pngLoader.h"
+#include "./browserObject.h"
+#include "./ifc_wasabihelper.h"
+
+#include <shlwapi.h>
+#include <strsafe.h>
+
+#ifndef LOAD_LIBRARY_AS_IMAGE_RESOURCE
+ #define LOAD_LIBRARY_AS_IMAGE_RESOURCE 0x000000020
+#endif //LOAD_LIBRARY_AS_IMAGE_RESOURCE
+
+PngLoader::PngLoader(HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply)
+ : ref(1), instance(hInstance), name(NULL), flags(0)
+
+{
+ name = Plugin_DuplicateResString(pszName);
+
+ if (FALSE != fPremultiply)
+ flags |= flagPremultiply;
+}
+
+PngLoader::~PngLoader()
+{
+ Plugin_FreeResString(name);
+}
+
+HRESULT PngLoader::CreateInstance(HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply, ifc_omimageloader **imageLoader)
+{
+ if (NULL == imageLoader) return E_POINTER;
+ *imageLoader = NULL;
+ if (NULL == pszName) return E_INVALIDARG;
+
+ *imageLoader = new PngLoader(hInstance, pszName, fPremultiply);
+ if (NULL == *imageLoader) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t PngLoader::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t PngLoader::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int PngLoader::QueryInterface(GUID interface_guid, void **object)
+{
+ return E_NOINTERFACE;
+}
+
+static HRESULT PngLoader_LoadResourceData(const void *data, unsigned int size, void **dataOut, int *cx, int *cy, BOOL fPremultiply)
+{
+ if (NULL == data) return E_INVALIDARG;
+
+ svc_imageLoader *loader = NULL;
+ ifc_wasabihelper *wasabi = NULL;
+ if (FAILED(Plugin_GetWasabiHelper(&wasabi))) return E_UNEXPECTED;
+
+ HRESULT hr = wasabi->GetPngLoader(&loader);
+ wasabi->Release();
+ if (FAILED(hr)) return hr;
+
+
+ *dataOut = (FALSE == fPremultiply) ?
+ loader->loadImageData(data, size, cx, cy) :
+ loader->loadImage(data, size, cx, cy);
+
+ if (NULL == *dataOut)
+ hr = E_OUTOFMEMORY;
+
+ loader->Release();
+ return hr;
+}
+
+static HRESULT PngLoader_LoadFromResource(HINSTANCE hInstance, LPCWSTR pszName, LPCWSTR pszType, void **dataOut, int *cx, int *cy, BOOL fPremultiply)
+{
+ UINT errorCode = 0;
+ HRSRC res = FindResourceW(hInstance, pszName, pszType);
+ if (NULL == res)
+ {
+ errorCode = GetLastError();
+ return HRESULT_FROM_WIN32(errorCode);
+ }
+
+ HRESULT hr;
+ HANDLE handle = LoadResource(hInstance, res);
+ if (NULL == handle)
+ {
+ errorCode = GetLastError();
+ hr = HRESULT_FROM_WIN32(errorCode);
+ }
+ else
+ {
+ UINT resourceSize = SizeofResource(hInstance, res);
+ if (0 == resourceSize)
+ {
+ errorCode = GetLastError();
+ hr = HRESULT_FROM_WIN32(errorCode);
+ }
+ else
+ {
+ void *resourceData = LockResource(handle);
+ if (NULL == resourceData)
+ hr = E_OUTOFMEMORY;
+ else
+ hr = PngLoader_LoadResourceData(resourceData, resourceSize, dataOut, cx, cy, fPremultiply);
+ }
+
+ FreeResource(handle);
+ }
+
+ return hr;
+}
+
+static HRESULT PngLoader_ParseResProtocol(LPWSTR pszAddress, LPCWSTR defaultType, HINSTANCE *module, LPCWSTR *resourceName, LPCWSTR *resourceType)
+{
+ if (NULL == module || NULL == resourceName || NULL == resourceType)
+ return E_POINTER;
+
+ if (NULL == pszAddress || L'\0' == *pszAddress)
+ return E_INVALIDARG;
+
+ INT cchAddress = lstrlenW(pszAddress);
+ const WCHAR szPrefix[] = L"res://";
+ INT cchPrefix = ARRAYSIZE(szPrefix) - 1;
+ if (cchAddress <= cchPrefix)
+ return S_FALSE;
+
+ if (CSTR_EQUAL != CompareStringW(CSTR_INVARIANT, NORM_IGNORECASE, pszAddress, cchPrefix, szPrefix, cchPrefix))
+ return S_FALSE;
+
+ pszAddress += cchPrefix;
+ cchAddress -= cchPrefix;
+
+ LPWSTR resType = NULL;
+ LPWSTR resName = NULL;
+
+ LPWSTR p = pszAddress + cchAddress;
+ while (p != pszAddress && L'/' != *p) p--;
+ if (p != pszAddress && p < (pszAddress + cchAddress))
+ {
+ resName = p + 1;
+ *p = L'\0';
+ p--;
+ }
+
+ if (NULL == resName || L'\0' == *resName)
+ return E_FAIL;
+
+ while (p != pszAddress && L'/' != *p) p--;
+ if (p != pszAddress && p < resName)
+ {
+ resType = p + 1;
+ if (L'\0' == *resType)
+ {
+ resType = NULL;
+ }
+ else
+ {
+ resType = p + 1;
+ *p = L'\0';
+ p--;
+ }
+ }
+
+ HINSTANCE hModule = LoadLibraryExW(pszAddress, NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
+ if (NULL == hModule)
+ {
+ UINT errorCode = GetLastError();
+ if (NULL != resType)
+ {
+ *(resType - 1) = L'/';
+ resType = NULL;
+ hModule = LoadLibraryExW(pszAddress, NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
+ if (NULL == hModule) errorCode = GetLastError();
+ }
+
+ if (ERROR_SUCCESS != errorCode)
+ return HRESULT_FROM_WIN32(errorCode);
+ }
+
+ if (NULL == resType)
+ resType = (LPWSTR)defaultType;
+
+ if (NULL != resType && FALSE == IS_INTRESOURCE(resType) && L'#' == *resType)
+ {
+ INT typeId = 0;
+ if (FALSE != StrToIntExW(resType + 1, STIF_DEFAULT, &typeId))
+ resType = MAKEINTRESOURCEW(typeId);
+ }
+
+ if (NULL != resName && FALSE == IS_INTRESOURCE(resName) && L'#' == *resName)
+ {
+ INT nameId;
+ if (FALSE != StrToIntExW(resName + 1, STIF_DEFAULT, &nameId))
+ resName = MAKEINTRESOURCEW(nameId);
+ }
+
+ *module = hModule;
+ *resourceName = resName;
+ *resourceType = resType;
+ return S_OK;
+}
+
+static HRESULT PngLoader_LoadFromFile(LPWSTR pszPath, void **dataOut, int *cx, int *cy, BOOL fPremultiply)
+{
+ HINSTANCE resModule = NULL;
+ LPCWSTR resName = NULL, resType = NULL;
+ HRESULT hr = PngLoader_ParseResProtocol(pszPath, RT_RCDATA, &resModule, &resName, &resType);
+ if (S_OK == hr)
+ return PngLoader_LoadFromResource(resModule, resName, resType, dataOut, cx, cy, fPremultiply);
+
+ if (FAILED(hr))
+ return hr;
+
+ UINT errorCode = 0;
+ HANDLE hFile = CreateFileW(pszPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
+ if (INVALID_HANDLE_VALUE == hFile)
+ {
+ errorCode = GetLastError();
+ return HRESULT_FROM_WIN32(errorCode);
+ }
+
+ UINT resourceSize = GetFileSize(hFile, NULL);
+ if (INVALID_FILE_SIZE == resourceSize)
+ {
+ errorCode = GetLastError();
+ hr = HRESULT_FROM_WIN32(errorCode);
+ }
+ else
+ {
+ void *resourceData = malloc(resourceSize);
+ if (NULL == resourceData)
+ hr = E_OUTOFMEMORY;
+ else
+ {
+ DWORD readed = 0;
+ if (0 == ReadFile(hFile, resourceData, resourceSize, &readed, NULL) || resourceSize != readed)
+ {
+ errorCode = GetLastError();
+ hr = HRESULT_FROM_WIN32(errorCode);
+ }
+ else
+ {
+ hr = PngLoader_LoadResourceData(resourceData, resourceSize, dataOut, cx, cy, fPremultiply);
+ }
+ free(resourceData);
+ }
+ }
+ CloseHandle(hFile);
+ return hr;
+}
+
+HRESULT PngLoader::LoadData(int *widthOut, int *heightOut, void** dataOut)
+{
+ if (NULL == dataOut)
+ return E_POINTER;
+ *dataOut = NULL;
+
+ return (NULL == instance && !IS_INTRESOURCE(name))?
+ PngLoader_LoadFromFile(name, dataOut, widthOut, heightOut, (0 != (flagPremultiply & flags))) :
+ PngLoader_LoadFromResource(instance, name, RT_RCDATA, dataOut, widthOut, heightOut, (0 != (flagPremultiply & flags)));
+}
+
+HRESULT PngLoader::FreeData(void *data)
+{
+ if (NULL == data)
+ return S_FALSE;
+
+ ifc_wasabihelper *wasabi = NULL;
+ HRESULT hr = Plugin_GetWasabiHelper(&wasabi);
+ if (SUCCEEDED(hr) && wasabi != NULL)
+ {
+ api_memmgr *memoryManager = NULL;
+ hr = wasabi->GetMemoryManager(&memoryManager);
+ if (SUCCEEDED(hr) && memoryManager != NULL)
+ {
+ memoryManager->sysFree(data);
+ memoryManager->Release();
+ }
+ wasabi->Release();
+ }
+ return hr;
+}
+
+HRESULT PngLoader::LoadBitmapEx(HBITMAP *bitmapOut, BITMAPINFOHEADER *headerInfo, void **dataOut)
+{
+ INT imageCX, imageCY;
+
+ if(NULL == bitmapOut) return E_POINTER;
+
+ void *data = NULL;
+ HRESULT hr = LoadData(&imageCX, &imageCY, &data);
+ if (FAILED(hr)) return hr;
+
+ ZeroMemory(headerInfo, sizeof(BITMAPINFOHEADER));
+ headerInfo->biSize = sizeof(BITMAPINFOHEADER);
+ headerInfo->biCompression = BI_RGB;
+ headerInfo->biBitCount = 32;
+ headerInfo->biPlanes = 1;
+ headerInfo->biWidth = imageCX;
+ headerInfo->biHeight = -imageCY;
+
+ *bitmapOut = CreateDIBSection(NULL, (LPBITMAPINFO)headerInfo, DIB_RGB_COLORS, dataOut, NULL, 0);
+ if (NULL != (*bitmapOut))
+ {
+ CopyMemory((*dataOut), data, headerInfo->biWidth * abs(headerInfo->biHeight) * sizeof(DWORD));
+ }
+ else
+ {
+ *dataOut = NULL;
+ hr = E_FAIL;
+ }
+ FreeData(data);
+ return hr;
+}
+
+HRESULT PngLoader::LoadBitmap(HBITMAP *bitmapOut, int *widthOut, int *heightOut)
+{
+ BITMAPINFOHEADER header = {0};
+ void *pixelData = NULL;
+
+ if(NULL == bitmapOut) return E_POINTER;
+
+ HRESULT hr = LoadBitmapEx(bitmapOut, &header, &pixelData);
+ if (SUCCEEDED(hr))
+ {
+ if (NULL != widthOut) *widthOut = header.biWidth;
+ if (NULL != heightOut) *heightOut = header.biHeight;
+ }
+ else
+ {
+ if (NULL != widthOut) *widthOut = 0;
+ if (NULL != heightOut) *heightOut = 0;
+ }
+ return hr;
+}
+
+#define CBCLASS PngLoader
+START_DISPATCH;
+CB(ADDREF, AddRef);
+CB(RELEASE, Release);
+CB(QUERYINTERFACE, QueryInterface);
+CB(API_LOADDATA, LoadData);
+CB(API_FREEDATA, FreeData);
+CB(API_LOADBITMAP, LoadBitmap);
+CB(API_LOADBITMAPEX, LoadBitmapEx);
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/pngLoader.h b/Src/omBrowser/pngLoader.h
new file mode 100644
index 00000000..d03797bc
--- /dev/null
+++ b/Src/omBrowser/pngLoader.h
@@ -0,0 +1,46 @@
+#ifndef NULLSOFT_WINAMP_OMIMAGELOADER_PNG_HEADER
+#define NULLSOFT_WINAMP_OMIMAGELOADER_PNG_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_imageloader.h"
+
+class ifc_wasabihelper;
+
+class PngLoader : public ifc_omimageloader
+{
+protected:
+ PngLoader(HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply);
+ ~PngLoader();
+
+public:
+ static HRESULT CreateInstance(HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply, ifc_omimageloader **imageLoader);
+
+public:
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ HRESULT (LoadData)(int *widthOut, int *heightOut, void **dataOut);
+ HRESULT (FreeData)(void *data);
+ HRESULT (LoadBitmapEx)(HBITMAP *bitmapOut, BITMAPINFOHEADER *headerInfo, void **dataOut);
+ HRESULT (LoadBitmap)(HBITMAP *bitmapOut, int *widthOut, int *heightOut);
+
+protected:
+ RECVS_DISPATCH;
+
+ typedef enum
+ {
+ flagPremultiply = 0x0001,
+ } Flags;
+
+protected:
+ ULONG ref;
+ HINSTANCE instance;
+ LPWSTR name;
+ UINT flags;
+};
+
+#endif //NULLSOFT_WINAMP_OMIMAGELOADER_PNG_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ratingMenu.cpp b/Src/omBrowser/ratingMenu.cpp
new file mode 100644
index 00000000..f8f37c8d
--- /dev/null
+++ b/Src/omBrowser/ratingMenu.cpp
@@ -0,0 +1,148 @@
+#include "main.h"
+#include "./ratingMenu.h"
+#include "./resource.h"
+#include "../nu/menuHelpers.h"
+#include "./ifc_skinhelper.h"
+#include "./ifc_skinnedrating.h"
+#include "./ifc_menucustomizer.h"
+
+#define RATING_MARKER MAKELONG(MAKEWORD('R','A'),MAKEWORD('T','E'))
+
+static BOOL RatingMenu_IsStar(HMENU hMenu, INT itemId, INT *valueOut)
+{
+ WCHAR szBuffer[8] = {0};
+ INT cchBuffer = GetMenuStringW(hMenu, itemId, szBuffer, ARRAYSIZE(szBuffer), MF_BYCOMMAND);
+ if (cchBuffer < 1 || cchBuffer > 5)
+ return FALSE;
+
+ for (INT i = 1; i < cchBuffer; i++)
+ {
+ if (szBuffer[i -1] != szBuffer[i])
+ return FALSE;
+ }
+
+ if (NULL != valueOut)
+ *valueOut = cchBuffer;
+
+ return TRUE;
+}
+
+static HMENU RatingMenu_FindMenuRecur(HMENU hMenu, MENUINFO *pmi, MENUITEMINFO *pmii)
+{
+ if (GetMenuInfo(hMenu, pmi) && RATING_MARKER == pmi->dwMenuData)
+ return hMenu;
+
+ INT count = GetMenuItemCount(hMenu);
+ for(INT i = 0; i < count; i++)
+ {
+ if (GetMenuItemInfo(hMenu, i, TRUE, pmii) && NULL != pmii->hSubMenu)
+ {
+ HMENU hRating = RatingMenu_FindMenuRecur(pmii->hSubMenu, pmi, pmii);
+ if (NULL != hRating)
+ return hRating;
+ }
+ }
+ return NULL;
+}
+
+HMENU RatingMenu_FindMenu(HMENU hMenu)
+{
+ if (NULL == hMenu)
+ return NULL;
+
+ MENUITEMINFO mii = {0};
+ mii.cbSize = sizeof(MENUITEMINFO);
+ mii.fMask = MIIM_SUBMENU;
+
+ MENUINFO mi = {0};
+ mi.cbSize = sizeof(MENUINFO);
+ mi.fMask = MIM_MENUDATA;
+
+ return RatingMenu_FindMenuRecur(hMenu, &mi, &mii);
+}
+
+BOOL RatingMenu_InitializeMenu(HMENU ratingMenu, INT ratingValue)
+{
+ if (NULL == ratingMenu) return FALSE;
+ MENUINFO mi = {0};
+ mi.cbSize = sizeof(MENUINFO);
+ mi.fMask = MIM_MENUDATA;
+ mi.dwMenuData = RATING_MARKER;
+ if (FALSE == SetMenuInfo(ratingMenu, &mi))
+ return FALSE;
+
+ return RatingMenu_SetValue(ratingMenu, ratingValue);
+}
+
+BOOL RatingMenu_SetValue(HMENU ratingMenu, INT ratingValue)
+{
+ if (NULL == ratingMenu) return FALSE;
+
+ INT ratingList[] = { ID_RATING_VALUE_1, ID_RATING_VALUE_2, ID_RATING_VALUE_3,
+ ID_RATING_VALUE_4, ID_RATING_VALUE_5};
+ ratingValue--;
+
+ MENUITEMINFO mii = {0};
+ mii.cbSize = sizeof(MENUITEMINFO);
+
+ UINT type = 0, state = 0;
+ for (INT i = 0; i < ARRAYSIZE(ratingList); i++)
+ {
+ mii.fMask = MIIM_STATE | MIIM_FTYPE;
+ if (GetMenuItemInfo(ratingMenu, ratingList[i], FALSE, &mii))
+ {
+ if (ratingValue == i)
+ {
+ type = mii.fType | MFT_RADIOCHECK;
+ state = mii.fState | MFS_CHECKED;
+ }
+ else
+ {
+ type = mii.fType & ~MFT_RADIOCHECK;
+ state = mii.fState & ~MFS_CHECKED;
+ }
+
+ mii.fMask = 0;
+ if (type != mii.fType)
+ {
+ mii.fType = type;
+ mii.fMask |= MIIM_FTYPE;
+ }
+
+ if (state != mii.fState)
+ {
+ mii.fState = state;
+ mii.fMask |= MIIM_STATE;
+ }
+
+ if (0 != mii.fMask)
+ SetMenuItemInfo(ratingMenu, ratingList[i], FALSE, &mii);
+ }
+ }
+ return TRUE;
+}
+
+HRESULT RatingMenu_GetCustomizer(HMENU hMenu, ifc_menucustomizer **customizer)
+{
+ if (NULL == customizer) return E_POINTER;
+ *customizer = NULL;
+
+ HMENU ratingMenu = RatingMenu_FindMenu(hMenu);
+ if (NULL == ratingMenu)
+ return S_OK;
+
+ ifc_skinhelper *skinHelper = NULL;
+ HRESULT hr = Plugin_GetSkinHelper(&skinHelper);
+ if (FAILED(hr) || skinHelper == NULL) return hr;
+
+ ifc_skinnedrating *skinnedRating = NULL;
+ hr = skinHelper->QueryInterface(IFC_SkinnedRating, (void**)&skinnedRating);
+ if (SUCCEEDED(hr) && skinnedRating != NULL)
+ {
+ hr = skinnedRating->CreateMenuCustomizer(ratingMenu, customizer);
+ skinnedRating->Release();
+ }
+
+ skinHelper->Release();
+ return hr;
+} \ No newline at end of file
diff --git a/Src/omBrowser/ratingMenu.h b/Src/omBrowser/ratingMenu.h
new file mode 100644
index 00000000..26afd0cf
--- /dev/null
+++ b/Src/omBrowser/ratingMenu.h
@@ -0,0 +1,17 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_RATING_MENU_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_RATING_MENU_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+class ifc_menucustomizer;
+
+BOOL RatingMenu_InitializeMenu(HMENU ratingMenu, INT ratingValue);
+HMENU RatingMenu_FindMenu(HMENU hMenu);
+BOOL RatingMenu_SetValue(HMENU ratingMenu, INT ratingValue);
+HRESULT RatingMenu_GetCustomizer(HMENU hMenu, ifc_menucustomizer **customizer);
+
+#include <wtypes.h>
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_RATING_MENU_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/ratingMenuCustomizer.cpp b/Src/omBrowser/ratingMenuCustomizer.cpp
new file mode 100644
index 00000000..bb397d42
--- /dev/null
+++ b/Src/omBrowser/ratingMenuCustomizer.cpp
@@ -0,0 +1,161 @@
+#include "main.h"
+#include "./ratingMenuCustomizer.h"
+#include "./ifc_skinhelper.h"
+#include "./ifc_skinnedrating.h"
+
+#include "../Plugins/General/gen_ml/ml_ipc_0313.h"
+
+#define RATING_MINSPACECX 16
+
+RatingMenuCustomizer::RatingMenuCustomizer(HMENU hMenu, ifc_skinnedrating *skinnedRating)
+ : ref(1), menu(hMenu), skin(skinnedRating)
+{
+ if (NULL != skin)
+ skin->AddRef();
+}
+
+RatingMenuCustomizer::~RatingMenuCustomizer()
+{
+ if (NULL != skin)
+ skin->Release();
+}
+
+HRESULT RatingMenuCustomizer::CreateInstance(HMENU hMenu, ifc_skinnedrating *skinnedRating, RatingMenuCustomizer **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ *instance = NULL;
+
+ if (NULL == hMenu || NULL == skinnedRating) return E_INVALIDARG;
+
+ *instance = new RatingMenuCustomizer(hMenu, skinnedRating);
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t RatingMenuCustomizer::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t RatingMenuCustomizer::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int RatingMenuCustomizer::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_MenuCustomizer))
+ *object = static_cast<ifc_menucustomizer*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+
+INT RatingMenuCustomizer::CustomDraw(HMENU menuInstance, INT action, HDC hdc, LPARAM param)
+{
+ if (menuInstance != menu)
+ return FALSE;
+
+ switch(action)
+ {
+ case MLMENU_ACTION_MEASUREITEM: return MeasureRating(hdc, (MEASUREITEMSTRUCT*)param);
+ case MLMENU_ACTION_DRAWITEM: return MLMENU_WANT_DRAWPART;
+ case MLMENU_ACTION_DRAWBACK: break;
+ case MLMENU_ACTION_DRAWICON: break;
+ case MLMENU_ACTION_DRAWTEXT: return DrawRating(hdc, (DRAWITEMSTRUCT*)param);
+ }
+
+ return FALSE;
+}
+
+HRESULT RatingMenuCustomizer::GetValue(INT itemId, INT *valueOut)
+{
+ if (NULL == menu) return E_UNEXPECTED;
+
+ WCHAR szBuffer[32] = {0};
+ INT cchBuffer = GetMenuStringW(menu, itemId, szBuffer, ARRAYSIZE(szBuffer), MF_BYCOMMAND);
+ if (cchBuffer < 1 || cchBuffer > 5)
+ return E_INVALIDARG;
+
+ for (INT i = 1; i < cchBuffer; i++)
+ {
+ if (szBuffer[i -1] != szBuffer[i])
+ return E_INVALIDARG;
+ }
+
+ if (NULL != valueOut)
+ *valueOut = cchBuffer;
+
+ return S_OK;
+}
+
+INT RatingMenuCustomizer::MeasureRating(HDC hdc, MEASUREITEMSTRUCT *pmis)
+{
+ RECT rect;
+ if (NULL == skin || NULL == hdc ||
+ FAILED(GetValue(pmis->itemID, NULL)) ||
+ FAILED(skin->CalcMinRect(5, &rect)))
+ {
+ return FALSE;
+ }
+
+ pmis->itemHeight = rect.bottom - rect.top + 6;
+
+ TEXTMETRIC tm;
+ if (GetTextMetrics(hdc, &tm) &&
+ (UINT)(tm.tmHeight + 2) > pmis->itemHeight)
+ {
+ pmis->itemHeight = tm.tmHeight + 2;
+ }
+
+ INT spaceCX = (pmis->itemHeight > RATING_MINSPACECX) ? pmis->itemHeight : RATING_MINSPACECX;
+ pmis->itemWidth = rect.right - rect.left + (2 * spaceCX) - (GetSystemMetrics(SM_CXMENUCHECK) - 1);
+
+ return TRUE;
+}
+
+INT RatingMenuCustomizer::DrawRating(HDC hdc, DRAWITEMSTRUCT *pdis)
+{
+ INT value;
+ if (NULL == skin || NULL == hdc || FAILED(GetValue(pdis->itemID, &value)))
+ return FALSE;
+
+ INT spaceCX = ((pdis->rcItem.bottom - pdis->rcItem.top) > RATING_MINSPACECX) ?
+ (pdis->rcItem.bottom - pdis->rcItem.top) :
+ RATING_MINSPACECX;
+
+ RECT rect;
+ CopyRect(&rect, &pdis->rcItem);
+ rect.left += spaceCX;
+
+ UINT menuState = GetMenuState(menu, pdis->itemID, MF_BYCOMMAND);
+ UINT trackingValue = (0 == ((MF_DISABLED | MF_GRAYED) & menuState)) ? value : 0;
+
+ return SUCCEEDED(skin->Draw(hdc, 5, value, trackingValue, &rect, RDS_LEFT | RDS_VCENTER | RDS_HOT));
+}
+
+#define CBCLASS RatingMenuCustomizer
+START_DISPATCH;
+ CB(API_CUSTOMDRAW, CustomDraw);
+END_DISPATCH;
+#undef CBCLASS
+
diff --git a/Src/omBrowser/ratingMenuCustomizer.h b/Src/omBrowser/ratingMenuCustomizer.h
new file mode 100644
index 00000000..8bc6f8ae
--- /dev/null
+++ b/Src/omBrowser/ratingMenuCustomizer.h
@@ -0,0 +1,47 @@
+#ifndef NULLSOFT_WINAMP_RATING_MENU_CUSTOMIZER_HEADER
+#define NULLSOFT_WINAMP_RATING_MENU_CUSTOMIZER_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+#include "./ifc_menucustomizer.h"
+
+class ifc_skinnedrating;
+
+class RatingMenuCustomizer : public ifc_menucustomizer
+{
+
+protected:
+ RatingMenuCustomizer(HMENU hMenu, ifc_skinnedrating *skinnedRating);
+ ~RatingMenuCustomizer();
+
+public:
+ static HRESULT CreateInstance(HMENU hMenu, ifc_skinnedrating *skinnedRating, RatingMenuCustomizer **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_menucustomizer (partial) */
+ INT CustomDraw(HMENU menuInstance, INT action, HDC hdc, LPARAM param);
+
+protected:
+ HRESULT GetValue(INT itemId, INT *valueOut);
+ INT MeasureRating(HDC hdc, MEASUREITEMSTRUCT *pmis);
+ INT DrawRating(HDC hdc, DRAWITEMSTRUCT *pdis);
+
+protected:
+ RECVS_DISPATCH;
+
+protected:
+ ULONG ref;
+ HMENU menu;
+ ifc_skinnedrating *skin;
+};
+
+
+#endif //NULLSOFT_WINAMP_RATING_MENU_CUSTOMIZER_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/resource.h b/Src/omBrowser/resource.h
new file mode 100644
index 00000000..6ed9e6b6
--- /dev/null
+++ b/Src/omBrowser/resource.h
@@ -0,0 +1,134 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by omBrowser.rc
+//
+#define IDS_ENCRYPTION_MIXED 102
+#define IDS_ENCRYPTION_40BIT 103
+#define IDS_ENCRYPTION_56BIT 104
+#define IDR_CONTEXTMENU 104
+#define IDS_ENCRYPTION_FORTEZZA 105
+#define IDD_BROWSER_OPTIONS 105
+#define IDS_ENCRYPTION_128BIT 106
+#define IDD_OPTIONS_UI 106
+#define IDS_CONNECTION_UNSECURE 107
+#define IDD_OPTIONS_DEBUG 107
+#define IDS_CONNECTION_ENCRYPTED 108
+#define IDD_OPTIONS_INFO 108
+#define IDS_CURRENT_PAGE 109
+#define IDS_OMBROWSER_TITLE 110
+#define IDS_RATING_0 111
+#define IDS_RATING_1 112
+#define IDS_RATING_2 113
+#define IDS_RATING_3 114
+#define IDS_RATING_4 115
+#define IDS_RATING_5 116
+#define IDS_RATING_CHANGETO 117
+#define IDS_RATING_CURRENT 118
+#define IDS_MORE 119
+#define IDS_HOME 120
+#define IDS_HOME_DESCRIPTION 121
+#define IDS_BACK 122
+#define IDS_BACK_DESCRIPTION 123
+#define IDS_FORWARD 124
+#define IDS_FORWARD_DESCRIPTION 125
+#define IDS_REFRESH 126
+#define IDS_REFRESH_DESCRIPTION 127
+#define IDS_STOP 128
+#define IDS_STOP_DESCRIPTION 129
+#define IDS_SEPARATOR 130
+#define IDS_SPACE 131
+#define IDS_FLEXSPACE 132
+#define IDS_MORE_DESCRIPTION 133
+#define IDS_RATED 134
+#define IDS_PLEASE_WAIT 135
+#define IDS_SERVICE_VERSIONCHECK 136
+#define IDS_SERVICE_GETINFO 137
+#define IDS_SERVICE_GETINFO_DESCRIPTION 138
+#define IDS_SERVICE_REPORT 139
+#define IDS_SERVICE_REPORT_DESCRIPTION 140
+#define IDS_SERVICE_UNSUBSCRIBE 141
+#define IDS_SERVICE_UNSUBSCRIBE_DESCRIPTION 142
+#define IDS_SECURE_CONNECTION 143
+#define IDS_SCRIPT_ERROR 144
+#define IDS_SCRIPT_ERROR_DESCRIPTION 145
+#define IDS_HISTORY 146
+#define IDS_HISTORY_DESCRIPTION 147
+#define IDS_NAVIGATING 148
+#define IDS_OPTIONS_UI 149
+#define IDS_OPTIONS_DEBUG 150
+#define IDS_OPTIONS_INFO 151
+#define IDS_TOOLBAR_TOPDOCK 152
+#define IDS_TOOLBAR_BOTTOMDOCK 153
+#define IDS_UNKNOWN 154
+#define IDS_STORAGE_INI 155
+#define IDS_STORAGE_XML 156
+#define IDR_BROWSERPOPUPACCEL 156
+#define IDS_STORAGE_URL 157
+#define IDR_BROWSERACCEL 237
+#define IDC_TABFRAME 1001
+#define IDC_TOOLBAR_LOCATION 1002
+#define IDC_CHECK1 1003
+#define IDC_FILTERMENU 1003
+#define IDC_CHECK2 1004
+#define IDC_SHOWERROR 1004
+#define IDC_CHECK3 1005
+#define IDC_SHOWDEBUGGER 1005
+#define IDC_TOOLBAR_AUTOHIDE 1006
+#define IDC_TOOLBAR_TABSTOP 1007
+#define IDC_STATUSBAR_ENABLED 1008
+#define IDC_TITLE 1009
+#define IDC_TOOLBAR_FORCEADDRESS 1009
+#define IDC_TOOLBAR_TABSTOP3 1010
+#define IDC_TOOLBAR_FANCYADDRESS 1010
+#define IDC_VERSION 1013
+#define IDC_MSIEVERSION 1014
+#define IDC_CLASS 1015
+#define IDC_CONFIGPATH 1016
+#define IDC_SESSIONID 1017
+#define IDC_SESSIONID2 1018
+#define IDC_CLIENTID 1018
+#define IDR_CURTAINPROGRESS_IMAGE 20000
+#define IDR_TOOLBARLARGE_IMAGE 20001
+#define IDR_TOOLBARPROGRESS_IMAGE 20002
+#define IDR_MENUARROW_IMAGE 20003
+#define IDR_SERVICEICON_IMAGE 20004
+#define IDR_TOOLBARADDRESS_IMAGE 20005
+#define ID_ADDRESSBAR_COPY 40016
+#define ID_ADDRESSBAR_COPYADDRESS 40017
+#define ID_ADDRESSBAR_EDITADDRESS 40018
+#define ID_ADDRESSBAR_ACTIVATE 40019
+#define ID_RATING_VALUE_5 40100
+#define ID_RATING_VALUE_4 40101
+#define ID_RATING_VALUE_3 40102
+#define ID_RATING_VALUE_2 40103
+#define ID_RATING_VALUE_1 40104
+#define ID_SERVICE_REPORT 40105
+#define ID_SERVICE_UNSUBSCRIBE 40106
+#define ID_SERVICE_GETINFO 40107
+#define ID_NAVIGATION_HOME 40108
+#define ID_NAVIGATION_BACK 40109
+#define ID_NAVIGATION_FORWARD 40110
+#define ID_NAVIGATION_STOP 40111
+#define ID_NAVIGATION_REFRESH 40112
+#define ID_NAVIGATION_REFRESH_COMPLETELY 40113
+#define ID_NAVIGATION_HISTORY 40114
+#define ID_TOOLBAR_DOCKTOP 40115
+#define ID_TOOLBAR_DOCKBOTTOM 40116
+#define ID_TOOLBAR_AUTOHIDE 40117
+#define ID_TOOLBAR_TABSTOP 40118
+#define ID_BROWSER_SECURECONNECTION 40119
+#define ID_BROWSER_SCRIPTERROR 40120
+#define ID_WINDOW_FULLSCREEN 40121
+#define ID_WINDOW_CLOSE 40122
+#define ID_ADDRESSBAR_CHANGED 40123
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 157
+#define _APS_NEXT_COMMAND_VALUE 40021
+#define _APS_NEXT_CONTROL_VALUE 1014
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Src/omBrowser/resources/curtainProgress.png b/Src/omBrowser/resources/curtainProgress.png
new file mode 100644
index 00000000..5dd024ac
--- /dev/null
+++ b/Src/omBrowser/resources/curtainProgress.png
@@ -0,0 +1,5 @@
+‰PNG
+
+IHDRDñYÍG¿ïçüŽ‚§…˜ØüÕùÖ~v«î„pJѧ-ޤç”Ìã¯<µßwCÑÄÙ¬Wî÷ýç"˜/\š*çßÿ{øóñõú̃…†þÿ~bNS‹33 ¾Û(Ÿ…½®ql^~ÉõeŠà¹—Rþðñ6§èóéÛAÈæR%£ë
+Ù:gÔ>ù¤=îû§¸Pn©§Y'PÔűEínG½ì6ŸUy‚ ˆÄCÖæðÂeOL%ŠÉERùg&1+q¶üoªË**3‡Gn~íÚÑ–öl®'.˜ãMN@(jŽŸÊ½¹h6¾œh¤òš %ãÿÙºyâB9Ÿƒ‹ºDG@l|hØìܹŘgK²nÆ–)š¬>8Ã9Õ¿TP«*_¸¶@On˜”CÄúLÓx+r!¶öEÿš_ô2r”§¼ýñŸBäÃàúÂ;ýnŒ† J¥º–ü ¯¹q…®þf¿ÇTK¿¸û
+ú¯U×(J>Énw…ßUÁ}ð3ÜzÿöÄ7³û1övbN§YwÝØ˜ÚÂ@ÏBˆ¨gùBwï0pG#Ïqƒæ†èGc-Ö¥¬=Éï¹¼»ÛÀ…=x6p:V½VRh4hk£a‡ \ No newline at end of file
diff --git a/Src/omBrowser/resources/menuArrow.png b/Src/omBrowser/resources/menuArrow.png
new file mode 100644
index 00000000..769a1e07
--- /dev/null
+++ b/Src/omBrowser/resources/menuArrow.png
Binary files differ
diff --git a/Src/omBrowser/resources/pages/dnsError.htm b/Src/omBrowser/resources/pages/dnsError.htm
new file mode 100644
index 00000000..7ffa7a2a
--- /dev/null
+++ b/Src/omBrowser/resources/pages/dnsError.htm
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>Winamp Online Services Error Page</title>
+ <meta http-equiv="content-type" content="text/html;charset=utf-8" />
+ <meta http-equiv="Content-Style-Type" content="text/css" />
+ <link rel="stylesheet" href="./winampError.css" type="text/css" media="all"/>
+ <script src="./errorPageStrings.js"></script>
+ <script src="./errorPageFunctions.js"></script>
+</head>
+<body>
+<!-- Container -->
+<div id="errorContainer">
+ <!-- Icon -->
+ <div id="errorIcon"></div>
+ <!-- Error Body -->
+ <div id="errorBody">
+ <!-- Error Title -->
+ <div id="errorTitle"><h1 id="errorTitleText"><noscript>An Error Has Occurred</noscript></h1></div>
+ <!-- Error Code -->
+ <div id="errorCode"><noscript>HTTP - Error</noscript></div>
+ <!-- Error Description -->
+ <div id="errorDesc"><p id="errorDescText"><noscript>An error has occurred. We would show you more but your browser does not support javascript.</noscript></p></div>
+ <!-- Error Options -->
+ <div id="errorTryAgain"><a href="javascript:tryagain();">Try Again</a></div>
+ <div id="errorMore"><a href="javascript:togglemore();">More</a></div>
+ <!-- Additional Info -->
+ <div id="errorMoreInfo">
+ <table>
+ <tr><td nowrap>Service name:</td><td><script language=javascript>document.write(unescape(geturlparams('servicename')));</script></td></tr>
+ <tr><td nowrap>Error code:</td><td><script language=javascript>document.write(geterrorhex());</script></td></tr>
+ <tr><td nowrap>Url:</td><td><script language=javascript>document.write(unescape(geturlparams('url')));</script></td></tr>
+ <tr><td nowrap>Service id:</td><td><script language=javascript>document.write(geturlparams('svcid'));</script></td></tr>
+ <tr><td nowrap>Client id:</td><td><script language=javascript>document.write(geturlparams('uniqueid'));</script></td></tr>
+ </table>
+ </div>
+ </div>
+</div>
+<script language=javascript>
+window.onload = function(){populatepage();};
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/Src/omBrowser/resources/pages/errorIcon.png b/Src/omBrowser/resources/pages/errorIcon.png
new file mode 100644
index 00000000..969f5069
--- /dev/null
+++ b/Src/omBrowser/resources/pages/errorIcon.png
Binary files differ
diff --git a/Src/omBrowser/resources/pages/errorPageFunctions.js b/Src/omBrowser/resources/pages/errorPageFunctions.js
new file mode 100644
index 00000000..315476a2
--- /dev/null
+++ b/Src/omBrowser/resources/pages/errorPageFunctions.js
@@ -0,0 +1,288 @@
+function geturlparams( key )
+{
+ key = key.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
+ var regexS = "[\\#&]"+key+"=([^&#]*)";
+ var regex = new RegExp( regexS );
+ var results = regex.exec( window.location.href );
+ if( results == null )
+ return "";
+ else
+ return results[1];
+}
+function geterrorhex()
+{
+ var signedInt=geturlparams('errorcode');
+ return "0x" + CvtI32(signedInt).toUpperCase();
+}
+function bitStr(N, bits)
+{
+ var S = "", Q
+ while (bits--) { S = (Q=N%2) + S ; N = (N-Q)/2 }
+ return S;
+}
+function hex(N, bits)
+{
+ return (0x10000 + N).toString(16).substring(5-bits)
+}
+function Four(d, c, b, a, bits)
+{
+ return hex(d, bits) + hex(c, bits) + hex(b, bits) + hex(a, bits)
+}
+function CvtI32(F)
+{
+ var X = F |0, a, b, c, d
+ var ba = bitStr(a = X & 0xFF, 8)
+ var bb = bitStr(b = X >> 8 & 0xFF, 8)
+ var bc = bitStr(c = X >> 16 & 0xFF, 8)
+ var bd = bitStr(d = X >> 24 & 0xFF, 8)
+ var hex = Four(d, c, b, a, 2)
+ return hex;
+}
+function tryagain()
+{
+ window.location.replace(unescape(geturlparams('url')));
+}
+function togglemore()
+{
+ var display=document.getElementById("errorMoreInfo").style.display;
+ if (display == "block") {
+ document.getElementById("errorMoreInfo").style.display="none";
+ }
+ else {
+ document.getElementById("errorMoreInfo").style.display="block";
+ }
+}
+function populatepage()
+{
+ var errorcode = parseInt(geturlparams('errorcode'));
+ switch (errorcode)
+ {
+ case 404:
+ var errorTitle = errorTitle404;
+ var errorCode = errorCode404;
+ var errorDescription = errorDescription404;
+ break;
+ case 403:
+ var errorTitle = errorTitle403;
+ var errorCode = errorCode403;
+ var errorDescription = errorDescription403;
+ break;
+ case 500:
+ var errorTitle = errorTitle500;
+ var errorCode = errorCode500;
+ var errorDescription = errorDescription500;
+ break;
+ case 503:
+ var errorTitle = errorTitle503;
+ var errorCode = errorCode503;
+ var errorDescription = errorDescription503;
+ break;
+ case 502:
+ var errorTitle = errorTitle502;
+ var errorCode = errorCode502;
+ var errorDescription = errorDescription502;
+ break;
+ case 501:
+ var errorTitle = errorTitle501;
+ var errorCode = errorCode501;
+ var errorDescription = errorDescription501;
+ break;
+ case 504:
+ var errorTitle = errorTitle504;
+ var errorCode = errorCode504;
+ var errorDescription = errorDescription504;
+ break;
+ case 505:
+ var errorTitle = errorTitle505;
+ var errorCode = errorCode505;
+ var errorDescription = errorDescription505;
+ break;
+ case 400:
+ var errorTitle = errorTitle400;
+ var errorCode = errorCode400;
+ var errorDescription = errorDescription400;
+ break;
+ case 401:
+ var errorTitle = errorTitle401;
+ var errorCode = errorCode401;
+ var errorDescription = errorDescription401;
+ break;
+ case 402:
+ var errorTitle = errorTitle402;
+ var errorCode = errorCode402;
+ var errorDescription = errorDescription402;
+ break;
+ case 405:
+ var errorTitle = errorTitle405;
+ var errorCode = errorCode405;
+ var errorDescription = errorDescription405;
+ break;
+ case 406:
+ var errorTitle = errorTitle406;
+ var errorCode = errorCode406;
+ var errorDescription = errorDescription406;
+ break;
+ case 407:
+ var errorTitle = errorTitle407;
+ var errorCode = errorCode407;
+ var errorDescription = errorDescription407;
+ break;
+ case 408:
+ var errorTitle = errorTitle408;
+ var errorCode = errorCode408;
+ var errorDescription = errorDescription408;
+ break;
+ case 409:
+ var errorTitle = errorTitle409;
+ var errorCode = errorCode409;
+ var errorDescription = errorDescription409;
+ break;
+ case 410:
+ var errorTitle = errorTitle410;
+ var errorCode = errorCode410;
+ var errorDescription = errorDescription410;
+ break;
+ case 411:
+ var errorTitle = errorTitle411;
+ var errorCode = errorCode411;
+ var errorDescription = errorDescription411;
+ break;
+ case 413:
+ var errorTitle = errorTitle413;
+ var errorCode = errorCode413;
+ var errorDescription = errorDescription413;
+ break;
+ case 414:
+ var errorTitle = errorTitle414;
+ var errorCode = errorCode414;
+ var errorDescription = errorDescription414;
+ break;
+ case 415:
+ var errorTitle = errorTitle415;
+ var errorCode = errorCode415;
+ var errorDescription = errorDescription415;
+ break;
+ case -2146697214:
+ var errorTitle = errorTitle800c0002;
+ var errorCode = errorCode800c0002;
+ var errorDescription = errorDescription800c0002;
+ break;
+ case -2146697213:
+ var errorTitle = errorTitle800c0003;
+ var errorCode = errorCode800c0003;
+ var errorDescription = errorDescription800c0003;
+ break;
+ case -2146697212:
+ var errorTitle = errorTitle800c0004;
+ var errorCode = errorCode800c0004;
+ var errorDescription = errorDescription800c0004;
+ break;
+ case -2146697211:
+ var errorTitle = errorTitle800c0005;
+ var errorCode = errorCode800c0005;
+ var errorDescription = errorDescription800c0005;
+ break;
+ case -2146697210:
+ var errorTitle = errorTitle800c0006;
+ var errorCode = errorCode800c0006;
+ var errorDescription = errorDescription800c0006;
+ break;
+ case -2146697209:
+ var errorTitle = errorTitle800c0007;
+ var errorCode = errorCode800c0007;
+ var errorDescription = errorDescription800c0007;
+ break;
+ case -2146697208:
+ var errorTitle = errorTitle800c0008;
+ var errorCode = errorCode800c0008;
+ var errorDescription = errorDescription800c0008;
+ break;
+ case -2146697207:
+ var errorTitle = errorTitle800c0009;
+ var errorCode = errorCode800c0009;
+ var errorDescription = errorDescription800c0009;
+ break;
+ case -2146697206:
+ var errorTitle = errorTitle800c000a;
+ var errorCode = errorCode800c000a;
+ var errorDescription = errorDescription800c000a;
+ break;
+ case -2146697205:
+ var errorTitle = errorTitle800c000b;
+ var errorCode = errorCode800c000b;
+ var errorDescription = errorDescription800c000b;
+ break;
+ case -2146697204:
+ var errorTitle = errorTitle800c000c;
+ var errorCode = errorCode800c000c;
+ var errorDescription = errorDescription800c000c;
+ break;
+ case -2146697203:
+ var errorTitle = errorTitle800c000d;
+ var errorCode = errorCode800c000d;
+ var errorDescription = errorDescription800c000d;
+ break;
+ case -2146697202:
+ var errorTitle = errorTitle800c000e;
+ var errorCode = errorCode800c000e;
+ var errorDescription = errorDescription800c000e;
+ break;
+ case -2146697201:
+ var errorTitle = errorTitle800c000f;
+ var errorCode = errorCode800c000f;
+ var errorDescription = errorDescription800c000f;
+ break;
+ case -2146697200:
+ var errorTitle = errorTitle800c0010;
+ var errorCode = errorCode800c0010;
+ var errorDescription = errorDescription800c0010;
+ break;
+ case -2146697196:
+ var errorTitle = errorTitle800c0014;
+ var errorCode = errorCode800c0014;
+ var errorDescription = errorDescription800c0014;
+ break;
+ case -2146697195:
+ var errorTitle = errorTitle800c0015;
+ var errorCode = errorCode800c0015;
+ var errorDescription = errorDescription800c0015;
+ break;
+ case -2146697194:
+ var errorTitle = errorTitle800c0016;
+ var errorCode = errorCode800c0016;
+ var errorDescription = errorDescription800c0016;
+ break;
+ case -2146697193:
+ var errorTitle = errorTitle800c0017;
+ var errorCode = errorCode800c0017;
+ var errorDescription = errorDescription800c0017;
+ break;
+ case -2146697192:
+ var errorTitle = errorTitle800c0018;
+ var errorCode = errorCode800c0018;
+ var errorDescription = errorDescription800c0018;
+ break;
+ case -2146697960:
+ var errorTitle = errorTitle800c0100;
+ var errorCode = errorCode800c0100;
+ var errorDescription = errorDescription800c0100;
+ break;
+ case -2146696704:
+ var errorTitle = errorTitle800c0200;
+ var errorCode = errorCode800c0200;
+ var errorDescription = errorDescription800c0200;
+ break;
+ case -2146696448:
+ var errorTitle = errorTitle800c0300;
+ var errorCode = errorCode800c0300;
+ var errorDescription = errorDescription800c0300;
+ break;
+ default:
+ var errorTitle = errorTitleUnknown;
+ var errorCode = errorCodeUnknown;
+ var errorDescription = errorDescriptionUnknown;
+ }
+ document.getElementById("errorTitleText").innerHTML = errorTitle;
+ document.getElementById("errorCode").innerHTML = errorCode;
+ document.getElementById("errorDescText").innerHTML = errorDescription;
+} \ No newline at end of file
diff --git a/Src/omBrowser/resources/pages/errorPageStrings.js b/Src/omBrowser/resources/pages/errorPageStrings.js
new file mode 100644
index 00000000..f011d690
--- /dev/null
+++ b/Src/omBrowser/resources/pages/errorPageStrings.js
@@ -0,0 +1,138 @@
+var errorTitleUnknown = "An Unknown Error has occurred";
+var errorCodeUnknown = "Unknown Error";
+var errorDescriptionUnknown = "Winamp has received an unknown error from the Online Service.";
+var errorTitle400 = "Bad Request";
+var errorCode400 = "HTTP 400 - Bad Request";
+var errorDescription400 = "The request to the Online Service has not been properly formatted, there is likely a syntax error in the URL or elsewhere in the request. This is most likely due to an error in the Online Services code.";
+var errorTitle401 = "Request is Unauthorized";
+var errorCode401 = "HTTP 401 - Unauthorized";
+var errorDescription401 = "The Online Service has made a request that requires HTTP authentication, and the request was not authorized by the server.";
+var errorTitle402 = "Payment Required";
+var errorCode402 = "HTTP 402 - Payment Required";
+var errorDescription402 = "The Online Service submitted a request that was not authorized, because payment is required.";
+var errorTitle403 = "Access has been denied";
+var errorCode403 = "HTTP 403 - Forbidden";
+var errorDescription403 = "Winamp was able to connect to the server for this Online Service, however the service has returned an error indicating that you do not have access to the page. This may be caused by a problem with the webserver configuration or other problem with the Online Service.";
+var errorTitle404 = "The page cannot be found";
+var errorCode404 = "HTTP 404 - File Not Found";
+var errorDescription404 = "Winamp was able to connect to the server for this Online Service, however the service has returned an error indicating that the page requested can not be found. This may be caused by a broken link, or other problem with the Online Service.";
+var errorTitle405 = "The requested method is not allowed";
+var errorCode405 = "HTTP 405 - Method Not Allowed";
+var errorDescription405 = "The request method specified by the online service is not allowed by the server, this is likely due to a server misconfiguration, or an attempt by the online service to use a webservice in a way it does not allow";
+var errorTitle406 = "The response is not acceptable";
+var errorCode406 = "HTTP 406 - Not Acceptable";
+var errorDescription406 = "The Online Service has made a request to a webserver, and the webserver is not able to respond in a format that the request has stated to be acceptable.";
+var errorTitle407 = "Proxy authentication is required";
+var errorCode407 = "HTTP 407 - Proxy Authentication Required";
+var errorDescription407 = "The Online Service has made a request to a proxy server, and the proxy server requires that the request be authenticated.";
+var errorTitle408 = "The request had timed out";
+var errorCode408 = "HTTP 408 - Request Timeout";
+var errorDescription408 = "Winamp did not send a request issued by the Online Service within the length of time that the Online Service would wait for the request.";
+var errorTitle409 = "A conflict has occurred";
+var errorCode409 = "HTTP 409 - Conflict";
+var errorDescription409 = "The Online Service has made a request to a server where a conflicting request has been made.";
+var errorTitle410 = "The requested page is gone";
+var errorCode410 = "HTTP 410 - Gone";
+var errorDescription410 = "The page requested by the Online Service is gone. Permanently. No forwarding address is known";
+var errorTitle411 = "Request length must be specified";
+var errorCode411 = "HTTP 411 - Length Required";
+var errorDescription411 = "The Online Service has made a request to a server that requires that the request specify the length of the request, and the Online Service has not specified the length.";
+var errorTitle413 = "The request is too large";
+var errorCode413 = "HTTP 413 - Request Entity Too Large";
+var errorDescription413 = "The Online Service has submitted a request to a webserver that has been refused because the request is too large.";
+var errorTitle414 = "The request is too large";
+var errorCode414 = "HTTP 414 - Request-URI Too Long";
+var errorDescription414 = "The Online Service has made a request to a server that has been refused because the request URI is too long, this is likely due to an problem with the Online Service adding too many query parameters.";
+var errorTitle415 = "The media type is not supported";
+var errorCode415 = "HTTP 415 - Unsupported Media Type";
+var errorDescription415 = "The Online Service has made a request to a resource on a server that is being refused because the request is not in a format that is supported for the request method being used.";
+var errorTitle500 = "An internal server error has occured";
+var errorCode500 = "HTTP 500 - Internal Server Error";
+var errorDescription500 = "The Online Service has made a request to a server that has encountered an error preventing the completion of the response.";
+var errorTitle501 = "Method not implemented";
+var errorCode501 = "HTTP 501 - Not Implemented";
+var errorDescription501 = "The Online Service has made a request to a server using a request method that the server does not support.";
+var errorTitle502 = "Bad response from proxy";
+var errorCode502 = "HTTP 502 - Bad Gateway";
+var errorDescription502 = "The Online Service has made a request to a server acting as a proxy or a gateway. The server has not received a valid response.";
+var errorTitle503 = "The service is currently unavailable";
+var errorCode503 = "HTTP 503 - Service Unavailable";
+var errorDescription503 = "The Online Service has made a request to a server that is currently unable to service the request. This may be temporary due to the server current load.";
+var errorTitle504 = "The proxy has timed out.";
+var errorCode504 = "HTTP 504 - Gateway Timeout";
+var errorDescription504 = "The Online Service has made a request to a server acting as a proxy, and this server has not received a timely response.";
+var errorTitle505 = "The HTTP version is not supported";
+var errorCode505 = "HTTP 505 - HTTP Version Not Supported";
+var errorDescription505 = "Winamp has made a request to the Online Service in an HTTP version not supported by the Online Service. This is either a server configuration problem with the Online Service, or you may need to change your browser's HTTP protocol settings.";
+
+var errorDnsDescription = "The request for the Online Service has returned a resource not found error from your browser, please ensure that you are connected to the Internet.";
+
+var errorTitle800c0005 = "The server or proxy was not found.";
+var errorCode800c0005 = "Resource Not Found";
+var errorDescription800c0005 = "The request for the Online Service has returned a resource not found error from your browser, please ensure that you are connected to the Internet.";
+var errorTitle800c000f = "Unable to load data from the server.";
+var errorCode800c000f = "Cannot Load Data";
+var errorDescription800c000f = errorDnsDescription;
+var errorTitle800c0002 = "The URL could not be parsed.";
+var errorCode800c0002 = "Invalid URL";
+var errorDescription800c0002 = errorDnsDescription;
+var errorTitle800c0003 = "No Internet session was established.";
+var errorCode800c0003 = "No Session Found";
+var errorDescription800c0003 = errorDnsDescription;
+var errorTitle800c0004 = "The attempt to connect to the Internet has failed.";
+var errorCode800c0004 = "Unable To Connect";
+var errorDescription800c0004 = errorDnsDescription;
+var errorTitle800c0006 = "Requested object was not found.";
+var errorCode800c0006 = "Object Not Found";
+var errorDescription800c0006 = errorDnsDescription;
+var errorTitle800c0007 = "Requested data is not available.";
+var errorCode800c0007 = "Data Not Available";
+var errorDescription800c0007 = errorDnsDescription;
+var errorTitle800c0008 = "The download has failed (the connection was interrupted).";
+var errorCode800c0008 = "Download Failed";
+var errorDescription800c0008 = errorDnsDescription;
+var errorTitle800c0009 = "Authentication is needed to access the object.";
+var errorCode800c0009 = "Authentication Required";
+var errorDescription800c0009 = errorDnsDescription;
+var errorTitle800c000a = "Required media not available or valid.";
+var errorCode800c000a = "No Valid Media";
+var errorDescription800c000a = errorDnsDescription;
+var errorTitle800c000b = "The Internet connection has timed out.";
+var errorCode800c000b = "Connection Timeout";
+var errorDescription800c000b = errorDnsDescription;
+var errorTitle800c000c = "Request is invalid.";
+var errorCode800c000c = "Invalid Request";
+var errorDescription800c000c = errorDnsDescription;
+var errorTitle800c000d = "Protocol is not recognized.";
+var errorCode800c000d = "Unknown Protocol";
+var errorDescription800c000d = errorDnsDescription;
+var errorTitle800c000e = "Navigation request has encountered a security issue.";
+var errorCode800c000e = "Security Problem";
+var errorDescription800c000e = errorDnsDescription;
+var errorTitle800c0010 = "Unable to create an instance of the object.";
+var errorCode800c0010 = "Cannot Instantiate Object";
+var errorDescription800c0010 = errorDnsDescription;
+var errorTitle800c0014 = "Attempt to redirect the navigation failed.";
+var errorCode800c0014 = "Redirect Failed";
+var errorDescription800c0014 = errorDnsDescription;
+var errorTitle800c0015 = "The request is being redirected to a directory.";
+var errorCode800c0015 = "Redirect To Directory";
+var errorDescription800c0015 = errorDnsDescription;
+var errorTitle800c0016 = "The requested resource could not be locked.";
+var errorCode800c0016 = "Cannot Lock Request";
+var errorDescription800c0016 = errorDnsDescription;
+var errorTitle800c0017 = "Reissue request with extended binding.";
+var errorCode800c0017 = "Use Extend Binding";
+var errorDescription800c0017 = errorDnsDescription;
+var errorTitle800c0018 = "Binding was terminated.";
+var errorCode800c0018 = "Terminated Bind";
+var errorDescription800c0018 = errorDnsDescription;
+var errorTitle800c0100 = "The component download was declined by the user.";
+var errorCode800c0100 = "Download Declined";
+var errorDescription800c0100 = errorDnsDescription;
+var errorTitle800c0200 = "Result is dispatched.";
+var errorCode800c0200 = "Result Dispatched";
+var errorDescription800c0200 = errorDnsDescription;
+var errorTitle800c0300 = "Cannot replace a protected System File Protection (SFP) file.";
+var errorCode800c0300 = "Cannot Replace SFP File ";
+var errorDescription800c0300 = errorDnsDescription; \ No newline at end of file
diff --git a/Src/omBrowser/resources/pages/httpError.htm b/Src/omBrowser/resources/pages/httpError.htm
new file mode 100644
index 00000000..f89a1927
--- /dev/null
+++ b/Src/omBrowser/resources/pages/httpError.htm
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>Winamp Online Services Error Page</title>
+ <meta http-equiv="content-type" content="text/html;charset=utf-8" />
+ <meta http-equiv="Content-Style-Type" content="text/css" />
+ <link rel="stylesheet" href="./winampError.css" type="text/css" media="all"/>
+ <script src="./errorPageStrings.js"></script>
+ <script src="./errorPageFunctions.js"></script>
+</head>
+<body>
+<!-- Container -->
+<div id="errorContainer">
+ <!-- Icon -->
+ <div id="errorIcon"></div>
+ <!-- Error Body -->
+ <div id="errorBody">
+ <!-- Error Title -->
+ <div id="errorTitle"><h1 id="errorTitleText"><noscript>An Error Has Occurred</noscript></h1></div>
+ <!-- Error Code -->
+ <div id="errorCode"><noscript>HTTP - Error</noscript></div>
+ <!-- Error Description -->
+ <div id="errorDesc"><p id="errorDescText"><noscript>An error has occurred. We would show you more but your browser does not support javascript.</noscript></p></div>
+ <!-- Error Options -->
+ <div id="errorTryAgain"><a href="javascript:tryagain();">Try Again</a></div>
+ <div id="errorMore"><a href="javascript:togglemore();">More</a></div>
+ <!-- Additional Info -->
+ <div id="errorMoreInfo">
+ <table>
+ <tr><td nowrap>Service name:</td><td><script language=javascript>document.write(unescape(geturlparams('servicename')));</script></td></tr>
+ <tr><td nowrap>Error code:</td><td><script language=javascript>document.write(geturlparams('errorcode'));</script></td></tr>
+ <tr><td nowrap>Url:</td><td><script language=javascript>document.write(unescape(geturlparams('url')));</script></td></tr>
+ <tr><td nowrap>Service id:</td><td><script language=javascript>document.write(geturlparams('svcid'));</script></td></tr>
+ <tr><td nowrap>Client id:</td><td><script language=javascript>document.write(geturlparams('uniqueid'));</script></td></tr>
+ </table>
+ </div>
+ </div>
+</div>
+<script language=javascript>
+window.onload = function(){populatepage();};
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/Src/omBrowser/resources/pages/inetDisabled.htm b/Src/omBrowser/resources/pages/inetDisabled.htm
new file mode 100644
index 00000000..70e20f59
--- /dev/null
+++ b/Src/omBrowser/resources/pages/inetDisabled.htm
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>Winamp Online Services Error Page</title>
+ <meta http-equiv="content-type" content="text/html;charset=utf-8" />
+ <meta http-equiv="Content-Style-Type" content="text/css" />
+ <link rel="stylesheet" href="./winampError.css" type="text/css" media="all"/>
+</head>
+<body>
+<!-- Container -->
+<div id="errorContainer">
+ <!-- Icon -->
+ <div id="errorIcon"></div>
+ <!-- Error Body -->
+ <div id="errorBody">
+ <!-- Error Title -->
+ <div id="errorTitle"><h1 id="errorTitleText">Internet Access Is Currently Disabled</h1></div>
+ <!-- Error Code -->
+ <div id="errorCode"><noscript>Internet Access Is Currently Disabled</noscript></div>
+ <!-- Error Description -->
+ <div id="errorDesc"><p id="errorDescText">Winamp has been configured to not access the internet which is why you are seeing this page.<br><br>If this is not intended or you would like to re-enable Winamp's internet access, this can be done by going to <b>Preferences</b> -> <b>General Preferences</b> -> Change '<b>Internet Connection Settings</b>' to a setting other than '<b>Not connected to the internet</b>' and then refresh this page.</p></div>
+ </div>
+</div>
+</body>
+</html> \ No newline at end of file
diff --git a/Src/omBrowser/resources/pages/navCancel.htm b/Src/omBrowser/resources/pages/navCancel.htm
new file mode 100644
index 00000000..2c81143f
--- /dev/null
+++ b/Src/omBrowser/resources/pages/navCancel.htm
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>Winamp Online Services Error Page</title>
+ <meta http-equiv="content-type" content="text/html;charset=utf-8" />
+ <meta http-equiv="Content-Style-Type" content="text/css" />
+ <link rel="stylesheet" href="./winampError.css" type="text/css" media="all"/>
+</head>
+<body>
+<!-- Container -->
+<div id="errorContainer">
+ <!-- Icon -->
+ <div id="errorIcon"></div>
+ <!-- Error Body -->
+ <div id="errorBody">
+ <!-- Error Title -->
+ <div id="errorTitle"><h1 id="errorTitleText">Action Cancelled</h1></div>
+ <!-- Error Code -->
+ <div id="errorCode"><noscript>Action Cancelled</noscript></div>
+ <!-- Error Description -->
+ <div id="errorDesc"><p id="errorDescText">Navigation to the page has been cancelled.</p></div>
+ </div>
+</div>
+</body>
+</html> \ No newline at end of file
diff --git a/Src/omBrowser/resources/pages/winampError.css b/Src/omBrowser/resources/pages/winampError.css
new file mode 100644
index 00000000..0bf0dbae
--- /dev/null
+++ b/Src/omBrowser/resources/pages/winampError.css
@@ -0,0 +1,64 @@
+a {
+ text-decoration: none;
+}
+body {
+ font: message-box;
+}
+h1 {
+ font-size: 150%;
+}
+#errorContainer {
+ position: relative;
+ margin: 1.6em auto;
+ max-width: 42em;
+ min-width: 34em;
+ left: 15px;
+ width:70%;
+ _width: 420px;
+}
+#errorBody {
+ position:relative;
+}
+#errorIcon {
+ position:relative;
+ top: 53px;
+ left: -56px;
+ height:39px;
+ width:40px;
+ background-image:url(./errorIcon.png);
+ _background-image: none;
+}
+#errorTitleText {
+ position:relative;
+ top: 10px;
+}
+#errorTitle {
+ position: relative;
+ text-align: left;
+ display:inline-block;
+ border-bottom: ridge 1px;
+}
+#errorCode {
+ position: relative;
+ text-align:right;
+ margin-bottom: -.5em;
+}
+#errorDesc {
+ position: relative;
+ margin-bottom: -.5em;
+}
+#errorTryAgain {
+ position: relative;
+ text-align: left;
+ top: 1.2em;
+}
+#errorMore {
+ position: relative;
+ text-align:right;
+ border-bottom: ridge 1px;
+ padding-bottom: .2em;
+}
+#errorMoreInfo {
+ position:relative;
+ display: none;
+} \ No newline at end of file
diff --git a/Src/omBrowser/resources/serviceIcon.png b/Src/omBrowser/resources/serviceIcon.png
new file mode 100644
index 00000000..b644c91c
--- /dev/null
+++ b/Src/omBrowser/resources/serviceIcon.png
Binary files differ
diff --git a/Src/omBrowser/resources/toolbarAddress.png b/Src/omBrowser/resources/toolbarAddress.png
new file mode 100644
index 00000000..94b55912
--- /dev/null
+++ b/Src/omBrowser/resources/toolbarAddress.png
Binary files differ
diff --git a/Src/omBrowser/resources/toolbarLarge.png b/Src/omBrowser/resources/toolbarLarge.png
new file mode 100644
index 00000000..cf4c8abc
--- /dev/null
+++ b/Src/omBrowser/resources/toolbarLarge.png
Binary files differ
diff --git a/Src/omBrowser/resources/toolbarProgress.png b/Src/omBrowser/resources/toolbarProgress.png
new file mode 100644
index 00000000..c252e884
--- /dev/null
+++ b/Src/omBrowser/resources/toolbarProgress.png
Binary files differ
diff --git a/Src/omBrowser/service.cpp b/Src/omBrowser/service.cpp
new file mode 100644
index 00000000..4a2f6a63
--- /dev/null
+++ b/Src/omBrowser/service.cpp
@@ -0,0 +1,391 @@
+#include "./main.h"
+#include "./service.h"
+#include "./ifc_omservicehost.h"
+#include "./ifc_omserviceeventmngr.h"
+
+#include "../winamp/wa_ipc.h"
+
+#include <strsafe.h>
+
+#define DEFAULT_GENERATION 2
+
+#define IS_INVALIDISPATCH(__disp) (((IDispatch *)1) == (__disp) || NULL == (__disp))
+
+OmService::OmService(UINT serviceId, ifc_omservicehost *serviceHost)
+ : ref(1), id(serviceId), name(NULL), url(NULL), icon(NULL), rating(0), version(0),
+ flags(0), generation(2), description(NULL), authorFirst(NULL), authorLast(NULL),
+ published(NULL), updated(NULL), thumbnail(NULL), screenshot(NULL), address(NULL),
+ host(serviceHost)
+{
+ if (NULL != host)
+ host->AddRef();
+
+ modified.SetEventHandler(ModifiedEvent, (ULONG_PTR)this);
+
+ InitializeCriticalSection(&lock);
+ InitializeCriticalSection(&eventLock);
+}
+
+OmService::~OmService()
+{
+ Plugin_FreeString(name);
+ Plugin_FreeString(url);
+ Plugin_FreeString(icon);
+ Plugin_FreeString(address);
+
+ Plugin_FreeString(description);
+ Plugin_FreeString(authorFirst);
+ Plugin_FreeString(authorLast);
+ Plugin_FreeString(published);
+ Plugin_FreeString(updated);
+ Plugin_FreeString(thumbnail);
+ Plugin_FreeString(screenshot);
+
+ UnregisterAllEventHandlers();
+
+ if (NULL != host)
+ host->Release();
+
+ DeleteCriticalSection(&lock);
+ DeleteCriticalSection(&eventLock);
+}
+
+HRESULT OmService::CreateInstance(UINT serviceId, ifc_omservicehost *host, OmService **serviceOut)
+{
+ if (NULL == serviceOut) return E_POINTER;
+ *serviceOut = new OmService(serviceId, host);
+ if (NULL == *serviceOut) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t OmService::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t OmService::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int OmService::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmService))
+ *object = static_cast<ifc_omservice*>(this);
+ else if (IsEqualIID(interface_guid, IFC_OmServiceDetails))
+ *object = static_cast<ifc_omservicedetails*>(this);
+ else if (IsEqualIID(interface_guid, IFC_OmServiceEditor))
+ *object = static_cast<ifc_omserviceeditor*>(this);
+ else if (IsEqualIID(interface_guid, IFC_OmServiceCopier))
+ *object = static_cast<ifc_omservicecopier*>(this);
+ else if (IsEqualIID(interface_guid, IFC_OmServiceCommand))
+ *object = static_cast<ifc_omservicecommand*>(this);
+ else if (IsEqualIID(interface_guid, IFC_OmServiceEventMngr))
+ *object = static_cast<ifc_omserviceeventmngr*>(this);
+ else if (IsEqualIID(interface_guid, IFC_OmServiceHostExt))
+ *object = static_cast<ifc_omservicehostext*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT OmService::StringCchCopyExMT(LPTSTR pszDest, size_t cchDest, LPCTSTR pszSrc, LPTSTR *ppszDestEnd, size_t *pcchRemaining, DWORD dwFlags)
+{
+ if (NULL == pszDest)
+ return E_POINTER;
+
+ EnterCriticalSection(&lock);
+ HRESULT hr = StringCchCopyEx(pszDest, cchDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
+ LeaveCriticalSection(&lock);
+ return hr;
+}
+
+UINT OmService::GetId()
+{
+ return id;
+}
+
+HRESULT OmService::SetId(UINT serviceId)
+{
+ id = serviceId;
+ return S_OK;
+}
+
+HRESULT OmService::GetName(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ return StringCchCopyExMT(pszBuffer, cchBufferMax, name, NULL, NULL,STRSAFE_IGNORE_NULLS | STRSAFE_NULL_ON_FAILURE);
+}
+
+HRESULT OmService::GetUrl(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ EnterCriticalSection(&lock);
+
+ HRESULT hr = GetUrlDirect(pszBuffer, cchBufferMax);
+ if(SUCCEEDED(hr))
+ {
+ if (NULL != host)
+ {
+ HRESULT hostResult = host->GetUrl(this, pszBuffer, cchBufferMax);
+ if (FAILED(hostResult) && E_NOTIMPL != hostResult)
+ hr = hostResult;
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+ return hr;
+}
+
+HRESULT OmService::GetUrlDirect(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ return StringCchCopyExMT(pszBuffer, cchBufferMax, url, NULL, NULL, STRSAFE_IGNORE_NULLS | STRSAFE_NULL_ON_FAILURE);
+}
+
+HRESULT OmService::GetIcon(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ return StringCchCopyExMT(pszBuffer, cchBufferMax, icon, NULL, NULL, STRSAFE_IGNORE_NULLS | STRSAFE_NULL_ON_FAILURE);
+}
+
+HRESULT OmService::GetExternal(IDispatch **ppDispatch)
+{
+ if (NULL == ppDispatch)
+ return E_POINTER;
+
+ *ppDispatch = NULL;
+
+ HWND hWinamp = NULL;
+ IDispatch *winampDisp = NULL;
+
+ if (SUCCEEDED(Plugin_GetWinampWnd(&hWinamp)) && NULL != hWinamp)
+ {
+ EnterCriticalSection(&lock);
+ UINT generation_cached = generation;
+ LeaveCriticalSection(&lock);
+
+ if (2 == generation_cached)
+ {
+ WCHAR szBuffer[64] = {0};
+ if (SUCCEEDED(StringCchPrintfW(szBuffer, ARRAYSIZE(szBuffer), L"%u", id)))
+ winampDisp = (IDispatch*)SENDWAIPC(hWinamp, IPC_JSAPI2_GET_DISPATCH_OBJECT, (WPARAM)szBuffer);
+ }
+ else if (1 == generation_cached)
+ {
+ winampDisp = (IDispatch*)SENDWAIPC(hWinamp, IPC_GET_DISPATCH_OBJECT, 0);
+ }
+
+ if (IS_INVALIDISPATCH(winampDisp))
+ winampDisp = NULL;
+ }
+
+ *ppDispatch = winampDisp;
+
+ EnterCriticalSection(&lock);
+ ifc_omservicehost *host_cached = host;
+ if (NULL != host_cached)
+ host_cached->AddRef();
+
+ LeaveCriticalSection(&lock);
+
+ if (NULL != host_cached)
+ {
+ host_cached->GetExternal(this, ppDispatch);
+ host_cached->Release();
+ }
+
+ return S_OK;
+}
+
+HRESULT OmService::GetRating(UINT *ratingOut)
+{
+ if (NULL == ratingOut)
+ return E_POINTER;
+
+ *ratingOut = rating;
+ return S_OK;
+}
+
+HRESULT OmService::GetVersion(UINT *versionOut)
+{
+ if (NULL == versionOut)
+ return E_POINTER;
+
+ *versionOut = version;
+ return S_OK;
+}
+
+HRESULT OmService::GetGeneration(UINT *generationOut)
+{
+ if (NULL == generationOut)
+ return E_POINTER;
+
+ EnterCriticalSection(&lock);
+ *generationOut = (0 == generation) ? DEFAULT_GENERATION : generation;
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+HRESULT OmService::GetFlags(UINT *flagsOut)
+{
+ if (NULL == flagsOut)
+ return E_POINTER;
+
+ *flagsOut = flags;
+ return S_OK;
+}
+
+HRESULT OmService::UpdateFlags(UINT flagsIn)
+{
+ flags = flagsIn;
+ return S_OK;
+}
+
+HRESULT OmService::SetAddress(LPCWSTR pszAddress)
+{
+ EnterCriticalSection(&lock);
+
+ HRESULT hr;
+ Plugin_FreeString(address);
+ if (NULL == pszAddress)
+ {
+ address = NULL;
+ hr = S_OK;
+ }
+ else
+ {
+ address = Plugin_CopyString(pszAddress);
+ hr = (NULL == address) ? E_OUTOFMEMORY : S_OK;
+ }
+
+ LeaveCriticalSection(&lock);
+ return hr;
+}
+
+HRESULT OmService::GetAddress(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ return StringCchCopyExMT(pszBuffer, cchBufferMax, address, NULL, NULL,STRSAFE_IGNORE_NULLS | STRSAFE_NULL_ON_FAILURE);
+}
+
+HRESULT OmService::GetHost(ifc_omservicehost **ppHost)
+{
+ if (NULL == ppHost) return E_POINTER;
+
+ EnterCriticalSection(&lock);
+
+ *ppHost = host;
+ if (NULL != host)
+ host->AddRef();
+
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+HRESULT OmService::SetHost(ifc_omservicehost *serviceHost)
+{
+ EnterCriticalSection(&lock);
+
+ if (NULL != host)
+ host->Release();
+
+ host = serviceHost;
+
+ if (NULL != host)
+ host->AddRef();
+
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+void CALLBACK OmService::ModifiedEvent(UINT nMark, FlagTracker *instance, ULONG_PTR user)
+{
+ OmService *service = (OmService*)user;
+ if (NULL == service) return;
+
+ service->Signal_ServiceChange(nMark);
+}
+
+HRESULT OmService::CopyTo(ifc_omservice *service, UINT *modifiedFlags)
+{
+ if (NULL == service || id != service->GetId())
+ return E_INVALIDARG;
+
+ HRESULT hr;
+ ifc_omserviceeditor *editor = NULL;
+ hr = service->QueryInterface(IFC_OmServiceEditor, (void**)&editor);
+ if (SUCCEEDED(hr) && editor != NULL)
+ {
+ editor->BeginUpdate();
+
+ if (FAILED(editor->SetName(name, FALSE))) hr = E_FAIL;
+ if (FAILED(editor->SetUrl(url, FALSE))) hr = E_FAIL;
+ if (FAILED(editor->SetIcon(icon, FALSE))) hr = E_FAIL;
+ if (FAILED(editor->SetRating(rating))) hr = E_FAIL;
+ if (FAILED(editor->SetVersion(version))) hr = E_FAIL;
+ if (FAILED(editor->SetFlags(flags, 0xFFFFFFFF))) hr = E_FAIL;
+ if (FAILED(editor->SetDescription(description, FALSE))) hr = E_FAIL;
+ if (FAILED(editor->SetAuthorFirst(authorFirst, FALSE))) hr = E_FAIL;
+ if (FAILED(editor->SetAuthorLast(authorLast, FALSE))) hr = E_FAIL;
+ if (FAILED(editor->SetUpdated(updated, FALSE))) hr = E_FAIL;
+ if (FAILED(editor->SetPublished(published, FALSE))) hr = E_FAIL;
+ if (FAILED(editor->SetThumbnail(thumbnail, FALSE))) hr = E_FAIL;
+ if (FAILED(editor->SetScreenshot(screenshot, FALSE))) hr = E_FAIL;
+ if (FAILED(editor->SetGeneration(generation))) hr = E_FAIL;
+
+ editor->EndUpdate();
+
+ if (NULL != modifiedFlags)
+ editor->GetModified(modifiedFlags);
+
+ editor->Release();
+ }
+
+ return hr;
+}
+
+HRESULT OmService::QueryState(HWND hBrowser, const GUID *commandGroup, UINT commandId)
+{
+ HRESULT hr;
+
+ EnterCriticalSection(&lock);
+
+ if (NULL != host)
+ hr = host->QueryCommandState(this, hBrowser, commandGroup, commandId);
+ else
+ hr = E_NOTIMPL;
+
+ LeaveCriticalSection(&lock);
+ return hr;
+}
+
+HRESULT OmService::Exec(HWND hBrowser, const GUID *commandGroup, UINT commandId, ULONG_PTR commandArg)
+{
+ HRESULT hr;
+
+ EnterCriticalSection(&lock);
+
+ if (NULL != host)
+ hr = host->ExecuteCommand(this, hBrowser, commandGroup, commandId, commandArg);
+ else
+ hr = E_NOTIMPL;
+
+ LeaveCriticalSection(&lock);
+ return hr;
+} \ No newline at end of file
diff --git a/Src/omBrowser/service.h b/Src/omBrowser/service.h
new file mode 100644
index 00000000..814bb0b8
--- /dev/null
+++ b/Src/omBrowser/service.h
@@ -0,0 +1,152 @@
+#ifndef NULLSOFT_WINAMP_OMSERVICE_IMPLEMENTATION_HEADER
+#define NULLSOFT_WINAMP_OMSERVICE_IMPLEMENTATION_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_omservice.h"
+#include "./ifc_omservicedetails.h"
+#include "./ifc_omserviceeditor.h"
+#include "./ifc_omservicecopier.h"
+#include "./ifc_omservicecommand.h"
+#include "./ifc_omservicehostext.h"
+#include "./ifc_omserviceeventmngr.h"
+#include "./flagTracker.h"
+#include <vector>
+#include <bfc/multipatch.h>
+
+#define MPIID_OMSVC 10
+#define MPIID_OMSVCDETAILS 20
+#define MPIID_OMSVCEDITOR 30
+#define MPIID_OMSVCCOPIER 40
+#define MPIID_OMSVCCOMMAND 50
+#define MPIID_OMSVCEVENTMNGR 60
+#define MPIID_OMSVCHOSTEXT 70
+
+class OmService : public MultiPatch<MPIID_OMSVC, ifc_omservice>,
+ public MultiPatch<MPIID_OMSVCDETAILS, ifc_omservicedetails>,
+ public MultiPatch<MPIID_OMSVCEDITOR, ifc_omserviceeditor>,
+ public MultiPatch<MPIID_OMSVCCOPIER, ifc_omservicecopier>,
+ public MultiPatch<MPIID_OMSVCCOMMAND, ifc_omservicecommand>,
+ public MultiPatch<MPIID_OMSVCEVENTMNGR, ifc_omserviceeventmngr>,
+ public MultiPatch<MPIID_OMSVCHOSTEXT, ifc_omservicehostext>
+{
+protected:
+ OmService(UINT serviceId, ifc_omservicehost *serviceHost);
+ ~OmService();
+
+public:
+ static HRESULT CreateInstance(UINT serviceId, ifc_omservicehost *serviceHost, OmService **serviceOut);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_omservice */
+ unsigned int GetId();
+ HRESULT GetName(LPWSTR pszBuffer, UINT cchBufferMax);
+ HRESULT GetUrl(LPWSTR pszBuffer, UINT cchBufferMax);
+ HRESULT GetUrlDirect(LPWSTR pszBuffer, UINT cchBufferMax);
+ HRESULT GetIcon(LPWSTR pszBuffer, UINT cchBufferMax);
+ HRESULT GetExternal(IDispatch **ppDispatch);
+ HRESULT GetRating(UINT *rating);
+ HRESULT GetVersion(UINT *version);
+ HRESULT GetFlags(UINT *flags);
+ HRESULT SetAddress(LPCWSTR pszAddress);
+ HRESULT GetAddress(LPWSTR pszBuffer, UINT cchBufferMax);
+ HRESULT GetGeneration(UINT *generation);
+ HRESULT UpdateFlags(UINT flags);
+
+ /* ifc_omservicedetails */
+ HRESULT GetDescription(LPWSTR pszBuffer, UINT cchBufferMax);
+ HRESULT GetAuthorFirst(LPWSTR pszBuffer, UINT cchBufferMax);
+ HRESULT GetAuthorLast(LPWSTR pszBuffer, UINT cchBufferMax);
+ HRESULT GetUpdated(LPWSTR pszBuffer, UINT cchBufferMax);
+ HRESULT GetPublished(LPWSTR pszBuffer, UINT cchBufferMax);
+ HRESULT GetThumbnail(LPWSTR pszBuffer, UINT cchBufferMax);
+ HRESULT GetScreenshot(LPWSTR pszBuffer, UINT cchBufferMax);
+
+ /* ifc_omserviceeditor */
+ HRESULT SetName(LPCWSTR pszName, BOOL utf8);
+ HRESULT SetUrl(LPCWSTR pszUrl, BOOL utf8);
+ HRESULT SetIcon(LPCWSTR pszPath, BOOL utf8);
+ HRESULT SetRating(UINT nRating);
+ HRESULT SetVersion(UINT nVersion);
+ HRESULT SetGeneration(UINT nGeneration);
+ HRESULT SetFlags(UINT nFlags, UINT nMask);
+ HRESULT SetDescription(LPCWSTR pszDescription, BOOL utf8);
+ HRESULT SetAuthorFirst(LPCWSTR pszName, BOOL utf8);
+ HRESULT SetAuthorLast(LPCWSTR pszName, BOOL utf8);
+ HRESULT SetUpdated(LPCWSTR pszDate, BOOL utf8);
+ HRESULT SetPublished(LPCWSTR pszDate, BOOL utf8);
+ HRESULT SetThumbnail(LPCWSTR pszPath, BOOL utf8);
+ HRESULT SetScreenshot(LPCWSTR pszPath, BOOL utf8);
+ HRESULT SetModified(UINT nFlags, UINT nMask);
+ HRESULT GetModified(UINT *pFlags);
+ HRESULT BeginUpdate();
+ HRESULT EndUpdate();
+
+ /* ifc_omservicecopier */
+ HRESULT CopyTo(ifc_omservice *service, UINT *modifiedFlags);
+
+ /* ifc_omservicecommand */
+ HRESULT QueryState(HWND hBrowser, const GUID *commandGroup, UINT commandId);
+ HRESULT Exec(HWND hBrowser, const GUID *commandGroup, UINT commandId, ULONG_PTR commandArg);
+
+ /* ifc_omserviceeventmngr */
+ HRESULT RegisterEventHandler(ifc_omserviceevent *handler);
+ HRESULT UnregisterEventHandler(ifc_omserviceevent *handler);
+ HRESULT Signal_ServiceChange(UINT modifiedFlags);
+ HRESULT Signal_CommandStateChange(const GUID *commandGroup, UINT commandId);
+
+ /* ifc_omservicehostext */
+ HRESULT GetHost(ifc_omservicehost **ppHost);
+ HRESULT SetHost(ifc_omservicehost *serviceHost);
+
+public:
+ HRESULT SetId(UINT serviceId);
+
+private:
+ static void CALLBACK ModifiedEvent(UINT nMark, FlagTracker *instance, ULONG_PTR user);
+ void UnregisterAllEventHandlers();
+ HRESULT StringCchCopyExMT(LPTSTR pszDest, size_t cchDest, LPCTSTR pszSrc, LPTSTR *ppszDestEnd, size_t *pcchRemaining, DWORD dwFlags);
+
+protected:
+ typedef std::vector<ifc_omserviceevent*> EventList;
+
+protected:
+ ULONG ref;
+ UINT id;
+ LPWSTR name;
+ LPWSTR url;
+ LPWSTR icon;
+ UINT rating;
+ UINT version;
+ UINT flags;
+ UINT generation;
+
+ LPWSTR description;
+ LPWSTR authorFirst;
+ LPWSTR authorLast;
+ LPWSTR published;
+ LPWSTR updated;
+ LPWSTR thumbnail;
+ LPWSTR screenshot;
+ FlagTracker modified;
+
+ LPWSTR address;
+ ifc_omservicehost *host;
+
+ CRITICAL_SECTION lock;
+
+ EventList eventList;
+ CRITICAL_SECTION eventLock;
+
+protected:
+ RECVS_MULTIPATCH;
+};
+
+#endif //NULLSOFT_WINAMP_OMSERVICE_IMPLEMENTATION_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/serviceDetails.cpp b/Src/omBrowser/serviceDetails.cpp
new file mode 100644
index 00000000..b3e46eeb
--- /dev/null
+++ b/Src/omBrowser/serviceDetails.cpp
@@ -0,0 +1,55 @@
+#include "./main.h"
+#include "./service.h"
+
+#include <strsafe.h>
+
+HRESULT OmService::GetDescription(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ return StringCchCopyExMT(pszBuffer, cchBufferMax, description, NULL, NULL, STRSAFE_IGNORE_NULLS);
+}
+
+HRESULT OmService::GetAuthorFirst(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ return StringCchCopyExMT(pszBuffer, cchBufferMax, authorFirst, NULL, NULL, STRSAFE_IGNORE_NULLS);
+}
+
+HRESULT OmService::GetAuthorLast(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ return StringCchCopyExMT(pszBuffer, cchBufferMax, authorLast, NULL, NULL, STRSAFE_IGNORE_NULLS);
+}
+
+HRESULT OmService::GetPublished(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ if (NULL == pszBuffer) return E_POINTER;
+
+ EnterCriticalSection(&lock);
+
+ LPCWSTR source = (NULL != published && L'\0' != *published) ? published : updated;
+ HRESULT hr = StringCchCopyEx(pszBuffer, cchBufferMax, source, NULL, NULL, STRSAFE_IGNORE_NULLS);
+
+ LeaveCriticalSection(&lock);
+ return hr;
+}
+
+HRESULT OmService::GetUpdated(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ if (NULL == pszBuffer) return E_POINTER;
+
+ EnterCriticalSection(&lock);
+
+ LPCWSTR source = (NULL != updated && L'\0' != *updated) ? updated : published;
+ HRESULT hr = StringCchCopyEx(pszBuffer, cchBufferMax, source, NULL, NULL, STRSAFE_IGNORE_NULLS);
+
+ LeaveCriticalSection(&lock);
+ return hr;
+}
+
+HRESULT OmService::GetThumbnail(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ return StringCchCopyExMT(pszBuffer, cchBufferMax, thumbnail, NULL, NULL, STRSAFE_IGNORE_NULLS | STRSAFE_NULL_ON_FAILURE);
+}
+
+HRESULT OmService::GetScreenshot(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ return StringCchCopyExMT(pszBuffer, cchBufferMax, screenshot, NULL, NULL, STRSAFE_IGNORE_NULLS | STRSAFE_NULL_ON_FAILURE);
+} \ No newline at end of file
diff --git a/Src/omBrowser/serviceDispatch.cpp b/Src/omBrowser/serviceDispatch.cpp
new file mode 100644
index 00000000..deb2dd4e
--- /dev/null
+++ b/Src/omBrowser/serviceDispatch.cpp
@@ -0,0 +1,87 @@
+#include "./main.h"
+#include "./service.h"
+
+#define CBCLASS OmService
+START_MULTIPATCH;
+ START_PATCH(MPIID_OMSVC)
+ M_CB(MPIID_OMSVC, ifc_omservice, ADDREF, AddRef);
+ M_CB(MPIID_OMSVC, ifc_omservice, RELEASE, Release);
+ M_CB(MPIID_OMSVC, ifc_omservice, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMSVC, ifc_omservice, API_GETID, GetId);
+ M_CB(MPIID_OMSVC, ifc_omservice, API_GETNAME, GetName);
+ M_CB(MPIID_OMSVC, ifc_omservice, API_GETURL, GetUrl);
+ M_CB(MPIID_OMSVC, ifc_omservice, API_GETURLDIRECT, GetUrlDirect);
+ M_CB(MPIID_OMSVC, ifc_omservice, API_GETICON, GetIcon);
+ M_CB(MPIID_OMSVC, ifc_omservice, API_GETEXTERNAL, GetExternal);
+ M_CB(MPIID_OMSVC, ifc_omservice, API_GETRATING, GetRating);
+ M_CB(MPIID_OMSVC, ifc_omservice, API_GETVERSION, GetVersion);
+ M_CB(MPIID_OMSVC, ifc_omservice, API_GETGENERATION, GetGeneration);
+ M_CB(MPIID_OMSVC, ifc_omservice, API_GETFLAGS, GetFlags);
+ M_CB(MPIID_OMSVC, ifc_omservice, API_SETADDRESS, SetAddress);
+ M_CB(MPIID_OMSVC, ifc_omservice, API_GETADDRESS, GetAddress);
+ M_CB(MPIID_OMSVC, ifc_omservice, API_UPDATEFLAGS, UpdateFlags);
+
+ NEXT_PATCH(MPIID_OMSVCDETAILS)
+ M_CB(MPIID_OMSVCDETAILS, ifc_omservicedetails, ADDREF, AddRef);
+ M_CB(MPIID_OMSVCDETAILS, ifc_omservicedetails, RELEASE, Release);
+ M_CB(MPIID_OMSVCDETAILS, ifc_omservicedetails, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMSVCDETAILS, ifc_omservicedetails, API_GETDESCRIPTION, GetDescription);
+ M_CB(MPIID_OMSVCDETAILS, ifc_omservicedetails, API_GETAUTHORFIRST, GetAuthorFirst);
+ M_CB(MPIID_OMSVCDETAILS, ifc_omservicedetails, API_GETAUTHORLAST, GetAuthorLast);
+ M_CB(MPIID_OMSVCDETAILS, ifc_omservicedetails, API_GETUPDATED, GetUpdated);
+ M_CB(MPIID_OMSVCDETAILS, ifc_omservicedetails, API_GETPUBLISHED, GetPublished);
+ M_CB(MPIID_OMSVCDETAILS, ifc_omservicedetails, API_GETTHUMBNAIL, GetThumbnail);
+ M_CB(MPIID_OMSVCDETAILS, ifc_omservicedetails, API_GETSCREENSHOT, GetScreenshot);
+
+ NEXT_PATCH(MPIID_OMSVCEDITOR)
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, ADDREF, AddRef);
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, RELEASE, Release);
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, API_SETNAME, SetName);
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, API_SETURL, SetUrl);
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, API_SETICON, SetIcon);
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, API_SETRATING, SetRating);
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, API_SETVERSION, SetVersion);
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, API_SETGENERATION, SetGeneration);
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, API_SETFLAGS, SetFlags);
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, API_SETDESCRIPTION, SetDescription);
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, API_SETAUTHORFIRST, SetAuthorFirst);
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, API_SETAUTHORLAST, SetAuthorLast);
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, API_SETUPDATED, SetUpdated);
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, API_SETPUBLISHED, SetPublished);
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, API_SETTHUMBNAIL, SetThumbnail);
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, API_SETSCREENSHOT, SetScreenshot);
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, API_SETMODIFIED, SetModified);
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, API_GETMODIFIED, GetModified);
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, API_BEGINUPDATE, BeginUpdate);
+ M_CB(MPIID_OMSVCEDITOR, ifc_omserviceeditor, API_ENDUPDATE, EndUpdate);
+
+ NEXT_PATCH(MPIID_OMSVCCOPIER)
+ M_CB(MPIID_OMSVCCOPIER, ifc_omservicecopier, ADDREF, AddRef);
+ M_CB(MPIID_OMSVCCOPIER, ifc_omservicecopier, RELEASE, Release);
+ M_CB(MPIID_OMSVCCOPIER, ifc_omservicecopier, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMSVCCOPIER, ifc_omservicecopier, API_COPYTO, CopyTo);
+
+ NEXT_PATCH(MPIID_OMSVCCOMMAND)
+ M_CB(MPIID_OMSVCCOMMAND, ifc_omservicecommand, ADDREF, AddRef);
+ M_CB(MPIID_OMSVCCOMMAND, ifc_omservicecommand, RELEASE, Release);
+ M_CB(MPIID_OMSVCCOMMAND, ifc_omservicecommand, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMSVCCOMMAND, ifc_omservicecommand, API_QUERYSTATE, QueryState);
+ M_CB(MPIID_OMSVCCOMMAND, ifc_omservicecommand, API_EXEC, Exec);
+
+ NEXT_PATCH(MPIID_OMSVCEVENTMNGR)
+ M_CB(MPIID_OMSVCEVENTMNGR, ifc_omserviceeventmngr, ADDREF, AddRef);
+ M_CB(MPIID_OMSVCEVENTMNGR, ifc_omserviceeventmngr, RELEASE, Release);
+ M_CB(MPIID_OMSVCEVENTMNGR, ifc_omserviceeventmngr, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMSVCEVENTMNGR, ifc_omserviceeventmngr, API_REGISTERHANDLER, RegisterEventHandler);
+ M_CB(MPIID_OMSVCEVENTMNGR, ifc_omserviceeventmngr, API_UNREGISTERHANDLER, UnregisterEventHandler);
+ M_CB(MPIID_OMSVCEVENTMNGR, ifc_omserviceeventmngr, API_SIGNAL_SERVICECHANGE, Signal_ServiceChange);
+ M_CB(MPIID_OMSVCEVENTMNGR, ifc_omserviceeventmngr, API_SIGNAL_COMMANDSTATECHANGE, Signal_CommandStateChange);
+
+ NEXT_PATCH(MPIID_OMSVCHOSTEXT)
+ M_CB(MPIID_OMSVCHOSTEXT, ifc_omservicehostext, API_GETHOST, GetHost);
+ M_CB(MPIID_OMSVCHOSTEXT, ifc_omservicehostext, API_SETHOST, SetHost);
+
+ END_PATCH
+END_MULTIPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/serviceEditor.cpp b/Src/omBrowser/serviceEditor.cpp
new file mode 100644
index 00000000..17171051
--- /dev/null
+++ b/Src/omBrowser/serviceEditor.cpp
@@ -0,0 +1,257 @@
+#include "main.h"
+#include "./service.h"
+#include <strsafe.h>
+
+static HRESULT Editor_SetStr(LPWSTR *ppTarget, LPCWSTR pValue, BOOL fUtf8, BOOL fCompare, LCID locale, UINT compareFlags)
+{
+ if (NULL == pValue)
+ {
+ if (NULL != *ppTarget)
+ {
+ Plugin_FreeString(*ppTarget);
+ *ppTarget = NULL;
+ return S_OK;
+ }
+ return S_FALSE;
+ }
+
+ LPWSTR v = NULL;
+
+ if (FALSE == fUtf8)
+ {
+ if (NULL != *ppTarget)
+ {
+ if (FALSE != fCompare && CSTR_EQUAL == CompareString(locale, compareFlags, *ppTarget, -1, pValue, -1))
+ return S_FALSE;
+ }
+
+ v = Plugin_CopyString(pValue);
+ if (NULL == v) return E_OUTOFMEMORY;
+ }
+ else
+ {
+ v = Plugin_MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pValue, -1);
+ if (NULL == v) return E_OUTOFMEMORY;
+
+ if (NULL != *ppTarget)
+ {
+ if (FALSE != fCompare && CSTR_EQUAL == CompareString(locale, compareFlags, *ppTarget, -1, v, -1))
+ {
+ Plugin_FreeString(v);
+ return S_FALSE;
+ }
+ }
+ }
+
+ Plugin_FreeString(*ppTarget);
+ *ppTarget = v;
+
+ return S_OK;
+}
+
+
+HRESULT OmService::SetName(LPCWSTR pszName, BOOL utf8)
+{
+ EnterCriticalSection(&lock);
+ HRESULT hr = Editor_SetStr(&name, pszName, utf8, TRUE, LOCALE_USER_DEFAULT, 0);
+ LeaveCriticalSection(&lock);
+
+ if (S_OK == hr) modified.Mark(modifiedName);
+ return hr;
+}
+
+HRESULT OmService::SetUrl(LPCWSTR pszUrl, BOOL utf8)
+{
+ EnterCriticalSection(&lock);
+ HRESULT hr = Editor_SetStr(&url, pszUrl, utf8, TRUE, CSTR_INVARIANT, 0);
+ LeaveCriticalSection(&lock);
+
+ if (S_OK == hr) modified.Mark(modifiedUrl);
+ return hr;
+}
+
+HRESULT OmService::SetIcon(LPCWSTR pszPath, BOOL utf8)
+{
+ EnterCriticalSection(&lock);
+ HRESULT hr = Editor_SetStr(&icon, pszPath, utf8, TRUE, CSTR_INVARIANT, 0);
+ LeaveCriticalSection(&lock);
+
+ if (S_OK == hr) modified.Mark(modifiedIcon);
+ return hr;
+}
+
+HRESULT OmService::SetRating(UINT nRating)
+{
+ HRESULT hr;
+
+ EnterCriticalSection(&lock);
+ if (rating == nRating)
+ {
+ hr = S_FALSE;
+ }
+ else
+ {
+ rating = nRating;
+ hr = S_OK;
+ }
+ LeaveCriticalSection(&lock);
+
+ if (S_OK == hr)
+ modified.Mark(modifiedRating);
+ return hr;
+}
+
+HRESULT OmService::SetVersion(UINT nVersion)
+{
+ HRESULT hr;
+
+ EnterCriticalSection(&lock);
+ if (version == nVersion)
+ hr = S_FALSE;
+ else
+ {
+ version = nVersion;
+ hr = S_OK;
+ }
+ LeaveCriticalSection(&lock);
+
+ if (S_OK == hr)
+ modified.Mark(modifiedVersion);
+
+ return hr;
+}
+
+HRESULT OmService::SetGeneration(UINT nGeneration)
+{
+ HRESULT hr;
+
+ EnterCriticalSection(&lock);
+ if (generation == nGeneration)
+ hr = S_FALSE;
+ else
+ {
+ generation = nGeneration;
+ hr = S_OK;
+ }
+ LeaveCriticalSection(&lock);
+
+ if (S_OK == hr)
+ modified.Mark(modifiedGeneration);
+
+ return hr;
+}
+
+HRESULT OmService::SetFlags(UINT nFlags, UINT nMask)
+{
+ HRESULT hr;
+
+ EnterCriticalSection(&lock);
+ UINT newFlags = (flags & ~nMask) | (nFlags & nMask);
+ if (flags == newFlags)
+ hr = S_FALSE;
+ else
+ {
+ flags = newFlags;
+ hr = S_OK;
+ }
+ LeaveCriticalSection(&lock);
+
+ if (S_OK == hr)
+ modified.Mark(modifiedFlags);
+
+ return hr;
+}
+
+HRESULT OmService::SetDescription(LPCWSTR pszDescription, BOOL utf8)
+{
+ EnterCriticalSection(&lock);
+ HRESULT hr = Editor_SetStr(&description, pszDescription, utf8, TRUE, LOCALE_USER_DEFAULT, 0);
+ LeaveCriticalSection(&lock);
+
+ if (S_OK == hr) modified.Mark(modifiedDescription);
+ return hr;
+}
+
+HRESULT OmService::SetAuthorFirst(LPCWSTR pszName, BOOL utf8)
+{
+ EnterCriticalSection(&lock);
+ HRESULT hr = Editor_SetStr(&authorFirst, pszName, utf8, TRUE, LOCALE_USER_DEFAULT, 0);
+ LeaveCriticalSection(&lock);
+ if (S_OK == hr) modified.Mark(modifiedAuthorFirst);
+ return hr;
+}
+
+HRESULT OmService::SetAuthorLast(LPCWSTR pszName, BOOL utf8)
+{
+ EnterCriticalSection(&lock);
+ HRESULT hr = Editor_SetStr(&authorLast, pszName, utf8, TRUE, LOCALE_USER_DEFAULT, 0);
+ LeaveCriticalSection(&lock);
+
+ if (S_OK == hr) modified.Mark(modifiedAuthorLast);
+ return hr;
+}
+
+HRESULT OmService::SetUpdated(LPCWSTR pszDate, BOOL utf8)
+{
+ EnterCriticalSection(&lock);
+ HRESULT hr = Editor_SetStr(&updated, pszDate, utf8, TRUE, CSTR_INVARIANT, 0);
+ LeaveCriticalSection(&lock);
+
+ if (S_OK == hr) modified.Mark(modifiedUpdated);
+ return hr;
+}
+
+HRESULT OmService::SetPublished(LPCWSTR pszDate, BOOL utf8)
+{
+ EnterCriticalSection(&lock);
+ HRESULT hr = Editor_SetStr(&published, pszDate, utf8, TRUE, CSTR_INVARIANT, 0);
+ LeaveCriticalSection(&lock);
+
+ if (S_OK == hr) modified.Mark(modifiedPublished);
+ return hr;
+}
+
+HRESULT OmService::SetThumbnail(LPCWSTR pszPath, BOOL utf8)
+{
+ EnterCriticalSection(&lock);
+ HRESULT hr = Editor_SetStr(&thumbnail, pszPath, utf8, TRUE, CSTR_INVARIANT, 0);
+ LeaveCriticalSection(&lock);
+
+ if (S_OK == hr) modified.Mark(modifiedThumbnail);
+ return hr;
+}
+
+HRESULT OmService::SetScreenshot(LPCWSTR pszPath, BOOL utf8)
+{
+ EnterCriticalSection(&lock);
+ HRESULT hr = Editor_SetStr(&screenshot, pszPath, utf8, TRUE, CSTR_INVARIANT, 0);
+ LeaveCriticalSection(&lock);
+
+ if (S_OK == hr) modified.Mark(modifiedScreenshot);
+ return hr;
+}
+
+HRESULT OmService::SetModified(UINT nFlags, UINT nMask)
+{
+ modified.Set(nFlags, nMask);
+ return S_OK;
+}
+
+HRESULT OmService::GetModified(UINT *pFlags)
+{
+ if (NULL == pFlags) return E_POINTER;
+ *pFlags = modified.Get();
+ return S_OK;
+}
+
+HRESULT OmService::BeginUpdate()
+{
+ modified.BeginUpdate();
+ return S_OK;
+}
+
+HRESULT OmService::EndUpdate()
+{
+ modified.EndUpdate();
+ return S_OK;
+} \ No newline at end of file
diff --git a/Src/omBrowser/serviceEventMngr.cpp b/Src/omBrowser/serviceEventMngr.cpp
new file mode 100644
index 00000000..4d9b100e
--- /dev/null
+++ b/Src/omBrowser/serviceEventMngr.cpp
@@ -0,0 +1,119 @@
+#include "main.h"
+#include "./service.h"
+#include "./ifc_omserviceevent.h"
+
+HRESULT OmService::RegisterEventHandler(ifc_omserviceevent *handler)
+{
+ if (NULL == handler)
+ return E_POINTER;
+
+ HRESULT hr;
+
+ EnterCriticalSection(&eventLock);
+
+ size_t index = eventList.size();
+ while (index--)
+ {
+ if (handler == eventList[index])
+ {
+ break;
+ }
+ }
+
+ if (((size_t)-1) == index)
+ {
+ eventList.push_back(handler);
+ handler->AddRef();
+ hr = S_OK;
+ }
+ else
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ LeaveCriticalSection(&eventLock);
+
+ return hr;
+}
+
+HRESULT OmService::UnregisterEventHandler(ifc_omserviceevent *handler)
+{
+ if (NULL == handler)
+ return E_POINTER;
+
+ HRESULT hr;
+
+ EnterCriticalSection(&eventLock);
+
+ size_t index = eventList.size();
+ while (index--)
+ {
+ if (handler == eventList[index])
+ {
+ break;
+ }
+ }
+
+ if (((size_t)-1) != index)
+ {
+ ifc_omserviceevent *h = eventList[index];
+ eventList.erase(eventList.begin() + index);
+ h->Release();
+ hr = S_OK;
+ }
+ else
+ {
+ hr = S_FALSE;
+ }
+
+ LeaveCriticalSection(&eventLock);
+
+ return hr;
+}
+
+void OmService::UnregisterAllEventHandlers()
+{
+ EnterCriticalSection(&eventLock);
+
+ size_t index = eventList.size();
+ while(index--)
+ {
+ ifc_omserviceevent *handler = eventList[index];
+ if (NULL != handler) handler->Release();
+ }
+ eventList.clear();
+
+ LeaveCriticalSection(&eventLock);
+}
+
+HRESULT OmService::Signal_ServiceChange(unsigned int modifiedFlags)
+{
+ EnterCriticalSection(&eventLock);
+
+ size_t index = eventList.size();
+ while (index--)
+ {
+ ifc_omserviceevent *handler = eventList[index];
+ if (NULL != handler)
+ handler->ServiceChange(this, modifiedFlags);
+ }
+
+ LeaveCriticalSection(&eventLock);
+ return S_OK;
+}
+
+HRESULT OmService::Signal_CommandStateChange(const GUID *commandGroup, UINT commandId)
+{
+ EnterCriticalSection(&eventLock);
+
+ size_t index = eventList.size();
+ while (index--)
+ {
+ ifc_omserviceevent *handler = eventList[index];
+ if (NULL != handler)
+ handler->CommandStateChange(this, commandGroup, commandId);
+ }
+
+ LeaveCriticalSection(&eventLock);
+ return S_OK;
+} \ No newline at end of file
diff --git a/Src/omBrowser/serviceFactory.cpp b/Src/omBrowser/serviceFactory.cpp
new file mode 100644
index 00000000..65b1d323
--- /dev/null
+++ b/Src/omBrowser/serviceFactory.cpp
@@ -0,0 +1,90 @@
+#include "./serviceFactory.h"
+#include "./serviceManager.h"
+
+OmServiceFactory::OmServiceFactory()
+ : object(NULL)
+{
+}
+
+OmServiceFactory::~OmServiceFactory()
+{
+ if (NULL != object)
+ object->Release();
+}
+
+FOURCC OmServiceFactory::GetServiceType()
+{
+ return WaSvc::UNIQUE;
+}
+
+const char *OmServiceFactory::GetServiceName()
+{
+ return "OmServiceManager Interface";
+}
+
+GUID OmServiceFactory::GetGUID()
+{
+ return IFC_OmServiceManager;
+}
+
+void *OmServiceFactory::GetInterface(int global_lock)
+{
+ if (NULL == object)
+ {
+ object = OmServiceManager::CreateInstance();
+ if (NULL == object) return NULL;
+ }
+
+ object->AddRef();
+ return object;
+}
+
+int OmServiceFactory::SupportNonLockingInterface()
+{
+ return 1;
+}
+
+int OmServiceFactory::ReleaseInterface(void *ifc)
+{
+ OmServiceManager *object = (OmServiceManager*)ifc;
+ if (NULL != object) object->Release();
+
+ return 1;
+}
+
+const char *OmServiceFactory::GetTestString()
+{
+ return NULL;
+}
+
+int OmServiceFactory::ServiceNotify(int msg, int param1, int param2)
+{
+ return 1;
+}
+
+HRESULT OmServiceFactory::Register(api_service *service)
+{
+ if (NULL == service) return E_INVALIDARG;
+ service->service_register(this);
+ return S_OK;
+}
+
+HRESULT OmServiceFactory::Unregister(api_service *service)
+{
+ if (NULL == service) return E_INVALIDARG;
+ service->service_deregister(this);
+ return S_OK;
+}
+
+#define CBCLASS OmServiceFactory
+START_DISPATCH;
+CB(WASERVICEFACTORY_GETSERVICETYPE, GetServiceType)
+CB(WASERVICEFACTORY_GETSERVICENAME, GetServiceName)
+CB(WASERVICEFACTORY_GETGUID, GetGUID)
+CB(WASERVICEFACTORY_GETINTERFACE, GetInterface)
+CB(WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface)
+CB(WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface)
+CB(WASERVICEFACTORY_GETTESTSTRING, GetTestString)
+CB(WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/serviceFactory.h b/Src/omBrowser/serviceFactory.h
new file mode 100644
index 00000000..f0127559
--- /dev/null
+++ b/Src/omBrowser/serviceFactory.h
@@ -0,0 +1,36 @@
+#ifndef NULLSOFT_WINAMP_OMSERVICEOBJECT_FACTORY_HEADER
+#define NULLSOFT_WINAMP_OMSERVICEOBJECT_FACTORY_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <api/service/waservicefactory.h>
+#include <api/service/services.h>
+
+class OmServiceManager;
+
+class OmServiceFactory : public waServiceFactory
+{
+public:
+ OmServiceFactory();
+ ~OmServiceFactory();
+
+ FOURCC GetServiceType();
+ const char *GetServiceName();
+ GUID GetGUID();
+ void *GetInterface( int global_lock );
+ int SupportNonLockingInterface();
+ int ReleaseInterface( void *ifc );
+ const char *GetTestString();
+ int ServiceNotify( int msg, int param1, int param2 );
+
+ HRESULT Register( api_service *service );
+ HRESULT Unregister( api_service *service );
+
+protected:
+ RECVS_DISPATCH;
+ OmServiceManager *object;
+};
+
+#endif //NULLSOFT_WINAMP_OMSERVICEOBJECT_FACTORY_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/serviceList.cpp b/Src/omBrowser/serviceList.cpp
new file mode 100644
index 00000000..a2b9b367
--- /dev/null
+++ b/Src/omBrowser/serviceList.cpp
@@ -0,0 +1,149 @@
+#include "./main.h"
+#include "./serviceList.h"
+
+#include "./ifc_omservice.h"
+
+OmServiceList::OmServiceList()
+ : ref(1), cursor(0)
+{
+}
+
+OmServiceList::~OmServiceList()
+{
+ size_t index = list.size();
+ while(index--)
+ {
+ list[index]->Release();
+ }
+}
+
+HRESULT OmServiceList::CreateInstance(OmServiceList **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ *instance = new OmServiceList();
+ if (NULL == *instance) return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+size_t OmServiceList::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t OmServiceList::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int OmServiceList::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmServiceEnum))
+ *object = static_cast<ifc_omserviceenum*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT OmServiceList::Next(unsigned long listSize, ifc_omservice **elementList, unsigned long *elementCount)
+{
+ if (NULL == elementList || 0 == listSize) return E_INVALIDARG;
+
+ size_t size = list.size();
+
+ if (cursor >= size)
+ {
+ if (NULL != elementCount) *elementCount = 0;
+ return S_FALSE;
+ }
+
+ size_t available = size - cursor;
+ size_t count = ((available > listSize) ? listSize : available);
+
+ ifc_omservice **source = &list.at(0) + cursor;
+ CopyMemory(elementList, source, count * sizeof(ifc_omservice*));
+ for(size_t i = 0; i < count; i++)
+ {
+ elementList[i]->AddRef();
+ }
+
+ cursor += count;
+
+ if (NULL != elementCount)
+ *elementCount = (ULONG)count;
+
+ return (count == listSize) ? S_OK : S_FALSE;
+}
+
+HRESULT OmServiceList::Reset(void)
+{
+ cursor = 0;
+ return S_OK;
+}
+
+HRESULT OmServiceList::Skip(unsigned long elementCount)
+{
+ size_t size = list.size();
+ cursor += elementCount;
+ if (cursor > size)
+ cursor = size;
+
+ return (cursor < size) ? S_OK : S_FALSE;
+}
+
+HRESULT OmServiceList::Add(ifc_omservice *service)
+{
+ if(NULL == service) return E_INVALIDARG;
+ list.push_back(service);
+ service->AddRef();
+ return S_OK;
+}
+
+HRESULT OmServiceList::Remove(size_t index)
+{
+ if (index >= list.size())
+ return E_FAIL;
+ ifc_omservice *temp = list[index];
+ list.erase(list.begin() + index);
+ temp->Release();
+
+ return S_OK;
+}
+
+HRESULT OmServiceList::Clear()
+{
+ size_t index = list.size();
+ while(index--)
+ {
+ list[index]->Release();
+ }
+ list.clear();
+ return S_OK;
+}
+
+#define CBCLASS OmServiceList
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_NEXT, Next)
+CB(API_RESET, Reset)
+CB(API_SKIP, Skip)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/serviceList.h b/Src/omBrowser/serviceList.h
new file mode 100644
index 00000000..ab01aa3b
--- /dev/null
+++ b/Src/omBrowser/serviceList.h
@@ -0,0 +1,51 @@
+#ifndef NULLSOFT_WINAMP_OMSERVICE_LIST_ENUMERATOR_HEADER
+#define NULLSOFT_WINAMP_OMSERVICE_LIST_ENUMERATOR_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+#include "./ifc_omserviceenum.h"
+#include <vector>
+
+class ifc_omservice;
+
+class OmServiceList : public ifc_omserviceenum
+{
+protected:
+ OmServiceList();
+ ~OmServiceList();
+
+public:
+ static HRESULT CreateInstance(OmServiceList **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_omserviceenum */
+ HRESULT Next(unsigned long listSize, ifc_omservice **elementList, unsigned long *elementCount);
+ HRESULT Reset(void);
+ HRESULT Skip(unsigned long elementCount);
+
+public:
+ HRESULT Add(ifc_omservice *service);
+ HRESULT Remove(size_t index);
+ HRESULT Clear();
+
+protected:
+ typedef std::vector<ifc_omservice*> SvcList;
+
+protected:
+ size_t ref;
+ SvcList list;
+ size_t cursor;
+
+protected:
+ RECVS_DISPATCH;
+};
+
+#endif //NULLSOFT_WINAMP_OMSERVICE_LIST_ENUMERATOR_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/serviceManager.cpp b/Src/omBrowser/serviceManager.cpp
new file mode 100644
index 00000000..3c66e983
--- /dev/null
+++ b/Src/omBrowser/serviceManager.cpp
@@ -0,0 +1,214 @@
+#include "main.h"
+#include "./serviceManager.h"
+#include "./service.h"
+
+#include "./ifc_wasabihelper.h"
+
+#include "./storageIni.h"
+#include "./storageXml.h"
+#include "./storageUrl.h"
+#include "./storageEnum.h"
+
+#include <shlwapi.h>
+#include <strsafe.h>
+
+OmServiceManager::OmServiceManager()
+ : ref(1), registerStorage(TRUE)
+{
+}
+
+OmServiceManager::~OmServiceManager()
+{
+ size_t index = storageList.size();
+ while(index--)
+ {
+ storageList[index]->Release();
+ }
+}
+
+OmServiceManager *OmServiceManager::CreateInstance()
+{
+ return new OmServiceManager();
+}
+
+size_t OmServiceManager::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t OmServiceManager::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int OmServiceManager::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmServiceManager))
+ *object = static_cast<ifc_omservicemanager*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+
+ return S_OK;
+}
+
+HRESULT OmServiceManager::RegisterDefaultStorage()
+{
+ ifc_omstorage *storage;
+ if (SUCCEEDED(OmStorageIni::CreateInstance((OmStorageIni**)&storage)))
+ {
+ RegisterStorage(storage);
+ storage->Release();
+ }
+
+ if (SUCCEEDED(OmStorageXml::CreateInstance((OmStorageXml**)&storage)))
+ {
+ RegisterStorage(storage);
+ storage->Release();
+ }
+
+ if (SUCCEEDED(OmStorageUrl::CreateInstance((OmStorageUrl**)&storage)))
+ {
+ RegisterStorage(storage);
+ storage->Release();
+ }
+
+ return S_OK;
+}
+
+HRESULT OmServiceManager::RegisterStorage(ifc_omstorage *storage)
+{
+ if (NULL == storage) return E_INVALIDARG;
+
+ HRESULT hr;
+ GUID storageId, testId;
+
+ if (FAILED(storage->GetId(&storageId)))
+ return E_FAIL;
+
+ size_t index = storageList.size();
+ while(index--)
+ {
+ if(SUCCEEDED(storageList[index]->GetId(&testId)) && IsEqualGUID(storageId, testId))
+ break;
+ }
+
+ if (((size_t)-1) == index)
+ {
+ storageList.push_back(storage);
+ storage->AddRef();
+ hr = S_OK;
+ }
+ else
+ {
+ hr = S_FALSE;
+ }
+ return hr;
+}
+
+HRESULT OmServiceManager::UnregisterStorage(const GUID *storageId)
+{
+ if (NULL == storageId) return E_INVALIDARG;
+
+ HRESULT hr = S_FALSE;
+ GUID testId;
+
+ size_t index = storageList.size();
+ while(index--)
+ {
+ ifc_omstorage *storage = storageList[index];
+ if(SUCCEEDED(storage->GetId(&testId)) && IsEqualGUID(*storageId, testId))
+ {
+ storageList.erase(storageList.begin() + index);
+ storage->Release();
+ hr = S_OK;
+ break;
+ }
+ }
+ return hr;
+}
+
+HRESULT OmServiceManager::QueryStorage(const GUID *storageId, ifc_omstorage **storageOut)
+{
+ if (NULL == storageOut) return E_POINTER;
+ *storageOut = NULL;
+
+ if (NULL == storageId)
+ return E_INVALIDARG;
+
+ if (FALSE != registerStorage && SUCCEEDED(RegisterDefaultStorage()))
+ registerStorage = FALSE;
+
+ HRESULT hr = S_FALSE;
+ GUID testId;
+
+ size_t index = storageList.size();
+ while(index--)
+ {
+ ifc_omstorage *storage = storageList[index];
+ if(SUCCEEDED(storage->GetId(&testId)) && IsEqualGUID(*storageId, testId))
+ {
+ storage->AddRef();
+ *storageOut = storage;
+ hr = S_OK;
+ break;
+ }
+ }
+
+ return hr;
+}
+
+HRESULT OmServiceManager::EnumStorage(const GUID *filterType, UINT filterCapabilities, ifc_omstorageenumerator **enumOut)
+{
+ if (FALSE != registerStorage && SUCCEEDED(RegisterDefaultStorage()))
+ registerStorage = FALSE;
+
+ return OmStorageEnumerator::CreateInstance(storageList.size() ? &storageList.at(0) : nullptr, storageList.size(),
+ filterType, filterCapabilities,
+ (OmStorageEnumerator**)enumOut);
+}
+
+HRESULT OmServiceManager::CreateService(UINT serviceId, ifc_omservicehost *host, ifc_omservice **serviceOut)
+{
+ if (NULL == serviceOut) return E_POINTER;
+
+ OmService *service = NULL;
+ HRESULT hr = OmService::CreateInstance(serviceId, host, &service);
+ if (FAILED(hr))
+ {
+ *serviceOut = NULL;
+ return hr;
+ }
+
+ *serviceOut = service;
+ return hr;
+}
+
+#define CBCLASS OmServiceManager
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_REGISTERSTORAGE, RegisterStorage)
+CB(API_UNREGISTERSTORAGE, UnregisterStorage)
+CB(API_QUERYSTORAGE, QueryStorage)
+CB(API_ENUMSTORAGE, EnumStorage)
+CB(API_CREATESERVICE, CreateService)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/serviceManager.h b/Src/omBrowser/serviceManager.h
new file mode 100644
index 00000000..c16aad63
--- /dev/null
+++ b/Src/omBrowser/serviceManager.h
@@ -0,0 +1,49 @@
+#ifndef NULLSOFT_WINAMP_OMSERVICE_MANAGER_HEADER
+#define NULLSOFT_WINAMP_OMSERVICE_MANAGER_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_omservicemanager.h"
+#include <vector>
+
+class OmServiceManager : public ifc_omservicemanager
+{
+protected:
+ OmServiceManager();
+ ~OmServiceManager();
+
+public:
+ static OmServiceManager *CreateInstance();
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_omservice */
+ HRESULT RegisterStorage(ifc_omstorage *storage);
+ HRESULT UnregisterStorage(const GUID *storageId);
+ HRESULT QueryStorage(const GUID *storageId, ifc_omstorage **storageOut);
+ HRESULT EnumStorage(const GUID *filterType, UINT filterCapabilities, ifc_omstorageenumerator **enumOut);
+ HRESULT CreateService(UINT serviceId, ifc_omservicehost *host, ifc_omservice **serviceOut);
+
+protected:
+ HRESULT RegisterDefaultStorage();
+
+protected:
+ RECVS_DISPATCH;
+
+protected:
+ typedef std::vector<ifc_omstorage*> StorageList;
+
+protected:
+ ULONG ref;
+ BOOL registerStorage;
+ StorageList storageList;
+};
+
+#endif //NULLSOFT_WINAMP_OMSERVICE_MANAGER_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/skinHelper.cpp b/Src/omBrowser/skinHelper.cpp
new file mode 100644
index 00000000..8f4ecdfb
--- /dev/null
+++ b/Src/omBrowser/skinHelper.cpp
@@ -0,0 +1,602 @@
+#include "main.h"
+
+#ifndef WA_DLG_IMPLEMENT
+#define WA_DLG_IMPLEMENT
+#endif // WA_DLG_IMPLEMENT
+#include "../winamp/wa_dlg.h"
+#undef WA_DLG_IMPLEMENT
+#include "./skinHelper.h"
+#include "./ratingMenuCustomizer.h"
+#include "./ifc_menucustomizer.h"
+#include <windows.h>
+#include <shlwapi.h>
+#include <strsafe.h>
+
+#define ENSURE_FUNCTION_LOADED(__function) {\
+ HRESULT hr;\
+ if (NULL == (__function)) {\
+ hr = LoadMediaLibraryModule();\
+ if (SUCCEEDED(hr) && NULL == (__function)) hr = E_UNEXPECTED;\
+ if (FAILED(hr)) return hr; }}
+
+#define BOOL2HRESULT(__result) ((FALSE != (__result)) ? S_OK : E_FAIL)
+
+SkinHelper::SkinHelper(HWND hwndWa)
+ : ref(1), hwndWinamp(hwndWa), mlModule(NULL), mlLoadResult(S_FALSE),
+ playlistFont(NULL), initializeColors(TRUE), cchHostCss(0),
+ mlSkinWindowEx(NULL), mlUnskinWindow(NULL), mlTrackSkinnedPopupMenuEx(NULL),
+ mlIsSkinnedPopupEnabled(NULL), mlInitSkinnedPopupHook(NULL),
+ mlRemoveSkinnedPopupHook(NULL), mlGetSkinColor(NULL), mlResetSkinColor(NULL),
+ mlRatingDraw(NULL), mlRatingHitTest(NULL), mlRatingCalcMinRect(NULL)
+{
+ ZeroMemory(szBrushes, sizeof(HBRUSH) * ARRAYSIZE(szBrushes));
+ ZeroMemory(szHostCss, sizeof(szHostCss));
+}
+
+SkinHelper::~SkinHelper()
+{
+ if (NULL != playlistFont)
+ DeleteObject(playlistFont);
+
+ for (int i = 0; i < ARRAYSIZE(szBrushes); i++)
+ {
+ if (NULL != szBrushes[i]) DeleteObject(szBrushes[i]);
+ }
+
+ if (NULL != mlModule)
+ FreeLibrary(mlModule);
+}
+
+HRESULT SkinHelper::CreateInstance(HWND hwndWinamp, SkinHelper **instance)
+{
+ if (NULL == instance) return E_POINTER;
+
+ *instance = NULL;
+
+ if (NULL == hwndWinamp || FALSE == IsWindow(hwndWinamp))
+ return E_INVALIDARG;
+
+ *instance = new SkinHelper(hwndWinamp);
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t SkinHelper::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t SkinHelper::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int SkinHelper::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_SkinHelper))
+ *object = static_cast<ifc_skinhelper*>(this);
+ else if (IsEqualIID(interface_guid, IFC_SkinnedMenu))
+ *object = static_cast<ifc_skinnedmenu*>(this);
+ else if (IsEqualIID(interface_guid, IFC_SkinnedRating))
+ *object = static_cast<ifc_skinnedrating*>(this);
+ else if (IsEqualIID(interface_guid, IFC_SkinnedBrowser))
+ *object = static_cast<ifc_skinnedbrowser*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT SkinHelper::GetColor(UINT colorIndex, COLORREF *pColor)
+{
+ if (NULL == pColor) return E_POINTER;
+
+ if (colorIndex >= WADLG_NUM_COLORS)
+ return E_INVALIDARG;
+
+ if (FALSE != initializeColors)
+ {
+ HRESULT hr = InitializeColorData();
+ if (FAILED(hr)) return hr;
+ }
+
+ *pColor = WADlg_getColor(colorIndex);
+ return S_OK;
+}
+
+HRESULT SkinHelper::GetColorEx(UINT uObject, UINT uPart, UINT uState, COLORREF *pColor)
+{
+ if (NULL == pColor) return E_POINTER;
+
+ ENSURE_FUNCTION_LOADED(mlGetSkinColor);
+ BOOL result = mlGetSkinColor(uObject, uPart, uState, pColor);
+ return BOOL2HRESULT(result);
+}
+
+HRESULT SkinHelper::GetBrush(UINT colorIndex, HBRUSH *pBrush)
+{
+ if (NULL == pBrush) return E_POINTER;
+
+ if (FALSE != initializeColors)
+ InitializeColorData();
+
+ if (colorIndex < WADLG_NUM_COLORS)
+ {
+ *pBrush = szBrushes[colorIndex];
+ if (NULL == *pBrush)
+ {
+ COLORREF color = WADlg_getColor(colorIndex);
+ *pBrush = CreateSolidBrush(color);
+ szBrushes[colorIndex] = *pBrush;
+ }
+ return S_OK;
+ }
+ return E_INVALIDARG;
+}
+
+HFONT SkinHelper::GetFont()
+{
+ if (NULL == playlistFont)
+ playlistFont = CreateSkinFont();
+
+ return playlistFont;
+}
+
+HRESULT SkinHelper::SkinWindow(HWND hwnd, const GUID *windowGuid, UINT flagsEx, FFCALLBACK callbackFF)
+{
+ SKINWINDOWPARAM swp;
+ swp.cbSize = sizeof(SKINWINDOWPARAM);
+ swp.hwndToSkin = hwnd;
+ swp.windowGuid = *windowGuid;
+ swp.flagsEx = flagsEx;
+ swp.callbackFF = callbackFF;
+
+ BOOL result = (BOOL)SENDWAIPC(hwndWinamp, IPC_SKINWINDOW, (WPARAM)&swp);
+ return BOOL2HRESULT(result);
+}
+
+HRESULT SkinHelper::SkinControl(HWND hwnd, UINT type, UINT style)
+{
+ ENSURE_FUNCTION_LOADED(mlSkinWindowEx);
+ BOOL result = mlSkinWindowEx(hwnd, type, style);
+ return BOOL2HRESULT(result);
+}
+
+HRESULT SkinHelper::UnskinWindow(HWND hwnd)
+{
+ ENSURE_FUNCTION_LOADED(mlUnskinWindow);
+ BOOL result = mlUnskinWindow(hwnd);
+ return BOOL2HRESULT(result);
+}
+
+static INT CALLBACK SkinHelper_CustomMenuProc(INT action, HMENU hMenu, HDC hdc, LPARAM param, ULONG_PTR user)
+{
+ ifc_menucustomizer *customizer = (ifc_menucustomizer*)user;
+ if (NULL != customizer)
+ {
+ return customizer->CustomDraw(hMenu, action, hdc, param);
+ }
+ return FALSE;
+}
+
+BOOL SkinHelper::TrackPopup(HMENU hMenu, UINT fuFlags, INT x, INT y, HWND hwnd, LPTPMPARAMS lptpm, ifc_menucustomizer *customizer)
+{
+ if (ForceNoSkinnedMenu != customizer && S_OK == IsPopupEnabled())
+ {
+ BOOL result;
+ HMLIMGLST hmlil = NULL;
+ INT width = 0;
+ UINT skinStyle = SMS_USESKINFONT;
+ MENUCUSTOMIZEPROC customProc = NULL;
+ ULONG_PTR customParam = 0;
+
+ if (NULL != customizer)
+ {
+ hmlil = customizer->GetImageList();
+ skinStyle = customizer->GetSkinStyle();
+ if (FAILED(customizer->GetWidth(&width)))
+ width = 0;
+
+ customProc = SkinHelper_CustomMenuProc;
+ customParam = (ULONG_PTR)customizer;
+ }
+
+ HRESULT hr = MlTrackSkinnedPopupMenuEx(hMenu, fuFlags, x, y, hwnd, lptpm,
+ hmlil, width, skinStyle, customProc, customParam, &result);
+
+ if (SUCCEEDED(hr))
+ return result;
+ }
+
+ return TrackPopupMenuEx(hMenu, fuFlags, x, y, hwnd, lptpm);
+}
+
+HRESULT SkinHelper::IsPopupEnabled()
+{
+ ENSURE_FUNCTION_LOADED(mlIsSkinnedPopupEnabled);
+ return (FALSE != mlIsSkinnedPopupEnabled()) ? S_OK : S_FALSE;
+}
+
+HANDLE SkinHelper::InitPopupHook(HWND hwnd, ifc_menucustomizer *customizer)
+{
+ if (ForceNoSkinnedMenu != customizer && S_OK == IsPopupEnabled())
+ {
+ HMLIMGLST hmlil = NULL;
+ INT width = 0;
+ UINT skinStyle = SMS_USESKINFONT;
+ MENUCUSTOMIZEPROC customProc = NULL;
+ ULONG_PTR customParam = 0;
+
+ if (NULL != customizer)
+ {
+ hmlil = customizer->GetImageList();
+ skinStyle = customizer->GetSkinStyle();
+ if (FAILED(customizer->GetWidth(&width)))
+ width = 0;
+
+ customProc = SkinHelper_CustomMenuProc;
+ customParam = (ULONG_PTR)customizer;
+ }
+
+ HANDLE hook;
+ HRESULT hr = MlInitSkinnedPopupHook(hwnd, hmlil, width, skinStyle, customProc, customParam, &hook);
+ if (FAILED(hr))
+ hook = NULL;
+ return hook;
+ }
+
+ return NULL;
+}
+
+HRESULT SkinHelper::RemovePopupHook(HANDLE hPopupHook)
+{
+ ENSURE_FUNCTION_LOADED(mlRemoveSkinnedPopupHook);
+ mlRemoveSkinnedPopupHook(hPopupHook);
+ return S_OK;
+}
+
+HRESULT SkinHelper::MlTrackSkinnedPopupMenuEx(HMENU hmenu, UINT fuFlags, INT x, INT y, HWND hwnd, LPTPMPARAMS lptpm, HMLIMGLST hmlil, INT width, UINT skinStyle, MENUCUSTOMIZEPROC customProc, ULONG_PTR customParam, INT *resultOut)
+{
+ if (NULL != resultOut)
+ *resultOut = 0;
+
+ ENSURE_FUNCTION_LOADED(mlTrackSkinnedPopupMenuEx);
+ INT result = mlTrackSkinnedPopupMenuEx(hmenu, fuFlags, x, y, hwnd, lptpm, hmlil, width, skinStyle, customProc, customParam);
+
+ if (NULL != resultOut)
+ *resultOut = result;
+
+ return S_OK;
+}
+
+HRESULT SkinHelper::MlInitSkinnedPopupHook(HWND hwnd, HMLIMGLST hmlil, INT width, UINT skinStyle, MENUCUSTOMIZEPROC customProc, ULONG_PTR customParam, HANDLE *hookOut)
+{
+ if (NULL == hookOut) return E_POINTER;
+ *hookOut = NULL;
+ ENSURE_FUNCTION_LOADED(mlInitSkinnedPopupHook);
+
+ *hookOut = mlInitSkinnedPopupHook(hwnd, hmlil, width, skinStyle, customProc, customParam);
+ if (NULL == *hookOut)
+ return E_FAIL;
+
+ return S_OK;
+}
+
+
+HRESULT SkinHelper::RatingDraw(HDC hdc, INT maxValue, INT value, INT trackingVal, RECT *prc, UINT fStyle)
+{
+ ENSURE_FUNCTION_LOADED(mlRatingDraw);
+ BOOL result = mlRatingDraw(hdc, maxValue, value, trackingVal, NULL, 0, prc, fStyle);
+ return BOOL2HRESULT(result);
+}
+
+HRESULT SkinHelper::RatingHitTest(POINT pt, INT maxValue, RECT *prc, UINT fStyle, LONG *result)
+{
+ if (NULL == result) return E_POINTER;
+ ENSURE_FUNCTION_LOADED(mlRatingHitTest);
+ *result = mlRatingHitTest(pt, maxValue, NULL, prc, fStyle);
+ return S_OK;
+}
+
+HRESULT SkinHelper::RatingCalcMinRect(INT maxValue, RECT *prc)
+{
+ ENSURE_FUNCTION_LOADED(mlRatingCalcMinRect);
+ BOOL result = mlRatingCalcMinRect(maxValue, NULL, prc);
+ return BOOL2HRESULT(result);
+}
+
+HRESULT SkinHelper::RatingCreateMenuCustomizer(HMENU hMenu, ifc_menucustomizer **customizer)
+{
+ return RatingMenuCustomizer::CreateInstance(hMenu, this, (RatingMenuCustomizer**)customizer);
+}
+
+HRESULT SkinHelper::LoadMediaLibraryModule()
+{
+ if (S_FALSE != mlLoadResult)
+ return mlLoadResult;
+
+ WCHAR szPath[MAX_PATH*2] = {0};
+ PathCombine(szPath, (LPCWSTR)SENDWAIPC(hwndWinamp, IPC_GETPLUGINDIRECTORYW, 0), L"gen_ml.dll");
+
+ mlModule = LoadLibrary(szPath);
+ if (NULL == mlModule)
+ mlLoadResult = HRESULT_FROM_WIN32(GetLastError());
+
+ if (SUCCEEDED(mlLoadResult))
+ {
+ mlSkinWindowEx = (MLSKINWINDOWEX)GetProcAddress(mlModule, "MlSkinWindowEx");
+ mlUnskinWindow = (MLUNSKINWINDOW)GetProcAddress(mlModule, "MlUnskinWindow");
+ mlTrackSkinnedPopupMenuEx = (MLTRACKSKINNEDPOPUPMENUEX)GetProcAddress(mlModule, "MlTrackSkinnedPopupMenuEx");
+ mlIsSkinnedPopupEnabled = (MLISSKINNEDPOPUPENABLED)GetProcAddress(mlModule, "MlIsSkinnedPopupEnabled");
+ mlGetSkinColor = (MLGETSKINCOLOR)GetProcAddress(mlModule, "MlGetSkinColor");
+ mlResetSkinColor = (MLRESETSKINCOLOR)GetProcAddress(mlModule, "MlResetSkinColor");
+ mlInitSkinnedPopupHook = (MLINITSKINNEDPOPUPHOOK)GetProcAddress(mlModule, "MlInitSkinnedPopupHook");
+ mlRemoveSkinnedPopupHook = (MLREMOVESKINNEDPOPUPHOOK)GetProcAddress(mlModule, "MlRemoveSkinnedPopupHook");
+ mlRatingDraw = (MLRATINGDRAW)GetProcAddress(mlModule, "MlRatingDraw");
+ mlRatingHitTest = (MLRATINGHITTEST)GetProcAddress(mlModule, "MlRatingHitTest");
+ mlRatingCalcMinRect = (MLRATINGCALCMINRECT)GetProcAddress(mlModule, "MlRatingCalcMinRect");
+ }
+ return mlLoadResult;
+}
+
+
+HRESULT SkinHelper::InitializeColorData()
+{
+ if (NULL == hwndWinamp || !IsWindow(hwndWinamp))
+ return E_UNEXPECTED;
+
+ for (int i = 0; i < ARRAYSIZE(szBrushes); i++)
+ {
+ if (NULL != szBrushes[i])
+ {
+ DeleteObject(szBrushes[i]);
+ szBrushes[i] = NULL;
+ }
+ }
+
+ cchHostCss = 0;
+
+ WADlg_init(hwndWinamp);
+ initializeColors = FALSE;
+
+ return S_OK;
+}
+
+HFONT SkinHelper::CreateSkinFont()
+{
+ if (NULL == hwndWinamp || !IsWindow(hwndWinamp))
+ return NULL;
+
+ LOGFONT lf =
+ {
+ 0, /* lfHeight */
+ 0, /* lfWidth */
+ 0, /* lfEscapement */
+ 0, /* lfOrientation */
+ FW_NORMAL, /* lfWeight */
+ FALSE, /* lfItalic */
+ FALSE, /* lfUnderline */
+ FALSE, /* lfStrikeOut */
+ DEFAULT_CHARSET, /* lfCharSet */
+ OUT_DEFAULT_PRECIS, /* lfOutPrecision */
+ CLIP_DEFAULT_PRECIS, /* lfClipPrecision */
+ DEFAULT_QUALITY, /* lfQuality */
+ DEFAULT_PITCH | FF_DONTCARE, /* lfPitchAndFamily */
+ TEXT(""), /* lfFaceName */
+ };
+
+
+ lf.lfHeight = -(INT)SENDWAIPC(hwndWinamp, IPC_GET_GENSKINBITMAP, 3);
+ lf.lfCharSet = (BYTE)SENDWAIPC(hwndWinamp, IPC_GET_GENSKINBITMAP, 2);
+
+ LPCSTR faceNameAnsi = (LPCSTR)SENDWAIPC(hwndWinamp,IPC_GET_GENSKINBITMAP, 1);
+ if (NULL != faceNameAnsi/* && '\0' != faceNameAnsi*/)
+ {
+ INT count = MultiByteToWideChar(CP_ACP, 0, faceNameAnsi, -1, lf.lfFaceName, ARRAYSIZE(lf.lfFaceName));
+ if (count > 0) count--;
+ lf.lfFaceName[count] = L'\0';
+ }
+ return CreateFontIndirect(&lf);
+}
+
+void SkinHelper::ResetColorCache()
+{
+ initializeColors = TRUE;
+ if (NULL != mlResetSkinColor)
+ mlResetSkinColor();
+}
+
+void SkinHelper::ResetFontCache()
+{
+ if (NULL != playlistFont)
+ {
+ DeleteObject(playlistFont);
+ playlistFont = NULL;
+ }
+}
+
+
+#define RGBTOHTML(__rgbColor) (((__rgbColor)>>16) & 0xFF | ((__rgbColor)&0xFF00) | (((__rgbColor)<<16)&0xFF0000))
+
+HRESULT SkinHelper::Browser_GetHostCss(wchar_t **ppchHostCss)
+{
+ if (NULL == ppchHostCss) return E_POINTER;
+ *ppchHostCss = NULL;
+
+ if (FALSE != initializeColors)
+ {
+ HRESULT hr = InitializeColorData();
+ if (FAILED(hr)) return hr;
+ }
+
+ if (0 == cchHostCss)
+ {
+ size_t remaining;
+ COLORREF szColors[] =
+ {
+ Browser_GetBackColor(),
+ Browser_GetTextColor(),
+ (COLORREF)WADlg_getColor(WADLG_LISTHEADER_BGCOLOR),
+ (COLORREF)WADlg_getColor(WADLG_SCROLLBAR_BGCOLOR),
+ (COLORREF)WADlg_getColor(WADLG_LISTHEADER_FRAME_TOPCOLOR),
+ (COLORREF)WADlg_getColor(WADLG_LISTHEADER_BGCOLOR),
+ (COLORREF)WADlg_getColor(WADLG_LISTHEADER_FRAME_BOTTOMCOLOR),
+ (COLORREF)WADlg_getColor(WADLG_LISTHEADER_BGCOLOR),
+ (COLORREF)WADlg_getColor(WADLG_BUTTONFG),
+ Browser_GetLinkColor(),
+ Browser_GetActiveLinkColor(),
+ Browser_GetVisitedLinkColor(),
+ Browser_GetHoveredLinkColor(),
+ };
+
+ for (INT i = 0; i < ARRAYSIZE(szColors); i++)
+ {
+ COLORREF c = szColors[i];
+ szColors[i] = RGBTOHTML(c);
+ }
+
+ HRESULT hr = StringCchPrintfEx(szHostCss, ARRAYSIZE(szHostCss), NULL, &remaining,
+ STRSAFE_IGNORE_NULLS | STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION,
+ L"body { "
+ L"background-color: #%06X;"
+ L"color: #%06X;"
+ L"scrollbar-face-color: #%06X;"
+ L"scrollbar-track-color: #%06X;"
+ L"scrollbar-3dlight-color: #%06X;"
+ L"scrollbar-shadow-color: #%06X;"
+ L"scrollbar-darkshadow-color: #%06X;"
+ L"scrollbar-highlight-color: #%06X;"
+ L"scrollbar-arrow-color: #%06X;"
+ L"}"
+ L"a:link {color: #%06X;}"
+ L"a:active {color: #%06X;}"
+ L"a:visited {color: #%06X;}"
+ L"a:hover {color: #%06X;}",
+ szColors[0], szColors[1], szColors[2], szColors[3], szColors[4], szColors[5], szColors[6],
+ szColors[7], szColors[8], szColors[9], szColors[10], szColors[11], szColors[12]
+ );
+ if (FAILED(hr))
+ return E_UNEXPECTED;
+
+ cchHostCss = ARRAYSIZE(szHostCss) - remaining;
+
+ }
+
+ LPWSTR buffer = (LPWSTR)CoTaskMemAlloc(sizeof(WCHAR) * (cchHostCss + 1));
+ if (NULL == buffer) return E_OUTOFMEMORY;
+
+ if (FAILED(StringCchCopy(buffer, cchHostCss + 1, szHostCss)))
+ return E_UNEXPECTED;
+
+ *ppchHostCss = buffer;
+ return S_OK;
+}
+
+COLORREF SkinHelper::Browser_GetBackColor(void)
+{
+ COLORREF rgb;
+ if (FAILED(GetColorEx(MLSO_OMBROWSER, BP_BACKGROUND, 0, &rgb)))
+ rgb = GetSysColor(COLOR_WINDOW);
+ return rgb;
+}
+
+COLORREF SkinHelper::Browser_GetTextColor(void)
+{
+ COLORREF rgb;
+ if (FAILED(GetColorEx(MLSO_OMBROWSER, BP_TEXT, BTS_NORMAL, &rgb)))
+ rgb = GetSysColor(COLOR_WINDOWTEXT);
+ return rgb;
+}
+
+COLORREF SkinHelper::Browser_GetLinkColor(void)
+{
+ COLORREF rgb;
+ if (FAILED(GetColorEx(MLSO_OMBROWSER, BP_LINK, BLS_NORMAL, &rgb)))
+ rgb = GetSysColor(COLOR_HOTLIGHT);
+ return rgb;
+}
+
+COLORREF SkinHelper::Browser_GetActiveLinkColor(void)
+{
+ COLORREF rgb;
+ if (FAILED(GetColorEx(MLSO_OMBROWSER, BP_LINK, BLS_ACTIVE, &rgb)))
+ rgb = GetSysColor(COLOR_HOTLIGHT);
+ return rgb;
+}
+
+COLORREF SkinHelper::Browser_GetVisitedLinkColor(void)
+{
+ COLORREF rgb;
+ if (FAILED(GetColorEx(MLSO_OMBROWSER, BP_LINK, BLS_VISITED, &rgb)))
+ rgb = GetSysColor(COLOR_WINDOWTEXT);
+ return rgb;
+}
+
+COLORREF SkinHelper::Browser_GetHoveredLinkColor(void)
+{
+ COLORREF rgb;
+ if (FAILED(GetColorEx(MLSO_OMBROWSER, BP_LINK, BLS_HOVER, &rgb)))
+ rgb = GetSysColor(COLOR_HOTLIGHT);
+ return rgb;
+}
+
+#define CBCLASS SkinHelper
+START_MULTIPATCH;
+ START_PATCH(MPIID_SKINHELPER)
+ M_CB(MPIID_SKINHELPER, ifc_skinhelper, ADDREF, AddRef);
+ M_CB(MPIID_SKINHELPER, ifc_skinhelper, RELEASE, Release);
+ M_CB(MPIID_SKINHELPER, ifc_skinhelper, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_SKINHELPER, ifc_skinhelper, API_GETCOLOR, GetColor);
+ M_CB(MPIID_SKINHELPER, ifc_skinhelper, API_GETCOLOREX, GetColorEx);
+ M_CB(MPIID_SKINHELPER, ifc_skinhelper, API_GETBRUSH, GetBrush);
+ M_CB(MPIID_SKINHELPER, ifc_skinhelper, API_GETFONT, GetFont);
+ M_CB(MPIID_SKINHELPER, ifc_skinhelper, API_SKINWINDOW, SkinWindow);
+ M_CB(MPIID_SKINHELPER, ifc_skinhelper, API_SKINCONTROL, SkinControl);
+ M_CB(MPIID_SKINHELPER, ifc_skinhelper, API_UNSKINWINDOW, UnskinWindow);
+ NEXT_PATCH(MPIID_SKINNEDMENU)
+ M_CB(MPIID_SKINNEDMENU, ifc_skinnedmenu, ADDREF, AddRef);
+ M_CB(MPIID_SKINNEDMENU, ifc_skinnedmenu, RELEASE, Release);
+ M_CB(MPIID_SKINNEDMENU, ifc_skinnedmenu, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_SKINNEDMENU, ifc_skinnedmenu, API_TRACKPOPUP, TrackPopup);
+ M_CB(MPIID_SKINNEDMENU, ifc_skinnedmenu, API_ISENABLED, IsPopupEnabled);
+ M_CB(MPIID_SKINNEDMENU, ifc_skinnedmenu, API_INITPOPUPHOOK, InitPopupHook);
+ M_CB(MPIID_SKINNEDMENU, ifc_skinnedmenu, API_REMOVEPOPUPHOOK, RemovePopupHook);
+ NEXT_PATCH(MPIID_SKINNEDRATING)
+ M_CB(MPIID_SKINNEDRATING, ifc_skinnedrating, ADDREF, AddRef);
+ M_CB(MPIID_SKINNEDRATING, ifc_skinnedrating, RELEASE, Release);
+ M_CB(MPIID_SKINNEDRATING, ifc_skinnedrating, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_SKINNEDRATING, ifc_skinnedrating, API_DRAW, RatingDraw);
+ M_CB(MPIID_SKINNEDRATING, ifc_skinnedrating, API_HITTEST, RatingHitTest);
+ M_CB(MPIID_SKINNEDRATING, ifc_skinnedrating, API_CALCMINRECT, RatingCalcMinRect);
+ M_CB(MPIID_SKINNEDRATING, ifc_skinnedrating, API_CREATEMENUCUSTOMIZER, RatingCreateMenuCustomizer);
+ NEXT_PATCH(MPIID_SKINNEDBROWSER)
+ M_CB(MPIID_SKINNEDBROWSER, ifc_skinnedbrowser, ADDREF, AddRef);
+ M_CB(MPIID_SKINNEDBROWSER, ifc_skinnedbrowser, RELEASE, Release);
+ M_CB(MPIID_SKINNEDBROWSER, ifc_skinnedbrowser, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_SKINNEDBROWSER, ifc_skinnedbrowser, API_GETHOSTCSS, Browser_GetHostCss);
+ M_CB(MPIID_SKINNEDBROWSER, ifc_skinnedbrowser, API_GETBACKCOLOR, Browser_GetBackColor);
+ M_CB(MPIID_SKINNEDBROWSER, ifc_skinnedbrowser, API_GETTEXTCOLOR, Browser_GetTextColor);
+ M_CB(MPIID_SKINNEDBROWSER, ifc_skinnedbrowser, API_GETLINKCOLOR, Browser_GetLinkColor);
+ M_CB(MPIID_SKINNEDBROWSER, ifc_skinnedbrowser, API_GETACTIVELINKCOLOR, Browser_GetActiveLinkColor);
+ M_CB(MPIID_SKINNEDBROWSER, ifc_skinnedbrowser, API_GETVISITEDLINKCOLOR, Browser_GetVisitedLinkColor);
+ M_CB(MPIID_SKINNEDBROWSER, ifc_skinnedbrowser, API_GETHOVEREDLINKCOLOR, Browser_GetHoveredLinkColor);
+ END_PATCH
+END_MULTIPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/skinHelper.h b/Src/omBrowser/skinHelper.h
new file mode 100644
index 00000000..1b7dddfd
--- /dev/null
+++ b/Src/omBrowser/skinHelper.h
@@ -0,0 +1,133 @@
+#ifndef NULLSOFT_WINAMP_SKIN_HELPER_HEADER
+#define NULLSOFT_WINAMP_SKIN_HELPER_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+#include "../Plugins/General/gen_ml/ml_ipc_0313.h"
+#include "../Plugins/General/gen_ml/colors.h"
+#include "../winamp/wa_ipc.h"
+#include "../winamp/wa_dlg.h"
+
+#include "./ifc_skinhelper.h"
+#include "./ifc_skinnedmenu.h"
+#include "./ifc_skinnedrating.h"
+#include "./ifc_skinnedbrowser.h"
+
+#include <bfc/multipatch.h>
+
+#define MPIID_SKINHELPER 10
+#define MPIID_SKINNEDMENU 20
+#define MPIID_SKINNEDRATING 30
+#define MPIID_SKINNEDBROWSER 40
+
+class SkinHelper : public MultiPatch<MPIID_SKINHELPER, ifc_skinhelper>,
+ public MultiPatch<MPIID_SKINNEDMENU, ifc_skinnedmenu>,
+ public MultiPatch<MPIID_SKINNEDRATING, ifc_skinnedrating>,
+ public MultiPatch<MPIID_SKINNEDBROWSER, ifc_skinnedbrowser>
+{
+
+protected:
+ SkinHelper(HWND hwndWa);
+ ~SkinHelper();
+
+public:
+ static HRESULT CreateInstance(HWND hwndWinamp, SkinHelper **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_skinhelper */
+ HRESULT GetColor(UINT colorIndex, COLORREF *pColor);
+ HRESULT GetColorEx(UINT uObject, UINT uPart, UINT uState, COLORREF *pColor);
+ HRESULT GetBrush(UINT colorIndex, HBRUSH *pBrush);
+ HFONT GetFont(void);
+ HRESULT SkinWindow(HWND hwnd, const GUID *windowGuid, UINT flagsEx, FFCALLBACK callbackFF);
+ HRESULT SkinControl(HWND hwnd, UINT type, UINT style);
+ HRESULT UnskinWindow(HWND hwnd);
+
+ /* ifc_skinnedmenu */
+ BOOL TrackPopup(HMENU hMenu, UINT fuFlags, INT x, INT y, HWND hwnd, LPTPMPARAMS lptpm, ifc_menucustomizer *customizer);
+ HRESULT IsPopupEnabled(void);
+ HANDLE InitPopupHook(HWND hwnd, ifc_menucustomizer *customizer);
+ HRESULT RemovePopupHook(HANDLE popupHook);
+
+ /* ifc_skinnedrating */
+ HRESULT RatingDraw(HDC hdc, INT maxValue, INT value, INT trackingVal, RECT *prc, UINT fStyle);
+ HRESULT RatingHitTest(POINT pt, INT maxValue, RECT *prc, UINT fStyle, LONG *result);
+ HRESULT RatingCalcMinRect(INT maxValue, RECT *prc);
+ HRESULT RatingCreateMenuCustomizer(HMENU hMenu, ifc_menucustomizer **customizer);
+
+ /* ifc_skinnedbrowser */
+ HRESULT Browser_GetHostCss(wchar_t **ppchHostCss);
+ COLORREF Browser_GetBackColor(void);
+ COLORREF Browser_GetTextColor(void);
+ COLORREF Browser_GetLinkColor(void);
+ COLORREF Browser_GetActiveLinkColor(void);
+ COLORREF Browser_GetVisitedLinkColor(void);
+ COLORREF Browser_GetHoveredLinkColor(void);
+
+public:
+ HFONT CreateSkinFont(void);
+ void ResetColorCache(void);
+ void ResetFontCache(void);
+
+protected:
+ HRESULT LoadMediaLibraryModule(void);
+ HRESULT InitializeColorData(void);
+ HRESULT MlTrackSkinnedPopupMenuEx(HMENU hmenu, UINT fuFlags, INT x, INT y, HWND hwnd, LPTPMPARAMS lptpm, HMLIMGLST hmlil, INT width, UINT skinStyle, MENUCUSTOMIZEPROC customProc, ULONG_PTR customParam, INT *resultOut);
+ HRESULT MlInitSkinnedPopupHook(HWND hwnd, HMLIMGLST hmlil, INT width, UINT skinStyle, MENUCUSTOMIZEPROC customProc, ULONG_PTR customParam, HANDLE *hookOut);
+
+protected:
+ RECVS_MULTIPATCH;
+
+protected:
+ typedef BOOL (__cdecl *MLSKINWINDOWEX)(HWND /*hwnd*/, INT /*type*/, UINT /*style*/);
+ typedef BOOL (__cdecl *MLUNSKINWINDOW)(HWND /*hwnd*/);
+ typedef BOOL (__cdecl *MLGETSKINCOLOR)(UINT /*uObject*/, UINT /*uPart*/, UINT /*uState*/, COLORREF* /*pColor*/);
+ typedef void (__cdecl *MLRESETSKINCOLOR)(void);
+ typedef BOOL (__cdecl *MLTRACKSKINNEDPOPUPMENUEX)(HMENU /*hmenu*/, UINT /*fuFlags*/, INT /*x*/, INT /*y*/, HWND /*hwnd*/,
+ LPTPMPARAMS /*lptpm*/, HMLIMGLST /*hmlil*/, INT /*width*/, UINT /*skinStyle*/,
+ MENUCUSTOMIZEPROC /*customProc*/, ULONG_PTR /*customParam*/);
+ typedef BOOL (__cdecl *MLISSKINNEDPOPUPENABLED)(void);
+ typedef HANDLE (__cdecl *MLINITSKINNEDPOPUPHOOK)(HWND /*hwnd*/, HMLIMGLST /*hmlil*/, INT /*width*/, UINT /*skinStyle*/,
+ MENUCUSTOMIZEPROC /*customProc*/, ULONG_PTR /*customParam*/);
+ typedef void (__cdecl *MLREMOVESKINNEDPOPUPHOOK)(HANDLE /*hPopupHook*/);
+
+ typedef BOOL (__cdecl *MLRATINGDRAW)(HDC /*hdc*/, INT /*maxValue*/, INT /*value*/, INT /*trackingVal*/, HMLIMGLST /*hmlil*/, INT /*index*/, RECT* /*prc*/, UINT /*fStyle*/);
+ typedef LONG (__cdecl *MLRATINGHITTEST)(POINT /*pt*/, INT /*maxValue*/, HMLIMGLST /*hmlil*/, RECT* /*prc*/, UINT /*fStyle*/);
+ typedef BOOL (__cdecl *MLRATINGCALCMINRECT)(INT /*maxValue*/, HMLIMGLST /*hmlil*/, RECT* /*prc*/);
+
+
+protected:
+ ULONG ref;
+ HWND hwndWinamp;
+ HMODULE mlModule;
+ HRESULT mlLoadResult;
+ HFONT playlistFont;
+ HBRUSH szBrushes[WADLG_NUM_COLORS];
+ BOOL initializeColors;
+ size_t cchHostCss;
+
+ MLSKINWINDOWEX mlSkinWindowEx;
+ MLUNSKINWINDOW mlUnskinWindow;
+ MLTRACKSKINNEDPOPUPMENUEX mlTrackSkinnedPopupMenuEx;
+ MLISSKINNEDPOPUPENABLED mlIsSkinnedPopupEnabled;
+ MLINITSKINNEDPOPUPHOOK mlInitSkinnedPopupHook;
+ MLREMOVESKINNEDPOPUPHOOK mlRemoveSkinnedPopupHook;
+ MLGETSKINCOLOR mlGetSkinColor;
+ MLRESETSKINCOLOR mlResetSkinColor;
+ MLRATINGDRAW mlRatingDraw;
+ MLRATINGHITTEST mlRatingHitTest;
+ MLRATINGCALCMINRECT mlRatingCalcMinRect;
+
+ WCHAR szHostCss[396];
+};
+
+
+#endif // NULLSOFT_WINAMP_SKIN_HELPER_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/statusbar.cpp b/Src/omBrowser/statusbar.cpp
new file mode 100644
index 00000000..97818d3a
--- /dev/null
+++ b/Src/omBrowser/statusbar.cpp
@@ -0,0 +1,931 @@
+#include "main.h"
+#include "./statusbar.h"
+#include "./graphics.h"
+#include "./browserHost.h"
+#include "../winamp/wa_dlg.h"
+#include "../Plugins/General/gen_ml/ml_ipc_0313.h"
+
+#include "./ifc_skinhelper.h"
+#include "./ifc_wasabihelper.h"
+
+#include <windows.h>
+#include <shlwapi.h>
+#include <strsafe.h>
+
+#define TEXTMARGIN_LEFT 3
+#define TEXTMARGIN_TOP 1
+#define TEXTMARGIN_RIGHT 3
+#define TEXTMARGIN_BOTTOM 1
+
+
+#define SBT_INFLATE_ID 31
+#define SBT_INFLATE_DELAY 50
+#define SBT_INFLATE_INTERVAL 20
+
+#define SBT_MOUSEROLL_ID 32
+#define SBT_MOUSEROLL_DELAY 50
+#define SBT_MOUSEROLL_INTERVAL 20
+
+#define SBF_MOUSEROLL 0x00000001
+#define SBF_CACHEDFONT 0x00000002
+
+typedef struct __STATUSBAR
+{
+ UINT flags;
+ RECT parentRect;
+ SIZE textSize;
+
+ LPWSTR pszText;
+ INT cchText;
+ INT cchTextMax;
+
+ HFONT textFont;
+ COLORREF rgbBk;
+ COLORREF rgbText;
+ HBRUSH brushBk;
+
+ LONG desiredCX;
+ LONG mouseY;
+ LONG desiredY;
+ HRGN windowRegion;
+ HWND hBrowser;
+
+ DWORD inflateTime;
+} STATUSBAR;
+
+typedef struct __STATUSBARMOUSEHOOK
+{
+ HHOOK hHook;
+ HWND hwnd;
+} STATUSBARMOUSEHOOK;
+
+static size_t tlsIndex = -1;
+
+
+#define GetStatusbar(__hwnd) ((STATUSBAR*)(LONG_PTR)(LONGX86)GetWindowLongPtr((__hwnd), 0))
+static LRESULT CALLBACK Statusbar_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static void CALLBACK Statusbar_InflateTimer(HWND hwnd, UINT uMsg, UINT_PTR eventId, DWORD timerId);
+static void CALLBACK Statusbar_MouseRollTimer(HWND hwnd, UINT uMsg, UINT_PTR eventId, DWORD timerId);
+static LRESULT CALLBACK Statusbar_MouseHook(INT code, WPARAM wParam, LPARAM lParam);
+
+BOOL Statusbar_RegisterClass(HINSTANCE hInstance)
+{
+ WNDCLASS wc;
+ ATOM klassAtom;
+ ifc_wasabihelper *wasabi;
+
+ if (GetClassInfo(hInstance, NWC_ONLINEMEDIASTATUSBAR, &wc))
+ return TRUE;
+
+ ZeroMemory(&wc, sizeof(WNDCLASS));
+
+ wc.hInstance = hInstance;
+ wc.lpszClassName = NWC_ONLINEMEDIASTATUSBAR;
+ wc.lpfnWndProc = Statusbar_WindowProc;
+ wc.style = CS_PARENTDC | CS_SAVEBITS;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = NULL;
+ wc.cbWndExtra = sizeof(STATUSBAR*);
+
+ klassAtom = RegisterClassW(&wc);
+ if (0 == klassAtom)
+ return FALSE;
+
+ if (SUCCEEDED(Plugin_GetWasabiHelper(&wasabi)))
+ {
+ api_application *application;
+ if (SUCCEEDED(wasabi->GetApplicationApi(&application)))
+ {
+ application->DirectMouseWheel_RegisterSkipClass(klassAtom);
+ application->Release();
+ }
+ wasabi->Release();
+ }
+ return TRUE;
+}
+
+static BOOL Statusbar_GetTextSize(HWND hwnd, HFONT textFont, LPCWSTR pszText, INT cchText, SIZE *textSize)
+{
+ HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
+ if (NULL == hdc) return FALSE;
+
+ HFONT originalFont = (HFONT)SelectObject(hdc, textFont);
+
+ BOOL result;
+ if (0 == cchText)
+ {
+ TEXTMETRIC tm;
+ result = GetTextMetrics(hdc, &tm);
+ if (FALSE != result)
+ {
+ textSize->cx = 0;
+ textSize->cy = tm.tmHeight;
+ }
+ }
+ else
+ {
+ result = GetTextExtentPoint32(hdc, pszText, cchText, textSize);
+ }
+
+ SelectObject(hdc, originalFont);
+ ReleaseDC(hwnd, hdc);
+
+ return result;
+}
+
+
+static BOOL Statusbar_SetWindowPos(HWND hwnd, HWND hwndInsertAfter, INT x, INT y, INT cx, INT cy, UINT flags)
+{
+ STATUSBAR *statusbar = GetStatusbar(hwnd);
+ if (NULL != statusbar)
+ {
+ INT k = cy/4;
+ if (k > cx) k = 0;
+
+ POINT szPoint[5] = {0};
+ //szPoint[0].x = 0;
+ //szPoint[0].y = 0;
+ szPoint[1].x = cx - k;
+ //szPoint[1].y = 0;
+ szPoint[2].x = cx;
+ szPoint[2].y = k;
+ szPoint[3].x = cx;
+ szPoint[3].y = cy;
+ //szPoint[4].x = 0;
+ szPoint[4].y = cy;
+
+ HRGN rgn = CreatePolygonRgn(szPoint, ARRAYSIZE(szPoint), WINDING);
+ if (0 != SetWindowRgn(hwnd, rgn, TRUE))
+ {
+ if (NULL != statusbar->windowRegion)
+ DeleteObject(statusbar->windowRegion);
+ statusbar->windowRegion = rgn;
+ }
+ else
+ {
+ if (NULL != rgn)
+ DeleteObject(rgn);
+ }
+ }
+
+ if (0 == SetWindowPos(hwnd, hwndInsertAfter, x, y, cx, cy, flags))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static void Statusbar_Inflate(HWND hwnd)
+{
+ STATUSBAR *statusbar = GetStatusbar(hwnd);
+ if (NULL == statusbar) return;
+
+ DWORD currentTime = GetTickCount();
+ DWORD kMult = (currentTime - statusbar->inflateTime) / SBT_INFLATE_INTERVAL;
+ if (kMult < 4) kMult = 1;
+
+ statusbar->inflateTime = currentTime;
+
+ RECT windowRect;
+ if (!GetWindowRect(hwnd, &windowRect))
+ return;
+
+ DWORD windowStyle = GetWindowStyle(hwnd);
+
+ LONG currentWidth = windowRect.right - windowRect.left;
+ LONG targetCX = statusbar->desiredCX;
+
+ if (0 == (SBS_ACTIVE & windowStyle) || targetCX < 16)
+ targetCX = 0;
+
+ if (currentWidth == targetCX)
+ return;
+
+ LONG width = currentWidth;
+ LONG height = windowRect.bottom - windowRect.top;
+ LONG step;
+
+ while(kMult-- && width != targetCX)
+ {
+ if (width > targetCX)
+ {
+ step = (width - targetCX) / 3;
+ if (step < 6) step = 6;
+
+ width -= step;
+ if (width < targetCX) width = targetCX;
+
+ }
+ else
+ {
+ step = (targetCX - width)*2 / 3;
+ if (step < 48) step = 48;
+
+ width += step;
+ if (width > targetCX) width = targetCX;
+ }
+ }
+
+ Statusbar_SetWindowPos(hwnd, HWND_TOP, 0, 0, width, height,
+ SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE);
+
+
+ if (width < (windowRect.right - windowRect.left))
+ {
+ if (NULL != statusbar->hBrowser)
+ {
+ RECT invalidRect;
+ SetRect(&invalidRect, windowRect.left + width - 4, windowRect.top, windowRect.right, windowRect.bottom);
+ MapWindowPoints(HWND_DESKTOP, statusbar->hBrowser, (POINT*)&invalidRect, 2);
+ RedrawWindow(statusbar->hBrowser, &invalidRect, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
+ }
+ }
+ else
+ {
+ RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASENOW | RDW_FRAME);
+ }
+
+ if (0 == width && 0 == (SBS_ACTIVE & windowStyle))
+ {
+ ShowWindow(hwnd, SW_HIDE);
+ }
+ else
+ {
+ if (width != targetCX)
+ {
+ SetTimer(hwnd, SBT_INFLATE_ID, SBT_INFLATE_INTERVAL, Statusbar_InflateTimer);
+ }
+ }
+}
+
+static void Statusbar_UpdateLayout(HWND hwnd, BOOL fForce)
+{
+ DWORD windowStyle = GetWindowStyle(hwnd);
+ if (0 == (WS_VISIBLE & windowStyle) && FALSE == fForce)
+ {
+ if (0 == (SBS_UPDATELAYOUT & windowStyle))
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle | SBS_UPDATELAYOUT);
+ return;
+ }
+
+ if (0 != (SBS_UPDATELAYOUT & windowStyle))
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle & ~SBS_UPDATELAYOUT);
+
+ STATUSBAR *statusbar = GetStatusbar(hwnd);
+ if (NULL == statusbar) return;
+
+ if (!Statusbar_GetTextSize(hwnd, statusbar->textFont, statusbar->pszText, statusbar->cchText, &statusbar->textSize))
+ ZeroMemory(&statusbar->textSize, sizeof(SIZE));
+
+ RECT windowRect;
+ SetRect(&windowRect,
+ statusbar->parentRect.left,
+ statusbar->parentRect.bottom - statusbar->textSize.cy + statusbar->mouseY,
+ statusbar->parentRect.left + statusbar->textSize.cx,
+ statusbar->parentRect.bottom + statusbar->mouseY);
+
+ if (0 != statusbar->textSize.cy)
+ windowRect.top -= (TEXTMARGIN_TOP + TEXTMARGIN_BOTTOM);
+ if (0 != statusbar->textSize.cx)
+ windowRect.right += (TEXTMARGIN_LEFT + TEXTMARGIN_RIGHT);
+
+ if (windowRect.right > statusbar->parentRect.right - 2)
+ windowRect.right = statusbar->parentRect.right - 2;
+
+ if ((windowRect.right - windowRect.left) < 20)
+ windowRect.right = windowRect.left;
+
+ if (windowRect.top < statusbar->parentRect.top + 20)
+ windowRect.top = statusbar->parentRect.bottom;
+
+ RECT previousRect;
+ if (!GetWindowRect(hwnd, &previousRect))
+ SetRectEmpty(&previousRect);
+
+ if (FALSE == EqualRect(&previousRect, &windowRect))
+ {
+ LONG width = windowRect.right - windowRect.left;
+ LONG height = windowRect.bottom - windowRect.top;
+ LONG prevWidth = previousRect.right - previousRect.left;
+ LONG prevHeight = previousRect.bottom - previousRect.top;
+
+ LONG widthAdjust = 0;
+ if (statusbar->desiredCX != prevWidth)
+ {
+ widthAdjust = width - prevWidth;
+ }
+
+ KillTimer(hwnd, SBT_INFLATE_ID);
+ statusbar->desiredCX = width;
+ statusbar->inflateTime = GetTickCount();
+
+ HWND hParent = GetParent(hwnd);
+ MapWindowPoints(HWND_DESKTOP, hParent, (POINT*)&previousRect, 2);
+ if (windowRect.left != previousRect.left || windowRect.top != previousRect.top || height != prevHeight || 0 != widthAdjust)
+ {
+ Statusbar_SetWindowPos(hwnd, HWND_TOP, windowRect.left, windowRect.top, prevWidth + widthAdjust, height,
+ SWP_NOACTIVATE | SWP_NOOWNERZORDER);
+
+ if (widthAdjust < 0 && NULL != statusbar->hBrowser)
+ {
+ RECT invalidRect;
+ SetRect(&invalidRect, previousRect.left + prevWidth + widthAdjust - 4, previousRect.top, previousRect.left + prevWidth, previousRect.bottom);
+ MapWindowPoints(HWND_DESKTOP, statusbar->hBrowser, (POINT*)&invalidRect, 2);
+ RedrawWindow(statusbar->hBrowser, &invalidRect, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
+ }
+ else if (0 != widthAdjust)
+ {
+ RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASENOW | RDW_FRAME);
+ }
+ }
+
+ if (width > prevWidth)
+ {
+ Statusbar_Inflate(hwnd);
+ }
+ else
+ {
+ SetTimer(hwnd, SBT_INFLATE_ID, SBT_INFLATE_DELAY, Statusbar_InflateTimer);
+ //Statusbar_Inflate(hwnd);
+ }
+ }
+ else
+ {
+ InvalidateRect(hwnd, NULL, FALSE);
+ }
+}
+
+
+
+static BOOL Statusbar_InstallMouseHook(HWND hwnd)
+{
+ if (TLS_OUT_OF_INDEXES == tlsIndex)
+ {
+ tlsIndex = Plugin_TlsAlloc();
+ if (TLS_OUT_OF_INDEXES == tlsIndex)
+ return FALSE;
+ }
+
+ STATUSBARMOUSEHOOK *hook = (STATUSBARMOUSEHOOK*)Plugin_TlsGetValue(tlsIndex);
+ if (NULL != hook) return FALSE;
+
+ hook = (STATUSBARMOUSEHOOK*)calloc(1, sizeof(STATUSBARMOUSEHOOK));
+ if (NULL == hook) return FALSE;
+
+ hook->hwnd = hwnd;
+ hook->hHook = SetWindowsHookEx(WH_MOUSE, Statusbar_MouseHook, NULL, GetCurrentThreadId());
+ if (NULL == hook->hHook)
+ {
+ free(hook);
+ return FALSE;
+ }
+
+ Plugin_TlsSetValue(tlsIndex, hook);
+ return TRUE;
+}
+
+static void Statusbar_RemoveMouseHook()
+{
+ if (TLS_OUT_OF_INDEXES == tlsIndex) return;
+
+ STATUSBARMOUSEHOOK *hook = (STATUSBARMOUSEHOOK*)Plugin_TlsGetValue(tlsIndex);
+ if (NULL == hook) return;
+
+ Plugin_TlsSetValue(tlsIndex, NULL);
+
+ if (NULL != hook->hHook)
+ UnhookWindowsHookEx(hook->hHook);
+ free(hook);
+}
+
+static void CALLBACK Statusbar_InstallMouseHookApc(ULONG_PTR param)
+{
+ Statusbar_InstallMouseHook((HWND)param);
+}
+
+static void CALLBACK Statusbar_RemoveMouseHookApc(ULONG_PTR param)
+{
+ Statusbar_RemoveMouseHook();
+}
+static void Statusbar_MouseRoll(HWND hwnd)
+{
+ STATUSBAR *psb = GetStatusbar(hwnd);
+ if (NULL == psb || 0 == (SBF_MOUSEROLL & psb->flags)) return;
+
+ if (psb->desiredY == psb->mouseY)
+ {
+ psb->flags &= ~SBF_MOUSEROLL;
+ return;
+ }
+
+ RECT windowRect;
+ if (!GetWindowRect(hwnd, &windowRect))
+ return;
+
+ windowRect.top -= psb->mouseY;
+
+ if (psb->mouseY > psb->desiredY)
+ {
+ psb->mouseY -= 4;
+ if (psb->mouseY < psb->desiredY) psb->mouseY = psb->desiredY;
+ }
+ else
+ {
+ psb->mouseY += 4;
+ if (psb->mouseY > psb->desiredY) psb->mouseY = psb->desiredY;
+ }
+
+ windowRect.top += psb->mouseY;
+ HWND hParent = GetParent(hwnd);
+ if (NULL != hParent)
+ {
+ MapWindowPoints(HWND_DESKTOP, hParent, (POINT*)&windowRect, 1);
+ SetWindowPos(hwnd, HWND_TOP, windowRect.left, windowRect.top, 0, 0,
+ SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER | SWP_ASYNCWINDOWPOS);
+ }
+
+ if (psb->desiredY == psb->mouseY ||
+ 0 == SetTimer(hwnd, SBT_MOUSEROLL_ID, SBT_MOUSEROLL_INTERVAL, Statusbar_MouseRollTimer))
+ {
+ psb->flags &= ~SBF_MOUSEROLL;
+ }
+}
+
+static void Statusbar_MouseCheck(HWND hwnd, POINT pt)
+{
+ STATUSBAR *psb = GetStatusbar(hwnd);
+ if (NULL == psb) return;
+
+ DWORD windowStyle = GetWindowStyle(hwnd);
+ if (0 != (WS_DISABLED & windowStyle))
+ {
+ if (0 != psb->desiredY)
+ {
+ psb->desiredY = 0;
+ if (0 == (SBF_MOUSEROLL & psb->flags) &&
+ 0 != SetTimer(hwnd, SBT_MOUSEROLL_ID, 0, Statusbar_MouseRollTimer))
+ {
+ psb->flags |= SBF_MOUSEROLL;
+ }
+ }
+ return;
+ }
+
+ RECT windowRect;
+ if (!GetWindowRect(hwnd, &windowRect))
+ return;
+
+ windowRect.right = windowRect.left + psb->desiredCX;
+ windowRect.top -= psb->mouseY;
+ windowRect.bottom -= psb->mouseY;
+ LONG mouseY = psb->desiredY;
+
+ if (pt.y < windowRect.bottom)
+ {
+ if (pt.y < (windowRect.bottom - 12))
+ {
+ pt.y += 12;
+ }
+ else
+ {
+ pt.y = windowRect.bottom - 1;
+ }
+ }
+
+ if (PtInRect(&windowRect, pt))
+ {
+ psb->desiredY = pt.y - windowRect.top + 1;
+ }
+ else
+ {
+ psb->desiredY = 0;
+ }
+
+ if (psb->desiredY != mouseY)
+ {
+ if (0 == (SBF_MOUSEROLL & psb->flags) &&
+ 0 != SetTimer(hwnd, SBT_MOUSEROLL_ID, 0, Statusbar_MouseRollTimer))
+ {
+ psb->flags |= SBF_MOUSEROLL;
+ }
+ }
+}
+
+static void Statusbar_Paint(HWND hwnd, HDC hdc, const RECT *prcPaint, BOOL fErase)
+{
+ DWORD windowStyle = GetWindowStyle(hwnd);
+ if (0 != (SBS_UPDATELAYOUT & windowStyle))
+ Statusbar_UpdateLayout(hwnd, TRUE);
+
+ STATUSBAR *statusbar = GetStatusbar(hwnd);
+ if (NULL == statusbar) return;
+
+ RECT clientRect, textRect;
+ GetClientRect(hwnd, &clientRect);
+ CopyRect(&textRect, &clientRect);
+
+ SetBkColor(hdc, statusbar->rgbBk);
+ SetTextColor(hdc, statusbar->rgbText);
+
+ HRGN rgnBack = CreateRectRgnIndirect((NULL != prcPaint) ? prcPaint : &clientRect);
+ HRGN rgn = NULL;
+
+ if (0 != statusbar->cchText)
+ {
+ textRect.top += TEXTMARGIN_TOP;
+ textRect.right -= TEXTMARGIN_RIGHT;
+
+ SetBkMode(hdc, TRANSPARENT);
+ SetTextAlign(hdc, TA_LEFT | TA_BOTTOM);
+
+ HFONT origFont = (HFONT)SelectObject(hdc, statusbar->textFont);
+
+ rgn = CreateRectRgnIndirect(&textRect);
+
+ DWORD options = (FALSE != fErase) ? ETO_OPAQUE : 0;
+ if (0 != ExtTextOut(hdc, textRect.left + TEXTMARGIN_LEFT, textRect.bottom - TEXTMARGIN_BOTTOM,
+ options, &textRect, statusbar->pszText, statusbar->cchText, NULL))
+ {
+ CombineRgn(rgnBack, rgnBack, rgn, RGN_DIFF);
+ }
+ SelectObject(hdc, origFont);
+ }
+
+ if (0 != fErase)
+ {
+ FillRgn(hdc, rgnBack, statusbar->brushBk);
+ }
+
+ if (NULL != rgn) DeleteObject(rgn);
+ if (NULL != rgnBack) DeleteObject(rgnBack);
+
+}
+
+static LRESULT Statusbar_OnCreate(HWND hwnd, CREATESTRUCT *pcs)
+{
+ STATUSBAR *statusbar = (STATUSBAR*)calloc(1, sizeof(STATUSBAR));
+ if (NULL != statusbar)
+ {
+ SetLastError(ERROR_SUCCESS);
+ if (!SetWindowLongPtr(hwnd, 0, (LONGX86)(LONG_PTR)statusbar) && ERROR_SUCCESS != GetLastError())
+ {
+ free(statusbar);
+ statusbar = NULL;
+ }
+ }
+
+ if (NULL == statusbar)
+ {
+ DestroyWindow(hwnd);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void Statusbar_OnDestroy(HWND hwnd)
+{
+ STATUSBAR *statusbar = GetStatusbar(hwnd);
+ SetWindowLongPtr(hwnd, 0, 0L);
+
+ if (NULL == statusbar) return;
+
+ if (NULL != statusbar->textFont && 0 == (SBF_CACHEDFONT & statusbar->flags))
+ DeleteObject(statusbar->textFont);
+
+ if (NULL != statusbar->windowRegion)
+ DeleteObject(statusbar->windowRegion);
+
+ if (NULL != statusbar->brushBk)
+ DeleteObject(statusbar->brushBk);
+
+ Statusbar_RemoveMouseHook();
+ if (NULL != statusbar->hBrowser)
+ PostMessage(statusbar->hBrowser, NBHM_QUEUEAPC, (WPARAM)hwnd, (LPARAM)Statusbar_RemoveMouseHookApc);
+
+ free(statusbar);
+}
+
+static void Statusbar_OnPaint(HWND hwnd)
+{
+ PAINTSTRUCT ps;
+ if (BeginPaint(hwnd, &ps))
+ {
+ if (ps.rcPaint.left != ps.rcPaint.right)
+ Statusbar_Paint(hwnd, ps.hdc, &ps.rcPaint, ps.fErase);
+ EndPaint(hwnd, &ps);
+ }
+}
+
+static void Statusbar_OnPrintClient(HWND hwnd, HDC hdc, UINT options)
+{
+ RECT clientRect;
+ if (GetClientRect(hwnd, &clientRect))
+ Statusbar_Paint(hwnd, hdc, &clientRect, 0 != (PRF_ERASEBKGND & options));
+}
+static BOOL Statusbar_SetText(HWND hwnd, LPCWSTR pszText)
+{
+ STATUSBAR *statusbar = GetStatusbar(hwnd);
+ if (NULL == statusbar) return FALSE;
+
+ INT cchText;
+ cchText = (NULL != pszText && FALSE == IS_INTRESOURCE(pszText)) ? lstrlen(pszText) : 0;
+
+ if (cchText >= statusbar->cchTextMax)
+ {
+ statusbar->cchText = 0;
+ statusbar->cchTextMax = 0;
+ if (NULL != statusbar->pszText)
+ Plugin_FreeString(statusbar->pszText);
+
+ INT cchMalloc = ((cchText / 1024) + 1) * 1024;
+ statusbar->pszText = Plugin_MallocString(cchMalloc);
+ if (NULL == statusbar->pszText)
+ return FALSE;
+
+ statusbar->cchTextMax = cchMalloc;
+ }
+
+ statusbar->cchText = cchText;
+ if (0 == cchText)
+ {
+ statusbar->pszText[0] = L'\0';
+ }
+ else
+ {
+ if (FAILED(StringCchCopy(statusbar->pszText, statusbar->cchTextMax, pszText)))
+ {
+ statusbar->pszText[0] = L'\0';
+ statusbar->cchText = 0;
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+static BOOL Statusbar_OnSetText(HWND hwnd, LPCWSTR pszText)
+{
+ if (FALSE == Statusbar_SetText(hwnd, pszText))
+ return FALSE;
+
+ Statusbar_UpdateLayout(hwnd, FALSE);
+ return TRUE;
+}
+
+static INT Statusbar_OnGetText(HWND hwnd, LPWSTR pszBuffer, INT cchBufferMax)
+{
+ if (NULL == pszBuffer || cchBufferMax)
+ return 0;
+
+ pszBuffer[0] = L'\0';
+
+ STATUSBAR *statusbar = GetStatusbar(hwnd);
+ if (NULL == statusbar) return 0;
+
+ INT cchCopy = (statusbar ? statusbar->cchText : 0);
+ if (NULL != statusbar && 0 != cchCopy)
+ {
+ if (cchCopy >= cchBufferMax)
+ cchCopy = (cchBufferMax - 1);
+
+ StringCchCopyN(pszBuffer, cchBufferMax, statusbar->pszText, cchCopy);
+ }
+ return cchCopy;
+}
+
+static INT Statusbar_OnGetTextLength(HWND hwnd)
+{
+ STATUSBAR *statusbar = GetStatusbar(hwnd);
+ return (NULL != statusbar) ? statusbar->cchText : 0;
+}
+
+static LRESULT Statusbar_OnShowWindow(HWND hwnd, BOOL fShow, UINT nState)
+{
+ STATUSBAR *psb = GetStatusbar(hwnd);
+ if (NULL != psb)
+ {
+ if (FALSE != fShow)
+ {
+ Statusbar_InstallMouseHook(hwnd);
+ if (NULL != psb->hBrowser)
+ PostMessage(psb->hBrowser, NBHM_QUEUEAPC, (WPARAM)hwnd, (LPARAM)Statusbar_InstallMouseHookApc);
+
+ }
+ else
+ {
+ Statusbar_RemoveMouseHook();
+ if (NULL != psb->hBrowser)
+ PostMessage(psb->hBrowser, NBHM_QUEUEAPC, (WPARAM)hwnd, (LPARAM)Statusbar_RemoveMouseHookApc);
+ }
+ }
+
+ return DefWindowProcW(hwnd, WM_SHOWWINDOW, (WPARAM)fShow, (LPARAM)nState);
+}
+static void Statusbar_OnUpdateSkin(HWND hwnd, BOOL fRedraw)
+{
+ STATUSBAR *statusbar = GetStatusbar(hwnd);
+ if (NULL == statusbar) return;
+
+ ifc_skinhelper *skin;
+ if (FAILED(Plugin_GetSkinHelper(&skin)))
+ skin = NULL;
+
+ if (NULL == skin || FAILED(skin->GetColor(WADLG_WNDBG, &statusbar->rgbBk)))
+ statusbar->rgbBk = GetSysColor(COLOR_WINDOW);
+
+ if (NULL == skin || FAILED(skin->GetColor(WADLG_WNDFG, &statusbar->rgbText)))
+ statusbar->rgbText = GetSysColor(COLOR_WINDOWTEXT);
+ statusbar->rgbText = BlendColors(statusbar->rgbText, statusbar->rgbBk, 127);
+
+ if (NULL != statusbar->textFont)
+ {
+ if (0 == (SBF_CACHEDFONT & statusbar->flags))
+ DeleteObject(statusbar->textFont);
+ statusbar->textFont = NULL;
+ }
+
+ if (NULL != skin)
+ statusbar->textFont = skin->GetFont();
+
+ if (NULL != statusbar->textFont)
+ statusbar->flags |= SBF_CACHEDFONT;
+ else
+ {
+ statusbar->flags &= ~SBF_CACHEDFONT;
+ LOGFONT lf;
+ SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0);
+ StringCchCopy(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), L"Tahoma");
+ statusbar->textFont = CreateFontIndirect(&lf);
+ }
+
+ if (NULL != skin)
+ skin->Release();
+
+ if (NULL != statusbar->brushBk)
+ DeleteObject(statusbar->brushBk);
+
+ statusbar->brushBk = CreateSolidBrush(statusbar->rgbBk);
+
+ Statusbar_UpdateLayout(hwnd, FALSE);
+}
+
+static void Statusbar_OnSetParentRect(HWND hwnd, const RECT *parentRect)
+{
+ STATUSBAR *statusbar = GetStatusbar(hwnd);
+ if (NULL == statusbar || NULL == parentRect) return;
+
+ CopyRect(&statusbar->parentRect, parentRect);
+ Statusbar_UpdateLayout(hwnd, FALSE);
+}
+
+static BOOL Statusbar_OnSetActive(HWND hwnd, BOOL fActive)
+{
+ DWORD windowStyle = GetWindowStyle(hwnd);
+ if (0 == (SBS_ACTIVE & windowStyle) == (FALSE == fActive))
+ return TRUE;
+
+ if (FALSE == fActive)
+ windowStyle &= ~SBS_ACTIVE;
+ else
+ windowStyle |= SBS_ACTIVE;
+
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle);
+
+ if (0 != (SBS_ACTIVE & windowStyle))
+ {
+ if (0 == (WS_VISIBLE & windowStyle))
+ {
+ Statusbar_UpdateLayout(hwnd, TRUE);
+ ShowWindow(hwnd, SW_SHOWNA);
+ }
+ }
+ else
+ {
+ if (0 != (WS_VISIBLE & windowStyle))
+ {
+ STATUSBAR *statusbar = GetStatusbar(hwnd);
+ if (NULL != statusbar)
+ {
+ KillTimer(hwnd, SBT_INFLATE_ID);
+ statusbar->desiredCX = 0;
+ statusbar->inflateTime = GetTickCount();
+ SetTimer(hwnd, SBT_INFLATE_ID, SBT_INFLATE_DELAY, Statusbar_InflateTimer);
+ }
+ }
+ }
+ return TRUE;
+}
+
+static BOOL Statusbar_OnUpdate(HWND hwnd, LPCWSTR pszText)
+{
+ STATUSBAR *psb = GetStatusbar(hwnd);
+ if (NULL == psb) return FALSE;
+
+ if (NULL == pszText || L'\0' == *pszText)
+ return TRUE;
+
+ if (NULL == pszText)
+ {
+ if (NULL == psb->pszText)
+ {
+ return TRUE;
+ }
+ pszText = L"";
+ }
+
+ if (NULL != psb->pszText &&
+ CSTR_EQUAL == CompareString(CSTR_INVARIANT, 0, psb->pszText, -1, pszText, -1))
+ {
+ return TRUE;
+ }
+
+ Statusbar_SetText(hwnd, pszText);
+
+ DWORD windowStyle = GetWindowStyle(hwnd);
+ if (0 != (WS_VISIBLE & windowStyle))
+ {
+ Statusbar_UpdateLayout(hwnd, FALSE);
+ InvalidateRect(hwnd, NULL, TRUE);
+ }
+
+ return TRUE;
+}
+
+static BOOL Statusbar_OnSetBrowserHost(HWND hwnd, HWND hBrowser)
+{
+ STATUSBAR *psb = GetStatusbar(hwnd);
+ if (NULL == psb) return FALSE;
+
+ psb->hBrowser = hBrowser;
+ return TRUE;
+}
+
+static LRESULT Statusbar_OnEnable(HWND hwnd, BOOL fEnable)
+{
+ UINT windowStyle = GetWindowStyle(hwnd);
+ UINT newStyle = windowStyle;
+
+ if (FALSE == fEnable)
+ newStyle |= WS_DISABLED;
+ else
+ newStyle &= ~WS_DISABLED;
+
+ if(newStyle == windowStyle)
+ return fEnable;
+
+ SetWindowLongPtr(hwnd, GWL_STYLE, newStyle);
+
+ return !fEnable;
+}
+
+static LRESULT CALLBACK Statusbar_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_CREATE: return Statusbar_OnCreate(hwnd, (CREATESTRUCT*)lParam);
+ case WM_DESTROY: Statusbar_OnDestroy(hwnd); break;
+ case WM_PAINT: Statusbar_OnPaint(hwnd); return 0;
+ case WM_PRINTCLIENT: Statusbar_OnPrintClient(hwnd, (HDC)wParam, (UINT)lParam); return 0;
+ case WM_ERASEBKGND: return 0;
+ case WM_SETTEXT: return Statusbar_OnSetText(hwnd, (LPCWSTR)lParam);
+ case WM_GETTEXT: return Statusbar_OnGetText(hwnd, (LPWSTR)lParam, (INT)wParam);
+ case WM_GETTEXTLENGTH: return Statusbar_OnGetTextLength(hwnd);
+ case WM_SHOWWINDOW: return Statusbar_OnShowWindow(hwnd, (BOOL)wParam, (UINT)lParam);
+
+ case SBM_UPDATESKIN: Statusbar_OnUpdateSkin(hwnd, (BOOL)lParam); return 0;
+ case SBM_SETPARENTRECT: Statusbar_OnSetParentRect(hwnd, (const RECT*)lParam); return 0;
+ case SBM_SETACTIVE: return Statusbar_OnSetActive(hwnd, (BOOL)wParam);
+ case SBM_UPDATE: return Statusbar_OnUpdate(hwnd, (LPCWSTR)lParam);
+ case SBM_SETBROWSERHOST: return Statusbar_OnSetBrowserHost(hwnd, (HWND)lParam);
+ case SBM_ENABLE: return Statusbar_OnEnable(hwnd, (BOOL)lParam);
+
+ }
+ return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+}
+static void CALLBACK Statusbar_InflateTimer(HWND hwnd, UINT uMsg, UINT_PTR eventId, DWORD timerId)
+{
+ KillTimer(hwnd, eventId);
+ Statusbar_Inflate(hwnd);
+}
+
+static void CALLBACK Statusbar_MouseRollTimer(HWND hwnd, UINT uMsg, UINT_PTR eventId, DWORD timerId)
+{
+ KillTimer(hwnd, eventId);
+ Statusbar_MouseRoll(hwnd);
+}
+
+static LRESULT CALLBACK Statusbar_MouseHook(INT code, WPARAM wParam, LPARAM lParam)
+{
+ STATUSBARMOUSEHOOK *hook = (STATUSBARMOUSEHOOK*)Plugin_TlsGetValue(tlsIndex);
+ if (NULL == hook || NULL == hook->hHook) return FALSE;
+
+ if (code >= 0)
+ {
+ MOUSEHOOKSTRUCT *mouseHook = (MOUSEHOOKSTRUCT*)lParam;
+ if (NULL != hook->hwnd)
+ {
+ Statusbar_MouseCheck(hook->hwnd, mouseHook->pt);
+ }
+ }
+ return CallNextHookEx(hook->hHook, code, wParam, lParam);
+}
diff --git a/Src/omBrowser/statusbar.h b/Src/omBrowser/statusbar.h
new file mode 100644
index 00000000..3fbe40bb
--- /dev/null
+++ b/Src/omBrowser/statusbar.h
@@ -0,0 +1,47 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_STATUSBAR_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_STATUSBAR_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+#define NWC_ONLINEMEDIASTATUSBAR L"Nullsoft_omBrowserStatusbar"
+
+BOOL Statusbar_RegisterClass(HINSTANCE hInstance);
+
+#define SBS_UPDATELAYOUT 0x00000001
+#define SBS_ACTIVE 0x00000002
+
+// messages
+#define SBM_FIRST (WM_USER + 10)
+
+#define SBM_UPDATESKIN (SBM_FIRST + 0) //wParam = not used, lParam = (LPARAM)(BOOL)redraw.
+#define Statusbar_UpdateSkin(/*HWND*/ __hStatusbar, /*BOOL*/ __fRedraw)\
+ ((BOOL)SENDMSG(__hStatusbar, SBM_UPDATESKIN, 0, (LPARAM)(__fRedraw)))
+
+#define SBM_SETPARENTRECT (SBM_FIRST + 1) //wParam = not used, lParam = (LPCRECT)parentRect.
+#define Statusbar_SetParentRect(/*HWND*/ __hStatusbar, /*LPCRECT*/ __parentRect)\
+ ((BOOL)SENDMSG(__hStatusbar, SBM_SETPARENTRECT, 0, (LPARAM)(__parentRect)))
+
+#define SBM_SETACTIVE (SBM_FIRST + 2) //wParam = (BOOL)fActive, lParam = not used.
+#define Statusbar_SetActive(/*HWND*/ __hStatusbar, /*BOOL*/ __fActive)\
+ ((BOOL)SENDMSG(__hStatusbar, SBM_SETACTIVE, (WPARAM)(__fActive), 0L))
+
+#define SBM_UPDATE (SBM_FIRST + 3) //wParam = 0, lParam = (LPCWSTR)pszText.
+#define Statusbar_Update(/*HWND*/ __hStatusbar, /*LPCWSTR*/ __pszText)\
+ ((BOOL)SENDMSG(__hStatusbar, SBM_UPDATE, 0, (LPARAM)(__pszText)))
+
+#define SBM_SETBROWSERHOST (SBM_FIRST + 4) //wParam = 0, lParam = (LPARAM)(HWND)hwndBrowserHost.
+#define Statusbar_SetBrowserHost(/*HWND*/ __hStatusbar, /*HWND*/ __hwndBrowserHost)\
+ ((BOOL)SENDMSG(__hStatusbar, SBM_SETBROWSERHOST, 0, (LPARAM)(__hwndBrowserHost)))
+
+#define SBM_ENABLE (SBM_FIRST + 5) //wParam - not used, lParam = (LPARAM)(BOOL)fEnable. Return previous value
+#define Statusbar_Enable(/*HWND*/ __hStatusbar, /*BOOL*/ __fEnable)\
+ ((BOOL)SENDMSG(__hStatusbar, SBM_ENABLE, 0, (LPARAM)(__fEnable)))
+
+// Notifications (WM_COMMAND)
+#define SBN_ENABLECHANGED 1
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_STATUSBAR_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/storageDwnld.cpp b/Src/omBrowser/storageDwnld.cpp
new file mode 100644
index 00000000..6f501781
--- /dev/null
+++ b/Src/omBrowser/storageDwnld.cpp
@@ -0,0 +1,395 @@
+#include "main.h"
+#include "./storageDwnld.h"
+#include "./ifc_omwebstorage.h"
+#include "./ifc_wasabihelper.h"
+#include "./ifc_omservicehost.h"
+#include "..\Components\wac_network\wac_network_http_receiver_api.h"
+
+OmStorageDwnld::OmStorageDwnld(api_downloadManager *downloadManager, BOOL enableCompression)
+ : ref(1), userCallback(NULL), userData(NULL), completed(NULL), flags(0),
+ opState(stateInitializing), resultCode(api_downloadManager::TICK_SUCCESS),
+ cookie(NULL), manager(downloadManager), serviceHost(NULL)
+{
+ if (NULL != manager)
+ manager->AddRef();
+
+ if (FALSE != enableCompression)
+ flags |= flagEnableCompression;
+
+ InitializeCriticalSection(&lock);
+}
+
+OmStorageDwnld::~OmStorageDwnld()
+{
+ EnterCriticalSection(&lock);
+
+ if (NULL != manager)
+ {
+ if (NULL != cookie)
+ {
+ manager->ReleaseDownload(cookie);
+ cookie = NULL;
+ }
+
+ manager->Release();
+ manager = NULL;
+ }
+
+ if (NULL != completed)
+ {
+ CloseHandle(completed);
+ completed = NULL;
+ }
+
+ if (NULL != serviceHost)
+ {
+ serviceHost->Release();
+ serviceHost = NULL;
+ }
+
+ LeaveCriticalSection(&lock);
+
+ DeleteCriticalSection(&lock);
+}
+
+HRESULT OmStorageDwnld::CreateInstance(api_downloadManager *downloadManager, BOOL enableCompression, OmStorageDwnld **instance)
+{
+ if (NULL == instance) return E_POINTER;
+
+ *instance = NULL;
+ if (NULL == downloadManager)
+ return E_INVALIDARG;
+
+ *instance = new OmStorageDwnld(downloadManager, enableCompression);
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t OmStorageDwnld::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t OmStorageDwnld::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int OmStorageDwnld::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmStorageAsync))
+ *object = static_cast<ifc_omstorageasync*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT OmStorageDwnld::GetState(UINT *state)
+{
+ if (NULL == state)
+ return E_POINTER;
+
+ EnterCriticalSection(&lock);
+ *state = opState;
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+HRESULT OmStorageDwnld::GetWaitHandle(HANDLE *handle)
+{
+ if (NULL == handle)
+ return E_POINTER;
+
+ HRESULT hr = S_OK;
+
+ EnterCriticalSection(&lock);
+
+ if (NULL == completed)
+ {
+ completed = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (NULL == completed)
+ {
+ *handle = NULL;
+ DWORD error = GetLastError();
+ hr = HRESULT_FROM_WIN32(error);
+ }
+ }
+
+ if (SUCCEEDED(hr) && FALSE == DuplicateHandle(GetCurrentProcess(), completed,
+ GetCurrentProcess(), handle, 0, FALSE, DUPLICATE_SAME_ACCESS))
+ {
+ *handle = NULL;
+ DWORD error = GetLastError();
+ hr = HRESULT_FROM_WIN32(error);
+ }
+
+ LeaveCriticalSection(&lock);
+ return hr;
+}
+
+HRESULT OmStorageDwnld::GetData(void **data)
+{
+ if (NULL == data)
+ return E_POINTER;
+
+ EnterCriticalSection(&lock);
+ *data = userData;
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+HRESULT OmStorageDwnld::GetCallback(AsyncCallback *callback)
+{
+ if (NULL == callback)
+ return E_POINTER;
+
+ EnterCriticalSection(&lock);
+ *callback = userCallback;
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+void OmStorageDwnld::OnInit(DownloadToken token)
+{
+ EnterCriticalSection(&lock);
+
+ AddRef();
+ cookie = token;
+ opState = stateConnecting;
+
+ if (NULL != manager)
+ {
+ manager->RetainDownload(cookie);
+
+ if (0 != (flagEnableCompression & flags))
+ {
+ api_httpreceiver *receiver = manager->GetReceiver(token);
+ if (NULL != receiver)
+ receiver->AllowCompression();
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+}
+
+void OmStorageDwnld::OnConnect(DownloadToken token)
+{
+ EnterCriticalSection(&lock);
+ opState = stateReceiving;
+ LeaveCriticalSection(&lock);
+}
+
+void OmStorageDwnld::OnTick(DownloadToken token)
+{
+ EnterCriticalSection(&lock);
+
+ if (stateConnecting == opState)
+ opState = stateReceiving;
+
+ LeaveCriticalSection(&lock);
+}
+
+void OmStorageDwnld::OnFinish(DownloadToken token)
+{
+ DownloadCompleted(api_downloadManager::TICK_SUCCESS);
+}
+
+void OmStorageDwnld::OnError(DownloadToken token, int errorCode)
+{
+ DownloadCompleted(errorCode);
+}
+
+void OmStorageDwnld::OnCancel(DownloadToken token)
+{
+ DownloadCompleted(api_downloadManager::TICK_NODATA);
+}
+
+void OmStorageDwnld::DownloadCompleted( INT errorCode )
+{
+ EnterCriticalSection( &lock );
+
+ resultCode = errorCode;
+ opState = stateCompleted;
+ HANDLE event = completed;
+
+ LeaveCriticalSection( &lock );
+
+ if ( NULL != event )
+ {
+ SetEvent( event );
+ }
+
+ EnterCriticalSection( &lock );
+ AsyncCallback cb = userCallback;
+ LeaveCriticalSection( &lock );
+
+ if ( NULL != cb )
+ {
+ cb( this );
+ }
+
+ Release();
+}
+
+HRESULT OmStorageDwnld::SetData(void *data)
+{
+ EnterCriticalSection(&lock);
+ userData = data;
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+HRESULT OmStorageDwnld::SetCallback(AsyncCallback callback)
+{
+ EnterCriticalSection(&lock);
+ userCallback = callback;
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+HRESULT OmStorageDwnld::GetResultCode()
+{
+ EnterCriticalSection(&lock);
+
+ HRESULT hr;
+ if (NULL == cookie || NULL == manager)
+ {
+ hr = E_UNEXPECTED;
+ }
+ else
+ {
+ switch(resultCode)
+ {
+ case api_downloadManager::TICK_SUCCESS: hr = E_DWNLD_OK; break;
+ case api_downloadManager::TICK_FAILURE: hr = (0 != (flagUserAbort & flags)) ? E_DWNLD_ABORT : E_DWNLD_FAIL; break;
+ case api_downloadManager::TICK_TIMEOUT: hr = E_DWNLD_TIMEOUT; break;
+ case api_downloadManager::TICK_CANT_CONNECT: hr = E_DWNLD_CANT_CONNECT; break;
+ case api_downloadManager::TICK_WRITE_ERROR: hr = E_DWNLD_WRITE_ERROR; break;
+ default: hr = E_DWNLD_BUSY; break;
+ }
+ }
+
+ LeaveCriticalSection(&lock);
+
+ return hr;
+}
+
+HRESULT OmStorageDwnld::GetBuffer(void **buffer, size_t *bufferSize)
+{
+ if (NULL == buffer) return E_POINTER;
+
+ EnterCriticalSection(&lock);
+
+ HRESULT hr = GetResultCode();
+ if (SUCCEEDED(hr) && 0 != manager->GetBuffer(cookie, buffer, bufferSize))
+ hr = E_DWNLD_FAIL;
+
+ LeaveCriticalSection(&lock);
+
+ if (FAILED(hr))
+ {
+ *buffer = NULL;
+ *bufferSize = 0;
+ }
+
+ return hr;
+}
+
+HRESULT OmStorageDwnld::RequestAbort(BOOL fDrop)
+{
+ EnterCriticalSection(&lock);
+ if (FALSE != fDrop)
+ {
+ userData = NULL;
+ userCallback = NULL;
+ }
+
+ if (NULL != cookie && NULL != manager)
+ {
+ opState = stateAborting;
+ flags |= flagUserAbort;
+ manager->CancelDownload(cookie);
+ }
+
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+HRESULT OmStorageDwnld::SetServiceHost(ifc_omservicehost *host)
+{
+ EnterCriticalSection(&lock);
+
+ if (NULL != serviceHost)
+ serviceHost->Release();
+
+ serviceHost = host;
+ if (NULL != serviceHost)
+ serviceHost->AddRef();
+
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+HRESULT OmStorageDwnld::GetServiceHost(ifc_omservicehost **host)
+{
+ if (NULL == host)
+ return E_POINTER;
+
+ EnterCriticalSection(&lock);
+
+ *host = serviceHost;
+ if (NULL != serviceHost)
+ serviceHost->AddRef();
+
+ LeaveCriticalSection(&lock);
+
+ return S_OK;
+}
+
+#define CBCLASS OmStorageDwnld
+START_MULTIPATCH;
+ START_PATCH(MPIID_OMSTORAGEASYNC)
+ M_CB(MPIID_OMSTORAGEASYNC, ifc_omstorageasync, ADDREF, AddRef);
+ M_CB(MPIID_OMSTORAGEASYNC, ifc_omstorageasync, RELEASE, Release);
+ M_CB(MPIID_OMSTORAGEASYNC, ifc_omstorageasync, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMSTORAGEASYNC, ifc_omstorageasync, API_GETSTATE, GetState);
+ M_CB(MPIID_OMSTORAGEASYNC, ifc_omstorageasync, API_GETWAITHANDLE, GetWaitHandle);
+ M_CB(MPIID_OMSTORAGEASYNC, ifc_omstorageasync, API_GETDATA, GetData);
+ NEXT_PATCH(MPIID_DOWNLOADCALLBACK)
+ M_CB(MPIID_DOWNLOADCALLBACK, ifc_downloadManagerCallback, ADDREF, AddRef);
+ M_CB(MPIID_DOWNLOADCALLBACK, ifc_downloadManagerCallback, RELEASE, Release);
+ M_CB(MPIID_DOWNLOADCALLBACK, ifc_downloadManagerCallback, QUERYINTERFACE, QueryInterface);
+ M_VCB(MPIID_DOWNLOADCALLBACK, ifc_downloadManagerCallback, IFC_DOWNLOADMANAGERCALLBACK_ONFINISH, OnFinish);
+ M_VCB(MPIID_DOWNLOADCALLBACK, ifc_downloadManagerCallback, IFC_DOWNLOADMANAGERCALLBACK_ONTICK, OnTick);
+ M_VCB(MPIID_DOWNLOADCALLBACK, ifc_downloadManagerCallback, IFC_DOWNLOADMANAGERCALLBACK_ONERROR, OnError);
+ M_VCB(MPIID_DOWNLOADCALLBACK, ifc_downloadManagerCallback, IFC_DOWNLOADMANAGERCALLBACK_ONCANCEL, OnCancel);
+ M_VCB(MPIID_DOWNLOADCALLBACK, ifc_downloadManagerCallback, IFC_DOWNLOADMANAGERCALLBACK_ONCONNECT, OnConnect);
+ M_VCB(MPIID_DOWNLOADCALLBACK, ifc_downloadManagerCallback, IFC_DOWNLOADMANAGERCALLBACK_ONINIT, OnInit);
+ END_PATCH
+END_MULTIPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/storageDwnld.h b/Src/omBrowser/storageDwnld.h
new file mode 100644
index 00000000..63c4ead6
--- /dev/null
+++ b/Src/omBrowser/storageDwnld.h
@@ -0,0 +1,84 @@
+#ifndef NULLSOFT_WINAMP_OMSTORAGE_DOWNLOADER_HEADER
+#define NULLSOFT_WINAMP_OMSTORAGE_DOWNLOADER_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_omstorageasync.h"
+#include "../Components/wac_downloadManager/wac_downloadManager_api.h"
+#include <bfc/multipatch.h>
+
+class ifc_omservicehost;
+
+#define MPIID_OMSTORAGEASYNC 10
+#define MPIID_DOWNLOADCALLBACK 20
+
+class OmStorageDwnld : public MultiPatch<MPIID_OMSTORAGEASYNC, ifc_omstorageasync>,
+ public MultiPatch<MPIID_DOWNLOADCALLBACK, ifc_downloadManagerCallback>
+{
+public:
+ typedef enum
+ {
+ flagEnableCompression = 0x00000001,
+ flagUserAbort = 0x00010000,
+ flagCompletedSynchronously = 0x00020000,
+ } Flags;
+
+protected:
+ OmStorageDwnld(api_downloadManager *downloadManager, BOOL enableCompression);
+ ~OmStorageDwnld();
+
+public:
+ static HRESULT CreateInstance(api_downloadManager *downloadManager, BOOL enableCompression, OmStorageDwnld **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_omstorageasync */
+ HRESULT GetState(UINT *state);
+ HRESULT GetWaitHandle(HANDLE *handle);
+ HRESULT GetData(void **data);
+
+ /* ifc_downloadManagerCallback */
+ void OnFinish(DownloadToken token);
+ void OnTick(DownloadToken token);
+ void OnError(DownloadToken token, int errorCode);
+ void OnCancel(DownloadToken token);
+ void OnConnect(DownloadToken token);
+ void OnInit(DownloadToken token);
+
+ HRESULT GetResultCode();
+ HRESULT GetBuffer(void **buffer, size_t *bufferSize);
+
+ HRESULT SetData(void *data);
+ HRESULT SetCallback(AsyncCallback callback);
+ HRESULT GetCallback(AsyncCallback *callback);
+
+ HRESULT RequestAbort(BOOL fDrop);
+
+ HRESULT SetServiceHost(ifc_omservicehost *host);
+ HRESULT GetServiceHost(ifc_omservicehost **host);
+
+protected:
+ void DownloadCompleted(INT errorCode);
+
+ size_t ref;
+ AsyncCallback userCallback;
+ void *userData;
+ HANDLE completed;
+ UINT flags;
+ UINT opState;
+ INT resultCode;
+ CRITICAL_SECTION lock;
+ DownloadToken cookie;
+ api_downloadManager *manager;
+ ifc_omservicehost *serviceHost;
+
+ RECVS_MULTIPATCH;
+};
+
+#endif //NULLSOFT_WINAMP_OMSTORAGE_DOWNLOADER_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/storageEnum.cpp b/Src/omBrowser/storageEnum.cpp
new file mode 100644
index 00000000..a4824e20
--- /dev/null
+++ b/Src/omBrowser/storageEnum.cpp
@@ -0,0 +1,119 @@
+#include "main.h"
+#include "./storageEnum.h"
+#include "./ifc_omstorage.h"
+
+OmStorageEnumerator::OmStorageEnumerator(ifc_omstorage **storageList, size_t storageSize, const GUID *type, UINT capabilities)
+ : ref(1), index(0), list(storageList), size(storageSize)
+{
+ fType = (NULL != type) ? *type : GUID_NULL;
+ fCapabilities = capabilities;
+}
+
+OmStorageEnumerator::~OmStorageEnumerator()
+{
+}
+
+HRESULT OmStorageEnumerator::CreateInstance(ifc_omstorage **storageList, size_t storageSize, const GUID *type, UINT capabilities, OmStorageEnumerator **instance)
+{
+ if (NULL == instance) return E_POINTER;
+
+ *instance = new OmStorageEnumerator(storageList, storageSize, type, capabilities);
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t OmStorageEnumerator::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t OmStorageEnumerator::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int OmStorageEnumerator::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmStorageEnumerator))
+ *object = static_cast<ifc_omstorageenumerator*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT OmStorageEnumerator::Next(ULONG listSize, ifc_omstorage **elementList, ULONG *elementCount)
+{
+ if (NULL == elementList || 0 == listSize) return E_INVALIDARG;
+ if (index >= size)
+ {
+ if (NULL != elementCount) *elementCount = 0;
+ return S_FALSE;
+ }
+
+ ULONG count = 0;
+ ifc_omstorage *storage = NULL;
+ GUID storageId = GUID_NULL;
+
+ for (;index < size && count < listSize; index++)
+ {
+ storage = list[index];
+ if (NULL != storage &&
+ SUCCEEDED(storage->GetType(&storageId)) && IsEqualGUID(storageId, fType) &&
+ (0 == fCapabilities || fCapabilities == (fCapabilities & storage->GetCapabilities())))
+ {
+ elementList[count] = storage;
+ storage->AddRef();
+ count++;
+ }
+ }
+
+ if (NULL != elementCount) *elementCount = count;
+
+ return (count == listSize) ? S_OK : S_FALSE;
+}
+
+HRESULT OmStorageEnumerator::Reset(void)
+{
+ index = 0;
+ return S_OK;
+}
+
+HRESULT OmStorageEnumerator::Skip(ULONG elementCount)
+{
+ index += elementCount;
+ if (index >= size)
+ {
+ index = (size - 1);
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
+#define CBCLASS OmStorageEnumerator
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_NEXT, Next)
+CB(API_RESET, Reset)
+CB(API_SKIP, Skip)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/storageEnum.h b/Src/omBrowser/storageEnum.h
new file mode 100644
index 00000000..141182c0
--- /dev/null
+++ b/Src/omBrowser/storageEnum.h
@@ -0,0 +1,42 @@
+#ifndef NULLSOFT_WINAMP_OMSTORAGE_ENUMERATOR_HEADER
+#define NULLSOFT_WINAMP_OMSTORAGE_ENUMERATOR_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_omstorageenum.h"
+
+class OmStorageEnumerator : public ifc_omstorageenumerator
+{
+protected:
+ OmStorageEnumerator(ifc_omstorage **storageList, size_t storageSize, const GUID *type, UINT capabilities);
+ ~OmStorageEnumerator();
+
+public:
+ static HRESULT CreateInstance(ifc_omstorage **storageList, size_t storageSize, const GUID *type, UINT capabilities, OmStorageEnumerator **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_omstorage */
+ HRESULT Next(ULONG listSize, ifc_omstorage **elementList, ULONG *elementCount);
+ HRESULT Reset(void);
+ HRESULT Skip(ULONG elementCount);
+
+protected:
+ ULONG ref;
+ size_t index;
+ ifc_omstorage **list;
+ size_t size;
+ GUID fType;
+ UINT fCapabilities;
+
+protected:
+ RECVS_DISPATCH;
+};
+
+#endif //NULLSOFT_WINAMP_OMSTORAGE_ENUMERATOR_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/storageHandler.cpp b/Src/omBrowser/storageHandler.cpp
new file mode 100644
index 00000000..453b3015
--- /dev/null
+++ b/Src/omBrowser/storageHandler.cpp
@@ -0,0 +1,92 @@
+#include "main.h"
+#include "./storageHandler.h"
+
+StorageHandler::StorageHandler(LPCWSTR pszKey, ifc_omstoragehelper::HandlerProc handlerProc, UINT flags)
+: ref(1), key(NULL), handler(handlerProc), flags(flags)
+{
+ if (0 != (flagCopyKey & flags))
+ key = Plugin_CopyString(pszKey);
+ else
+ key = (LPWSTR)pszKey;
+}
+
+StorageHandler::~StorageHandler()
+{
+ if (0 != (flagCopyKey & flags))
+ Plugin_FreeString(key);
+}
+
+HRESULT StorageHandler::CreateInstance(LPCWSTR pszKey, ifc_omstoragehelper::HandlerProc handlerProc, UINT flags, StorageHandler **instance)
+{
+ if (NULL == instance)
+ return E_POINTER;
+
+ if (NULL == pszKey || L'\0' == pszKey || NULL == handlerProc)
+ {
+ *instance = NULL;
+ return E_INVALIDARG;
+ }
+
+ *instance = new StorageHandler(pszKey, handlerProc, flags);
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t StorageHandler::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t StorageHandler::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int StorageHandler::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmStorageHandler))
+ *object = static_cast<ifc_omstoragehandler*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT StorageHandler::GetKey(LPCWSTR *ppKey)
+{
+ if (NULL == ppKey) return E_POINTER;
+ *ppKey = key;
+ return S_OK;
+}
+
+void StorageHandler::Invoke(ifc_omservice *service, LPCWSTR pszKey, LPCWSTR pszValue)
+{
+ handler(service, pszKey, pszValue);
+}
+
+#define CBCLASS StorageHandler
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_GETKEY, GetKey)
+VCB(API_INVOKE, Invoke)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/storageHandler.h b/Src/omBrowser/storageHandler.h
new file mode 100644
index 00000000..b52b2ba3
--- /dev/null
+++ b/Src/omBrowser/storageHandler.h
@@ -0,0 +1,47 @@
+#ifndef NULLSOFT_ONLINEMEDIA_PLUGIN_STORAGE_HANDLER_HEADER
+#define NULLSOFT_ONLINEMEDIA_PLUGIN_STORAGE_HANDLER_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_omstoragehandler.h"
+#include "./ifc_omstoragehelper.h"
+class ifc_omservice;
+
+class StorageHandler : public ifc_omstoragehandler
+{
+public:
+ typedef enum
+ {
+ flagCopyKey = 0x00000001,
+ } Flags;
+
+protected:
+ StorageHandler(LPCWSTR pszKey, ifc_omstoragehelper::HandlerProc handlerProc, UINT flags);
+ ~StorageHandler();
+
+public:
+ static HRESULT CreateInstance(LPCWSTR pszKey, ifc_omstoragehelper::HandlerProc handlerProc, UINT flags, StorageHandler **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_omstoragehandler */
+ HRESULT GetKey(LPCWSTR *ppKey);
+ void Invoke(ifc_omservice *service, LPCWSTR pszKey, LPCWSTR pszValue);
+
+protected:
+ ULONG ref;
+ LPWSTR key;
+ ifc_omstoragehelper::HandlerProc handler;
+ UINT flags;
+
+protected:
+ RECVS_DISPATCH;
+};
+
+#endif //NULLSOFT_ONLINEMEDIA_PLUGIN_STORAGE_HANDLER_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/storageHandlerEnum.cpp b/Src/omBrowser/storageHandlerEnum.cpp
new file mode 100644
index 00000000..580a3504
--- /dev/null
+++ b/Src/omBrowser/storageHandlerEnum.cpp
@@ -0,0 +1,154 @@
+#include "main.h"
+#include "./storageHandlerEnum.h"
+#include "./storageHandler.h"
+
+StorageHandlerEnum::StorageHandlerEnum()
+ : ref(1), index(0)
+{
+}
+
+StorageHandlerEnum::~StorageHandlerEnum()
+{
+ size_t index = handlerList.size();
+ while(index--)
+ {
+ handlerList[index]->Release();
+ }
+}
+
+HRESULT StorageHandlerEnum::CreateInstance(StorageHandlerEnum **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ *instance = new StorageHandlerEnum();
+ if (NULL == *instance) return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+HRESULT StorageHandlerEnum::CreateFromTemplate(const ifc_omstoragehelper::TemplateRecord *recordList, size_t recordCount, StorageHandlerEnum **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ *instance = new StorageHandlerEnum();
+ if (NULL == *instance)
+ return E_OUTOFMEMORY;
+
+ if (NULL != recordList)
+ {
+ StorageHandler *handler = NULL;
+ for (size_t i = 0; i < recordCount; i++)
+ {
+ const ifc_omstoragehelper::TemplateRecord *record = &recordList[i];
+ if (NULL != record &&
+ SUCCEEDED(StorageHandler::CreateInstance(record->key, record->handler, StorageHandler::flagCopyKey, &handler)))
+ {
+ if (FAILED((*instance)->AddHandler(handler)))
+ {
+ handler->Release();
+ }
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+size_t StorageHandlerEnum::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t StorageHandlerEnum::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int StorageHandlerEnum::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmStorageHandlerEnum))
+ *object = static_cast<ifc_omstoragehandlerenum*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT StorageHandlerEnum::Next(ULONG listSize, ifc_omstoragehandler **elementList, ULONG *elementCount)
+{
+ if (NULL == elementList || 0 == listSize) return E_INVALIDARG;
+ size_t size = handlerList.size();
+
+ if (index >= size)
+ {
+ if (NULL != elementCount) *elementCount = 0;
+ return S_FALSE;
+ }
+
+ ULONG count = 0;
+ ifc_omstoragehandler *handler = NULL;
+
+ for (;index < size && count < listSize; index++)
+ {
+ handler = handlerList[index];
+ elementList[count] = handler;
+ handler->AddRef();
+ count++;
+ }
+
+ if (NULL != elementCount)
+ *elementCount = count;
+
+ return (count == listSize) ? S_OK : S_FALSE;
+}
+
+HRESULT StorageHandlerEnum::Reset(void)
+{
+ index = 0;
+ return S_OK;
+}
+
+HRESULT StorageHandlerEnum::Skip(ULONG elementCount)
+{
+ index += elementCount;
+ if (index >= handlerList.size())
+ {
+ index = (handlerList.size() - 1);
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
+HRESULT StorageHandlerEnum::AddHandler(ifc_omstoragehandler *handler)
+{
+ if (NULL == handler)
+ return E_INVALIDARG;
+
+ handlerList.push_back(handler);
+
+ return S_OK;
+}
+
+#define CBCLASS StorageHandlerEnum
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_NEXT, Next)
+CB(API_RESET, Reset)
+CB(API_SKIP, Skip)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/storageHandlerEnum.h b/Src/omBrowser/storageHandlerEnum.h
new file mode 100644
index 00000000..bc8ea8cc
--- /dev/null
+++ b/Src/omBrowser/storageHandlerEnum.h
@@ -0,0 +1,48 @@
+#ifndef NULLSOFT_ONLINEMEDIA_PLUGIN_STORAGE_HANDLER_ENUMERATOR_HEADER
+#define NULLSOFT_ONLINEMEDIA_PLUGIN_STORAGE_HANDLER_ENUMERATOR_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_omstoragehandlerenum.h"
+#include "./ifc_omstoragehelper.h"
+#include <vector>
+
+class StorageHandlerEnum : public ifc_omstoragehandlerenum
+{
+protected:
+ StorageHandlerEnum();
+ ~StorageHandlerEnum();
+
+public:
+ static HRESULT CreateInstance(StorageHandlerEnum **instance);
+ static HRESULT CreateFromTemplate(const ifc_omstoragehelper::TemplateRecord *recordList, size_t recordCount, StorageHandlerEnum **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_omstoragehandlerenum */
+ HRESULT Next(ULONG listSize, ifc_omstoragehandler **elementList, ULONG *elementCount);
+ HRESULT Reset(void);
+ HRESULT Skip(ULONG elementCount);
+
+public:
+ HRESULT AddHandler(ifc_omstoragehandler *handler);
+
+protected:
+ typedef std::vector<ifc_omstoragehandler*> HandlerList;
+
+protected:
+ ULONG ref;
+ HandlerList handlerList;
+ size_t index;
+
+protected:
+ RECVS_DISPATCH;
+};
+
+#endif //NULLSOFT_ONLINEMEDIA_PLUGIN_STORAGE_HANDLER_ENUMERATOR_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/storageHelper.cpp b/Src/omBrowser/storageHelper.cpp
new file mode 100644
index 00000000..fef47374
--- /dev/null
+++ b/Src/omBrowser/storageHelper.cpp
@@ -0,0 +1,77 @@
+#include "main.h"
+#include "./storageHelper.h"
+#include "./storageHandler.h"
+#include "./storageHandlerEnum.h"
+
+StorageHelper::StorageHelper()
+: ref(1)
+{
+}
+
+StorageHelper::~StorageHelper()
+{
+}
+
+HRESULT StorageHelper::CreateInstance(StorageHelper **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ *instance = new StorageHelper();
+ if (NULL == *instance) return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+size_t StorageHelper::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t StorageHelper::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int StorageHelper::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmStorageHelper))
+ *object = static_cast<ifc_omstoragehelper*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT StorageHelper::CreateHandler(const wchar_t *key, HandlerProc proc, ifc_omstoragehandler **handler)
+{
+ return StorageHandler::CreateInstance(key, proc, StorageHandler::flagCopyKey, (StorageHandler**)handler);
+}
+
+HRESULT StorageHelper::CreateEnumerator(const TemplateRecord *recordList, size_t recordCount, ifc_omstoragehandlerenum **enumerator)
+{
+ return StorageHandlerEnum::CreateFromTemplate(recordList, recordCount, (StorageHandlerEnum**)enumerator);
+}
+
+#define CBCLASS StorageHelper
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_CREATEHANDLER, CreateHandler)
+CB(API_CREATEENUMERATOR, CreateEnumerator)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/storageHelper.h b/Src/omBrowser/storageHelper.h
new file mode 100644
index 00000000..530a5a06
--- /dev/null
+++ b/Src/omBrowser/storageHelper.h
@@ -0,0 +1,35 @@
+#ifndef NULLSOFT_WINAMP_OMSTORAGE_HELPER_HEADER
+#define NULLSOFT_WINAMP_OMSTORAGE_HELPER_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_omstoragehelper.h"
+
+class StorageHelper : public ifc_omstoragehelper
+{
+protected:
+ StorageHelper();
+ ~StorageHelper();
+
+public:
+ static HRESULT CreateInstance(StorageHelper **instance);
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_omstoragehelper */
+ HRESULT CreateHandler(const wchar_t *key, HandlerProc proc, ifc_omstoragehandler **handler);
+ HRESULT CreateEnumerator(const TemplateRecord *recordList, size_t recordCount, ifc_omstoragehandlerenum **enumerator);
+
+protected:
+ size_t ref;
+
+protected:
+ RECVS_DISPATCH;
+};
+
+#endif //NULLSOFT_WINAMP_OMSTORAGE_HELPER_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/storageIni.cpp b/Src/omBrowser/storageIni.cpp
new file mode 100644
index 00000000..779396de
--- /dev/null
+++ b/Src/omBrowser/storageIni.cpp
@@ -0,0 +1,317 @@
+#include "main.h"
+#include "./storageIni.h"
+#include "./resource.h"
+#include "./ifc_omservice.h"
+#include "./loaderIni.h"
+#include "./enumIniFile.h"
+#include "./enumAsync.h"
+#include "./ifc_omservicehost.h"
+#include "./ifc_omservicehostext.h"
+#include "./ifc_omstoragehandlerenum.h"
+#include "./ifc_omstorageext.h"
+#include <strsafe.h>
+
+OmStorageIni::OmStorageIni()
+ : ref(1)
+{
+}
+
+OmStorageIni::~OmStorageIni()
+{
+}
+
+HRESULT OmStorageIni::CreateInstance(OmStorageIni **instance)
+{
+ if (NULL == instance) return E_POINTER;
+
+ *instance = new OmStorageIni();
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t OmStorageIni::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t OmStorageIni::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int OmStorageIni::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmStorage))
+ *object = static_cast<ifc_omstorage*>(this);
+ else if (IsEqualIID(interface_guid, STID_OmFileStorage))
+ *object = static_cast<ifc_omfilestorage*>(this);
+ else if (IsEqualIID(interface_guid, SUID_OmStorageIni))
+ *object = static_cast<ifc_omstorage*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT OmStorageIni::GetId(GUID *storageUid)
+{
+ if (NULL == storageUid) return E_POINTER;
+ *storageUid = SUID_OmStorageIni;
+ return S_OK;
+}
+
+HRESULT OmStorageIni::GetType(GUID *storageType)
+{
+ if (NULL == storageType) return E_POINTER;
+ *storageType = STID_OmFileStorage;
+ return S_OK;
+}
+
+UINT OmStorageIni::GetCapabilities()
+{
+ return capLoad | capSave | capDelete | capReload | capPublic;
+}
+
+HRESULT OmStorageIni::GetDescription(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ if (NULL == pszBuffer) return E_POINTER;
+ Plugin_LoadString(IDS_STORAGE_INI, pszBuffer, cchBufferMax);
+ return S_OK;
+}
+
+HRESULT OmStorageIni::Load(LPCWSTR pszAddress, ifc_omservicehost *host, ifc_omserviceenum **ppEnum)
+{
+ if (NULL == ppEnum) return E_POINTER;
+ *ppEnum = NULL;
+
+ if (NULL == pszAddress || L'\0' == *pszAddress)
+ return E_INVALIDARG;
+
+ return EnumIniFile::CreateInstance(pszAddress, host, (EnumIniFile**)ppEnum);
+}
+
+HRESULT OmStorageIni::Save(ifc_omservice **serviceList, ULONG listCount, UINT saveFlags, ULONG *savedCount)
+{
+ if (NULL != savedCount)
+ *savedCount = 0;
+
+ if(NULL == serviceList && 0 != listCount)
+ return E_INVALIDARG;
+
+ HRESULT hr = S_OK;
+ ULONG saved = 0;
+
+ LoaderIni loader;
+
+ for(ULONG i = 0; i < listCount; i++)
+ {
+ ifc_omservice *service = serviceList[i];
+ if (NULL == service) continue;
+
+ if (FAILED(loader.Save(service, saveFlags)))
+ hr = E_FAIL;
+ else
+ saved++;
+ }
+
+ if (NULL != savedCount)
+ *savedCount = saved++;
+
+ return hr;
+}
+
+HRESULT OmStorageIni::Delete(ifc_omservice **serviceList, ULONG listCount, ULONG *deletedCount)
+{
+ if (NULL == serviceList)
+ {
+ if (NULL != deletedCount) *deletedCount = 0;
+ return E_INVALIDARG;
+ }
+
+ WCHAR szBuffer[MAX_PATH * 2] = {0};
+ ULONG deleted = 0;
+
+ for(ULONG i = 0; i < listCount; i++)
+ {
+ if (SUCCEEDED(serviceList[i]->GetAddress(szBuffer, ARRAYSIZE(szBuffer))) &&
+ 0 != DeleteFile(szBuffer))
+ {
+ deleted++;
+ }
+ }
+
+ if (NULL != deletedCount)
+ *deletedCount = deleted;
+
+ return S_OK;
+}
+
+HRESULT OmStorageIni::Reload(ifc_omservice **serviceList, ULONG listCount, ULONG *reloadedCount)
+{
+ if (NULL != reloadedCount)
+ *reloadedCount = 0;
+
+ if(NULL == serviceList && 0 != listCount)
+ return E_INVALIDARG;
+
+ HRESULT hr = S_OK;
+ ULONG loaded = 0;
+
+ LoaderIni loader;
+
+ for(ULONG i = 0; i < listCount; i++)
+ {
+ ifc_omservice *service = serviceList[i];
+ if (NULL == service) continue;
+
+ loader.RegisterHandlers(NULL);
+
+ ifc_omservicehostext *serviceExt = NULL;
+ if (service->QueryInterface(IFC_OmServiceHostExt, (void**)&serviceExt))
+ {
+ ifc_omservicehost *serviceHost = NULL;
+ if (SUCCEEDED(serviceExt->GetHost(&serviceHost)) && serviceHost != NULL)
+ {
+ ifc_omstorageext *storageExt = NULL;
+ if (SUCCEEDED(serviceHost->QueryInterface(IFC_OmStorageExt, (void**)&storageExt)) && storageExt != NULL)
+ {
+ ifc_omstoragehandlerenum *handlerEnum = NULL;
+ if (SUCCEEDED(storageExt->Enumerate(&SUID_OmStorageIni, &handlerEnum)) && handlerEnum != NULL)
+ {
+ loader.RegisterHandlers(handlerEnum);
+ handlerEnum->Release();
+ }
+ storageExt->Release();
+ }
+ serviceHost->Release();
+ }
+ serviceExt->Release();
+ }
+
+ if (FAILED(loader.Reload(service)))
+ hr = E_FAIL;
+ else
+ loaded++;
+ }
+
+ if (NULL != reloadedCount)
+ *reloadedCount = loaded++;
+
+ return hr;
+}
+
+HRESULT OmStorageIni::BeginLoad(LPCWSTR pszAddress, ifc_omservicehost *serviceHost, ifc_omstorageasync::AsyncCallback callback, void *data, ifc_omstorageasync **async)
+{
+ if (NULL == async)
+ return E_POINTER;
+
+ ifc_omserviceenum *enumerator = NULL;
+ HRESULT hr = Load(pszAddress, serviceHost, &enumerator);
+ if (SUCCEEDED(hr) && enumerator != NULL)
+ {
+ EnumAsyncWrapper *asyncWrapper = NULL;
+ hr = EnumAsyncWrapper::CreateInstance(enumerator, &asyncWrapper);
+ if (SUCCEEDED(hr) && asyncWrapper != NULL)
+ {
+ asyncWrapper->SetCallback(callback);
+ asyncWrapper->SetData(data);
+ *async = asyncWrapper;
+
+ hr = asyncWrapper->BeginEnumerate();
+ if (FAILED(hr))
+ {
+ *async = NULL;
+ asyncWrapper->Release();
+ }
+ }
+ enumerator->Release();
+ }
+
+ return hr;
+}
+
+HRESULT OmStorageIni::EndLoad(ifc_omstorageasync *async, ifc_omserviceenum **ppEnum)
+{
+ EnumAsyncWrapper *asyncWrapper = (EnumAsyncWrapper*)async;
+ if (NULL == asyncWrapper) return E_INVALIDARG;
+
+ if (NULL != ppEnum)
+ *ppEnum = NULL;
+
+ UINT state = 0;
+ if (FAILED(async->GetState(&state)) || ifc_omstorageasync::stateCompleted != state)
+ {
+ HANDLE completed = NULL;
+ if (FAILED(async->GetWaitHandle(&completed)))
+ return E_UNEXPECTED;
+
+ while(WAIT_OBJECT_0 != WaitForSingleObjectEx(completed, INFINITE, TRUE));
+ CloseHandle(completed);
+ }
+
+ HRESULT hr = asyncWrapper->GetResultCode();
+ if (SUCCEEDED(hr))
+ {
+ if (NULL != ppEnum)
+ {
+ hr = asyncWrapper->GetServiceList(ppEnum);
+ }
+ }
+ return hr;
+}
+
+HRESULT OmStorageIni::RequestAbort(ifc_omstorageasync *async, BOOL fDrop)
+{
+ EnumAsyncWrapper *asyncWrapper = (EnumAsyncWrapper*)async;
+ if (NULL == asyncWrapper) return E_INVALIDARG;
+ return asyncWrapper->RequestAbort(fDrop);
+}
+
+HRESULT OmStorageIni::GetFilter(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ if (NULL == pszBuffer) return E_POINTER;
+ return StringCchCopy(pszBuffer, cchBufferMax, L"*.ini");
+}
+
+#define CBCLASS OmStorageIni
+START_MULTIPATCH;
+ START_PATCH(MPIID_OMSTORAGE)
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, ADDREF, AddRef);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, RELEASE, Release);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, API_GETID, GetId);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, API_GETTYPE, GetType);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, API_GETCAPABILITIES, GetCapabilities);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, API_GETDESCRIPTION, GetDescription);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, API_LOAD, Load);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, API_SAVE, Save);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, API_DELETE, Delete);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, API_RELOAD, Reload);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, API_BEGINLOAD, BeginLoad);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, API_ENDLOAD, EndLoad);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, API_REQUESTABORT, RequestAbort);
+ NEXT_PATCH(MPIID_OMFILESTORAGE)
+ M_CB(MPIID_OMFILESTORAGE, ifc_omfilestorage, ADDREF, AddRef);
+ M_CB(MPIID_OMFILESTORAGE, ifc_omfilestorage, RELEASE, Release);
+ M_CB(MPIID_OMFILESTORAGE, ifc_omfilestorage, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMFILESTORAGE, ifc_omfilestorage, API_GETFILTER, GetFilter);
+ END_PATCH
+END_MULTIPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/storageIni.h b/Src/omBrowser/storageIni.h
new file mode 100644
index 00000000..ecc497dd
--- /dev/null
+++ b/Src/omBrowser/storageIni.h
@@ -0,0 +1,54 @@
+#ifndef NULLSOFT_WINAMP_OMSTORAGE_INI_HEADER
+#define NULLSOFT_WINAMP_OMSTORAGE_INI_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_omfilestorage.h"
+#include <bfc/multipatch.h>
+
+#define MPIID_OMSTORAGE 10
+#define MPIID_OMFILESTORAGE 20
+
+class OmStorageIni : public MultiPatch<MPIID_OMSTORAGE, ifc_omstorage>,
+ public MultiPatch<MPIID_OMFILESTORAGE, ifc_omfilestorage>
+{
+protected:
+ OmStorageIni();
+ ~OmStorageIni();
+
+public:
+ static HRESULT CreateInstance(OmStorageIni **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_omstorage */
+ HRESULT GetId(GUID *storageUid);
+ HRESULT GetType(GUID *storageType);
+ UINT GetCapabilities();
+ HRESULT GetDescription(LPWSTR pszBuffer, UINT cchBufferMax);
+
+ HRESULT Load(LPCWSTR pszAddress, ifc_omservicehost *host, ifc_omserviceenum **ppEnum);
+ HRESULT Save(ifc_omservice **serviceList, ULONG listCount, UINT saveFlags, ULONG *savedCount);
+ HRESULT Delete(ifc_omservice **serviceList, ULONG listCount, ULONG *deletedCount);
+ HRESULT Reload(ifc_omservice **serviceList, ULONG listCount, ULONG *reloadedCount);
+ HRESULT BeginLoad(LPCWSTR pszAddress, ifc_omservicehost *serviceHost, ifc_omstorageasync::AsyncCallback callback, void *data, ifc_omstorageasync **async);
+ HRESULT EndLoad(ifc_omstorageasync *async, ifc_omserviceenum **ppEnum);
+ HRESULT RequestAbort(ifc_omstorageasync *async, BOOL fDrop);
+
+ /* ifc_omfilestorage */
+ HRESULT GetFilter(LPWSTR pszBuffer, UINT cchBufferMax);
+
+protected:
+ RECVS_MULTIPATCH;
+
+protected:
+ ULONG ref;
+};
+
+#endif //NULLSOFT_WINAMP_OMSTORAGE_INI_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/storageUrl.cpp b/Src/omBrowser/storageUrl.cpp
new file mode 100644
index 00000000..a71ed140
--- /dev/null
+++ b/Src/omBrowser/storageUrl.cpp
@@ -0,0 +1,255 @@
+#include "main.h"
+#include "./storageUrl.h"
+#include "./ifc_omwebstorage.h"
+#include "./resource.h"
+#include "./storageDwnld.h"
+#include "./ifc_omservice.h"
+#include "./ifc_omserviceenum.h"
+#include "./ifc_omservicehost.h"
+#include "./ifc_wasabihelper.h"
+#include "./enumXmlBuffer.h"
+#include "../Components/wac_downloadManager/wac_downloadManager_api.h"
+
+#include <strsafe.h>
+
+OmStorageUrl::OmStorageUrl()
+ : ref(1), manager(NULL)
+{
+}
+
+OmStorageUrl::~OmStorageUrl()
+{
+ if (NULL != manager)
+ {
+ ifc_wasabihelper *wasabi = NULL;
+ if (SUCCEEDED(Plugin_GetWasabiHelper(&wasabi)) && wasabi != NULL)
+ {
+ wasabi->ReleaseWasabiInterface(&DownloadManagerGUID, (void**)&manager);
+ wasabi->Release();
+ }
+ manager = NULL;
+ }
+}
+
+HRESULT OmStorageUrl::CreateInstance(OmStorageUrl **instance)
+{
+ if (NULL == instance) return E_POINTER;
+
+ *instance = new OmStorageUrl();
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t OmStorageUrl::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t OmStorageUrl::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int OmStorageUrl::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmStorage))
+ *object = static_cast<ifc_omstorage*>(this);
+ else if (IsEqualIID(interface_guid, SUID_OmStorageUrl))
+ *object = static_cast<ifc_omstorage*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT OmStorageUrl::GetId(GUID *storageUid)
+{
+ if (NULL == storageUid) return E_POINTER;
+ *storageUid = SUID_OmStorageUrl;
+ return S_OK;
+}
+
+HRESULT OmStorageUrl::GetType(GUID *storageType)
+{
+ if (NULL == storageType) return E_POINTER;
+ *storageType = STID_OmWebStorage;
+ return S_OK;
+}
+
+UINT OmStorageUrl::GetCapabilities()
+{
+ return capLoad | capPublic;
+}
+
+HRESULT OmStorageUrl::GetDescription(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ if (NULL == pszBuffer) return E_POINTER;
+ Plugin_LoadString(IDS_STORAGE_URL, pszBuffer, cchBufferMax);
+ return S_OK;
+}
+
+HRESULT OmStorageUrl::Load(LPCWSTR pszAddress, ifc_omservicehost *host, ifc_omserviceenum **ppEnum)
+{
+ if (NULL == ppEnum) return E_POINTER;
+ *ppEnum = NULL;
+
+ ifc_omstorageasync *async = NULL;
+ HRESULT hr = BeginLoad(pszAddress, host, NULL, NULL, &async);
+ if (SUCCEEDED(hr) && async != NULL)
+ {
+ hr = EndLoad(async, ppEnum);
+ async->Release();
+ }
+
+ return hr;
+}
+
+HRESULT OmStorageUrl::Save(ifc_omservice **serviceList, ULONG listCount, UINT saveFlags, ULONG *savedCount)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT OmStorageUrl::Delete(ifc_omservice **serviceList, ULONG listCount, ULONG *deletedCount)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT OmStorageUrl::BeginLoad(LPCWSTR pszAddress, ifc_omservicehost *serviceHost, ifc_omstorageasync::AsyncCallback callback, void *data, ifc_omstorageasync **async)
+{
+ if (NULL == async) return E_POINTER;
+ *async = NULL;
+
+ if (NULL == pszAddress || L'\0' == *pszAddress)
+ return E_INVALIDARG;
+
+ LPSTR address = Plugin_WideCharToMultiByte(CP_ACP, 0, pszAddress, -1, NULL, NULL);
+ if (NULL == address) return E_OUTOFMEMORY;
+
+ HRESULT hr(S_OK);
+
+ if (NULL == manager)
+ {
+ ifc_wasabihelper *wasabi = NULL;
+ hr = Plugin_GetWasabiHelper(&wasabi);
+ if (SUCCEEDED(hr) && wasabi != NULL)
+ {
+ hr = wasabi->QueryWasabiInterface(&DownloadManagerGUID, (void**)&manager);
+ wasabi->Release();
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ OmStorageDwnld *downloader = NULL;
+ hr = OmStorageDwnld::CreateInstance(manager, TRUE, &downloader);
+ if (SUCCEEDED(hr) && downloader != NULL)
+ {
+ if (NULL != callback) downloader->SetCallback(callback);
+ if (NULL != data) downloader->SetData(data);
+
+ downloader->SetServiceHost(serviceHost);
+ *async = downloader;
+
+ if ( manager->DownloadEx( address, downloader, api_downloadManager::DOWNLOADEX_BUFFER ) == 0 )
+ {
+ hr = E_FAIL;
+ downloader->Release();
+ *async = NULL;
+ }
+ }
+ }
+
+ Plugin_FreeAnsiString(address);
+ return hr;
+}
+
+HRESULT OmStorageUrl::EndLoad(ifc_omstorageasync *async, ifc_omserviceenum **ppEnum)
+{
+ OmStorageDwnld *downloader = (OmStorageDwnld*)async;
+ if (NULL == downloader) return E_INVALIDARG;
+
+ if (NULL != ppEnum)
+ *ppEnum = NULL;
+
+ UINT state = 0;
+ if (FAILED(async->GetState(&state)) || ifc_omstorageasync::stateCompleted != state)
+ {
+ HANDLE completed = NULL;
+ if (FAILED(async->GetWaitHandle(&completed)) || completed == NULL)
+ return E_UNEXPECTED;
+
+ while(WAIT_OBJECT_0 != WaitForSingleObjectEx(completed, INFINITE, TRUE));
+ CloseHandle(completed);
+ }
+
+ HRESULT hr = downloader->GetResultCode();
+ if (SUCCEEDED(hr))
+ {
+ void *buffer = NULL;
+ size_t bufferSize;
+ hr = downloader->GetBuffer(&buffer, &bufferSize);
+ if (SUCCEEDED(hr))
+ {
+ if (NULL != ppEnum)
+ {
+ EnumXmlBuffer *enumerator = NULL;
+ ifc_omservicehost *serviceHost = NULL;
+ if (FAILED(downloader->GetServiceHost(&serviceHost)))
+ serviceHost = NULL;
+
+ hr = EnumXmlBuffer::CreateInstance(buffer, bufferSize, async, serviceHost, &enumerator);
+ if (SUCCEEDED(hr))
+ {
+ *ppEnum = enumerator;
+ }
+
+ if (NULL != serviceHost)
+ serviceHost->Release();
+ }
+ }
+ }
+ return hr;
+}
+
+HRESULT OmStorageUrl::RequestAbort(ifc_omstorageasync *async, BOOL fDrop)
+{
+ OmStorageDwnld *downloader = (OmStorageDwnld*)async;
+ if (NULL == downloader) return E_INVALIDARG;
+
+ return downloader->RequestAbort(fDrop);
+}
+
+#define CBCLASS OmStorageUrl
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_GETID, GetId);
+CB(API_GETTYPE, GetType);
+CB(API_GETCAPABILITIES, GetCapabilities);
+CB(API_GETDESCRIPTION, GetDescription);
+CB(API_LOAD, Load);
+CB(API_SAVE, Save);
+CB(API_DELETE, Delete);
+CB(API_BEGINLOAD, BeginLoad);
+CB(API_ENDLOAD, EndLoad);
+CB(API_REQUESTABORT, RequestAbort);
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/storageUrl.h b/Src/omBrowser/storageUrl.h
new file mode 100644
index 00000000..e270ee70
--- /dev/null
+++ b/Src/omBrowser/storageUrl.h
@@ -0,0 +1,47 @@
+#ifndef NULLSOFT_WINAMP_OMSTORAGE_URL_HEADER
+#define NULLSOFT_WINAMP_OMSTORAGE_URL_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_omwebstorage.h"
+
+class api_downloadManager;
+
+class OmStorageUrl : public ifc_omstorage
+{
+protected:
+ OmStorageUrl();
+ ~OmStorageUrl();
+
+public:
+ static HRESULT CreateInstance(OmStorageUrl **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_omstorage */
+ HRESULT GetId(GUID *storageUid);
+ HRESULT GetType(GUID *storageType);
+ UINT GetCapabilities();
+ HRESULT GetDescription(LPWSTR pszBuffer, UINT cchBufferMax);
+ HRESULT Load(LPCWSTR pszAddress, ifc_omservicehost *host, ifc_omserviceenum **ppEnum);
+ HRESULT Save(ifc_omservice **serviceList, ULONG listCount, UINT saveFlags, ULONG *savedCount);
+ HRESULT Delete(ifc_omservice **serviceList, ULONG listCount, ULONG *deletedCount);
+ HRESULT BeginLoad(LPCWSTR pszAddress, ifc_omservicehost *serviceHost, ifc_omstorageasync::AsyncCallback callback, void *data, ifc_omstorageasync **async);
+ HRESULT EndLoad(ifc_omstorageasync *async, ifc_omserviceenum **ppEnum);
+ HRESULT RequestAbort(ifc_omstorageasync *async, BOOL fDrop);
+
+protected:
+ ULONG ref;
+ api_downloadManager *manager;
+
+protected:
+ RECVS_DISPATCH;
+};
+
+#endif //NULLSOFT_WINAMP_OMSTORAGE_URL_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/storageXml.cpp b/Src/omBrowser/storageXml.cpp
new file mode 100644
index 00000000..c2049f58
--- /dev/null
+++ b/Src/omBrowser/storageXml.cpp
@@ -0,0 +1,146 @@
+#include "main.h"
+#include "./storageXml.h"
+#include "./resource.h"
+
+#include "./ifc_omservice.h"
+#include "./ifc_omserviceenum.h"
+#include "./enumXmlFile.h"
+
+#include <strsafe.h>
+
+OmStorageXml::OmStorageXml()
+ : ref(1)
+{
+}
+
+OmStorageXml::~OmStorageXml()
+{
+}
+
+HRESULT OmStorageXml::CreateInstance(OmStorageXml **instance)
+{
+ if (NULL == instance) return E_POINTER;
+
+ *instance = new OmStorageXml();
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t OmStorageXml::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t OmStorageXml::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int OmStorageXml::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmStorage))
+ *object = static_cast<ifc_omstorage*>(this);
+ else if (IsEqualIID(interface_guid, STID_OmFileStorage))
+ *object = static_cast<ifc_omfilestorage*>(this);
+ else if (IsEqualIID(interface_guid, SUID_OmStorageXml))
+ *object = static_cast<ifc_omstorage*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT OmStorageXml::GetId(GUID *storageUid)
+{
+ if (NULL == storageUid) return E_POINTER;
+ *storageUid = SUID_OmStorageXml;
+ return S_OK;
+}
+
+HRESULT OmStorageXml::GetType(GUID *storageType)
+{
+ if (NULL == storageType) return E_POINTER;
+ *storageType = STID_OmFileStorage;
+ return S_OK;
+}
+
+UINT OmStorageXml::GetCapabilities()
+{
+ return capLoad | capPublic;
+}
+
+HRESULT OmStorageXml::GetDescription(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ if (NULL == pszBuffer) return E_POINTER;
+ Plugin_LoadString(IDS_STORAGE_XML, pszBuffer, cchBufferMax);
+ return S_OK;
+}
+
+HRESULT OmStorageXml::Load(LPCWSTR pszAddress, ifc_omservicehost *host, ifc_omserviceenum **ppEnum)
+{
+ if (NULL == ppEnum) return E_POINTER;
+ *ppEnum = NULL;
+
+ if (NULL == pszAddress || L'\0' == *pszAddress)
+ return E_INVALIDARG;
+
+ return EnumXmlFile::CreateInstance(pszAddress, host, (EnumXmlFile**)ppEnum);
+}
+
+HRESULT OmStorageXml::Save(ifc_omservice **serviceList, ULONG listCount, UINT saveFlags, ULONG *savedCount)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT OmStorageXml::Delete(ifc_omservice **serviceList, ULONG listCount, ULONG *deletedCount)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT OmStorageXml::GetFilter(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ if (NULL == pszBuffer) return E_POINTER;
+ return StringCchCopy(pszBuffer, cchBufferMax, L"*.xml");
+}
+
+#define CBCLASS OmStorageXml
+START_MULTIPATCH;
+ START_PATCH(MPIID_OMSTORAGE)
+
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, ADDREF, AddRef);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, RELEASE, Release);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, API_GETID, GetId);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, API_GETTYPE, GetType);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, API_GETCAPABILITIES, GetCapabilities);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, API_GETDESCRIPTION, GetDescription);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, API_LOAD, Load);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, API_SAVE, Save);
+ M_CB(MPIID_OMSTORAGE, ifc_omstorage, API_DELETE, Delete);
+
+ NEXT_PATCH(MPIID_OMFILESTORAGE)
+ M_CB(MPIID_OMFILESTORAGE, ifc_omfilestorage, ADDREF, AddRef);
+ M_CB(MPIID_OMFILESTORAGE, ifc_omfilestorage, RELEASE, Release);
+ M_CB(MPIID_OMFILESTORAGE, ifc_omfilestorage, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_OMFILESTORAGE, ifc_omfilestorage, API_GETFILTER, GetFilter);
+
+ END_PATCH
+END_MULTIPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/storageXml.h b/Src/omBrowser/storageXml.h
new file mode 100644
index 00000000..9a7d35df
--- /dev/null
+++ b/Src/omBrowser/storageXml.h
@@ -0,0 +1,49 @@
+#ifndef NULLSOFT_WINAMP_OMSTORAGE_XML_HEADER
+#define NULLSOFT_WINAMP_OMSTORAGE_XML_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_omfilestorage.h"
+#include <bfc/multipatch.h>
+
+#define MPIID_OMSTORAGE 10
+#define MPIID_OMFILESTORAGE 20
+
+class OmStorageXml : public MultiPatch<MPIID_OMSTORAGE, ifc_omstorage>,
+ public MultiPatch<MPIID_OMFILESTORAGE, ifc_omfilestorage>
+{
+protected:
+ OmStorageXml();
+ ~OmStorageXml();
+
+public:
+ static HRESULT CreateInstance(OmStorageXml **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_omstorage */
+ HRESULT GetId(GUID *storageUid);
+ HRESULT GetType(GUID *storageType);
+ UINT GetCapabilities();
+ HRESULT GetDescription(LPWSTR pszBuffer, UINT cchBufferMax);
+ HRESULT Load(LPCWSTR pszAddress, ifc_omservicehost *host, ifc_omserviceenum **ppEnum);
+ HRESULT Save(ifc_omservice **serviceList, ULONG listCount, UINT saveFlags, ULONG *savedCount);
+ HRESULT Delete(ifc_omservice **serviceList, ULONG listCount, ULONG *deletedCount);
+
+ /* ifc_omfilestorage */
+ HRESULT GetFilter(LPWSTR pszBuffer, UINT cchBufferMax);
+
+protected:
+ RECVS_MULTIPATCH;
+
+protected:
+ ULONG ref;
+};
+
+#endif //NULLSOFT_WINAMP_OMSTORAGE_XML_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/stringBuilder.cpp b/Src/omBrowser/stringBuilder.cpp
new file mode 100644
index 00000000..fad3c719
--- /dev/null
+++ b/Src/omBrowser/stringBuilder.cpp
@@ -0,0 +1,84 @@
+#include "main.h"
+#include "./stringBuilder.h"
+
+#include <strsafe.h>
+StringBuilder::StringBuilder()
+ : buffer(NULL), cursor(NULL), allocated(0), remaining(0)
+{
+}
+
+StringBuilder::~StringBuilder()
+{
+ Plugin_FreeString(buffer);
+}
+
+HRESULT StringBuilder::Allocate(size_t newSize)
+{
+ if (newSize <= allocated)
+ return S_FALSE;
+
+ LPWSTR t = Plugin_ReAllocString(buffer, newSize);
+ if (NULL == t) return E_OUTOFMEMORY;
+
+ cursor = t + (cursor - buffer);
+ buffer = t;
+
+ remaining += newSize - allocated;
+ allocated = newSize;
+
+ return S_OK;
+}
+
+void StringBuilder::Clear(void)
+{
+ if (NULL != buffer)
+ {
+ buffer[0] = L'\0';
+ }
+ cursor = buffer;
+ remaining = allocated;
+}
+
+LPCWSTR StringBuilder::Get(void)
+{
+ return buffer;
+}
+
+HRESULT StringBuilder::Set(size_t index, WCHAR value)
+{
+ if (NULL == buffer)
+ return E_POINTER;
+
+ if (index >= allocated)
+ return E_INVALIDARG;
+
+ buffer[index] = value;
+ return S_OK;
+}
+
+HRESULT StringBuilder::Append(LPCWSTR pszString)
+{
+ HRESULT hr;
+ if (NULL == buffer)
+ {
+ hr = Allocate(1024);
+ if (FAILED(hr)) return hr;
+ }
+
+ size_t cchCursor = remaining;
+ hr = StringCchCopyEx(cursor, cchCursor, pszString, &cursor, &remaining, STRSAFE_IGNORE_NULLS);
+ if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
+ {
+ size_t offset = cchCursor - remaining;
+ size_t requested = lstrlen(pszString) + (allocated - remaining) + 1;
+ size_t newsize = allocated * 2;
+ while (newsize < requested) newsize = newsize * 2;
+
+ hr = Allocate(newsize);
+ if (FAILED(hr)) return hr;
+
+ hr = StringCchCopyEx(cursor, remaining, pszString + offset, &cursor, &remaining, STRSAFE_IGNORE_NULLS);
+ }
+
+ return hr;
+} \ No newline at end of file
diff --git a/Src/omBrowser/stringBuilder.h b/Src/omBrowser/stringBuilder.h
new file mode 100644
index 00000000..76d22182
--- /dev/null
+++ b/Src/omBrowser/stringBuilder.h
@@ -0,0 +1,30 @@
+#ifndef NULLSOFT_WINAMP_STRING_BUILDER_HEADER
+#define NULLSOFT_WINAMP_STRING_BUILDER_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+class StringBuilder
+{
+public:
+ StringBuilder();
+ ~StringBuilder();
+
+public:
+ HRESULT Allocate(size_t newSize);
+ void Clear(void);
+ LPCWSTR Get(void);
+ HRESULT Set(size_t index, WCHAR value);
+ HRESULT Append(LPCWSTR pszString);
+
+protected:
+ LPWSTR buffer;
+ LPWSTR cursor;
+ size_t allocated;
+ size_t remaining;
+};
+
+#endif //NULLSOFT_WINAMP_STRING_BUILDER_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/toolbar.cpp b/Src/omBrowser/toolbar.cpp
new file mode 100644
index 00000000..d1a0d78c
--- /dev/null
+++ b/Src/omBrowser/toolbar.cpp
@@ -0,0 +1,3572 @@
+#include "main.h"
+#include "./toolbar.h"
+#include "./graphics.h"
+#include "./resource.h"
+#include "./toolbarItem.h"
+#include "./toolbarStatic.h"
+#include "./toolbarButton.h"
+#include "./toolbarRating.h"
+#include "./toolbarProgress.h"
+#include "./toolbarAddress.h"
+#include "../winamp/wa_dlg.h"
+#include "../Plugins/General/gen_ml/ml_ipc_0313.h"
+#include "./ifc_imageloader.h"
+#include "./ifc_skinhelper.h"
+#include "./ifc_omservice.h"
+#include "./ifc_omservicecommand.h"
+#include "./menu.h"
+#include "./ifc_wasabihelper.h"
+
+#include "./browserUiCommon.h"
+
+
+#include <windows.h>
+#include <shlwapi.h>
+#include <commctrl.h>
+#include <strsafe.h>
+#include <vector>
+
+#define TOOLBAR_SPACE_LEFT 0
+#define TOOLBAR_SPACE_TOP 4
+#define TOOLBAR_SPACE_RIGHT 1
+#define TOOLBAR_SPACE_BOTTOM 3
+
+#define TOOLBAR_HIDDENHEIGHT 3
+
+#define TOOLBAR_ICONSTATE_NORMAL 0
+#define TOOLBAR_ICONSTATE_HIGHLIGHTED 1
+#define TOOLBAR_ICONSTATE_PRESSED 2
+#define TOOLBAR_ICONSTATE_DISABLED 3
+#define TOOLBAR_ICONSTATE_COUNT 4
+
+#define TBS_MENULOOP 0x00000001
+#define TBS_HIDDEN 0x00000002
+#define TBS_HIDETIMERSET 0x00000004
+#define TBS_NOFOCUSRECT 0x00000008
+
+#define ICON_NONE (-1)
+#define ICON_CHEVRON (-2) // - resolved on the fly
+#define ICON_SEPARATOR 0
+#define ICON_CHEVRON_BOTTOM 1
+#define ICON_CHEVRON_TOP 2
+#define ICON_BACK 3
+#define ICON_FORWARD 4
+#define ICON_REFRESH 5
+#define ICON_STOP 6
+#define ICON_HOME 7
+#define ICON_ERROR 8
+#define ICON_LOCK 9
+#define ICON_HISTORY 10
+#define ICON_ADDRESSBAR 11
+
+#define ICON_SEPARATOR_WIDTH 6
+#define ICON_CHEVRON_WIDTH 13
+#define ICON_HISTORY_WIDTH 9
+#define ICON_ARROW_WIDTH 17
+
+#define TOOLBRUSH_BACK 0
+#define TOOLBRUSH_FRAME 1
+#define TOOLBRUSH_ITEMBK 2
+#define TOOLBRUSH_LAST TOOLBRUSH_ITEMBK
+
+#define ID_CHEVRON_CLICKED 1
+
+#define TOOLBAR_BKCOLOR WADLG_LISTHEADER_BGCOLOR
+#define TOOLBAR_FGCOLOR WADLG_LISTHEADER_FONTCOLOR
+
+#define EDIT_ALPHA 50
+#define TEXT_ALPHA 127
+#define HIGHLIGHT_ALPHA 160
+#define TIMER_AUTOHIDE_ID 14
+#define TIMER_AUTOHIDE_DELAY 300
+
+#define AUTOHIDE_ANIMATETIME 200
+
+typedef std::vector<ToolbarItem*> ItemList;
+
+typedef struct __TOOLBAR
+{
+ UINT ref;
+ UINT flags;
+ HBRUSH szBrushes[TOOLBRUSH_LAST + 1];
+ HIMAGELIST imageList;
+ HFONT textFont;
+ ItemList *items;
+ ToolbarItem *chevron;
+ ToolbarItem *pressed;
+ ToolbarItem *highlighted;
+ UINT resolveCache;
+ HFONT ownedFont;
+ HWND hTooltip;
+ COLORREF rgbBk;
+ COLORREF rgbFg;
+ COLORREF rgbText;
+ COLORREF rgbHilite;
+ COLORREF rgbFrame;
+ COLORREF rgbEdit;
+ COLORREF rgbEditBk;
+ size_t iFocused;
+ HWND hBrowser;
+ TOOLBARTEXTMETRIC textMetric;
+} TOOLBAR;
+
+typedef struct __TOOLBARMOUSEHOOK
+{
+ HHOOK hHook;
+ HWND hwnd;
+} TOOLBARMOUSEHOOK;
+
+static size_t tlsIndex = TLS_OUT_OF_INDEXES;
+
+typedef ToolbarItem *(CALLBACK *TOOLBARITEMFACTORY)(ToolbarItem::Template * /*itemTemplate*/);
+
+typedef struct __TOOLBARITEMCLASS
+{
+ LPCSTR name;
+ TOOLBARITEMFACTORY creator;
+ LPCWSTR text;
+ LPCWSTR description;
+ INT iconId;
+ INT commandId;
+ UINT style;
+} TOOLBARITEMCLASS;
+
+#define REGISTER_ITEM(__name, __creator, __textId, __descriptionId, __iconId, __commandId, __style)\
+ { (__name), (__creator), MAKEINTRESOURCE(__textId),\
+ MAKEINTRESOURCE(__descriptionId), (__iconId), (__commandId), (__style) }
+
+#define REGISTER_STATIC(__name, __textId, __descriptionId, __iconId, __style)\
+ REGISTER_ITEM(__name, ToolbarStatic::CreateInstance, __textId, __descriptionId, __iconId, 0, __style)
+
+#define REGISTER_BUTTON(__name, __textId, __descriptionId, __iconId, __commandId, __style)\
+ REGISTER_ITEM(__name, ToolbarButton::CreateInstance, __textId, __descriptionId, __iconId, __commandId, __style)
+
+#define REGISTER_RATING(__name, __textId, __descriptionId, __style)\
+ REGISTER_ITEM(__name, ToolbarRating::CreateInstance, __textId, __descriptionId, ICON_NONE, 0, __style)
+
+#define REGISTER_PROGRESS(__name, __textId, __descriptionId, __style)\
+ REGISTER_ITEM(__name, ToolbarProgress::CreateInstance, __textId, __descriptionId, ICON_NONE, 0, __style)
+
+#define REGISTER_ADDRESSBAR(__name, __style)\
+ REGISTER_ITEM(__name, ToolbarAddress::CreateInstance, NULL, NULL, ICON_NONE, 0, __style)
+
+const static TOOLBARITEMCLASS szRegisteredToolItems[] =
+{
+ REGISTER_STATIC(TOOLITEM_SEPARATOR, IDS_SEPARATOR, 0, ICON_SEPARATOR, ToolbarStatic::styleSeparator),
+ REGISTER_STATIC(TOOLITEM_SPACE, IDS_SPACE, 0, ICON_NONE, ToolbarStatic::styleSpacer),
+ REGISTER_STATIC(TOOLITEM_FLEXSPACE, IDS_FLEXSPACE, 0, ICON_NONE, ToolbarStatic::styleSpacer | ToolbarItem::styleFlexible),
+ REGISTER_RATING(TOOLITEM_USERRATING, IDS_RATED, NULL, ToolbarItem::styleWantKey),
+ REGISTER_PROGRESS(TOOLITEM_DOWNLOADPROGRESS, NULL, NULL, ToolbarItem::stateDisabled),
+ REGISTER_ADDRESSBAR(TOOLITEM_ADDRESSBAR, ToolbarItem::styleFlexible | ToolbarItem::styleWantKey | ToolbarItem::styleTabstop),
+
+ REGISTER_BUTTON(TOOLITEM_CHEVRON, IDS_MORE, IDS_MORE_DESCRIPTION, ICON_CHEVRON,
+ ID_CHEVRON_CLICKED, ToolbarItem::styleWantKey),
+ REGISTER_BUTTON(TOOLITEM_BUTTON_HOME, IDS_HOME, IDS_HOME_DESCRIPTION, ICON_HOME,
+ ID_NAVIGATION_HOME, ToolbarItem::styleWantKey),
+ REGISTER_BUTTON(TOOLITEM_BUTTON_BACK, IDS_BACK, IDS_BACK_DESCRIPTION, ICON_BACK,
+ ID_NAVIGATION_BACK, ToolbarItem::styleWantKey),
+ REGISTER_BUTTON(TOOLITEM_BUTTON_FORWARD, IDS_FORWARD, IDS_FORWARD_DESCRIPTION, ICON_FORWARD,
+ ID_NAVIGATION_FORWARD, ToolbarItem::styleWantKey),
+ REGISTER_BUTTON(TOOLITEM_BUTTON_STOP, IDS_STOP, IDS_STOP_DESCRIPTION, ICON_STOP,
+ ID_NAVIGATION_STOP, ToolbarItem::styleWantKey),
+ REGISTER_BUTTON(TOOLITEM_BUTTON_REFRESH, IDS_REFRESH, IDS_REFRESH_DESCRIPTION, ICON_REFRESH,
+ ID_NAVIGATION_REFRESH, ToolbarItem::styleWantKey),
+ REGISTER_BUTTON(TOOLITEM_BUTTON_HISTORY, IDS_HISTORY, IDS_HISTORY_DESCRIPTION, ICON_HISTORY,
+ ID_NAVIGATION_HISTORY, ToolbarItem::styleWantKey),
+
+ REGISTER_BUTTON(TOOLITEM_CMDLINK_INFO, IDS_SERVICE_GETINFO, IDS_SERVICE_GETINFO_DESCRIPTION, ICON_NONE,
+ ID_SERVICE_GETINFO, ToolbarItem::styleWantKey | ToolbarButton::styleCommandLink),
+ REGISTER_BUTTON(TOOLITEM_CMDLINK_REPORT, IDS_SERVICE_REPORT, IDS_SERVICE_REPORT_DESCRIPTION, ICON_NONE,
+ ID_SERVICE_REPORT, ToolbarItem::styleWantKey | ToolbarButton::styleCommandLink),
+ REGISTER_BUTTON(TOOLITEM_CMDLINK_UNSUBSCRIBE, IDS_SERVICE_UNSUBSCRIBE, IDS_SERVICE_UNSUBSCRIBE_DESCRIPTION, ICON_NONE,
+ ID_SERVICE_UNSUBSCRIBE, ToolbarItem::styleWantKey | ToolbarButton::styleCommandLink),
+
+ REGISTER_BUTTON(TOOLITEM_BUTTON_SECURECONNECTION, IDS_SECURE_CONNECTION, IDS_SECURE_CONNECTION, ICON_LOCK,
+ ID_BROWSER_SECURECONNECTION, ToolbarItem::styleWantKey),
+
+ REGISTER_BUTTON(TOOLITEM_BUTTON_SCRIPTERROR, IDS_SCRIPT_ERROR, IDS_SCRIPT_ERROR_DESCRIPTION, ICON_ERROR,
+ ID_BROWSER_SCRIPTERROR, ToolbarItem::styleWantKey),
+
+
+
+};
+
+#define GetToolbar(__hwnd) ((TOOLBAR*)(LONG_PTR)(LONGX86)GetWindowLongPtr((__hwnd), 0))
+static LRESULT CALLBACK Toolbar_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static LRESULT CALLBACK Toolbar_MouseHook(INT code, WPARAM wParam, LPARAM lParam);
+
+
+typedef struct __TOOLBARITEMINSERTREC
+{
+ LPCSTR name;
+ UINT style;
+} TOOLBARITEMINSERTREC;
+
+BOOL Toolbar_RegisterClass(HINSTANCE hInstance)
+{
+ WNDCLASS wc;
+ ATOM klassAtom;
+ ifc_wasabihelper *wasabi;
+
+ if (GetClassInfo(hInstance, NWC_ONLINEMEDIATOOLBAR, &wc))
+ return TRUE;
+
+ ZeroMemory(&wc, sizeof(WNDCLASS));
+
+ wc.hInstance = hInstance;
+ wc.lpszClassName = NWC_ONLINEMEDIATOOLBAR;
+ wc.lpfnWndProc = Toolbar_WindowProc;
+ wc.style = 0;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = NULL;
+ wc.cbWndExtra = sizeof(TOOLBAR*);
+
+ klassAtom = RegisterClassW(&wc);
+ if (0 == klassAtom)
+ return FALSE;
+
+ if (SUCCEEDED(Plugin_GetWasabiHelper(&wasabi)))
+ {
+ api_application *application;
+ if (SUCCEEDED(wasabi->GetApplicationApi(&application)))
+ {
+ application->DirectMouseWheel_RegisterSkipClass(klassAtom);
+ application->Release();
+ }
+ wasabi->Release();
+ }
+ return TRUE;
+}
+
+static BOOL Toolbar_ClearItems(TOOLBAR *toolbar)
+{
+ if (NULL == toolbar) return FALSE;
+ if (NULL == toolbar->items) return TRUE;
+
+ size_t index = toolbar->items->size();
+
+ while(index--)
+ {
+ ToolbarItem *item = toolbar->items->at(index);
+ if (NULL != item) item->Release();
+ }
+ toolbar->items->clear();
+ return TRUE;
+
+}
+static ULONG Toolbar_AddRef(TOOLBAR *toolbar)
+{
+ if (NULL == toolbar) return 0;
+ return InterlockedIncrement((LONG*)&toolbar->ref);
+}
+
+static ULONG Toolbar_Release(TOOLBAR *toolbar)
+{
+ if (0 == toolbar || 0 == toolbar->ref) return 0;
+ LONG r = InterlockedDecrement((LONG*)&toolbar->ref);
+ if (0 == r)
+ {
+ if (NULL != toolbar->hTooltip)
+ DestroyWindow(toolbar->hTooltip);
+
+ if (NULL != toolbar->chevron)
+ toolbar->chevron->Release();
+
+ if (NULL != toolbar->items)
+ {
+ Toolbar_ClearItems(toolbar);
+ delete(toolbar->items);
+ }
+
+ if (NULL != toolbar->imageList)
+ ImageList_Destroy(toolbar->imageList);
+
+ if (NULL != toolbar->ownedFont)
+ DeleteObject(toolbar->ownedFont);
+
+
+ free(toolbar);
+ }
+ return r;
+}
+
+static const TOOLBARITEMCLASS *Toolbar_FindClass(LPCSTR pszName)
+{
+ if (NULL == pszName) return NULL;
+
+ for (INT i =0; i < ARRAYSIZE(szRegisteredToolItems); i++)
+ {
+ if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, NORM_IGNORECASE,
+ szRegisteredToolItems[i].name, -1, pszName, -1))
+ {
+ return &szRegisteredToolItems[i];
+ }
+ }
+ return NULL;
+}
+
+static ToolbarItem* Toolbar_CreateItem(LPCSTR pszName, UINT styleOverride)
+{
+ const TOOLBARITEMCLASS *iClass = Toolbar_FindClass(pszName);
+ if (NULL == iClass || NULL == iClass->creator)
+ return NULL;
+
+ ToolbarItem::Template iTemplate;
+ ZeroMemory(&iTemplate, sizeof(ToolbarItem::Template));
+
+ iTemplate.name = iClass->name;
+ iTemplate.text = iClass->text;
+ iTemplate.description= iClass->description;
+ iTemplate.iconId = iClass->iconId;
+ iTemplate.commandId = iClass->commandId;
+ iTemplate.style = iClass->style | styleOverride;
+ return iClass->creator(&iTemplate);
+}
+
+static BOOL Toolbar_GetClientRect(HWND hwnd, RECT *prc)
+{
+ if (!GetClientRect(hwnd, prc))
+ return FALSE;
+ prc->left += TOOLBAR_SPACE_LEFT;
+ prc->right -= TOOLBAR_SPACE_RIGHT;
+
+ if (0 != (TBS_BOTTOMDOCK & GetWindowLongPtr(hwnd, GWL_STYLE)))
+ {
+ prc->top += TOOLBAR_SPACE_TOP;
+ prc->bottom -= TOOLBAR_SPACE_BOTTOM;
+ }
+ else
+ {
+ prc->top += TOOLBAR_SPACE_BOTTOM;
+ prc->bottom -= TOOLBAR_SPACE_TOP;
+ }
+ return TRUE;
+}
+static void Toolbar_UpdateColorTable(HWND hwnd, ifc_skinhelper *skinHelper)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ if (NULL == skinHelper || FAILED(skinHelper->GetColor(TOOLBAR_BKCOLOR, &toolbar->rgbBk)))
+ toolbar->rgbBk = GetSysColor(COLOR_WINDOW);
+
+ if (NULL == skinHelper || FAILED(skinHelper->GetColor(TOOLBAR_FGCOLOR, &toolbar->rgbFg)))
+ toolbar->rgbFg = GetSysColor(COLOR_WINDOWTEXT);
+
+ COLORREF rgbItemBk;
+ if (NULL == skinHelper || FAILED(skinHelper->GetColor(WADLG_ITEMBG, &rgbItemBk)))
+ rgbItemBk = GetSysColor(COLOR_WINDOW);
+
+ COLORREF rgbItem;
+ if (NULL == skinHelper || FAILED(skinHelper->GetColor(WADLG_ITEMFG, &rgbItem)))
+ rgbItem = GetSysColor(COLOR_WINDOWTEXT);
+
+ if (NULL != skinHelper)
+ {
+ const INT szFrameColors[] =
+ {
+ WADLG_HILITE,
+ WADLG_LISTHEADER_FRAME_MIDDLECOLOR,
+ WADLG_LISTHEADER_FRAME_BOTTOMCOLOR,
+ WADLG_LISTHEADER_FRAME_TOPCOLOR,
+ };
+
+ for (INT i = 0; i < ARRAYSIZE(szFrameColors); i++)
+ {
+ if (SUCCEEDED(skinHelper->GetColor(szFrameColors[i], &toolbar->rgbFrame)))
+ toolbar->rgbFrame = GetSysColor(COLOR_GRAYTEXT);
+
+ INT distance = GetColorDistance(toolbar->rgbFrame, rgbItemBk);
+ if (distance < 0) distance = -distance;
+ if (distance >= 40) break;
+ }
+ }
+ else
+ toolbar->rgbFrame = GetSysColor(COLOR_GRAYTEXT);
+
+ toolbar->rgbEdit = BlendColors(toolbar->rgbBk, rgbItem, EDIT_ALPHA);
+ toolbar->rgbEditBk = BlendColors(toolbar->rgbBk, rgbItemBk, EDIT_ALPHA);
+ toolbar->rgbText = BlendColors(toolbar->rgbFg, toolbar->rgbBk, TEXT_ALPHA);
+ toolbar->rgbHilite = BlendColors(toolbar->rgbFg, toolbar->rgbBk, HIGHLIGHT_ALPHA);
+
+}
+static void Toolbar_UpdateTextMetrics(HWND hwnd)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ ZeroMemory(&toolbar->textMetric, sizeof(TOOLBARTEXTMETRIC));
+
+ RECT clientRect;
+ if (!Toolbar_GetClientRect(hwnd, &clientRect))
+ return;
+
+ INT iconCX, iconCY;
+ if (NULL == toolbar->imageList ||
+ FALSE == ImageList_GetIconSize(toolbar->imageList, &iconCX, &iconCY))
+ {
+ iconCX = 0;
+ iconCY = 0;
+ }
+ else
+ {
+ iconCY = iconCY / TOOLBAR_ICONSTATE_COUNT;
+ }
+
+
+ HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
+ if (NULL == hdc) return;
+
+ HFONT originalFont = (HFONT)SelectObject(hdc, toolbar->textFont);
+
+ TEXTMETRIC tm;
+ if (GetTextMetrics(hdc, &tm))
+ {
+ toolbar->textMetric.height = tm.tmHeight;
+ toolbar->textMetric.aveCharWidth = tm.tmAveCharWidth;
+ toolbar->textMetric.overhang = tm.tmOverhang;
+
+ INT clientHeight = clientRect.bottom - clientRect.top;
+ if (tm.tmHeight >= iconCY)
+ {
+ toolbar->textMetric.baseY = tm.tmAscent - tm.tmInternalLeading;
+ INT t = clientHeight - toolbar->textMetric.baseY;
+ toolbar->textMetric.origY = clientRect.top + t/2;
+ if (0 != t%2)
+ {
+ toolbar->textMetric.origY += 1;
+ toolbar->textMetric.baseY += 1;
+ }
+ }
+ else
+ {
+ toolbar->textMetric.baseY = (clientHeight - iconCY)/2;
+ if (tm.tmDescent > toolbar->textMetric.baseY)
+ toolbar->textMetric.baseY = tm.tmDescent;
+ //toolbar->textMetric.baseY += 8;
+ toolbar->textMetric.baseY = clientHeight - toolbar->textMetric.baseY;
+ toolbar->textMetric.origY = (clientRect.top + toolbar->textMetric.baseY + tm.tmDescent) - tm.tmHeight;
+ toolbar->textMetric.baseY -= toolbar->textMetric.origY;
+ }
+ }
+
+ SelectObject(hdc, originalFont);
+ ReleaseDC(hwnd, hdc);
+}
+static HIMAGELIST Toolbar_LoadImagelist(TOOLBAR *toolbar, HINSTANCE hInstance, LPCWSTR pszPath, INT iconWidth, INT iconStatesCount)
+{
+ if (iconWidth <= 0 || iconStatesCount <= 0 || NULL == pszPath)
+ return NULL;
+
+ HBITMAP bitmap = NULL;
+
+ ifc_omimageloader *loader;
+ if (SUCCEEDED(Plugin_QueryImageLoader(hInstance, pszPath, FALSE, &loader)))
+ {
+ loader->LoadBitmap(&bitmap, NULL, NULL);
+ loader->Release();
+ }
+
+ DIBSECTION dib;
+ if (NULL == bitmap ||
+ sizeof(DIBSECTION) != GetObject(bitmap, sizeof(DIBSECTION), &dib))
+ {
+ if (NULL != bitmap) DeleteObject(bitmap);
+ return NULL;
+ }
+
+ if (dib.dsBm.bmHeight < 0) dib.dsBm.bmHeight = -dib.dsBm.bmHeight;
+
+ Image_Colorize((BYTE*)dib.dsBm.bmBits, dib.dsBm.bmWidth, dib.dsBm.bmHeight, dib.dsBm.bmBitsPixel,
+ ColorAdjustLuma(toolbar->rgbBk, -140, TRUE), toolbar->rgbFg, FALSE);
+
+ Image_BlendOnColorEx((BYTE*)dib.dsBm.bmBits, dib.dsBm.bmWidth, dib.dsBm.bmHeight,
+ 0, 0, dib.dsBm.bmWidth, dib.dsBm.bmHeight, dib.dsBm.bmBitsPixel, FALSE, toolbar->rgbBk);
+
+
+ if (iconWidth > dib.dsBm.bmWidth) iconWidth = dib.dsBm.bmWidth;
+
+ INT iconHeight = dib.dsBm.bmHeight / iconStatesCount;
+ INT initial = dib.dsBm.bmWidth / iconWidth;
+
+ HIMAGELIST himl = ImageList_Create(iconWidth, iconHeight * iconStatesCount, ILC_COLOR24, initial, 1);
+ if (NULL != himl)
+ {
+ INT index = ImageList_Add(himl, bitmap, NULL);
+ if (-1 == index)
+ {
+ ImageList_Destroy(himl);
+ himl = NULL;
+ }
+ }
+ DeleteObject(bitmap);
+ return himl;
+}
+
+static LONG Toolbar_ShowChevron(HWND hwnd, const RECT *prcClient) // return client cx change
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL != toolbar && NULL != toolbar->chevron && toolbar->chevron->IsRectEmpty())
+ {
+ RECT chevronRect;
+ CopyRect(&chevronRect, prcClient);
+ if (toolbar->chevron->AdjustRect(hwnd, &chevronRect))
+ {
+ chevronRect.left = prcClient->right - (chevronRect.right - chevronRect.left);
+ chevronRect.right = prcClient->right;
+ if (toolbar->chevron->SetRect(&chevronRect))
+ return (chevronRect.left - prcClient->right);
+ }
+ }
+ return 0;
+}
+
+static ToolbarItem *Toolbar_GetItem(TOOLBAR *toolbar, size_t index)
+{
+ if (NULL == toolbar || NULL == toolbar->items)
+ return NULL;
+
+ size_t count = toolbar->items->size();
+
+ if (index < count)
+ return toolbar->items->at(index);
+ if (index == count)
+ return toolbar->chevron;
+
+ return NULL;
+}
+
+static BOOL Toolbar_IsItemAcceptFocus(ToolbarItem *item, BOOL fTabstopOnly)
+{
+ if (NULL == item)
+ return FALSE;
+
+ UINT itemStyle = item->GetStyle();
+ if (0 != ((ToolbarItem::stateDisabled | ToolbarItem::stateHidden) & itemStyle))
+ return FALSE;
+
+ UINT mask = ToolbarItem::styleTabstop;
+ if (FALSE == fTabstopOnly) mask |= ToolbarItem::styleWantKey;
+ if (0 == (mask & itemStyle))
+ return FALSE;
+
+ return (FALSE == item->IsRectEmpty());
+}
+
+static void Toolbar_UpdateTabstop(HWND hwnd)
+{
+ BOOL fEnable = FALSE;
+ UINT windowStyle = GetWindowStyle(hwnd);
+
+ if (0 != (TBS_TABSTOP & windowStyle))
+ {
+ fEnable = TRUE;
+ }
+ else
+ {
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL != toolbar && NULL != toolbar->items)
+ {
+ size_t index = toolbar->items->size();
+ while(index--)
+ {
+ if (FALSE != Toolbar_IsItemAcceptFocus(toolbar->items->at(index), TRUE))
+ {
+ fEnable = TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ if (FALSE != fEnable)
+ {
+ if (0 == (WS_TABSTOP & windowStyle))
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle | WS_TABSTOP);
+ }
+ else
+ {
+ if (0 != (WS_TABSTOP & windowStyle))
+ {
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle & ~WS_TABSTOP);
+ }
+ }
+}
+static INT Toolbar_InsertItemInternal(TOOLBAR *toolbar, ToolbarItem *item, INT insertBefore, HWND hwnd)
+{
+ if (NULL == toolbar || NULL == toolbar->items || NULL == item)
+ return ITEM_ERR;
+
+ INT index = ITEM_ERR;
+
+ if (TBIP_FIRST == insertBefore)
+ {
+ toolbar->items->insert(toolbar->items->begin(), item);
+ index = 0;
+ }
+ else if (TBIP_LAST == insertBefore)
+ {
+ toolbar->items->push_back(item);
+ index = ((INT)toolbar->items->size() - 1);
+ }
+ else
+ {
+ if (insertBefore < 0) insertBefore = 0;
+ else if (insertBefore >= (INT)toolbar->items->size()) insertBefore = (INT)toolbar->items->size();
+ toolbar->items->insert(toolbar->items->begin() + insertBefore, item);
+ index = insertBefore;
+ }
+
+ if (ITEM_ERR != index)
+ {
+ item->AddRef();
+ item->UpdateSkin(hwnd);
+ }
+
+ return index;
+}
+
+static size_t Toolbar_GetFocusIndex(HWND hwnd, size_t focusIndex, INT searchDirection, BOOL fTabstopOnly)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar || NULL == toolbar->items || 0 == toolbar->items->size())
+ return ((size_t)-1);
+
+
+ ToolbarItem *item = Toolbar_GetItem(toolbar, focusIndex);
+ if (NULL != item && Toolbar_IsItemAcceptFocus(item, fTabstopOnly))
+ return focusIndex;
+
+ if (0 == searchDirection)
+ return ((size_t)-1);
+
+ if (searchDirection > 0)
+ {
+ size_t count = toolbar->items->size();
+ size_t i = focusIndex + 1;
+ for (; i < count; i++)
+ {
+ if (Toolbar_IsItemAcceptFocus(toolbar->items->at(i), fTabstopOnly))
+ return i;
+ }
+ if (i == count && Toolbar_IsItemAcceptFocus(toolbar->chevron, fTabstopOnly))
+ return i;
+ }
+ else
+ {
+ size_t count = toolbar->items->size();
+ if (focusIndex == count && Toolbar_IsItemAcceptFocus(toolbar->chevron, fTabstopOnly))
+ return count;
+
+ size_t i = focusIndex;
+ if (i <= count)
+ {
+ while(i--)
+ {
+ if (Toolbar_IsItemAcceptFocus(toolbar->items->at(i), fTabstopOnly))
+ return i;
+ }
+ }
+ }
+
+ return ((size_t)-1);
+}
+
+static void Toolbar_OffsetItems(ToolbarItem **itemList, INT count, INT offsetX, INT offsetY)
+{
+ while(count-- > 0)
+ {
+ if (NULL != itemList[count])
+ itemList[count]->OffsetRect(offsetX, offsetY);
+ }
+}
+static void Toolbar_HideItems(ToolbarItem **itemList, INT count, INT *chevronItemCount)
+{
+ INT chevronItems = 0;
+ while(count-- > 0)
+ {
+ if (NULL != itemList[count])
+ {
+ if (0 == (ToolbarItem::styleNoChevron & itemList[count]->GetStyle()))
+ chevronItems++;
+ itemList[count]->SetRectEmpty();
+ }
+ }
+
+ if (NULL != chevronItemCount)
+ *chevronItemCount = chevronItems;
+}
+
+static LONG Toolbar_CutoffItems(ToolbarItem **itemList, INT count, LONG cutoffCX)
+{
+ RECT elementRect;
+ LONG left = cutoffCX;
+ ToolbarItem *item;
+ while(count-- > 0)
+ {
+ item = itemList[count];
+ if (NULL == item)
+ continue;
+
+ DWORD style = item->GetStyle();
+ if (0 == (ToolbarItem::styleChevronOnly & style) &&
+ (0 == (ToolbarItem::stateHidden & style) || 0 == (ToolbarItem::stylePopup & style)) &&
+ item->GetRect(&elementRect))
+ {
+ if (elementRect.right <= cutoffCX)
+ return elementRect.right;
+
+ if (0 == count)
+ left = elementRect.left;
+
+ item->SetRectEmpty();
+ }
+ }
+ return left;
+}
+
+static LONG Toolbar_CalculateClient(HWND hwnd, ToolbarItem **itemList, INT count, const RECT *prcClient, INT *deltaCX)
+{
+ ToolbarItem *item;
+ RECT elementRect;
+ INT index;
+ UINT style;
+ LONG elementLeft = prcClient->left;
+
+ for (index = 0; index < count; index++)
+ {
+ item = itemList[index];
+ if (NULL != item)
+ {
+ style = item->GetStyle();
+ if (0 != (ToolbarItem::styleChevronOnly & style) ||
+ (0 != (ToolbarItem::stateHidden & style) && 0!= (ToolbarItem::stylePopup & style)))
+ {
+ item->SetRectEmpty();
+ continue;
+ }
+
+ CopyRect(&elementRect, prcClient);
+ elementRect.left = elementLeft;
+
+ if (0 != (ToolbarItem::styleFlexible & style))
+ {
+ RECT testRect;
+ INT flexMinimum = 0;
+ SetRect(&testRect, elementRect.left, elementRect.top, elementRect.left, elementRect.bottom);
+ if (item->AdjustRect(hwnd, &testRect) && testRect.right > elementRect.left)
+ {
+ flexMinimum = (testRect.right - elementRect.left);
+ }
+
+ if (index != (count -1))
+ {
+ INT delta = 0;
+ INT section;
+
+ if ((elementRect.left + flexMinimum) < prcClient->right)
+ {
+ CopyRect(&testRect, &elementRect);
+ testRect.left += flexMinimum;
+
+ section = Toolbar_CalculateClient(hwnd, itemList + (index + 1),
+ count - index - 1, &testRect, &delta);
+ }
+ else
+ {
+ section = prcClient->right - (elementRect.left + flexMinimum);
+ }
+
+ if (section < 0)
+ { // we need to move back
+ item->SetRectEmpty();
+ elementLeft += (flexMinimum - section);
+ if (index > 0)
+ elementLeft = Toolbar_CutoffItems(itemList, index, elementLeft);
+ return (elementLeft - prcClient->left);
+ }
+
+ if (NULL != deltaCX)
+ *deltaCX += delta;
+
+ elementRect.right = elementRect.right - section + delta;
+ if (elementRect.right < elementRect.left)
+ elementRect.right = elementRect.left;
+ }
+
+ if (item->AdjustRect(hwnd, &elementRect))
+ {
+ item->SetRect(&elementRect);
+ Toolbar_OffsetItems(itemList + (index + 1), count - index - 1, elementRect.right - elementRect.left - flexMinimum, 0);
+ elementLeft = prcClient->right;
+ break;
+ }
+ }
+
+ if (item->AdjustRect(hwnd, &elementRect))
+ {
+ if (elementRect.right > prcClient->right)
+ {
+ INT chevronItems;
+ Toolbar_HideItems(itemList + index, count - index, &chevronItems);
+
+ if (chevronItems > 0)
+ {
+ LONG delta = Toolbar_ShowChevron(hwnd, prcClient);
+ if (NULL != deltaCX) *deltaCX += delta;
+ elementLeft = (index > 0) ?
+ Toolbar_CutoffItems(itemList, index, prcClient->right + delta) :
+ (prcClient->left + delta);
+ }
+ break;
+ }
+
+ item->SetRect(&elementRect);
+ elementLeft += (elementRect.right - elementRect.left);
+ }
+ }
+ }
+ return (elementLeft - prcClient->left);
+}
+
+
+static void Toolbar_UpdateLayout(HWND hwnd, BOOL fRedraw)
+{
+ UINT windowStyle = GetWindowStyle(hwnd);
+ if (0 != (TBS_LOCKUPDATE & windowStyle)) return;
+
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ RECT clientRect;
+ if (!Toolbar_GetClientRect(hwnd, &clientRect)) return;
+
+ Toolbar_UpdateTextMetrics(hwnd);
+
+ size_t count = (NULL != toolbar->items) ? toolbar->items->size() : 0;
+
+ if (NULL != toolbar->chevron)
+ {
+ INT chevronOnly = 0;
+ ToolbarItem *item;
+ for (size_t i = 0; i < count; i++)
+ {
+ item = toolbar->items->at(i);
+ UINT style = item->GetStyle();
+
+ if (NULL != item &&
+ 0 != (ToolbarItem::styleChevronOnly & style) &&
+ 0 == (ToolbarItem::stateHidden & style))
+ {
+ chevronOnly++;
+ }
+ }
+
+ toolbar->chevron->SetRectEmpty();
+ if (0 != chevronOnly)
+ clientRect.right += Toolbar_ShowChevron(hwnd, &clientRect);
+ }
+
+
+ Toolbar_CalculateClient(hwnd, toolbar->items->size() ? &toolbar->items->at(0) : nullptr, (INT)count, &clientRect, NULL);
+
+ if (((size_t)-1) != toolbar->iFocused)
+ {
+ size_t focusIndex = Toolbar_GetFocusIndex(hwnd, toolbar->iFocused, -1, FALSE);
+ if (focusIndex != toolbar->iFocused)
+ {
+ ToolbarItem *itemNew, *itemOld;
+
+ itemOld = Toolbar_GetItem(toolbar, toolbar->iFocused);
+ itemNew = Toolbar_GetItem(toolbar, focusIndex);
+ toolbar->iFocused = focusIndex;
+
+ if (NULL != itemOld)
+ itemOld->SetFocus(hwnd, itemNew, FALSE);
+ if (NULL != itemNew)
+ itemNew->SetFocus(hwnd, itemOld, TRUE);
+ }
+ }
+
+ if (FALSE != fRedraw)
+ {
+ RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_NOERASE);
+ }
+}
+
+static ToolbarItem *Toolbar_HitTest(HWND hwnd, POINT pt)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL != toolbar)
+ {
+ ToolbarItem *item;
+ size_t count = (NULL != toolbar->items) ? toolbar->items->size() : 0;
+ for (size_t i = 0; i <= count; i++)
+ {
+ item = (i < count) ? toolbar->items->at(i) : toolbar->chevron;
+
+ if (NULL != item && item->PtInItem(pt))
+ return item;
+ }
+ }
+ return NULL;
+}
+static HFONT Toolbar_CreateFont(HFONT skinFont)
+{
+ LOGFONT lf;
+ if (NULL == skinFont) return NULL;
+
+ INT skinHeight = (sizeof(LOGFONT) == GetObject(skinFont, sizeof(LOGFONT), &lf)) ? lf.lfHeight : -11;
+ ZeroMemory(&lf, sizeof(LOGFONT));
+
+ lf.lfHeight = skinHeight;
+ lf.lfWeight = FW_DONTCARE;
+ lf.lfItalic = FALSE;
+ lf.lfUnderline = FALSE;
+ lf.lfStrikeOut = FALSE;
+ lf.lfCharSet = DEFAULT_CHARSET;
+ lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf.lfQuality = DEFAULT_QUALITY;
+ lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ StringCchCopy(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), L"MS Shell Dlg 2");
+
+ return CreateFontIndirect(&lf);
+}
+
+
+static HWND Toolbar_CreateTooltip(HINSTANCE hInstance, HWND hOwner)
+{
+ HWND hTooltip = CreateWindowExW(WS_EX_TRANSPARENT , TOOLTIPS_CLASS, NULL,
+ WS_POPUP | TTS_ALWAYSTIP,
+ 0, 0, 0, 0,
+ hOwner, NULL, hInstance, NULL);
+
+ if (NULL == hTooltip)
+ return NULL;
+
+ SetWindowPos(hTooltip, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
+ SendMessage(hTooltip, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1000, 0));
+ SendMessage(hTooltip, TTM_SETDELAYTIME, TTDT_RESHOW, MAKELPARAM(-2, 0));
+
+ OSVERSIONINFO ov;
+ ov.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ if (::GetVersionEx(&ov) &&
+ ov.dwMajorVersion >= 6 &&
+ VER_PLATFORM_WIN32_NT == ov.dwPlatformId)
+ {
+ RECT rcMargin;
+ SetRect(&rcMargin, 3, 1, 3, 1);
+ SendMessage(hTooltip, TTM_SETMARGIN, 0, (LPARAM)&rcMargin);
+ }
+
+ TOOLINFO ti;
+ ZeroMemory(&ti, sizeof(TOOLINFO));
+ ti.cbSize = sizeof(TOOLINFO);
+ ti.hwnd = hOwner;
+ ti.lpszText = LPSTR_TEXTCALLBACK;
+ SendMessage(hTooltip, TTM_ADDTOOL, 0, (LPARAM)&ti);
+
+ SendMessage(hTooltip, TTM_SETMAXTIPWIDTH, 0, 1000);
+
+ return hTooltip;
+}
+static void Toolbar_RelayTooltipMsg(HWND hTooltip, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ MSG msg;
+
+ msg.hwnd = hwnd;
+ msg.message = uMsg;
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+
+ //DWORD pts = GetMessagePos();
+ //POINTSTOPOINT(msg.pt, pts);
+ //msg.time = GetMessageTime();
+
+ SendMessage(hTooltip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
+}
+static void Toolbar_SetTooltipItem(HWND hwnd, ToolbarItem *item)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ TOOLINFO ti;
+
+ ti.cbSize = sizeof(TOOLINFO);
+ ti.hwnd = hwnd;
+ ti.uId = 0;
+ ti.lpszText = NULL;
+
+ if (SendMessage(toolbar->hTooltip, TTM_GETTOOLINFO, 0, (LPARAM)&ti))
+ {
+ RECT clientRect, toolRect;
+ Toolbar_GetClientRect(hwnd, &clientRect);
+
+ if (NULL == item || FALSE == item->GetRect(&toolRect))
+ {
+ SendMessage(toolbar->hTooltip, TTM_ACTIVATE, FALSE, 0L);
+ return;
+ }
+
+ toolRect.top = clientRect.top;
+ toolRect.bottom = clientRect.bottom;
+
+ if (ti.lParam != (LPARAM)item || !::EqualRect(&ti.rect, &toolRect))
+ {
+ CopyRect(&ti.rect, &toolRect);
+ ti.lParam = (LPARAM)item;
+ SendMessage(toolbar->hTooltip, TTM_SETTOOLINFO, 0, (LPARAM)&ti);
+ }
+ SendMessage(toolbar->hTooltip, TTM_ACTIVATE, TRUE, 0L);
+ }
+
+}
+static void Toolbar_ClearBrushCache(HWND hwnd)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ for (INT i = 0; i < ARRAYSIZE(toolbar->szBrushes); i++)
+ {
+ if (NULL != toolbar->szBrushes[i])
+ {
+ DeleteObject(toolbar->szBrushes[i]);
+ toolbar->szBrushes[i] = NULL;
+ }
+ }
+}
+
+static HBRUSH Toolbar_GetBrush(HWND hwnd, UINT brushId)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return NULL;
+
+ if (brushId >= ARRAYSIZE(toolbar->szBrushes))
+ return NULL;
+
+ if (NULL == toolbar->szBrushes[brushId])
+ {
+ COLORREF brushColor = 0x00FF00FF;
+ switch(brushId)
+ {
+ case TOOLBRUSH_BACK: brushColor = toolbar->rgbBk;break;
+ case TOOLBRUSH_FRAME: brushColor = toolbar->rgbFrame; break;
+ case TOOLBRUSH_ITEMBK: brushColor = toolbar->rgbEditBk; break;
+ }
+ toolbar->szBrushes[brushId] = CreateSolidBrush(brushColor);
+ }
+ return toolbar->szBrushes[brushId];
+}
+
+
+static HRGN Toolbar_GetFrameRgn(const RECT *prcToolbar, BOOL bottomDock)
+{
+ if (TOOLBAR_SPACE_TOP < 1)
+ return NULL;
+
+ HRGN regionFrame;
+ INT origY = (FALSE != bottomDock) ? prcToolbar->top : prcToolbar->bottom - 1;
+ regionFrame = CreateRectRgn(prcToolbar->left, origY, prcToolbar->right, origY + 1);
+ return regionFrame;
+}
+
+static void Toolbar_PaintBack(HWND hwnd, HDC hdc, const RECT *prcToolbar, HRGN regionPaint)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ UINT windowStyle = GetWindowStyle(hwnd);
+
+ if (0 == (TBS_HIDDEN & toolbar->flags))
+ {
+ HRGN regionFrame = Toolbar_GetFrameRgn(prcToolbar, (0 != (TBS_BOTTOMDOCK & windowStyle)));
+ if (NULL != regionFrame)
+ {
+ if (FillRgn(hdc, regionFrame, Toolbar_GetBrush(hwnd, TOOLBRUSH_FRAME)))
+ CombineRgn(regionPaint, regionPaint, regionFrame, RGN_DIFF);
+ DeleteObject(regionFrame);
+ }
+ }
+
+ FillRgn(hdc, regionPaint, Toolbar_GetBrush(hwnd, TOOLBRUSH_BACK));
+}
+
+
+
+static void Toolbar_Paint(HWND hwnd, HDC hdc, const RECT *prcPaint, BOOL fErase)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ RECT clientRect;
+ GetClientRect(hwnd, &clientRect);
+
+ DWORD windowStyle = GetWindowStyle(hwnd);
+
+ HRGN paintRegion = CreateRectRgnIndirect(prcPaint);
+
+ if (0 == (TBS_HIDDEN & toolbar->flags))
+ {
+ INT savedDC = SaveDC(hdc);
+
+ HRGN itemRegion = CreateRectRgn(0,0,0,0);
+
+ SetBkColor(hdc, toolbar->rgbBk);
+ SetTextColor(hdc, toolbar->rgbText);
+ SelectObject(hdc, toolbar->textFont);
+
+ ToolbarItem *item;
+ RECT paintRect;
+ UINT style;
+
+ BOOL fFocused = (GetFocus() == hwnd);
+ UINT commonState= 0;
+
+ if (0 != (WS_DISABLED & windowStyle))
+ commonState |= ToolbarItem::stateDisabled;
+
+ size_t count = (NULL != toolbar->items) ? toolbar->items->size() : 0;
+ for (size_t i = 0; i <= count; i++)
+ {
+ item = (i < count) ? toolbar->items->at(i) : toolbar->chevron;
+
+ if (NULL != item && item->IntersectRect(&paintRect, prcPaint))
+ {
+ style = item->GetStyle() | commonState;
+ if (i == toolbar->iFocused && fFocused)
+ style |= ToolbarItem::stateFocused;
+
+ if (0 != (TBS_NOFOCUSRECT & toolbar->flags))
+ style |= ToolbarItem::stateNoFocusRect;
+
+ if (0 == (ToolbarItem::stateHidden & style) &&
+ item->Paint(hwnd, hdc, &paintRect, style))
+ {
+ SetRectRgn(itemRegion, paintRect.left, paintRect.top, paintRect.right, paintRect.bottom);
+ CombineRgn(paintRegion, paintRegion, itemRegion, RGN_DIFF);
+ }
+ }
+ }
+ DeleteObject(itemRegion);
+ RestoreDC(hdc, savedDC);
+ }
+
+ Toolbar_PaintBack(hwnd, hdc, &clientRect, paintRegion);
+ DeleteObject(paintRegion);
+
+}
+
+static INT Toolbar_FindListItem(ToolbarItem **itemList, INT start, INT count, LPCSTR pszName, INT cchName)
+{
+ ToolbarItem *item;
+ for (INT i = start; i < count; i++)
+ {
+ item = itemList[i];
+ if (NULL != item && item->IsEqual(pszName, cchName))
+ {
+ return i;
+ }
+ }
+ return ITEM_ERR;
+}
+static INT Toolbar_ResolveName(HWND hwnd, LPCSTR pszName)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar || NULL == toolbar->items)
+ return ITEM_ERR;
+
+ UINT index;
+ UINT count = (UINT)toolbar->items->size();
+
+ if (IS_INTRESOURCE(pszName))
+ {
+ index = (UINT)(UINT_PTR)pszName;
+
+ if (index == count && NULL != toolbar->chevron)
+ return index;
+
+ return (index < count) ? index : ITEM_ERR;
+ }
+
+ INT cchName = lstrlenA(pszName);
+ if (0 == cchName) return ITEM_ERR;
+
+ if (count == toolbar->resolveCache)
+ {
+ if (toolbar->chevron->IsEqual(pszName, cchName))
+ index = count;
+ else
+ {
+ index = ITEM_ERR;
+ toolbar->resolveCache = 0;
+ }
+ }
+ else
+ {
+ index = ITEM_ERR;
+ }
+
+ if (ITEM_ERR == index)
+ index = Toolbar_FindListItem(toolbar->items->size() ? & toolbar->items->at(0) : nullptr, toolbar->resolveCache, count, pszName, cchName);
+
+ if (ITEM_ERR == index && 0 != toolbar->resolveCache)
+ index = Toolbar_FindListItem(toolbar->items->size() ? &toolbar->items->at(0) : nullptr, 0, toolbar->resolveCache, pszName, cchName);
+
+ if (ITEM_ERR == index && NULL != toolbar->chevron && toolbar->chevron->IsEqual(pszName, cchName))
+ index = count;
+
+
+ toolbar->resolveCache = (ITEM_ERR != index) ? index : 0;
+ return index;
+}
+
+static BOOL Toolbar_DisplayChevronMenu(HWND hwnd)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar || NULL == toolbar->items) return FALSE;
+
+ HMENU hMenu = CreatePopupMenu();
+ if (NULL == hMenu) return FALSE;
+
+ size_t count = toolbar->items->size();
+ UINT insertedCount = 0;
+ MENUITEMINFO mi;
+ mi.cbSize = sizeof(MENUITEMINFO);
+
+ UINT style;
+ WCHAR szBuffer[80] = {0};
+ INT commandId = 0;
+ ToolbarItem *item;
+ BOOL insertBreak = FALSE;
+ for (size_t i = 0; i < count; i++)
+ {
+ item = toolbar->items->at(i);
+ if (NULL != item)
+ {
+ style = item->GetStyle();
+ if(0 == ((ToolbarItem::stateHidden | ToolbarItem::styleNoChevron) & style) &&
+ item->IsRectEmpty() &&
+ FALSE != item->FillMenuInfo(hwnd, &mi, szBuffer, ARRAYSIZE(szBuffer)))
+ {
+ if (MIIM_FTYPE == mi.fMask && MFT_MENUBREAK == mi.fType)
+ {
+ if (insertedCount > 0)
+ insertBreak = TRUE;
+ }
+ else
+ {
+ if (FALSE != InsertMenuItem(hMenu, insertedCount, TRUE, &mi))
+ {
+ if (insertBreak)
+ {
+ mi.fMask = MIIM_FTYPE;
+ mi.fType = MFT_MENUBREAK;
+ if (InsertMenuItem(hMenu, insertedCount, TRUE, &mi))
+ insertedCount++;
+ insertBreak = FALSE;
+ }
+ insertedCount++;
+ }
+ }
+
+ }
+ }
+ }
+
+ if (NULL != hMenu && insertedCount > 0)
+ {
+ RECT windowRect;
+ GetWindowRect(hwnd, &windowRect);
+ UINT windowStyle = GetWindowStyle(hwnd);
+ UINT menuStyle = TPM_RIGHTALIGN | TPM_RETURNCMD;
+ POINT menuOrig;
+ menuOrig.x = windowRect.right;
+ if (0 != (TBS_BOTTOMDOCK & windowStyle))
+ {
+ menuOrig.y = windowRect.top;
+ menuStyle |= (TPM_BOTTOMALIGN | TPM_VERNEGANIMATION);
+ }
+ else
+ {
+ menuOrig.y = windowRect.bottom;
+ menuStyle |= (TPM_TOPALIGN | TPM_VERPOSANIMATION);
+ }
+
+ commandId = Menu_TrackPopup(hMenu, menuStyle, menuOrig.x, menuOrig.y, hwnd, NULL);
+
+
+ }
+
+ DestroyMenu(hMenu);
+
+ if (0 != commandId)
+ Toolbar_SendCommand(hwnd, commandId);
+
+
+ return TRUE;
+}
+
+static void Toolbar_DisplayContextMenu(HWND hwnd, INT x, INT y)
+{
+ HMENU hMenu = Menu_GetMenu(MENU_TOOLBAR, 0);
+ if (NULL != hMenu)
+ {
+ UINT windowStyle = GetWindowStyle(hwnd);
+ CheckMenuRadioItem(hMenu, ID_TOOLBAR_DOCKTOP, ID_TOOLBAR_DOCKBOTTOM,
+ (0 != (TBS_BOTTOMDOCK & windowStyle)) ? ID_TOOLBAR_DOCKBOTTOM :ID_TOOLBAR_DOCKTOP,
+ MF_BYCOMMAND);
+
+ CheckMenuItem(hMenu, ID_TOOLBAR_AUTOHIDE,
+ MF_BYCOMMAND | ((0 != (TBS_AUTOHIDE & windowStyle)) ? MF_CHECKED :MF_UNCHECKED));
+
+ CheckMenuItem(hMenu, ID_TOOLBAR_TABSTOP,
+ MF_BYCOMMAND | ((0 != (TBS_TABSTOP & windowStyle)) ? MF_CHECKED :MF_UNCHECKED));
+
+ Menu_TrackPopup(hMenu, TPM_LEFTALIGN | TPM_TOPALIGN, x, y, hwnd, NULL);
+
+ Menu_ReleaseMenu(hMenu, MENU_TOOLBAR);
+ }
+
+}
+
+static BOOL Toolbar_InstallMouseHook(HWND hwnd)
+{
+ if (TLS_OUT_OF_INDEXES == tlsIndex)
+ {
+ tlsIndex = Plugin_TlsAlloc();
+ if (TLS_OUT_OF_INDEXES == tlsIndex) return FALSE;
+ }
+
+ TOOLBARMOUSEHOOK *hook = (TOOLBARMOUSEHOOK*)calloc(1, sizeof(TOOLBARMOUSEHOOK));
+ if (NULL == hook) return FALSE;
+
+ hook->hwnd = hwnd;
+ hook->hHook = SetWindowsHookEx(WH_MOUSE, Toolbar_MouseHook, NULL, GetCurrentThreadId());
+ if (NULL == hook->hHook)
+ {
+ free(hook);
+ return FALSE;
+ }
+
+ Plugin_TlsSetValue(tlsIndex, hook);
+ return TRUE;
+}
+
+static void Toolbar_TrackMouseLeave(HWND hwnd)
+{
+ TRACKMOUSEEVENT tm;
+ tm.cbSize = sizeof(TRACKMOUSEEVENT);
+ tm.dwFlags = TME_QUERY;
+ tm.hwndTrack = hwnd;
+ if (TrackMouseEvent(&tm) && 0 == (TME_LEAVE & tm.dwFlags))
+ {
+ tm.cbSize = sizeof(TRACKMOUSEEVENT);
+ tm.dwFlags = TME_LEAVE;
+ tm.hwndTrack = hwnd;
+ TrackMouseEvent(&tm);
+ }
+}
+
+static BOOL Toolbar_RemoveMouseHook(HWND hwnd, BOOL fOnlyMine)
+{
+ if (TLS_OUT_OF_INDEXES == tlsIndex) return FALSE;
+
+ TOOLBARMOUSEHOOK *hook = (TOOLBARMOUSEHOOK*)Plugin_TlsGetValue(tlsIndex);
+ if (NULL == hook) return FALSE;
+
+ if (FALSE != fOnlyMine && hwnd != hook->hwnd)
+ return FALSE;
+
+ Plugin_TlsSetValue(tlsIndex, NULL);
+
+ if (NULL != hook->hHook)
+ UnhookWindowsHookEx(hook->hHook);
+
+ if (NULL != hook->hwnd && hwnd != hook->hwnd)
+ {
+ Toolbar_TrackMouseLeave(hook->hwnd);
+ }
+
+ free(hook);
+ return TRUE;
+}
+
+static void Toolbar_AutoShowWindow(HWND hwnd)
+{
+ KillTimer(hwnd, TIMER_AUTOHIDE_ID);
+
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ HWND hFocus = GetFocus();
+
+ BOOL fFocused = (hFocus == hwnd);
+
+ UINT windowStyle = GetWindowStyle(hwnd);
+ if ((TBS_AUTOHIDE | WS_VISIBLE) != ((TBS_AUTOHIDE | WS_VISIBLE) & windowStyle))
+ return;
+
+ if (0 == (TBS_HIDDEN & toolbar->flags))
+ {
+ if (0 != (TBS_HIDETIMERSET & toolbar->flags))
+ toolbar->flags &= ~TBS_HIDETIMERSET;
+
+ if (FALSE == fFocused)
+ Toolbar_TrackMouseLeave(hwnd);
+ return;
+ }
+
+ Toolbar_RemoveMouseHook(hwnd, FALSE);
+
+ if (FALSE == fFocused && FALSE == Toolbar_InstallMouseHook(hwnd))
+ return;
+
+ toolbar->flags &= ~TBS_HIDDEN;
+
+ RECT windowRect;
+ if (GetWindowRect(hwnd, &windowRect))
+ {
+ HWND hParent = GetParent(hwnd);
+ if(NULL != hParent)
+ {
+ MapWindowPoints(HWND_DESKTOP, hParent, (POINT*)&windowRect, 2);
+ INT height = Toolbar_GetIdealHeight(hwnd);
+ INT x = windowRect.left;
+ INT y = windowRect.top;
+ UINT swpFlags = SWP_NOMOVE | SWP_NOREDRAW;
+ UINT animateFlags = AW_SLIDE | AW_VER_POSITIVE;
+
+ if (0 != (TBS_BOTTOMDOCK & windowStyle))
+ {
+ y = windowRect.bottom - height;
+ swpFlags &= ~SWP_NOMOVE;
+ animateFlags = AW_SLIDE | AW_VER_NEGATIVE;
+ }
+ SetWindowPos(hwnd, HWND_TOP, x, y, windowRect.right - windowRect.left, height, swpFlags);
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE);
+ BOOL result = AnimateWindow(hwnd, AUTOHIDE_ANIMATETIME, animateFlags);
+ if (!result)
+ {
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle | WS_VISIBLE);
+ InvalidateRect(hwnd, NULL, TRUE);
+ }
+ }
+ }
+
+
+ if (FALSE == fFocused)
+ Toolbar_TrackMouseLeave(hwnd);
+}
+
+static void CALLBACK Toolbar_AutoHideTimerProc(HWND hwnd, UINT uMsg, UINT_PTR eventId, DWORD time)
+{
+ KillTimer(hwnd, eventId);
+
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ UINT windowStyle = GetWindowStyle(hwnd);
+ if (0 == (TBS_AUTOHIDE & windowStyle)) return;
+
+ toolbar->flags &= ~TBS_HIDETIMERSET;
+ if (0 != ((TBS_HIDDEN | TBS_MENULOOP) & toolbar->flags))
+ return;
+
+ HWND hFocus = ::GetFocus();
+ if (hwnd == hFocus || IsChild(hwnd, hFocus))
+ return;
+
+ Toolbar_RemoveMouseHook(hwnd, TRUE);
+ RECT windowRect;
+ if (GetWindowRect(hwnd, &windowRect))
+ {
+ HWND hParent = GetParent(hwnd);
+ if(NULL != hParent)
+ {
+ MapWindowPoints(HWND_DESKTOP, hParent, (POINT*)&windowRect, 2);
+ INT height = TOOLBAR_HIDDENHEIGHT;
+ INT x = windowRect.left;
+ INT y = windowRect.top;
+ UINT swpFlags = SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOREDRAW;
+ UINT animateFlags = AW_HIDE | AW_SLIDE | AW_VER_NEGATIVE;
+ HWND zOrder = HWND_TOP;
+
+ if (0 != (TBS_BOTTOMDOCK & windowStyle))
+ {
+ y = windowRect.bottom - height;
+ swpFlags &= ~SWP_NOMOVE;
+ zOrder = HWND_BOTTOM;
+ animateFlags = AW_HIDE | AW_SLIDE | AW_VER_POSITIVE;
+ }
+
+ AnimateWindow(hwnd, AUTOHIDE_ANIMATETIME, animateFlags);
+
+ if (NULL != toolbar->hBrowser)
+ {
+ RECT invalidRect;
+ CopyRect(&invalidRect, &windowRect);
+ MapWindowPoints(hParent, toolbar->hBrowser, (POINT*)&invalidRect, 2);
+ RedrawWindow(toolbar->hBrowser, &invalidRect, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);
+ }
+
+ SetWindowPos(hwnd, zOrder, x, y, windowRect.right - windowRect.left, height, swpFlags);
+
+ if (0 != (WS_VISIBLE & windowStyle))
+ {
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle | WS_VISIBLE);
+ InvalidateRect(hwnd, NULL, TRUE);
+ }
+ }
+ }
+
+ toolbar->flags |= TBS_HIDDEN;
+}
+
+static void Toolbar_AutoHideWindow(HWND hwnd, BOOL fImmediate)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+ if (0 != ((TBS_HIDDEN | TBS_MENULOOP) & toolbar->flags))
+ {
+ return;
+ }
+
+ UINT windowStyle = GetWindowStyle(hwnd);
+ if (0 == (TBS_AUTOHIDE & windowStyle)) return;
+
+ if (FALSE == fImmediate)
+ {
+ if (SetTimer(hwnd, TIMER_AUTOHIDE_ID, TIMER_AUTOHIDE_DELAY, Toolbar_AutoHideTimerProc))
+ toolbar->flags |= TBS_HIDETIMERSET;
+ }
+ else
+ {
+ Toolbar_AutoHideTimerProc(hwnd, WM_TIMER, TIMER_AUTOHIDE_ID, GetTickCount());
+ }
+}
+
+static void Toolbar_UpdateUiFlags(HWND hwnd)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ UINT uiState = (UINT)SendMessage(hwnd, WM_QUERYUISTATE, 0, 0L);
+
+ if (0 != (UISF_HIDEFOCUS & uiState)) toolbar->flags |= TBS_NOFOCUSRECT;
+ else toolbar->flags &= ~TBS_NOFOCUSRECT;
+}
+static void Toolbar_NotifyParent(HWND hwnd, UINT eventId)
+{
+ HWND hParent = GetParent(hwnd);
+ if (NULL == hParent) return;
+ UINT controlId = (UINT)GetWindowLongPtr(hwnd, GWLP_ID);
+ SENDCMD(hParent, controlId, eventId, hwnd);
+}
+static LRESULT Toolbar_OnCreate(HWND hwnd, CREATESTRUCT *pcs)
+{
+ TOOLBAR *toolbar = (TOOLBAR*)calloc(1, sizeof(TOOLBAR));
+ if (NULL != toolbar)
+ {
+ Toolbar_AddRef(toolbar);
+
+ SetLastError(ERROR_SUCCESS);
+ if (!SetWindowLongPtr(hwnd, 0, (LONGX86)(LONG_PTR)toolbar) && ERROR_SUCCESS != GetLastError())
+ {
+ free(toolbar);
+ toolbar = NULL;
+ }
+ }
+
+ if (NULL == toolbar)
+ {
+ DestroyWindow(hwnd);
+ return -1;
+ }
+
+ toolbar->chevron = Toolbar_CreateItem(TOOLITEM_CHEVRON, 0);
+ toolbar->items = new ItemList();
+ toolbar->hTooltip = Toolbar_CreateTooltip(pcs->hInstance, hwnd);
+
+ if (NULL != toolbar->hTooltip)
+ {
+ ifc_skinhelper *skinHelper;
+ if (SUCCEEDED(Plugin_GetSkinHelper(&skinHelper)))
+ {
+ skinHelper->SkinControl(toolbar->hTooltip, SKINNEDWND_TYPE_TOOLTIP,
+ SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWS_USESKINFONT);
+
+ skinHelper->Release();
+ }
+ }
+
+ if (0 != (TBS_AUTOHIDE & pcs->style))
+ toolbar->flags |= TBS_HIDDEN;
+
+ return 0;
+}
+
+static void Toolbar_OnDestroy(HWND hwnd)
+{
+ Toolbar_RemoveMouseHook(hwnd, TRUE);
+ Toolbar_ClearBrushCache(hwnd);
+
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ SetWindowLongPtr(hwnd, 0, 0L);
+
+ Toolbar_Release(toolbar);
+}
+
+static void Toolbar_OnPaint(HWND hwnd)
+{
+ PAINTSTRUCT ps;
+ if (BeginPaint(hwnd, &ps))
+ {
+ if (ps.rcPaint.left != ps.rcPaint.right)
+ Toolbar_Paint(hwnd, ps.hdc, &ps.rcPaint, ps.fErase);
+ EndPaint(hwnd, &ps);
+ }
+}
+
+static void Toolbar_OnPrintClient(HWND hwnd, HDC hdc, UINT options)
+{
+ RECT clientRect;
+ if (GetClientRect(hwnd, &clientRect))
+ Toolbar_Paint(hwnd, hdc, &clientRect, 0 != (PRF_ERASEBKGND & options));
+}
+
+static void Toolbar_OnWindowPosChanged(HWND hwnd, WINDOWPOS *pwp)
+{
+ if (SWP_NOSIZE == ((SWP_NOSIZE | SWP_FRAMECHANGED) & pwp->flags))
+ return;
+
+ Toolbar_UpdateLayout(hwnd, 0 == (SWP_NOREDRAW & pwp->flags));
+}
+
+static void Toolbar_OnSetRedraw(HWND hwnd, BOOL allowRedraw)
+{
+ UINT windowStyle = GetWindowStyle(hwnd);
+ if (FALSE == allowRedraw)
+ {
+ if (0 == (TBS_LOCKUPDATE & windowStyle))
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle | TBS_LOCKUPDATE);
+ }
+ else
+ {
+ if (0 != (TBS_LOCKUPDATE & windowStyle))
+ {
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle & ~TBS_LOCKUPDATE);
+ Toolbar_UpdateTabstop(hwnd);
+ Toolbar_UpdateLayout(hwnd, FALSE);
+ InvalidateRect(hwnd, NULL, TRUE);
+ }
+ }
+ DefWindowProcW(hwnd, WM_SETREDRAW, (WPARAM)allowRedraw, 0L);
+}
+
+
+static void Toolbar_OnEnterMenuLoop(HWND hwnd, BOOL fContext)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ toolbar->flags |= TBS_MENULOOP;
+}
+static void Toolbar_OnExitMenuLoop(HWND hwnd, BOOL fContext)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ toolbar->flags &= ~TBS_MENULOOP;
+
+ Toolbar_TrackMouseLeave(hwnd);
+}
+
+static void Toolbar_OnSetFocus(HWND hwnd, HWND hFocus)
+{
+ UINT windowStyle = GetWindowStyle(hwnd);
+
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+
+ BOOL focusDirLeft = FALSE;
+ if (0 != (0x8000 & GetAsyncKeyState(VK_LEFT)))
+ {
+ focusDirLeft = TRUE;
+ }
+ else if (0 != (0x8000 & GetAsyncKeyState(VK_TAB)))
+ {
+ if (0 != (0x8000 & GetAsyncKeyState(VK_SHIFT)))
+ focusDirLeft = TRUE;
+ }
+ else if (0 != (0x8000 & GetAsyncKeyState(VK_LBUTTON)) || 0 != (0x8000 & GetAsyncKeyState(VK_RBUTTON)) ||
+ 0 != (0x8000 & GetAsyncKeyState(VK_MBUTTON)) || 0 != (0x8000 & GetAsyncKeyState(VK_XBUTTON1)) ||
+ 0 != (0x8000 & GetAsyncKeyState(VK_XBUTTON2)))
+ {
+ // mouse press (?)
+ }
+
+ if ((size_t)-1 != toolbar->iFocused)
+ toolbar->iFocused = Toolbar_GetFocusIndex(hwnd, toolbar->iFocused, 0, FALSE);
+
+ if ((size_t)-1 == toolbar->iFocused)
+ {
+ if (0 != (TBS_TABSTOP & windowStyle))
+ {
+ if (FALSE == focusDirLeft)
+ toolbar->iFocused = Toolbar_GetFocusIndex(hwnd, 0, 1, FALSE);
+ else
+ {
+ size_t last = (NULL != toolbar->items) ? toolbar->items->size() : 0;
+ if (last > 0)
+ toolbar->iFocused = Toolbar_GetFocusIndex(hwnd, last - 1, -1, FALSE);
+ }
+ }
+ else
+ {
+ size_t lim, index;
+ INT inc;
+ if (FALSE == focusDirLeft)
+ {
+ lim = toolbar->items->size();
+ index = 0;
+ inc = 1;
+ }
+ else
+ {
+ lim = (size_t)-1;
+ index = toolbar->items->size();
+ if (index > 0) index--;
+ inc = -1;
+ }
+
+ for (; index != lim; index += inc)
+ {
+ UINT itemStyle = toolbar->items->at(index)->GetStyle();
+ UINT mask = ToolbarItem::styleTabstop | ToolbarItem::stateDisabled | ToolbarItem::stateHidden;
+ if (ToolbarItem::styleTabstop == (mask & itemStyle))
+ {
+ toolbar->iFocused = index;
+ break;
+ }
+ }
+ }
+ }
+
+ if (((size_t)-1) != toolbar->iFocused)
+ {
+ ToolbarItem *item = Toolbar_GetItem(toolbar, toolbar->iFocused);
+ if (NULL != item) item->SetFocus(hwnd, NULL, TRUE);
+ }
+
+
+ if (0 != (WS_TABSTOP & windowStyle))
+ Toolbar_AutoShowWindow(hwnd);
+}
+
+static void Toolbar_OnKillFocus(HWND hwnd, HWND hFocus)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL != toolbar && ((size_t)-1) != toolbar->iFocused)
+ {
+ ToolbarItem *item = Toolbar_GetItem(toolbar, toolbar->iFocused);
+ if (NULL != item) item->SetFocus(hwnd, NULL, FALSE);
+ toolbar->iFocused = ((size_t)-1);
+ }
+ Toolbar_AutoHideWindow(hwnd, TRUE);
+}
+
+static void Toolbar_OnKeyDown(HWND hwnd, INT vKey, UINT flags)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ Toolbar_AutoShowWindow(hwnd);
+
+ INT searchDirection = 0;
+ if (VK_LEFT == vKey) searchDirection = -1;
+ else if (VK_RIGHT == vKey) searchDirection = 1;
+
+ toolbar->iFocused = Toolbar_GetFocusIndex(hwnd, toolbar->iFocused, searchDirection, FALSE);
+
+ ToolbarItem *focusedItem = Toolbar_GetItem(toolbar, toolbar->iFocused);
+
+ BOOL fHandled = (NULL != focusedItem && focusedItem->KeyDown(hwnd, vKey, flags));
+ if (!fHandled)
+ {
+ switch(vKey)
+ {
+ case VK_LEFT:
+ Toolbar_NextItem(hwnd, TBNS_PREVITEM, FALSE);
+ break;
+ case VK_RIGHT:
+ Toolbar_NextItem(hwnd, TBNS_NEXTITEM, FALSE);
+ break;
+ case VK_HOME:
+ case VK_PRIOR:
+ {
+ size_t first = 0;
+ first = Toolbar_GetFocusIndex(hwnd, first, 1, FALSE);
+ if (((size_t)-1) != first)
+ Toolbar_NextItem(hwnd, MAKEINTRESOURCE(first), TRUE);
+ }
+ break;
+ case VK_END:
+ case VK_NEXT:
+ {
+ size_t last = toolbar->items->size();
+ last = Toolbar_GetFocusIndex(hwnd, last, -1, FALSE);
+ if (((size_t)-1) != last)
+ Toolbar_NextItem(hwnd, MAKEINTRESOURCE(last), TRUE);
+ }
+ break;
+
+ }
+ }
+}
+
+static void Toolbar_OnKeyUp(HWND hwnd, INT vKey, UINT flags)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ toolbar->iFocused = Toolbar_GetFocusIndex(hwnd, toolbar->iFocused, FALSE, FALSE);
+
+ ToolbarItem *focusedItem = Toolbar_GetItem(toolbar, toolbar->iFocused);
+
+ BOOL fHandled = (NULL != focusedItem && focusedItem->KeyUp(hwnd, vKey, flags));
+}
+
+static void Toolbar_OnMouseMove(HWND hwnd, UINT mouseFlags, POINTS pts)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ Toolbar_AutoShowWindow(hwnd);
+
+ POINT pt;
+ POINTSTOPOINT(pt, pts);
+
+ RECT clientRect;
+ Toolbar_GetClientRect(hwnd, &clientRect);
+
+ if (NULL != toolbar->pressed)
+ {
+ if (!PtInRect(&clientRect, pt))
+ {
+ toolbar->pressed->MouseLeave(hwnd);
+ }
+ else
+ {
+ toolbar->pressed->MouseMove(hwnd, mouseFlags, pt);
+ }
+ return;
+ }
+
+ ToolbarItem *item = (PtInRect(&clientRect, pt)) ? Toolbar_HitTest(hwnd, pt) : NULL;
+
+ ToolbarItem *prevHighlighted = toolbar->highlighted;
+ if (NULL != toolbar->highlighted)
+ {
+ if (item != toolbar->highlighted)
+ {
+ toolbar->highlighted->MouseLeave(hwnd);
+ toolbar->highlighted = NULL;
+ }
+ }
+
+ if (NULL != item)
+ {
+ UINT style = item->GetStyle();
+ if (0 == ((ToolbarItem::stateDisabled | ToolbarItem::stateHidden | ToolbarItem::styleStatic) & style))
+ {
+ toolbar->highlighted = item;
+ item->MouseMove(hwnd, mouseFlags, pt);
+ Toolbar_TrackMouseLeave(hwnd);
+ }
+ }
+
+ if (NULL != toolbar->hTooltip)
+ {
+ if (prevHighlighted == toolbar->highlighted || NULL != prevHighlighted)
+ Toolbar_RelayTooltipMsg(toolbar->hTooltip, hwnd, WM_MOUSEMOVE, (WPARAM)mouseFlags, *((LPARAM*)(&pts)));
+
+ if (prevHighlighted != toolbar->highlighted)
+ {
+ Toolbar_SetTooltipItem(hwnd, toolbar->highlighted);
+ if (NULL != toolbar->highlighted)
+ Toolbar_RelayTooltipMsg(toolbar->hTooltip, hwnd, WM_MOUSEMOVE, (WPARAM)mouseFlags, *((LPARAM*)(&pts)));
+
+ }
+ }
+}
+
+static void Toolbar_OnMouseLeave(HWND hwnd)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ if (NULL != toolbar->highlighted)
+ {
+ toolbar->highlighted->MouseLeave(hwnd);
+ toolbar->highlighted = NULL;
+ }
+
+ Toolbar_SetTooltipItem(hwnd, NULL);
+
+
+ POINT cursor;
+ if (GetFocus() != hwnd && GetCursorPos(&cursor))
+ {
+ HWND hCursor = WindowFromPoint(cursor);
+ if (NULL != hCursor &&
+ GetWindowThreadProcessId(hwnd, NULL) != GetWindowThreadProcessId(hCursor, NULL))
+ {
+ Toolbar_AutoHideWindow(hwnd, FALSE);
+ }
+ }
+}
+
+static void Toolbar_OnLButtonDown(HWND hwnd, UINT mouseFlags, POINTS pts)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ Toolbar_SetTooltipItem(hwnd, NULL);
+
+ if (NULL != toolbar->highlighted)
+ Toolbar_RelayTooltipMsg(toolbar->hTooltip, hwnd, WM_LBUTTONDOWN, (WPARAM)mouseFlags, *((LPARAM*)(&pts)));
+
+ POINT pt;
+ POINTSTOPOINT(pt, pts);
+
+ RECT clientRect;
+ Toolbar_GetClientRect(hwnd, &clientRect);
+
+ ToolbarItem *item = (PtInRect(&clientRect, pt)) ? Toolbar_HitTest(hwnd, pt) : NULL;
+
+ if (NULL != item)
+ {
+ if (0 == ((ToolbarItem::stateDisabled | ToolbarItem::stateHidden | ToolbarItem::styleStatic) & item->GetStyle()))
+ {
+ item->LButtonDown(hwnd, mouseFlags, pt);
+ toolbar->pressed = item;
+ }
+ }
+
+ SetCapture(hwnd);
+}
+
+static void Toolbar_OnLButtonUp(HWND hwnd, UINT mouseFlags, POINTS pts)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ if (NULL != toolbar->highlighted)
+ Toolbar_RelayTooltipMsg(toolbar->hTooltip, hwnd, WM_LBUTTONUP, (WPARAM)mouseFlags, *((LPARAM*)(&pts)));
+
+ POINT pt;
+ POINTSTOPOINT(pt, pts);
+
+ RECT clientRect;
+ Toolbar_GetClientRect(hwnd, &clientRect);
+
+ ToolbarItem *item = (PtInRect(&clientRect, pt)) ? Toolbar_HitTest(hwnd, pt) : NULL;
+
+ if (NULL != toolbar->pressed)
+ {
+ ToolbarItem *pressed = toolbar->pressed;
+ toolbar->pressed = NULL;
+ Toolbar_AddRef(toolbar);
+ pressed->AddRef();
+ if (pressed == item)
+ pressed->Click(hwnd, mouseFlags, pt);
+
+ pressed->LButtonUp(hwnd, mouseFlags, pt);
+ pressed->Release();
+ Toolbar_Release(toolbar);
+ }
+
+ if (hwnd == GetCapture())
+ ReleaseCapture();
+}
+
+static void Toolbar_OnRButtonDown(HWND hwnd, UINT mouseFlags, POINTS pts)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ Toolbar_SetTooltipItem(hwnd, NULL);
+
+ if (NULL != toolbar->highlighted)
+ Toolbar_RelayTooltipMsg(toolbar->hTooltip, hwnd, WM_RBUTTONDOWN, (WPARAM)mouseFlags, *((LPARAM*)(&pts)));
+
+}
+
+static void Toolbar_OnRButtonUp(HWND hwnd, UINT mouseFlags, POINTS pts)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ if (NULL != toolbar->highlighted)
+ Toolbar_RelayTooltipMsg(toolbar->hTooltip, hwnd, WM_RBUTTONUP, (WPARAM)mouseFlags, *((LPARAM*)(&pts)));
+}
+
+static void Toolbar_OnMButtonDown(HWND hwnd, UINT mouseFlags, POINTS pts)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ Toolbar_SetTooltipItem(hwnd, NULL);
+
+ if (NULL != toolbar->highlighted)
+ Toolbar_RelayTooltipMsg(toolbar->hTooltip, hwnd, WM_MBUTTONDOWN, (WPARAM)mouseFlags, *((LPARAM*)(&pts)));
+}
+
+static void Toolbar_OnMButtonUp(HWND hwnd, UINT mouseFlags, POINTS pts)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ if (NULL != toolbar->highlighted)
+ Toolbar_RelayTooltipMsg(toolbar->hTooltip, hwnd, WM_MBUTTONUP, (WPARAM)mouseFlags, *((LPARAM*)(&pts)));
+}
+
+static void Toolbar_OnContextMenu(HWND hwnd, HWND hOwner, POINTS pts)
+{
+ POINT pt;
+ POINTSTOPOINT(pt, pts);
+
+ if (-1 == pt.x || -1 == pt.y)
+ {
+ RECT windowRect;
+ GetWindowRect(hwnd, &windowRect);
+ if (!GetCursorPos(&pt) || !PtInRect(&windowRect, pt))
+ {
+ pt.x = windowRect.left + 2;
+ pt.y = windowRect.top + 2;
+ }
+ }
+ else
+ {
+ POINT localPt = pt;
+ MapWindowPoints(HWND_DESKTOP, hwnd, &localPt, 1);
+
+ RECT clientRect;
+ Toolbar_GetClientRect(hwnd, &clientRect);
+ ToolbarItem *item = (PtInRect(&clientRect, localPt)) ? Toolbar_HitTest(hwnd, localPt) : NULL;
+
+ if (NULL != item)
+ {
+ UINT itemStyle = item->GetStyle();
+ if (0 == ((ToolbarItem::stateHidden | ToolbarItem::stateDisabled) & itemStyle))
+ {
+ RECT itemRect;
+ if (item->GetRect(&itemRect) && PtInRect(&itemRect, localPt))
+ {
+ if (FALSE != item->DisplayContextMenu(hwnd, pt.x, pt.y))
+ return;
+ }
+ }
+ }
+ }
+
+ Toolbar_DisplayContextMenu(hwnd, pt.x, pt.y);
+}
+static void Toolbar_OnCaptureChanged(HWND hwnd, HWND hCapture)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+ Toolbar_TrackMouseLeave(hwnd);
+}
+static LRESULT Toolbar_OnGetFont(HWND hwnd)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return NULL;
+ return (LRESULT)toolbar->textFont;
+}
+
+
+static void Toolbar_OnSetFont(HWND hwnd, HFONT hFont, BOOL fRedraw)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ toolbar->textFont = hFont;
+
+ Toolbar_UpdateTextMetrics(hwnd);
+
+ if (FALSE != fRedraw)
+ InvalidateRect(hwnd, NULL, TRUE);
+}
+
+
+static void Toolbar_GetTootipDispInfo(HWND hwnd, NMTTDISPINFO *pdisp)
+{
+ ToolbarItem *item = (ToolbarItem*)pdisp->lParam;
+ if (NULL != item)
+ {
+ item->GetTip(pdisp->szText, ARRAYSIZE(pdisp->szText));
+ }
+}
+
+static LRESULT Toolbar_OnTooltipNotify(HWND hwnd, NMHDR *pnmh)
+{
+ switch(pnmh->code)
+ {
+ case TTN_GETDISPINFO:
+ Toolbar_GetTootipDispInfo(hwnd, (NMTTDISPINFO*)pnmh);
+ break;
+ }
+ return 0;
+}
+static LRESULT Toolbar_OnNotify(HWND hwnd, INT controlId, NMHDR *pnmh)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return 0;
+
+ if (toolbar->hTooltip == pnmh->hwndFrom && NULL != toolbar->hTooltip)
+ return Toolbar_OnTooltipNotify(hwnd, pnmh);
+
+ return 0;
+}
+
+static void Toolbar_OnCommand(HWND hwnd, INT commandId, INT eventId, HWND hControl)
+{
+ BOOL fEnabled;
+ switch(commandId)
+ {
+ case ID_TOOLBAR_DOCKTOP:
+ case ID_TOOLBAR_DOCKBOTTOM:
+ fEnabled = (ID_TOOLBAR_DOCKBOTTOM == commandId);
+ if (fEnabled != Toolbar_EnableBottomDock(hwnd, fEnabled))
+ Toolbar_NotifyParent(hwnd, TBN_DOCKCHANGED);
+ break;
+ case ID_TOOLBAR_AUTOHIDE:
+ fEnabled = (0 == (TBS_AUTOHIDE & GetWindowStyle(hwnd)));
+ if (fEnabled != Toolbar_EnableAutoHide(hwnd, fEnabled))
+ Toolbar_NotifyParent(hwnd, TBN_AUTOHIDECHANGED);
+ break;
+ case ID_TOOLBAR_TABSTOP:
+ fEnabled = (0 == (TBS_TABSTOP & GetWindowStyle(hwnd)));
+ if (fEnabled != Toolbar_EnableTabStop(hwnd, fEnabled))
+ Toolbar_NotifyParent(hwnd, TBN_TABSTOPCHANGED);
+ break;
+ }
+}
+
+static BOOL Toolbar_ProcessTabKey(HWND hwnd, UINT messageId)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return FALSE;
+
+ BOOL focusDirLeft = (0 != (0x8000 & GetAsyncKeyState(VK_SHIFT)));
+
+ size_t lim, index;
+ INT inc;
+ if (FALSE == focusDirLeft)
+ {
+ inc = 1;
+ lim = toolbar->items->size();
+ index = toolbar->iFocused;
+ if ((size_t)-1 == index) index = 0;
+ index++;
+ if (index >= lim) return FALSE;
+ }
+ else
+ {
+ inc = -1;
+ lim = (size_t)-1;
+ index = toolbar->iFocused;
+ if ((size_t)-1 == index) index = toolbar->items->size();
+ index--;
+ if (index >= toolbar->items->size()) return FALSE;
+ }
+
+ for (; index != lim; index += inc)
+ {
+ ToolbarItem *item = toolbar->items->at(index);
+ if (FALSE != Toolbar_IsItemAcceptFocus(item, TRUE))
+ {
+ item->SetFocus(hwnd, NULL, TRUE);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static LRESULT Toolbar_OnGetDlgCode(HWND hwnd, INT vKey, MSG *pMsg)
+{
+ if (NULL != pMsg)
+ {
+ switch(vKey)
+ {
+ case VK_TAB:
+ if (FALSE == Toolbar_ProcessTabKey(hwnd, pMsg->message))
+ {
+ if (WM_KEYDOWN == pMsg->message)
+ Toolbar_AutoHideWindow(hwnd, TRUE);
+
+ return 0;
+ }
+ break;
+
+ }
+ }
+
+ return DLGC_WANTALLKEYS;
+}
+
+
+static void Toolbar_OnUpdateUiState(HWND hwnd, INT action, INT state)
+{
+ DefWindowProc(hwnd, WM_UPDATEUISTATE, MAKEWPARAM(action, state), 0L);
+ Toolbar_UpdateUiFlags(hwnd);
+}
+
+static void Toolbar_OnEnable(HWND hwnd, BOOL fEnable)
+{
+ InvalidateRect(hwnd, NULL, FALSE);
+}
+
+static LRESULT Toolbar_OnSetCursor(HWND hwnd, HWND hCursor, UINT hitTest, UINT messageId)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return FALSE;
+
+ if (0 == (TBS_MENULOOP & toolbar->flags) && hwnd == hCursor)
+ {
+ ToolbarItem *item = (NULL != toolbar->pressed) ? toolbar->pressed : toolbar->highlighted;
+ if (NULL != item && FALSE != item->SetCursor(hwnd, hCursor, hitTest, messageId))
+ {
+ return TRUE;
+ }
+ }
+
+ return DefWindowProcW(hwnd, WM_SETCURSOR, (WPARAM)hCursor, MAKELPARAM(hitTest, messageId));
+}
+
+static LRESULT Toolbar_OnColorEdit(HWND hwnd, HDC hdcCtrl, HWND hwndCtrl)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return 0;
+
+ SetTextColor(hdcCtrl, toolbar->rgbEdit);
+ SetBkColor(hdcCtrl, toolbar->rgbEditBk);
+ return (LRESULT)Toolbar_GetBrush(hwnd, TOOLBRUSH_ITEMBK);
+}
+
+static LRESULT Toolbar_OnColorStatic(HWND hwnd, HDC hdcCtrl, HWND hwndCtrl)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return 0;
+
+ SetTextColor(hdcCtrl, toolbar->rgbText);
+ SetBkColor(hdcCtrl, toolbar->rgbBk);
+ return (LRESULT)Toolbar_GetBrush(hwnd, TOOLBRUSH_BACK);
+}
+
+
+static LRESULT Toolbar_OnGetIdealHeight(HWND hwnd)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar || NULL == toolbar->imageList) return 0;
+
+ INT toolbarHeight, iconWidth;
+ if (!ImageList_GetIconSize(toolbar->imageList, &iconWidth, &toolbarHeight))
+ toolbarHeight = 0;
+ else
+ toolbarHeight /= TOOLBAR_ICONSTATE_COUNT;
+
+ HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
+ if (NULL != hdc)
+ {
+ HFONT originalFont = (HFONT)SelectObject(hdc, toolbar->textFont);
+ TEXTMETRIC tm;
+ if (GetTextMetrics(hdc, &tm))
+ {
+ tm.tmHeight += ((tm.tmHeight - (tm.tmAscent - tm.tmInternalLeading))/2 + 2);
+ if (toolbarHeight <= tm.tmHeight)
+ toolbarHeight = tm.tmHeight + 4;
+ }
+ SelectObject(hdc, originalFont);
+ ReleaseDC(hwnd, hdc);
+ }
+ return toolbarHeight + TOOLBAR_SPACE_TOP + TOOLBAR_SPACE_BOTTOM;
+}
+
+static void Toolbar_OnUpdateSkin(HWND hwnd, BOOL fRedraw)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return;
+
+ ifc_skinhelper *skinHelper;
+ if (FAILED(Plugin_GetSkinHelper(&skinHelper)))
+ skinHelper = NULL;
+
+ Toolbar_UpdateColorTable(hwnd, skinHelper);
+ Toolbar_ClearBrushCache(hwnd);
+
+ if (NULL != toolbar->imageList)
+ ImageList_Destroy(toolbar->imageList);
+
+ toolbar->imageList = Toolbar_LoadImagelist(toolbar, Plugin_GetInstance(),
+ MAKEINTRESOURCE(IDR_TOOLBARLARGE_IMAGE),
+ 21, TOOLBAR_ICONSTATE_COUNT);
+
+ if (NULL != toolbar->ownedFont)
+ {
+ DeleteObject(toolbar->ownedFont);
+ }
+
+ HFONT font = (NULL != skinHelper) ? skinHelper->GetFont() : NULL;
+
+ if (0/* create custom font */)
+ {
+ toolbar->ownedFont = Toolbar_CreateFont(font);
+ if (NULL != toolbar->ownedFont)
+ font = toolbar->ownedFont;
+ }
+ else
+ {
+ toolbar->ownedFont = NULL;
+ }
+
+ SendMessage(hwnd, WM_SETFONT, (WPARAM)font, FALSE);
+
+ if (NULL != toolbar->hTooltip)
+ {
+ SendMessage(toolbar->hTooltip, WM_SETFONT, (WPARAM)(toolbar->textFont), TRUE);
+ }
+
+ Toolbar_UpdateUiFlags(hwnd);
+
+ if (NULL != toolbar->items)
+ {
+ size_t index = toolbar->items->size();
+ while(index-- > 0)
+ {
+ ToolbarItem *item = toolbar->items->at(index);
+ if (NULL != item)
+ {
+ item->UpdateSkin(hwnd);
+ }
+ }
+ }
+
+ Toolbar_UpdateLayout(hwnd, FALSE);
+
+ if (FALSE != fRedraw)
+ InvalidateRect(hwnd, NULL, TRUE);
+
+ if (NULL != skinHelper)
+ skinHelper->Release();
+}
+
+
+static LRESULT Toolbar_OnGetIconSize(HWND hwnd, INT iconIndex, SIZE *pSize)
+{
+ if (NULL == pSize) return FALSE;
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+
+ if (ICON_CHEVRON == iconIndex)
+ {
+ UINT windowStyle = GetWindowStyle(hwnd);
+ iconIndex = (0 != (TBS_BOTTOMDOCK & windowStyle)) ? ICON_CHEVRON_BOTTOM : ICON_CHEVRON_TOP;
+ }
+
+ if (NULL == toolbar ||
+ NULL == toolbar->imageList ||
+ iconIndex < 0 ||
+ iconIndex >= ImageList_GetImageCount(toolbar->imageList))
+ {
+ ZeroMemory(pSize, sizeof(SIZE));
+ return FALSE;
+ }
+
+ INT cx, cy;
+ BOOL result = ImageList_GetIconSize(toolbar->imageList, &cx, &cy);
+
+ if (FALSE != result)
+ {
+ pSize->cy = cy / TOOLBAR_ICONSTATE_COUNT;
+ switch(iconIndex)
+ {
+ case ICON_SEPARATOR:
+ pSize->cx = ICON_SEPARATOR_WIDTH;
+ break;
+ case ICON_CHEVRON_TOP:
+ case ICON_CHEVRON_BOTTOM:
+ pSize->cx = ICON_CHEVRON_WIDTH;
+ break;
+ case ICON_HISTORY:
+ pSize->cx = ICON_HISTORY_WIDTH;
+ break;
+ case ICON_BACK:
+ case ICON_FORWARD:
+ pSize->cx =ICON_ARROW_WIDTH;
+ break;
+ default:
+ pSize->cx = cx;
+ break;
+ }
+
+ }
+ else
+ ZeroMemory(pSize, sizeof(SIZE));
+ return result;
+}
+
+static LRESULT Toolbar_OnSendCommand(HWND hwnd, INT commandId)
+{
+ HWND hParent = GetParent(hwnd);
+ if (NULL == hParent) return FALSE;
+
+ if (ID_CHEVRON_CLICKED == commandId)
+ {
+ Toolbar_DisplayChevronMenu(hwnd);
+ return 0;
+ }
+
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL != toolbar && NULL != toolbar->items)
+ {
+ size_t index= toolbar->items->size();
+ while(index--)
+ toolbar->items->at(index)->CommandSent(hwnd, commandId);
+ }
+ return SendMessage(hParent, WM_COMMAND, MAKEWPARAM(commandId, 0), (LPARAM)hwnd);
+}
+
+static LRESULT Toolbar_OnDrawIcon(HWND hwnd, TOOLBARDRAWICONPARAM *iconParam)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar || NULL == iconParam) return FALSE;
+ INT iconIndex = iconParam->iconIndex;
+ if (ICON_CHEVRON == iconIndex)
+ {
+ UINT windowStyle = GetWindowStyle(hwnd);
+ iconIndex = (0 != (TBS_BOTTOMDOCK & windowStyle)) ? ICON_CHEVRON_BOTTOM : ICON_CHEVRON_TOP;
+ }
+
+ if (NULL == toolbar->imageList ||
+ iconIndex < 0 ||
+ iconIndex >= ImageList_GetImageCount(toolbar->imageList))
+ {
+ return FALSE;
+ }
+
+
+
+ INT frameHeight, frameWidth;
+ if (!ImageList_GetIconSize(toolbar->imageList, &frameWidth, &frameHeight))
+ {
+ frameHeight = 0;
+ frameWidth = 0;
+ }
+
+ INT offsetY;
+ if (0 != (ToolbarItem::stateDisabled & iconParam->itemState))
+ offsetY = TOOLBAR_ICONSTATE_DISABLED;
+ else if (0 != (ToolbarItem::statePressed & iconParam->itemState))
+ offsetY = TOOLBAR_ICONSTATE_PRESSED;
+ else if (0 != (ToolbarItem::stateHighlighted & iconParam->itemState))
+ offsetY = TOOLBAR_ICONSTATE_HIGHLIGHTED;
+ else
+ offsetY = TOOLBAR_ICONSTATE_NORMAL;
+
+ frameHeight = frameHeight / TOOLBAR_ICONSTATE_COUNT;
+
+ IMAGELISTDRAWPARAMS param;
+ param.cbSize = sizeof(IMAGELISTDRAWPARAMS) - sizeof(DWORD) * 3;
+ param.himl = toolbar->imageList;
+ param.i = iconIndex;
+ param.hdcDst = iconParam->hdcDst;
+ param.x = iconParam->x;
+ param.y = iconParam->y;
+ param.cx = (iconParam->cx > frameWidth) ? frameWidth : iconParam->cx;
+ param.cy = (iconParam->cy > frameHeight) ? frameHeight : iconParam->cy;
+ param.xBitmap = 0;
+ param.yBitmap = frameHeight * offsetY;
+ param.rgbBk = CLR_NONE;
+ param.rgbFg = CLR_NONE;
+ param.fStyle = ILD_NORMAL;
+ param.dwRop = SRCCOPY;
+ param.fState = ILS_NORMAL;
+ param.Frame = 0;
+ param.crEffect = 0;
+
+ return ImageList_DrawIndirect(&param);
+}
+
+static LRESULT Toolbar_OnGetItemCount(HWND hwnd)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar || NULL == toolbar->items) return 0;
+ return (INT)toolbar->items->size();
+}
+
+static LRESULT Toolbar_OnClear(HWND hwnd)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return FALSE;
+ if (NULL == toolbar->items) return TRUE;
+
+ Toolbar_ClearItems(toolbar);
+
+ UINT windowStyle = GetWindowStyle(hwnd);
+ if (0 == (TBS_LOCKUPDATE & windowStyle))
+ {
+ Toolbar_UpdateTabstop(hwnd);
+ Toolbar_UpdateLayout(hwnd, FALSE);
+ InvalidateRect(hwnd, NULL, TRUE);
+ }
+
+ return TRUE;
+}
+
+static LRESULT Toolbar_OnInsertItem(HWND hwnd, TOOLBARINSERTITEM *insertItem)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar || NULL == toolbar->items ||
+ NULL == insertItem || insertItem->cbSize != sizeof(TOOLBARINSERTITEM))
+ {
+ return -1;
+ }
+
+ INT index = ITEM_ERR;
+
+ UINT styleOverride = 0;
+ if (0 != (TBIS_HIDDEN & insertItem->style)) styleOverride |= ToolbarItem::stateHidden;
+ if (0 != (TBIS_DISABLED & insertItem->style)) styleOverride |= ToolbarItem::stateDisabled;
+ if (0 != (TBIS_CHEVRONONLY & insertItem->style)) styleOverride |= ToolbarItem::styleChevronOnly;
+ if (0 != (TBIS_NOCHEVRON & insertItem->style)) styleOverride |= ToolbarItem::styleNoChevron;
+ if (0 != (TBIS_POPUP & insertItem->style)) styleOverride |= ToolbarItem::stylePopup;
+
+ ToolbarItem *item = Toolbar_CreateItem(insertItem->pszName, styleOverride);
+ if (NULL != item)
+ {
+ index = Toolbar_InsertItemInternal(toolbar, item, insertItem->insertBefore, hwnd);
+ item->Release();
+ if (ITEM_ERR != index)
+ {
+ UINT windowStyle = GetWindowStyle(hwnd);
+ if (0 == (TBS_LOCKUPDATE & windowStyle))
+ {
+ Toolbar_UpdateTabstop(hwnd);
+ Toolbar_UpdateLayout(hwnd, FALSE);
+ InvalidateRect(hwnd, NULL, TRUE);
+ }
+ }
+ }
+
+ return index;
+}
+
+static LRESULT Toolbar_OnFindItem(HWND hwnd, LPCSTR pszName)
+{
+ return Toolbar_ResolveName(hwnd, pszName);
+}
+
+static LRESULT Toolbar_OnRemoveItem(HWND hwnd, LPCSTR pszName)
+{
+ INT index = Toolbar_ResolveName(hwnd, pszName);
+ if (ITEM_ERR == index) return FALSE;
+
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar || NULL == toolbar->items || index == toolbar->items->size())
+ return FALSE;
+
+ ToolbarItem *item = toolbar->items->at(index);
+ toolbar->items->erase(toolbar->items->begin() + index);
+ if (NULL != item) item->Release();
+
+ UINT windowStyle = GetWindowStyle(hwnd);
+ if (0 == (TBS_LOCKUPDATE & windowStyle))
+ {
+ Toolbar_UpdateTabstop(hwnd);
+ Toolbar_UpdateLayout(hwnd, FALSE);
+ InvalidateRect(hwnd, NULL, TRUE);
+ }
+
+ return TRUE;
+}
+
+
+static LRESULT Toolbar_OnSetItemInt(HWND hwnd, LPCSTR pszName, INT value)
+{
+ INT index = Toolbar_ResolveName(hwnd, pszName);
+ if (ITEM_ERR == index) return FALSE;
+
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (index == toolbar->items->size()) return FALSE;
+ return toolbar->items->at(index)->SetValueInt(hwnd, value);
+}
+
+static LRESULT Toolbar_OnSetItemString(HWND hwnd, LPCSTR pszName, LPCWSTR value)
+{
+ INT index = Toolbar_ResolveName(hwnd, pszName);
+ if (ITEM_ERR == index) return FALSE;
+
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (index == toolbar->items->size()) return FALSE;
+ return toolbar->items->at(index)->SetValueStr(hwnd, value);
+}
+static COLORREF Toolbar_OnGetBkColor(HWND hwnd)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ return (NULL != toolbar) ? toolbar->rgbBk : 0x00FF00FF;
+}
+static COLORREF Toolbar_OnGetFgColor(HWND hwnd)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ return (NULL != toolbar) ? toolbar->rgbFg : 0x00FF00FF;
+}
+
+static COLORREF Toolbar_OnGetTextColor(HWND hwnd)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ return (NULL != toolbar) ? toolbar->rgbText : 0x00FF00FF;
+}
+
+static COLORREF Toolbar_OnGetHiliteColor(HWND hwnd)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ return (NULL != toolbar) ? toolbar->rgbHilite : 0x00FF00FF;
+}
+
+static COLORREF Toolbar_OnGetEditColor(HWND hwnd)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ return (NULL != toolbar) ? toolbar->rgbEdit : 0x00FF00FF;
+}
+
+static COLORREF Toolbar_OnGetEditBkColor(HWND hwnd)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ return (NULL != toolbar) ? toolbar->rgbEditBk : 0x00FF00FF;
+}
+
+static LRESULT Toolbar_OnEnableItem(HWND hwnd, LPCSTR pszName, BOOL fEnable)
+{
+ INT index = Toolbar_ResolveName(hwnd, pszName);
+ if (ITEM_ERR == index) return FALSE;
+
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (index == toolbar->items->size()) return FALSE;
+
+ ToolbarItem *item = toolbar->items->at(index);
+ if (NULL == item) return FALSE;
+
+ item->SetStyle(hwnd, (0 != fEnable) ? 0 : ToolbarItem::stateDisabled, ToolbarItem::stateDisabled);
+ if (FALSE == fEnable && toolbar->highlighted == item)
+ Toolbar_SetTooltipItem(hwnd, NULL);
+
+ Toolbar_UpdateTabstop(hwnd);
+
+ return TRUE;
+}
+
+static LRESULT Toolbar_OnGetItemStyle(HWND hwnd, LPCSTR pszName, UINT fMask)
+{
+ INT index = Toolbar_ResolveName(hwnd, pszName);
+ if (ITEM_ERR == index) return 0;
+
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (index == toolbar->items->size()) return 0;
+
+ UINT itemStyle = toolbar->items->at(index)->GetStyle();
+ return (itemStyle & fMask);
+}
+
+static LRESULT Toolbar_OnGetItemCommand(HWND hwnd, LPCSTR pszName)
+{
+ INT index = Toolbar_ResolveName(hwnd, pszName);
+ if (ITEM_ERR == index) return 0;
+
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (index == toolbar->items->size()) return 0;
+
+ return toolbar->items->at(index)->GetCommandId();
+}
+
+static LRESULT Toolbar_OnShowItem(HWND hwnd, LPCSTR pszName, BOOL fShow)
+{
+ INT index = Toolbar_ResolveName(hwnd, pszName);
+ if (ITEM_ERR == index) return FALSE;
+
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (index == toolbar->items->size()) return FALSE;
+
+ ToolbarItem *item = toolbar->items->at(index);
+ if (NULL == item) return FALSE;
+
+ UINT style = item->GetStyle();
+ if ((0 != (ToolbarItem::stateHidden & style)) == (FALSE == fShow))
+ return TRUE;
+
+ item->SetStyle(hwnd, (0 != fShow) ? 0 : ToolbarItem::stateHidden, ToolbarItem::stateHidden);
+
+ UINT windowStyle = GetWindowStyle(hwnd);
+ if (0 == (TBS_LOCKUPDATE & windowStyle))
+ {
+ Toolbar_UpdateTabstop(hwnd);
+ Toolbar_UpdateLayout(hwnd, FALSE);
+ InvalidateRect(hwnd, NULL, TRUE);
+ }
+
+ return TRUE;
+}
+
+static LRESULT Toolbar_OnSetItemDescription(HWND hwnd, LPCSTR pszName, LPCWSTR pszDescription)
+{
+ INT index = Toolbar_ResolveName(hwnd, pszName);
+ if (ITEM_ERR == index) return FALSE;
+
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (index == toolbar->items->size()) return FALSE;
+
+ ToolbarItem *item = toolbar->items->at(index);
+ if (NULL == item) return FALSE;
+
+ if (FALSE == item->SetDescription(hwnd, pszDescription))
+ return FALSE;
+
+ if (IsWindowVisible(hwnd) && IsWindowEnabled(hwnd))
+ Toolbar_UpdateTip(hwnd);
+
+ return TRUE;
+}
+
+
+static void Toolbar_OnUpdateTip(HWND hwnd)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL != toolbar && NULL != toolbar->hTooltip)
+ {
+ TOOLINFO ti;
+ ti.cbSize = sizeof(TOOLINFO);
+ ti.uId = 0;
+ ti.hinst = NULL;
+ ti.hwnd = hwnd;
+ ti.lpszText = LPSTR_TEXTCALLBACK;
+ SendMessage(toolbar->hTooltip, TTM_UPDATETIPTEXT, 0, (LPARAM)&ti);
+ }
+
+}
+
+static LRESULT Toolbar_OnGetTextMetrics(HWND hwnd, TOOLBARTEXTMETRIC *metric)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return FALSE;
+ CopyMemory(metric, &toolbar->textMetric, sizeof(TOOLBARTEXTMETRIC));
+ return TRUE;
+}
+
+static LRESULT Toolbar_OnGetBkBrush(HWND hwnd)
+{
+ return (LRESULT)Toolbar_GetBrush(hwnd, TOOLBRUSH_BACK);
+}
+
+static LRESULT Toolbar_OnLayout(HWND hwnd, TOOLBARLAYOUT *layout)
+{
+ if (NULL == layout)
+ return FALSE;
+
+ CopyRect(&layout->clientRect, layout->prcParent);
+ DWORD windowStyle = GetWindowStyle(hwnd);
+
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar || 0 == (WS_VISIBLE & windowStyle))
+ {
+ layout->insertAfter = HWND_BOTTOM;
+ SetRectEmpty(&layout->toolbarRect);
+ return TRUE;
+ }
+
+ CopyRect(&layout->toolbarRect, layout->prcParent);
+
+ INT toolbarHeight, clientInflate;
+
+ if (0 != (TBS_AUTOHIDE & windowStyle))
+ {
+ clientInflate = TOOLBAR_HIDDENHEIGHT;
+ toolbarHeight = (0 == (TBS_HIDDEN & toolbar->flags)) ?
+ Toolbar_GetIdealHeight(hwnd) : TOOLBAR_HIDDENHEIGHT;
+ }
+ else
+ {
+ toolbarHeight = Toolbar_GetIdealHeight(hwnd);
+ clientInflate = toolbarHeight;
+ }
+
+
+ if (0 != (TBS_BOTTOMDOCK & windowStyle))
+ {
+ layout->toolbarRect.top = layout->toolbarRect.bottom - toolbarHeight;
+ if (layout->toolbarRect.top < layout->prcParent->top)
+ layout->toolbarRect.top = layout->prcParent->top;
+ layout->clientRect.bottom -= clientInflate;
+ layout->insertAfter = (0 == (TBS_AUTOHIDE & windowStyle) || 0 != (TBS_HIDDEN & toolbar->flags)) ?
+ HWND_BOTTOM : HWND_TOP;
+ }
+ else
+ {
+ layout->toolbarRect.bottom = layout->toolbarRect.top + toolbarHeight;
+ if (layout->toolbarRect.bottom > layout->prcParent->bottom)
+ layout->toolbarRect.bottom = layout->prcParent->bottom;
+ layout->clientRect.top += clientInflate;
+ layout->insertAfter = HWND_TOP;
+ }
+
+ return TRUE;
+}
+
+static BOOL Toolbar_OnNextItem(HWND hwnd, LPCSTR pszName, BOOL fUseName)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return FALSE;
+
+ size_t focusIndex = toolbar->iFocused;
+ if (FALSE == fUseName)
+ {
+ focusIndex = Toolbar_GetFocusIndex(hwnd, toolbar->iFocused, 0, FALSE);
+ if (((size_t)-1) == focusIndex)
+ {
+ if (TBNS_NEXTITEM == pszName)
+ {
+ focusIndex = toolbar->items->size();
+ if (focusIndex > 0) focusIndex--;
+ }
+ else
+ {
+ focusIndex = 0;
+ }
+ }
+ else
+ {
+ if (TBNS_NEXTITEM == pszName)
+ {
+ if (focusIndex <= toolbar->items->size())
+ focusIndex = Toolbar_GetFocusIndex(hwnd, focusIndex + 1, 1, FALSE);
+ }
+ else
+ {
+ if (focusIndex > 0)
+ focusIndex = Toolbar_GetFocusIndex(hwnd, focusIndex - 1, -1, FALSE);
+ }
+
+ if (((size_t)-1) == focusIndex)
+ focusIndex = toolbar->iFocused;
+ }
+ }
+ else
+ {
+ INT index = Toolbar_ResolveName(hwnd, pszName);
+ if (ITEM_ERR == index ||
+ !Toolbar_IsItemAcceptFocus(Toolbar_GetItem(toolbar, index), FALSE))
+ return FALSE;
+ focusIndex = (size_t)index;
+ }
+
+ BOOL focusChanged = FALSE;
+ if (focusIndex != toolbar->iFocused)
+ {
+ ToolbarItem *itemNew, *itemOld;
+
+ itemOld = Toolbar_GetItem(toolbar, toolbar->iFocused);
+ itemNew = Toolbar_GetItem(toolbar, focusIndex);
+ toolbar->iFocused = focusIndex;
+
+ if (NULL != itemOld) itemOld->SetFocus(hwnd, itemNew, FALSE);
+ if (NULL != itemNew) itemNew->SetFocus(hwnd, itemOld, TRUE);
+
+ focusChanged = TRUE;
+ }
+
+ HWND hFocus = GetFocus();
+ if (hwnd != hFocus && FALSE == IsChild(hwnd, hFocus))
+ {
+ if (IsWindowVisible(hwnd) && IsWindowEnabled(hwnd))
+ {
+ HWND hRoot = GetAncestor(hwnd, GA_ROOT);
+ if (NULL != hRoot)
+ SendMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)hwnd, TRUE);
+ if (hwnd != GetFocus())
+ SetFocus(hwnd);
+ }
+ }
+ else if (FALSE == focusChanged)
+ {
+ ToolbarItem *item = Toolbar_GetItem(toolbar, toolbar->iFocused);
+ if (NULL != item) item->SetFocus(hwnd, item, TRUE);
+ }
+
+ return TRUE;
+}
+
+static BOOL Toolbar_OnGetItemInfo(HWND hwnd, LPCSTR pszName, TBITEMINFO *itemInfo)
+{
+ if (NULL == itemInfo)
+ return FALSE;
+
+ INT index = Toolbar_ResolveName(hwnd, pszName);
+ if (ITEM_ERR == index) return FALSE;
+
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar || index == toolbar->items->size()) return FALSE;
+
+ ToolbarItem *item = toolbar->items->at(index);
+ if (NULL == item) return FALSE;
+
+ BOOL result = TRUE;
+
+ itemInfo->commandId = item->GetCommandId();
+ itemInfo->style = item->GetStyle();
+
+ if (NULL != itemInfo->pszText)
+ {
+ if (FAILED(item->GetText(itemInfo->pszText, itemInfo->cchText)))
+ result = FALSE;
+ }
+
+ if (NULL != itemInfo->pszDescription)
+ {
+ if (FAILED(item->GetDescription(itemInfo->pszDescription, itemInfo->cchDescription)))
+ result = FALSE;
+ }
+ return result;
+}
+
+
+static HRESULT Toolbar_GetServiceCommandState(HWND hBrowser,ifc_omservicecommand *serviceCommand, const GUID *commandGroup, UINT commandId, HRESULT defaultState)
+{
+ HRESULT state = (NULL != serviceCommand) ? serviceCommand->QueryState(hBrowser, commandGroup, commandId) : defaultState;
+ if (E_NOTIMPL == state)
+ state = defaultState;
+ return state;
+}
+
+static INT Toolbar_InsertItemHelper(HWND hwnd, LPCSTR pszName, UINT overrideStyle, INT insertBefore)
+{
+ INT index = ITEM_ERR;
+
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL != toolbar && NULL != toolbar->items)
+ {
+ ToolbarItem *item = Toolbar_CreateItem(pszName, overrideStyle);
+ if (NULL != item)
+ {
+ index = Toolbar_InsertItemInternal(toolbar, item, insertBefore, hwnd);
+ item->Release();
+ }
+ }
+ return index;
+}
+static INT Toolbar_AddItemHelper(HWND hwnd, LPCSTR pszName, UINT overrideStyle)
+{
+ return Toolbar_InsertItemHelper(hwnd, pszName, overrideStyle, TBIP_LAST);
+}
+
+static INT Toolbar_AddItemHelper2(HWND hwnd, LPCSTR pszName, UINT overrideStyle, ifc_omservicecommand *serviceCommand, const GUID *commandGroup, ULONG commandId, HRESULT defaultState)
+{
+ HWND hBrowser = GetParent(hwnd);
+ HRESULT commandState = Toolbar_GetServiceCommandState(hBrowser, serviceCommand, commandGroup, commandId, defaultState);
+ if (CMDSTATE_ENABLED != commandState)
+ return ITEM_ERR;
+
+ return Toolbar_AddItemHelper(hwnd, pszName, overrideStyle);
+}
+
+static LRESULT Toolbar_OnAutoPopulate(HWND hwnd, ifc_omservice *service, UINT flags)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar || NULL == toolbar->items)
+ return 0;
+
+ ifc_omservicecommand *serviceCommand;
+ if (NULL == service || FAILED(service->QueryInterface(IFC_OmServiceCommand, (void**)&serviceCommand)))
+ serviceCommand = NULL;
+
+ UINT windowStyle = GetWindowStyle(hwnd);
+
+ Toolbar_ClearItems(toolbar);
+
+ ToolbarItem *item;
+ HRESULT commandStatus;
+ size_t blockSize, currentSize;
+
+ HWND hBrowser = GetParent(hwnd);
+
+ // Back/Forward
+ commandStatus = Toolbar_GetServiceCommandState(hBrowser, serviceCommand, &CMDGROUP_NAVIGATION, NAVCOMMAND_BACKFORWARD, CMDSTATE_ENABLED);
+ if (SUCCEEDED(commandStatus))
+ {
+ Toolbar_AddItemHelper(hwnd, TOOLITEM_BUTTON_BACK, ToolbarItem::stateDisabled);
+ Toolbar_AddItemHelper(hwnd, TOOLITEM_BUTTON_FORWARD, ToolbarItem::stateDisabled);
+
+ // History
+ if (0 != toolbar->items->size())
+ {
+ Toolbar_AddItemHelper2(hwnd, TOOLITEM_BUTTON_HISTORY, ToolbarItem::stateDisabled | ToolbarItem::styleNoChevron,
+ serviceCommand, &CMDGROUP_NAVIGATION, NAVCOMMAND_HISTORY, CMDSTATE_ENABLED);
+ }
+ }
+
+ blockSize = toolbar->items->size();
+
+ // Home
+ Toolbar_AddItemHelper2(hwnd, TOOLITEM_BUTTON_HOME, ToolbarItem::stateDisabled,
+ serviceCommand, &CMDGROUP_NAVIGATION, NAVCOMMAND_HOME, CMDSTATE_ENABLED);
+
+ // Refresh
+ Toolbar_AddItemHelper2(hwnd, TOOLITEM_BUTTON_REFRESH, ToolbarItem::stateDisabled,
+ serviceCommand, &CMDGROUP_NAVIGATION, NAVCOMMAND_REFRESH, CMDSTATE_ENABLED);
+
+ // Stop
+ Toolbar_AddItemHelper2(hwnd, TOOLITEM_BUTTON_STOP, ToolbarItem::stateDisabled,
+ serviceCommand, &CMDGROUP_NAVIGATION, NAVCOMMAND_STOP, CMDSTATE_ENABLED);
+
+ currentSize = toolbar->items->size();
+ if (0 != blockSize && 0 != currentSize && blockSize != currentSize)
+ Toolbar_InsertItemHelper(hwnd, TOOLITEM_SPACE, ToolbarItem::styleNoChevron, (INT)blockSize);
+
+ BOOL fShowFlexSpace = TRUE;
+
+ // Addressbar
+ UINT style = ToolbarItem::styleNoChevron | ToolbarItem::stateDisabled | ToolbarItem::stylePopup;
+
+ if (0 == (TBS_FORCEADDRESS & windowStyle) &&
+ CMDSTATE_ENABLED != Toolbar_GetServiceCommandState(hBrowser, serviceCommand,
+ &CMDGROUP_ADDRESSBAR, ADDRESSCOMMAND_VISIBLE,
+ (0 != (TBS_SHOWADDRESS & windowStyle)) ? CMDSTATE_ENABLED : CMDSTATE_DISABLED))
+ {
+ style |= ToolbarItem::stateHidden;
+ }
+
+ if (CMDSTATE_ENABLED == Toolbar_GetServiceCommandState(hBrowser, serviceCommand,
+ &CMDGROUP_ADDRESSBAR, ADDRESSCOMMAND_READONLY,
+ (0 != (TBPF_READONLYADDRESS & flags) ? CMDSTATE_ENABLED : CMDSTATE_DISABLED)))
+ {
+ style |= ToolbarAddress::styleAddressReadonly;
+ }
+
+ if (0 == (TBS_FANCYADDRESS & windowStyle))
+ style |= ToolbarAddress::styleAddressShowReal;
+
+ if (ITEM_ERR != Toolbar_AddItemHelper(hwnd, TOOLITEM_ADDRESSBAR, style))
+ {
+ currentSize++;
+ if (0 == (ToolbarItem::stateHidden & style))
+ fShowFlexSpace = FALSE;
+ }
+
+
+
+ if (0 != currentSize)
+ {
+ Toolbar_AddItemHelper(hwnd, TOOLITEM_FLEXSPACE, ToolbarItem::stylePopup | ((FALSE == fShowFlexSpace) ? ToolbarItem::stateHidden : 0));
+ }
+
+ if (NULL != serviceCommand && 0 == (TBPF_NOSERVICECOMMANDS & flags))
+ {
+ blockSize = toolbar->items->size();
+
+ // Rating
+ commandStatus = Toolbar_GetServiceCommandState(hBrowser, serviceCommand, &CMDGROUP_SERVICE, SVCCOMMAND_RATE, CMDSTATE_UNKNOWN);
+ if (SUCCEEDED(commandStatus))
+ {
+ UINT rating;
+ if (NULL != service && SUCCEEDED(service->GetRating(&rating)))
+ {
+ if (ITEM_ERR != Toolbar_AddItemHelper(hwnd, TOOLITEM_USERRATING, 0))
+ Toolbar_SetItemInt(hwnd, TOOLITEM_USERRATING, rating);
+ }
+ }
+
+ // Show Info
+ Toolbar_AddItemHelper2(hwnd, TOOLITEM_CMDLINK_INFO, ToolbarItem::styleChevronOnly,
+ serviceCommand, &CMDGROUP_SERVICE, SVCCOMMAND_SHOWINFO, CMDSTATE_UNKNOWN);
+
+ // Report
+ Toolbar_AddItemHelper2(hwnd, TOOLITEM_CMDLINK_REPORT, ToolbarItem::styleChevronOnly,
+ serviceCommand, &CMDGROUP_SERVICE, SVCCOMMAND_REPORT, CMDSTATE_UNKNOWN);
+
+ // Remove
+ Toolbar_AddItemHelper2(hwnd, TOOLITEM_CMDLINK_UNSUBSCRIBE, ToolbarItem::styleChevronOnly,
+ serviceCommand, &CMDGROUP_SERVICE, SVCCOMMAND_UNSUBSCRIBE, CMDSTATE_UNKNOWN);
+
+ currentSize = toolbar->items->size();
+
+ if (0 != currentSize && blockSize != currentSize)
+ Toolbar_AddItemHelper(hwnd, TOOLITEM_SEPARATOR, ToolbarItem::styleChevronOnly);
+
+ }
+
+ const TOOLBARITEMINSERTREC szBrowserTools[] =
+ {
+ { TOOLITEM_BUTTON_SECURECONNECTION, ToolbarItem::stateHidden | ToolbarItem::stylePopup | ToolbarItem::styleNoChevron /*| TBIS_NOREMOVE*/ },
+ { TOOLITEM_BUTTON_SCRIPTERROR, ToolbarItem::stateHidden | ToolbarItem::stylePopup | ToolbarItem::styleNoChevron /*| TBIS_NOREMOVE*/},
+ { TOOLITEM_DOWNLOADPROGRESS, ToolbarItem::styleNoChevron | ToolbarItem::stateDisabled /*| TBIS_NOREMOVE*/},
+ };
+
+ for (INT i = 0; i < ARRAYSIZE(szBrowserTools); i++)
+ {
+ item = Toolbar_CreateItem(szBrowserTools[i].name, szBrowserTools[i].style);
+ if (NULL != item)
+ {
+ Toolbar_InsertItemInternal(toolbar, item, TBIP_LAST, hwnd);
+ item->Release();
+ }
+ }
+
+ if (0 == (TBS_LOCKUPDATE & windowStyle))
+ {
+ Toolbar_UpdateTabstop(hwnd);
+ Toolbar_UpdateLayout(hwnd, FALSE);
+ InvalidateRect(hwnd, NULL, TRUE);
+ }
+
+ if (NULL != serviceCommand)
+ serviceCommand->Release();
+
+ return (INT)(INT_PTR)toolbar->items->size();
+
+}
+
+static LRESULT Toolbar_OnEnableBottomDock(HWND hwnd, BOOL fEnable)
+{
+ UINT windowStyle = GetWindowStyle(hwnd);
+ UINT newStyle = windowStyle;
+
+ if (FALSE == fEnable)
+ newStyle &= ~TBS_BOTTOMDOCK;
+ else
+ newStyle |= TBS_BOTTOMDOCK;
+
+ if(newStyle == windowStyle)
+ return fEnable;
+
+ if (0 != (TBS_AUTOHIDE & windowStyle))
+ {
+ HWND hFocus = GetFocus();
+ if (hwnd == hFocus || IsChild(hwnd, hFocus))
+ Toolbar_AutoHideWindow(hwnd, TRUE);
+ }
+
+ SetWindowLongPtr(hwnd, GWL_STYLE, newStyle);
+
+
+ HWND hParent = GetParent(hwnd);
+ if (NULL != hParent)
+ {
+ SetWindowPos(hParent, NULL, 0, 0, 0, 0,
+ SWP_NOSIZE |SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
+ }
+
+ HWND insertAfter = HWND_TOP;
+ if (0 != (TBS_BOTTOMDOCK & newStyle))
+ {
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar ||
+ 0 == (TBS_AUTOHIDE & windowStyle) ||
+ 0 != (TBS_HIDDEN & toolbar->flags))
+ {
+ insertAfter = HWND_BOTTOM;
+ }
+ }
+
+ SetWindowPos(hwnd, insertAfter, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW);
+ InvalidateRect(hwnd, NULL, TRUE);
+
+ return !fEnable;
+}
+
+static LRESULT Toolbar_OnEnableAutoHide(HWND hwnd, BOOL fEnable)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return 0;
+
+ UINT windowStyle = GetWindowStyle(hwnd);
+ UINT newStyle = windowStyle;
+
+ KillTimer(hwnd, TIMER_AUTOHIDE_ID);
+ toolbar->flags &= ~TBS_HIDETIMERSET;
+
+ if (FALSE == fEnable)
+ {
+ newStyle &= ~TBS_AUTOHIDE;
+ toolbar->flags &= ~TBS_HIDDEN;
+ }
+ else
+ {
+ newStyle |= TBS_AUTOHIDE;
+
+ HWND hFocus = GetFocus();
+ if (hwnd != hFocus && FALSE == IsChild(hwnd, hFocus))
+ toolbar->flags |= TBS_HIDDEN;
+ }
+
+ if(newStyle == windowStyle)
+ return fEnable;
+
+
+ SetWindowLongPtr(hwnd, GWL_STYLE, newStyle);
+
+ HWND hParent = GetParent(hwnd);
+ if (NULL != hParent)
+ {
+ SetWindowPos(hParent, NULL, 0, 0, 0, 0,
+ SWP_NOSIZE |SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
+ }
+
+ InvalidateRect(hwnd, NULL, TRUE);
+
+ return !fEnable;
+}
+
+static LRESULT Toolbar_OnEnableTabStop(HWND hwnd, BOOL fEnable)
+{
+ UINT windowStyle = GetWindowStyle(hwnd);
+ UINT newStyle = windowStyle;
+
+ if (FALSE == fEnable)
+ newStyle &= ~TBS_TABSTOP;
+ else
+ newStyle |= TBS_TABSTOP;
+
+ if(newStyle == windowStyle)
+ return fEnable;
+
+ SetWindowLongPtr(hwnd, GWL_STYLE, newStyle);
+
+ Toolbar_UpdateTabstop(hwnd);
+
+ return !fEnable;
+}
+
+static LRESULT Toolbar_OnEnableForceAddress(HWND hwnd, BOOL fEnable)
+{
+ UINT windowStyle = GetWindowStyle(hwnd);
+ UINT newStyle = windowStyle;
+
+ if (FALSE == fEnable)
+ newStyle &= ~TBS_FORCEADDRESS;
+ else
+ newStyle |= TBS_FORCEADDRESS;
+
+ if(newStyle == windowStyle)
+ return fEnable;
+
+ SetWindowLongPtr(hwnd, GWL_STYLE, newStyle);
+
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL != toolbar && NULL != toolbar->items)
+ {
+ size_t index = toolbar->items->size();
+ while(index--)
+ {
+ ToolbarItem *item = toolbar->items->at(index);
+ if (NULL != item && item->IsEqual(TOOLITEM_ADDRESSBAR, -1))
+ {
+ UINT itemStyle = item->GetStyle();
+ if (FALSE != fEnable)
+ {
+ if (0 != (ToolbarItem::stateHidden & itemStyle))
+ {
+ Toolbar_LockUpdate(hwnd, TRUE);
+ if (FALSE != Toolbar_ShowItem(hwnd, MAKEINTRESOURCE(index), TRUE))
+ {
+ size_t nextIndex = index + 1;
+ if (nextIndex < toolbar->items->size())
+ {
+ ToolbarItem *nextItem = toolbar->items->at(nextIndex);
+ if (NULL != nextItem && nextItem->IsEqual(TOOLITEM_FLEXSPACE, -1))
+ {
+ Toolbar_ShowItem(hwnd, MAKEINTRESOURCE(nextIndex), FALSE);
+ }
+ }
+ }
+ Toolbar_LockUpdate(hwnd, FALSE);
+ InvalidateRect(hwnd, NULL, TRUE);
+ }
+ }
+ else
+ {
+ HRESULT commandState = E_NOTIMPL;
+ HWND hBrowser = GetParent(hwnd);
+ ifc_omservice *service;
+ if (NULL != hBrowser && FALSE != BrowserControl_GetService(hBrowser, &service))
+ {
+ ifc_omservicecommand *serviceCommand;
+ if (SUCCEEDED(service->QueryInterface(IFC_OmServiceCommand, (void**)&serviceCommand)))
+ {
+ commandState = serviceCommand->QueryState(hBrowser, &CMDGROUP_ADDRESSBAR, ADDRESSCOMMAND_VISIBLE);
+ serviceCommand->Release();
+ }
+ service->Release();
+ }
+
+ if (E_NOTIMPL == commandState)
+ commandState = (0 != (TBS_SHOWADDRESS & windowStyle)) ? CMDSTATE_ENABLED : CMDSTATE_DISABLED;
+
+ if (0 == (ToolbarItem::stateHidden & itemStyle) && CMDSTATE_ENABLED != commandState)
+ {
+ Toolbar_LockUpdate(hwnd, TRUE);
+ if (FALSE != Toolbar_ShowItem(hwnd, MAKEINTRESOURCE(index), FALSE))
+ {
+ size_t nextIndex = index + 1;
+ if (nextIndex < toolbar->items->size())
+ {
+ ToolbarItem *nextItem = toolbar->items->at(nextIndex);
+ if (NULL != nextItem && nextItem->IsEqual(TOOLITEM_FLEXSPACE, -1))
+ {
+ Toolbar_ShowItem(hwnd, MAKEINTRESOURCE(nextIndex), TRUE);
+ }
+ }
+ }
+ Toolbar_LockUpdate(hwnd, FALSE);
+ InvalidateRect(hwnd, NULL, TRUE);
+ }
+
+
+ }
+ break;
+ }
+ }
+ }
+
+ return !fEnable;
+}
+
+static LRESULT Toolbar_OnEnableFancyAddress(HWND hwnd, BOOL fEnable)
+{
+ UINT windowStyle = GetWindowStyle(hwnd);
+ UINT newStyle = windowStyle;
+
+ if (FALSE == fEnable)
+ newStyle &= ~TBS_FANCYADDRESS;
+ else
+ newStyle |= TBS_FANCYADDRESS;
+
+ if(newStyle == windowStyle)
+ return fEnable;
+
+ SetWindowLongPtr(hwnd, GWL_STYLE, newStyle);
+
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL != toolbar && NULL != toolbar->items)
+ {
+ size_t index = toolbar->items->size();
+ while(index--)
+ {
+ ToolbarItem *item = toolbar->items->at(index);
+ if (NULL != item && item->IsEqual(TOOLITEM_ADDRESSBAR, -1))
+ {
+ UINT style = (FALSE != fEnable) ? 0 : ToolbarAddress::styleAddressShowReal;
+ item->SetStyle(hwnd, style, ToolbarAddress::styleAddressShowReal);
+ break;
+ }
+ }
+ }
+
+ return !fEnable;
+}
+
+static LRESULT Toolbar_OnSetBrowserHost(HWND hwnd, HWND hBrowser)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return 0;
+
+ toolbar->hBrowser = hBrowser;
+ return TRUE;
+}
+
+
+static LRESULT Toolbar_OnGetImageListHeight(HWND hwnd)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ INT iconCX, iconCY;
+ if (NULL == toolbar ||
+ NULL == toolbar->imageList ||
+ FALSE == ImageList_GetIconSize(toolbar->imageList, &iconCX, &iconCY))
+ {
+ return 0;
+ }
+
+ return iconCY/TOOLBAR_ICONSTATE_COUNT;
+}
+
+static LRESULT Toolbar_OnGetNextTabItem(HWND hwnd, LPCSTR pszName, BOOL fPrevious)
+{
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return ITEM_ERR;
+
+ INT index = Toolbar_ResolveName(hwnd, pszName);
+ if (ITEM_ERR == index)
+ return ITEM_ERR;
+
+ if (0 == index && FALSE == fPrevious)
+ return ITEM_ERR;
+
+ UINT windowStyle = GetWindowStyle(hwnd);
+ BOOL fTabstopOnly = (0 == (TBS_TABSTOP & windowStyle));
+ INT direction = (FALSE == fPrevious) ? 1 : -1;
+ return Toolbar_GetFocusIndex(hwnd, index + direction, direction, fTabstopOnly);
+}
+
+static void Toolbar_OnCheckHide(HWND hwnd, BOOL fImmediate)
+{
+ Toolbar_AutoHideWindow(hwnd, fImmediate);
+}
+
+static LRESULT Toolbar_OnGetTextLength(HWND hwnd, LPCSTR pszName, size_t *textLength)
+{
+ if (NULL == textLength) return FALSE;
+ *textLength = 0;
+
+ TOOLBAR *toolbar = GetToolbar(hwnd);
+ if (NULL == toolbar) return FALSE;
+
+ size_t index = Toolbar_ResolveName(hwnd, pszName);
+ if (ITEM_ERR == index) return FALSE;
+
+ ToolbarItem *item = Toolbar_GetItem(toolbar, index);
+ if (NULL == item) return FALSE;
+
+ if (FAILED(item->GetTextLength(textLength)))
+ return FALSE;
+
+ return TRUE;
+}
+
+static LRESULT CALLBACK Toolbar_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_CREATE: return Toolbar_OnCreate(hwnd, (CREATESTRUCT*)lParam);
+ case WM_DESTROY: Toolbar_OnDestroy(hwnd); break;
+ case WM_PAINT: Toolbar_OnPaint(hwnd); return 0;
+ case WM_PRINTCLIENT: Toolbar_OnPrintClient(hwnd, (HDC)wParam, (UINT)lParam); return 0;
+ case WM_ERASEBKGND: return 0;
+ case WM_WINDOWPOSCHANGED: Toolbar_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); return 0;
+ case WM_SETREDRAW: Toolbar_OnSetRedraw(hwnd, (BOOL)wParam); return 0;
+ case WM_MOUSEMOVE: Toolbar_OnMouseMove(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
+ case WM_MOUSELEAVE: Toolbar_OnMouseLeave(hwnd); return 0;
+ case WM_LBUTTONDOWN:
+ Toolbar_OnLButtonDown(hwnd, (UINT)wParam, MAKEPOINTS(lParam));
+ break;
+ case WM_LBUTTONUP: Toolbar_OnLButtonUp(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); break;
+ case WM_RBUTTONDOWN: Toolbar_OnRButtonDown(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); break;
+ case WM_RBUTTONUP: Toolbar_OnRButtonUp(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); break;
+ case WM_MBUTTONDOWN: Toolbar_OnMButtonDown(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); break;
+ case WM_MBUTTONUP: Toolbar_OnMButtonUp(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); break;
+ case WM_CAPTURECHANGED: Toolbar_OnCaptureChanged(hwnd, (HWND)lParam); return 0;
+ case WM_GETFONT: return Toolbar_OnGetFont(hwnd);
+ case WM_SETFONT: Toolbar_OnSetFont(hwnd, (HFONT)wParam, (BOOL)LOWORD(lParam)); return 0;
+ case WM_NOTIFY: return Toolbar_OnNotify(hwnd, (INT)wParam, (NMHDR*)lParam);
+ case WM_COMMAND: Toolbar_OnCommand(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); return 0;
+ case WM_ENTERMENULOOP: Toolbar_OnEnterMenuLoop(hwnd, (BOOL)wParam); return 0;
+ case WM_EXITMENULOOP: Toolbar_OnExitMenuLoop(hwnd, (BOOL)wParam); return 0;
+ case WM_SETFOCUS: Toolbar_OnSetFocus(hwnd, (HWND)wParam); return 0;
+ case WM_KILLFOCUS: Toolbar_OnKillFocus(hwnd, (HWND)wParam); return 0;
+ case WM_CONTEXTMENU: Toolbar_OnContextMenu(hwnd, (HWND)wParam, MAKEPOINTS(lParam)); return 0;
+ case WM_KEYDOWN: Toolbar_OnKeyDown(hwnd, (INT)wParam, (UINT)lParam); return 0;
+ case WM_KEYUP: Toolbar_OnKeyUp(hwnd, (INT)wParam, (UINT)lParam); return 0;
+ case WM_GETDLGCODE: return Toolbar_OnGetDlgCode(hwnd, (INT)wParam, (MSG*)lParam);
+ case WM_UPDATEUISTATE: Toolbar_OnUpdateUiState(hwnd, LOWORD(wParam), HIWORD(wParam)); return 0;
+ case WM_ENABLE: Toolbar_OnEnable(hwnd, (BOOL)wParam); return 0;
+ case WM_SETCURSOR: return Toolbar_OnSetCursor(hwnd, (HWND)wParam, LOWORD(lParam), HIWORD(lParam));
+ case WM_CTLCOLOREDIT: return Toolbar_OnColorEdit(hwnd, (HDC)wParam, (HWND)lParam);
+ case WM_CTLCOLORSTATIC: return Toolbar_OnColorStatic(hwnd, (HDC)wParam, (HWND)lParam);
+
+ case TBM_UPDATESKIN: Toolbar_OnUpdateSkin(hwnd, (BOOL)lParam); return 0;
+ case TBM_GETIDEALHEIGHT: return Toolbar_OnGetIdealHeight(hwnd);
+ case TBM_GETICONSIZE: return Toolbar_OnGetIconSize(hwnd, (INT)wParam, (SIZE*)lParam);
+ case TBM_SENDCOMMAND: return Toolbar_OnSendCommand(hwnd, (INT)wParam);
+ case TBM_DRAWICON: return Toolbar_OnDrawIcon(hwnd, (TOOLBARDRAWICONPARAM*)lParam);
+ case TBM_GETITEMCOUNT: return Toolbar_OnGetItemCount(hwnd);
+ case TBM_CLEAR: return Toolbar_OnClear(hwnd);
+ case TBM_INSERTITEM: return Toolbar_OnInsertItem(hwnd, (TOOLBARINSERTITEM*)lParam);
+ case TBM_FINDITEM: return Toolbar_OnFindItem(hwnd, (LPCSTR)lParam);
+ case TBM_REMOVEITEM: return Toolbar_OnRemoveItem(hwnd, (LPCSTR)lParam);
+ case TBM_SETITEMINT: return Toolbar_OnSetItemInt(hwnd, (LPCSTR)lParam, (INT)wParam);
+ case TBM_SETITEMSTRING: return Toolbar_OnSetItemString(hwnd, (LPCSTR)lParam, (LPCWSTR)wParam);
+ case TBM_GETBKCOLOR: return Toolbar_OnGetBkColor(hwnd);
+ case TBM_GETFGCOLOR: return Toolbar_OnGetFgColor(hwnd);
+ case TBM_GETTEXTCOLOR: return Toolbar_OnGetTextColor(hwnd);
+ case TBM_GETHILITECOLOR: return Toolbar_OnGetHiliteColor(hwnd);
+ case TBM_ENABLEITEM: return Toolbar_OnEnableItem(hwnd,(LPCSTR)lParam, (BOOL)wParam);
+ case TBM_SHOWITEM: return Toolbar_OnShowItem(hwnd,(LPCSTR)lParam, (BOOL)wParam);
+ case TBM_UPDATETIP: Toolbar_OnUpdateTip(hwnd); return 0;
+ case TBM_GETTEXTMETRICS: return Toolbar_OnGetTextMetrics(hwnd, (TOOLBARTEXTMETRIC*)lParam);
+ case TBM_GETBKBRUSH: return Toolbar_OnGetBkBrush(hwnd);
+ case TBM_LAYOUT: return Toolbar_OnLayout(hwnd, (TOOLBARLAYOUT*)lParam);
+ case TBM_NEXTITEM: return Toolbar_OnNextItem(hwnd, (LPCSTR)lParam, (BOOL)wParam);
+ case TBM_GETITEMSTYLE: return Toolbar_OnGetItemStyle(hwnd, (LPCSTR)lParam, (UINT)wParam);
+ case TBM_GETITEMCOMMAND: return Toolbar_OnGetItemCommand(hwnd, (LPCSTR)lParam);
+ case TBM_SETITEMDESCRIPTION:return Toolbar_OnSetItemDescription(hwnd, (LPCSTR)lParam, (LPCWSTR)wParam);
+ case TBM_GETITEMINFO: return Toolbar_OnGetItemInfo(hwnd, (LPCSTR)lParam, (TBITEMINFO*)wParam);
+ case TBM_AUTOPOPULATE: return Toolbar_OnAutoPopulate(hwnd, (ifc_omservice*)lParam, (UINT)wParam);
+ case TBM_ENABLEBOTTOMDOCK: return Toolbar_OnEnableBottomDock(hwnd, (BOOL)lParam);
+ case TBM_ENABLEAUTOHIDE: return Toolbar_OnEnableAutoHide(hwnd, (BOOL)lParam);
+ case TBM_ENABLETABSTOP: return Toolbar_OnEnableTabStop(hwnd, (BOOL)lParam);
+ case TBM_ENABLEFORCEADDRESS: return Toolbar_OnEnableForceAddress(hwnd, (BOOL)lParam);
+ case TBM_ENABLEFANCYADDRESS: return Toolbar_OnEnableFancyAddress(hwnd, (BOOL)lParam);
+ case TBM_SETBROWSERHOST: return Toolbar_OnSetBrowserHost(hwnd, (HWND)lParam);
+ case TBM_GETEDITCOLOR: return Toolbar_OnGetEditColor(hwnd);
+ case TBM_GETEDITBKCOLOR: return Toolbar_OnGetEditBkColor(hwnd);
+ case TBM_GETIMAGELISTHEIGHT:return Toolbar_OnGetImageListHeight(hwnd);
+ case TBM_GETNEXTTABITEM: return Toolbar_OnGetNextTabItem(hwnd, (LPCSTR)lParam, (BOOL)wParam);
+ case TBM_CHECKHIDE: Toolbar_OnCheckHide(hwnd, (BOOL)lParam); return 0;
+ case TBM_GETTEXTLENGTH: return Toolbar_OnGetTextLength(hwnd, (LPCSTR)lParam, (size_t*)wParam);
+ }
+ return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+}
+
+static LRESULT CALLBACK Toolbar_MouseHook(INT code, WPARAM wParam, LPARAM lParam)
+{
+ TOOLBARMOUSEHOOK *hook = (TOOLBARMOUSEHOOK*)Plugin_TlsGetValue(tlsIndex);
+ if (NULL == hook || NULL == hook->hHook) return FALSE;
+
+
+ if (code >= 0)
+ {
+ MOUSEHOOKSTRUCT *mouseHook = (MOUSEHOOKSTRUCT*)lParam;
+ if (mouseHook->hwnd != hook->hwnd)
+ {
+ TOOLBAR *toolbar = GetToolbar(hook->hwnd);
+ if (NULL != toolbar)
+ {
+ if (0 != (TBS_HIDDEN & toolbar->flags))
+ {
+ Toolbar_RemoveMouseHook(hook->hwnd, TRUE);
+ }
+ else if (0 == ((TBS_MENULOOP | TBS_HIDETIMERSET) & toolbar->flags))
+ {
+ HWND hAncestor = GetAncestor(mouseHook->hwnd, GA_ROOT);
+ BOOL autoHide;
+ if (NULL == hAncestor || FALSE == IsChild(hAncestor, hook->hwnd))
+ {
+ autoHide = TRUE;
+ }
+ else
+ {
+ RECT toolbarRect;
+ if (!GetWindowRect(hook->hwnd, &toolbarRect))
+ SetRectEmpty(&toolbarRect);
+ toolbarRect.top -= 6;
+ toolbarRect.bottom += 6;
+ autoHide = !PtInRect(&toolbarRect, mouseHook->pt);
+ }
+
+ if (FALSE != autoHide)
+ Toolbar_AutoHideWindow(hook->hwnd, FALSE);
+ }
+ }
+ }
+ }
+ return CallNextHookEx(hook->hHook, code, wParam, lParam);
+} \ No newline at end of file
diff --git a/Src/omBrowser/toolbar.h b/Src/omBrowser/toolbar.h
new file mode 100644
index 00000000..ef9ae581
--- /dev/null
+++ b/Src/omBrowser/toolbar.h
@@ -0,0 +1,293 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+// registered classes
+
+#define TOOLCLS_STATIC "static"
+#define TOOLCLS_BUTTON "button"
+#define TOOLCLS_RATING "rating"
+#define TOOLCLS_PROGRESS "progress"
+#define TOOLCLS_ADDRESSBAR "addressbar"
+
+#define TOOLITEM_SEPARATOR "separator"
+#define TOOLITEM_SPACE "space"
+#define TOOLITEM_FLEXSPACE "spaceFlexible"
+#define TOOLITEM_CHEVRON "chevron"
+
+#define TOOLITEM_BUTTON_HOME (TOOLCLS_BUTTON "Home")
+#define TOOLITEM_BUTTON_BACK (TOOLCLS_BUTTON "Back")
+#define TOOLITEM_BUTTON_FORWARD (TOOLCLS_BUTTON "Forward")
+#define TOOLITEM_BUTTON_STOP (TOOLCLS_BUTTON "Stop")
+#define TOOLITEM_BUTTON_REFRESH (TOOLCLS_BUTTON "Refresh")
+#define TOOLITEM_BUTTON_HISTORY (TOOLCLS_BUTTON "History")
+#define TOOLITEM_CMDLINK_INFO (TOOLCLS_BUTTON "Info")
+#define TOOLITEM_CMDLINK_REPORT (TOOLCLS_BUTTON "Report")
+#define TOOLITEM_CMDLINK_UNSUBSCRIBE (TOOLCLS_BUTTON "Unsubscribe")
+
+#define TOOLITEM_USERRATING (TOOLCLS_RATING "User")
+#define TOOLITEM_DOWNLOADPROGRESS (TOOLCLS_PROGRESS "Download")
+#define TOOLITEM_ADDRESSBAR (TOOLCLS_ADDRESSBAR "Main")
+
+#define TOOLITEM_BUTTON_SCRIPTERROR (TOOLCLS_BUTTON "ScriptError")
+#define TOOLITEM_BUTTON_SECURECONNECTION (TOOLCLS_BUTTON "SecureConnection")
+
+#define NWC_ONLINEMEDIATOOLBAR L"Nullsoft_omBrowserToolbar"
+
+
+BOOL Toolbar_RegisterClass(HINSTANCE hInstance);
+
+#define ITEM_ERR ((INT)-1)
+
+// styles
+#define TBS_LOCKUPDATE 0x00000001 // do not reset directly use Toolbar_LockUpdate().
+#define TBS_AUTOHIDE 0x00000002
+#define TBS_BOTTOMDOCK 0x00000004
+#define TBS_TABSTOP 0x00000008
+#define TBS_SHOWADDRESS 0x00000010
+#define TBS_FORCEADDRESS 0x00000020
+#define TBS_FANCYADDRESS 0x00000040
+
+// item styles
+#define TBIS_HIDDEN 0x0001
+#define TBIS_DISABLED 0x0002
+#define TBIS_CHEVRONONLY 0x0004 // show item only in chevron
+#define TBIS_NOCHEVRON 0x0008 // show item in toolbar and ignore in chevron
+#define TBIS_POPUP 0x0010 // item only take space when visible
+
+
+// messages
+#define TBM_FIRST (WM_USER + 10)
+
+#define TBM_UPDATESKIN (TBM_FIRST + 0) //wParam = not used, lParam = (LPARAM)(BOOL)fRedraw.
+#define Toolbar_UpdateSkin(/*HWND*/ __hToolbar, /*BOOL*/ __fRedraw)\
+ (SENDMSG(__hToolbar, TBM_UPDATESKIN, 0, (LPARAM)(__fRedraw)))
+
+#define TBM_GETIDEALHEIGHT (TBM_FIRST + 1)
+#define Toolbar_GetIdealHeight(/*HNWD*/__hToolbar)\
+ ((INT)SendMessage((__hToolbar), TBM_GETIDEALHEIGHT, 0, 0L))
+
+#define TBM_GETICONSIZE (TBM_FIRST + 3)
+#define Toolbar_GetIconSize(/*HWND*/ __hToolbar, /*INT*/ __iconIndex, /*PSIZE*/ __sizeOut)\
+ ((BOOL)SendMessage((__hToolbar), TBM_GETICONSIZE, (WPARAM)(__iconIndex), (LPARAM)(__sizeOut)))
+
+#define TBM_SENDCOMMAND (TBM_FIRST + 4)
+#define Toolbar_SendCommand(/*HWND*/ __hToolbar, /*INT*/ __commandId)\
+ ((BOOL)SendMessage((__hToolbar), TBM_SENDCOMMAND, (WPARAM)(__commandId), 0L))
+
+
+typedef struct __TOOLBARDRAWICONPARAM
+{
+ HDC hdcDst;
+ INT iconIndex;
+ INT x;
+ INT y;
+ INT cx;
+ INT cy;
+ UINT itemState;
+} TOOLBARDRAWICONPARAM;
+
+#define TBM_DRAWICON (TBM_FIRST + 5)
+#define Toolbar_DrawIcon(/*HWND*/ __hToolbar, /*TOOLBARDRAWICONPARAM* */ __toolbarDrawIconParam)\
+ ((BOOL)SendMessage((__hToolbar), TBM_DRAWICON, 0, (LPARAM)(__toolbarDrawIconParam)))
+
+#define Toolbar_LockUpdate(/*HWND*/ __hToolbar, /*BOOL*/__fLock)\
+ (SendMessage((__hToolbar), WM_SETREDRAW, (WPARAM)(0 == (__fLock)), 0L))
+
+#define TBM_GETITEMCOUNT (TBM_FIRST + 6)
+#define Toolbar_GetItemCount(/*HWND*/ __hToolbar)\
+ ((INT)SendMessage((__hToolbar), TBM_GETITEMCOUNT, 0, 0L))
+
+#define TBM_CLEAR (TBM_FIRST + 7)
+#define Toolbar_Clear(/*HWND*/ __hToolbar)\
+ ((BOOL)SendMessage((__hToolbar), TBM_CLEAR, 0, 0L))
+
+#define TBIP_FIRST 0x0000
+#define TBIP_LAST 0xFFFFFF
+
+typedef struct __TOOLBARINSERTITEM
+{
+ INT cbSize;
+ INT insertBefore; // you can use TBIP_XXX here
+ LPCSTR pszName;
+ UINT style;
+} TOOLBARINSERTITEM;
+
+#define TBM_INSERTITEM (TBM_FIRST + 8) // wParam - not used, lParam = (LPARAM)(TOOLBARINSERTITEM*)pInsertItem; Return item index or ITEM_ERR
+#define Toolbar_InsertItem(/*HWND*/ __hToolbar, /*TOOLBARINSERTITEM*/ __pInsertItem)\
+ ((INT)SendMessage((__hToolbar), TBM_INSERTITEM, 0, (LPARAM)__pInsertItem))
+
+#define TBM_FINDITEM (TBM_FIRST + 9)
+#define Toolbar_FindItem(/*HWND*/ __hToolbar, /*LPCSTR*/ __pszItemName)\
+ ((INT)SendMessage((__hToolbar), TBM_FINDITEM, 0, (LPARAM)(__pszItemName)))
+
+#define TBM_REMOVEITEM (TBM_FIRST + 10) // itemName can be INT index
+#define Toolbar_RemoveItem(/*HWND*/ __hToolbar, /*LPCSTR*/__pszItemName)\
+ ((BOOL)SendMessage((__hToolbar), TBM_REMOVEITEM, 0, (LPARAM)(__pszItemName)))
+
+#define TBM_SETITEMINT (TBM_FIRST + 11) // itemName can be INT index
+#define Toolbar_SetItemInt(/*HWND*/ __hToolbar, /*LPCSTR*/ __pszItemName, /*INT*/ __intValue)\
+ ((BOOL)SendMessage((__hToolbar), TBM_SETITEMINT, (WPARAM)(__intValue), (LPARAM)(__pszItemName)))
+
+#define TBM_SETITEMSTRING (TBM_FIRST + 12) // itemName can be INT index
+#define Toolbar_SetItemString(/*HWND*/ __hToolbar, /*LPCSTR*/ __pszItemName, /*LPCWSTR*/ __stringValue)\
+ ((BOOL)SendMessage((__hToolbar), TBM_SETITEMSTRING, (WPARAM)(__stringValue), (LPARAM)(__pszItemName)))
+
+#define TBM_GETBKCOLOR (TBM_FIRST + 13)
+#define Toolbar_GetBkColor(/*HWND*/ __hToolbar)\
+ ((COLORREF)SendMessage((__hToolbar), TBM_GETBKCOLOR, 0, 0L))
+
+#define TBM_GETFGCOLOR (TBM_FIRST + 14)
+#define Toolbar_GetFgColor(/*HWND*/ __hToolbar)\
+ ((COLORREF)SendMessage((__hToolbar), TBM_GETFGCOLOR, 0, 0L))
+
+#define TBM_GETTEXTCOLOR (TBM_FIRST + 15)
+#define Toolbar_GetTextColor(/*HWND*/ __hToolbar)\
+ ((COLORREF)SendMessage((__hToolbar), TBM_GETTEXTCOLOR, 0, 0L))
+
+#define TBM_GETHILITECOLOR (TBM_FIRST + 16)
+#define Toolbar_GetHiliteColor(/*HWND*/ __hToolbar)\
+ ((COLORREF)SendMessage((__hToolbar), TBM_GETHILITECOLOR, 0, 0L))
+
+#define TBM_ENABLEITEM (TBM_FIRST + 17) // itemName can be INT index
+#define Toolbar_EnableItem(/*HWND*/ __hToolbar, /*LPCSTR*/ __pszItemName, /*BOOL*/ __fEnable)\
+ ((BOOL)SendMessage((__hToolbar), TBM_ENABLEITEM, (WPARAM)(__fEnable), (LPARAM)(__pszItemName)))
+
+#define TBM_SHOWITEM (TBM_FIRST + 18) // itemName can be INT index
+#define Toolbar_ShowItem(/*HWND*/ __hToolbar, /*LPCSTR*/ __pszItemName, /*BOOL*/ __fShow)\
+ ((BOOL)SendMessage((__hToolbar), TBM_SHOWITEM, (WPARAM)(__fShow), (LPARAM)(__pszItemName)))
+
+#define TBM_UPDATETIP (TBM_FIRST + 19)
+#define Toolbar_UpdateTip(/*HWND*/ __hToolbar)\
+ ((BOOL)SendMessage((__hToolbar), TBM_UPDATETIP, 0, 0L))
+
+typedef struct __TOOLBARTEXTMETRIC
+{
+ INT height;
+ INT baseY;
+ INT origY;
+ INT aveCharWidth;
+ INT overhang;
+} TOOLBARTEXTMETRIC;
+
+#define TBM_GETTEXTMETRICS (TBM_FIRST + 20)
+#define Toolbar_GetTextMetrics(/*HWND*/ __hToolbar, /*TOOLBARTEXTMETRIC* */ __textMetric)\
+ ((BOOL)SendMessage((__hToolbar), TBM_GETTEXTMETRICS, 0, (LPARAM)__textMetric))
+
+#define TBM_GETBKBRUSH (TBM_FIRST + 21)
+#define Toolbar_GetBkBrush(/*HWND*/ __hToolbar)\
+ ((HBRUSH)SendMessage((__hToolbar), TBM_GETBKBRUSH, 0, 0L))
+
+typedef struct __TOOLBARLAYOUT
+{
+ const RECT *prcParent; // [in] - parent window rect
+ HWND insertAfter; // [out] - toolar insert after
+ RECT toolbarRect; // [out] - toolbar rect
+ RECT clientRect; // [out] - new parent client rect
+} TOOLBARLAYOUT;
+
+#define TBM_LAYOUT (TBM_FIRST + 22)
+#define Toolbar_Layout(/*HWND*/ __hToolbar, /*TOOLBARLAYOUT* */ __pLayout)\
+ ((BOOL)SendMessage((__hToolbar), TBM_LAYOUT, 0, (LPARAM)(__pLayout)))
+
+#define TBNS_NEXTITEM MAKEINTRESOURCEA(0)
+#define TBNS_PREVITEM MAKEINTRESOURCEA(1)
+
+#define TBM_NEXTITEM (TBM_FIRST + 23)
+#define Toolbar_NextItem(/*HWND*/ __hToolbar, /*LPCSTR*/ __pszItemName, /*BOOL*/ __fUseName)\
+ ((BOOL)SendMessage((__hToolbar), TBM_NEXTITEM, (WPARAM)(__fUseName), (LPARAM)(__pszItemName)))
+
+#define TBM_GETITEMSTYLE (TBM_FIRST + 24) // itemName can be INT index,
+#define Toolbar_GetItemStyle(/*HWND*/ __hToolbar, /*LPCSTR*/ __pszItemName, /*UINT*/ __fMask)\
+ ((UINT)SendMessage((__hToolbar), TBM_GETITEMSTYLE, (WPARAM)(__fMask), (LPARAM)(__pszItemName)))
+
+#define TBM_GETITEMCOMMAND (TBM_FIRST + 25) // itemName can be INT index,
+#define Toolbar_GetItemCommand(/*HWND*/ __hToolbar, /*LPCSTR*/ __pszItemName)\
+ ((INT)SendMessage((__hToolbar), TBM_GETITEMCOMMAND, 0, (LPARAM)(__pszItemName)))
+
+#define TBM_SETITEMDESCRIPTION (TBM_FIRST + 26) // itemName can be INT index
+#define Toolbar_SetItemDescription(/*HWND*/ __hToolbar, /*LPCSTR*/ __pszItemName, /*LPCWSTR*/__pszDescription)\
+ ((BOOL)SendMessage((__hToolbar), TBM_SETITEMDESCRIPTION, (WPARAM)(__pszDescription), (LPARAM)(__pszItemName)))
+
+typedef struct __TBITEMINFO
+{
+ INT commandId;
+ UINT style;
+ LPWSTR pszText;
+ INT cchText;
+ LPWSTR pszDescription;
+ INT cchDescription;
+} TBITEMINFO;
+
+#define TBM_GETITEMINFO (TBM_FIRST + 27) // itemName can be INT index
+#define Toolbar_GetItemInfo(/*HWND*/ __hToolbar, /*LPCSTR*/ __pszItemName, /*TBITEM* */__itemInfo)\
+ ((BOOL)SendMessage((__hToolbar), TBM_GETITEMINFO, (WPARAM)(__itemInfo), (LPARAM)(__pszItemName)))
+
+#define TBPF_NORMAL 0x00000000
+#define TBPF_NOSERVICECOMMANDS 0x00000001
+#define TBPF_READONLYADDRESS 0x00000004
+
+#define TBM_AUTOPOPULATE (TBM_FIRST + 28) //wParam - (WPARAM)(UINT)populateFlags; lParam = (LPARAM)(ifc_omservice*)service; Return: number of buttons added.
+#define Toolbar_AutoPopulate(/*HWND*/ __hToolbar, /*ifc_omservice* */ __service, /*UINT*/__populateFlags)\
+ ((UINT)SendMessage((__hToolbar), TBM_AUTOPOPULATE, (WPARAM)(__populateFlags), (LPARAM)(__service)))
+
+#define TBM_ENABLEBOTTOMDOCK (TBM_FIRST + 29) //wParam - not used; lParam = (LPARAM)(BOOL)fEnable; Return: previous state.
+#define Toolbar_EnableBottomDock(/*HWND*/ __hToolbar, /*BOOL*/ __fEnable)\
+ ((BOOL)SendMessage((__hToolbar), TBM_ENABLEBOTTOMDOCK, 0, (LPARAM)(__fEnable)))
+
+#define TBM_ENABLEAUTOHIDE (TBM_FIRST + 30) //wParam - not used; lParam = (LPARAM)(BOOL)fEnable; Return: previous state.
+#define Toolbar_EnableAutoHide(/*HWND*/ __hToolbar, /*BOOL*/ __fEnable)\
+ ((BOOL)SendMessage((__hToolbar), TBM_ENABLEAUTOHIDE, 0, (LPARAM)(__fEnable)))
+
+#define TBM_ENABLETABSTOP (TBM_FIRST + 31) //wParam - not used; lParam = (LPARAM)(BOOL)fEnable; Return: previous state.
+#define Toolbar_EnableTabStop(/*HWND*/ __hToolbar, /*BOOL*/ __fEnable)\
+ ((BOOL)SendMessage((__hToolbar), TBM_ENABLETABSTOP, 0, (LPARAM)(__fEnable)))
+
+#define TBM_SETBROWSERHOST (TBM_FIRST + 32) //wParam = 0, lParam = (LPARAM)(HWND)hwndBrowserHost.
+#define Toolbar_SetBrowserHost(/*HWND*/ __hStatusbar, /*HWND*/ __hwndBrowserHost)\
+ ((BOOL)SENDMSG(__hStatusbar, TBM_SETBROWSERHOST, 0, (LPARAM)(__hwndBrowserHost)))
+
+#define TBM_GETEDITCOLOR (TBM_FIRST + 33)
+#define Toolbar_GetEditColor(/*HWND*/ __hToolbar)\
+ ((COLORREF)SendMessage((__hToolbar), TBM_GETEDITCOLOR, 0, 0L))
+
+#define TBM_GETEDITBKCOLOR (TBM_FIRST + 34)
+#define Toolbar_GetEditBkColor(/*HWND*/ __hToolbar)\
+ ((COLORREF)SendMessage((__hToolbar), TBM_GETEDITBKCOLOR, 0, 0L))
+
+#define TBM_GETIMAGELISTHEIGHT (TBM_FIRST + 35)
+#define Toolbar_GetImageListHeight(/*HWND*/ __hToolbar)\
+ ((INT)SendMessage((__hToolbar), TBM_GETIMAGELISTHEIGHT, 0, 0L))
+
+
+#define TBM_GETNEXTTABITEM (TBM_FIRST + 36)
+#define Toolbar_GetNextTabItem(/*HWND*/ __hToolbar, /*LPCSTR*/ __pszItemName, /*BOOL*/ __fPrevious)\
+ ((INT)SendMessage((__hToolbar), TBM_GETNEXTTABITEM, (BOOL)(__fPrevious), (LPARAM)(__pszItemName)))
+
+#define TBM_CHECKHIDE (TBM_FIRST + 37) // wParam - not used, lParam = (LPARAM)(BOOL)__fImmediate
+#define Toolbar_CheckHide(/*HWND*/ __hToolbar, /*BOOL*/ __fImmediate)\
+ (SendMessage((__hToolbar), TBM_CHECKHIDE, 0, (BOOL)(__fImmediate)))
+
+#define TBM_ENABLEFORCEADDRESS (TBM_FIRST + 38) //wParam - not used; lParam = (LPARAM)(BOOL)fEnable; Return: previous state.
+#define Toolbar_EnableForceAddress(/*HWND*/ __hToolbar, /*BOOL*/ __fEnable)\
+ ((BOOL)SendMessage((__hToolbar), TBM_ENABLEFORCEADDRESS, 0, (LPARAM)(__fEnable)))
+
+#define TBM_ENABLEFANCYADDRESS (TBM_FIRST + 39) //wParam - not used; lParam = (LPARAM)(BOOL)fEnable; Return: previous state.
+#define Toolbar_EnableFancyAddress(/*HWND*/ __hToolbar, /*BOOL*/ __fEnable)\
+ ((BOOL)SendMessage((__hToolbar), TBM_ENABLEFANCYADDRESS, 0, (LPARAM)(__fEnable)))
+
+#define TBM_GETTEXTLENGTH (TBM_FIRST + 40) // wParam - (WPARAM)(size_t*)__textLengthOut, lParam - (LPARAM)(LPCSTR)(__itemName); Return TRUE if supported
+#define Toolbar_GetTextLength(/*HWND*/ __hToolbar, /*LPCSTR*/ __pszItemName, /*size_t* */ __textLengthOut)\
+ ((BOOL)SendMessage((__hToolbar), TBM_GETTEXTLENGTH, (WPARAM)(__textLengthOut), (LPARAM)(__pszItemName)))
+
+// Nitifications (WM_COMMAND)
+#define TBN_DOCKCHANGED 1
+#define TBN_AUTOHIDECHANGED 2
+#define TBN_TABSTOPCHANGED 3
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_HEADER
diff --git a/Src/omBrowser/toolbarAddress.cpp b/Src/omBrowser/toolbarAddress.cpp
new file mode 100644
index 00000000..4f3bc35b
--- /dev/null
+++ b/Src/omBrowser/toolbarAddress.cpp
@@ -0,0 +1,761 @@
+#include "main.h"
+#include "./toolbarAddress.h"
+#include "./toolbar.h"
+#include "./toolbarEditbox.h"
+#include "./resource.h"
+#include "./graphics.h"
+#include "./menu.h"
+#include "./ifc_imageloader.h"
+#include "./addressEncoder.h"
+
+
+#include <wininet.h>
+//#include <shlwapi.h>
+#include <strsafe.h>
+
+#define ADDRESSBAR_MINWIDTH 96
+
+ UINT minWidth;
+ HBITMAP bitmap;
+ INT iconHeight;
+ INT iconWidth;
+ INT textHeight;
+ INT textMargin;
+ COLORREF rgbText;
+ COLORREF rgbBk;
+ HWND hEditor;
+
+ToolbarAddress::ToolbarAddress(LPCSTR pszName, UINT nStyle) :
+ ToolbarItem(pszName, nStyle, ICON_NONE, NULL, NULL),
+ minWidth(ADDRESSBAR_MINWIDTH), bitmap(NULL), iconHeight(0), iconWidth(0),
+ textHeight(12), textMargin(0), rgbText(0x000000), rgbBk(0xFFFFFF), hEditor(NULL)
+{
+}
+
+ToolbarAddress::~ToolbarAddress()
+{
+ if (NULL != bitmap)
+ DeleteObject(bitmap);
+ if (NULL != hEditor)
+ DestroyWindow(hEditor);
+}
+
+ToolbarItem* CALLBACK ToolbarAddress::CreateInstance(ToolbarItem::Template *item)
+{
+ if (NULL == item)
+ return NULL;
+
+ return new ToolbarAddress( (NULL != item->name) ? item->name : TOOLCLS_ADDRESSBAR,
+ item->style);
+}
+
+BOOL ToolbarAddress::ActivateEditor(HWND hToolbar, const POINT *ppt)
+{
+ if (NULL == hEditor)
+ {
+ UINT editorStyle = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_TABSTOP |
+ ES_LEFT | ES_NOHIDESEL | ES_AUTOHSCROLL;
+
+ if (0 != (styleAddressReadonly & style))
+ editorStyle |= ES_READONLY;
+
+ hEditor = CreateWindowEx(WS_EX_NOPARENTNOTIFY, L"Edit", text, editorStyle, 0, 0, 0, 0, hToolbar, NULL, NULL, 0);
+
+ if (NULL == hEditor)
+ return FALSE;
+
+ ToolbarEditbox_AttachWindow(hEditor, this);
+
+ HFONT hFont = (HFONT)SendMessage(hToolbar, WM_GETFONT, 0, 0L);
+ SendMessage(hEditor, WM_SETFONT, (WPARAM)hFont, 0L);
+ SendMessage(hEditor, EM_SETMARGINS, (WPARAM)(EC_LEFTMARGIN | EC_RIGHTMARGIN), MAKELPARAM(textMargin, textMargin));
+ }
+
+ UINT editorStyle = GetWindowStyle(hEditor);
+ if (0 == (WS_VISIBLE & editorStyle))
+ {
+ RECT textRect;
+ CopyRect(&textRect, &rect);
+ InflateRect(&textRect, -((iconWidth -1)/2), -((iconHeight -1)/2));
+ textRect.top = textRect.bottom - textHeight;
+
+ SetWindowPos(hEditor, NULL, textRect.left, textRect.top,
+ textRect.right - textRect.left, textRect.bottom - textRect.top,
+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW);
+
+ UINT editorStyle = GetWindowStyle(hEditor);
+ if (0 == (WS_VISIBLE & editorStyle))
+ SetWindowLongPtr(hEditor, GWL_STYLE, editorStyle | WS_VISIBLE);
+
+ }
+
+ if (IsWindowVisible(hEditor))
+ {
+ if (hEditor != GetFocus())
+ ::SetFocus(hEditor);
+
+ if (NULL != ppt)
+ {
+ POINT editorPt = *ppt;
+ MapWindowPoints(hToolbar, hEditor, &editorPt, 1);
+ PostMessage(hEditor, WM_LBUTTONDOWN, (WPARAM)(MK_LBUTTON), MAKELPARAM(editorPt.x, editorPt.y));
+ }
+ else
+ {
+ SendMessage(hEditor, NTEBM_SELECTALL, 0, 0);
+ }
+
+ InvalidateRect(hEditor, NULL, FALSE);
+ }
+
+ InvalidateRect(hToolbar, &rect, FALSE);
+ return TRUE;
+}
+
+
+UINT ToolbarAddress::GetStyle()
+{
+ UINT filteredStyle = style;
+ if (0 != (styleAddressReadonly & filteredStyle))
+ filteredStyle &= ~styleTabstop;
+
+ return filteredStyle;
+}
+
+void ToolbarAddress::SetStyle(HWND hToolbar, UINT newStyle, UINT styleMask)
+{
+ ToolbarItem::SetStyle(hToolbar, newStyle, styleMask);
+
+ if (NULL != hEditor)
+ {
+ if (0 != (stateHidden & styleMask) && 0 != (stateHidden & style))
+ {
+ if (GetFocus() == hEditor)
+ EditboxNavigateNextCtrl(hEditor, TRUE);
+ else
+ DestroyWindow(hEditor);
+ }
+
+ if (0 != (styleAddressReadonly & styleMask))
+ {
+ UINT editorStyle = GetWindowStyle(hEditor);
+ if (0 == (styleAddressReadonly & style) != 0 == (ES_READONLY & editorStyle))
+ SendMessage(hEditor, EM_SETREADONLY, (WPARAM)(0 != (styleAddressReadonly & style)), 0L);
+ }
+ }
+}
+
+BOOL ToolbarAddress::SetRect(const RECT *prc)
+{
+ BOOL result = ToolbarItem::SetRect(prc);
+ if (FALSE == result) return result;
+
+ if (NULL != hEditor)
+ {
+ UINT editorStyle = GetWindowStyle(hEditor);
+ if (0 != (WS_VISIBLE & editorStyle))
+ {
+ RECT textRect;
+ CopyRect(&textRect, &rect);
+ InflateRect(&textRect, -((iconWidth -1)/2), -((iconHeight -1)/2));
+ textRect.top = textRect.bottom - textHeight;
+
+ SetWindowPos(hEditor, NULL, textRect.left, textRect.top,
+ textRect.right - textRect.left, textRect.bottom - textRect.top,
+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW);
+ }
+ }
+
+ return result;
+}
+
+BOOL ToolbarAddress::SetRectEmpty()
+{
+ BOOL result = ToolbarItem::SetRectEmpty();
+ if (FALSE == result) return result;
+
+
+ if (NULL != hEditor)
+ {
+ if (GetFocus() == hEditor)
+ EditboxNavigateNextCtrl(hEditor, TRUE);
+ else
+ DestroyWindow(hEditor);
+ }
+
+ return result;
+}
+
+BOOL ToolbarAddress::SetDescription(HWND hToolbar, LPCWSTR pszDescription)
+{
+ if (NULL != pszDescription && FALSE == IS_INTRESOURCE(pszDescription))
+ {
+ if (CSTR_EQUAL == CompareString(CSTR_INVARIANT, 0, L"about:blank", -1, pszDescription, -1))
+ pszDescription = NULL;
+ }
+
+ BOOL result = ToolbarItem::SetDescription(hToolbar, pszDescription);
+ if (NULL != hToolbar)
+ InvalidateRect(hToolbar, &rect, TRUE);
+ return result;
+}
+
+BOOL ToolbarAddress::AdjustRect(HWND hToolbar, RECT *proposedRect)
+{
+ if (0 == (styleFlexible & style) ||
+ proposedRect->right < proposedRect->left ||
+ ((UINT)(proposedRect->right - proposedRect->left)) < minWidth)
+ {
+ proposedRect->right = proposedRect->left + minWidth;
+ }
+ //INT iconCY = Toolbar_GetImageListHeight(hToolbar);
+ INT height = textHeight + iconHeight;
+ INT t = ((proposedRect->bottom - proposedRect->top) - height);
+ proposedRect->top += (t/2 + t%2);
+ proposedRect->bottom = proposedRect->top + height;
+
+
+ return TRUE;
+}
+
+BOOL ToolbarAddress::Paint(HWND hToolbar, HDC hdc, const RECT *paintRect, UINT state)
+{
+
+ if (NULL == bitmap)
+ return FALSE;
+
+ RECT blitRect;
+ if (!IntersectRect(&blitRect, paintRect))
+ return TRUE;
+
+ BOOL success = FALSE;
+ HDC hdcSrc = CreateCompatibleDC(hdc);
+
+ UINT editorStyle = (NULL != hEditor) ? GetWindowStyle(hEditor) : 0;
+ INT offsetY;
+ if (0 != (stateDisabled & state) || 0 != (styleAddressReadonly & style))
+ offsetY = 2* iconHeight;
+ else if (WS_VISIBLE == ((WS_VISIBLE | ES_READONLY | WS_DISABLED) & editorStyle))
+ offsetY = 1 * iconHeight;
+ else
+ offsetY = 0;
+
+ INT partCY = (iconHeight - 1)/2;
+ INT partCX = (iconWidth - 1)/2;
+
+ RECT textRect;
+ CopyRect(&textRect, &rect);
+ InflateRect(&textRect, -partCX, -partCY);
+
+ INT clipRgnCode = -1;
+ HRGN clipRgn = CreateRectRgn(0, 0, 0, 0);
+ if (NULL != clipRgn)
+ {
+ clipRgnCode = GetClipRgn(hdc, clipRgn);
+ ExcludeClipRect(hdc, textRect.left, textRect.top, textRect.right, textRect.bottom);
+ }
+
+ if (NULL != hdcSrc)
+ {
+ success = TRUE;
+ HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcSrc, bitmap);
+
+ // left-top
+ BitBlt(hdc, rect.left, rect.top, partCX, partCY, hdcSrc, 0, offsetY + 0, SRCCOPY);
+ // right-top
+ BitBlt(hdc, rect.right - partCX, rect.top, partCX, partCY, hdcSrc, iconWidth - partCX, offsetY + 0, SRCCOPY);
+ // right-bottom
+ BitBlt(hdc, rect.right - partCX, rect.bottom - partCY, partCX, partCY, hdcSrc, iconWidth - partCX, offsetY + (iconHeight - partCY), SRCCOPY);
+ // left-bottom
+ BitBlt(hdc, rect.left, rect.bottom - partCY, partCX, partCY, hdcSrc, 0, offsetY + (iconHeight - partCY), SRCCOPY);
+
+ INT stretchMode = SetStretchBltMode(hdc, COLORONCOLOR);
+
+ StretchBlt(hdc, rect.left, rect.top + partCY, partCX, (rect.bottom - rect.top) - 2*partCY, hdcSrc, 0, offsetY + partCY, partCX, 1, SRCCOPY);
+ StretchBlt(hdc, rect.right - partCX, rect.top + partCY, partCX, (rect.bottom - rect.top) - 2*partCY, hdcSrc, iconWidth - partCX, offsetY + partCY, partCX, 1, SRCCOPY);
+ StretchBlt(hdc, rect.left + partCX, rect.top, (rect.right - rect.left) - 2 * partCX, partCY, hdcSrc, partCX, offsetY + 0, 1, partCY, SRCCOPY);
+ StretchBlt(hdc, rect.left + partCX, rect.bottom - partCY, (rect.right - rect.left) - 2 * partCX, partCY, hdcSrc, partCX, offsetY + (iconHeight - partCY), 1, partCY, SRCCOPY);
+
+
+ if (COLORONCOLOR != stretchMode)
+ SetStretchBltMode(hdc, stretchMode);
+
+
+ SelectObject(hdcSrc, hbmpOld);
+ DeleteDC(hdcSrc);
+ }
+
+ if (clipRgnCode >= 0)
+ SelectClipRgn(hdc, ( 0 != clipRgnCode) ? (clipRgn ? clipRgn : NULL) : NULL);
+
+ if (NULL != clipRgn)
+ DeleteObject(clipRgn);
+
+ COLORREF rgbTextOrig, rgbBkOrig;
+
+ if (0 == (stateDisabled & state) && 0 == (styleAddressReadonly & style))
+ {
+ rgbTextOrig = SetTextColor(hdc, rgbText);
+ rgbBkOrig = SetBkColor(hdc, rgbBk);
+ }
+ else
+ {
+ rgbTextOrig = GetTextColor(hdc);
+ rgbBkOrig = GetBkColor(hdc);
+ }
+
+ LPCWSTR pszText;
+ pszText = ( 0 == (styleAddressShowReal & style) && NULL != description) ? description : text;
+
+
+ UINT cchText = (NULL != pszText && FALSE == IS_INTRESOURCE(pszText)) ? lstrlen(pszText) : 0;
+ INT textAlign = SetTextAlign(hdc, TA_LEFT | TA_BOTTOM);
+ ExtTextOut(hdc, textRect.left + textMargin, textRect.bottom, ETO_OPAQUE | ETO_CLIPPED, &textRect, pszText, cchText, NULL);
+
+ if (textAlign != (TA_LEFT | TA_BOTTOM)) SetTextAlign(hdc, textAlign);
+ if (rgbText != rgbTextOrig) SetTextColor(hdc, rgbTextOrig);
+ if (rgbBk != rgbBkOrig) SetBkColor(hdc, rgbBkOrig);
+
+
+
+ return success;
+}
+
+INT ToolbarAddress::GetTip(LPTSTR pszBuffer, INT cchBufferMax)
+{
+ return 0;
+}
+
+HRESULT ToolbarAddress::GetText(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ if (NULL == pszBuffer) return E_POINTER;
+ if (0 == cchBufferMax) return E_OUTOFMEMORY;
+ if (NULL == text)
+ {
+ *pszBuffer = L'\0';
+ return S_OK;
+ }
+
+ if (IS_INTRESOURCE(text))
+ return Plugin_CopyResString(pszBuffer, cchBufferMax, text);
+
+ return AddressEncoder_EncodeString(text, pszBuffer,(size_t*)&cchBufferMax, ICU_BROWSER_MODE);
+}
+
+HRESULT ToolbarAddress::GetTextLength(size_t *pcchLength)
+{
+ if (NULL == pcchLength)
+ return E_POINTER;
+
+ if (NULL == text)
+ {
+ *pcchLength = 0;
+ return S_OK;
+ }
+
+ if (IS_INTRESOURCE(text))
+ {
+ WCHAR szBuffer[8192] = {0};
+ HRESULT hr = Plugin_CopyResString(szBuffer, ARRAYSIZE(szBuffer), text);
+ *pcchLength = (FAILED(hr)) ? 0 : lstrlen(szBuffer);
+ return hr;
+ }
+
+ WCHAR szBuffer[1] = {0};
+ size_t cchBufferMax = ARRAYSIZE(szBuffer);
+ HRESULT hr = AddressEncoder_EncodeString(text, szBuffer, &cchBufferMax, ICU_BROWSER_MODE);
+ if (SUCCEEDED(hr) || ENC_E_INSUFFICIENT_BUFFER == hr)
+ {
+ if (0 != cchBufferMax) cchBufferMax--;
+ *pcchLength = cchBufferMax;
+ hr = S_OK;
+ }
+ else
+ {
+ hr = E_FAIL;
+ *pcchLength = 0;
+
+ }
+
+ return hr;
+
+}
+void ToolbarAddress::MouseMove(HWND hToolbar, UINT mouseFlags, POINT pt)
+{
+// UINT styleNew = (PtInItem(pt)) ? stateHighlighted : 0;
+// SetStyle(hToolbar, styleNew, stateHighlighted);
+
+}
+
+void ToolbarAddress::MouseLeave(HWND hToolbar)
+{
+ if (0 != (stateHighlighted & style))
+ {
+ SetStyle(hToolbar, 0, stateHighlighted);
+ }
+}
+
+void ToolbarAddress::LButtonDown(HWND hToolbar, UINT mouseFlags, POINT pt)
+{
+ ActivateEditor(hToolbar, &pt);
+}
+
+void ToolbarAddress::UpdateSkin(HWND hToolbar)
+{
+ if (NULL != bitmap)
+ {
+ DeleteObject(bitmap);
+ bitmap = NULL;
+ }
+
+ iconHeight = 0;
+ iconWidth = 0;
+
+ COLORREF rgbToolBk = Toolbar_GetBkColor(hToolbar);
+ rgbText = Toolbar_GetEditColor(hToolbar);
+ rgbBk = Toolbar_GetEditBkColor(hToolbar);
+
+ ifc_omimageloader *loader;
+ if (SUCCEEDED(Plugin_QueryImageLoader(Plugin_GetInstance(), MAKEINTRESOURCE(IDR_TOOLBARADDRESS_IMAGE), TRUE, &loader)))
+ {
+ BITMAPINFOHEADER headerInfo;
+ BYTE *pixelData;
+ if (SUCCEEDED(loader->LoadBitmapEx(&bitmap, &headerInfo, (void**)&pixelData)))
+ {
+ if (headerInfo.biHeight < 0) headerInfo.biHeight = -headerInfo.biHeight;
+ iconHeight = headerInfo.biHeight/3;
+ iconWidth = headerInfo.biWidth;
+
+ Image_Colorize(pixelData, headerInfo.biWidth, headerInfo.biHeight, headerInfo.biBitCount,
+ rgbToolBk, Toolbar_GetFgColor(hToolbar), FALSE);
+
+ // disabled
+ Image_BlendOnColorEx(pixelData, headerInfo.biWidth, headerInfo.biHeight,
+ 0, 0, headerInfo.biWidth, iconHeight, headerInfo.biBitCount, FALSE, rgbToolBk);
+ // highlighted
+ Image_BlendOnColorEx(pixelData, headerInfo.biWidth, headerInfo.biHeight,
+ 0, 1*iconHeight, headerInfo.biWidth, iconHeight, headerInfo.biBitCount, FALSE, rgbBk);
+ // normal
+ Image_BlendOnColorEx(pixelData, headerInfo.biWidth, headerInfo.biHeight,
+ 0, 2*iconHeight, headerInfo.biWidth, iconHeight, headerInfo.biBitCount, FALSE, rgbBk);
+
+ }
+ loader->Release();
+ }
+
+ textHeight = 12;
+ HFONT toolbarFont = (HFONT)SendMessage(hToolbar, WM_GETFONT, 0, 0L);
+
+ if (NULL != toolbarFont)
+ {
+ HDC hdc = GetDCEx(hToolbar, NULL, DCX_CACHE | DCX_NORESETATTRS);
+ if (NULL != hdc)
+ {
+ HFONT originalFont = (HFONT)SelectObject(hdc, toolbarFont);
+
+ TEXTMETRIC tm;
+ if (GetTextMetrics(hdc, &tm))
+ {
+ textHeight = tm.tmHeight;
+ textMargin = tm.tmAveCharWidth/2 + tm.tmAveCharWidth%2;
+ }
+
+ SelectObject(hdc, originalFont);
+ ReleaseDC(hToolbar, hdc);
+ }
+
+ if (NULL != hEditor)
+ {
+ UINT editorStyle = GetWindowStyle(hEditor);
+ if (0 != (WS_VISIBLE & editorStyle))
+ {
+ SendMessage(hEditor, WM_SETFONT, (WPARAM)toolbarFont, 0L);
+ SendMessage(hEditor, EM_SETMARGINS, (WPARAM)(EC_LEFTMARGIN | EC_RIGHTMARGIN), MAKELPARAM(textMargin, textMargin));
+ }
+ }
+ }
+}
+
+BOOL ToolbarAddress::FillMenuInfo(HWND hToolbar, MENUITEMINFO *pmii, LPWSTR pszBuffer, INT cchBufferMax)
+{
+ return FALSE;
+}
+void ToolbarAddress::CommandSent(HWND hToolbar, INT commandId)
+{
+ if (NULL != hEditor && ID_ADDRESSBAR_CHANGED != commandId)
+ {
+ if (GetFocus() == hEditor)
+ EditboxNavigateNextCtrl(hEditor, TRUE);
+ else
+ DestroyWindow(hEditor);
+ }
+}
+
+
+
+BOOL ToolbarAddress::SetValueStr(HWND hToolbar, LPCWSTR value)
+{
+ Plugin_FreeResString(text);
+
+ if (NULL != value)
+ {
+ if (FALSE != IS_INTRESOURCE(value) || FAILED(AddressEncoder_DecodeString(value, &text)))
+ text = Plugin_DuplicateResString(value);
+ }
+ else
+ text = NULL;
+
+ RECT textRect;
+ CopyRect(&textRect, &rect);
+ InflateRect(&textRect, -((iconWidth -1)/2), -(iconHeight - 1)/2);
+
+ InvalidateRect(hToolbar, &textRect, TRUE);
+
+ return TRUE;
+}
+
+BOOL ToolbarAddress::SetClipboardText(HWND hToolbar, LPCWSTR pszText)
+{
+ if(FALSE == OpenClipboard(hToolbar))
+ return FALSE;
+
+ EmptyClipboard();
+
+ INT cchLen;
+ HGLOBAL hMemory;
+
+ cchLen = (NULL != pszText) ? lstrlenW(pszText) : 0;
+ hMemory = (0 != cchLen) ? GlobalAlloc(GMEM_MOVEABLE, (cchLen + 1) * sizeof(WCHAR)) : NULL;
+ if (NULL != hMemory)
+ {
+ LPWSTR pszDest = (LPWSTR)GlobalLock(hMemory);
+ CopyMemory(pszDest, pszText, (cchLen + 1) * sizeof(WCHAR));
+ GlobalUnlock(hMemory);
+ }
+ SetClipboardData(CF_UNICODETEXT, hMemory);
+
+
+ LPSTR pszTextAnsi = (NULL != pszText) ? Plugin_WideCharToMultiByte(CP_ACP, 0, pszText, -1, NULL, NULL) : NULL;
+ cchLen = (NULL != pszTextAnsi) ? lstrlenA(pszTextAnsi) : 0;
+ hMemory = (0 != cchLen) ? GlobalAlloc(GMEM_MOVEABLE, (cchLen + 1) * sizeof(CHAR)) : NULL;
+ if (NULL != hMemory)
+ {
+ LPWSTR pszDest = (LPWSTR)GlobalLock(hMemory);
+ CopyMemory(pszDest, pszTextAnsi, (cchLen + 1) * sizeof(CHAR));
+ GlobalUnlock(hMemory);
+ }
+ SetClipboardData(CF_TEXT, hMemory);
+
+ CloseClipboard();
+ return TRUE;
+}
+
+BOOL ToolbarAddress::DisplayContextMenu(HWND hToolbar, INT x, INT y)
+{
+ HMENU hMenu = Menu_GetMenu(MENU_ADDRESSBAR, 0);
+ if (NULL != hMenu)
+ {
+ UINT fEnable = MF_BYCOMMAND;
+ if (0 != (styleAddressReadonly & style))
+ fEnable |= (MF_DISABLED | MF_GRAYED);
+ else
+ fEnable |= MF_ENABLED;
+
+ EnableMenuItem(hMenu, ID_ADDRESSBAR_EDITADDRESS, fEnable);
+
+ INT commandId = Menu_TrackPopup(hMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD, x, y, hToolbar, NULL);
+ switch(commandId)
+ {
+ case ID_ADDRESSBAR_COPY:
+ if (0 == (styleAddressShowReal & style) && NULL != description)
+ {
+ UINT cchTextMax = (IS_INTRESOURCE(description)) ? 2048 : (lstrlen(description) + 1);
+ LPWSTR pszText = Plugin_MallocString(cchTextMax);
+ if (NULL != pszText && FAILED(GetDescription(pszText, cchTextMax)))
+ {
+ Plugin_FreeString(pszText);
+ pszText = NULL;
+ }
+ SetClipboardText(hToolbar, pszText);
+ Plugin_FreeString(pszText);
+ break;
+ }
+ // let it go
+ case ID_ADDRESSBAR_COPYADDRESS:
+ {
+ size_t cchTextMax;
+ if (SUCCEEDED(GetTextLength(&cchTextMax)))
+ {
+ cchTextMax++;
+ LPWSTR pszText = Plugin_MallocString(cchTextMax);
+ if (NULL != pszText && FAILED(GetText(pszText, (UINT)cchTextMax)))
+ {
+ Plugin_FreeString(pszText);
+ pszText = NULL;
+ }
+
+ SetClipboardText(hToolbar, pszText);
+ Plugin_FreeString(pszText);
+ }
+ }
+ break;
+ case ID_ADDRESSBAR_EDITADDRESS:
+ ActivateEditor(hToolbar, NULL);
+ break;
+ }
+
+ Menu_ReleaseMenu(hMenu, MENU_ADDRESSBAR);
+ }
+ return TRUE;
+}
+
+void ToolbarAddress::SetFocus(HWND hToolbar, ToolbarItem *focusItem, BOOL fSet)
+{
+ ActivateEditor(hToolbar, NULL);
+}
+
+BOOL ToolbarAddress::SetCursor(HWND hToolbar, HWND hCursor, UINT hitTest, UINT messageId)
+{
+ RECT textRect;
+ CopyRect(&textRect, &rect);
+ InflateRect(&textRect, -((iconWidth -1)/2), -(iconHeight - 1)/2);
+ UINT messagePos = GetMessagePos();
+ POINTS messagePts = MAKEPOINTS(messagePos);
+ POINT messagePt;
+ POINTSTOPOINT(messagePt, messagePts);
+ MapWindowPoints(HWND_DESKTOP, hToolbar, &messagePt, 1);
+ if (::PtInRect(&textRect, messagePt))
+ {
+ HCURSOR cursor = LoadCursor(NULL, IDC_IBEAM);
+ if (NULL != cursor)
+ {
+ ::SetCursor(cursor);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void ToolbarAddress::EditboxDestroyed(HWND hwnd)
+{
+ if (hEditor == hwnd)
+ {
+ hEditor = NULL;
+
+ HWND hToolbar = GetParent(hwnd);
+ if (NULL != hToolbar)
+ {
+ InvalidateRect(hToolbar, &rect, FALSE);
+ Toolbar_CheckHide(hToolbar, TRUE);
+ }
+ }
+}
+
+BOOL ToolbarAddress::EditboxKillFocus(HWND hwnd, HWND hFocus)
+{
+ DestroyWindow(hwnd);
+ return TRUE;
+}
+
+void ToolbarAddress::EditboxResetText(HWND hwnd)
+{
+ UINT editboxStyle = GetWindowStyle(hwnd);
+ if (0 != (WS_VISIBLE & editboxStyle))
+ SetWindowLongPtr(hwnd, GWL_STYLE, editboxStyle & ~WS_VISIBLE);
+
+ SetWindowText(hwnd, text);
+ SendMessage(hEditor, NTEBM_SELECTALL, 0, 0L);
+
+ if (0 != (WS_VISIBLE & editboxStyle))
+ {
+ UINT editboxStyle = GetWindowStyle(hwnd);
+ if (0 == (WS_VISIBLE & editboxStyle))
+ SetWindowLongPtr(hwnd, GWL_STYLE, editboxStyle | WS_VISIBLE);
+
+ InvalidateRect(hwnd, NULL, FALSE);
+ }
+
+}
+
+void ToolbarAddress::EditboxNavigateNextCtrl(HWND hwnd, BOOL fForward)
+{
+ HWND hToolbar = GetParent(hwnd);
+ if (NULL != hToolbar)
+ {
+ INT itemIndex = Toolbar_GetNextTabItem(hToolbar, name, (FALSE == fForward));
+ if (ITEM_ERR != itemIndex)
+ {
+ if (FALSE != Toolbar_NextItem(hToolbar, MAKEINTRESOURCE(itemIndex), TRUE))
+ {
+ ::SetFocus(hToolbar);
+ return;
+ }
+ }
+
+ HWND hParent = GetAncestor(hToolbar, GA_PARENT);
+ while(NULL != hParent &&
+ 0 != (WS_CHILD & GetWindowStyle(hParent)) &&
+ 0 != (WS_EX_CONTROLPARENT & GetWindowStyleEx(hParent)))
+ {
+ HWND hTest = GetAncestor(hParent, GA_PARENT);
+ if (NULL == hTest) break;
+ hParent = hTest;
+ }
+
+ if (NULL != hParent)
+ {
+ HWND hFocus = GetNextDlgTabItem(hParent, hToolbar, (FALSE == fForward));
+ if (NULL != hFocus) ::SetFocus(hFocus);
+ }
+ }
+}
+
+void ToolbarAddress::EditboxAcceptText(HWND hwnd)
+{
+ UINT cchLenMax = GetWindowTextLength(hwnd);
+ if (0 == cchLenMax) return;
+
+ cchLenMax++;
+ Plugin_FreeResString(text);
+ text = Plugin_MallocString(cchLenMax);
+ if (NULL != text)
+ {
+ INT cchText = GetWindowText(hwnd, text, cchLenMax);
+ if (0 != cchText)
+ {
+ LPCWSTR begin, end;
+ begin = text;
+ end = text + cchText + 1;
+ while (L' ' == *begin && begin != end) begin++;
+ while (L' ' == *end && begin != end) end--;
+ if (end <= begin) return;
+ }
+ }
+
+ HWND hToolbar = GetParent(hwnd);
+
+ if (NULL != hToolbar)
+ {
+ Toolbar_SendCommand(hToolbar, ID_ADDRESSBAR_CHANGED);
+ }
+
+ EditboxNavigateNextCtrl(hwnd, TRUE);
+}
+BOOL ToolbarAddress::EditboxKeyDown(HWND hwnd, UINT vKey, UINT state)
+{
+ switch(vKey)
+ {
+ case VK_UP:
+ case VK_DOWN:
+ return TRUE;
+ }
+ return FALSE;
+}
+BOOL ToolbarAddress::EditboxKeyUp(HWND hwnd, UINT vKey, UINT state)
+{
+ return FALSE;
+}
+BOOL ToolbarAddress::EditboxPreviewChar(HWND hwnd, UINT vKey, UINT state)
+{
+ return FALSE;
+} \ No newline at end of file
diff --git a/Src/omBrowser/toolbarAddress.h b/Src/omBrowser/toolbarAddress.h
new file mode 100644
index 00000000..b9a00526
--- /dev/null
+++ b/Src/omBrowser/toolbarAddress.h
@@ -0,0 +1,79 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_ADDRESS_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_ADDRESS_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./toolbarItem.h"
+#include "./toolbarEditbox.h"
+
+class ToolbarAddress : public ToolbarItem, public ToolbarEditboxHost
+{
+public:
+ typedef enum
+ {
+ styleAddressReadonly = 0x00010000,
+ styleAddressShowReal = 0x00020000,
+ } addressStyles;
+
+protected:
+ ToolbarAddress(LPCSTR pszName, UINT nStyle);
+ ~ToolbarAddress();
+
+public:
+ static ToolbarItem* CALLBACK CreateInstance(ToolbarItem::Template *itemTemplate);
+
+public:
+ BOOL AdjustRect(HWND hToolbar, RECT *proposedRect);
+ BOOL Paint(HWND hToolbar, HDC hdc, const RECT *paintRect, UINT state);
+ INT GetTip(LPTSTR pszBuffer, INT cchBufferMax);
+ BOOL SetDescription(HWND hToolbar, LPCWSTR pszDescription);
+ BOOL SetRect(const RECT *prc);
+ BOOL SetRectEmpty();
+ UINT GetStyle();
+ void SetStyle(HWND hToolbar, UINT newStyle, UINT styleMask);
+ HRESULT GetText(LPWSTR pszBuffer, UINT cchBufferMax);
+ HRESULT GetTextLength(size_t *pcchLength);
+
+ void MouseMove(HWND hToolbar, UINT mouseFlags, POINT pt);
+ void MouseLeave(HWND hToolbar);
+ void LButtonDown(HWND hToolbar, UINT mouseFlags, POINT pt);
+ void SetFocus(HWND hToolbar, ToolbarItem *focusItem, BOOL fSet);
+ BOOL SetCursor(HWND hToolbar, HWND hCursor, UINT hitTest, UINT messageId);
+
+ void UpdateSkin(HWND hToolbar);
+ BOOL FillMenuInfo(HWND hToolbar, MENUITEMINFO *pmii, LPWSTR pszBuffer, INT cchBufferMax);
+ void CommandSent(HWND hToolbar, INT commandId);
+
+ BOOL SetValueStr(HWND hToolbar, LPCWSTR value);
+
+ BOOL DisplayContextMenu(HWND hToolbar, INT x, INT y);
+
+ //ToolbarEditboxHost
+ void EditboxDestroyed(HWND hwnd);
+ BOOL EditboxKillFocus(HWND hwnd, HWND hFocus);
+ void EditboxResetText(HWND hwnd);
+ void EditboxNavigateNextCtrl(HWND hwnd, BOOL fForward);
+ void EditboxAcceptText(HWND hwnd);
+ BOOL EditboxKeyDown(HWND hwnd, UINT vKey, UINT state);
+ BOOL EditboxKeyUp(HWND hwnd, UINT vKey, UINT state);
+ BOOL EditboxPreviewChar(HWND hwnd, UINT vKey, UINT state);
+
+protected:
+ BOOL ActivateEditor(HWND hToolbar, const POINT *ppt);
+ BOOL SetClipboardText(HWND hToolbar, LPCWSTR pszText);
+
+protected:
+ UINT minWidth;
+ HBITMAP bitmap;
+ INT iconHeight;
+ INT iconWidth;
+ INT textHeight;
+ INT textMargin;
+ COLORREF rgbText;
+ COLORREF rgbBk;
+ HWND hEditor;
+};
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_STATIC_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/toolbarButton.cpp b/Src/omBrowser/toolbarButton.cpp
new file mode 100644
index 00000000..fc2a9e46
--- /dev/null
+++ b/Src/omBrowser/toolbarButton.cpp
@@ -0,0 +1,300 @@
+#include "main.h"
+#include "./toolbarButton.h"
+#include "./toolbar.h"
+#include "./graphics.h"
+#include "./resource.h"
+#include "../Plugins/General/gen_ml/ml_ipc_0313.h"
+#include <strsafe.h>
+
+#define CMDLINK_SPACECX_UNITS 2
+
+ToolbarButton::ToolbarButton(LPCSTR pszName, INT nCommand, UINT nStyle, INT nIcon, LPCWSTR pszText, LPCWSTR pszDescription) :
+ ToolbarItem(pszName, nStyle, nIcon, pszText, pszDescription),
+ commandId(nCommand), offsetX(0), offsetY(0), rgbText(0), rgbHilite(0)
+{
+}
+
+ToolbarItem* CALLBACK ToolbarButton::CreateInstance(ToolbarItem::Template *item)
+{
+ if (NULL == item)
+ return NULL;
+
+ return new ToolbarButton( (NULL != item->name) ? item->name : TOOLCLS_BUTTON,
+ item->commandId,
+ item->style,
+ item->iconId,
+ item->text,
+ item->description);
+}
+
+static LPCTSTR ToolbarButton_GetResourceString(LPCTSTR pszResource, LPTSTR pszBuffer, INT cchBufferMax)
+{
+ if (IS_INTRESOURCE(pszResource))
+ {
+ Plugin_LoadString((INT)(INT_PTR)pszResource, pszBuffer, cchBufferMax);
+ return pszBuffer;
+ }
+ return pszResource;
+}
+
+static BOOL ToolbarButton_GetTextSise(HWND hToolbar, LPCWSTR pszText, INT cchText, SIZE *textSize, TEXTMETRIC *ptm)
+{
+ if (NULL == textSize)
+ return FALSE;
+
+ if (cchText < 0)
+ cchText = lstrlenW(pszText);
+
+ HDC hdc = GetDCEx(hToolbar, NULL, DCX_CACHE | DCX_NORESETATTRS);
+ if (NULL == hdc) return FALSE;
+
+ BOOL result = FALSE;
+ HFONT font = (HFONT)SendMessage(hToolbar, WM_GETFONT, 0, 0L);
+ HFONT originalFont = (HFONT)SelectObject(hdc, font);
+
+ if (NULL != ptm && !GetTextMetrics(hdc, ptm))
+ ZeroMemory(ptm, sizeof(TEXTMETRIC));
+
+ if (0 != cchText)
+ {
+ if (GetTextExtentPoint32(hdc, pszText, cchText, textSize))
+ result = TRUE;
+ }
+ else
+ ZeroMemory(textSize, sizeof(SIZE));
+
+ SelectObject(hdc, originalFont);
+ ReleaseDC(hToolbar, hdc);
+ return result;
+}
+
+BOOL ToolbarButton::AdjustRect(HWND hToolbar, RECT *proposedRect)
+{
+ if (0 != (ToolbarButton::styleCommandLink & style))
+ {
+ SIZE linkSize = {0};
+ LPCTSTR pszText;
+ WCHAR szBuffer[128] = {0};
+ TOOLBARTEXTMETRIC ttm = {0};
+
+ pszText = ToolbarButton_GetResourceString(text, szBuffer, ARRAYSIZE(szBuffer));
+ if (!ToolbarButton_GetTextSise(hToolbar, pszText, -1, &linkSize, NULL))
+ ZeroMemory(&linkSize, sizeof(SIZE));
+
+ if (!Toolbar_GetTextMetrics(hToolbar, &ttm))
+ ZeroMemory(&ttm, sizeof(TOOLBARTEXTMETRIC));
+
+ offsetX = MulDiv(CMDLINK_SPACECX_UNITS, ttm.aveCharWidth, 4);
+ offsetY = ttm.baseY;
+ proposedRect->right = proposedRect->left + linkSize.cx + 2 * offsetX + ttm.overhang;
+
+ proposedRect->top = ttm.origY;
+ proposedRect->bottom = proposedRect->top + ttm.height;
+ return TRUE;
+ }
+
+ SIZE iconSize;
+ if (!Toolbar_GetIconSize(hToolbar, iconId, &iconSize))
+ ZeroMemory(&iconSize, sizeof(SIZE));
+
+ proposedRect->right = proposedRect->left + iconSize.cx;
+ INT offsetY = (proposedRect->bottom - proposedRect->top) - iconSize.cy;
+ if (0 != offsetY)
+ {
+ proposedRect->top += offsetY/2;
+ if (0 != (offsetY%2)) proposedRect->top++;
+ }
+ proposedRect->bottom = proposedRect->top + iconSize.cy;
+ return TRUE;
+}
+
+void ToolbarButton::UpdateSkin(HWND hToolbar)
+{
+ rgbText = Toolbar_GetTextColor(hToolbar);
+ rgbHilite = Toolbar_GetHiliteColor(hToolbar);
+}
+
+BOOL ToolbarButton::Paint(HWND hToolbar, HDC hdc, const RECT *paintRect, UINT state)
+{
+ if (statePressed == ((statePressed | stateHighlighted) & state))
+ state &= ~statePressed;
+
+ if (0 != (ToolbarButton::styleCommandLink & style))
+ {
+ LPCTSTR pszText;
+ WCHAR szBuffer[256] = {0};
+ pszText = ToolbarButton_GetResourceString(text, szBuffer, ARRAYSIZE(szBuffer));
+ INT cchText = lstrlen(pszText);
+ if (0 == cchText)
+ return FALSE;
+
+
+ COLORREF originalFg = GetTextColor(hdc);
+ COLORREF rgbFg = (0 == (stateHighlighted & style)) ? rgbText : rgbHilite;
+
+ SetTextColor(hdc, rgbFg);
+ INT originalMode = SetBkMode(hdc, TRANSPARENT);
+ UINT originalAlign = SetTextAlign(hdc, TA_LEFT | TA_BASELINE);
+
+ ExtTextOut(hdc, rect.left + offsetX, rect.top + offsetY, ETO_CLIPPED | ETO_OPAQUE, &rect, pszText, cchText, NULL);
+
+ if (TRANSPARENT != originalMode) SetBkMode(hdc, originalMode);
+ if ((TA_LEFT | TA_BASELINE) != originalAlign) SetTextAlign(hdc, originalAlign);
+
+ if (0 != (stateHighlighted & style))
+ {
+ COLORREF originalBk = SetBkColor(hdc, rgbFg);
+
+ RECT partRect;
+ ::SetRect(&partRect, rect.left + offsetX, rect.top + offsetY + 1, rect.right - offsetX, rect.top + offsetY + 2);
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &partRect, NULL, 0, NULL);
+
+ SetBkColor(hdc, originalBk);
+ }
+
+ if (rgbFg != originalFg)
+ SetTextColor(hdc, originalFg);
+
+ return TRUE;
+ }
+
+ TOOLBARDRAWICONPARAM param;
+ param.hdcDst = hdc;
+ param.iconIndex = iconId;
+ param.x = rect.left;
+ param.y = rect.top;
+ param.cx = rect.right - rect.left;
+ param.cy = rect.bottom - rect.top;
+ param.itemState = state;
+ if (Toolbar_DrawIcon(hToolbar, &param))
+ {
+ if (stateFocused == ((stateFocused | stateNoFocusRect) & state))
+ {
+ RECT focusRect;
+ CopyRect(&focusRect, &rect);
+ focusRect.left += 1;
+ focusRect.top += 2;
+ focusRect.bottom -= 1;
+ COLORREF origBk = SetBkColor(hdc, 0x00000000);
+ COLORREF origFg = SetTextColor(hdc, 0x00FFFFFF);
+ DrawFocusRect(hdc, &focusRect);
+ if (origBk != 0x00000000) SetBkColor(hdc, origBk);
+ if (origFg != 0x00FFFFFF) SetTextColor(hdc, origFg);
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+INT ToolbarButton::GetTip(LPTSTR pszBuffer, INT cchBufferMax)
+{
+ if (IS_INTRESOURCE(description))
+ {
+ if (NULL == pszBuffer || cchBufferMax < 1)
+ return 0;
+ Plugin_LoadString((INT)(INT_PTR)description, pszBuffer, cchBufferMax);
+ return lstrlen(pszBuffer);
+ }
+
+ size_t remaining;
+ HRESULT hr = StringCchCopyEx(pszBuffer, cchBufferMax, description, NULL, &remaining, STRSAFE_IGNORE_NULLS);
+ return SUCCEEDED(hr) ? (cchBufferMax - (INT)remaining) : 0;
+
+}
+
+BOOL ToolbarButton::PtInItem(POINT pt)
+{
+ return (pt.x >= (rect.left + offsetX) && pt.x < (rect.right - offsetX) && rect.bottom != rect.top);
+}
+INT ToolbarButton::GetCommandId()
+{
+ return commandId;
+}
+void ToolbarButton::MouseMove(HWND hToolbar, UINT mouseFlags, POINT pt)
+{
+ UINT styleNew = (PtInItem(pt)) ? stateHighlighted : 0;
+ SetStyle(hToolbar, styleNew, stateHighlighted);
+
+}
+
+void ToolbarButton::MouseLeave(HWND hToolbar)
+{
+ if (0 != (stateHighlighted & style))
+ {
+ SetStyle(hToolbar, 0, stateHighlighted);
+ }
+}
+
+void ToolbarButton::LButtonDown(HWND hToolbar, UINT mouseFlags, POINT pt)
+{
+ SetStyle(hToolbar, statePressed, statePressed);
+}
+void ToolbarButton::LButtonUp(HWND hToolbar, UINT mouseFlags, POINT pt)
+{
+ SetStyle(hToolbar, 0, statePressed);
+}
+void ToolbarButton::Click(HWND hToolbar, UINT mouseFlags, POINT pt)
+{
+ if (0 != commandId)
+ {
+ Toolbar_SendCommand(hToolbar, commandId);
+ }
+}
+
+BOOL ToolbarButton::FillMenuInfo(HWND hToolbar, MENUITEMINFO *pmii, LPWSTR pszBuffer, INT cchBufferMax)
+{
+ pmii->fMask = MIIM_STRING | MIIM_ID | MIIM_STATE;
+ pmii->wID = commandId;
+ pmii->fState = MFS_UNHILITE;
+ pmii->fState |= ((0 == (stateDisabled & style)) ? MFS_ENABLED : MFS_DISABLED);
+ pmii->dwTypeData = pszBuffer;
+
+ if (IS_INTRESOURCE(text))
+ {
+ Plugin_LoadString((INT)(INT_PTR)text, pszBuffer, cchBufferMax);
+ }
+ else
+ {
+ if (FAILED(StringCchCopyEx(pszBuffer, cchBufferMax, text, NULL, NULL, STRSAFE_IGNORE_NULLS)))
+ pszBuffer[0] = L'\0';
+ }
+ return TRUE;
+}
+
+
+
+
+BOOL ToolbarButton::KeyDown(HWND hToolbar, INT vKey, UINT flags)
+{
+ switch(vKey)
+ {
+ case VK_SPACE:
+ case VK_RETURN:
+ SetStyle(hToolbar, statePressed | stateHighlighted, statePressed | stateHighlighted);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL ToolbarButton::KeyUp(HWND hToolbar, INT vKey, UINT flags)
+{
+ switch(vKey)
+ {
+ case VK_SPACE:
+ case VK_RETURN:
+ if (0 != (statePressed & style))
+ {
+ SetStyle(hToolbar, 0, (statePressed | stateHighlighted));
+ if (0 != commandId)
+ Toolbar_SendCommand(hToolbar, commandId);
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void ToolbarButton::SetFocus(HWND hToolbar, ToolbarItem *focusItem, BOOL fSet)
+{
+ InvalidateRect(hToolbar, &rect, FALSE);
+}
diff --git a/Src/omBrowser/toolbarButton.h b/Src/omBrowser/toolbarButton.h
new file mode 100644
index 00000000..a3bdbc6c
--- /dev/null
+++ b/Src/omBrowser/toolbarButton.h
@@ -0,0 +1,56 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_BUTTON_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_BUTTON_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./toolbarItem.h"
+
+class ToolbarButton : public ToolbarItem
+{
+public:
+ typedef enum
+ {
+ stylePushbutton = 0x00000000,
+ styleCommandLink = 0x00010000,
+ } buttonStyles;
+
+protected:
+ ToolbarButton(LPCSTR pszName, INT nCommand, UINT nStyle, INT nIcon, LPCWSTR pszText, LPCWSTR pszDescription);
+ virtual ~ToolbarButton() {}
+
+public:
+ static ToolbarItem* CALLBACK CreateInstance(ToolbarItem::Template *itemTemplate);
+
+public:
+ BOOL AdjustRect(HWND hToolbar, RECT *proposedRect);
+ BOOL Paint(HWND hToolbar, HDC hdc, const RECT *paintRect, UINT state);
+ INT GetTip(LPTSTR pszBuffer, INT cchBufferMax);
+
+ void MouseMove(HWND hToolbar, UINT mouseFlags, POINT pt);
+ void MouseLeave(HWND hToolbar);
+ void LButtonDown(HWND hToolbar, UINT mouseFlags, POINT pt);
+ void LButtonUp(HWND hToolbar, UINT mouseFlags, POINT pt);
+ void Click(HWND hToolbar, UINT mouseFlags, POINT pt);
+ void UpdateSkin(HWND hToolbar);
+ BOOL PtInItem(POINT pt);
+
+ INT GetCommandId();
+
+ BOOL FillMenuInfo(HWND hToolbar, MENUITEMINFO *pmii, LPWSTR pszBuffer, INT cchBufferMax);
+
+ void SetFocus(HWND hToolbar, ToolbarItem *focusItem, BOOL fSet);
+ BOOL KeyDown(HWND hToolbar, INT vKey, UINT flags);
+ BOOL KeyUp(HWND hToolbar, INT vKey, UINT flags);
+
+
+protected:
+ UINT commandId;
+ INT offsetX;
+ INT offsetY;
+ COLORREF rgbText;
+ COLORREF rgbHilite;
+};
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_BUTTON_HEADER
diff --git a/Src/omBrowser/toolbarEditbox.cpp b/Src/omBrowser/toolbarEditbox.cpp
new file mode 100644
index 00000000..e4940676
--- /dev/null
+++ b/Src/omBrowser/toolbarEditbox.cpp
@@ -0,0 +1,990 @@
+#define OEMRESOURCE
+
+#include "main.h"
+#include "./toolbarEditbox.h"
+#include "./menu.h"
+#include "./ifc_skinhelper.h"
+
+#include "../Plugins/General/gen_ml/ml_ipc_0313.h"
+
+#include <richedit.h>
+#include <strsafe.h>
+
+#define NTEF_USERFLAGSMASK 0x00FFFFFF
+#define NTEF_UNICODE 0x01000000
+#define NTEF_CLICKEDONCE 0x02000000
+#define NTEF_SHOWCURSOR 0x04000000
+#define NTEF_KEYDOWN 0x08000000
+#define NTEF_MENULOOP 0x10000000
+#define NTEF_SHOWCARET 0x20000000
+
+typedef struct __TOOLBAREDITBOX
+{
+ WNDPROC originalProc;
+ UINT flags;
+ ToolbarEditboxHost *host;
+ DWORD dblclkTime;
+} TOOLBAREDITBOX;
+
+static ATOM TOOLBAREDITBOX_PROP = 0;
+static HHOOK mouseHook = NULL;
+
+#define GetEditbox(__hwnd) ((TOOLBAREDITBOX*)GetProp((__hwnd), MAKEINTATOM(TOOLBAREDITBOX_PROP)))
+
+static LRESULT CALLBACK ToolbarEditbox_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static INT CALLBACK ToolbarEditbox_WordBreakProc(LPWSTR pszText, INT iCurrent, INT cchLen, INT code);
+static INT CALLBACK ToolbarEditbox_WordBreakProc2(LPWSTR pszText, INT iCurrent, INT cchLen, INT code);
+
+static void CALLBACK ToolbarEditbox_Uninitialize()
+{
+ if (0 != TOOLBAREDITBOX_PROP)
+ {
+ GlobalDeleteAtom(TOOLBAREDITBOX_PROP);
+ TOOLBAREDITBOX_PROP = 0;
+ }
+}
+
+
+BOOL ToolbarEditbox_AttachWindow(HWND hEditbox, ToolbarEditboxHost *host)
+{
+ if (!IsWindow(hEditbox))
+ return FALSE;
+
+ if (0 == TOOLBAREDITBOX_PROP)
+ {
+ TOOLBAREDITBOX_PROP = GlobalAddAtom(L"NullsoftToolbarEditBox");
+ if (0 == TOOLBAREDITBOX_PROP) return FALSE;
+ Plugin_RegisterUnloadCallback(ToolbarEditbox_Uninitialize);
+ }
+
+ TOOLBAREDITBOX *editbox = (TOOLBAREDITBOX*)GetProp(hEditbox, MAKEINTATOM(TOOLBAREDITBOX_PROP));
+ if (NULL != editbox) return TRUE;
+
+ editbox = (TOOLBAREDITBOX*)calloc(1, sizeof(TOOLBAREDITBOX));
+ if (NULL == editbox) return FALSE;
+
+
+ ifc_skinhelper *skinHelper = NULL;
+ if (SUCCEEDED(Plugin_GetSkinHelper(&skinHelper)))
+ {
+ // skinHelper->SkinControl(hEditbox, SKINNEDWND_TYPE_EDIT, SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWES_BOTTOM);
+ skinHelper->Release();
+ }
+
+ ZeroMemory(editbox, sizeof(TOOLBAREDITBOX));
+
+ if (IsWindowUnicode(hEditbox))
+ editbox->flags |= NTEF_UNICODE;
+
+ editbox->host = host;
+
+ editbox->originalProc = (WNDPROC)(LONG_PTR)((0 != (NTEF_UNICODE & editbox->flags)) ?
+ SetWindowLongPtrW(hEditbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)ToolbarEditbox_WindowProc) :
+ SetWindowLongPtrA(hEditbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)ToolbarEditbox_WindowProc));
+
+ if (NULL == editbox->originalProc || !SetProp(hEditbox, MAKEINTATOM(TOOLBAREDITBOX_PROP), editbox))
+ {
+ if (NULL != editbox->originalProc)
+ {
+ if (0 != (NTEF_UNICODE & editbox->flags))
+ SetWindowLongPtrW(hEditbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)editbox->originalProc);
+ else
+ SetWindowLongPtrA(hEditbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)editbox->originalProc);
+ }
+
+ free(editbox);
+ return FALSE;
+ }
+ SendMessage(hEditbox, EM_SETWORDBREAKPROC, 0, (LPARAM)ToolbarEditbox_WordBreakProc);
+ return TRUE;
+}
+
+static void ToolbarEditbox_PatchCursor()
+{
+ ShowCursor(FALSE);
+ SetCursor(LoadCursor(NULL, IDC_ARROW));
+ ShowCursor(TRUE);
+
+ CURSORINFO cursorInfo;
+ cursorInfo.cbSize = sizeof(CURSORINFO);
+ if (GetCursorInfo(&cursorInfo) &&
+ 0 != (CURSOR_SHOWING & cursorInfo.flags))
+ {
+ POINT pt;
+ GetCursorPos(&pt);
+ HWND hTarget= WindowFromPoint(pt);
+ if (NULL != hTarget)
+ {
+ UINT hitTest = (UINT)SendMessage(hTarget, WM_NCHITTEST, 0, MAKELPARAM(pt.x, pt.y));
+ UINT uMsg = (HTCLIENT == hitTest) ? WM_MOUSEMOVE : WM_NCMOUSEMOVE;
+ SendMessage(hTarget, WM_SETCURSOR, (WPARAM)hTarget, MAKELPARAM(hitTest, uMsg));
+ }
+ }
+}
+
+
+static void ToolbarEditbox_Detach(HWND hwnd)
+{
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+ RemoveProp(hwnd, MAKEINTATOM(TOOLBAREDITBOX_PROP));
+
+ ToolbarEditbox_PatchCursor();
+
+ if (NULL != editbox && 0 != (NTEF_SHOWCURSOR & editbox->flags))
+ {
+ ShowCursor(TRUE);
+ editbox->flags &= ~NTEF_SHOWCURSOR;
+ }
+
+ if (NULL != mouseHook)
+ {
+ UnhookWindowsHookEx(mouseHook);
+ mouseHook = NULL;
+ }
+
+ if (NULL == editbox)
+ return;
+
+ if (NULL != editbox->originalProc)
+ {
+ if (0 != (NTEF_UNICODE & editbox->flags))
+ SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)editbox->originalProc);
+ else
+ SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)editbox->originalProc);
+ }
+
+ free(editbox);
+}
+
+
+static LRESULT ToolbarEditbox_CallOrigWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+
+ if (NULL == editbox || NULL == editbox->originalProc)
+ {
+ return (0 != (NTEF_UNICODE & editbox->flags)) ?
+ DefWindowProcW(hwnd, uMsg, wParam, lParam) :
+ DefWindowProcA(hwnd, uMsg, wParam, lParam);
+ }
+
+ return (0 != (NTEF_UNICODE & editbox->flags)) ?
+ CallWindowProcW(editbox->originalProc, hwnd, uMsg, wParam, lParam) :
+ CallWindowProcA(editbox->originalProc, hwnd, uMsg, wParam, lParam);
+}
+
+static void ToolbarEditbox_ResetText(HWND hwnd)
+{
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+ if (NULL != editbox && NULL != editbox->host)
+ editbox->host->EditboxResetText(hwnd);
+}
+
+static void ToolbarEditbox_NavigateNextCtrl(HWND hwnd, BOOL fForward)
+{
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+ if (NULL != editbox && NULL != editbox->host)
+ editbox->host->EditboxNavigateNextCtrl(hwnd, fForward);
+}
+
+static void ToolbarEditbox_AcceptText(HWND hwnd)
+{
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+ if (NULL != editbox && NULL != editbox->host)
+ editbox->host->EditboxAcceptText(hwnd);
+}
+
+static BOOL ToolbarEditbox_IsDelimiterChar(WCHAR testChar)
+{
+ WORD info;
+ if (FALSE == GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, &testChar, 1, &info))
+ return 0;
+
+ return (0 != ((C1_SPACE | C1_PUNCT | C1_CNTRL | C1_BLANK) & info));
+}
+
+static INT ToolbarEditbox_FindLeft(LPCWSTR pszText, INT iCurrent, INT cchLen)
+{
+ if (iCurrent <= 0)
+ return 0;
+
+ LPCWSTR pszCursor = &pszText[iCurrent];
+ BOOL charDelim = ToolbarEditbox_IsDelimiterChar(*pszCursor);
+
+ for(;;)
+ {
+ pszCursor = CharPrev(pszText, pszCursor);
+ if (charDelim != ToolbarEditbox_IsDelimiterChar(*pszCursor))
+ return (INT)(INT_PTR)(CharNext(pszCursor) - pszText);
+
+ if (pszCursor == pszText)
+ break;
+ }
+ return 0;
+}
+
+static INT ToolbarEditbox_FindRight(LPCWSTR pszText, INT iCurrent, INT cchLen)
+{
+ if (iCurrent >= cchLen)
+ return cchLen;
+
+ LPCWSTR pszEnd = &pszText[cchLen];
+ LPCWSTR pszCursor = &pszText[iCurrent];
+
+ if (iCurrent > 0)
+ pszCursor = CharNext(pszCursor);
+
+ BOOL charDelim = ToolbarEditbox_IsDelimiterChar(*pszCursor);
+
+ for(;;)
+ {
+ pszCursor = CharNext(pszCursor);
+ if (pszCursor >= pszEnd)
+ break;
+
+ if (charDelim != ToolbarEditbox_IsDelimiterChar(*pszCursor))
+ return (INT)(INT_PTR)(pszCursor - pszText);
+ }
+ return cchLen;
+}
+
+static INT ToolbarEditbox_FindWordLeft(LPCWSTR pszText, INT iCurrent, INT cchLen, BOOL fRightCtrl)
+{
+ if (iCurrent < 2)
+ return 0;
+
+ LPCWSTR pszCursor = &pszText[iCurrent];
+
+ if (FALSE == fRightCtrl)
+ pszCursor = CharPrev(pszText, pszCursor);
+
+ BOOL prevCharDelim = ToolbarEditbox_IsDelimiterChar(*pszCursor);
+ for(;;)
+ {
+ pszCursor = CharPrev(pszText, pszCursor);
+ if (TRUE == ToolbarEditbox_IsDelimiterChar(*pszCursor))
+ {
+ if (FALSE == prevCharDelim)
+ return (INT)(INT_PTR)(CharNext(pszCursor) - pszText);
+
+ prevCharDelim = TRUE;
+ }
+ else
+ prevCharDelim = FALSE;
+
+ if (pszCursor == pszText)
+ break;
+ }
+ return 0;
+}
+
+static INT ToolbarEditbox_FindWordRight(LPCWSTR pszText, INT iCurrent, INT cchLen)
+{
+ if ( iCurrent >= (cchLen - 1))
+ return cchLen;
+
+ LPCWSTR pszEnd = &pszText[cchLen];
+ LPCWSTR pszCursor = &pszText[iCurrent];
+
+ BOOL prevCharDelim = ToolbarEditbox_IsDelimiterChar(*pszCursor);
+
+ for(;;)
+ {
+ pszCursor = CharNext(pszCursor);
+ if (pszCursor >= pszEnd)
+ break;
+
+ if (prevCharDelim != ToolbarEditbox_IsDelimiterChar(*pszCursor))
+ {
+ prevCharDelim = TRUE;
+ return (INT)(INT_PTR)(pszCursor - pszText);
+ }
+ else
+ prevCharDelim = FALSE;
+
+ }
+ return cchLen;
+}
+
+static INT CALLBACK ToolbarEditbox_WordBreakProc(LPWSTR pszText, INT iCurrent, INT cchLen, INT code)
+{
+ switch(code)
+ {
+ case WB_ISDELIMITER: return (iCurrent < 0) ? 0 : ((iCurrent > cchLen) ? (cchLen + 1) : ToolbarEditbox_IsDelimiterChar(pszText[iCurrent]));
+ case WB_LEFT: return ToolbarEditbox_FindLeft(pszText, iCurrent, cchLen);
+ case WB_RIGHT: return ToolbarEditbox_FindRight(pszText, iCurrent, cchLen);
+ case WB_MOVEWORDLEFT: return ToolbarEditbox_FindWordLeft(pszText, iCurrent, cchLen, FALSE);
+ case WB_MOVEWORDRIGHT: return ToolbarEditbox_FindWordRight(pszText, iCurrent, cchLen);
+ }
+ return 0;
+}
+
+static INT CALLBACK ToolbarEditbox_WordBreakProcOverrideLeft(LPWSTR pszText, INT iCurrent, INT cchLen, INT code)
+{
+ switch(code)
+ {
+ case WB_LEFT: return ToolbarEditbox_FindWordLeft(pszText, iCurrent, cchLen, FALSE);
+ case WB_RIGHT: return ToolbarEditbox_FindWordRight(pszText, iCurrent, cchLen);
+ }
+ return ToolbarEditbox_WordBreakProc(pszText, iCurrent, cchLen, code);
+}
+
+static INT CALLBACK ToolbarEditbox_WordBreakProcOverrideRight(LPWSTR pszText, INT iCurrent, INT cchLen, INT code)
+{
+ switch(code)
+ {
+ case WB_LEFT: return ToolbarEditbox_FindWordLeft(pszText, iCurrent, cchLen, TRUE);
+ case WB_RIGHT: return ToolbarEditbox_FindWordRight(pszText, iCurrent, cchLen);
+ }
+ return ToolbarEditbox_WordBreakProc(pszText, iCurrent, cchLen, code);
+}
+
+
+static void ToolbarEditbox_OnDestroy(HWND hwnd)
+{
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+ if (NULL != editbox && NULL != editbox->host)
+ editbox->host->EditboxDestroyed(hwnd);
+
+ WNDPROC originalProc = (editbox ? editbox->originalProc : NULL);
+ BOOL fUnicode = (0 != (NTEF_UNICODE & editbox->flags));
+
+ ToolbarEditbox_Detach(hwnd);
+
+ if (NULL != originalProc)
+ {
+ if (FALSE != fUnicode)
+ CallWindowProcW(originalProc, hwnd, WM_DESTROY, 0, 0L);
+ else
+ CallWindowProcA(originalProc, hwnd, WM_DESTROY, 0, 0L);
+ }
+
+}
+
+static void ToolbarEditbox_OnSetFocus(HWND hwnd, HWND hFocus)
+{
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+ if (NULL != editbox)
+ {
+ editbox->flags &= ~NTEF_CLICKEDONCE;
+ }
+ ToolbarEditbox_CallOrigWindowProc(hwnd, WM_SETFOCUS, (WPARAM)hFocus, 0L);
+}
+
+static void ToolbarEditbox_OnKillFocus(HWND hwnd, HWND hFocus)
+{
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+ if (NULL != editbox && NULL != editbox->host )
+ {
+ if (FALSE != editbox->host->EditboxKillFocus(hwnd, hFocus))
+ return;
+ }
+
+ ToolbarEditbox_CallOrigWindowProc(hwnd, WM_KILLFOCUS, (WPARAM)hFocus, 0L);
+}
+
+static LRESULT ToolbarEditbox_OnGetDlgCode(HWND hwnd, INT vKey, MSG* pMsg)
+{
+ LRESULT result = ToolbarEditbox_CallOrigWindowProc(hwnd, WM_GETDLGCODE, (WPARAM)vKey, (LPARAM)pMsg);
+ result |= DLGC_WANTALLKEYS;
+ result &= ~DLGC_HASSETSEL;
+ return result;
+}
+
+
+static LRESULT ToolbarEditbox_OnSetCursor(HWND hwnd, HWND hOwner, INT hitTest, INT messageId)
+{
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+ if (HTCLIENT == hitTest &&
+ NULL != editbox && 0 == (NTEF_MENULOOP & editbox->flags))
+ {
+ HCURSOR hCursor = (HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(OCR_IBEAM), IMAGE_CURSOR,
+ 0, 0, LR_DEFAULTCOLOR | LR_SHARED | LR_DEFAULTSIZE);
+ if (NULL != hCursor)
+ {
+ SetCursor(hCursor);
+ return TRUE;
+ }
+ }
+
+ HWND hParent = GetParent(hwnd);
+ if (NULL != hParent &&
+ FALSE != (BOOL)SendMessage(hParent, WM_SETCURSOR, (WPARAM)hOwner, MAKELPARAM(hitTest, messageId)))
+ {
+ return TRUE;
+ }
+
+ return ToolbarEditbox_CallOrigWindowProc(hwnd, WM_SETCURSOR, (WPARAM)hOwner, MAKELPARAM(hitTest, messageId));
+}
+
+static void ToolbarEditbox_OnContextMenu(HWND hwnd, HWND hTarget, POINTS pts)
+{
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+ if (NULL != editbox) editbox->flags |= NTEF_MENULOOP;
+// SendMessage(hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELPARAM(HTCLIENT, WM_MOUSEMOVE));
+ ToolbarEditbox_CallOrigWindowProc(hwnd, WM_CONTEXTMENU, (WPARAM)hTarget, *((LPARAM*)&pts));
+ if (NULL != editbox) editbox->flags &= ~NTEF_MENULOOP;
+}
+
+static void ToolbarEditbox_OnLButtonDown(HWND hwnd, UINT vKey, POINTS pts)
+{
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+ if (NULL != editbox)
+ {
+ if (0 != (NTEF_SHOWCARET & editbox->flags))
+ {
+ editbox->flags &= ~NTEF_SHOWCARET;
+ ShowCaret(hwnd);
+ }
+
+
+ DWORD clickTime = GetTickCount();
+ if (clickTime >= editbox->dblclkTime && clickTime <= (editbox->dblclkTime + GetDoubleClickTime()))
+ {
+ SendMessage(hwnd, NTEBM_SELECTALL, 0, 0L);
+ return;
+ }
+
+ UINT start, end;
+ SendMessage(hwnd, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ if (start != end)
+ {
+ editbox->flags |= NTEF_CLICKEDONCE;
+ }
+ }
+
+ ToolbarEditbox_CallOrigWindowProc(hwnd, WM_LBUTTONDOWN, (WPARAM)vKey, *((LPARAM*)&pts));
+}
+
+static void ToolbarEditbox_OnLButtonUp(HWND hwnd, UINT vKey, POINTS pts)
+{
+ ToolbarEditbox_CallOrigWindowProc(hwnd, WM_LBUTTONUP, (WPARAM)vKey, *((LPARAM*)&pts));
+
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+ if (NULL != editbox && 0 == (NTEF_CLICKEDONCE & editbox->flags) && hwnd == GetFocus())
+ {
+ editbox->flags |= NTEF_CLICKEDONCE;
+ UINT start, end;
+ SendMessage(hwnd, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ if (start == end)
+ {
+ SendMessage(hwnd, NTEBM_SELECTALL, 0, 0L);
+ }
+ }
+}
+
+static void ToolbarEditbox_OnLButtonDblClk(HWND hwnd, UINT vKey, POINTS pts)
+{
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+ if (NULL == editbox) return;
+
+ DWORD clickTime = GetTickCount();
+ if (clickTime >= editbox->dblclkTime && clickTime <= (editbox->dblclkTime + 2*GetDoubleClickTime()))
+ {
+ INT r = (INT)SendMessage(hwnd, EM_CHARFROMPOS, 0, *(LPARAM*)&pts);
+ r = LOWORD(r);
+ SendMessage(hwnd, EM_SETSEL, (WPARAM)r, (LPARAM)r);
+ editbox->dblclkTime = 0;
+ }
+ else
+ {
+ editbox->dblclkTime = clickTime;
+ }
+
+ INT f, l;
+ SendMessage(hwnd, EM_GETSEL, (WPARAM)&f, (LPARAM)&l);
+ if (f != l) return;
+
+
+ ToolbarEditbox_CallOrigWindowProc(hwnd, WM_LBUTTONDBLCLK, (WPARAM)vKey, *((LPARAM*)&pts));
+
+}
+
+static void ToolbarEditbox_OnMouseMove(HWND hwnd, UINT vKey, POINTS pts)
+{
+ ToolbarEditbox_CallOrigWindowProc(hwnd, WM_MOUSEMOVE, (WPARAM)vKey, *((LPARAM*)&pts));
+
+ if (0 != (MK_LBUTTON & vKey))
+ {
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+ if (NULL != editbox && 0 == (NTEF_SHOWCARET & editbox->flags) &&
+ hwnd == GetFocus())
+ {
+ UINT start, end;
+ SendMessage(hwnd, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ if (start != end)
+ {
+ if (FALSE != HideCaret(hwnd))
+ editbox->flags |= NTEF_SHOWCARET;
+ }
+ }
+ }
+}
+
+static LRESULT CALLBACK ToolbarEditbox_MouseHook(int nCode, WPARAM wParam, LPARAM lParam)
+{
+ ToolbarEditbox_PatchCursor();
+
+ TOOLBAREDITBOX *editbox = GetEditbox(GetFocus());
+ if (NULL != editbox && 0 != (NTEF_SHOWCURSOR & editbox->flags))
+ {
+ ShowCursor(TRUE);
+ editbox->flags &= ~NTEF_SHOWCURSOR;
+ }
+
+ LRESULT result = CallNextHookEx(mouseHook, nCode, wParam, lParam);
+ UnhookWindowsHookEx(mouseHook);
+ mouseHook = NULL;
+ return result;
+}
+
+static void ToolbarEditbox_DeleteWord(HWND hwnd, UINT vKey, UINT state)
+{
+ BOOL resetVisible = FALSE;
+ INT first, last;
+ SendMessage(hwnd, EM_GETSEL, (WPARAM)&first, (LPARAM)&last);
+ if (first == last)
+ {
+ UINT windowStyle = GetWindowStyle(hwnd);
+ if (0 != (WS_VISIBLE & windowStyle))
+ {
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE);
+ resetVisible = TRUE;
+ }
+
+ SendMessage(hwnd, WM_KEYDOWN, (WPARAM)vKey, (LPARAM)state);
+ INT newFirst, newLast;
+ SendMessage(hwnd, EM_GETSEL, (WPARAM)&newFirst, (LPARAM)&newLast);
+ if (newFirst != first || newLast != last)
+ SendMessage(hwnd, EM_SETSEL, (WPARAM)first, (LPARAM)newLast);
+ }
+
+ SendMessage(hwnd, EM_REPLACESEL, TRUE, NULL);
+ if (FALSE != resetVisible)
+ {
+ UINT windowStyle = GetWindowStyle(hwnd);
+ if (0 == (WS_VISIBLE & windowStyle))
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle | WS_VISIBLE);
+
+ InvalidateRect(hwnd, NULL, FALSE);
+ }
+
+}
+static void ToolbarEditbox_OnKeyDown(HWND hwnd, UINT vKey, UINT state)
+{
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+ if (NULL != editbox)
+ {
+ if (0 != (NTEF_SHOWCARET & editbox->flags))
+ {
+ editbox->flags &= ~NTEF_SHOWCARET;
+ ShowCaret(hwnd);
+ }
+
+ editbox->flags |= NTEF_KEYDOWN;
+
+ }
+
+
+ if (NULL == editbox || NULL == editbox->host ||
+ FALSE == editbox->host->EditboxKeyDown(hwnd, vKey, state))
+ {
+ EDITWORDBREAKPROC fnOrigBreak = NULL;
+ if(0 != (0x8000 & GetAsyncKeyState(VK_CONTROL)))
+ {
+ switch(vKey)
+ {
+ case VK_LEFT:
+ case VK_RIGHT:
+ fnOrigBreak = (EDITWORDBREAKPROC)SendMessage(hwnd, EM_GETWORDBREAKPROC, 0, 0L);
+ if (ToolbarEditbox_WordBreakProc == fnOrigBreak)
+ {
+ EDITWORDBREAKPROC fnOverride = (VK_LEFT == vKey) ?
+ ToolbarEditbox_WordBreakProcOverrideLeft : ToolbarEditbox_WordBreakProcOverrideRight;
+ SendMessage(hwnd, EM_SETWORDBREAKPROC, 0, (LPARAM)fnOverride);
+ }
+ break;
+ case VK_DELETE:
+ ToolbarEditbox_DeleteWord(hwnd, VK_RIGHT, state);
+ return;
+ case VK_BACK:
+ ToolbarEditbox_DeleteWord(hwnd, VK_LEFT, state);
+ return;
+
+
+ }
+ }
+
+ ToolbarEditbox_CallOrigWindowProc(hwnd, WM_KEYDOWN, (WPARAM)vKey, (LPARAM)state);
+
+ if (NULL != fnOrigBreak)
+ SendMessage(hwnd, EM_SETWORDBREAKPROC, 0, (LPARAM)fnOrigBreak);
+ }
+
+ if (('0' <= vKey && vKey <= '9') ||
+ ('A' <= vKey && vKey <= 'Z') ||
+ (VK_NUMPAD0 <= vKey && vKey <= VK_DIVIDE) ||
+ (VK_OEM_1 <= vKey && vKey <= VK_OEM_3) ||
+ (VK_OEM_4 <= vKey && vKey <= VK_OEM_8) ||
+ VK_OEM_NEC_EQUAL == vKey ||
+ VK_OEM_102 == vKey)
+ {
+ if (0 == (0x8000 & GetAsyncKeyState(VK_CONTROL)) &&
+ 0 == (0x8000 & GetAsyncKeyState(VK_MENU)))
+ {
+ PostMessage(hwnd, NTEBM_UPDATECURSOR, 0, 0L);
+ }
+ }
+
+}
+
+static void ToolbarEditbox_OnKeyUp(HWND hwnd, UINT vKey, UINT state)
+{
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+ if (NULL == editbox || NULL == editbox->host ||
+ FALSE == editbox->host->EditboxKeyUp(hwnd, vKey, state))
+ {
+ ToolbarEditbox_CallOrigWindowProc(hwnd, WM_KEYUP, (WPARAM)vKey, (LPARAM)state);
+ }
+
+ if (NULL != editbox)
+ editbox->flags &= ~NTEF_KEYDOWN;
+
+ if (NULL == mouseHook)
+ {
+ mouseHook = SetWindowsHookEx(WH_MOUSE, ToolbarEditbox_MouseHook, NULL, GetCurrentThreadId());
+ }
+
+}
+
+static void ToolbarEditbox_OnChar(HWND hwnd, UINT vKey, UINT state)
+{
+ BOOL fControl = FALSE;
+ if (0 != (0x8000 & GetAsyncKeyState(VK_CONTROL)))
+ {
+ fControl = TRUE;
+ UINT scanCode = (HIWORD(state) & 0x00FF);
+ vKey = MapVirtualKey(scanCode, MAPVK_VSC_TO_VK);
+ }
+
+ switch(vKey)
+ {
+ case VK_ESCAPE: ToolbarEditbox_ResetText(hwnd); return;
+ case VK_TAB: ToolbarEditbox_NavigateNextCtrl(hwnd, 0 == (0x8000 & GetAsyncKeyState(VK_SHIFT))); return;
+ case VK_RETURN: ToolbarEditbox_AcceptText(hwnd); return;
+ }
+
+ if (FALSE != fControl)
+ {
+ switch(vKey)
+ {
+ case 'A': SendMessage(hwnd, NTEBM_SELECTALL, 0, 0L); return;
+ case 'Z': SendMessage(hwnd, EM_UNDO, 0, 0L); return;
+ case 'X': SendMessage(hwnd, WM_CUT, 0, 0L); return;
+ case 'C': SendMessage(hwnd, WM_COPY, 0, 0L); return;
+ case 'V': SendMessage(hwnd, WM_PASTE, 0, 0L); return;
+ }
+ return;
+ }
+
+
+
+
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+ if (NULL != editbox && NULL != editbox->host &&
+ FALSE != editbox->host->EditboxPreviewChar(hwnd, vKey, state))
+ {
+ return;
+ }
+
+ ToolbarEditbox_CallOrigWindowProc(hwnd, WM_CHAR, (WPARAM)vKey, (LPARAM)state);
+}
+
+
+static void ToolbarEditbox_OnUpdateCursor(HWND hwnd)
+{
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+ if (NULL != editbox && 0 != (NTEF_KEYDOWN & editbox->flags))
+ {
+ if (NULL != mouseHook)
+ {
+ UnhookWindowsHookEx(mouseHook);
+ mouseHook = NULL;
+ }
+
+ if (0 == (NTEF_SHOWCURSOR & editbox->flags))
+ {
+ CURSORINFO cursorInfo;
+ cursorInfo.cbSize = sizeof(CURSORINFO);
+ if (GetCursorInfo(&cursorInfo) && 0 != (CURSOR_SHOWING & cursorInfo.flags))
+ {
+ ShowCursor(FALSE);
+ editbox->flags |= NTEF_SHOWCURSOR;
+ }
+ }
+ }
+}
+
+static void ToolbarEditbox_OnEnterMenuLoop(HWND hwnd, BOOL fContext)
+{
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+ if (NULL != editbox) editbox->flags |= NTEF_MENULOOP;
+
+ ToolbarEditbox_CallOrigWindowProc(hwnd, WM_ENTERMENULOOP, (WPARAM)fContext, 0L);
+}
+
+static void ToolbarEditbox_OnExitMenuLoop(HWND hwnd, BOOL fContext)
+{
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+ if (NULL != editbox) editbox->flags &= ~NTEF_MENULOOP;
+
+ ToolbarEditbox_CallOrigWindowProc(hwnd, WM_EXITMENULOOP, (WPARAM)fContext, 0L);
+}
+
+static BOOL ToolbarEditbox_RemoveBadChars(LPCWSTR pszText, LPWSTR *bufferOut)
+{
+ LPWSTR buffer = NULL;
+ if (NULL == pszText) return FALSE;
+
+ const WCHAR szBadChars[] = { L'\r', L'\n', L'\t', L'\0'};
+ BOOL fDetected = FALSE;
+
+ for (LPCWSTR p = pszText; L'\0' != *p && FALSE == fDetected; p++)
+ {
+ for (LPCWSTR b = szBadChars; L'\0' != *b; b++)
+ {
+ if (*p == *b)
+ {
+ fDetected = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (FALSE == fDetected)
+ return FALSE;
+
+ if (NULL == bufferOut)
+ return TRUE;
+
+ INT cchText = lstrlen(pszText);
+ buffer = Plugin_MallocString(cchText + 1);
+ if (NULL == buffer) return FALSE;
+
+ LPCWSTR s = pszText;
+ LPWSTR d = buffer;
+ LPCWSTR b;
+ for(;;)
+ {
+ for (b = szBadChars; L'\0' != *b && *s != *b; b++);
+ if(L'\0' != *b)
+ {
+ if (L'\t' == *b)
+ {
+ *d = L' ';
+ d++;
+ }
+ }
+ else
+ {
+ *d = *s;
+ d++;
+ }
+
+ if (L'\0' == *s)
+ break;
+
+ s++;
+
+ }
+
+ *bufferOut = buffer;
+ return TRUE;
+}
+
+static LRESULT ToolbarEditbox_OnSetText(HWND hwnd, LPCWSTR pszText)
+{
+ LPWSTR buffer;
+ if (FALSE == ToolbarEditbox_RemoveBadChars(pszText, &buffer))
+ buffer = NULL;
+ else
+ pszText = buffer;
+
+ LRESULT result = ToolbarEditbox_CallOrigWindowProc(hwnd, WM_SETTEXT, 0, (LPARAM)pszText);
+
+ if (NULL != buffer)
+ Plugin_FreeString(buffer);
+
+ return result;
+}
+
+static LRESULT ToolbarEditbox_OnReplaceSel(HWND hwnd, BOOL fUndo, LPCWSTR pszText)
+{
+ LPWSTR buffer;
+ if (FALSE == ToolbarEditbox_RemoveBadChars(pszText, &buffer))
+ buffer = NULL;
+ else
+ pszText = buffer;
+
+ LRESULT result = ToolbarEditbox_CallOrigWindowProc(hwnd, EM_REPLACESEL, (WPARAM)fUndo, (LPARAM)pszText);
+
+ if (NULL != buffer)
+ Plugin_FreeString(buffer);
+
+ return result;
+}
+
+static void ToolbarEditbox_ReplaceText(HWND hwnd, LPCWSTR pszText, BOOL fUndo, BOOL fScrollCaret)
+{
+ UINT windowStyle = GetWindowStyle(hwnd);
+ if (0 != (WS_VISIBLE & windowStyle))
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE);
+
+ SendMessage(hwnd, EM_REPLACESEL, (WPARAM)fUndo, (LPARAM)pszText);
+ if (FALSE != fScrollCaret)
+ {
+ INT f, l;
+ SendMessage(hwnd, EM_GETSEL, (WPARAM)&f, (LPARAM)&l);
+ SendMessage(hwnd, EM_SETSEL, (WPARAM)f, (LPARAM)l);
+ }
+
+ if (0 != (WS_VISIBLE & windowStyle))
+ {
+ windowStyle = GetWindowStyle(hwnd);
+ if (0 == (WS_VISIBLE & windowStyle))
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle | WS_VISIBLE);
+ InvalidateRect(hwnd, NULL, FALSE);
+ }
+}
+
+static void ToolbarEditbox_OnPaste(HWND hwnd)
+{
+ IDataObject *pObject;
+ HRESULT hr = OleGetClipboard(&pObject);
+ if (SUCCEEDED(hr))
+ {
+ FORMATETC fmt = {CF_UNICODETEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+ STGMEDIUM stgm;
+ hr = pObject->GetData(&fmt, &stgm);
+ if(S_OK == hr)
+ {
+ LPCWSTR pClipboard = (LPCWSTR)GlobalLock(stgm.hGlobal);
+ ToolbarEditbox_ReplaceText(hwnd, pClipboard, TRUE, TRUE);
+ GlobalUnlock(stgm.hGlobal);
+ ReleaseStgMedium(&stgm);
+
+ }
+ else
+ {
+ fmt.cfFormat = CF_TEXT;
+ hr = pObject->GetData(&fmt, &stgm);
+ if(S_OK == hr)
+ {
+ LPCSTR pClipboardAnsi = (LPCSTR)GlobalLock(stgm.hGlobal);
+ LPWSTR pClipboard = Plugin_MultiByteToWideChar(CP_ACP, 0, pClipboardAnsi, -1);
+ ToolbarEditbox_ReplaceText(hwnd, pClipboard, TRUE, TRUE);
+ Plugin_FreeString(pClipboard);
+ GlobalUnlock(stgm.hGlobal);
+ ReleaseStgMedium(&stgm);
+ }
+ }
+ pObject->Release();
+ }
+}
+
+
+static void ToolbarEditbox_OnSelectAll(HWND hwnd)
+{
+ UINT windowStyle = GetWindowStyle(hwnd);
+
+ INT f, l, tl;
+ tl = GetWindowTextLength(hwnd);
+ SendMessage(hwnd, EM_GETSEL, (WPARAM)&f, (LPARAM)&l);
+ if (f == 0 && tl == l)
+ return;
+
+ if (0 != (WS_VISIBLE & windowStyle))
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE);
+
+ RECT rc;
+ GetWindowRect(hwnd, &rc);
+ SetWindowPos(hwnd, NULL, 0, 0, 0xFFFFF, rc.bottom - rc.top,
+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_NOCOPYBITS);
+
+ SendMessage(hwnd, EM_SETSEL, 0, -1);
+
+ SetWindowPos(hwnd, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top,
+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_NOCOPYBITS);
+
+ if (0 != (WS_VISIBLE & windowStyle))
+ {
+ UINT windowStyle = GetWindowStyle(hwnd);
+ if (0 == (WS_VISIBLE & windowStyle))
+ {
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle | WS_VISIBLE);
+ InvalidateRect(hwnd, NULL, FALSE);
+ }
+ }
+
+ TOOLBAREDITBOX *editbox = GetEditbox(hwnd);
+ if (NULL != editbox &&
+ 0 == (NTEF_SHOWCARET & editbox->flags) &&
+ FALSE != HideCaret(hwnd))
+ {
+ editbox->flags |= NTEF_SHOWCARET;
+ }
+}
+
+
+
+static LRESULT ToolbarEditbox_OnFindWordBreak(HWND hwnd, INT code, INT start)
+{
+ EDITWORDBREAKPROC fnBreak = (EDITWORDBREAKPROC)SendMessage(hwnd, EM_GETWORDBREAKPROC, 0, 0L);
+ if (NULL == fnBreak) return 0;
+
+ UINT cchText = GetWindowTextLength(hwnd);
+ if (0 == cchText) return 0;
+
+ LPWSTR pszText = Plugin_MallocString(cchText + 1);
+ if (NULL == pszText) return 0;
+
+ LRESULT result = 0;
+ cchText = GetWindowText(hwnd, pszText, cchText + 1);
+ if (0 != cchText)
+ {
+ result = fnBreak(pszText, start, cchText, code);
+ }
+ Plugin_FreeString(pszText);
+ return result;
+}
+
+static LRESULT CALLBACK ToolbarEditbox_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_DESTROY: ToolbarEditbox_OnDestroy(hwnd); return 0;
+ case WM_SETFOCUS: ToolbarEditbox_OnSetFocus(hwnd, (HWND)wParam); return 0;
+ case WM_KILLFOCUS: ToolbarEditbox_OnKillFocus(hwnd, (HWND)wParam); return 0;
+ case WM_GETDLGCODE: return ToolbarEditbox_OnGetDlgCode(hwnd, (INT)wParam, (MSG*)lParam);
+ case WM_SETCURSOR: return ToolbarEditbox_OnSetCursor(hwnd, (HWND)wParam, (INT)LOWORD(lParam), (INT)HIWORD(lParam));
+ case WM_CONTEXTMENU: ToolbarEditbox_OnContextMenu(hwnd, (HWND)wParam, MAKEPOINTS(lParam)); return 0;
+ case WM_LBUTTONDOWN: ToolbarEditbox_OnLButtonDown(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
+ case WM_LBUTTONUP: ToolbarEditbox_OnLButtonUp(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
+ case WM_LBUTTONDBLCLK: ToolbarEditbox_OnLButtonDblClk(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
+ case WM_MOUSEMOVE: ToolbarEditbox_OnMouseMove(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
+ case WM_KEYDOWN: ToolbarEditbox_OnKeyDown(hwnd, (UINT)wParam, (UINT)lParam); return 0;
+ case WM_KEYUP: ToolbarEditbox_OnKeyUp(hwnd, (UINT)wParam, (UINT)lParam); return 0;
+ case WM_CHAR: ToolbarEditbox_OnChar(hwnd, (UINT)wParam, (UINT)lParam); return 0;
+ case WM_ENTERMENULOOP: ToolbarEditbox_OnEnterMenuLoop(hwnd, (BOOL)wParam); return 0;
+ case WM_EXITMENULOOP: ToolbarEditbox_OnExitMenuLoop(hwnd, (BOOL)wParam); return 0;
+ case WM_SETTEXT: return ToolbarEditbox_OnSetText(hwnd, (LPCWSTR)lParam);
+ case WM_PASTE: ToolbarEditbox_OnPaste(hwnd); return 1;
+ case EM_REPLACESEL: ToolbarEditbox_OnReplaceSel(hwnd, (BOOL)wParam, (LPCWSTR)lParam); return 0;
+ case EM_FINDWORDBREAK: return ToolbarEditbox_OnFindWordBreak(hwnd, (INT)wParam, (INT)lParam);
+
+ case NTEBM_UPDATECURSOR: ToolbarEditbox_OnUpdateCursor(hwnd); return 0;
+ case NTEBM_SELECTALL: ToolbarEditbox_OnSelectAll(hwnd); return 0;
+ }
+
+ return ToolbarEditbox_CallOrigWindowProc(hwnd, uMsg, wParam, lParam);
+}
diff --git a/Src/omBrowser/toolbarEditbox.h b/Src/omBrowser/toolbarEditbox.h
new file mode 100644
index 00000000..71cc4731
--- /dev/null
+++ b/Src/omBrowser/toolbarEditbox.h
@@ -0,0 +1,32 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_TOOLBAREDITBOX_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_TOOLBAREDITBOX_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+class ToolbarEditboxHost;
+
+BOOL ToolbarEditbox_AttachWindow(HWND hEditbox, ToolbarEditboxHost *host);
+
+#define NTEBM_FIRST (WM_APP + 2)
+#define NTEBM_SELECTALL (NTEBM_FIRST + 0)
+#define NTEBM_UPDATECURSOR (NTEBM_FIRST + 1) // internal
+
+
+class __declspec(novtable) ToolbarEditboxHost
+{
+public:
+ virtual void EditboxDestroyed(HWND hwnd) = 0;
+ virtual BOOL EditboxKillFocus(HWND hwnd, HWND hFocus) = 0; // return TRUE if handled
+ virtual void EditboxResetText(HWND hwnd) = 0;
+ virtual void EditboxNavigateNextCtrl(HWND hwnd, BOOL fForward) = 0;
+ virtual void EditboxAcceptText(HWND hwnd) = 0;
+ virtual BOOL EditboxKeyDown(HWND hwnd, UINT vKey, UINT state) = 0; // return TRUE if handled;
+ virtual BOOL EditboxKeyUp(HWND hwnd, UINT vKey, UINT state) = 0; // return TRUE if handled;
+ virtual BOOL EditboxPreviewChar(HWND hwnd, UINT vKey, UINT state) = 0; // return TRUE if handled;
+};
+
+#endif // NULLSOFT_WINAMP_OMBROWSER_TOOLBAREDITBOX_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/toolbarItem.cpp b/Src/omBrowser/toolbarItem.cpp
new file mode 100644
index 00000000..e96e0051
--- /dev/null
+++ b/Src/omBrowser/toolbarItem.cpp
@@ -0,0 +1,117 @@
+#include "main.h"
+#include "./toolbarItem.h"
+#include "./toolbar.h"
+#include "./graphics.h"
+#include "./resource.h"
+#include "../Plugins/General/gen_ml/ml_ipc_0313.h"
+#include <strsafe.h>
+
+ToolbarItem::ToolbarItem(LPCSTR pszName, UINT nStyle, INT nIcon, LPCWSTR pszText, LPCWSTR pszDescription)
+ : ref(1), name(NULL), style(nStyle), iconId(nIcon), text(NULL), description(NULL)
+{
+ name = Plugin_CopyAnsiString(pszName);
+ text = Plugin_DuplicateResString(pszText);
+ description = Plugin_DuplicateResString(pszDescription);
+}
+
+ToolbarItem::~ToolbarItem()
+{
+ Plugin_FreeAnsiString(name);
+ Plugin_FreeResString(text);
+ Plugin_FreeResString(description);
+}
+
+ULONG ToolbarItem::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+ULONG ToolbarItem::Release()
+{
+ if (0 == ref) return ref;
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r) delete(this);
+ return r;
+}
+
+LPCSTR ToolbarItem::GetName()
+{
+ return name;
+}
+
+UINT ToolbarItem::GetStyle()
+{
+ return style;
+}
+
+void ToolbarItem::SetStyle(HWND hToolbar, UINT newStyle, UINT styleMask)
+{
+ UINT styleNew = (style & ~styleMask) | (newStyle & styleMask);
+ if (style != styleNew)
+ {
+ style = styleNew;
+ if (NULL != hToolbar && 0 == (stateHidden & style))
+ InvalidateRect(hToolbar, &rect, FALSE);
+ }
+}
+
+BOOL ToolbarItem::SetRect(const RECT *prc)
+{
+ return CopyRect(&rect, prc);
+}
+
+BOOL ToolbarItem::GetRect(RECT *prc)
+{
+ return CopyRect(prc, &rect);
+}
+
+BOOL ToolbarItem::OffsetRect(INT dx, INT dy)
+{
+ return ::OffsetRect(&rect, dx, dy);
+}
+
+BOOL ToolbarItem::SetRectEmpty()
+{
+ return ::SetRectEmpty(&rect);
+}
+
+BOOL ToolbarItem::IsRectEmpty()
+{
+ return ::IsRectEmpty(&rect);
+}
+
+BOOL ToolbarItem::PtInRect(POINT pt)
+{
+ return ::PtInRect(&rect, pt);
+}
+
+BOOL ToolbarItem::PtInItem(POINT pt)
+{
+ return (pt.x >= rect.left && pt.x < rect.right && rect.bottom != rect.top);
+}
+
+BOOL ToolbarItem::IntersectRect(RECT *prcDst, const RECT *prcSrc)
+{
+ return ::IntersectRect(prcDst, &rect, prcSrc);
+}
+
+BOOL ToolbarItem::IsEqual(LPCSTR pszName, INT cchName)
+{
+ return (NULL != name && CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, NORM_IGNORECASE, pszName, cchName, name, -10));
+}
+BOOL ToolbarItem::SetDescription(HWND hToolbar, LPCWSTR pszDescription)
+{
+ Plugin_FreeResString(description);
+ description = Plugin_DuplicateResString(pszDescription);
+ return TRUE;
+}
+
+HRESULT ToolbarItem::GetText(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ return Plugin_CopyResString(pszBuffer, cchBufferMax, text);
+}
+
+HRESULT ToolbarItem::GetDescription(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ return Plugin_CopyResString(pszBuffer, cchBufferMax, description);
+} \ No newline at end of file
diff --git a/Src/omBrowser/toolbarItem.h b/Src/omBrowser/toolbarItem.h
new file mode 100644
index 00000000..7a652305
--- /dev/null
+++ b/Src/omBrowser/toolbarItem.h
@@ -0,0 +1,107 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_TOOLBARITEM_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_TOOLBARITEM_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+
+#define ICON_NONE (-1)
+
+class __declspec(novtable) ToolbarItem
+{
+public:
+ typedef enum
+ {
+ stateHidden = 0x0001,
+ stateDisabled = 0x0002,
+ statePressed = 0x0004,
+ stateHighlighted = 0x0008,
+ stateFocused = 0x0010,
+ stateNoFocusRect = 0x0020,
+
+ styleChevronOnly = 0x0100,
+ styleNoChevron = 0x0200,
+ stylePopup = 0x0400,
+
+ styleFlexible = 0x1000, // item can change it width
+ styleStatic = 0x2000, // item not reacting on mouse or keyboard events
+ styleWantKey = 0x4000,
+ styleTabstop = 0x8000, // item wants to have it's own tabstop (not TBS_TABSTOP)
+ } Styles;
+
+ typedef struct __Template
+ {
+ LPCSTR name;
+ LPCWSTR text;
+ LPCWSTR description;
+ INT iconId;
+ INT commandId;
+ UINT style;
+ } Template;
+
+protected:
+ ToolbarItem(LPCSTR pszName, UINT nStyle, INT nIcon, LPCWSTR pszText, LPCWSTR pszDescription);
+ virtual ~ToolbarItem();
+
+public:
+ ULONG AddRef();
+ ULONG Release();
+
+ LPCSTR GetName();
+ virtual UINT GetStyle();
+ virtual void SetStyle(HWND hToolbar, UINT newStyle, UINT styleMask); // if NULL != hToolbar - item will be invalidated
+
+ virtual BOOL SetRect(const RECT *prc);
+ BOOL GetRect(RECT *prc);
+ BOOL OffsetRect(INT dx, INT dy);
+ virtual BOOL SetRectEmpty();
+ BOOL IsRectEmpty();
+ BOOL PtInRect(POINT pt);
+
+ BOOL IntersectRect(RECT *prcDst, const RECT *prcSrc);
+
+ BOOL IsEqual(LPCSTR pszName, INT cchName);
+
+ virtual HRESULT GetText(LPWSTR pszBuffer, UINT cchBufferMax);
+ virtual HRESULT GetTextLength(size_t *pcchLength) { return E_NOTIMPL; }
+ virtual HRESULT GetDescription(LPWSTR pszBuffer, UINT cchBufferMax);
+ virtual BOOL SetDescription(HWND hToolbar, LPCWSTR pszDescription);
+
+ virtual BOOL AdjustRect(HWND hToolbar, RECT *proposedRect) { return FALSE; }
+ virtual BOOL Paint(HWND hToolbar, HDC hdc, const RECT *paintRect, UINT state) { return FALSE;}
+ virtual INT GetTip(LPTSTR pszBuffer, INT cchBufferMax) { return 0; }
+ virtual void MouseMove(HWND hToolbar, UINT mouseFlags, POINT pt) {}
+ virtual void MouseLeave(HWND hToolbar) {}
+ virtual void LButtonDown(HWND hToolbar, UINT mouseFlags, POINT pt) {}
+ virtual void LButtonUp(HWND hToolbar, UINT mouseFlags, POINT pt) {}
+ virtual void Click(HWND hToolbar, UINT mouseFlags, POINT pt) {}
+
+ virtual BOOL SetValueInt(HWND hToolbar, INT value) { return FALSE; }
+ virtual BOOL SetValueStr(HWND hToolbar, LPCWSTR value) { return FALSE; }
+
+ virtual INT GetCommandId() { return 0; }
+
+ virtual void UpdateSkin(HWND hToolbar) {}
+ virtual BOOL PtInItem(POINT pt);
+
+ virtual BOOL FillMenuInfo(HWND hToolbar, MENUITEMINFO *pmii, LPWSTR pszBuffer, INT cchBufferMax) { return FALSE; }
+ virtual BOOL KeyDown(HWND hToolbar, INT vKey, UINT flags) { return FALSE; }
+ virtual BOOL KeyUp(HWND hToolbar, INT vKey, UINT flags) { return FALSE; }
+ virtual void SetFocus(HWND hToolbar, ToolbarItem *focusItem, BOOL fSet) {}
+ virtual BOOL SetCursor(HWND hToolbar, HWND hCursor, UINT hitTest, UINT messageId) { return FALSE; }
+ virtual void CommandSent(HWND hToolbar, INT commandId) {}
+ virtual BOOL DisplayContextMenu(HWND hToolbar, INT x, INT y) { return FALSE; }
+
+protected:
+ ULONG ref;
+ LPSTR name;
+ UINT style;
+ RECT rect;
+ INT iconId;
+ LPWSTR text;
+ LPWSTR description;
+};
+
+#endif // NULLSOFT_WINAMP_OMBROWSER_TOOLBARITEM_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/toolbarProgress.cpp b/Src/omBrowser/toolbarProgress.cpp
new file mode 100644
index 00000000..3e544711
--- /dev/null
+++ b/Src/omBrowser/toolbarProgress.cpp
@@ -0,0 +1,197 @@
+#include "main.h"
+#include "./toolbarProgress.h"
+#include "./toolbar.h"
+#include "./graphics.h"
+#include "./resource.h"
+#include "../Plugins/General/gen_ml/ml_ipc_0313.h"
+#include "./ifc_imageloader.h"
+#include <strsafe.h>
+
+#define PROGRESS_FRAMECOUNT 9
+
+static ATOM TOOLBARPROGRESS_PROP = 0;
+#define TIMER_PROGRESSSTEP_ID 111
+#define TIMER_PROGRESSSTEP_INTERVAL 120
+
+
+ToolbarProgress::ToolbarProgress(LPCSTR pszName, UINT nStyle, LPCWSTR pszText, LPCWSTR pszDescription)
+ : ToolbarItem(pszName, nStyle, ICON_NONE, pszText, pszDescription),
+ bitmap(NULL), frame(0), hTimer(NULL)
+
+{
+}
+
+ToolbarProgress::~ToolbarProgress()
+{
+ if (NULL != hTimer)
+ Animate(hTimer, FALSE);
+
+ if (NULL != bitmap)
+ DeleteObject(bitmap);
+}
+
+static void CALLBACK ToolbarProgress_TimerElapsed(HWND hwnd, UINT uMsg, UINT_PTR eventId, DWORD dwTime)
+{
+ ToolbarProgress *item = (ToolbarProgress*)GetProp(hwnd, MAKEINTATOM(TOOLBARPROGRESS_PROP));
+ if (NULL == item || 0 != ((ToolbarItem::stateDisabled | ToolbarItem::stateHidden) & item->GetStyle()))
+ {
+ if (NULL != item)
+ item->Animate(hwnd, FALSE);
+ else
+ KillTimer(hwnd, TIMER_PROGRESSSTEP_ID);
+ return;
+ }
+ item->Animate(hwnd, TRUE);
+}
+
+
+ToolbarItem* CALLBACK ToolbarProgress::CreateInstance(ToolbarItem::Template *item)
+{
+ if (NULL == item)
+ return NULL;
+
+ return new ToolbarProgress( (NULL != item->name) ? item->name : TOOLCLS_PROGRESS,
+ item->style | styleNoChevron,
+ item->text,
+ item->description);
+}
+
+void ToolbarProgress::SetStyle(HWND hToolbar, UINT newStyle, UINT styleMask)
+{
+ __super::SetStyle(hToolbar, newStyle, styleMask);
+
+ if (0 == ((stateDisabled | stateHidden) & style))
+ {
+ Animate(hToolbar, TRUE);
+ }
+}
+
+BOOL ToolbarProgress::Animate(HWND hToolbar, BOOL fAnimate)
+{
+ if (FALSE == fAnimate)
+ {
+ if (NULL != hTimer)
+ {
+ RemoveProp(hTimer, MAKEINTATOM(TOOLBARPROGRESS_PROP));
+ KillTimer(hTimer, TIMER_PROGRESSSTEP_ID);
+ hTimer = NULL;
+ }
+
+ if (0 != frame)
+ {
+ frame = 0;
+ InvalidateRect(hToolbar, &rect, FALSE);
+ }
+
+
+ }
+ else
+ {
+ if (NULL == hTimer)
+ {
+ if (0 == TOOLBARPROGRESS_PROP)
+ {
+ TOOLBARPROGRESS_PROP = GlobalAddAtom(L"omToolbarProgressProp");
+ if (0 == TOOLBARPROGRESS_PROP) return FALSE;
+ }
+
+ if (!SetProp(hToolbar, MAKEINTATOM(TOOLBARPROGRESS_PROP), (HANDLE)this))
+ return FALSE;
+
+ if (!SetTimer(hToolbar, TIMER_PROGRESSSTEP_ID, TIMER_PROGRESSSTEP_INTERVAL,
+ ToolbarProgress_TimerElapsed))
+ {
+ RemoveProp(hToolbar, MAKEINTATOM(TOOLBARPROGRESS_PROP));
+ return FALSE;
+
+ }
+ hTimer = hToolbar;
+ }
+
+ if (++frame >= PROGRESS_FRAMECOUNT)
+ {
+ frame = 1;
+ }
+ InvalidateRect(hToolbar, &rect, FALSE);
+
+ }
+
+ return TRUE;
+}
+
+void ToolbarProgress::UpdateSkin(HWND hToolbar)
+{
+
+ if (NULL != bitmap)
+ {
+ DeleteObject(bitmap);
+ bitmap = NULL;
+ }
+
+ ifc_omimageloader *loader;
+
+ if (SUCCEEDED(Plugin_QueryImageLoader(Plugin_GetInstance(), MAKEINTRESOURCE(IDR_TOOLBARPROGRESS_IMAGE), TRUE, &loader)))
+ {
+ BITMAPINFOHEADER headerInfo;
+ BYTE *pixelData;
+ if (SUCCEEDED(loader->LoadBitmapEx(&bitmap, &headerInfo, (void**)&pixelData)))
+ {
+ if (headerInfo.biHeight < 0) headerInfo.biHeight = -headerInfo.biHeight;
+
+ Image_Colorize(pixelData, headerInfo.biWidth, headerInfo.biHeight, headerInfo.biBitCount,
+ Toolbar_GetBkColor(hToolbar), Toolbar_GetFgColor(hToolbar), TRUE);
+ }
+ loader->Release();
+ }
+
+}
+
+BOOL ToolbarProgress::AdjustRect(HWND hToolbar, RECT *proposedRect)
+{
+ BITMAP bm;
+ if (NULL == bitmap || sizeof(BITMAP) != GetObject(bitmap, sizeof(BITMAP), &bm))
+ return FALSE;
+
+ if (bm.bmHeight < 0) bm.bmHeight = -bm.bmHeight;
+ bm.bmHeight /= PROGRESS_FRAMECOUNT;
+ proposedRect->right = proposedRect->left + bm.bmWidth;
+ proposedRect->top += (((proposedRect->bottom - proposedRect->top) - bm.bmHeight)/2);
+ proposedRect->bottom = proposedRect->top + bm.bmHeight;
+
+ return TRUE;
+}
+
+BOOL ToolbarProgress::Paint(HWND hToolbar, HDC hdc, const RECT *paintRect, UINT state)
+{
+ BITMAP bm;
+ if (NULL == bitmap || sizeof(BITMAP) != GetObject(bitmap, sizeof(BITMAP), &bm))
+ return FALSE;
+
+ if (bm.bmHeight < 0) bm.bmHeight = -bm.bmHeight;
+ bm.bmHeight /= PROGRESS_FRAMECOUNT;
+
+ RECT blitRect;
+ if (!IntersectRect(&blitRect, paintRect))
+ return TRUE;
+
+ BOOL success = FALSE;
+ HDC hdcSrc = CreateCompatibleDC(hdc);
+
+ if (NULL != hdcSrc)
+ {
+ HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcSrc, bitmap);
+
+ success = BitBlt(hdc, blitRect.left, blitRect.top,
+ blitRect.right - blitRect.left, blitRect.bottom - blitRect.top,
+ hdcSrc,
+ blitRect.left - rect.left,
+ bm.bmHeight * frame + (blitRect.top - rect.top),
+ SRCCOPY);
+
+ SelectObject(hdcSrc, hbmpOld);
+ DeleteDC(hdcSrc);
+ }
+
+ return success;
+
+} \ No newline at end of file
diff --git a/Src/omBrowser/toolbarProgress.h b/Src/omBrowser/toolbarProgress.h
new file mode 100644
index 00000000..8e33da28
--- /dev/null
+++ b/Src/omBrowser/toolbarProgress.h
@@ -0,0 +1,34 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_PROGRESS_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_PROGRESS_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./toolbarItem.h"
+
+class ToolbarProgress : public ToolbarItem
+{
+protected:
+ ToolbarProgress(LPCSTR pszName, UINT nStyle, LPCWSTR pszText, LPCWSTR pszDescription);
+ ~ToolbarProgress();
+
+public:
+ static ToolbarItem* CALLBACK CreateInstance(ToolbarItem::Template *itemTemplate);
+
+public:
+ void SetStyle(HWND hToolbar, UINT newStyle, UINT styleMask);
+ BOOL AdjustRect(HWND hToolbar, RECT *proposedRect);
+ BOOL Paint(HWND hToolbar, HDC hdc, const RECT *paintRect, UINT state);
+ void UpdateSkin(HWND hToolbar);
+
+
+ BOOL Animate(HWND hToolbar, BOOL fAnimate);
+
+protected:
+ HBITMAP bitmap;
+ INT frame;
+ HWND hTimer;
+};
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_PROGRESS_HEADER
diff --git a/Src/omBrowser/toolbarRating.cpp b/Src/omBrowser/toolbarRating.cpp
new file mode 100644
index 00000000..df142ab4
--- /dev/null
+++ b/Src/omBrowser/toolbarRating.cpp
@@ -0,0 +1,461 @@
+#include "main.h"
+#include "./toolbarRating.h"
+#include "./toolbar.h"
+#include "./graphics.h"
+#include "./resource.h"
+#include "./ifc_skinhelper.h"
+#include "./ifc_skinnedrating.h"
+#include "./menu.h"
+#include "../Plugins/General/gen_ml/ml_ipc_0313.h"
+#include <strsafe.h>
+
+#define RATING_SPACECX_PX 4
+#define RATING_SPACECX_UNIT 2
+
+#define RATING_STARSTYLE (RDS_LEFT | RDS_TOP)
+
+ BYTE rating;
+ BYTE highlighted;
+ BYTE focused;
+ RECT ratingRect;
+ RECT textRect;
+ INT baseLine;
+ ifc_skinnedrating *skinnedRating;
+
+ToolbarRating::ToolbarRating(LPCSTR pszName, UINT nStyle, LPCWSTR pszText, LPCWSTR pszDescription) :
+ ToolbarItem(pszName, nStyle, ICON_NONE, pszText, pszDescription),
+ rating(0), highlighted(0), focused(0), baseLine(0), skinnedRating(NULL)
+{
+ ifc_skinhelper *skinHelper;
+ if (SUCCEEDED(Plugin_GetSkinHelper(&skinHelper)))
+ {
+ if (FAILED(skinHelper->QueryInterface(IFC_SkinnedRating, (void**)&skinnedRating)))
+ skinnedRating = NULL;
+
+ skinHelper->Release();
+ }
+}
+
+ToolbarRating::~ToolbarRating()
+{
+ if (NULL != skinnedRating)
+ skinnedRating->Release();
+}
+
+ToolbarItem* CALLBACK ToolbarRating::CreateInstance(ToolbarItem::Template *item)
+{
+ if (NULL == item)
+ return NULL;
+
+ return new ToolbarRating( (NULL != item->name) ? item->name : TOOLCLS_RATING,
+ item->style,
+ item->text,
+ item->description);
+
+}
+static BOOL ToolbarRating_GetTextSize(LPCWSTR pszText, HWND hToolbar, SIZE *textSize)
+{
+ BOOL result = FALSE;
+ WCHAR szText[64] = {0};
+
+ if (IS_INTRESOURCE(pszText))
+ {
+ Plugin_LoadString((INT)(INT_PTR)pszText, szText, ARRAYSIZE(szText));
+ pszText = szText;
+ }
+
+ INT cchText = (NULL != pszText) ? lstrlenW(pszText) : 0;
+
+ if (0 != cchText)
+ {
+ HDC hdc = GetDCEx(hToolbar, NULL, DCX_CACHE | DCX_NORESETATTRS);
+ if (NULL != hdc)
+ {
+ HFONT font = (HFONT)SendMessage(hToolbar, WM_GETFONT, 0, 0L);
+ HFONT originalFont = (HFONT)SelectObject(hdc, font);
+ result = GetTextExtentPoint32(hdc, pszText, cchText, textSize);
+ SelectObject(hdc, originalFont);
+ ReleaseDC(hToolbar, hdc);
+ }
+ }
+
+ return result;
+}
+
+BOOL ToolbarRating::AdjustRect(HWND hToolbar, RECT *proposedRect)
+{
+ TOOLBARTEXTMETRIC ttm;
+
+ if (NULL == skinnedRating || FAILED(skinnedRating->CalcMinRect(5, &ratingRect)))
+ ::SetRectEmpty(&ratingRect);
+
+ if (!Toolbar_GetTextMetrics(hToolbar, &ttm))
+ ZeroMemory(&ttm, sizeof(TOOLBARTEXTMETRIC));
+
+ ::SetRectEmpty(&textRect);
+ ToolbarRating_GetTextSize(text, hToolbar, ((SIZE*)&textRect) + 1);
+
+ INT spaceCX = MulDiv(RATING_SPACECX_UNIT, ttm.aveCharWidth, 4);
+
+ LONG cx = (ratingRect.right - ratingRect.left) + 2*spaceCX + (textRect.right - textRect.left) + 4;
+
+ ::OffsetRect(&textRect, spaceCX, ttm.origY - proposedRect->top);
+ baseLine = ttm.baseY;
+
+ ::OffsetRect(&ratingRect,
+ spaceCX + (textRect.right - textRect.left) + 4,
+ (ttm.origY - proposedRect->top) + baseLine - (ratingRect.bottom - ratingRect.top) + 1);
+
+ proposedRect->right = proposedRect->left + cx;
+ return TRUE;
+}
+
+
+BOOL ToolbarRating::Paint(HWND hToolbar, HDC hdc, const RECT *paintRect, UINT state)
+{
+ RECT cotrolRect;
+ CopyRect(&cotrolRect, &ratingRect);
+ ::OffsetRect(&cotrolRect, rect.left, rect.top);
+
+ INT trackingVal = (0 != (stateHighlighted & style)) ? highlighted : rating;
+
+ UINT fStyle = RATING_STARSTYLE | RDS_OPAQUE;
+ if (0 == rating || 0 != ((stateFocused | stateHighlighted) & state))
+ fStyle |= RDS_SHOWEMPTY;
+
+ if (0 == (stateDisabled & style))
+ fStyle |= RDS_HOT;
+
+ HRGN rgn = CreateRectRgnIndirect(&rect);
+ HRGN rgn2 = CreateRectRgnIndirect(&textRect);
+ OffsetRgn(rgn2, rect.left, rect.top);
+ CombineRgn(rgn, rgn, rgn2, RGN_DIFF);
+ SetRectRgn(rgn2, cotrolRect.left, cotrolRect.top, cotrolRect.right, cotrolRect.bottom);
+ CombineRgn(rgn, rgn, rgn2, RGN_DIFF);
+ HBRUSH hb = Toolbar_GetBkBrush(hToolbar);
+ FillRgn(hdc, rgn, hb);
+ DeleteObject(rgn);
+ DeleteObject(rgn2);
+
+ if (!::IsRectEmpty(&textRect))
+ {
+ WCHAR szText[64], *pszText(text);
+
+ if (IS_INTRESOURCE(pszText))
+ {
+ Plugin_LoadString((INT)(INT_PTR)pszText, szText, ARRAYSIZE(szText));
+ pszText = szText;
+ }
+
+ INT cchText = lstrlenW(pszText);
+ if (0 != cchText)
+ {
+ UINT originalAlign = SetTextAlign(hdc, TA_LEFT | TA_BASELINE);
+ RECT rc;
+ CopyRect(&rc, &textRect);
+ ::OffsetRect(&rc, rect.left, rect.top);
+ ExtTextOut(hdc, rc.left, rc.top + baseLine, ETO_OPAQUE, &rc, pszText, cchText, NULL);
+
+ if ((TA_LEFT | TA_BASELINE) != originalAlign) SetTextAlign(hdc, originalAlign);
+ }
+ }
+
+ if (NULL == skinnedRating || FAILED(skinnedRating->Draw(hdc, 5, rating, trackingVal, &cotrolRect, fStyle)))
+ {
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &cotrolRect, NULL, 0, NULL);
+ }
+ else
+ {
+ if (stateFocused == ((stateFocused | stateNoFocusRect) & state) && focused > 0 && focused < 6)
+ {
+ RECT focusRect;
+ CopyRect(&focusRect, &cotrolRect);
+ INT starWidth = (cotrolRect.right - cotrolRect.left)/5;
+
+ focusRect.left += starWidth * (focused - 1);
+ focusRect.right = focusRect.left + starWidth;
+ InflateRect(&focusRect, 1, 1);
+
+ COLORREF origBk = SetBkColor(hdc, 0x00000000);
+ COLORREF origFg = SetTextColor(hdc, 0x00FFFFFF);
+ DrawFocusRect(hdc, &focusRect);
+ if (origBk != 0x00000000) SetBkColor(hdc, origBk);
+ if (origFg != 0x00FFFFFF) SetTextColor(hdc, origFg);
+ }
+ }
+
+ return TRUE;
+}
+
+void ToolbarRating::MouseMove(HWND hToolbar, UINT mouseFlags, POINT pt)
+{
+ BYTE tracking = 0;
+ UINT state = 0;
+ if (PtInItem(pt))
+ {
+ state = stateHighlighted;
+
+ RECT controlRect;
+ CopyRect(&controlRect, &ratingRect);
+ ::OffsetRect(&controlRect, rect.left, rect.top);
+
+ POINT ptTest = pt;
+ ptTest.y = controlRect.top;
+
+ LONG result;
+ if (NULL == skinnedRating || FAILED(skinnedRating->HitTest(pt, 5, &controlRect, RATING_STARSTYLE, &result)))
+ result = 0;
+
+ UINT hitTest = HIWORD(result);
+ if (0 != ((RHT_ONVALUE | RHT_ONVALUEABOVE | RHT_ONVALUEBELOW) & hitTest))
+ tracking = (BYTE)LOWORD(result);
+ }
+
+ BOOL invalidate = FALSE;
+
+ if (tracking != highlighted)
+ {
+ highlighted = tracking;
+ invalidate = TRUE;
+ }
+
+ if ((stateHighlighted & style) != (stateHighlighted & state))
+ {
+ style |= ((style & ~stateHighlighted) | state);
+ invalidate = TRUE;
+ }
+
+ if (FALSE != invalidate)
+ {
+ RECT invalidRect;
+ CopyRect(&invalidRect, &ratingRect);
+ ::OffsetRect(&invalidRect, rect.left, rect.top);
+ InvalidateRect(hToolbar, &invalidRect, FALSE);
+ Toolbar_UpdateTip(hToolbar);
+ }
+}
+
+void ToolbarRating::MouseLeave(HWND hToolbar)
+{
+ BOOL invalidate = FALSE;
+ if (highlighted != 0)
+ {
+ highlighted = 0;
+ invalidate = TRUE;
+ }
+
+ if (0 != (stateHighlighted & style))
+ {
+ style &= ~stateHighlighted;
+ invalidate = TRUE;
+ }
+
+ if (FALSE != invalidate)
+ {
+ RECT invalidRect;
+ CopyRect(&invalidRect, &ratingRect);
+ ::OffsetRect(&invalidRect, rect.left, rect.top);
+ InvalidateRect(hToolbar, &invalidRect, FALSE);
+ }
+}
+void ToolbarRating::LButtonDown(HWND hToolbar, UINT mouseFlags, POINT pt)
+{
+ style |= statePressed;
+}
+void ToolbarRating::LButtonUp(HWND hToolbar, UINT mouseFlags, POINT pt)
+{
+ style &= ~statePressed;
+}
+
+void ToolbarRating::Click(HWND hToolbar, UINT mouseFlags, POINT pt)
+{
+ if (0 == (ToolbarItem::statePressed & style))
+ return;
+
+ RECT controlRect;
+ CopyRect(&controlRect, &ratingRect);
+ ::OffsetRect(&controlRect, rect.left, rect.top);
+
+ POINT ptTest = pt;
+ ptTest.y = controlRect.top;
+
+ LONG result;
+ if (NULL == skinnedRating || FAILED(skinnedRating->HitTest(pt, 5, &controlRect, RATING_STARSTYLE, &result)))
+ result = 0;
+
+ if (0 != ((RHT_ONVALUE | RHT_ONVALUEABOVE | RHT_ONVALUEBELOW) & HIWORD(result)) && LOWORD(result) > 0)
+ {
+ SendRating(hToolbar, LOWORD(result));
+ }
+}
+
+void ToolbarRating::SendRating(HWND hToolbar, INT ratingValue)
+{
+ INT commandId = 0;
+ switch(ratingValue)
+ {
+ case 1: commandId = ID_RATING_VALUE_1; break;
+ case 2: commandId = ID_RATING_VALUE_2; break;
+ case 3: commandId = ID_RATING_VALUE_3; break;
+ case 4: commandId = ID_RATING_VALUE_4; break;
+ case 5: commandId = ID_RATING_VALUE_5; break;
+ }
+ if (0 != commandId)
+ Toolbar_SendCommand(hToolbar, commandId);
+
+}
+void ToolbarRating::UpdateSkin(HWND hToolbar)
+{
+
+}
+
+BOOL ToolbarRating::PtInItem(POINT pt)
+{
+ return (pt.x >= (rect.left + textRect.left) && pt.x < (rect.left + ratingRect.right) && rect.bottom != rect.top);
+}
+
+BOOL ToolbarRating::SetValueInt(HWND hToolbar, INT value)
+{
+ if (value < 0) value = 0;
+ if (value > 5) value = 5;
+ if (rating != value)
+ {
+ rating = value;
+
+ RECT invalidRect;
+ CopyRect(&invalidRect, &ratingRect);
+ ::OffsetRect(&invalidRect, rect.left, rect.top);
+ InvalidateRect(hToolbar, &invalidRect, FALSE);
+
+ }
+ return TRUE;
+}
+
+static LPCWSTR ToolbarRating_FormatRating(INT ratingValue, LPWSTR pszBuffer, INT cchBufferMax)
+{
+ INT stringId;
+ switch(ratingValue)
+ {
+ case 5: stringId = IDS_RATING_5; break;
+ case 4: stringId = IDS_RATING_4; break;
+ case 3: stringId = IDS_RATING_3; break;
+ case 2: stringId = IDS_RATING_2; break;
+ case 1: stringId = IDS_RATING_1; break;
+ default: stringId = IDS_RATING_0; break;
+ }
+
+ Plugin_LoadString(stringId, pszBuffer, cchBufferMax);
+ return pszBuffer;
+}
+
+INT ToolbarRating::GetTip(LPTSTR pszBuffer, INT cchBufferMax)
+{
+ WCHAR szText[64] = {0}, szRated[32] = {0};
+ size_t remaining = 0;
+ LPWSTR cursor;
+
+ Plugin_LoadString(IDS_RATING_CURRENT, szText, ARRAYSIZE(szText));
+ ToolbarRating_FormatRating(rating, szRated, ARRAYSIZE(szRated));
+
+ HRESULT hr = StringCchPrintfEx(pszBuffer, cchBufferMax, &cursor, &remaining, STRSAFE_IGNORE_NULLS, TEXT("%s %s "), szText, szRated);
+ if (FAILED(hr)) return 0;
+
+ if (NULL != highlighted)
+ {
+ Plugin_LoadString(IDS_RATING_CHANGETO, szText, ARRAYSIZE(szText));
+ ToolbarRating_FormatRating(highlighted, szRated, ARRAYSIZE(szRated));
+ hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_IGNORE_NULLS, TEXT("\r\n%s %s "), szText, szRated);
+ if (FAILED(hr)) return 0;
+ }
+
+ return cchBufferMax - (INT)remaining;
+
+}
+
+BOOL ToolbarRating::FillMenuInfo(HWND hToolbar, MENUITEMINFO *pmii, LPWSTR pszBuffer, INT cchBufferMax)
+{
+ pmii->fMask = MIIM_STRING | MIIM_ID | MIIM_STATE | MIIM_SUBMENU;
+ pmii->wID = 0;
+ pmii->fState = MFS_ENABLED;
+ pmii->dwTypeData = pszBuffer;
+ pmii->hSubMenu = Menu_GetMenu(MENU_RATING, RATINGTOMCF(rating));
+
+ if (IS_INTRESOURCE(text))
+ {
+ Plugin_LoadString((INT)(INT_PTR)text, pszBuffer, cchBufferMax);
+ }
+ else
+ {
+ if (FAILED(StringCchCopyEx(pszBuffer, cchBufferMax, text, NULL, NULL, STRSAFE_IGNORE_NULLS)))
+ pszBuffer[0] = L'\0';
+ }
+ return TRUE;
+}
+
+void ToolbarRating::SetFocus(HWND hToolbar, ToolbarItem *focusItem, BOOL fSet)
+{
+
+ if (FALSE != fSet)
+ {
+ focused = 1;
+ if (NULL != focusItem)
+ {
+ INT mineIndex = Toolbar_FindItem(hToolbar, name);
+ INT otherIndex = Toolbar_FindItem(hToolbar, focusItem->GetName());
+ if (ITEM_ERR != mineIndex &&
+ ITEM_ERR != otherIndex &&
+ otherIndex > mineIndex)
+ {
+ focused = 5;
+ }
+ }
+ }
+ else
+ {
+ focused = 0;
+ }
+ InvalidateRect(hToolbar, &rect, FALSE);
+}
+
+BOOL ToolbarRating::KeyDown(HWND hToolbar, INT vKey, UINT flags)
+{
+ switch(vKey)
+ {
+ case VK_LEFT:
+ if (focused > 1)
+ {
+ focused--;
+ InvalidateRect(hToolbar, &rect, FALSE);
+ return TRUE;
+ }
+ break;
+ case VK_RIGHT:
+ if (focused < 5)
+ {
+ focused++;
+ InvalidateRect(hToolbar, &rect, FALSE);
+ return TRUE;
+ }
+ break;
+ case VK_SPACE:
+ case VK_RETURN:
+ SetStyle(hToolbar, statePressed, statePressed);
+ return TRUE;
+ }
+ return FALSE;
+}
+BOOL ToolbarRating::KeyUp(HWND hToolbar, INT vKey, UINT flags)
+{
+ switch(vKey)
+ {
+ case VK_SPACE:
+ case VK_RETURN:
+ if (0 != (statePressed & style) && 0 != focused)
+ {
+ SetStyle(hToolbar, 0, statePressed);
+ SendRating(hToolbar, focused);
+ }
+ return TRUE;
+ }
+ return FALSE;
+} \ No newline at end of file
diff --git a/Src/omBrowser/toolbarRating.h b/Src/omBrowser/toolbarRating.h
new file mode 100644
index 00000000..53383dad
--- /dev/null
+++ b/Src/omBrowser/toolbarRating.h
@@ -0,0 +1,55 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_RATING_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_RATING_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./toolbarItem.h"
+
+class ifc_skinnedrating;
+
+class ToolbarRating : public ToolbarItem
+{
+protected:
+ ToolbarRating(LPCSTR pszName, UINT nStyle, LPCWSTR pszText, LPCWSTR pszDescription);
+ ~ToolbarRating();
+
+public:
+ static ToolbarItem* CALLBACK CreateInstance(ToolbarItem::Template *itemTemplate);
+
+public:
+ BOOL AdjustRect(HWND hToolbar, RECT *proposedRect);
+ BOOL Paint(HWND hToolbar, HDC hdc, const RECT *paintRect, UINT state);
+
+ void MouseMove(HWND hToolbar, UINT mouseFlags, POINT pt);
+ void MouseLeave(HWND hToolbar);
+ void LButtonDown(HWND hToolbar, UINT mouseFlags, POINT pt);
+ void LButtonUp(HWND hToolbar, UINT mouseFlags, POINT pt);
+ void Click(HWND hToolbar, UINT mouseFlags, POINT pt);
+ void UpdateSkin(HWND hToolbar);
+ BOOL PtInItem(POINT pt);
+
+ INT GetTip(LPTSTR pszBuffer, INT cchBufferMax);
+ BOOL FillMenuInfo(HWND hToolbar, MENUITEMINFO *pmii, LPWSTR pszBuffer, INT cchBufferMax);
+
+ BOOL SetValueInt(HWND hToolbar, INT value);
+
+ void SetFocus(HWND hToolbar, ToolbarItem *focusItem, BOOL fSet);
+ BOOL KeyDown(HWND hToolbar, INT vKey, UINT flags);
+ BOOL KeyUp(HWND hToolbar, INT vKey, UINT flags);
+
+protected:
+ void SendRating(HWND hToolbar, INT ratingValue);
+
+protected:
+ BYTE rating;
+ BYTE highlighted;
+ BYTE focused;
+ RECT ratingRect;
+ RECT textRect;
+ INT baseLine;
+ ifc_skinnedrating *skinnedRating;
+};
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_RATING_HEADER
diff --git a/Src/omBrowser/toolbarStatic.cpp b/Src/omBrowser/toolbarStatic.cpp
new file mode 100644
index 00000000..71835868
--- /dev/null
+++ b/Src/omBrowser/toolbarStatic.cpp
@@ -0,0 +1,115 @@
+#include "main.h"
+#include "./toolbarStatic.h"
+#include "./toolbar.h"
+#include <strsafe.h>
+
+#define SPACER_WIDTH_UNITS 6
+#define SPACER_WIDTH_PX 8
+
+ToolbarStatic::ToolbarStatic(LPCSTR pszName, UINT nStyle, INT nIcon, LPCWSTR pszText, LPCWSTR pszDescription) :
+ ToolbarItem(pszName, nStyle, nIcon, pszText, pszDescription), spaceWidth(SPACER_WIDTH_PX)
+{
+
+}
+
+ToolbarItem* CALLBACK ToolbarStatic::CreateInstance(ToolbarItem::Template *item)
+{
+ if (NULL == item)
+ return NULL;
+
+ return new ToolbarStatic( (NULL != item->name) ? item->name : TOOLCLS_STATIC,
+ (item->style | styleStatic),
+ item->iconId,
+ item->text,
+ item->description);
+}
+
+BOOL ToolbarStatic::AdjustRect(HWND hToolbar, RECT *proposedRect)
+{
+ if (0 != (styleSpacer & style))
+ {
+ if (0 == (styleFlexible & style) ||
+ (proposedRect->right - proposedRect->left) < spaceWidth)
+ {
+ proposedRect->right = proposedRect->left + spaceWidth;
+ }
+ return TRUE;
+ }
+
+ if (0 != (styleSeparator & style))
+ {
+ SIZE iconSize;
+ if (!Toolbar_GetIconSize(hToolbar, iconId, &iconSize))
+ ZeroMemory(&iconSize, sizeof(SIZE));
+
+ if (0 == (styleFlexible & style) ||
+ (proposedRect->right - proposedRect->left) < iconSize.cx)
+ {
+ proposedRect->right = proposedRect->left + iconSize.cx;
+ }
+
+ proposedRect->top += ((proposedRect->bottom - proposedRect->top) - iconSize.cy)/2;
+ proposedRect->bottom = proposedRect->top + iconSize.cy;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOL ToolbarStatic::Paint(HWND hToolbar, HDC hdc, const RECT *paintRect, UINT state)
+{
+ if (0 != (styleSpacer & style))
+ return FALSE;
+
+
+ if (0 != (styleSeparator & style))
+ {
+ TOOLBARDRAWICONPARAM param;
+ param.hdcDst = hdc;
+ param.iconIndex = iconId;
+ param.x = rect.left;
+ param.y = rect.top;
+ param.cx = rect.right - rect.left;
+ param.cy = rect.bottom - rect.top;
+ param.itemState = state;
+ return Toolbar_DrawIcon(hToolbar, &param);
+ }
+
+ return FALSE;
+}
+
+INT ToolbarStatic::GetTip(LPTSTR pszBuffer, INT cchBufferMax)
+{
+ return 0;
+}
+
+void ToolbarStatic::UpdateSkin(HWND hToolbar)
+{
+ spaceWidth = SPACER_WIDTH_PX;
+ HDC hdc = GetDCEx(hToolbar, NULL, DCX_CACHE | DCX_NORESETATTRS);
+ if (NULL != hdc)
+ {
+ HFONT font = (HFONT)SendMessage(hToolbar, WM_GETFONT, 0, 0L);
+ HFONT originalFont = (HFONT)SelectObject(hdc, font);
+
+ TEXTMETRIC tm;
+ if (GetTextMetrics(hdc, &tm))
+ {
+ spaceWidth = MulDiv(SPACER_WIDTH_UNITS, tm.tmAveCharWidth, 4);
+ }
+
+ SelectObject(hdc, originalFont);
+ ReleaseDC(hToolbar, hdc);
+ }
+}
+
+BOOL ToolbarStatic::FillMenuInfo(HWND hToolbar, MENUITEMINFO *pmii, LPWSTR pszBuffer, INT cchBufferMax)
+{
+ if (0 != ((styleSpacer | styleSeparator) & style))
+ {
+ pmii->fMask = MIIM_FTYPE;
+ pmii->fType = MFT_MENUBREAK;
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/Src/omBrowser/toolbarStatic.h b/Src/omBrowser/toolbarStatic.h
new file mode 100644
index 00000000..e9d86a7a
--- /dev/null
+++ b/Src/omBrowser/toolbarStatic.h
@@ -0,0 +1,39 @@
+#ifndef NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_STATIC_HEADER
+#define NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_STATIC_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./toolbarItem.h"
+
+class ToolbarStatic : public ToolbarItem
+{
+public:
+ typedef enum
+ {
+ styleLabel = 0x00000000,
+ styleSpacer = 0x00010000,
+ styleSeparator = 0x00020000,
+
+ } staticStyles;
+
+protected:
+ ToolbarStatic(LPCSTR pszName, UINT nStyle, INT nIcon, LPCWSTR pszText, LPCWSTR pszDescription);
+ ~ToolbarStatic() {}
+
+public:
+ static ToolbarItem* CALLBACK CreateInstance(ToolbarItem::Template *itemTemplate);
+
+public:
+ BOOL AdjustRect(HWND hToolbar, RECT *proposedRect);
+ BOOL Paint(HWND hToolbar, HDC hdc, const RECT *paintRect, UINT state);
+ INT GetTip(LPTSTR pszBuffer, INT cchBufferMax);
+ void UpdateSkin(HWND hToolbar);
+ BOOL FillMenuInfo(HWND hToolbar, MENUITEMINFO *pmii, LPWSTR pszBuffer, INT cchBufferMax);
+
+protected:
+ INT spaceWidth;
+};
+
+#endif //NULLSOFT_WINAMP_OMBROWSER_TOOLBAR_STATIC_HEADER
diff --git a/Src/omBrowser/travelLogHelper.cpp b/Src/omBrowser/travelLogHelper.cpp
new file mode 100644
index 00000000..bbbbbf48
--- /dev/null
+++ b/Src/omBrowser/travelLogHelper.cpp
@@ -0,0 +1,331 @@
+#include "main.h"
+#include "./travelLogHelper.h"
+#include "./graphics.h"
+#include "./resource.h"
+#include "./ifc_skinhelper.h"
+#include "./ifc_imageloader.h"
+#include "./menu.h"
+#include "../Plugins/General/gen_ml/ml_ipc_0313.h"
+
+#include <exdisp.h>
+#include <tlogstg.h>
+
+#define TRAVELLOGPOPUP_MAXCHARWIDTH 42
+
+TravelLogHelper::TravelLogHelper(IWebBrowser2 *pWeb)
+ : ref(1), pWeb2(pWeb), bitmap(NULL), pixelData(NULL), firstFwd(FALSE), entriesCount(0), backEntry(-1)
+{
+ if (NULL != pWeb2)
+ pWeb2->AddRef();
+}
+
+TravelLogHelper::~TravelLogHelper()
+{
+ if (NULL != pWeb2)
+ pWeb2->Release();
+
+ if (NULL != bitmap)
+ DeleteObject(bitmap);
+}
+
+HRESULT TravelLogHelper::CreateInstance(IWebBrowser2 *pWeb2, TravelLogHelper **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ *instance = NULL;
+
+ if (NULL == pWeb2)
+ return E_INVALIDARG;
+
+ *instance = new TravelLogHelper(pWeb2);
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t TravelLogHelper::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t TravelLogHelper::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int TravelLogHelper::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_TravelLogHelper))
+ *object = static_cast<ifc_travelloghelper*>(this);
+ else if (IsEqualIID(interface_guid, IFC_MenuCustomizer))
+ *object = static_cast<ifc_menucustomizer*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT TravelLogHelper::QueryStorage(ITravelLogStg **ppLog)
+{
+ HRESULT hr;
+
+ if (NULL == ppLog)
+ return E_POINTER;
+
+ *ppLog = NULL;
+
+ if (NULL == pWeb2) return E_UNEXPECTED;
+
+ IServiceProvider *pProvider;
+ hr = pWeb2->QueryInterface(IID_IServiceProvider, (void**)&pProvider);
+ if (SUCCEEDED(hr))
+ {
+ hr = pProvider->QueryService(SID_STravelLogCursor, ppLog);
+ pProvider->Release();
+ }
+ return hr;
+}
+
+BOOL TravelLogHelper::DrawIcon(HMENU menuInstance, HDC hdc, DRAWITEMSTRUCT *pdis)
+{
+ if (0 == (ODS_SELECTED & pdis->itemState))
+ return FALSE;
+
+ LONG entry = pdis->itemID - 101;
+ if (entry < 0 || ((ULONG)entry) > entriesCount)
+ return FALSE;
+
+ BOOL fForward = (FALSE != firstFwd) ? TRUE : FALSE;
+ if (-1 != backEntry && entry >= backEntry)
+ fForward = !fForward;
+
+ if (NULL == bitmap)
+ {
+ ifc_omimageloader *imageLoader;
+ if (SUCCEEDED(Plugin_QueryImageLoader(Plugin_GetInstance(), MAKEINTRESOURCE(IDR_MENUARROW_IMAGE), FALSE, &imageLoader)))
+ {
+ if (SUCCEEDED(imageLoader->LoadBitmapEx(&bitmap, &header, &pixelData)))
+ {
+ if (header.biHeight < 0) header.biHeight = -header.biHeight;
+
+ Image_Colorize((BYTE*)pixelData, header.biWidth, header.biHeight,
+ header.biBitCount, GetBkColor(hdc), GetTextColor(hdc), TRUE);
+ }
+ imageLoader->Release();
+ }
+ }
+
+ BOOL resultOk = FALSE;
+ if (NULL != bitmap)
+ {
+ INT cx = header.biWidth/2;
+ INT cy = header.biHeight;
+ if (cy < 0) cy = -cy;
+
+ INT side = (pdis->rcItem.bottom - pdis->rcItem.top - 2);
+ if (cy < side) side = cy;
+
+ INT top = pdis->rcItem.top + ((pdis->rcItem.bottom - pdis->rcItem.top) - side)/2;
+ INT left = pdis->rcItem.left + (GetSystemMetrics(SM_CXMENUCHECK) - side)/2 + 3;
+
+ resultOk = StretchDIBits(hdc, left, top, side, side,
+ ((FALSE != fForward) ? cx : 0), 0, cx, cy, pixelData, (BITMAPINFO*)&header, DIB_RGB_COLORS, SRCCOPY);
+
+ }
+ return resultOk;
+}
+
+INT TravelLogHelper::CustomDraw(HMENU menuInstance, INT action, HDC hdc, LPARAM param)
+{
+ switch(action)
+ {
+ case MLMENU_ACTION_DRAWITEM:
+ return MLMENU_WANT_DRAWPART;
+ case MLMENU_ACTION_DRAWICON:
+ return DrawIcon(menuInstance, hdc, (DRAWITEMSTRUCT*)param);
+ }
+ return FALSE;
+}
+
+
+HRESULT TravelLogHelper::ShowPopup(UINT fuFlags, INT x, INT y, HWND hwnd, LPTPMPARAMS lptpm)
+{
+ HRESULT hr;
+ ITravelLogStg *pLog;
+ hr = QueryStorage(&pLog);
+ if (FAILED(hr) || NULL == pLog) return hr;
+
+ DWORD entriesMax;
+ if (FAILED(pLog->GetCount(TLEF_RELATIVE_FORE | TLEF_RELATIVE_BACK, &entriesMax)))
+ entriesMax = 0;
+
+ ITravelLogEntry **entries = NULL;
+
+ INT selectedEntry = -1;
+ firstFwd = (0 == (TPM_BOTTOMALIGN & fuFlags));
+ entriesCount = 0;
+ backEntry = -1;
+
+ if (0 != entriesMax)
+ {
+ entries = (ITravelLogEntry**)calloc(entriesMax, sizeof(ITravelLogEntry*));
+ if (NULL != entries)
+ {
+ IEnumTravelLogEntry *pEnum = NULL;
+ TLENUMF tlenum = (0 != (TPM_BOTTOMALIGN & fuFlags)) ? TLEF_RELATIVE_BACK : TLEF_RELATIVE_FORE;
+ if (SUCCEEDED(pLog->EnumEntries(tlenum, &pEnum)))
+ {
+ ULONG fetched;
+ pEnum->Reset();
+ pEnum->Next(entriesMax - entriesCount, &entries[entriesCount], &fetched);
+ if (0 != fetched)
+ {
+ ITravelLogEntry *t, **l, **r;
+ for (l = &entries[entriesCount], r = &entries[entriesCount + fetched - 1]; l < r; l++, r--)
+ {
+ t = *l;
+ *l = *r;
+ *r = t;
+ }
+ entriesCount += fetched;
+ }
+ pEnum->Release();
+ }
+
+ tlenum = (0 != (TLEF_RELATIVE_FORE & tlenum)) ?
+ ((tlenum & ~TLEF_RELATIVE_FORE) | TLEF_RELATIVE_BACK) :
+ tlenum = ((tlenum & ~TLEF_RELATIVE_BACK) | TLEF_RELATIVE_FORE);
+
+ if (SUCCEEDED(pLog->EnumEntries(tlenum, &pEnum)))
+ {
+
+ ULONG fetched;
+ pEnum->Reset();
+ pEnum->Next(entriesMax - entriesCount, &entries[entriesCount], &fetched);
+ if (0 != fetched)
+ {
+ backEntry = entriesCount;
+ entriesCount += fetched;
+ }
+ pEnum->Release();
+ }
+ }
+
+ if (entriesCount > 0)
+ {
+ HMENU hMenu = CreatePopupMenu();
+ if (NULL != hMenu)
+ {
+ MENUITEMINFOW mii = {0};
+ mii.cbSize = sizeof(MENUITEMINFOW);
+ mii.fMask = MIIM_STRING | MIIM_ID | MIIM_STATE;
+ mii.fState = MFS_ENABLED | MFS_UNCHECKED;
+
+ for (ULONG i = 0; i < entriesCount; i++)
+ {
+ if (NULL != entries[i])
+ {
+ LPWSTR pszTitle;
+ if (SUCCEEDED(entries[i]->GetTitle(&pszTitle)) && NULL != pszTitle)
+ {
+ INT cchTitle = lstrlen(pszTitle);
+
+ if (cchTitle > TRAVELLOGPOPUP_MAXCHARWIDTH)
+ {
+ pszTitle[TRAVELLOGPOPUP_MAXCHARWIDTH] = L'\0';
+ for (INT k = 0; k < 3; k++)
+ pszTitle[TRAVELLOGPOPUP_MAXCHARWIDTH - 1 - k] = L'.';
+
+ }
+ mii.dwTypeData = pszTitle;
+ mii.wID = 101 + i;
+ InsertMenuItem(hMenu, i, TRUE, &mii);
+ CoTaskMemFree(pszTitle);
+ }
+ }
+ }
+
+
+ { // insert current page
+ WCHAR szBuffer[256] = {0};
+
+ Plugin_LoadString(IDS_CURRENT_PAGE, szBuffer, ARRAYSIZE(szBuffer));
+
+ mii.dwTypeData = szBuffer;
+ mii.fMask = MIIM_STRING | MIIM_ID | MIIM_STATE | MIIM_FTYPE;
+ mii.fState = MFS_ENABLED | MFS_DEFAULT | MFS_CHECKED;
+ mii.fType = MFT_STRING | MFT_RADIOCHECK;
+ mii.wID = 100;
+
+ if (-1 == backEntry)
+ InsertMenuItem(hMenu, GetMenuItemCount(hMenu), TRUE, &mii);
+ else
+ InsertMenuItem(hMenu, 101 + backEntry, FALSE, &mii);
+ }
+
+
+
+ HANDLE hHook = Menu_InitializeHook(hwnd, this);
+
+ UINT commandId = TrackPopupMenuEx(hMenu, fuFlags | TPM_RETURNCMD, x, y, hwnd, lptpm);
+
+ if (NULL != hHook) Menu_RemoveHook(hHook);
+
+ if (commandId > 100 && commandId <= (100 + entriesCount))
+ selectedEntry = commandId - 101;
+
+ DestroyMenu(hMenu);
+ }
+ }
+
+ }
+
+ if (-1 != selectedEntry && NULL != entries[selectedEntry])
+ {
+ pLog->TravelTo(entries[selectedEntry]);
+ }
+
+ if (NULL != entries)
+ {
+ for (ULONG i = 0; i < entriesCount; i++)
+ {
+ if (NULL != entries[i]) entries[i]->Release();
+ }
+ free(entries);
+
+ }
+ pLog->Release();
+ return hr;
+}
+
+#define CBCLASS TravelLogHelper
+START_MULTIPATCH;
+ START_PATCH(MPIID_TRAVELLOGHELPER)
+ M_CB(MPIID_TRAVELLOGHELPER, ifc_travelloghelper, ADDREF, AddRef);
+ M_CB(MPIID_TRAVELLOGHELPER, ifc_travelloghelper, RELEASE, Release);
+ M_CB(MPIID_TRAVELLOGHELPER, ifc_travelloghelper, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_TRAVELLOGHELPER, ifc_travelloghelper, API_QUERYSTORAGE, QueryStorage);
+ M_CB(MPIID_TRAVELLOGHELPER, ifc_travelloghelper, API_SHOWPOPUP, ShowPopup);
+ NEXT_PATCH(MPIID_MENUCUSTOMIZER)
+ M_CB(MPIID_MENUCUSTOMIZER, ifc_menucustomizer, ADDREF, AddRef);
+ M_CB(MPIID_MENUCUSTOMIZER, ifc_menucustomizer, RELEASE, Release);
+ M_CB(MPIID_MENUCUSTOMIZER, ifc_menucustomizer, QUERYINTERFACE, QueryInterface);
+ M_CB(MPIID_MENUCUSTOMIZER, ifc_menucustomizer, API_CUSTOMDRAW, CustomDraw);
+ END_PATCH
+END_MULTIPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/travelLogHelper.h b/Src/omBrowser/travelLogHelper.h
new file mode 100644
index 00000000..316a2a9e
--- /dev/null
+++ b/Src/omBrowser/travelLogHelper.h
@@ -0,0 +1,62 @@
+#ifndef NULLSOFT_WINAMP_TRAVELLOG_HELPER_HEADER
+#define NULLSOFT_WINAMP_TRAVELLOG_HELPER_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+#include "./browserInternal.h"
+#include "./ifc_menucustomizer.h"
+#include "./ifc_travelloghelper.h"
+#include "./obj_ombrowser.h"
+#include <bfc/multipatch.h>
+
+interface IWebBrowser2;
+
+#define MPIID_TRAVELLOGHELPER 10
+#define MPIID_MENUCUSTOMIZER 20
+
+
+class TravelLogHelper : public MultiPatch<MPIID_TRAVELLOGHELPER, ifc_travelloghelper>,
+ public MultiPatch<MPIID_MENUCUSTOMIZER, ifc_menucustomizer>
+
+{
+protected:
+ TravelLogHelper(IWebBrowser2 *pWeb2);
+ ~TravelLogHelper();
+
+public:
+ static HRESULT CreateInstance(IWebBrowser2 *pWeb2, TravelLogHelper **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_travelloghelper */
+ HRESULT QueryStorage(ITravelLogStg **ppLog);
+ HRESULT ShowPopup(UINT fuFlags, INT x, INT y, HWND hwnd, LPTPMPARAMS lptpm);
+
+ /* ifc_menucustomizer */
+ INT CustomDraw(HMENU menuInstance, INT action, HDC hdc, LPARAM param);
+
+protected:
+ BOOL DrawIcon(HMENU menuInstance, HDC hdc, DRAWITEMSTRUCT *pdis);
+
+protected:
+ RECVS_MULTIPATCH;;
+
+protected:
+ ULONG ref;
+ IWebBrowser2 *pWeb2;
+ HBITMAP bitmap;
+ BITMAPINFOHEADER header;
+ void *pixelData;
+ BOOL firstFwd;
+ ULONG entriesCount;
+ LONG backEntry;
+};
+
+#endif //NULLSOFT_WINAMP_TRAVELLOG_HELPER_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/utility.cpp b/Src/omBrowser/utility.cpp
new file mode 100644
index 00000000..bb3b0319
--- /dev/null
+++ b/Src/omBrowser/utility.cpp
@@ -0,0 +1,343 @@
+#include "main.h"
+#include "./utility.h"
+#include "./cacheManager.h"
+#include "./mlNavigationHelper.h"
+#include "./graphicsObject.h"
+#include "./storageHelper.h"
+#include "./wasabiHelper.h"
+
+#define LISTENER_CLASS L"Nullsoft_OmBrowserListener"
+#define LWM_FIRST (WM_USER + 11)
+#define LWM_INVOKECALLBACK (LWM_FIRST + 0)
+
+#define ICBP_TYPE_DISPPARAM2 0x0001
+
+struct INVOKECALLBACKPARAM
+{
+ INVOKECALLBACKPARAM() : type(0), callback(NULL) {}
+
+ UINT type;
+ void *callback;
+};
+
+struct ICBP_DISPPARAM2
+{
+ ICBP_DISPPARAM2() : object(NULL), param1(0), param2(0) {}
+
+ INVOKECALLBACKPARAM header;
+ Dispatchable *object;
+ ULONG_PTR param1;
+ ULONG_PTR param2;
+};
+
+static void CALLBACK InvokeCallback_MarshallingApc(ULONG_PTR data)
+{
+ INVOKECALLBACKPARAM *icbp = (INVOKECALLBACKPARAM*)data;
+ if (NULL == icbp) return;
+
+ switch(icbp->type)
+ {
+ case ICBP_TYPE_DISPPARAM2:
+ if (NULL != icbp->callback)
+ {
+ ICBP_DISPPARAM2 *p = (ICBP_DISPPARAM2*)icbp;
+ ((ifc_omutility::ThreadCallback2)icbp->callback)(p->object, p->param1, p->param2);
+ if (NULL != p->object) p->object->Release();
+ }
+ break;
+ }
+
+ free(icbp);
+}
+
+static LRESULT WINAPI Listener_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case LWM_INVOKECALLBACK:
+ if (NULL != lParam)
+ ((ifc_omutility::ThreadCallback)lParam)((ULONG_PTR)wParam);
+ return TRUE;
+ }
+
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
+}
+
+OmUtility::OmUtility()
+ : ref(1), cacheManager(NULL), navigationHelper(NULL), graphicsObject(NULL),
+ storageHelper(NULL), hListener(NULL)
+{
+ WNDCLASS listenerClass = {0};
+ if (0 == GetClassInfo(Plugin_GetInstance(), LISTENER_CLASS, &listenerClass))
+ {
+ ZeroMemory(&listenerClass, sizeof(listenerClass));
+ listenerClass.hInstance = Plugin_GetInstance();
+ listenerClass.lpfnWndProc = Listener_WindowProc;
+ listenerClass.lpszClassName =LISTENER_CLASS;
+ listenerClass.style = 0;
+ RegisterClassW(&listenerClass);
+ }
+
+ hListener = CreateWindow(LISTENER_CLASS, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, Plugin_GetInstance(), NULL);
+}
+
+OmUtility::~OmUtility()
+{
+ if (NULL != navigationHelper)
+ navigationHelper->Release();
+
+ if (NULL != cacheManager)
+ cacheManager->Release();
+
+ if (NULL != graphicsObject)
+ graphicsObject->Release();
+
+ if (NULL != hListener)
+ DestroyWindow(hListener);
+
+ if (NULL != storageHelper)
+ storageHelper->Release();
+}
+
+OmUtility *OmUtility::CreateInstance()
+{
+ return new OmUtility();
+}
+
+size_t OmUtility::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t OmUtility::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int OmUtility::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_OmUtility))
+ *object = static_cast<ifc_omutility*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT OmUtility::EnsurePathExist(LPCWSTR pszDirectory)
+{
+ return Plugin_EnsurePathExist(pszDirectory);
+}
+
+HRESULT OmUtility::MakeResourcePath(LPWSTR pszBuffer, UINT cchBufferMax, HINSTANCE hInstance, LPCWSTR pszType, LPCWSTR pszName, UINT uFlags)
+{
+ return Plugin_MakeResourcePath(pszBuffer, cchBufferMax, hInstance, pszType, pszName, uFlags);
+}
+
+HRESULT OmUtility::GetCacheManager(ifc_omcachemanager **managerOut)
+{
+ if (NULL == managerOut)
+ return E_POINTER;
+
+ if (NULL == cacheManager)
+ {
+ HRESULT hr = CacheManager::CreateInstance(&cacheManager);
+ if (FAILED(hr))
+ {
+ *managerOut = NULL;
+ return hr;
+ }
+ }
+
+ cacheManager->AddRef();
+ *managerOut = cacheManager;
+ return S_OK;
+}
+
+HRESULT OmUtility::GetMlNavigationHelper(HWND hLibrary, ifc_mlnavigationhelper **helper)
+{
+ if (NULL == helper)
+ return E_POINTER;
+
+ if (NULL == hLibrary)
+ {
+ *helper = NULL;
+ return E_INVALIDARG;
+ }
+
+ if (NULL == navigationHelper)
+ {
+ HRESULT hr;
+ ifc_omcachemanager *cache = NULL;
+
+ if (FAILED(GetCacheManager(&cache)))
+ {
+ hr = E_FAIL;
+ cache = NULL;
+ }
+ else
+ {
+ hr = MlNavigationHelper::CreateInstance(hLibrary, cache, &navigationHelper);
+ }
+
+ if (NULL != cache)
+ cache->Release();
+
+ if (FAILED(hr))
+ {
+ *helper = NULL;
+ return hr;
+ }
+ }
+ else
+ {
+ if (hLibrary != navigationHelper->GetLibrary())
+ return E_UNEXPECTED;
+ }
+
+ navigationHelper->AddRef();
+ *helper = navigationHelper;
+ return S_OK;
+}
+
+HRESULT OmUtility::QueryImageLoader(HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply, ifc_omimageloader **imageLoader)
+{
+ return Plugin_QueryImageLoader(hInstance, pszName, fPremultiply, imageLoader);
+}
+
+HRESULT OmUtility::GetGraphics(ifc_omgraphics **graphics)
+{
+ if (NULL == graphics)
+ return E_POINTER;
+
+ if (NULL == graphicsObject)
+ {
+ HRESULT hr = GraphicsObject::CreateInstance(&graphicsObject);
+ if (FAILED(hr)) return hr;
+ }
+
+ graphicsObject->AddRef();
+ *graphics = graphicsObject;
+ return S_OK;
+}
+
+HRESULT OmUtility::PostMainThreadCallback(ThreadCallback callback, ULONG_PTR data)
+{
+ if (NULL == callback)
+ return E_INVALIDARG;
+
+ if (NULL != hListener &&
+ FALSE != PostMessage(hListener, LWM_INVOKECALLBACK, (WPARAM)data, (LPARAM)callback))
+ {
+ return S_OK;
+ }
+
+ ifc_wasabihelper *wasabi = NULL;
+ HRESULT hr = Plugin_GetWasabiHelper(&wasabi);
+ if (SUCCEEDED(hr) && wasabi != NULL)
+ {
+ api_application *application = NULL;
+ hr = wasabi->GetApplicationApi(&application);
+ if (SUCCEEDED(hr) && application != NULL)
+ {
+ HANDLE hThread = application->main_getMainThreadHandle();
+ if (NULL == hThread)
+ hr = E_FAIL;
+ else
+ {
+ DWORD r = QueueUserAPC((PAPCFUNC)callback, hThread, data);
+ if (0 == r)
+ {
+ r = GetLastError();
+ hr = HRESULT_FROM_WIN32(r);
+ }
+ }
+ application->Release();
+ }
+ wasabi->Release();
+ }
+ return hr;
+}
+
+HRESULT OmUtility::PostMainThreadCallback2(ThreadCallback2 callback, Dispatchable *object, ULONG_PTR param1, ULONG_PTR param2)
+{
+ if (NULL == callback || NULL == object)
+ return E_INVALIDARG;
+
+ ICBP_DISPPARAM2 *data = (ICBP_DISPPARAM2*)calloc(1, sizeof(ICBP_DISPPARAM2));
+ if (NULL == data) return E_OUTOFMEMORY;
+
+ data->header.type = ICBP_TYPE_DISPPARAM2;
+ data->header.callback = callback;
+ data->object = object;
+ if (NULL != data->object)
+ data->object->AddRef();
+
+ data->param1 = param1;
+ data->param2 = param2;
+
+ HRESULT hr = PostMainThreadCallback(InvokeCallback_MarshallingApc, (ULONG_PTR)data);
+ if (FAILED(hr))
+ {
+ if (NULL != data->object)
+ data->object->Release();
+
+ free(data);
+ }
+
+ return hr;
+}
+
+HRESULT OmUtility::GetStorageHelper(ifc_omstoragehelper **helper)
+{
+ if (NULL == helper)
+ return E_POINTER;
+
+ if (NULL == storageHelper)
+ {
+ HRESULT hr = StorageHelper::CreateInstance(&storageHelper);
+ if (FAILED(hr))
+ {
+ *helper = NULL;
+ return hr;
+ }
+ }
+
+ *helper = storageHelper;
+ storageHelper->AddRef();
+
+ return S_OK;
+}
+
+#define CBCLASS OmUtility
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_ENSUREPATHEXIST, EnsurePathExist)
+CB(API_MAKERESPATH, MakeResourcePath)
+CB(API_GETCACHEMANAGER, GetCacheManager)
+CB(API_GETMLNAVIGATIONHELPER, GetMlNavigationHelper)
+CB(API_QUERYIMAGELOADER, QueryImageLoader)
+CB(API_GETGRAPHICS, GetGraphics)
+CB(API_POSTMAINTHREADCALLBACK, PostMainThreadCallback)
+CB(API_POSTMAINTHREADCALLBACK2, PostMainThreadCallback2)
+CB(API_GETSTORAGEHELPER, GetStorageHelper)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/utility.h b/Src/omBrowser/utility.h
new file mode 100644
index 00000000..a66f825b
--- /dev/null
+++ b/Src/omBrowser/utility.h
@@ -0,0 +1,53 @@
+#ifndef NULLSOFT_WINAMP_OMUTILITY_HEADER
+#define NULLSOFT_WINAMP_OMUTILITY_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_omutility.h"
+
+class CacheManager;
+class MlNavigationHelper;
+class GraphicsObject;
+class StorageHelper;
+
+class OmUtility : public ifc_omutility
+{
+protected:
+ OmUtility();
+ ~OmUtility();
+
+public:
+ static OmUtility *CreateInstance();
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_omutility */
+ HRESULT EnsurePathExist(LPCWSTR pszDirectory);
+ HRESULT MakeResourcePath(LPWSTR pszBuffer, UINT cchBufferMax, HINSTANCE hInstance, LPCWSTR pszType, LPCWSTR pszName, UINT uFlags);
+ HRESULT GetCacheManager(ifc_omcachemanager **cacheManager);
+ HRESULT GetMlNavigationHelper(HWND hLibrary, ifc_mlnavigationhelper **helper);
+ HRESULT QueryImageLoader(HINSTANCE hInstance, LPCWSTR pszName, BOOL fPremultiply, ifc_omimageloader **imageLoader);
+ HRESULT GetGraphics(ifc_omgraphics **graphics);
+ HRESULT PostMainThreadCallback(ThreadCallback callback, ULONG_PTR param);
+ HRESULT PostMainThreadCallback2(ThreadCallback2 callback, Dispatchable *object, ULONG_PTR param1, ULONG_PTR param2);
+ HRESULT GetStorageHelper(ifc_omstoragehelper **helper);
+
+protected:
+ RECVS_DISPATCH;
+
+protected:
+ ULONG ref;
+ CacheManager *cacheManager;
+ MlNavigationHelper *navigationHelper;
+ GraphicsObject *graphicsObject;
+ StorageHelper *storageHelper;
+ HWND hListener;
+};
+
+#endif //NULLSOFT_WINAMP_OMUTILITY_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/utilityFactory.cpp b/Src/omBrowser/utilityFactory.cpp
new file mode 100644
index 00000000..2fa5b33e
--- /dev/null
+++ b/Src/omBrowser/utilityFactory.cpp
@@ -0,0 +1,91 @@
+#include "main.h"
+#include "./utilityFactory.h"
+#include "./utility.h"
+
+OmUtilityFactory::OmUtilityFactory()
+ : object(NULL)
+{
+}
+
+OmUtilityFactory::~OmUtilityFactory()
+{
+ if (NULL != object)
+ object->Release();
+}
+
+FOURCC OmUtilityFactory::GetServiceType()
+{
+ return WaSvc::UNIQUE;
+}
+
+const char *OmUtilityFactory::GetServiceName()
+{
+ return "OmUtility Interface";
+}
+
+GUID OmUtilityFactory::GetGUID()
+{
+ return IFC_OmUtility;
+}
+
+void *OmUtilityFactory::GetInterface(int global_lock)
+{
+ if (NULL == object)
+ {
+ object = OmUtility::CreateInstance();
+ if (NULL == object) return NULL;
+ }
+
+ object->AddRef();
+ return object;
+}
+
+int OmUtilityFactory::SupportNonLockingInterface()
+{
+ return 1;
+}
+
+int OmUtilityFactory::ReleaseInterface(void *ifc)
+{
+ OmUtility *object = (OmUtility*)ifc;
+ if (NULL != object) object->Release();
+
+ return 1;
+}
+
+const char *OmUtilityFactory::GetTestString()
+{
+ return NULL;
+}
+
+int OmUtilityFactory::ServiceNotify(int msg, int param1, int param2)
+{
+ return 1;
+}
+
+HRESULT OmUtilityFactory::Register(api_service *service)
+{
+ if (NULL == service) return E_INVALIDARG;
+ service->service_register(this);
+ return S_OK;
+}
+
+HRESULT OmUtilityFactory::Unregister(api_service *service)
+{
+ if (NULL == service) return E_INVALIDARG;
+ service->service_deregister(this);
+ return S_OK;
+}
+
+#define CBCLASS OmUtilityFactory
+START_DISPATCH;
+CB(WASERVICEFACTORY_GETSERVICETYPE, GetServiceType)
+CB(WASERVICEFACTORY_GETSERVICENAME, GetServiceName)
+CB(WASERVICEFACTORY_GETGUID, GetGUID)
+CB(WASERVICEFACTORY_GETINTERFACE, GetInterface)
+CB(WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface)
+CB(WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface)
+CB(WASERVICEFACTORY_GETTESTSTRING, GetTestString)
+CB(WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/utilityFactory.h b/Src/omBrowser/utilityFactory.h
new file mode 100644
index 00000000..73c8aad4
--- /dev/null
+++ b/Src/omBrowser/utilityFactory.h
@@ -0,0 +1,39 @@
+#ifndef NULLSOFT_WINAMP_UTILITY_FACTORY_HEADER
+#define NULLSOFT_WINAMP_UTILITY_FACTORY_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <api/service/waservicefactory.h>
+#include <api/service/services.h>
+
+class OmUtility;
+
+class OmUtilityFactory : public waServiceFactory
+{
+public:
+ OmUtilityFactory();
+ ~OmUtilityFactory();
+
+public:
+ FOURCC GetServiceType();
+ const char *GetServiceName();
+ GUID GetGUID();
+ void *GetInterface(int global_lock);
+ int SupportNonLockingInterface();
+ int ReleaseInterface(void *ifc);
+ const char *GetTestString();
+ int ServiceNotify(int msg, int param1, int param2);
+public:
+ HRESULT Register(api_service *service);
+ HRESULT Unregister(api_service *service);
+
+protected:
+ RECVS_DISPATCH;
+
+protected:
+ OmUtility *object;
+};
+
+#endif //NULLSOFT_WINAMP_UTILITY_FACTORY_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/version.rc2 b/Src/omBrowser/version.rc2
new file mode 100644
index 00000000..e516d2e5
--- /dev/null
+++ b/Src/omBrowser/version.rc2
@@ -0,0 +1,39 @@
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+#include "../Winamp/buildType.h"
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION WINAMP_PRODUCTVER
+ PRODUCTVERSION WINAMP_PRODUCTVER
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Winamp SA"
+ VALUE "FileDescription", "Winamp 5.x System Component"
+ VALUE "FileVersion", STR_WINAMP_PRODUCTVER
+ VALUE "InternalName", "ombrowser.w5s"
+ VALUE "LegalCopyright", "Copyright © 2007-2023 Winamp SA"
+ VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
+ VALUE "OriginalFilename", "ombrowser.w5s"
+ VALUE "ProductName", "Winamp Browser Service"
+ VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/Src/omBrowser/wasabiHelper.cpp b/Src/omBrowser/wasabiHelper.cpp
new file mode 100644
index 00000000..39112f2e
--- /dev/null
+++ b/Src/omBrowser/wasabiHelper.cpp
@@ -0,0 +1,252 @@
+#include "main.h"
+#include "./wasabiHelper.h"
+#include <api/service/waservicefactory.h>
+
+EXTERN_C const GUID pngLoaderGUID =
+{ 0x5e04fb28, 0x53f5, 0x4032, { 0xbd, 0x29, 0x3, 0x2b, 0x87, 0xec, 0x37, 0x25 } };
+
+WasabiHelper::WasabiHelper(api_service *serviceManager)
+ : ref(1), serviceManager(NULL), applicationApi(NULL), configApi(NULL), memoryApi(NULL),
+ pngLoader(NULL), languageManager(NULL), securityApi(NULL), threadpoolApi(NULL), languageModule(NULL)
+{
+ this->serviceManager = serviceManager;
+}
+
+WasabiHelper::~WasabiHelper()
+{
+ ReleaseWasabiInterface(&applicationApiServiceGuid, applicationApi);
+ ReleaseWasabiInterface(&AgaveConfigGUID, configApi);
+ ReleaseWasabiInterface(&languageApiGUID, languageManager);
+ ReleaseWasabiInterface(&pngLoaderGUID, pngLoader);
+ ReleaseWasabiInterface(&memMgrApiServiceGuid, memoryApi);
+ ReleaseWasabiInterface(&JSAPI2::api_securityGUID, securityApi);
+ ReleaseWasabiInterface(&ThreadPoolGUID, threadpoolApi);
+}
+
+HRESULT WasabiHelper::CreateInstance(api_service *serviceManager, WasabiHelper **instance)
+{
+ if (NULL == instance) return E_POINTER;
+ if (NULL == serviceManager) return E_INVALIDARG;
+
+ *instance = new WasabiHelper(serviceManager);
+ if (*instance == NULL) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t WasabiHelper::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t WasabiHelper::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int WasabiHelper::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object) return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_WasabiHelper))
+ *object = static_cast<ifc_wasabihelper*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT WasabiHelper::QueryWasabiInterface(const GUID *iid, void **ppi)
+{
+ if (NULL == ppi) return E_POINTER;
+ *ppi = NULL;
+
+ if (NULL == iid) return E_INVALIDARG;
+
+ if (NULL == serviceManager) return E_UNEXPECTED;
+ waServiceFactory *serviceFactory = serviceManager->service_getServiceByGuid(*iid);
+ if (NULL == serviceFactory) return E_NOINTERFACE;
+
+ *ppi = serviceFactory->getInterface();
+ if (NULL == *ppi) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+HRESULT WasabiHelper::ReleaseWasabiInterface(const GUID *iid, void *pi)
+{
+ if (NULL == iid || NULL == pi) return E_INVALIDARG;
+
+ if (NULL == serviceManager) return E_UNEXPECTED;
+ waServiceFactory *serviceFactory = serviceManager->service_getServiceByGuid(*iid);
+ if (NULL == serviceFactory) return E_NOINTERFACE;
+
+ serviceFactory->releaseInterface(pi);
+ return S_OK;
+}
+
+HRESULT WasabiHelper::GetServiceManager(api_service **manager)
+{
+ if (NULL == manager) return E_POINTER;
+ *manager = serviceManager;
+
+ if (NULL == *manager) return E_UNEXPECTED;
+ (*manager)->AddRef();
+
+ return S_OK;
+}
+
+HRESULT WasabiHelper::GetApplicationApi(api_application **application)
+{
+ if (NULL == application) return E_POINTER;
+ HRESULT hr = (NULL == applicationApi)? QueryWasabiInterface(&applicationApiServiceGuid, (void**)&applicationApi) : S_OK;
+
+ *application = applicationApi;
+ if (NULL != applicationApi)
+ applicationApi->AddRef();
+
+ return hr;
+}
+
+HRESULT WasabiHelper::GetConfigApi(api_config ** config)
+{
+ if (NULL == config) return E_POINTER;
+ HRESULT hr = (NULL == configApi)? QueryWasabiInterface(&AgaveConfigGUID, (void**)&configApi) : S_OK;
+
+ *config = configApi;
+ if (NULL != configApi)
+ configApi->AddRef();
+
+ return hr;
+}
+
+HRESULT WasabiHelper::GetMemoryManager(api_memmgr **memoryManager)
+{
+ if (NULL == memoryManager) return E_POINTER;
+ HRESULT hr = (NULL == memoryApi)? QueryWasabiInterface(&memMgrApiServiceGuid, (void**)&memoryApi) : S_OK;
+
+ *memoryManager = memoryApi;
+ if (NULL != memoryApi)
+ memoryApi->AddRef();
+
+ return hr;
+}
+
+HRESULT WasabiHelper::GetPngLoader(svc_imageLoader **loader)
+{
+ if (NULL == loader) return E_POINTER;
+ HRESULT hr = (NULL == pngLoader)? QueryWasabiInterface(&pngLoaderGUID, (void**)&pngLoader) : S_OK;
+
+ *loader = pngLoader;
+ if (NULL != pngLoader)
+ pngLoader->AddRef();
+
+ return hr;
+}
+
+HRESULT WasabiHelper::InitLanguageSupport()
+{
+ if (NULL != languageManager && NULL != languageModule)
+ return S_FALSE;
+
+ if(NULL == languageManager)
+ {
+ languageModule = NULL;
+ HRESULT hr = QueryWasabiInterface(&languageApiGUID, (void**)&languageManager);
+ if (FAILED(hr))
+ return hr;
+ }
+
+ if (NULL == languageModule)
+ {
+ languageModule = languageManager->StartLanguageSupport(Plugin_GetInstance(), omBrowserLangGUID);
+ if (NULL == languageModule)
+ {
+ languageManager->Release();
+ languageManager = NULL;
+ return E_FAIL;
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT WasabiHelper::GetLanguageManager(api_language **language)
+{
+ if (NULL == language) return E_POINTER;
+
+ HRESULT hr = InitLanguageSupport();
+ if (FAILED(hr)) return hr;
+
+ *language = (SUCCEEDED(hr)) ? languageManager : NULL;
+ if (NULL != *language)
+ (*language)->AddRef();
+
+ return hr;
+}
+
+HRESULT WasabiHelper::GetLanguageModule(HINSTANCE *module)
+{
+ if (NULL == module) return E_POINTER;
+
+ HRESULT hr = InitLanguageSupport();
+ if (FAILED(hr)) return hr;
+
+ *module = languageModule;
+ return S_OK;
+}
+
+HRESULT WasabiHelper::GetSecurityApi(JSAPI2::api_security **security)
+{
+ if (NULL == security) return E_POINTER;
+ HRESULT hr = (NULL == securityApi)? QueryWasabiInterface(&JSAPI2::api_securityGUID, (void**)&securityApi) : S_OK;
+
+ *security = securityApi;
+ if (NULL != securityApi)
+ securityApi->AddRef();
+ return hr;
+}
+
+HRESULT WasabiHelper::GetThreadpoolApi(api_threadpool **threadpool)
+{
+ if (NULL == threadpool) return E_POINTER;
+ HRESULT hr = (NULL == threadpoolApi)? QueryWasabiInterface(&ThreadPoolGUID, (void**)&threadpoolApi) : S_OK;
+
+ *threadpool = threadpoolApi;
+ if (NULL != *threadpool)
+ threadpoolApi->AddRef();
+ return hr;
+}
+
+#define CBCLASS WasabiHelper
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_QUERYWASABIINTERFACE, QueryWasabiInterface)
+CB(API_RELEASEWASABIINTERFACE, ReleaseWasabiInterface)
+CB(API_GETSERVICEMANAGER, GetServiceManager)
+CB(API_GETAPPLICATION, GetApplicationApi)
+CB(API_GETCONFIG, GetConfigApi)
+CB(API_GETMEMORYMANAGER, GetMemoryManager)
+CB(API_GETPNGLOADER, GetPngLoader)
+CB(API_GETLANGUAGEMANAGER, GetLanguageManager)
+CB(API_GETLANGUAGEMODULE, GetLanguageModule)
+CB(API_GETSECURITY, GetSecurityApi)
+CB(API_GETTHREADPOOL, GetThreadpoolApi)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/wasabiHelper.h b/Src/omBrowser/wasabiHelper.h
new file mode 100644
index 00000000..bee55246
--- /dev/null
+++ b/Src/omBrowser/wasabiHelper.h
@@ -0,0 +1,57 @@
+#ifndef NULLSOFT_WINAMP_WASABI_HELPER_HEADER
+#define NULLSOFT_WINAMP_WASABI_HELPER_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include "./ifc_wasabihelper.h"
+
+class WasabiHelper : public ifc_wasabihelper
+{
+protected:
+ WasabiHelper(api_service *serviceManager);
+ ~WasabiHelper();
+
+public:
+ static HRESULT CreateInstance(api_service *serviceManager, WasabiHelper **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_wasabihelper */
+ HRESULT QueryWasabiInterface(const GUID *iid, void **ppi);
+ HRESULT ReleaseWasabiInterface(const GUID *iid, void *pi);
+ HRESULT GetServiceManager(api_service **serviceManager);
+ HRESULT GetApplicationApi(api_application **application);
+ HRESULT GetConfigApi(api_config ** config);
+ HRESULT GetMemoryManager(api_memmgr **memoryManager);
+ HRESULT GetPngLoader(svc_imageLoader **loader);
+ HRESULT GetLanguageManager(api_language **languageManager);
+ HRESULT GetLanguageModule(HINSTANCE *module);
+ HRESULT GetSecurityApi(JSAPI2::api_security **security);
+ HRESULT GetThreadpoolApi(api_threadpool **threadpool);
+
+protected:
+ HRESULT InitLanguageSupport();
+
+protected:
+ RECVS_DISPATCH;
+
+protected:
+ ULONG ref;
+ api_service *serviceManager;
+ api_application *applicationApi;
+ api_config *configApi;
+ api_memmgr *memoryApi;
+ svc_imageLoader *pngLoader;
+ api_language *languageManager;
+ JSAPI2::api_security *securityApi;
+ api_threadpool *threadpoolApi;
+ HINSTANCE languageModule;
+};
+
+#endif //NULLSOFT_WINAMP_WASABI_HELPER_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/winampHook.cpp b/Src/omBrowser/winampHook.cpp
new file mode 100644
index 00000000..ba4604be
--- /dev/null
+++ b/Src/omBrowser/winampHook.cpp
@@ -0,0 +1,288 @@
+#include "main.h"
+#include "./winampHook.h"
+#include "./ifc_winamphook.h"
+#include "../winamp/wa_ipc.h"
+
+#include <windows.h>
+
+#define WINAMP_REFRESHSKIN 40291
+#define WHPROCRECOVERY L"WaHookProcRecovery"
+
+static ATOM WAWNDATOM = 0;
+#define GetWinampHook(__hwnd) ((WinampHook*)GetProp((__hwnd), MAKEINTATOM(WAWNDATOM)))
+
+WinampHook::WinampHook(HWND hwndWinamp)
+ : ref(1), hwnd(hwndWinamp), originalProc(NULL), flags(0), lastCookie(0)
+{
+}
+
+WinampHook::~WinampHook()
+{
+ DetachFromWinamp();
+
+ if (0 != WAWNDATOM)
+ {
+ GlobalDeleteAtom(WAWNDATOM);
+ WAWNDATOM = 0;
+ }
+}
+
+HRESULT WinampHook::CreateInstance(HWND hwndWinamp, WinampHook **instance)
+{
+ if (NULL == instance) return E_POINTER;
+
+ *instance = NULL;
+
+ if (NULL == hwndWinamp || FALSE == IsWindow(hwndWinamp))
+ return E_INVALIDARG;
+
+ *instance = new WinampHook(hwndWinamp);
+ if (NULL == *instance) return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+ULONG WinampHook::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+ULONG WinampHook::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+HRESULT WinampHook::RegisterCallback(ifc_winamphook *callback, UINT *cookie)
+{
+ if (NULL == cookie) return E_POINTER;
+ *cookie = 0;
+
+ if (NULL == callback) return E_INVALIDARG;
+
+ if (FAILED(AttachToWinamp()))
+ return E_UNEXPECTED;
+
+ *cookie = ++lastCookie;
+
+ callbackMap.insert({ *cookie, callback });
+ callback->AddRef();
+
+ return S_OK;
+}
+
+HRESULT WinampHook::UnregisterCallback(UINT cookie)
+{
+ if (0 == cookie) return E_INVALIDARG;
+
+ for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
+ {
+ if (cookie == iter->first)
+ {
+ ifc_winamphook *hook = iter->second;
+ callbackMap.erase(iter);
+
+ if (NULL != hook)
+ hook->Release();
+
+ return S_OK;
+ }
+ }
+ return S_FALSE;
+}
+
+HWND WinampHook::GetWinamp()
+{
+ return hwnd;
+}
+
+LRESULT WinampHook::CallPrevWinampProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ if (NULL == originalProc || NULL == hwnd) return 0;
+ return (0 != (flagUnicode & flags)) ?
+ CallWindowProcW(originalProc, hwnd, uMsg, wParam, lParam) :
+ CallWindowProcA(originalProc, hwnd, uMsg, wParam, lParam);
+}
+
+LRESULT WinampHook::CallDefWinampProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ if (NULL == hwnd) return 0;
+ return (0 != (flagUnicode & flags)) ?
+ DefWindowProcW(hwnd, uMsg, wParam, lParam) :
+ DefWindowProcA(hwnd, uMsg, wParam, lParam);
+}
+
+HRESULT WinampHook::AttachToWinamp()
+{
+ if (NULL == hwnd || !IsWindow(hwnd)) return E_UNEXPECTED;
+
+ if (0 == WAWNDATOM)
+ {
+ WAWNDATOM = GlobalAddAtom(L"WinampHook");
+ if (0 == WAWNDATOM) return E_FAIL;
+ }
+
+ WinampHook *hookInstance = GetWinampHook(hwnd);
+ if (this == hookInstance) return S_FALSE;
+
+ if (NULL != hookInstance || NULL != originalProc)
+ return E_FAIL;
+
+ flags = 0;
+ if (IsWindowUnicode(hwnd)) flags |= flagUnicode;
+
+ originalProc = (WNDPROC)(LONG_PTR)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)WinampWindowProc);
+ if (NULL == originalProc || FALSE == SetProp(hwnd, MAKEINTATOM(WAWNDATOM), this))
+ {
+ if (NULL != originalProc)
+ SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)originalProc);
+ return E_FAIL;
+ }
+
+ return S_OK;
+}
+
+HRESULT WinampHook::DetachFromWinamp()
+{
+ if (NULL == hwnd || !IsWindow(hwnd)) return E_UNEXPECTED;
+ if (0 == WAWNDATOM) return E_FAIL;
+
+ for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
+ {
+ if (NULL != iter->second)
+ iter->second->Release();
+ }
+ callbackMap.clear();
+
+ WinampHook *hookInstance = GetWinampHook(hwnd);
+ if (this != hookInstance) return E_FAIL;
+
+ RemoveProp(hwnd, MAKEINTATOM(WAWNDATOM));
+ WNDPROC currentProc = (WNDPROC)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_WNDPROC);
+ if (currentProc == WinampWindowProc)
+ {
+ SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)originalProc);
+ }
+ else
+ {
+ SetProp(hwnd, WHPROCRECOVERY, (HANDLE)originalProc);
+ }
+ originalProc = NULL;
+ flags = 0;
+ return S_OK;
+}
+
+LRESULT WinampHook::OnWinampDestroy()
+{
+ WNDPROC proc = originalProc;
+ DetachFromWinamp();
+ return (IsWindowUnicode(hwnd)) ?
+ CallWindowProcW(proc, hwnd, WM_DESTROY, 0, 0L) :
+ CallWindowProcA(proc, hwnd, WM_DESTROY, 0, 0L);
+}
+
+LRESULT WinampHook::OnWinampIPC(UINT commandId, WPARAM param)
+{
+ switch(commandId)
+ {
+ case IPC_CB_RESETFONT:
+ for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
+ if (NULL != iter->second) iter->second->ResetFont();
+ break;
+
+ case IPC_HOOK_OKTOQUIT:
+ for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
+ if (NULL != iter->second && S_FALSE == iter->second->IsQuitAllowed()) return 0;
+ break;
+
+ case IPC_SKIN_CHANGED:
+ {
+ WCHAR szBuffer[MAX_PATH*2] = {0};
+ SENDWAIPC(hwnd, IPC_GETSKINW, szBuffer);
+ for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
+ if (NULL != iter->second) iter->second->SkinChanged(szBuffer);
+ }
+ break;
+
+ case IPC_FF_ONCOLORTHEMECHANGED:
+ if (FALSE != IS_INTRESOURCE(param))
+ param = 0L;
+ for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
+ if (NULL != iter->second) iter->second->SkinColorChange((LPCWSTR)param);
+ break;
+
+ case IPC_FILE_TAG_MAY_HAVE_UPDATED:
+ {
+ WCHAR szBuffer[MAX_PATH*2] = {0};
+ param = (0 != MultiByteToWideChar(CP_ACP, 0, (char*)param, -1, szBuffer, ARRAYSIZE(szBuffer))) ?
+ (WPARAM)szBuffer : 0L;
+
+ for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
+ if (NULL != iter->second) iter->second->FileMetaChange((LPCWSTR)param);
+ }
+ break;
+
+ case IPC_FILE_TAG_MAY_HAVE_UPDATEDW:
+ for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
+ if (NULL != iter->second) iter->second->FileMetaChange((LPCWSTR)param);
+ break;
+ }
+
+ return CallPrevWinampProc(WM_WA_IPC, param, (LPARAM)commandId);
+}
+
+void WinampHook::OnWinampCommand(UINT commandId, UINT controlId, HWND hControl)
+{
+ switch(commandId)
+ {
+ case WINAMP_REFRESHSKIN:
+ for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
+ if (NULL != iter->second) iter->second->SkinChanging();
+ break;
+ }
+}
+
+void WinampHook::OnSysColorChange()
+{
+ for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
+ if (NULL != iter->second) iter->second->SysColorChange();
+}
+
+LRESULT WinampHook::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_DESTROY: return OnWinampDestroy();
+ case WM_WA_IPC: return OnWinampIPC((UINT)lParam, wParam);
+ case WM_COMMAND: OnWinampCommand(LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break;
+ case WM_SYSCOLORCHANGE: OnSysColorChange(); break;
+ }
+ return CallPrevWinampProc(uMsg, wParam, lParam);
+}
+
+static LRESULT CALLBACK WinampWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ WinampHook *hookInstance = GetWinampHook(hwnd);
+ if (NULL == hookInstance)
+ {
+ WNDPROC recovery = (WNDPROC)GetProp(hwnd, WHPROCRECOVERY);
+ if (NULL != recovery)
+ {
+ return (IsWindowUnicode(hwnd)) ?
+ CallWindowProcW(recovery, hwnd, uMsg, wParam, lParam) :
+ CallWindowProcA(recovery, hwnd, uMsg, wParam, lParam);
+ }
+
+ return (IsWindowUnicode(hwnd)) ?
+ DefWindowProcW(hwnd, uMsg, wParam, lParam) :
+ DefWindowProcA(hwnd, uMsg, wParam, lParam);
+ }
+
+ return hookInstance->WindowProc(uMsg, wParam, lParam);
+} \ No newline at end of file
diff --git a/Src/omBrowser/winampHook.h b/Src/omBrowser/winampHook.h
new file mode 100644
index 00000000..c382ef64
--- /dev/null
+++ b/Src/omBrowser/winampHook.h
@@ -0,0 +1,62 @@
+#ifndef NULLSOFT_WINAMP_HOOK_HEADER
+#define NULLSOFT_WINAMP_HOOK_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+#include <map>
+
+class ifc_winamphook;
+
+class WinampHook
+{
+protected:
+ WinampHook(HWND hwndWinamp);
+ ~WinampHook();
+
+public:
+ static HRESULT CreateInstance(HWND hwndWinamp, WinampHook **instance);
+
+public:
+ ULONG AddRef();
+ ULONG Release();
+
+ HRESULT RegisterCallback(ifc_winamphook *callback, UINT *cookie);
+ HRESULT UnregisterCallback(UINT cookie);
+
+ HWND GetWinamp();
+ LRESULT CallPrevWinampProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
+ LRESULT CallDefWinampProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+protected:
+ HRESULT AttachToWinamp();
+ HRESULT DetachFromWinamp();
+ LRESULT WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+ LRESULT OnWinampDestroy();
+ LRESULT OnWinampIPC(UINT commandId, WPARAM param);
+ void OnWinampCommand(UINT commandId, UINT controlId, HWND hControl);
+ void OnSysColorChange();
+
+protected:
+ typedef enum
+ {
+ flagUnicode = 0x00000001,
+ } Flags;
+
+ typedef std::map<UINT, ifc_winamphook*> CallbackMap;
+
+ friend static LRESULT CALLBACK WinampWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+protected:
+ ULONG ref;
+ HWND hwnd;
+ WNDPROC originalProc;
+ UINT flags;
+ UINT lastCookie;
+ CallbackMap callbackMap;
+};
+
+#endif //NULLSOFT_WINAMP_HOOK_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/xmlResponseParser.cpp b/Src/omBrowser/xmlResponseParser.cpp
new file mode 100644
index 00000000..fb3065ae
--- /dev/null
+++ b/Src/omBrowser/xmlResponseParser.cpp
@@ -0,0 +1,207 @@
+#include "main.h"
+#include "./xmlResponseParser.h"
+#include "./ifc_omservicehost.h"
+#include "./ifc_omservice.h"
+#include "./ifc_omstoragehandlerenum.h"
+#include "./ifc_omstorageext.h"
+#include "./ifc_omfilestorage.h"
+
+
+#include "../xml/obj_xml.h"
+
+#include <shlwapi.h>
+#include <strsafe.h>
+
+
+XmlResponseParser::XmlResponseParser()
+ : reader(NULL), code((UINT)-1), text(NULL), host(NULL)
+{
+}
+
+XmlResponseParser::~XmlResponseParser()
+{
+ if (NULL != reader)
+ {
+ reader->Release();
+ reader = NULL;
+ }
+
+ if (NULL != host)
+ host->Release();
+
+ while(false == deque.empty())
+ {
+ deque.front()->Release();
+ deque.pop_front();
+ }
+}
+
+HRESULT XmlResponseParser::Initialize(obj_xml *xml, ifc_omservicehost *serviceHost)
+{
+ if (NULL == xml) return E_INVALIDARG;
+
+ if (NULL != reader)
+ {
+ if (reader == xml)
+ return S_FALSE;
+
+ reader->Release();
+ }
+
+ reader = xml;
+ reader->AddRef();
+
+ reader->xmlreader_registerCallback(L"response\fstatusCode", this);
+ reader->xmlreader_registerCallback(L"response\fstatusText", this);
+ reader->xmlreader_registerCallback(L"response\fdata\fservices\fservice", this);
+
+ if (NULL != host)
+ host->Release();
+
+ ifc_omstoragehandlerenum *handlerEnum(NULL);
+
+ host = serviceHost;
+ if (NULL != host)
+ {
+ host->AddRef();
+
+ ifc_omstorageext *storageExt;
+ if (SUCCEEDED(host->QueryInterface(IFC_OmStorageExt, (void**)&storageExt)))
+ {
+ if (FAILED(storageExt->Enumerate(&SUID_OmStorageXml, &handlerEnum)))
+ handlerEnum = NULL;
+ storageExt->Release();
+ }
+ }
+
+ parser.RegisterHandlers(handlerEnum);
+ if (NULL != handlerEnum)
+ {
+ handlerEnum->Release();
+ }
+
+ Reset();
+
+ return S_OK;
+}
+HRESULT XmlResponseParser::Finish()
+{
+ if (NULL != reader)
+ {
+ reader->Release();
+ reader = NULL;
+ }
+ return S_OK;
+}
+HRESULT XmlResponseParser::Reset()
+{
+ code = (UINT)-1;
+
+ if (NULL != text)
+ {
+ Plugin_FreeString(text);
+ text = NULL;
+ }
+
+ string.Clear();
+
+ return S_OK;
+}
+
+HRESULT XmlResponseParser::GetCode(UINT *value)
+{
+ if (NULL == value) return E_POINTER;
+ if ((UINT)-1 == code)
+ {
+ *value = 0;
+ return E_PENDING;
+ }
+
+ *value = code;
+ return S_OK;
+}
+
+HRESULT XmlResponseParser::GetText(LPWSTR pszBuffer, UINT cchBufferMax)
+{
+ if (NULL == pszBuffer) return E_POINTER;
+ if (NULL == text)
+ {
+ pszBuffer[0] = L'\0';
+ return E_PENDING;
+ }
+
+ return StringCchCopy(pszBuffer, cchBufferMax, text);
+}
+
+HRESULT XmlResponseParser::PeekService(ifc_omservice **service)
+{
+ if (NULL == service) return E_POINTER;
+ if (0 == deque.size()) return S_FALSE;
+
+ *service = deque.back();
+ deque.pop_back();
+ return S_OK;
+}
+
+void XmlResponseParser::OnStartElement(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params)
+{
+ if (CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, xmltag, -1, L"service", -1))
+ {
+ parser.Initialize(reader, xmlpath, host);
+ }
+ else
+ {
+ string.Clear();
+ }
+}
+
+void XmlResponseParser::OnEndElement(const wchar_t *xmlpath, const wchar_t *xmltag)
+{
+ if (S_OK == parser.GetActive())
+ {
+ ifc_omservice *service;
+ if (SUCCEEDED(parser.Finish(NULL, &service)) && NULL != service)
+ {
+ deque.push_front(service);
+ }
+ }
+ else
+ {
+ if ((UINT)-1 == code && CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, xmltag, -1, L"statusCode", -1))
+ {
+ LPCWSTR sCode = string.Get();
+ if (NULL == sCode || L'\0' == *sCode ||
+ FALSE == StrToIntEx(sCode, STIF_SUPPORT_HEX, (INT*)&code))
+ {
+ code = (UINT)-1;
+ }
+ }
+ else if (NULL == text && CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, xmltag, -1, L"statusText", -1))
+ {
+ text = Plugin_CopyString(string.Get());
+ }
+
+
+ }
+}
+
+void XmlResponseParser::OnCharData(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *value)
+{
+ if (S_OK != parser.GetActive())
+ {
+ string.Append(value);
+ }
+}
+
+void XmlResponseParser::OnError(int linenum, int errcode, const wchar_t *errstr)
+{
+ string.Clear();
+}
+
+#define CBCLASS XmlResponseParser
+START_DISPATCH;
+VCB(ONSTARTELEMENT, OnStartElement)
+VCB(ONENDELEMENT, OnEndElement)
+VCB(ONCHARDATA, OnCharData)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/xmlResponseParser.h b/Src/omBrowser/xmlResponseParser.h
new file mode 100644
index 00000000..d73e2857
--- /dev/null
+++ b/Src/omBrowser/xmlResponseParser.h
@@ -0,0 +1,56 @@
+#ifndef NULLSOFT_WINAMP_XML_RESPONSE_PARSER_HEADER
+#define NULLSOFT_WINAMP_XML_RESPONSE_PARSER_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+#include "../xml/ifc_xmlreadercallback.h"
+#include "./xmlServiceParser.h"
+#include "./stringBuilder.h"
+#include <deque>
+
+class obj_xml;
+class ifc_omservicehost;
+class ifc_omstorage;
+
+class XmlResponseParser : public ifc_xmlreadercallback
+{
+public:
+ XmlResponseParser();
+ ~XmlResponseParser();
+
+public:
+ HRESULT Initialize(obj_xml *xml, ifc_omservicehost *serviceHost);
+ HRESULT Finish();
+ HRESULT Reset();
+
+ HRESULT GetCode(UINT *value);
+ HRESULT GetText(LPWSTR pszBuffer, UINT cchBufferMax);
+
+ HRESULT PeekService(ifc_omservice **service);
+
+protected:
+ void OnStartElement(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params);
+ void OnEndElement(const wchar_t *xmlpath, const wchar_t *xmltag);
+ void OnCharData(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *str);
+ void OnError(int linenum, int errcode, const wchar_t *errstr);
+
+protected:
+ typedef std::deque<ifc_omservice*> ServiceDeque;
+
+protected:
+ obj_xml *reader;
+ UINT code;
+ LPWSTR text;
+
+ XmlServiceParser parser;
+ ifc_omservicehost *host;
+ ServiceDeque deque;
+ StringBuilder string;
+protected:
+ RECVS_DISPATCH;
+
+};
+#endif// NULLSOFT_WINAMP_XML_RESPONSE_PARSER_HEADER \ No newline at end of file
diff --git a/Src/omBrowser/xmlServiceParser.cpp b/Src/omBrowser/xmlServiceParser.cpp
new file mode 100644
index 00000000..8a7ad7b2
--- /dev/null
+++ b/Src/omBrowser/xmlServiceParser.cpp
@@ -0,0 +1,331 @@
+#include "main.h"
+#include "./xmlServiceParser.h"
+
+#include "../xml/obj_xml.h"
+
+#include "./service.h"
+#include "./ifc_omservicehost.h"
+#include "./ifc_omstoragehandler.h"
+#include "./ifc_omstoragehandlerenum.h"
+#include "./ifc_omstorageext.h"
+
+#include <shlwapi.h>
+#include <strsafe.h>
+
+typedef void (CALLBACK *TAGCALLBACK)(XmlServiceParser* /*reader*/, OmService* /*editor*/, LPCWSTR /*value*/);
+
+typedef struct __TAGRECORD
+{
+ LPCWSTR name;
+ TAGCALLBACK callback;
+} TAGRECORD;
+
+static void CALLBACK ParserXml_ReadId(XmlServiceParser *reader, OmService *service, LPCWSTR value)
+{
+ INT iVal;
+ if (StrToIntEx(value, STIF_SUPPORT_HEX, &iVal))
+ {
+ service->SetId(iVal);
+ }
+}
+
+static void CALLBACK ParserXml_ReadName(XmlServiceParser *reader, OmService *service, LPCWSTR value)
+{
+ service->SetName(value, FALSE);
+}
+
+static void CALLBACK ParserXml_ReadUrl(XmlServiceParser *reader, OmService *service, LPCWSTR value)
+{
+ service->SetUrl(value, FALSE);
+}
+
+static void CALLBACK ParserXml_ReadAuth(XmlServiceParser *reader, OmService *service, LPCWSTR value)
+{
+ INT iVal;
+ if (StrToIntEx(value, STIF_SUPPORT_HEX, &iVal))
+ {
+ // service->SetAuth(iVal);
+ }
+}
+
+static void CALLBACK ParserXml_ReadIcon(XmlServiceParser *reader, OmService *service, LPCWSTR value)
+{
+ service->SetIcon(value, FALSE);
+}
+
+static void CALLBACK ParserXml_ReadThumbnail(XmlServiceParser *reader, OmService *service, LPCWSTR value)
+{
+ service->SetThumbnail(value, FALSE);
+}
+
+static void CALLBACK ParserXml_ReadScreenshot(XmlServiceParser *reader, OmService *service, LPCWSTR value)
+{
+ service->SetScreenshot(value, FALSE);
+}
+
+static void CALLBACK ParserXml_ReadVersion(XmlServiceParser *reader, OmService *service, LPCWSTR value)
+{
+ INT iVal;
+ if (StrToIntEx(value, STIF_SUPPORT_HEX, &iVal))
+ service->SetVersion(iVal);
+}
+
+static void CALLBACK ParserXml_ReadGeneration(XmlServiceParser *reader, OmService *service, LPCWSTR value)
+{
+ INT iVal;
+ if (StrToIntEx(value, STIF_SUPPORT_HEX, &iVal))
+ {
+ service->SetGeneration(iVal);
+ }
+}
+
+static void CALLBACK ParserXml_ReadDescription(XmlServiceParser *reader, OmService *service, LPCWSTR value)
+{
+ service->SetDescription(value, FALSE);
+}
+
+static void CALLBACK ParserXml_ReadAuthorFirst(XmlServiceParser *reader, OmService *service, LPCWSTR value)
+{
+ service->SetAuthorFirst(value, FALSE);
+}
+
+static void CALLBACK ParserXml_ReadAuthorLast(XmlServiceParser *reader, OmService *service, LPCWSTR value)
+{
+ service->SetAuthorLast(value, FALSE);
+}
+
+static void CALLBACK ParserXml_ReadPublished(XmlServiceParser *reader, OmService *service, LPCWSTR value)
+{
+ service->SetPublished(value, FALSE);
+}
+
+static void CALLBACK ParserXml_ReadUpdated(XmlServiceParser *reader, OmService *service, LPCWSTR value)
+{
+ service->SetUpdated(value, FALSE);
+}
+
+static const TAGRECORD szTagTable[] =
+{
+ { L"id", ParserXml_ReadId },
+ { L"name", ParserXml_ReadName },
+ { L"version", ParserXml_ReadVersion },
+ { L"icon_url", ParserXml_ReadIcon },
+ { L"entry_url", ParserXml_ReadUrl },
+ { L"generation", ParserXml_ReadGeneration },
+ { L"author_comments_long", ParserXml_ReadDescription },
+ { L"author_firstname", ParserXml_ReadAuthorFirst},
+ { L"author_lastname", ParserXml_ReadAuthorLast },
+ { L"date_published", ParserXml_ReadPublished },
+ { L"date_updated", ParserXml_ReadUpdated },
+ { L"thumbnail", ParserXml_ReadThumbnail },
+ { L"screenshot", ParserXml_ReadScreenshot },
+};
+
+XmlServiceParser::XmlServiceParser()
+ : checkList(NULL), checkSize(0), parser(NULL), service(NULL), result(E_UNEXPECTED)
+{
+}
+
+XmlServiceParser::~XmlServiceParser()
+{
+ Finish(NULL, NULL);
+
+ if (NULL != checkList)
+ free(checkList);
+ size_t index = handlerList.size();
+ while (index--)
+ handlerList[index]->Release();
+}
+
+HRESULT XmlServiceParser::RegisterHandlers(ifc_omstoragehandlerenum *handlerEnum)
+{
+ if (E_PENDING == result)
+ return E_PENDING;
+
+ if (NULL != checkList)
+ {
+ free(checkList);
+ checkList = NULL;
+ checkSize = 0;
+ }
+
+ size_t index = handlerList.size();
+ while(index--) handlerList[index]->Release();
+ handlerList.clear();
+
+ if (NULL != handlerEnum)
+ {
+ ifc_omstoragehandler *handler;
+ handlerEnum->Reset();
+ while(S_OK == handlerEnum->Next(1, &handler, NULL))
+ {
+ handlerList.push_back(handler);
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT XmlServiceParser::Initialize(obj_xml *reader, LPCWSTR match, ifc_omservicehost *host)
+{
+ result = E_UNEXPECTED;
+
+ if (NULL != parser) return E_UNEXPECTED;
+ if (NULL == reader) return E_INVALIDARG;
+
+ HRESULT hr;
+ WCHAR szBuffer[1024] = {0};
+ LPWSTR cursor = szBuffer;
+ size_t remaining = ARRAYSIZE(szBuffer);
+
+ if (NULL == checkList)
+ {
+ size_t checkCount = ARRAYSIZE(szTagTable) + handlerList.size();
+ checkSize = checkCount/8 + ((checkCount%8) ? 1 : 0);
+
+ checkList = (BYTE*)calloc(checkSize, sizeof(BYTE));
+ if (NULL != checkList)
+ ZeroMemory(checkList, checkSize);
+ }
+
+ hr = StringCchCopyEx(cursor, remaining, match, &cursor, &remaining, STRSAFE_IGNORE_NULLS);
+ if (FAILED(hr)) return E_UNEXPECTED;
+
+ hr = StringCchCopyEx(cursor, remaining, ((cursor != szBuffer) ? L"\f*" : L"*"), &cursor, &remaining, STRSAFE_IGNORE_NULLS);
+ if (FAILED(hr)) return E_UNEXPECTED;
+
+ parser = reader;
+ parser->AddRef();
+ parser->xmlreader_registerCallback(szBuffer, this);
+
+ hr = OmService::CreateInstance(0, host, &service);
+ if (FAILED(hr)) return hr;
+
+ service->BeginUpdate();
+
+ result = E_PENDING;
+ return S_OK;
+}
+
+HRESULT XmlServiceParser::Finish(HRESULT *parserResult, ifc_omservice **ppService)
+{
+ if (NULL == parser)
+ return E_UNEXPECTED;
+
+ if (E_PENDING == result)
+ result= S_OK;
+
+ buffer.Clear();
+
+ if (NULL != checkList)
+ ZeroMemory(checkList, checkSize);
+
+ parser->xmlreader_unregisterCallback(this);
+ parser->Release();
+ parser = NULL;
+
+ if (NULL != service && 0 == service->GetId())
+ {
+ if (SUCCEEDED(result))
+ result = E_UNEXPECTED;
+
+ service->Release();
+ service = NULL;
+ }
+
+ if (NULL != parserResult)
+ *parserResult = result;
+
+ if (NULL != ppService)
+ {
+ if (SUCCEEDED(result))
+ {
+ *ppService = service;
+ service->AddRef();
+ }
+ else
+ {
+ *ppService = NULL;
+ }
+ }
+
+ if (NULL != service)
+ {
+ service->SetModified(0, (UINT)-1);
+ service->EndUpdate();
+
+ service->Release();
+ service = NULL;
+ }
+
+ result = E_UNEXPECTED;
+ return S_OK;
+}
+
+HRESULT XmlServiceParser::GetActive()
+{
+ return (E_PENDING == result) ? S_OK : S_FALSE;
+}
+
+void XmlServiceParser::OnStartElement(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params)
+{
+ buffer.Clear();
+}
+
+void XmlServiceParser::OnEndElement(const wchar_t *xmlpath, const wchar_t *xmltag)
+{
+ size_t i;
+ for (i = 0; i < ARRAYSIZE(szTagTable); i++)
+ {
+ if (NULL == checkList || 0 == (checkList[i/8] & (0x01 << (i%8))) && E_PENDING == result)
+ {
+ if (CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, szTagTable[i].name, -1, xmltag, -1))
+ {
+ checkList[i/8] |= (0x01 << (i%8));
+ szTagTable[i].callback(this, service, buffer.Get());
+ return;
+ }
+ }
+ }
+
+ size_t handlerSize = handlerList.size();
+ size_t iCheck = ARRAYSIZE(szTagTable);
+ for (i = 0; i < handlerSize; i++, iCheck++)
+ {
+ if (NULL == checkList || 0 == (checkList[iCheck/8] & (0x01 << (iCheck%8))) && E_PENDING == result)
+ {
+ LPCWSTR pszKey;
+ if (SUCCEEDED(handlerList[i]->GetKey(&pszKey)) &&
+ CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, pszKey, -1, xmltag, -1))
+ {
+ checkList[iCheck/8] |= (0x01 << (iCheck%8));
+ handlerList[i]->Invoke(service, xmltag, buffer.Get());
+ return;
+ }
+ }
+ }
+}
+
+void XmlServiceParser::OnCharData(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *value)
+{
+ buffer.Append(value);
+}
+
+void XmlServiceParser::OnError(int linenum, int errcode, const wchar_t *errstr)
+{
+ result = E_FAIL;
+ if (NULL != service)
+ {
+ service->Release();
+ service = NULL;
+ }
+}
+
+#define CBCLASS XmlServiceParser
+START_DISPATCH;
+VCB(ONSTARTELEMENT, OnStartElement)
+VCB(ONENDELEMENT, OnEndElement)
+VCB(ONCHARDATA, OnCharData)
+VCB(ONERROR, OnError)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/omBrowser/xmlServiceParser.h b/Src/omBrowser/xmlServiceParser.h
new file mode 100644
index 00000000..70ba2255
--- /dev/null
+++ b/Src/omBrowser/xmlServiceParser.h
@@ -0,0 +1,54 @@
+#ifndef NULLSOFT_WINAMP_XML_SERVICE_PARSER_HEADER
+#define NULLSOFT_WINAMP_XML_SERVICE_PARSER_HEADER
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+#include <wtypes.h>
+#include "../xml/ifc_xmlreadercallback.h"
+#include "./stringBuilder.h"
+#include <vector>
+
+class obj_xml;
+class OmService;
+class ifc_omservice;
+class ifc_omservicehost;
+class ifc_omstoragehandler;
+class ifc_omstoragehandlerenum;
+
+class XmlServiceParser : public ifc_xmlreadercallback
+{
+public:
+ XmlServiceParser();
+ ~XmlServiceParser();
+
+public:
+ HRESULT Initialize(obj_xml *reader, LPCWSTR match, ifc_omservicehost *host);
+ HRESULT Finish(HRESULT *parserResult, ifc_omservice **ppService);
+ HRESULT GetActive();
+ HRESULT RegisterHandlers(ifc_omstoragehandlerenum *handlerEnum);
+
+protected:
+ void OnStartElement(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params);
+ void OnEndElement(const wchar_t *xmlpath, const wchar_t *xmltag);
+ void OnCharData(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *str);
+ void OnError(int linenum, int errcode, const wchar_t *errstr);
+
+protected:
+ typedef std::vector<ifc_omstoragehandler*> HandlerList;
+protected:
+ StringBuilder buffer;
+ HandlerList handlerList;
+ BYTE *checkList;
+ size_t checkSize;
+
+ obj_xml *parser;
+ OmService *service;
+ HRESULT result;
+
+protected:
+ RECVS_DISPATCH;
+
+};
+#endif// NULLSOFT_WINAMP_XML_SERVICE_PARSER_HEADER \ No newline at end of file