diff options
Diffstat (limited to 'Src/Plugins/Library/ml_online')
89 files changed, 18161 insertions, 0 deletions
diff --git a/Src/Plugins/Library/ml_online/BufferCache.h b/Src/Plugins/Library/ml_online/BufferCache.h new file mode 100644 index 00000000..fdc3b1e4 --- /dev/null +++ b/Src/Plugins/Library/ml_online/BufferCache.h @@ -0,0 +1,13 @@ +#ifndef NULLSOFT_BUFFERCACHEH +#define NULLSOFT_BUFFERCACHEH +#include <time.h> +#include "../nu/GrowBuf.h" + +class Buffer_GrowBuf : public GrowBuf +{ +public: + Buffer_GrowBuf() : expire_time(0) {} + time_t expire_time; +}; + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/JSAPI2_Creator.cpp b/Src/Plugins/Library/ml_online/JSAPI2_Creator.cpp new file mode 100644 index 00000000..d6d99442 --- /dev/null +++ b/Src/Plugins/Library/ml_online/JSAPI2_Creator.cpp @@ -0,0 +1,93 @@ +#include "api__ml_online.h" +#include "JSAPI2_Creator.h" +#include "jsapi2_omcom.h" +#include "resource.h" + + +IDispatch *JSAPI2_Creator::CreateAPI(const wchar_t *name, const wchar_t *key, JSAPI::ifc_info *info) +{ + if (!wcscmp(name, L"OnlineServices")) + return new JSAPI2::OnlineServicesAPI(key, info); + else + return 0; +} + +int JSAPI2_Creator::PromptForAuthorization(HWND parent, const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, JSAPI2::api_security::AuthorizationData *data) +{ + if (group && !wcscmp(group, L"onlineservices")) + { + return JSAPI2::svc_apicreator::AUTHORIZATION_DENY; + } + else + return JSAPI2::svc_apicreator::AUTHORIZATION_UNDEFINED; +} + +#define CBCLASS JSAPI2_Creator +START_DISPATCH; +CB(JSAPI2_SVC_APICREATOR_CREATEAPI, CreateAPI); +CB(JSAPI2_SVC_APICREATOR_PROMPTFORAUTHORIZATION, PromptForAuthorization); +END_DISPATCH; +#undef CBCLASS + +static JSAPI2_Creator jsapi2_svc; +static const char serviceName[] = "Online Services Javascript Objects"; + +// {4B0FA456-2B3B-4584-A96C-54765EA46448} +static const GUID jsapi2_factory_guid = +{ 0x4b0fa456, 0x2b3b, 0x4584, { 0xa9, 0x6c, 0x54, 0x76, 0x5e, 0xa4, 0x64, 0x48 } }; + +FOURCC JSAPI2Factory::GetServiceType() +{ + return jsapi2_svc.getServiceType(); +} + +const char *JSAPI2Factory::GetServiceName() +{ + return serviceName; +} + +GUID JSAPI2Factory::GetGUID() +{ + return jsapi2_factory_guid; +} + +void *JSAPI2Factory::GetInterface(int global_lock) +{ +// if (global_lock) +// WASABI_API_SVC->service_lock(this, (void *)ifc); + return &jsapi2_svc; +} + +int JSAPI2Factory::SupportNonLockingInterface() +{ + return 1; +} + +int JSAPI2Factory::ReleaseInterface(void *ifc) +{ + //WASABI_API_SVC->service_unlock(ifc); + return 1; +} + +const char *JSAPI2Factory::GetTestString() +{ + return 0; +} + +int JSAPI2Factory::ServiceNotify(int msg, int param1, int param2) +{ + return 1; +} + +#define CBCLASS JSAPI2Factory +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/Plugins/Library/ml_online/JSAPI2_Creator.h b/Src/Plugins/Library/ml_online/JSAPI2_Creator.h new file mode 100644 index 00000000..4190b391 --- /dev/null +++ b/Src/Plugins/Library/ml_online/JSAPI2_Creator.h @@ -0,0 +1,31 @@ +#pragma once + +#include "../Winamp/JSAPI2_svc_apicreator.h" + +#include <api/service/waservicefactory.h> +#include <api/service/services.h> + +class JSAPI2Factory : public waServiceFactory +{ + 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 ); + + protected: + RECVS_DISPATCH; +}; + + +class JSAPI2_Creator : public JSAPI2::svc_apicreator +{ + IDispatch *CreateAPI(const wchar_t *name, const wchar_t *key, JSAPI::ifc_info *info); + int PromptForAuthorization(HWND parent, const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, JSAPI2::api_security::AuthorizationData *data); +protected: + RECVS_DISPATCH; +}; diff --git a/Src/Plugins/Library/ml_online/JnetCOM.cpp b/Src/Plugins/Library/ml_online/JnetCOM.cpp new file mode 100644 index 00000000..e93506f3 --- /dev/null +++ b/Src/Plugins/Library/ml_online/JnetCOM.cpp @@ -0,0 +1,656 @@ +#include "JnetCOM.h" +#include "main.h" +#include "../nu/AutoChar.h" +#include "../nu/AutoWide.h" +#include <algorithm> +#include <map> +#include "config.h" +#include <time.h> +#include "../nu/MediaLibraryInterface.h" +#include "api__ml_online.h" +#include <api/service/waServiceFactory.h> +#include <strsafe.h> + +extern C_Config *g_config; + +BufferMap buffer_map; + +enum +{ + DISP_JNET_INIT = 9323, + DISP_JNET_DOWNLOAD, + DISP_JNET_STATUS, + DISP_JNET_SIZE, + DISP_JNET_BUFFER, + DISP_JNET_BUFFER_RAW, + DISP_JNET_POST, +}; + +HANDLE DuplicateCurrentThread() +{ + HANDLE fakeHandle = GetCurrentThread(); + HANDLE copiedHandle = 0; + HANDLE processHandle = GetCurrentProcess(); + DuplicateHandle(processHandle, fakeHandle, processHandle, &copiedHandle, 0, FALSE, DUPLICATE_SAME_ACCESS); + return copiedHandle; +} + +#define CHECK_ID(str, id) if (wcscmp(rgszNames[i], L##str) == 0) { rgdispid[i] = id; continue; } +HRESULT JnetCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid) +{ + bool unknowns = false; + for (unsigned int i = 0;i != cNames;i++) + { + CHECK_ID("Init", DISP_JNET_INIT) + CHECK_ID("Download", DISP_JNET_DOWNLOAD) + CHECK_ID("Status", DISP_JNET_STATUS) + CHECK_ID("Buffer", DISP_JNET_BUFFER) + CHECK_ID("BufferRaw", DISP_JNET_BUFFER_RAW) + CHECK_ID("Size", DISP_JNET_SIZE) + CHECK_ID("Post", DISP_JNET_POST) + + rgdispid[i] = DISPID_UNKNOWN; + unknowns = true; + + } + if (unknowns) + return DISP_E_UNKNOWNNAME; + else + return S_OK; +} + +HRESULT JnetCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo) +{ + return E_NOTIMPL; +} + +HRESULT JnetCOM::GetTypeInfoCount(unsigned int FAR * pctinfo) +{ + return E_NOTIMPL; +} + + +HRESULT JnetCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr) +{ + switch (dispid) + { + case DISP_JNET_INIT: + { + if (!active && NULL == callback) + { + finalSize = 0; + isBlocking = true; + if ( pdispparams->cArgs == 2 ) + { + isBlocking = false; + htmldiv = SysAllocString(pdispparams->rgvarg[0].bstrVal); // HTML DIV + callback = pdispparams->rgvarg[1].pdispVal; // callback object; + if (NULL != callback) + callback->AddRef(); + } + } + else + { + if (pvarResult) + { + VariantInit(pvarResult); + V_VT(pvarResult) = VT_I4; + V_I4(pvarResult) = -1; + } + } + return S_OK; + } + break; + case DISP_JNET_DOWNLOAD: + if (pdispparams->cArgs == 1 || pdispparams->cArgs == 2) + { + int result = -1; + if ( !active ) + { + time_t ret = 0; + active = 1; + + DownloadURL(pdispparams); + result = 1; + } + else result = -1; + + if (pvarResult) + { + VariantInit(pvarResult); + V_VT(pvarResult) = VT_I4; + V_I4(pvarResult) = result; + } + + return S_OK; + } + break; + case DISP_JNET_POST: + if (pdispparams->cArgs == 2) + { + int result = -1; + if ( !active ) + { + time_t ret = 0; + active = 1; + + PostURL(pdispparams); + result = 1; + } + else result = -1; + + if (pvarResult) + { + VariantInit(pvarResult); + V_VT(pvarResult) = VT_I4; + V_I4(pvarResult) = result; + } + + return S_OK; + } + break; + case DISP_JNET_STATUS: + { + if (pvarResult && errorstr && active ) + { + AutoWide result(errorstr); + BSTR tag = SysAllocString(result); + VariantInit(pvarResult); + V_VT(pvarResult) = VT_BSTR; + V_BSTR(pvarResult) = tag; + } + return S_OK; + } + break; + case DISP_JNET_SIZE: + { + if (pvarResult && active ) + { + VariantInit(pvarResult); + V_VT(pvarResult) = VT_I4; + V_I4(pvarResult) = (INT)finalSize; + } + return S_OK; + } + break; + case DISP_JNET_BUFFER_RAW: + { + if (pvarResult && jnetbuf->get() && active) + { + char dummy[1]={0}; + size_t len = jnetbuf->getlen(); + char *source = (char *)jnetbuf->get(); + if (!len || !source) + { + source=dummy; + len=1; + } + else + { + while (*(source+len-1) == 0 && len) + len--; + } + SAFEARRAY *bufferArray=SafeArrayCreateVector(VT_UI1, 0, (ULONG)len); + void *data; + SafeArrayAccessData(bufferArray, &data); + memcpy(data, source, len); + SafeArrayUnaccessData(bufferArray); + VariantInit(pvarResult); + V_VT(pvarResult) = VT_ARRAY|VT_UI1; + V_ARRAY(pvarResult) = bufferArray; + } + return S_OK; + } + case DISP_JNET_BUFFER: + { + if (pvarResult && jnetbuf->get() && active ) + { + AutoWide result((char *)jnetbuf->get()); + BSTR tag = SysAllocString(result); + VariantInit(pvarResult); + V_VT(pvarResult) = VT_BSTR; + V_BSTR(pvarResult) = tag; + } + return S_OK; + } + break; + } + return DISP_E_MEMBERNOTFOUND; +} + +STDMETHODIMP JnetCOM::QueryInterface(REFIID riid, PVOID *ppvObject) +{ + if (!ppvObject) + return E_POINTER; + + else if (IsEqualIID(riid, IID_IDispatch)) + *ppvObject = (IDispatch *)this; + else if (IsEqualIID(riid, IID_IUnknown)) + *ppvObject = this; + else + { + *ppvObject = NULL; + return E_NOINTERFACE; + } + + AddRef(); + return S_OK; +} + +ULONG JnetCOM::AddRef(void) +{ + return ++refCount; +} + +ULONG JnetCOM::Release(void) +{ + if (--refCount) + return refCount; + + threadexit = 1; // exit the thread if active + if (!isBlocking) + { // Only if a callback was associated would the thread be running + while (getter) // If there no getter, the thread is gone + Sleep(10); + } + + if (!finalSize) + { + BufferMap::iterator buffer_it = buffer_map.find(url); + if (buffer_it != buffer_map.end()) + { + jnetbuf = buffer_it->second; + buffer_map.erase(buffer_it->first); + delete jnetbuf; + jnetbuf = NULL; + } + } + Plugin_FreeString(url); + url=0; + if (postData) + { + free(postData); + postData=0; + } + + if (NULL != callback) + { + callback->Release(); + callback = NULL; + } + + delete this; + return 0; +} + +static VOID CALLBACK CallbackAPC(ULONG_PTR param) +{ + VARIANT arguments[2]; + DISPPARAMS params; + unsigned int ret; + + JnetCOM *jnet = (JnetCOM *)param; + if (NULL == jnet || NULL == jnet->callback) + return; + + VariantInit(&arguments[0]); + VariantInit(&arguments[1]); + + V_VT(&arguments[0]) = VT_DISPATCH; + V_DISPATCH(&arguments[0]) = jnet; + + V_VT(&arguments[1]) = VT_BSTR; + V_BSTR(&arguments[1]) = jnet->htmldiv; + + params.cArgs = ARRAYSIZE(arguments); + params.cNamedArgs = 0; + params.rgdispidNamedArgs = NULL; + params.rgvarg = arguments; + + jnet->callback->Invoke(0, GUID_NULL, 0, DISPATCH_METHOD, ¶ms, NULL, NULL, &ret); + + + V_DISPATCH(&arguments[0]) = NULL; + V_BSTR(&arguments[1]) = NULL; + + VariantClear(&arguments[0]); + VariantClear(&arguments[1]); + + jnet->Release(); + + +} + +void JnetCOM::callBack() +{ + AddRef(); + if (GetCurrentThreadId() == callingThreadId) + CallbackAPC((ULONG_PTR)this); + else + { + if (NULL == callingThreadHandle || + 0 == QueueUserAPC(CallbackAPC, callingThreadHandle, (ULONG_PTR)this)) + { + Release(); + } + } +} + +#define USER_AGENT_SIZE (10 /*User-Agent*/ + 2 /*: */ + 6 /*Winamp*/ + 1 /*/*/ + 1 /*5*/ + 3/*.21*/ + 1 /*Null*/) +void SetUserAgent(api_httpreceiver *http) +{ + char user_agent[USER_AGENT_SIZE] = {0}; + int bigVer = ((winampVersion & 0x0000FF00) >> 12); + int smallVer = ((winampVersion & 0x000000FF)); + StringCchPrintfA(user_agent, USER_AGENT_SIZE, "User-Agent: Winamp/%01x.%02x", bigVer, smallVer); + http->addheader(user_agent); +} + +int JnetCOM::JthreadProc() +{ + int ret; + char temp[WORKSIZE] = {0}; + + char *proxy = mediaLibrary.GetProxy(); + + waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(httpreceiverGUID); + if (sf) getter = (api_httpreceiver *)sf->getInterface(); + + // we're keying off of 'getter' to know if the thread is running or not, so we can release now + Release(); + + if (!getter) + return -1; + + getter->AllowCompression(); + getter->open(API_DNS_AUTODNS, WORKSIZE, proxy); + + SetUserAgent(getter); + + getter->connect(AutoChar(url)); + + BOOL bDone = FALSE; + while (!bDone && !threadexit) + { + Sleep(10); + ret = getter->run(); + if (ret == -1 || ret == 1) + bDone = TRUE; + + int bytesReceived = getter->get_bytes(temp, WORKSIZE); + if (bytesReceived) + jnetbuf->add(temp, bytesReceived); + } + + if (!threadexit) + { + + if (ret == -1) StringCchCopyA(errorstr, 2048, getter->geterrorstr()); + else + { + int bytesReceived; + do // flush out the socket + { + bytesReceived = getter->get_bytes(temp, WORKSIZE); + if (bytesReceived) + jnetbuf->add(temp, bytesReceived); + } + while (bytesReceived); + + temp[0] = 0; + jnetbuf->add(temp, 1); + } + + finalSize = jnetbuf->getlen(); + + callBack(); + } + + sf->releaseInterface(getter); + threadexit = 0; + if (callingThreadHandle) + CloseHandle(callingThreadHandle); + getter = NULL; + return ret; +} + +int JnetCOM::PostProcedure() +{ + int ret; + char temp[WORKSIZE] = {0}; + + char *proxy = mediaLibrary.GetProxy(); + + waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(httpreceiverGUID); + if (sf) getter = (api_httpreceiver *)sf->getInterface(); + + // we're keying off of 'getter' to know if the thread is running or not, so we can release now + Release(); + if (!getter) + return -1; + + getter->AllowCompression(); + getter->open(API_DNS_AUTODNS, WORKSIZE, proxy); + + SetUserAgent(getter); + getter->addheader("Content-Type: application/x-www-form-urlencoded"); + + size_t contentLength = strlen(postData); + char contentLengthHeader[256] = {0}; + StringCchPrintfA(contentLengthHeader, 256, "Content-Length: %u", contentLength); + getter->addheader(contentLengthHeader); + + char *dataIndex = postData; + bool done=false; + + getter->connect(AutoChar(url), 0, "POST"); + + // time to post data! + api_connection *connection = getter->GetConnection(); + + while (contentLength && !threadexit) + { + Sleep(1); + getter->run(); + + size_t lengthToSend = min(contentLength, connection->GetSendBytesAvailable()); + if (lengthToSend) + { + connection->send(dataIndex, (int)lengthToSend); + dataIndex+=lengthToSend; + contentLength-=lengthToSend; + } + } + + while (!threadexit && !done) + { + Sleep(10); + ret = getter->run(); + if (ret == -1) + break; + + // ---- check our reply code ---- + int replycode = getter->getreplycode(); + switch (replycode) + { + case 0: + break; + case 100: + break; + case 200: + { + int bytesReceived = getter->get_bytes(temp, WORKSIZE); + if (bytesReceived) + jnetbuf->add(temp, bytesReceived); + do + { + Sleep(10); + ret = getter->run(); + bytesReceived = getter->get_bytes(temp, WORKSIZE); + if (bytesReceived) + jnetbuf->add(temp, bytesReceived); + } + while (ret == HTTPRECEIVER_RUN_OK); + done=true; // just in case + } + break; + default: + done=true; + break; + } + if (ret != HTTPRECEIVER_RUN_OK) + break; + } + if (!threadexit) + { + if (ret == -1) + StringCchCopyA(errorstr, 2048, getter->geterrorstr()); + else + { + int bytesReceived; + do // flush out the socket + { + bytesReceived = getter->get_bytes(temp, WORKSIZE); + if (bytesReceived) + jnetbuf->add(temp, bytesReceived); + } + while (bytesReceived && !threadexit); + + temp[0] = 0; + jnetbuf->add(temp, 1); + } + + if ( !threadexit ) + { + finalSize = jnetbuf->getlen(); + callBack(); + } + + } + sf->releaseInterface(getter); + + threadexit = 0; + if (callingThreadHandle) + CloseHandle(callingThreadHandle); + getter = NULL; + return ret; +} + +void JnetCOM::DownloadURL(DISPPARAMS FAR *pdispparams) +{ + Plugin_FreeString(url); + url = Plugin_CopyString(pdispparams->rgvarg[pdispparams->cArgs - 1].bstrVal); + + callingThreadId = GetCurrentThreadId(); + callingThreadHandle = DuplicateCurrentThread(); + + BufferMap::iterator buffer_it = buffer_map.find(url); + if (buffer_it != buffer_map.end()) + { + time_t check = time(NULL); + jnetbuf = buffer_it->second; + if ( check >= jnetbuf->expire_time) + { + buffer_map.erase(buffer_it->first); + delete jnetbuf; + jnetbuf = NULL; + } + else + { + finalSize = jnetbuf->getlen(); + callBack(); + } + + } + if (!jnetbuf) + { + time_t now = 0; + + jnetbuf = buffer_map[url] = new Buffer_GrowBuf; + + if ( pdispparams->cArgs == 2 ) // passed in a time from Javascript, or 0 to not cache + { + if ( pdispparams->rgvarg[0].iVal ) + { + now = time(NULL); + jnetbuf->expire_time = now + pdispparams->rgvarg[0].iVal; + } + } + else // Use winamp config cache time + { + int when = 0, x = 0; + + x = g_config->ReadInt("radio_upd_freq", 0); + switch ( x ) + { + case 0: + { + when = 3600; // One Hour + } + break; + case 1: + { + when = 3600 * 24; // One Day aka 24 hours + } + break; + case 2: + { + when = 3600 * 24 * 7; // One week (weak) + } + break; + default: + break; + } + if (when) + now = time(NULL); + + jnetbuf->expire_time = now + when; + + } + if (isBlocking) + { + AddRef(); // need to call this because JthreadProc does a Release + JthreadProc(); // Call it directly, block until done. + } + else + { + // Launch the thread + DWORD threadId; + AddRef(); // make sure jnetcom object doesn't die while the thread is launching. + jnetThread = CreateThread(NULL, NULL, JThreadProc, (void *)this, NULL, &threadId); + } + + } +} + +void JnetCOM::PostURL(DISPPARAMS FAR *pdispparams) +{ + postData = AutoCharDup(pdispparams->rgvarg[0].bstrVal); + Plugin_FreeString(url); + url = Plugin_CopyString(pdispparams->rgvarg[1].bstrVal); + + callingThreadId = GetCurrentThreadId(); + callingThreadHandle = DuplicateCurrentThread(); + + if (!jnetbuf) + { + time_t now = 0; + + jnetbuf = buffer_map[url] = new Buffer_GrowBuf; + + if (isBlocking) + { + AddRef(); // need to do this beacuse PostProcedure calls Release + PostProcedure(); // Call it directly, block until done. + } + else + { + // Launch the thread + DWORD threadId; + AddRef(); // make sure the jnetcom doesn't get deleted before the thread launches + jnetThread = CreateThread(NULL, NULL, jnetPostProcedure, (void *)this, NULL, &threadId); + } + + } +} + diff --git a/Src/Plugins/Library/ml_online/JnetCOM.h b/Src/Plugins/Library/ml_online/JnetCOM.h new file mode 100644 index 00000000..c3a5e023 --- /dev/null +++ b/Src/Plugins/Library/ml_online/JnetCOM.h @@ -0,0 +1,91 @@ +#ifndef NULLSOFT_JNETCOMH +#define NULLSOFT_JNETCOMH + +#include <process.h> +#include <ocidl.h> + +#include "../../..\Components\wac_network\wac_network_http_receiver_api.h" +#include <objbase.h> +#include "BufferCache.h" +#include <map> +#include <string> + + +typedef std::map<std::wstring, Buffer_GrowBuf *> BufferMap; +extern BufferMap buffer_map; +#define WORKSIZE 32768 + +class JnetCOM : public IDispatch +{ +public: + JnetCOM() : + refCount(1), + threadexit(0), + active(0), + jnetThread(0), + jnetbuf(NULL), + isBlocking(0), + finalSize(0), + getter(NULL), + callback(NULL), + postData(0), + url(0), + callingThreadId(0), + callingThreadHandle(0) + { + memset(errorstr, 0, sizeof(errorstr)); + } + STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject); + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + int refCount; + // *** IDispatch Methods *** + STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid); + STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo); + STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo); + STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr); + + void DownloadURL(DISPPARAMS FAR *pdispparams ); + void PostURL(DISPPARAMS FAR *pdispparams); + void callBack(); + + int threadexit; + int isBlocking; + + api_httpreceiver *getter; + Buffer_GrowBuf *jnetbuf; + IDispatch *callback; + BSTR htmldiv; + DWORD callingThreadId; + HANDLE callingThreadHandle; + + static DWORD WINAPI JThreadProc(void *param) + { + CoInitialize(NULL); + JnetCOM *th = static_cast<JnetCOM*>(param); + int ret = th->JthreadProc(); + _endthread(); + return ret; + } + + static DWORD WINAPI jnetPostProcedure(void *param) + { + CoInitialize(NULL); + JnetCOM *th = static_cast<JnetCOM*>(param); + int ret = th->PostProcedure(); + _endthread(); + return ret; + } + + size_t finalSize; + wchar_t *url; + char *postData; + int active; + char errorstr[2048]; + HANDLE jnetThread; +private: + int JthreadProc(); + int PostProcedure(); +}; + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Main.cpp b/Src/Plugins/Library/ml_online/Main.cpp new file mode 100644 index 00000000..4f4f3c86 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Main.cpp @@ -0,0 +1,599 @@ +#include "main.h" +#include "./api__ml_online.h" +#include "./config.h" +#include "./navigation.h" +#include "./resource.h" +#include "./preferences.h" +#include "./serviceHelper.h" + +#include "../../General/gen_ml/ml.h" +#include "../../General/gen_ml/ml_ipc_0313.h" + +#include "../nu/MediaLibraryInterface.h" +#include "../nu/AutoChar.h" +#include "../nu/ns_wc.h" +#include "../nu/AutoWide.h" +#include <vector> +#include "../nu/nonewthrow.c" +#include "../nu/ConfigCOM.h" + +#include "BufferCache.h" +#include "OMCOM.h" +#include "JNetCom.h" // for buffer_map + +#include <shlwapi.h> +#include <strsafe.h> + + +static int Plugin_Init(); +static void Plugin_Quit(); +static INT_PTR Plugin_MessageProc(INT msg, INT_PTR param1, INT_PTR param2, INT_PTR param3); + +static Navigation *navigation = NULL; +static std::vector<PLUGINUNLOADCALLBACK> *unloadCallbacks = NULL; + +C_Config *g_config=NULL; + +extern "C" winampMediaLibraryPlugin plugin = +{ + MLHDR_VER, + "nullsoft(ml_online.dll)", + Plugin_Init, + Plugin_Quit, + Plugin_MessageProc, + 0, + 0, + 0, +}; + + +HINSTANCE Plugin_GetInstance(void) +{ + return plugin.hDllInstance; +} + +HWND Plugin_GetWinamp(void) +{ + return plugin.hwndWinampParent; +} + +HWND Plugin_GetLibrary(void) +{ + return plugin.hwndLibraryParent; +} + +HRESULT Plugin_GetNavigation(Navigation **instance) +{ + if(NULL == instance) return E_POINTER; + + if (NULL == navigation) + { + *instance = NULL; + return E_UNEXPECTED; + } + + *instance = navigation; + navigation->AddRef(); + + return S_OK; +} + +typedef struct __PLUGINTIMERREC +{ + UINT_PTR id; + PLUGINTIMERPROC callback; + ULONG_PTR data; +} PLUGINTIMERREC; + +typedef std::vector<PLUGINTIMERREC> PluginTimerList; + +static void CALLBACK Plugin_TimerProcDispath(HWND hwnd, UINT uMsg, UINT_PTR eventId, DWORD elapsedMs) +{ + HWND hLibrary = Plugin_GetLibrary(); + if (NULL != hLibrary && FALSE != IsWindow(hLibrary)) + { + PluginTimerList *list = (PluginTimerList*)GetProp(hLibrary, L"OnlineMediaTimerData"); + if (NULL != list) + { + size_t index = list->size(); + while(index--) + { + PLUGINTIMERREC *rec = &list->at(index); + if (rec->id == eventId) + { + rec->callback(eventId, elapsedMs, rec->data); + return; + } + } + } + } + + KillTimer(hwnd, eventId); +} + +UINT_PTR Plugin_SetTimer(UINT elapseMs, PLUGINTIMERPROC callback, ULONG_PTR data) +{ + HWND hLibrary = Plugin_GetLibrary(); + if (NULL == hLibrary || FALSE == IsWindow(hLibrary)) + return 0; + + if (GetCurrentThreadId() != GetWindowThreadProcessId(hLibrary, NULL)) + return 0; + + if (NULL == callback) + return 0; + + PluginTimerList *list = (PluginTimerList*)GetProp(hLibrary, L"OnlineMediaTimerData"); + if (NULL == list) + { + list = new PluginTimerList(); + if (NULL == list) return 0; + if (0 == SetProp(hLibrary, L"OnlineMediaTimerData", list)) + { + delete(list); + return 0; + } + } + + PLUGINTIMERREC rec; + rec.data = data; + rec.callback = callback; + rec.id = SetTimer(NULL, NULL, elapseMs, Plugin_TimerProcDispath); + if (0 == rec.id) + { + if (0 == list->size()) + { + RemoveProp(hLibrary, L"OnlineMediaTimerData"); + delete(list); + } + return 0; + } + + list->push_back(rec); + return rec.id; +} + +void Plugin_KillTimer(UINT_PTR eventId) +{ + KillTimer(NULL, eventId); + + HWND hLibrary = Plugin_GetLibrary(); + if (NULL == hLibrary || FALSE == IsWindow(hLibrary)) + return; + + PluginTimerList *list = (PluginTimerList*)GetProp(hLibrary, L"OnlineMediaTimerData"); + if (NULL == list) return; + + size_t index = list->size(); + while(index--) + { + if (list->at(index).id == eventId) + { + list->erase(list->begin() + index); + break; + } + } + + if (0 == list->size()) + { + RemoveProp(hLibrary, L"OnlineMediaTimerData"); + delete(list); + } +} + +static void Plugin_UninitializeTimer() +{ + HWND hLibrary = Plugin_GetLibrary(); + if (NULL == hLibrary || FALSE == IsWindow(hLibrary)) + return; + + PluginTimerList *list = (PluginTimerList*)GetProp(hLibrary, L"OnlineMediaTimerData"); + RemoveProp(hLibrary, L"OnlineMediaTimerData"); + if (NULL == list) return; + + size_t index = list->size(); + while(index--) + { + KillTimer(NULL, list->at(index).id); + } + + delete(list); +} + + +wchar_t g_w_cachedir[2048] = {0}; +int winampVersion=0; + +OMCOM omCOM; + +URLMap urlMap; +MetadataMap metadataMap; +Nullsoft::Utility::LockGuard urlMapGuard; + +void LoadCacheItem( wchar_t *path ) +{ + FILECACHETYPE cachefile = {0}; + unsigned long size = 0; + HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) return; + ReadFile(hFile, &cachefile, sizeof(FILECACHETYPE),&size, NULL); + if ( size == sizeof(FILECACHETYPE )) + { + size = 0; + time_t now = time(NULL); + //read the header, validate + if ( cachefile.version == FILECACHEVERSION ) + { + if ( now < cachefile.expires ) + { + char *url = (char *)calloc((size_t)cachefile.urllen, sizeof(char)); + if (url) + { + size = 0; + ReadFile(hFile, url, (DWORD)cachefile.urllen, &size, NULL); + if ( cachefile.urllen == size ) // we read it ok! + { + char tempbuf[16384] = {0}; + Buffer_GrowBuf *newbuffer = new Buffer_GrowBuf; + INT64 readin=0; + newbuffer->expire_time = (time_t)cachefile.expires; + while ( readin != cachefile.datalen ) + { + DWORD toread=(DWORD)cachefile.datalen - (DWORD)readin; + if ( toread > 16384 ) toread=16384; + size = 0; + int success = ReadFile(hFile, &tempbuf, toread , &size, NULL); + if ( success ) + { + if ( size ) + { + newbuffer->add(tempbuf,(int)size); + readin += size; + } + } + else + { + break; + } + } + if ( readin != cachefile.datalen ) + { + delete newbuffer; + } + else + { + buffer_map[(wchar_t *)AutoWide(url)]=newbuffer; + } + } + else + { + free(url); + } + } + } + } + } + CloseHandle(hFile); + DeleteFile(path); +} + +void LoadCache() +{ + WIN32_FIND_DATA FindFileData = {0}; + HANDLE hFind; + wchar_t searchs[2048] = {0}; + + buffer_map.clear(); + + StringCchPrintf(searchs, 2048, L"%s\\*.w5x",g_w_cachedir); + hFind = FindFirstFile(searchs, &FindFileData); + if ( hFind != INVALID_HANDLE_VALUE ) + { + do + { + wchar_t activefile[2048] = {0}; + StringCchPrintf(activefile, 2048, L"%s\\%s",g_w_cachedir,FindFileData.cFileName); + LoadCacheItem(activefile); + } while ( FindNextFile(hFind, &FindFileData) ); + FindClose(hFind); + } +} + +void SaveCache() +{ + BufferMap::iterator buffer_it; + DWORD start=0xABBACAFE; + for(buffer_it = buffer_map.begin();buffer_it != buffer_map.end(); buffer_it++) + { + time_t now = time(NULL); + if ( buffer_it->second->expire_time > now ) + { + wchar_t filename[2048] = {0}; + FILECACHETYPE cachefile; + HANDLE hFile; + INT64 size=0; + memset((void *)&cachefile,0,sizeof(FILECACHETYPE)); + cachefile.version = FILECACHEVERSION; + cachefile.expires = buffer_it->second->expire_time; + AutoChar charUrl(buffer_it->first.c_str()); + cachefile.urllen = strlen(charUrl)+1; + cachefile.datalen = buffer_it->second->getlen()+1; + + StringCchPrintf(filename, 2048, L"%s\\%08X.w5x",g_w_cachedir,start++); + hFile = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + WriteFile(hFile, &cachefile, sizeof(FILECACHETYPE),(LPDWORD)&size,NULL); + if ( size == sizeof(FILECACHETYPE) ) + { + char blank[2]="\0"; + size = 0; WriteFile(hFile, (char *)charUrl ,(DWORD)cachefile.urllen, (LPDWORD)&size, NULL); + size = 0; WriteFile(hFile, buffer_it->second->get() , (DWORD)buffer_it->second->getlen(), (LPDWORD)&size, NULL); + size = 0; WriteFile(hFile, blank , 1, (LPDWORD)&size, NULL); + } + else + { + CloseHandle(hFile); + hFile=NULL; + DeleteFile(filename); + } + } + if (hFile) + { + CloseHandle(hFile); + hFile=NULL; + } + } + } +} + +void initConfigCache() +{ + wchar_t iniFileName[2048] = {0}; + mediaLibrary.BuildPath(L"Plugins\\ml", iniFileName, 2048); + CreateDirectory(iniFileName, NULL); + mediaLibrary.BuildPath(L"Plugins\\ml\\cache", g_w_cachedir, 2048); + CreateDirectory(g_w_cachedir, NULL); + mediaLibrary.BuildPath(L"Plugins\\ml\\ml_online.ini", iniFileName, 2048); + AutoChar charFn(iniFileName); + g_config = new C_Config(AutoChar(iniFileName)); + + int x = g_config->ReadInt("maxbandwidth", MAXBANDWIDTH ); + g_config->WriteInt("maxbandwidth",x); + + x = g_config->ReadInt("minbandwidth",1); + g_config->WriteInt("minbandwidth",x); + + LoadCache(); +} + +static void Plugin_ExecuteOpenOnce() +{ + CHAR szBuffer[128] = {0}; + INT cchLen = Config_ReadStr("Navigation", "openOnce", NULL, szBuffer, ARRAYSIZE(szBuffer)); + if (0 != cchLen) + { + UINT serviceId; + if (FALSE != StrToIntExA(szBuffer, STIF_SUPPORT_HEX, (INT*)&serviceId)) + { + + cchLen = Config_ReadStr("Navigation", "openOnceMode", NULL, szBuffer, ARRAYSIZE(szBuffer)); + UINT showMode; + if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, NORM_IGNORECASE, "popup", -1, szBuffer, cchLen)) + showMode = SHOWMODE_POPUP; + else if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, NORM_IGNORECASE, "ensureVisible", -1, szBuffer, cchLen)) + showMode = SHOWMODE_ENSUREVISIBLE; + else + showMode = SHOWMODE_NORMAL; + + ServiceHelper_ShowService(serviceId, showMode); + } + + Config_WriteStr("Navigation", "openOnce", NULL); + Config_WriteStr("Navigation", "openOnceMode", NULL); + } +} + +static int Plugin_Init() +{ + if (FAILED(WasabiApi_Initialize(plugin.hDllInstance, plugin.service))) + return 1; + + if (FAILED(WasabiApi_LoadDefaults()) || + NULL == OMBROWSERMNGR || + NULL == OMSERVICEMNGR || + NULL == OMUTILITY) + { + WasabiApi_Release(); + return 2; + } + + ServiceHelper_Initialize(); + + if (NULL != WASABI_API_LNG) + { + static wchar_t szDescription[256]; + StringCchPrintf(szDescription, ARRAYSIZE(szDescription), + WASABI_API_LNGSTRINGW(IDS_PLUGIN_NAME), + PLUGIN_VERSION_MAJOR, PLUGIN_VERSION_MINOR); + plugin.description = (char*)szDescription; + } + + mediaLibrary.library = plugin.hwndLibraryParent; + mediaLibrary.winamp = plugin.hwndWinampParent; + mediaLibrary.instance = plugin.hDllInstance; + + winampVersion = mediaLibrary.GetWinampVersion(); + + omCOM.Publish(); + + Preferences_Register(); + + if (NULL == navigation) + { + if (FAILED(Navigation::CreateInstance(&navigation))) + { + navigation = NULL; + + if (NULL != unloadCallbacks) + { + size_t index = unloadCallbacks->size(); + while(index--) + unloadCallbacks->at(index)(); + delete(unloadCallbacks); + } + + Preferences_Unregister(); + WasabiApi_Release(); + return 3; + } + } + + initConfigCache(); + + Plugin_ExecuteOpenOnce(); + return ML_INIT_SUCCESS; +} + +static void Plugin_Quit() +{ + SaveCache(); + buffer_map.clear(); + + Plugin_UninitializeTimer(); + + if (NULL != navigation) + { + navigation->Finish(); + navigation->Release(); + navigation = NULL; + } + + if (NULL != unloadCallbacks) + { + size_t index = unloadCallbacks->size(); + while(index--) + unloadCallbacks->at(index)(); + delete(unloadCallbacks); + unloadCallbacks = NULL; + } + + Preferences_Unregister(); + + WasabiApi_Release(); +} + +static INT_PTR TitleHook(waHookTitleStructW *hookTitle) +{ + if (NULL == hookTitle || + NULL == hookTitle->filename) + { + return 0; + } + + Nullsoft::Utility::AutoLock lock(urlMapGuard); + // this is kinda slow but AOL Videos is so underused anyway that this map won't fill up much + URLMap::iterator itr; + for (itr=urlMap.begin();itr!=urlMap.end();itr++) + { + if (!_wcsnicmp(hookTitle->filename, itr->url.c_str(), itr->url_wcslen)) + { + if (NULL != hookTitle->title) + StringCchCopy(hookTitle->title, 2048, itr->title.c_str()); + + hookTitle->length = itr->length; + return 1; + } + } + + return 0; +} + +static INT_PTR MetadataHook(extendedFileInfoStructW *hookMetadata) +{ + if (NULL == hookMetadata || + NULL == hookMetadata->filename || + NULL == hookMetadata->metadata) + { + return 0; + } + + Nullsoft::Utility::AutoLock lock(urlMapGuard); + // this is kinda slow but AOL Videos is so underused anyway that this map won't fill up much + MetadataMap::iterator itr; + + for (itr=metadataMap.begin();itr!=metadataMap.end();itr++) + { + if (CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, hookMetadata->filename, -1, itr->url.c_str(), - 1) && + CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, hookMetadata->metadata, -1, itr->tag.c_str(), - 1)) + { + StringCchCopy(hookMetadata->ret, hookMetadata->retlen, itr->metadata.c_str()); + return 1; + } + } + return 0; +} + + +static INT_PTR Plugin_MessageProc(int msg, INT_PTR param1, INT_PTR param2, INT_PTR param3) +{ + INT_PTR result = 0; + if (NULL != navigation && + FALSE != navigation->ProcessMessage(msg, param1, param2, param3, &result)) + { + return result; + } + + switch (msg) + { + case ML_IPC_HOOKTITLEW: return TitleHook((waHookTitleStructW *)param1); + case ML_IPC_HOOKEXTINFOW: return MetadataHook((extendedFileInfoStructW *)param1); + case ML_MSG_CONFIG: Preferences_Show(); return TRUE; + } + + return FALSE; +} + + +void Plugin_RegisterUnloadCallback(PLUGINUNLOADCALLBACK callback) +{ + if (NULL == unloadCallbacks) + { + unloadCallbacks = new std::vector<PLUGINUNLOADCALLBACK>(); + if (NULL == unloadCallbacks) + return; + } + unloadCallbacks->push_back(callback); +} + + +extern "C" __declspec(dllexport) winampMediaLibraryPlugin *winampGetMediaLibraryPlugin() +{ + return &plugin; +} + +#if 0 +extern "C" __declspec( dllexport ) int winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param) { + + // prompt to remove our settings with default as no (just incase) + /*if(MessageBoxA(hwndDlg,"Do you also want to remove the saved settings for this plugin?", + plugin.description,MB_YESNO|MB_DEFBUTTON2) == IDYES) + { + WritePrivateProfileString("ml_rg", 0, 0, iniFile); + }*/ + + // also attempt to remove the ReplayGainAnalysis.dll so everything is kept cleaner + /*char path[MAX_PATH] = {0}; + GetModuleFileName(hDllInst, path, MAX_PATH); + PathRemoveFileSpec(path); + PathAppend(path, "ReplayGainAnalysis.dll"); + // if we get a handle then try to lower the handle count so we can delete + HINSTANCE rgLib = GetModuleHandle(path); + if(rgLib) + FreeLibrary(rgLib); + DeleteFile(path);*/ + + // allow an on-the-fly removal (since we've got to be with a compatible client build) + return ML_PLUGIN_UNINSTALL_NOW; + } +#endif
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Main.h b/Src/Plugins/Library/ml_online/Main.h new file mode 100644 index 00000000..5b6c887d --- /dev/null +++ b/Src/Plugins/Library/ml_online/Main.h @@ -0,0 +1,79 @@ +#ifndef NULLSOFT_MAINH +#define NULLSOFT_MAINH + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "../../General/gen_ml/ml.h" +#include "./common.h" + +#include <string> +#include <vector> +#include "../nu/AutoLock.h" + +#define PLUGIN_VERSION_MAJOR 2 +#define PLUGIN_VERSION_MINOR 03 + +HINSTANCE Plugin_GetInstance(void); +HWND Plugin_GetWinamp(void); +HWND Plugin_GetLibrary(void); + +class Navigation; +HRESULT Plugin_GetNavigation(Navigation **instance); + +typedef void (CALLBACK *PLUGINUNLOADCALLBACK)(void); +void Plugin_RegisterUnloadCallback(PLUGINUNLOADCALLBACK callback); + + +extern int winampVersion; + +#define MUTEX_T CRITICAL_SECTION +#define MUTEX_ENTER(n) EnterCriticalSection(&(n)) +#define MUTEX_LEAVE(n) LeaveCriticalSection(&(n)) +#define MUTEX_INIT(n) InitializeCriticalSection(&(n)) +#define MUTEX_DEL(n) DeleteCriticalSection(&(n)) + +#define FILECACHEVERSION 0x00000001 +typedef struct FileCacheType { + INT64 version; + INT64 expires; + INT64 urllen; + INT64 datalen; + INT64 resv1; // Future use, older versions MUST ignore + INT64 resv2; // Future use, older versions MUST ignore + INT64 resv3; // Future use, older versions MUST ignore + INT64 resv4; // Future use, older versions MUST ignore +} FileCacheType; +#define FILECACHETYPE FileCacheType + +struct url_info +{ + std::wstring url; + size_t url_wcslen; + std::wstring title; + int length; +} ; + +struct metadata_info +{ + std::wstring url; + std::wstring tag; + std::wstring metadata; +} ; + +typedef std::vector<url_info> URLMap; // just to save some typing & template code ugliness +typedef std::vector<metadata_info> MetadataMap; + + +extern URLMap urlMap; +extern MetadataMap metadataMap; + +extern Nullsoft::Utility::LockGuard urlMapGuard; + +typedef void (CALLBACK *PLUGINTIMERPROC)(UINT_PTR /*eventId*/, DWORD /*elapsedMs*/, ULONG_PTR /*data*/); +UINT_PTR Plugin_SetTimer(UINT elapseMs, PLUGINTIMERPROC callback, ULONG_PTR data); +void Plugin_KillTimer(UINT_PTR eventId); + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/OMCOM.cpp b/Src/Plugins/Library/ml_online/OMCOM.cpp new file mode 100644 index 00000000..8a00b456 --- /dev/null +++ b/Src/Plugins/Library/ml_online/OMCOM.cpp @@ -0,0 +1,821 @@ +#include "main.h" +#include "./omcom.h" +#include "./resource.h" +#include "./api__ml_online.h" + +#include "JnetCOM.h" + +#include "./navigation.h" +#include "./preferences.h" +#include "./serviceHelper.h" +#include "./serviceHost.h" +#include "./config.h" + +#include "../nu/ConfigCOM.h" +#include "../nu/MediaLibraryInterface.h" +#include "../nu/AutoChar.h" +#include "../nu/AutoWide.h" +#include "../nu/AutoUrl.h" + + +#include <ifc_omservice.h> +#include <ifc_omserviceeditor.h> +#include <ifc_omfilestorage.h> + + +#include "../Winamp/JSAPI.h" // IDispatch helper macros + +#include <shlwapi.h> +#include <strsafe.h> + +extern MediaLibraryInterface mediaLibrary; +extern C_Config *g_config; + +#define CONFIG_SERIALNUMBER "serialNumber" +#define SERIALNUMBER_INVALID ((INT)-1) +#define SERIALNUMBER_DEFAULT ((INT)0) + +enum +{ + DISPATCH_ISSUBSCRIBED = 12312, + DISPATCH_ADDSUBSCRIBED, + DISPATCH_CLEARSUBSCRIBED, + DISPATCH_SERIALNUMBER, + DISPATCH_JNETCREATE, + DISPATCH_GETWID, + DISPATCH_GETSID, + DISPATCH_PLAY, + DISPATCH_CONFIG, + DISPATCH_ENQUEUE, + DISPATCH_PREF, + DISPATCH_SETSIZE, + DISPATCH_GETX, + DISPATCH_GETY, + DISPATCH_NAVDISPLAY, + DISPATCH_FOCUSURL, + DISPATCH_SETCURRENTGUID, + DISPATCH_ADDTITLEHOOK, + DISPATCH_REMOVETITLEHOOK, + DISPATCH_ADDMETADATAHOOK, + DISPATCH_REMOVEMETADATAHOOK, + DISPATCH_SUBSCRIBE, +}; + + + +OMCOM::OMCOM() + : config(NULL), serialNumber(SERIALNUMBER_INVALID), publishCookie(0) +{ + +} + +OMCOM::~OMCOM() +{ + if (NULL != config) + config->Release(); + + if (0 != publishCookie) + { + SENDWAIPC(Plugin_GetWinamp(), IPC_REMOVE_DISPATCH_OBJECT, publishCookie); + publishCookie = NULL; + } +} + +HRESULT OMCOM::Publish() +{ + if (0 != publishCookie) + return E_FAIL; + + DispatchInfo dispatchInfo; + ZeroMemory(&dispatchInfo, sizeof(dispatchInfo)); + + dispatchInfo.name = L"OnMedia"; + dispatchInfo.dispatch = this; + + if (0 != SENDWAIPC(Plugin_GetWinamp(), IPC_ADD_DISPATCH_OBJECT, (WPARAM)&dispatchInfo)) + return E_FAIL; + + publishCookie = dispatchInfo.id; + return S_OK; +} + +HRESULT OMCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid) +{ + bool unknowns = false; + for (unsigned int i = 0;i != cNames;i++) + { + if (wcscmp(rgszNames[i], L"IsOmSubscribed") == 0) + rgdispid[i] = DISPATCH_ISSUBSCRIBED; + else if (wcscmp(rgszNames[i], L"AddOmSubscribed") == 0) + rgdispid[i] = DISPATCH_ADDSUBSCRIBED; + else if (wcscmp(rgszNames[i], L"ClearOmSubscribed") == 0) + rgdispid[i] = DISPATCH_CLEARSUBSCRIBED; + else if (wcscmp(rgszNames[i], L"OmSerialNumber") == 0) + rgdispid[i] = DISPATCH_SERIALNUMBER; + else if (wcscmp(rgszNames[i], L"JnetCreate") == 0) + rgdispid[i] = DISPATCH_JNETCREATE; + else if (wcscmp(rgszNames[i], L"GetUniqueID") == 0) + rgdispid[i] = DISPATCH_GETWID; + else if (wcscmp(rgszNames[i], L"GetSessionID") == 0) + rgdispid[i] = DISPATCH_GETSID; + else if (wcscmp(rgszNames[i], L"PlayUrl") == 0) + rgdispid[i] = DISPATCH_PLAY; + else if (wcscmp(rgszNames[i], L"Config") == 0) + rgdispid[i] = DISPATCH_CONFIG; + else if (wcscmp(rgszNames[i], L"EnqueueUrl") == 0) + rgdispid[i] = DISPATCH_ENQUEUE; + else if (wcscmp(rgszNames[i], L"ShowPreferences") == 0) + rgdispid[i] = DISPATCH_PREF; + else if (wcscmp(rgszNames[i], L"SetSize") == 0) + rgdispid[i] = DISPATCH_SETSIZE; + else if (wcscmp(rgszNames[i], L"GetX") == 0) + rgdispid[i] = DISPATCH_GETX; + else if (wcscmp(rgszNames[i], L"GetY") == 0) + rgdispid[i] = DISPATCH_GETY; + else if (wcscmp(rgszNames[i], L"DisplayNav") == 0) + rgdispid[i] = DISPATCH_NAVDISPLAY; + else if (wcscmp(rgszNames[i], L"FocusUrl") == 0) + rgdispid[i] = DISPATCH_FOCUSURL; + else if (wcscmp(rgszNames[i], L"SetCurrentGUID") == 0) + rgdispid[i] = DISPATCH_SETCURRENTGUID; + else if (wcscmp(rgszNames[i], L"AddTitleHook") == 0) + rgdispid[i] = DISPATCH_ADDTITLEHOOK; + else if (wcscmp(rgszNames[i], L"RemoveTitleHook") == 0) + rgdispid[i] = DISPATCH_REMOVETITLEHOOK; + else if (wcscmp(rgszNames[i], L"AddMetadataHook") == 0) + rgdispid[i] = DISPATCH_ADDMETADATAHOOK; + else if (wcscmp(rgszNames[i], L"RemoveMetadataHook") == 0) + rgdispid[i] = DISPATCH_REMOVEMETADATAHOOK; + else if (wcscmp(rgszNames[i], L"Subscribe") == 0) + rgdispid[i] = DISPATCH_SUBSCRIBE; + else + { + rgdispid[i] = DISPID_UNKNOWN; + unknowns = true; + } + } + if (unknowns) + return DISP_E_UNKNOWNNAME; + else + return S_OK; +} +HRESULT OMCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo) +{ + return E_NOTIMPL; +} + +HRESULT OMCOM::GetTypeInfoCount(unsigned int FAR * pctinfo) +{ + return E_NOTIMPL; +} + +#define VIDEO_GENFF_SIZEREQUEST (WM_USER+2048) +static void RemoveTitleHook(const wchar_t *url) +{ + Nullsoft::Utility::AutoLock lock(urlMapGuard); +DISPATCH_REMOVETITLEHOOK_again: + URLMap::iterator itr; + for (itr=urlMap.begin();itr!=urlMap.end();itr++) + { + if (CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, url, -1, itr->url.c_str(), - 1)) + { + urlMap.erase(itr); + goto DISPATCH_REMOVETITLEHOOK_again; + } + } +} + +static void RemoveMetadataHook(const wchar_t *url) +{ + Nullsoft::Utility::AutoLock lock(urlMapGuard); +DISPATCH_REMOVEMETADATAHOOK_again: + MetadataMap::iterator itr; + for (itr=metadataMap.begin();itr!=metadataMap.end();itr++) + { + if (CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, url, -1, itr->url.c_str(), - 1)) + { + metadataMap.erase(itr); + goto DISPATCH_REMOVEMETADATAHOOK_again; + } + } +} + +static void RemoveMetadataHook(const wchar_t *url, const wchar_t *tag) +{ + Nullsoft::Utility::AutoLock lock(urlMapGuard); +DISPATCH_REMOVEMETADATAHOOK_again2: + MetadataMap::iterator itr; + for (itr=metadataMap.begin();itr!=metadataMap.end();itr++) + { + if (CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, url, -1, itr->url.c_str(), - 1) && + CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, tag, -1, itr->tag.c_str(), - 1)) + { + metadataMap.erase(itr); + goto DISPATCH_REMOVEMETADATAHOOK_again2; + } + } +} + +HRESULT OMCOM::FindService(VARIANTARG *pArg, ifc_omservice **service) +{ + if (NULL == service) + return E_POINTER; + + *service = NULL; + if (NULL == pArg) + return E_INVALIDARG; + + HRESULT hr = E_INVALIDARG; + UINT serviceId; + + if (VT_BSTR == pArg->vt) + { + if (FALSE != StrToIntEx(pArg->bstrVal, STIF_SUPPORT_HEX, (INT*)&serviceId)) + hr = S_OK; + } + else if (VT_I4 == pArg->vt) + { + serviceId = pArg->lVal; + hr = S_OK; + } + + if (SUCCEEDED(hr)) + hr = ServiceHelper_Find(serviceId, service); + + return hr; +} +static HRESULT OmCom_AddServiceToNavigation(ifc_omservice *service) +{ + Navigation *navigation; + HRESULT hr = Plugin_GetNavigation(&navigation); + if (SUCCEEDED(hr)) + { + if (NULL != navigation->CreateItem(service)) + { + hr = S_OK; + } + else + { + hr = E_FAIL; + } + navigation->Release(); + } + return hr; +} + +static HRESULT OmCom_SubscribeToService(UINT serviceId, LPCWSTR pszName, LPCWSTR pszUrl, INT iconId) +{ + ifc_omservice *service = NULL; + HRESULT hr = ServiceHelper_Find(serviceId, &service); + if (FAILED(hr)) return hr; + + if (S_FALSE == hr) + { + ServiceHost *serviceHost; + if (FAILED(ServiceHost::GetCachedInstance(&serviceHost))) + serviceHost = NULL; + + if (NULL != OMSERVICEMNGR) + { + hr = OMSERVICEMNGR->CreateService(serviceId, serviceHost, &service); + } + else + hr = E_FAIL; + } + else if (S_OK == ServiceHelper_IsSubscribed(service)) + { + hr = S_FALSE; + } + + if (SUCCEEDED(hr)) + { + if (S_OK == hr) + { + ifc_omserviceeditor *editor; + hr = service->QueryInterface(IFC_OmServiceEditor, (void**)&editor); + if (SUCCEEDED(hr)) + { + if (NULL != pszName && L'\0' != *pszName) + editor->SetName(pszName, FALSE); + + if (NULL != pszUrl && L'\0' != *pszUrl) + editor->SetUrl(pszUrl, FALSE); + + WCHAR szIcon[256] = {0}; + if (SUCCEEDED(StringCchPrintf(szIcon, ARRAYSIZE(szIcon), L"%u", iconId))) + { + editor->SetIcon(szIcon, FALSE); + } + + hr = editor->SetFlags(SVCF_SUBSCRIBED, SVCF_SUBSCRIBED); + if (SUCCEEDED(hr)) + ServiceHelper_Save(service); + editor->Release(); + } + + if (SUCCEEDED(hr)) + OmCom_AddServiceToNavigation(service); + } + service->Release(); + } + + return hr; +} + +HRESULT OMCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr) +{ + if (dispid == DISPATCH_ADDTITLEHOOK) + { + if (pdispparams->cArgs == 3) + { + Nullsoft::Utility::AutoLock lock(urlMapGuard); + RemoveTitleHook(pdispparams->rgvarg[2].bstrVal); // ensure no duplicates + url_info info; + info.url = pdispparams->rgvarg[2].bstrVal; + info.url_wcslen = wcslen(info.url.c_str()); + info.title=pdispparams->rgvarg[1].bstrVal; + info.length= pdispparams->rgvarg[0].lVal; + urlMap.push_back(info); + return S_OK; + } + } + if (dispid == DISPATCH_REMOVETITLEHOOK) + { + if (pdispparams->cArgs == 1) + { + RemoveTitleHook(pdispparams->rgvarg[0].bstrVal); + return S_OK; + } + else + return DISP_E_BADPARAMCOUNT; + } + + if (dispid == DISPATCH_REMOVEMETADATAHOOK) + { + if (pdispparams->cArgs == 1) + { + RemoveMetadataHook(pdispparams->rgvarg[0].bstrVal); + return S_OK; + } + else if (pdispparams->cArgs == 2) + { + RemoveMetadataHook(pdispparams->rgvarg[1].bstrVal, pdispparams->rgvarg[0].bstrVal); + return S_OK; + } + else + return DISP_E_BADPARAMCOUNT; + } + + if (dispid == DISPATCH_ADDMETADATAHOOK) + { + if (pdispparams->cArgs == 3) + { + Nullsoft::Utility::AutoLock lock(urlMapGuard); + RemoveMetadataHook(pdispparams->rgvarg[2].bstrVal, pdispparams->rgvarg[1].bstrVal); // ensure no duplicates + metadata_info info; + info.url = pdispparams->rgvarg[2].bstrVal; + info.tag = pdispparams->rgvarg[1].bstrVal; + info.metadata= pdispparams->rgvarg[0].bstrVal; + metadataMap.push_back(info); + return S_OK; + } + } + + if (dispid == DISPATCH_SERIALNUMBER) + { + int serial = GetSerialNumber(FALSE); + if (pdispparams->cArgs == 1) + { + SetSerialNumber(pdispparams->rgvarg[0].lVal); + serial = GetSerialNumber(FALSE); + } + + JSAPI_INIT_RESULT(pvarResult, VT_I4); + JSAPI_SET_RESULT(pvarResult, lVal, serial); + return S_OK; + } + + if (dispid == DISPATCH_ADDSUBSCRIBED) + { + return AddOmSubscribed(wFlags, pdispparams, pvarResult, puArgErr); + } + + if (dispid == DISPATCH_SUBSCRIBE) + { + return Subscribe(wFlags, pdispparams, pvarResult, puArgErr); + } + + if (dispid == DISPATCH_CLEARSUBSCRIBED && pdispparams->cArgs == 1) + { + JSAPI_VERIFY_METHOD(wFlags); + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1); + JSAPI_INIT_RESULT(pvarResult, VT_I4); + + BOOL result = FALSE; + ifc_omservice *service; + if (S_OK == FindService(&JSAPI_PARAM(pdispparams, 1), &service)) + { + if (SUCCEEDED(ServiceHelper_Subscribe(service, FALSE, SHF_SAVE /* | SHF_NOTIFY*/))) + result = TRUE; + + service->Release(); + } + + JSAPI_SET_RESULT(pvarResult, lVal, result); + return S_OK; + } + + if (dispid == DISPATCH_ISSUBSCRIBED) + { + return IsOmSubscribed(wFlags, pdispparams, pvarResult, puArgErr); + } + + if (dispid == DISPATCH_JNETCREATE) + { + VariantInit(pvarResult); + V_VT(pvarResult) = VT_DISPATCH; + V_DISPATCH(pvarResult) = new JnetCOM(); + return S_OK; + } + + if (dispid == DISPATCH_GETWID) + { + WCHAR szBuffer[512] = {0}; + if (NULL == OMBROWSERMNGR || + FAILED(OMBROWSERMNGR->GetClientId(szBuffer, ARRAYSIZE(szBuffer)))) + { + szBuffer[0] = L'\0'; + } + + BSTR tag = SysAllocString(szBuffer); + VariantInit(pvarResult); + V_VT(pvarResult) = VT_BSTR; + V_BSTR(pvarResult) = tag; + + return S_OK; + } + + if (dispid == DISPATCH_GETSID) + { + WCHAR szBuffer[512] = {0}; + if (NULL == OMBROWSERMNGR || + FAILED(OMBROWSERMNGR->GetSessionId(szBuffer, ARRAYSIZE(szBuffer)))) + { + szBuffer[0] = L'\0'; + } + + BSTR tag = SysAllocString(szBuffer); + VariantInit(pvarResult); + V_VT(pvarResult) = VT_BSTR; + V_BSTR(pvarResult) = tag; + + return S_OK; + } + + if (dispid == DISPATCH_PLAY && pdispparams->cArgs == 1) + { + if (pdispparams->rgvarg[0].bstrVal) + mediaLibrary.PlayStream(pdispparams->rgvarg[0].bstrVal); + return S_OK; + } + + if (dispid == DISPATCH_PREF) + { + Preferences_Show(); + return S_OK; + } + + if (dispid == DISPATCH_CONFIG) + { + VariantInit(pvarResult); + if(NULL == config && FAILED(ConfigCOM::CreateInstanceA("ml_online_config", g_config->GetPath(), &config))) + { + V_VT(pvarResult) = VT_NULL; + } + else + { + V_VT(pvarResult) = VT_DISPATCH; + V_DISPATCH(pvarResult) = config; + config->AddRef(); + } + return S_OK; + } + + if (dispid == DISPATCH_ENQUEUE && pdispparams->cArgs == 1) + { + if (pdispparams->rgvarg[0].bstrVal) + mediaLibrary.EnqueueStream(pdispparams->rgvarg[0].bstrVal); + return S_OK; + } + + if (dispid == DISPATCH_SETSIZE && pdispparams->cArgs == 2) + { + HWND hView = NULL; + Navigation *navigation; + if (SUCCEEDED(Plugin_GetNavigation(&navigation))) + { + hView = navigation->GetActiveView(NULL); + navigation->Release(); + } + + if (NULL != hView && mediaLibrary.library && + GetParent(mediaLibrary.library) && + g_config->ReadInt("AutoSize",1)) + { + HWND hWnd; + bool GenFF = false; + if (GetParent(GetParent(mediaLibrary.library))) + { + hWnd = GetParent(GetParent(mediaLibrary.library)); + GenFF = true; + } + else + hWnd = GetParent(mediaLibrary.library); + + int width = pdispparams->rgvarg[1].lVal; + int height = pdispparams->rgvarg[0].lVal; + + RECT rc; + GetWindowRect(hView, &rc); // Our Html page + int WWidth = rc.right - rc.left; + int WHeight = rc.bottom - rc.top; + + GetWindowRect(hWnd, &rc); // Gen ML Size + int PWidth = rc.right - rc.left; + int PHeight = rc.bottom - rc.top; + + // Subtract the original window size from the parent(base) size + PWidth -= WWidth; + PHeight -= WHeight; + + // Add the target size to the parent(base) size + PWidth += width; + PHeight += height; + + if (GenFF) + { + SendMessage(hWnd, VIDEO_GENFF_SIZEREQUEST, PWidth, PHeight); + } + else + { + SetWindowPos(hWnd, 0, 0, 0, PWidth, PHeight, SWP_NOMOVE|SWP_ASYNCWINDOWPOS); + // weird? sometimes height isnt set if called once... + SetWindowPos(hWnd, 0, 0, 0, PWidth, PHeight, SWP_NOMOVE|SWP_ASYNCWINDOWPOS); + } + } + return S_OK; + } + + if (dispid == DISPATCH_GETX) + { + RECT rc; + HWND hView = NULL; + Navigation *navigation; + if (SUCCEEDED(Plugin_GetNavigation(&navigation))) + { + hView = navigation->GetActiveView(NULL); + navigation->Release(); + } + + if (NULL != hView) + { + GetWindowRect(hView, &rc); // Our Html page + int WWidth = rc.right - rc.left; + + if (pvarResult) + { + VariantInit(pvarResult); + V_VT(pvarResult) = VT_I4; + V_I4(pvarResult) = WWidth; + } + } + return S_OK; + } + + if (dispid == DISPATCH_GETY) + { + RECT rc; + HWND hView = NULL; + Navigation *navigation; + if (SUCCEEDED(Plugin_GetNavigation(&navigation))) + { + hView = navigation->GetActiveView(NULL); + navigation->Release(); + } + + if (NULL != hView) + { + GetWindowRect(hView, &rc); // Our Html page + int WHeight = rc.bottom - rc.top; + if (pvarResult) + { + VariantInit(pvarResult); + V_VT(pvarResult) = VT_I4; + V_I4(pvarResult) = WHeight; + } + } + return S_OK; + } + + if (dispid == DISPATCH_NAVDISPLAY && pdispparams->cArgs == 1) + { + //int visible = pdispparams->rgvarg[0].lVal; + return E_NOTIMPL; + } + + if (dispid == DISPATCH_FOCUSURL && pdispparams->cArgs == 2) + { + ifc_omservice *service; + if (S_OK == FindService(&pdispparams->rgvarg[1], &service)) + { + Navigation *navigation; + if (SUCCEEDED(Plugin_GetNavigation(&navigation))) + { + navigation->ShowService(service->GetId(), pdispparams->rgvarg[0].bstrVal); + navigation->Release(); + } + + service->Release(); + } + return S_OK; + } + + return DISP_E_MEMBERNOTFOUND; +} + +STDMETHODIMP OMCOM::QueryInterface(REFIID riid, PVOID *ppvObject) +{ + if (!ppvObject) + return E_POINTER; + else if (IsEqualIID(riid, IID_IDispatch)) + *ppvObject = (IDispatch *)this; + else if (IsEqualIID(riid, IID_IUnknown)) + *ppvObject = this; + else + { + *ppvObject = NULL; + return E_NOINTERFACE; + } + + AddRef(); + return S_OK; +} + +ULONG OMCOM::AddRef(void) +{ + return 0; +} + +ULONG OMCOM::Release(void) +{ + return 0; +} + +HRESULT OMCOM::IsOmSubscribed(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + JSAPI_VERIFY_METHOD(wFlags); + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1); + JSAPI_INIT_RESULT(pvarResult, VT_I4); + // 0 No knowledge , 1 Knowledge and Disabled, 2 Knowledge and Enabled + + ifc_omservice *service; + if (S_OK == FindService(&JSAPI_PARAM(pdispparams, 1), &service)) + { + JSAPI_SET_RESULT(pvarResult, lVal, (S_OK == ServiceHelper_IsSubscribed(service)) ? 2 : 1); + service->Release(); + } + else + { + JSAPI_SET_RESULT(pvarResult, lVal, 0); + } + + return S_OK; +} + +HRESULT OMCOM::AddOmSubscribed(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + JSAPI_VERIFY_METHOD(wFlags); + JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 3, 4); + + JSAPI_INIT_RESULT(pvarResult, VT_I4); + + LPCWSTR pszUrl, pszName; + UINT baseArg, serviceId, iconId; + + baseArg = 0; + + if (pdispparams->cArgs >= 4) + { + JSAPI_GETUNSIGNED_AS_NUMBER(iconId, pdispparams, (baseArg + 1), puArgErr); + baseArg++; + } + else + iconId = 0; + + JSAPI_GETUNSIGNED_AS_NUMBER(serviceId, pdispparams, (baseArg + 1), puArgErr); + JSAPI_GETSTRING(pszName, pdispparams, (baseArg + 2), puArgErr); + JSAPI_GETSTRING(pszUrl, pdispparams, (baseArg + 3), puArgErr); + + + + + INT result = OmCom_SubscribeToService(serviceId, pszName, pszUrl, iconId); + JSAPI_SET_RESULT(pvarResult, lVal, result); + + return S_OK; +} + +typedef int (*HTTPRETRIEVEFILEW)(HWND hwnd, char *url, wchar_t *file, wchar_t *dlgtitle); +HRESULT OMCOM::Subscribe(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + // window.external.OnMedia.Subscribe(String name, String url, String id, String icon, String version); + JSAPI_VERIFY_METHOD(wFlags); + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 5); + JSAPI_INIT_RESULT(pvarResult, VT_BOOL); + + WCHAR szBuffer[4096] = {0}; + LPCWSTR pszName, pszUrl, pszIcon; + UINT serviceId, version; + + JSAPI_GETSTRING(pszName, pdispparams, 1, puArgErr); + JSAPI_GETSTRING(pszUrl, pdispparams, 2, puArgErr); + JSAPI_GETUNSIGNED_AS_NUMBER(serviceId, pdispparams, 3, puArgErr); + JSAPI_GETNUMBER_AS_STRING(pszIcon, szBuffer, pdispparams, 4, puArgErr); + JSAPI_GETUNSIGNED_AS_NUMBER(version, pdispparams, 5, puArgErr); + + HRESULT hr; + ifc_omservice *service; + hr = ServiceHelper_Find(serviceId, &service); + if (S_OK != hr) + { + hr = ServiceHelper_Create(serviceId, pszName, pszIcon, pszUrl, SVCF_SUBSCRIBED | SVCF_PREAUTHORIZED, 2, TRUE, &service); + if (SUCCEEDED(hr)) + { + OmCom_AddServiceToNavigation(service); + service->Release(); + } + } + else + { + hr = ServiceHelper_Subscribe(service, TRUE, SHF_SAVE /*| SHF_NOTIFY*/); // do not call SHF_NOTIFY - or it will adjust stats + if (S_OK == hr) + OmCom_AddServiceToNavigation(service); + + service->Release(); + } + + JSAPI_SET_RESULT(pvarResult, boolVal, (SUCCEEDED(hr) ? VARIANT_TRUE : VARIANT_FALSE)); + return S_OK; +} + +HRESULT OMCOM::SetSerialNumber(INT sn) +{ + if (SERIALNUMBER_INVALID == sn) + return E_INVALIDARG; + + if (serialNumber == sn) + return S_FALSE; + + serialNumber = sn; + + CHAR szBuffer[64] = {0}; + HRESULT hr = StringCchPrintfA(szBuffer, ARRAYSIZE(szBuffer), "%d", serialNumber); + if (SUCCEEDED(hr)) + { + hr = Config_WriteStr(NULL, CONFIG_SERIALNUMBER, szBuffer); + } + + return hr; +} + +INT OMCOM::GetSerialNumber(BOOL fForceRead) +{ + if (FALSE != fForceRead || SERIALNUMBER_INVALID == serialNumber) + { + serialNumber = Config_ReadInt(NULL, CONFIG_SERIALNUMBER, SERIALNUMBER_DEFAULT); + } + return serialNumber; +} + +/* +HRESULT OMCOM::Login(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + // window.external.OnMedia.Login(String url); + JSAPI_VERIFY_METHOD(wFlags); + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1); + JSAPI_INIT_RESULT(pvarResult, VT_BOOL); + JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE); + const wchar_t *url = JSAPI_PARAM(pdispparams, 1).bstrVal; + HWND active_view = OmView_GetActive(); + if (active_view) + { + OmService *service = OmView_GetService(active_view); + if (service) + { + OMNAVIGATION->SelectService(service, url); + JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE); + } + } + return S_OK; +} +*/
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/OMCOM.h b/Src/Plugins/Library/ml_online/OMCOM.h new file mode 100644 index 00000000..07fbd5f3 --- /dev/null +++ b/Src/Plugins/Library/ml_online/OMCOM.h @@ -0,0 +1,43 @@ +#ifndef NULLSOFT_OMCOMH +#define NULLSOFT_OMCOMH + +#include <ocidl.h> + +class ConfigCOM; +class ifc_omservice; + +class OMCOM : public IDispatch +{ +public: + OMCOM(); + ~OMCOM(); + + STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject); + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + // *** IDispatch Methods *** + STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid); + STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo); + STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo); + STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr); + +private: + STDMETHOD (IsOmSubscribed)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr); + STDMETHOD (AddOmSubscribed)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr); + STDMETHOD (Subscribe)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr); + + HRESULT FindService(VARIANTARG *pArg, ifc_omservice **service); + +public: + INT GetSerialNumber(BOOL fForceRead); + HRESULT SetSerialNumber(INT sn); + HRESULT Publish(); + +protected: + ConfigCOM *config; + INT serialNumber; + UINT publishCookie; +}; + + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Preferences.cpp b/Src/Plugins/Library/ml_online/Preferences.cpp new file mode 100644 index 00000000..5bac3daf --- /dev/null +++ b/Src/Plugins/Library/ml_online/Preferences.cpp @@ -0,0 +1,110 @@ +#include "main.h" +#include "./preferences.h" + +#include "../winamp/wa_ipc.h" +#include "./resource.h" +#include "./api__ml_online.h" +#include "./config.h" + +#include <windows.h> +#include <shlobj.h> + +static prefsDlgRecW preferences; +extern C_Config *g_config; + +static INT_PTR CALLBACK Preferences_DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + +BOOL Preferences_Register() +{ + WCHAR szBuffer[256] = {0}; + WASABI_API_LNGSTRINGW_BUF(IDS_ONLINE_SERVICES, szBuffer, ARRAYSIZE(szBuffer)); + + preferences.hInst = WASABI_API_LNG_HINST; + preferences.dlgID = IDD_OMPREF; + preferences.proc = (void *)Preferences_DialogProc; + preferences.name = Plugin_CopyString(szBuffer); + preferences.where = 6; // Media Library + + return (BOOL)SENDWAIPC(Plugin_GetWinamp(), IPC_ADD_PREFS_DLGW, &preferences); + +} + +void Preferences_Unregister() +{ + SENDWAIPC(Plugin_GetWinamp(), IPC_REMOVE_PREFS_DLG, &preferences); + +} + +BOOL Preferences_Show() +{ + return (BOOL)SENDWAIPC(Plugin_GetWinamp(), IPC_OPENPREFSTOPAGE, &preferences); +} + +static INT_PTR CALLBACK Preferences_DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: + { + CheckDlgButton(hwndDlg,IDC_AUTOSIZE,g_config->ReadInt("AutoSize",1)); + + char tmp[64] = {0}; + wsprintfA(tmp,"%i",g_config->ReadInt("maxbandwidth", MAXBANDWIDTH )); + SetDlgItemTextA(hwndDlg,IDC_RADIO_MAXBW,tmp); + wsprintfA(tmp,"%i",g_config->ReadInt("minbandwidth",1)); + SetDlgItemTextA(hwndDlg,IDC_RADIO_MINBW,tmp); + int radiofreq=g_config->ReadInt("radio_upd_freq",0); + CheckDlgButton(hwndDlg,radiofreq==0?IDC_RADIO_HOURLY:radiofreq==1?IDC_RADIO_DAILY:radiofreq==2?IDC_RADIO_WEEKLY:IDC_RADIO_NEVER,BST_CHECKED); + SetDlgItemTextA(hwndDlg, IDC_NOWPLAYINGURL, g_config->ReadString("nowplayingurl","")); + } + break; + + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDC_AUTOSIZE: + g_config->WriteInt("AutoSize",IsDlgButtonChecked(hwndDlg,IDC_AUTOSIZE)); + break; + + case IDC_RADIO_NEVER: + case IDC_RADIO_DAILY: + case IDC_RADIO_WEEKLY: + case IDC_RADIO_HOURLY: + { + int radiofreq=0; + if(IsDlgButtonChecked(hwndDlg,IDC_RADIO_NEVER)) radiofreq=3; + if(IsDlgButtonChecked(hwndDlg,IDC_RADIO_DAILY)) radiofreq=1; + if(IsDlgButtonChecked(hwndDlg,IDC_RADIO_WEEKLY)) radiofreq=2; + if(IsDlgButtonChecked(hwndDlg,IDC_RADIO_HOURLY)) radiofreq=0; + g_config->WriteInt("radio_upd_freq",radiofreq); + } + break; + + case IDC_NOWPLAYINGURL: + if (HIWORD(wParam) == EN_CHANGE) + { + char nowplayingurl[1024] = {0}; + GetDlgItemTextA(hwndDlg, IDC_NOWPLAYINGURL, nowplayingurl, ARRAYSIZE(nowplayingurl)); + g_config->WriteString("nowplayingurl",nowplayingurl); + } + break; + } + break; + + case WM_DESTROY: + { + char tmp[64]={0,}; + GetDlgItemTextA(hwndDlg,IDC_RADIO_MAXBW,tmp,sizeof(tmp)-1); + int x = atoi(tmp); + if ( x < 2 ) x = 2; + g_config->WriteInt("maxbandwidth",x); + GetDlgItemTextA(hwndDlg,IDC_RADIO_MINBW,tmp,sizeof(tmp)-1); + int y = atoi(tmp); + if ( y < 1 ) y = 1; + if ( y > x ) y = x-1; + g_config->WriteInt("minbandwidth",y); + } + break; + } + return 0; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Preferences.h b/Src/Plugins/Library/ml_online/Preferences.h new file mode 100644 index 00000000..0fee936b --- /dev/null +++ b/Src/Plugins/Library/ml_online/Preferences.h @@ -0,0 +1,16 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_PREFERENCES_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_PREFERENCES_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +#define MAXBANDWIDTH 3500 + +BOOL Preferences_Register(); +void Preferences_Unregister(); +BOOL Preferences_Show(); + +#endif // NULLOSFT_ONLINEMEDIA_PLUGIN_PREFERENCES_HEADER diff --git a/Src/Plugins/Library/ml_online/Setup/SetupGroupFilter.h b/Src/Plugins/Library/ml_online/Setup/SetupGroupFilter.h new file mode 100644 index 00000000..feb4be24 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/SetupGroupFilter.h @@ -0,0 +1,91 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPGROUPFILTER_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPGROUPFILTER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include <vector> + +class ifc_omservice; + +class __declspec(novtable) SetupGroupFilter +{ +public: + typedef enum + { + serviceIgnore = 0x00000000, + serviceInclude = 0x00000001, + serviceForceSubscribe = 0x00000002, + serviceForceUnsubscribe = 0x00000004, + } FilterResult; +protected: + SetupGroupFilter(const GUID *filterId); + virtual ~SetupGroupFilter(); + +public: + static HRESULT CreateInstance(const GUID *filterId, SetupGroupFilter **instance); + +public: + virtual ULONG AddRef(); + virtual ULONG Release(); + + virtual HRESULT GetId(GUID *filterId); + + virtual HRESULT Initialize() = 0; + virtual HRESULT ProcessService(ifc_omservice *service, UINT *filterResult) = 0; + +protected: + typedef std::vector<UINT> ServiceIdList; + static BOOL CALLBACK AppendServiceIdCallback(UINT serviceId, void *data); + +protected: + ULONG ref; + GUID id; +}; + + +// {2F45FBDF-4372-4def-B20C-C6F1BAE5AE85} +static const GUID FUID_SetupFeaturedGroupFilter = +{ 0x2f45fbdf, 0x4372, 0x4def, { 0xb2, 0xc, 0xc6, 0xf1, 0xba, 0xe5, 0xae, 0x85 } }; + + +class SetupFeaturedGroupFilter : public SetupGroupFilter +{ +protected: + SetupFeaturedGroupFilter(); + ~SetupFeaturedGroupFilter(); +public: + static HRESULT CreateInstance(SetupFeaturedGroupFilter **instance); + +public: + HRESULT Initialize(); + HRESULT ProcessService(ifc_omservice *service, UINT *filterResult); + +protected: + ServiceIdList filterList; +}; + +// {7CA8722D-8B11-43a0-8F55-533C9DE3D73E} +static const GUID FUID_SetupKnownGroupFilter = +{ 0x7ca8722d, 0x8b11, 0x43a0, { 0x8f, 0x55, 0x53, 0x3c, 0x9d, 0xe3, 0xd7, 0x3e } }; + + +class SetupKnownGroupFilter : public SetupGroupFilter +{ +protected: + SetupKnownGroupFilter(); + ~SetupKnownGroupFilter(); +public: + static HRESULT CreateInstance(SetupKnownGroupFilter **instance); + +public: + HRESULT Initialize(); + HRESULT ProcessService(ifc_omservice *service, UINT *filterResult); + +protected: + ServiceIdList filterList; +}; + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPGROUPFILTER_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setup.cpp b/Src/Plugins/Library/ml_online/Setup/setup.cpp new file mode 100644 index 00000000..e8497306 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setup.cpp @@ -0,0 +1,71 @@ +#define GUID_DEFINE +#include "../../winamp/setup/svc_setup.h" +#undef GUID_DEFINE + +#include "./setupPage.h" + +#include "../api__ml_online.h" + + +static HRESULT Setup_RegisterPage() +{ + HRESULT hr; + svc_setup *setupSvc; + SetupPage *page; + + + if (FAILED(WasabiApi_LoadDefaults()) || + NULL == OMBROWSERMNGR || + NULL == OMSERVICEMNGR || + NULL == OMUTILITY) + { + return E_UNEXPECTED; + } + + setupSvc = QueryWasabiInterface(svc_setup, UID_SVC_SETUP); + if (NULL == setupSvc) + return E_POINTER; + + page = SetupPage::CreateInstance(); + if (NULL == page) + hr = E_OUTOFMEMORY; + else + { + // try to insert before 'feedback' (if present) + // otherwise dump at the end of the pages list. + int index = 0xFFFFF; + if (FAILED(setupSvc->GetPageCount(&index))) + index = 0xFFFFF; + else if (index > 0 && index == 3) + index--; + + hr = setupSvc->InsertPage(page, &index); + if (SUCCEEDED(hr)) + setupSvc->AddJob((ifc_setupjob*)page); + + page->Release(); + } + + ReleaseWasabiInterface(UID_SVC_SETUP, setupSvc); + + return hr; +} + +EXTERN_C _declspec(dllexport) BOOL RegisterSetup(HINSTANCE hInstance, api_service *waServices) +{ + // check the current date and if past November 30th 2013 + // then we will prevent the online page from being shown + time_t now = time(0); + struct tm *tn = localtime(&now); + tn->tm_sec = tn->tm_min = tn->tm_hour = 0; + + if (mktime(tn) >= 1387497600) + return FALSE; + + if (FAILED(WasabiApi_Initialize(hInstance, waServices))) + return FALSE; + + BOOL result = SUCCEEDED(Setup_RegisterPage()); + WasabiApi_Release(); + return result; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupDetails.cpp b/Src/Plugins/Library/ml_online/Setup/setupDetails.cpp new file mode 100644 index 00000000..5e1b7be2 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupDetails.cpp @@ -0,0 +1,80 @@ +#include "./common.h" +#include "./setupDetails.h" +#include "./setupServicePanel.h" + +EXTERN_C ATOM DETAILS_PROP = 0; +HMODULE hEditModule = NULL; + + +BOOL SetupDetails_Initialize() +{ + if (0 == DETAILS_PROP) + { + DETAILS_PROP = GlobalAddAtom(L"omSetupDetailsProp"); + if (0 == DETAILS_PROP) return FALSE; + } + + if (NULL == (hEditModule = LoadLibrary(L"riched20.dll"))) + return FALSE; + + return TRUE; +} + +void SetupDetails_Uninitialize() +{ + if (NULL != hEditModule) + { + FreeLibrary(hEditModule); + hEditModule = NULL; + } + + if (0 != DETAILS_PROP) + { + GlobalDeleteAtom(DETAILS_PROP); + DETAILS_PROP = 0; + } +} + +void SetupDetails_SetDescription(HWND hEdit, LPCWSTR pszText) +{ + SetWindowText(hEdit, pszText); + + DWORD originalStyle = GetWindowStyle(hEdit); + DWORD windowStyle = originalStyle & ~WS_VSCROLL; + + INT lineCount = (INT)SendMessage(hEdit, EM_GETLINECOUNT, 0, 0L); + if (lineCount > 0) + { + INT charIndex = (INT)SendMessage(hEdit, EM_LINEINDEX, (WPARAM)(lineCount - 1), 0L); + if (-1 != charIndex) + { + LRESULT result = SendMessage(hEdit, EM_POSFROMCHAR, charIndex, 0L); + POINTS pts = MAKEPOINTS(result); + RECT clientRect; + if (GetClientRect(hEdit, &clientRect) && pts.y > (clientRect.bottom - 14)) + { + windowStyle |= WS_VSCROLL; + } + } + } + + if (windowStyle != originalStyle) + { + SetWindowLongPtr(hEdit, GWL_STYLE, windowStyle); + SetWindowPos(hEdit, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED); + } + + ShowWindow(hEdit, SW_HIDE); + if (0 != ShowWindow(hEdit, (L'\0' != *pszText) ? SW_SHOWNA : SW_HIDE)) + InvalidateRect(hEdit, NULL, TRUE); +} + +HWND SetupDetails_CreateServiceView(HWND hParent, LPCWSTR pszName, ifc_omservice *service) +{ + return ServicePanel::CreateInstance(hParent, pszName, service, NULL); +} + +BOOL SetupDetails_GetUniqueName(HWND hwnd, LPWSTR pszBuffer, UINT cchBufferMax) +{ + return (BOOL)SendMessage(hwnd, NSDM_GETUNIQUENAME, (WPARAM)cchBufferMax, (LPARAM)pszBuffer); +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupDetails.h b/Src/Plugins/Library/ml_online/Setup/setupDetails.h new file mode 100644 index 00000000..2afd1b48 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupDetails.h @@ -0,0 +1,30 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPDETAILS_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPDETAILS_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +class ifc_omservice; +class SetupGroup; +class SetupListboxItem; + +#define NSDM_FIRST (WM_APP + 7) +#define NSDM_GETUNIQUENAME (NSDM_FIRST + 0) + +EXTERN_C ATOM DETAILS_PROP; + +BOOL SetupDetails_Initialize(); +void SetupDetails_Uninitialize(); + + +HWND SetupDetails_CreateServiceView(HWND hParent, LPCWSTR pszName, ifc_omservice *service); +HWND SetupDetails_CreateGroupView(HWND hParent, LPCWSTR pszName, SetupGroup *group); +BOOL SetupDetails_GetUniqueName(HWND hwnd, LPWSTR pszBuffer, UINT cchBufferMax); + +// internal +void SetupDetails_SetDescription(HWND hEdit, LPCWSTR pszText); + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPDETAILS_HEADER diff --git a/Src/Plugins/Library/ml_online/Setup/setupDetailsGroup.cpp b/Src/Plugins/Library/ml_online/Setup/setupDetailsGroup.cpp new file mode 100644 index 00000000..38ca9943 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupDetailsGroup.cpp @@ -0,0 +1,284 @@ +#include "./setupDetails.h" +#include "../common.h" +#include "../resource.h" +#include "../api__ml_online.h" + +#include "../../winamp/commandLink.h" +#include "./setupGroup.h" + +#include <commctrl.h> +#include <strsafe.h> + +#ifndef IDC_HELPLINK +#define IDC_HELPLINK 10000 +#endif + +struct GROUPDETAILSCREATEPARAM +{ + GROUPDETAILSCREATEPARAM() : group(NULL), name(NULL) {} + + SetupGroup *group; + LPCWSTR name; +}; + +struct GROUPDETAILS +{ + GROUPDETAILS() : group(NULL), name(NULL), fontTitle(NULL) {} + + SetupGroup *group; + LPWSTR name; + HFONT fontTitle; +}; + +#define GetDetails(__hwnd) ((GROUPDETAILS*)GetPropW((__hwnd), MAKEINTATOM(DETAILS_PROP))) + +static INT_PTR WINAPI GroupDetails_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +HWND SetupDetails_CreateGroupView(HWND hParent, LPCWSTR pszName, SetupGroup *group) +{ + GROUPDETAILSCREATEPARAM param; + param.group = group; + param.name = pszName; + return WASABI_API_CREATEDIALOGPARAMW(IDD_SETUP_GROUPDETAILS, hParent, GroupDetails_DialogProc, (LPARAM)¶m); +} + +static void GroupDetails_SetTitle(HWND hwnd, SetupGroup *group) +{ + HWND hTitle = GetDlgItem(hwnd, IDC_TITLE); + if (NULL == hTitle) return; + + WCHAR szBuffer[128] = {0}; + if (NULL == group || + FAILED(group->GetLongName(szBuffer, ARRAYSIZE(szBuffer)))) + { + szBuffer[0] = L'\0'; + } + + GROUPDETAILS *details = GetDetails(hwnd); + if (NULL != details && NULL == details->fontTitle) + { + HFONT dialogFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L); + LOGFONT lf; + if (0 != GetObject(dialogFont, sizeof(LOGFONT), &lf)) + { + StringCchCopy(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), L"Arial Bold"); + lf.lfWidth = 0; + lf.lfWeight = FW_DONTCARE; + lf.lfHeight += (lf.lfHeight < 0) ? -2 : +2; + lf.lfQuality = 5/*ANTIALIASED_QUALITY*/; + details->fontTitle = CreateFontIndirect(&lf); + } + + if (NULL != details->fontTitle) + { + SendMessage(hTitle, WM_SETFONT, (WPARAM)details->fontTitle, 0L); + } + } + + SetWindowText(hTitle, szBuffer); + InvalidateRect(hTitle, NULL, TRUE); +} + +static void GroupDetails_SetDescription(HWND hwnd, SetupGroup *group) +{ + HWND hDescription = GetDlgItem(hwnd, IDC_DESCRIPTION); + if (NULL == hDescription) return; + + WCHAR szBuffer[4096] = {0}; + if (NULL == group || + FAILED(group->GetDescription(szBuffer, ARRAYSIZE(szBuffer)))) + { + szBuffer[0] = L'\0'; + } + + SetupDetails_SetDescription(hDescription, szBuffer); +} + +static BOOL GroupDetails_ShowHelp(HWND hwnd) +{ + INT result = (INT)(INT_PTR)ShellExecuteW(hwnd, L"open", + L"https://help.winamp.com/hc/articles/8112753225364-Online-Services-Security", + NULL, NULL, SW_SHOWNORMAL); + return (result > 32); +} + +static void GroupDetails_UpdateLayout(HWND hwnd, BOOL fRedraw) +{ + RECT clientRect, rect; + if(FALSE == GetClientRect(hwnd, &clientRect)) + return; + + + UINT commonFlags = SWP_NOACTIVATE | SWP_NOZORDER; + if (FALSE != fRedraw) commonFlags |= SWP_NOREDRAW; + + LONG bottomLine = clientRect.bottom; + + HWND hControl; + SIZE linkSize; + RECT linkMargins; + + if (NULL != (hControl = GetDlgItem(hwnd, IDC_HELPLINK)) && + CommandLink_GetIdealSize(hControl, &linkSize)) + { + if (!CommandLink_GetMargins(hControl, &linkMargins)) + SetRectEmpty(&linkMargins); + + if (linkSize.cy > 0) + bottomLine -= linkSize.cy; + + SetWindowPos(hControl, NULL, clientRect.left + 4, bottomLine, linkSize.cx, linkSize.cy, commonFlags); + } + else + { + ZeroMemory(&linkSize, sizeof(linkSize)); + SetRectEmpty(&linkMargins); + } + + if (NULL != (hControl = GetDlgItem(hwnd, IDC_HELPTEXT))) + { + LONG x = clientRect.left + 4 + linkSize.cx/* - linkMargins.right*/; + LONG y = 0; + + HDC hdc = GetDCEx(hControl, NULL, DCX_CACHE | DCX_WINDOW | DCX_NORESETATTRS); + if (NULL != hdc) + { + HFONT font = (HFONT)SendMessage(hControl, WM_GETFONT, 0, 0L); + HFONT originalFont = (HFONT)SelectObject(hdc, font); + + TEXTMETRICW tm; + if (GetTextMetricsW(hdc, &tm)) + y = tm.tmHeight; + + SelectObject(hdc, originalFont); + ReleaseDC(hControl, hdc); + } + + SetWindowPos(hControl, NULL, x, clientRect.bottom - linkMargins.bottom - y, clientRect.right - x, y, commonFlags); + } + + if (NULL != (hControl = GetDlgItem(hwnd, IDC_DESCRIPTION)) && + FALSE != GetWindowRect(hControl, &rect)) + { + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rect, 2); + SetWindowPos(hControl, NULL, rect.left, rect.right, rect.right - rect.left, bottomLine - rect.top, + commonFlags | SWP_NOMOVE); + } +} + +static INT_PTR GroupDetails_OnInitDialog(HWND hwnd, HWND hFocus, LPARAM lParam) +{ + GROUPDETAILSCREATEPARAM *param = (GROUPDETAILSCREATEPARAM*)lParam; + + GROUPDETAILS *details = (GROUPDETAILS*)calloc(1, sizeof(GROUPDETAILS)); + if (NULL == details) return FALSE; + + if (!SetProp(hwnd, MAKEINTATOM(DETAILS_PROP), details)) + return FALSE; + + if (NULL != param) + { + if (NULL != param->group) + { + details->group = param->group; + details->group->AddRef(); + } + + details->name = Plugin_CopyString(param->name); + } + + HINSTANCE winampInstance = (NULL != WASABI_API_APP) ? WASABI_API_APP->main_gethInstance() : NULL; + if (NULL != winampInstance) + { + WCHAR szBuffer[256] = {0}; + WASABI_API_LNGSTRINGW_BUF(IDS_CLICKHERE, szBuffer, ARRAYSIZE(szBuffer)); + HWND hLink = CreateWindowExW(WS_EX_NOPARENTNOTIFY | WS_EX_TRANSPARENT, NWC_COMMANDLINKW, szBuffer, + WS_VISIBLE | WS_CHILD | WS_TABSTOP | CLS_ALWAYSUNDERLINE | CLS_DEFAULTCOLORS /* | CLS_HOTTRACK */, + 0, 0, 0, 0, hwnd, (HMENU)IDC_HELPLINK, winampInstance, NULL); + + if (NULL != hLink) + { + SendMessageW(hLink, WM_SETFONT, (WPARAM)SendMessageW(hwnd, WM_GETFONT, 0, 0L), 0L); + } + } + + GroupDetails_UpdateLayout(hwnd, FALSE); + + if (NULL != param) + { + GroupDetails_SetTitle(hwnd, param->group); + GroupDetails_SetDescription(hwnd, param->group); + } + + return FALSE; +} + +static void GroupDetails_OnDestroy(HWND hwnd) +{ + GROUPDETAILS *details = GetDetails(hwnd); + RemoveProp(hwnd, MAKEINTATOM(DETAILS_PROP)); + + if (NULL != details) + { + if (NULL != details->group) + details->group->Release(); + if (NULL != details->fontTitle) + DeleteObject(details->fontTitle); + + Plugin_FreeString(details->name); + } +} + + +static INT_PTR GroupDetails_OnDialogColor(HWND hwnd, HDC hdc, HWND hControl) +{ + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if (NULL != hParent && hParent != hwnd) + return (INT_PTR)SendMessage(hParent, WM_CTLCOLORDLG, (WPARAM)hdc, (LPARAM)hControl); + return 0; +} + + +static INT_PTR GroupDetails_OnStaticColor(HWND hwnd, HDC hdc, HWND hControl) +{ + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if (NULL != hParent && hParent != hwnd) + return (INT_PTR)SendMessage(hParent, WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hControl); + return 0; +} + +static LRESULT GroupDetails_OnNotify(HWND hwnd, INT controlId, NMHDR *pnmh) +{ + switch(controlId) + { + case IDC_HELPLINK: + if (NM_CLICK == pnmh->code) + GroupDetails_ShowHelp(hwnd); + return TRUE; + } + return 0; +} + +static BOOL GroupDetails_OnGetUniqueName(HWND hwnd, LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer) + return FALSE; + + GROUPDETAILS *details = GetDetails(hwnd); + return SUCCEEDED(StringCchCopy(pszBuffer, cchBufferMax, + (NULL != details && NULL != details->name) ? details->name : L"")); +} +static INT_PTR WINAPI GroupDetails_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: return GroupDetails_OnInitDialog(hwnd, (HWND)wParam, lParam); + case WM_DESTROY: GroupDetails_OnDestroy(hwnd); break; + case WM_CTLCOLORDLG: return GroupDetails_OnDialogColor(hwnd, (HDC)wParam, (HWND)lParam); + case WM_CTLCOLORSTATIC: return GroupDetails_OnStaticColor(hwnd, (HDC)wParam, (HWND)lParam); + case WM_NOTIFY: MSGRESULT(hwnd, GroupDetails_OnNotify(hwnd, (INT)wParam, (NMHDR*)lParam)); + + case NSDM_GETUNIQUENAME: MSGRESULT(hwnd, GroupDetails_OnGetUniqueName(hwnd, (LPWSTR)lParam, (UINT)wParam)); + } + return 0; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupDetailsService.cpp b/Src/Plugins/Library/ml_online/Setup/setupDetailsService.cpp new file mode 100644 index 00000000..3e3907fa --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupDetailsService.cpp @@ -0,0 +1,596 @@ +#include "./setupDetails.h" +#include "../common.h" +#include "../resource.h" +#include "../wasabi.h" + +#include <ifc_omservice.h> +#include <ifc_omservicedetails.h> +#include <ifc_omcachemanager.h> +#include <ifc_omserviceevent.h> +#include <ifc_omcachegroup.h> +#include <ifc_omcacherecord.h> +#include <ifc_imageloader.h> +#include <ifc_omgraphics.h> +#include <ifc_omserviceeventmngr.h> + +#include <shlwapi.h> +#include <strsafe.h> + + + +#define GetPanel(__hwnd) ((ServicePanel*)GetPropW((__hwnd), MAKEINTATOM(DETAILS_PROP))) + +#define GET_IDETAILS(__service, __details)\ + (NULL != (service) && SUCCEEDED((service)->QueryInterface(IFC_OmServiceDetails, (void**)&(__details)))) + +static INT_PTR WINAPI ServicePanel_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + + + +HWND OmSetupDetails_CreateServiceView(HWND hParent, ifc_omservice *service) +{ + return WASABI_API_CREATEDIALOGPARAMW(IDD_SETUP_SERVICEDETAILS, hParent, ServicePanel_DialogProc, (LPARAM)service); +} + +static HFONT ServicePanel_PickTitleFont(HWND hwnd, LPCWSTR pszTitle, INT cchTitle, INT maxWidth) +{ + HFONT dialogFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L); + + LOGFONT lf; + if (0 == GetObject(dialogFont, sizeof(LOGFONT), &lf)) + return NULL; + + HFONT titleFont = NULL; + if (cchTitle > 0) + { + LOGFONT lf; + if (0 != GetObject(dialogFont, sizeof(LOGFONT), &lf)) + { + StringCchCopy(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), L"Arial Bold"); + lf.lfWidth = 0; + lf.lfWeight = FW_DONTCARE; + lf.lfQuality = 5/*ANTIALIASED_QUALITY*/; + + HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL != hdc) + { + HFONT origFont = (HFONT)GetCurrentObject(hdc, OBJ_FONT); + SIZE textSize; + + INT heightLimit = (lf.lfHeight < 0) ? 1 : -1; + lf.lfHeight += (lf.lfHeight < 0) ? -2 : +2; + do + { + textSize.cx = 0; + if (NULL != titleFont) DeleteObject(titleFont); + titleFont = CreateFontIndirect(&lf); + if (NULL != titleFont) + { + SelectObject(hdc, titleFont); + GetTextExtentPoint32(hdc, pszTitle, cchTitle, &textSize); + } + lf.lfHeight += (lf.lfHeight < 0) ? 1 : -1; + + } while(textSize.cx > maxWidth && lf.lfHeight != heightLimit); + + if (0 == textSize.cx) + { + DeleteObject(titleFont); + titleFont = NULL; + } + + SelectObject(hdc, origFont); + ReleaseDC(hwnd, hdc); + } + } + } + + if (NULL == titleFont && + 0 != GetObject(dialogFont, sizeof(LOGFONT), &lf)) + { + titleFont = CreateFontIndirect(&lf); + } + return titleFont; +} + +static void ServicePanel_SetServiceName(HWND hwnd, ifc_omservice *service) +{ + HWND hTitle = GetDlgItem(hwnd, IDC_TITLE); + if (NULL == hTitle) return; + + WCHAR szBuffer[128]; + if (NULL == service || + FAILED(service->GetName(szBuffer, ARRAYSIZE(szBuffer)))) + { + szBuffer[0] = L'\0'; + } + + + + SERVICEDETAILS *details = GetDetails(hwnd); + if (NULL != details) + { + INT cchBuffer = lstrlen(szBuffer); + RECT rc; + GetClientRect(hTitle, &rc); + HFONT titleFont = ServicePanel_PickTitleFont(hwnd, szBuffer, cchBuffer, rc.right - rc.left); + if (NULL != titleFont) + { + if (NULL != details->fontTitle) DeleteObject(details->fontTitle); + details->fontTitle = titleFont; + SendMessage(hTitle, WM_SETFONT, (WPARAM)details->fontTitle, 0L); + } + } + + SetWindowText(hTitle, szBuffer); + InvalidateRect(hTitle, NULL, TRUE); +} + + +static void ServicePanel_SetServiceDescription(HWND hwnd, ifc_omservice *service) +{ + HWND hDescription = GetDlgItem(hwnd, IDC_DESCRIPTION); + if (NULL == hDescription) return; + + WCHAR szBuffer[4096] = {0}; + + ifc_omservicedetails *details = 0; + if (GET_IDETAILS(service, details)) + { + details->GetDescription(szBuffer, ARRAYSIZE(szBuffer)); + details->Release(); + } + + OmSetupDetails_SetDescription(hDescription, szBuffer); +} + +static LPCWSTR ServicePanel_FormatDate(LPCWSTR pszDate, LPWSTR pszBuffer, INT cchBufferMax) +{ + SYSTEMTIME st; + ZeroMemory(&st, sizeof(SYSTEMTIME)); + LPCWSTR cursor; + + cursor = pszDate; + INT index = 0; + + for(;;) + { + + INT iVal; + + if (FALSE == StrToIntEx(cursor, STIF_DEFAULT, &iVal) || iVal < 1) + { + index = 0; + break; + } + + if (0 == index) + { + if (iVal < 2000 || iVal > 2100) + break; + st.wYear = iVal; + index++; + } + else if (1 == index) + { + if (iVal < 1 || iVal > 12) + break; + st.wMonth = iVal; + index++; + } + else if (2 == index) + { + if (iVal < 1 || iVal > 31) + break; + st.wDay = iVal; + index++; + } + else + { + index = 0; + break; + } + + while(L'\0' != *cursor && L'-' != *cursor) cursor++; + if (L'-' == *cursor) cursor++; + if (L'\0' == *cursor) + break; + + } + + if (3 == index && + 0 != GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, pszBuffer, cchBufferMax)) + { + return pszBuffer; + } + + return pszDate; +} + + + +static HRESULT ServicePanel_GetFullName(ifc_omservicedetails *details, LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer) + return E_POINTER; + + *pszBuffer = L'\0'; + + HRESULT hr = S_OK; + if (NULL != details) + { + hr = details->GetAuthorFirst(pszBuffer, cchBufferMax); + if (SUCCEEDED(hr)) + { + UINT cchBuffer = lstrlen(pszBuffer); + LPWSTR cursor = pszBuffer + cchBuffer; + size_t remaining = cchBufferMax - cchBuffer; + + if (cursor != pszBuffer) + { + hr = StringCchCopyEx(cursor, remaining, L" ", &cursor, &remaining, 0); + if (SUCCEEDED(hr)) + { + hr = details->GetAuthorLast(cursor, (UINT)remaining); + if (FAILED(hr) || L'\0' == *cursor) + { + pszBuffer[cchBuffer] = L'\0'; + } + } + } + } + } + return hr; +} + +static void ServicePanel_SetServiceMeta(HWND hwnd, ifc_omservice *service) +{ + HWND hMeta = GetDlgItem(hwnd, IDC_SERVICEMETA); + if (NULL == hMeta) return; + + WCHAR szBuffer[512] = {0}; + + ifc_omservicedetails *svcdetails = 0; + if (GET_IDETAILS(service, svcdetails)) + { + HRESULT hr = S_OK; + LPWSTR cursor = szBuffer; + WCHAR szValue[256] = {0}, szPrefix[64] = {0}; + size_t remaining = ARRAYSIZE(szBuffer); + + if (SUCCEEDED(ServicePanel_GetFullName(svcdetails, szValue, ARRAYSIZE(szValue))) && L'\0' != szValue[0]) + { + WASABI_API_LNGSTRINGW_BUF(IDS_SERVICE_BYAUTHOR, szPrefix, ARRAYSIZE(szPrefix)); + hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, + L"%s%s", szPrefix, szValue); + } + + if (SUCCEEDED(svcdetails->GetUpdated(szValue, ARRAYSIZE(szValue))) && L'\0' != szValue[0]) + { + if (cursor != szBuffer) + hr = StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE); + + if (SUCCEEDED(hr)) + { + WCHAR szDate[128] = {0}; + WASABI_API_LNGSTRINGW_BUF(IDS_SERVICE_LASTUPDATED, szPrefix, ARRAYSIZE(szPrefix)); + StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, + L"%s%s", szPrefix, ServicePanel_FormatDate(szValue, szDate, ARRAYSIZE(szDate))); + } + } + + svcdetails->Release(); + + } + + SERVICEDETAILS *details = GetDetails(hwnd); + if (NULL != details && NULL == details->fontMeta) + { + HFONT dialogFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L); + LOGFONT lf; + if (0 != GetObject(dialogFont, sizeof(LOGFONT), &lf)) + { + StringCchCopy(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), L"Tahoma"); + lf.lfWidth = 0; + lf.lfHeight += (lf.lfHeight < 0) ? 1 : -1; + lf.lfQuality = ANTIALIASED_QUALITY; + details->fontMeta = CreateFontIndirect(&lf); + } + + if (NULL != details->fontMeta) + { + SendMessage(hMeta, WM_SETFONT, (WPARAM)details->fontMeta, 0L); + } + } + + SetWindowText(hMeta, szBuffer); + if (0 != ShowWindow(hMeta, (L'\0' != szBuffer[0]) ? SW_SHOWNA : SW_HIDE)) + InvalidateRect(hMeta, NULL, TRUE); +} + +static void ServicePanel_SetThumbnail(HWND hwnd, ifc_omservice *service) +{ + HWND hThumbnail = GetDlgItem(hwnd, IDC_THUMBNAIL); + if (NULL == hThumbnail) return; + + SendMessage(hThumbnail, WM_SETREDRAW, FALSE, 0L); + + HBITMAP hBitmap; + + BITMAPINFOHEADER header; + void *pixelData; + + WCHAR szPath[2048]; + + ifc_omservicedetails *details = 0; + if (GET_IDETAILS(service, details)) + { + if (SUCCEEDED(details->GetThumbnail(szPath, ARRAYSIZE(szPath)))) + { + ifc_omcachemanager *cacheManager; + if (SUCCEEDED(OMUTILITY->GetCacheManager(&cacheManager))) + { + ifc_omcachegroup *cacheGroup; + if (SUCCEEDED(cacheManager->Find(L"thumbnail", TRUE, &cacheGroup, NULL))) + { + ifc_omcacherecord *cacheRecord; + if (SUCCEEDED(cacheGroup->Find(szPath, TRUE, &cacheRecord, FALSE))) + { + cacheRecord->Release(); + } + cacheGroup->Release(); + } + cacheManager->Release(); + } + } + details->Release(); + } + + ifc_omimageloader *imageLoader; + if (SUCCEEDED(OMUTILITY->QueryImageLoader(NULL, szPath, FALSE, &imageLoader))) + { + if (FAILED(imageLoader->LoadBitmapEx(&hBitmap, &header, &pixelData))) + hBitmap = NULL; + imageLoader->Release(); + } + + if (NULL == hBitmap && + SUCCEEDED(OMUTILITY->QueryImageLoader(WASABI_API_ORIG_HINST, MAKEINTRESOURCE(IDR_SERVICE64X64_IMAGE), FALSE, &imageLoader))) + { + if (FAILED(imageLoader->LoadBitmapEx(&hBitmap, &header, &pixelData))) + hBitmap = NULL; + imageLoader->Release(); + } + + HBITMAP hTest = (HBITMAP)SendMessage(hThumbnail, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap); + if (NULL != hTest) + DeleteObject(hTest); + + if (NULL != hBitmap) + { + hTest = (HBITMAP)SendMessage(hThumbnail, STM_GETIMAGE, IMAGE_BITMAP, 0L); + if (hTest != hBitmap) + { // this is XP and up image copy was created and alpha channel will be handled properly + DeleteObject(hBitmap); + } + else + { // fix alpha channel + if (32 == header.biBitCount) + { + HDC hdcFixed = CreateCompatibleDC(NULL); + if (NULL != hdcFixed) + { + BITMAPINFOHEADER headerFixed; + CopyMemory(&headerFixed, &header, sizeof(BITMAPINFOHEADER)); + BYTE *pixelsFixed; + INT cx = header.biWidth; + INT cy = abs(header.biHeight); + HBITMAP bitmapFixed = CreateDIBSection(NULL, (LPBITMAPINFO)&headerFixed, DIB_RGB_COLORS, (void**)&pixelsFixed, NULL, 0); + + if (NULL != bitmapFixed) + { + HBITMAP bitmapOrig = (HBITMAP)SelectObject(hdcFixed, bitmapFixed); + HBRUSH hb = (HBRUSH)SendMessage(hwnd, WM_CTLCOLORDLG, (WPARAM)hdcFixed, (LPARAM)hwnd); + if (NULL == hb) + hb = GetSysColorBrush(COLOR_3DFACE); + RECT rect; + SetRect(&rect, 0, 0, cx, cy); + FillRect(hdcFixed, &rect, hb); + + ifc_omgraphics *graphics; + if (SUCCEEDED(OMUTILITY->GetGraphics(&graphics))) + { + HDC hdcSrc = CreateCompatibleDC(NULL); + if (NULL != hdcSrc) + { + HBITMAP bitmapSrcOrig = (HBITMAP)SelectObject(hdcSrc, hBitmap); + BLENDFUNCTION bf; + bf.BlendOp = AC_SRC_OVER; + bf.BlendFlags = 0; + bf.SourceConstantAlpha = 0xFF; + bf.AlphaFormat = AC_SRC_ALPHA; + + RECT blendRect; + SetRect(&blendRect, 0, 0, cx, cy); + + graphics->Premultiply((BYTE*)pixelData, cx, cy); + graphics->AlphaBlend(hdcFixed, &blendRect, hdcSrc, &blendRect, bf); + + SelectObject(hdcSrc, bitmapSrcOrig); + DeleteDC(hdcSrc); + } + graphics->Release(); + } + + SelectObject(hdcFixed, bitmapOrig); + SendMessage(hThumbnail, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)bitmapFixed); + DeleteObject(hBitmap); + + } + DeleteDC(hdcFixed); + } + } + } + } + + RECT clientRect; + if (GetClientRect(hThumbnail, &clientRect)) + { + INT cx = clientRect.right - clientRect.left; + INT cy = clientRect.bottom - clientRect.top; + if (64 != cx || 64 != cy) + { + SetWindowPos(hThumbnail, NULL, 0, 0, 64, 64, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER); + } + } + + SendMessage(hThumbnail, WM_SETREDRAW, TRUE, 0L); + + if (0 != ShowWindow(hThumbnail, (NULL != hBitmap) ? SW_SHOWNA : SW_HIDE)) + InvalidateRect(hThumbnail, NULL, TRUE); +} + + +static void CALLBACK ServicePanel_OnServiceNotify(UINT serviceUid, UINT callbackType, UINT callbackParam, ULONG_PTR user) +{ + HWND hwnd = (HWND)user; + if (NULL == hwnd) return; + + SERVICEDETAILS *details = GetDetails(hwnd); + + if (NULL == details || + NULL == details->service || + serviceUid != details->service->GetId()) + { + return; + } + + switch(callbackType) + { + case OmService::eventServiceModified: + if (0 != (OmService::modifiedName & callbackParam)) + ServicePanel_SetServiceName(hwnd, details->service); + if (0 != (OmService::modifiedDescription & callbackParam)) + ServicePanel_SetServiceDescription(hwnd, details->service); + if (0 != ((OmService::modifiedAuthor | OmService::modifiedDate) & callbackParam)) + ServicePanel_SetServiceMeta(hwnd, details->service); + if (0 != (OmService::modifiedThumbnail & callbackParam)) + ServicePanel_SetThumbnail(hwnd, details->service); + break; + } +} + +static INT_PTR ServicePanel_OnInitDialog(HWND hwnd, HWND hFocus, LPARAM lParam) +{ + ifc_omservice *service = (ifc_omservice*)lParam; + + SERVICEDETAILS *details = (SERVICEDETAILS*)malloc(sizeof(SERVICEDETAILS)); + if (NULL == details) return FALSE; + ZeroMemory(details, sizeof(SERVICEDETAILS)); + + if (!SetProp(hwnd, MAKEINTATOM(DETAILS_PROP), details)) + return FALSE; + + details->service = service; + details->service->AddRef(); + + ServicePanel_SetServiceName(hwnd, service); + ServicePanel_SetServiceDescription(hwnd, service); + ServicePanel_SetThumbnail(hwnd, service); + ServicePanel_SetServiceMeta(hwnd, service); + + if (NULL != service) + { + ifc_omserviceeventmngr *eventManager; + if (SUCCEEDED(service->GetEventManager(&eventManager))) + { + if (SUCCEEDED(eventManager->RegisterHandler(eventHander))) + { + details->eventHandler = eventHandler; + } + else + { + eventHandler->Release(); + } + } + } + + return FALSE; +} + +static void ServicePanel_OnDestroy(HWND hwnd) +{ + OMSERVICEMNGR->UnregisterCallback(ServicePanel_OnServiceNotify, (ULONG_PTR)hwnd); + + SERVICEDETAILS *details = GetDetails(hwnd); + RemoveProp(hwnd, MAKEINTATOM(DETAILS_PROP)); + + if (NULL != details) + { + if (NULL != details->service) + details->service->Release(); + if (NULL != details->fontTitle) + DeleteObject(details->fontTitle); + if (NULL != details->fontMeta) + DeleteObject(details->fontMeta); + } + + HWND hThumbnail = GetDlgItem(hwnd, IDC_THUMBNAIL); + if (NULL != hThumbnail) + { + HBITMAP hBitmap = (HBITMAP)SendMessage(hThumbnail, STM_SETIMAGE, IMAGE_BITMAP, 0L); + if (NULL != hBitmap) + DeleteObject(hBitmap); + } +} + + +static INT_PTR ServicePanel_OnDialogColor(HWND hwnd, HDC hdc, HWND hControl) +{ + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if (NULL != hParent && hParent != hwnd) + return (INT_PTR)SendMessage(hParent, WM_CTLCOLORDLG, (WPARAM)hdc, (LPARAM)hControl); + return 0; +} + + +static INT_PTR ServicePanel_OnStaticColor(HWND hwnd, HDC hdc, HWND hControl) +{ + INT_PTR result = 0; + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if (NULL != hParent && hParent != hwnd) + result = (INT_PTR)SendMessage(hParent, WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hControl); + + INT controlId = GetDlgCtrlID(hControl); + switch(controlId) + { + case IDC_SERVICEMETA: + { + COLORREF rgbBk = GetBkColor(hdc); + COLORREF rgbFg = GetTextColor(hdc); + + ifc_omgraphics *graphics; + if (SUCCEEDED(OMUTILITY->GetGraphics(&graphics))) + { + graphics->BlendColor(rgbFg, rgbBk, 180, &rgbFg); + graphics->Release(); + } + + SetTextColor(hdc, rgbFg); + } + break; + } + return result; +} + +static INT_PTR WINAPI ServicePanel_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: return ServicePanel_OnInitDialog(hwnd, (HWND)wParam, lParam); + case WM_DESTROY: ServicePanel_OnDestroy(hwnd); break; + case WM_CTLCOLORDLG: return ServicePanel_OnDialogColor(hwnd, (HDC)wParam, (HWND)lParam); + case WM_CTLCOLORSTATIC: return ServicePanel_OnStaticColor(hwnd, (HDC)wParam, (HWND)lParam); + } + return 0; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupGroup.cpp b/Src/Plugins/Library/ml_online/Setup/setupGroup.cpp new file mode 100644 index 00000000..bf1faf28 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupGroup.cpp @@ -0,0 +1,929 @@ +#include "./setupGroup.h" +#include "./setupGroupFilter.h" +#include "./setupListboxLabel.h" +#include "./setupDetails.h" +#include "./setupPage.h" +#include "../common.h" +#include "../api__ml_online.h" +#include "../resource.h" +#include "../serviceHost.h" +#include "../serviceHelper.h" + +#include "../../nu/menuHelpers.h" +#include <vector> + +#include <ifc_omservice.h> +#include <ifc_omstorage.h> +#include <ifc_omstorageasync.h> +#include <ifc_omserviceenum.h> +#include <ifc_omfilestorage.h> + +#include <shlwapi.h> +#include <strsafe.h> +#include <algorithm> + +typedef std::vector<ifc_omservice*> ServiceList; + +#define GROUP_MARGINCX 0 +#define GROUP_MARGINCY 1 + +#define TEXT_OFFSET_LEFT 2 +#define TEXT_OFFSET_BOTTOM 2 +#define TEXT_ALIGN (TA_LEFT | TA_BOTTOM) + +SetupGroup::SetupGroup(INT groupId, LPCWSTR pszName, LPCWSTR pszAddress, const GUID *storageId, const GUID *filterId, UINT fStyle) + : ref(1), id(groupId), name(NULL), flags(0), emptyLabel(NULL), errorCode(S_OK), hPage(NULL), + longName(NULL), description(NULL), address(NULL), loadResult(NULL), style(fStyle), loadComplete(NULL) +{ + name = Plugin_DuplicateResString(pszName); + address = Plugin_DuplicateResString(pszAddress); + this->storageId = (NULL != storageId) ? *storageId : GUID_NULL; + this->filterId = (NULL != filterId) ? *filterId : GUID_NULL; + + InitializeCriticalSection(&lock); +} + +SetupGroup::~SetupGroup() +{ + Plugin_FreeResString(name); + Plugin_FreeResString(address); + + SetLongName(NULL); + SetDescription(NULL); + + EnterCriticalSection(&lock); + + size_t index = list.size(); + while(index--) + { + list[index]->Release(); + } + + if (NULL != emptyLabel) + emptyLabel->Release(); + + if (NULL != loadResult) + { + ifc_omstorage *storage; + HRESULT hr = OMSERVICEMNGR->QueryStorage(&storageId, &storage); + if (SUCCEEDED(hr)) + { + storage->RequestAbort(loadResult, TRUE); + } + + loadResult->Release(); + loadResult = NULL; + } + + if (NULL != loadComplete) + CloseHandle(loadComplete); + + LeaveCriticalSection(&lock); + + DeleteCriticalSection(&lock); + +} + +SetupGroup *SetupGroup::CreateInstance(INT groupId, LPCWSTR pszName, LPCWSTR pszAddress, const GUID *storageId, const GUID *filterId, UINT fStyle) +{ + return new SetupGroup(groupId, pszName, pszAddress, storageId, filterId, fStyle); +} + +ULONG SetupGroup::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG SetupGroup::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + return r; +} + +HRESULT SetupGroup::GetName(LPWSTR pszBuffer, INT cchBufferMax) +{ + if (NULL == pszBuffer) + return E_POINTER; + + HRESULT hr; + if (NULL != name) + { + if (IS_INTRESOURCE(name)) + { + WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)name, pszBuffer, cchBufferMax); + hr = (L'\0' != *pszBuffer) ? S_OK : E_FAIL; + } + else + { + hr = StringCchCopyW(pszBuffer, cchBufferMax, name); + } + } + else + { + hr = StringCchCopyW(pszBuffer, cchBufferMax, L"Unknown"); + } + return hr; +} + +HRESULT SetupGroup::GetLongName(LPWSTR pszBuffer, INT cchBufferMax) +{ + if (NULL == pszBuffer) + return E_POINTER; + + HRESULT hr; + if (NULL == longName) + return GetName(pszBuffer, cchBufferMax); + + if (IS_INTRESOURCE(longName)) + { + WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)longName, pszBuffer, cchBufferMax); + hr = (L'\0' != *pszBuffer) ? S_OK : E_FAIL; + } + else + { + hr = StringCchCopyW(pszBuffer, cchBufferMax, longName); + } + return hr; +} + +HRESULT SetupGroup::GetDescription(LPWSTR pszBuffer, INT cchBufferMax) +{ + if (NULL == pszBuffer) + return E_POINTER; + + HRESULT hr; + + if (NULL != description && IS_INTRESOURCE(description)) + { + WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)description, pszBuffer, cchBufferMax); + hr = (L'\0' != *pszBuffer) ? S_OK : E_FAIL; + } + else + { + hr = StringCchCopyEx(pszBuffer, cchBufferMax, description, NULL, NULL, STRSAFE_IGNORE_NULLS); + } + return hr; +} +size_t SetupGroup::GetRecordCount() +{ + return list.size(); +} + +size_t SetupGroup::GetListboxCount() +{ + if (0 != (flagCollapsed & flags)) return 0; + size_t listSize = list.size(); + + if (0 == listSize) + { + return (NULL != emptyLabel && FALSE == emptyLabel->IsNameNull()) ? 1 : 0; + } + + return listSize; +} + +SetupListboxItem *SetupGroup::GetListboxItem(size_t index) +{ + if (0 != (flagCollapsed & flags)) return NULL; + size_t listSize = list.size(); + + if (0 == listSize) + { + return (NULL != emptyLabel && FALSE == emptyLabel->IsNameNull()) ? emptyLabel : NULL; + } + return list[index]; +} + +BOOL SetupGroup::IsModified() +{ + size_t index = list.size(); + while(index--) + { + if (list[index]->IsModified()) + return TRUE; + } + + return FALSE; +} + +BOOL SetupGroup::IsExpanded() +{ + return (0 == (flagCollapsed & flags)); +} + +void SetupGroup::SetExpanded(BOOL fExpanded) +{ + if ((FALSE == fExpanded) == (FALSE == IsExpanded())) + return; + + if (FALSE == fExpanded) + flags |= flagCollapsed; + else + flags &= ~flagCollapsed; +} + +void SetupGroup::Clear(BOOL fInvalidate) +{ + size_t index = list.size(); + if (0 == index) return; + + EnterCriticalSection(&lock); + + while(index--) + { + SetupRecord *record = list[index]; + if (NULL != record) + { + record->Release(); + } + } + list.clear(); + + LeaveCriticalSection(&lock); + + SetEmptyText(MAKEINTRESOURCE(IDS_SETUP_EMPTYGROUP), FALSE); + + if (FALSE != fInvalidate && NULL != hPage) + PostMessage(hPage, SPM_UPDATELIST, (WPARAM)id, NULL); +} + +static void CALLBACK SetupGroup_LoadCallback(ifc_omstorageasync *result) +{ + if (NULL == result) return; + SetupGroup *group; + if (SUCCEEDED(result->GetData((void**)&group)) && NULL != group) + { + group->OnLoadCompleted(); + } +} + + +__inline static int __cdecl SetupGroup_AlphabeticalSorter(const void *elem1, const void *elem2) +{ + SetupRecord *record1 = (SetupRecord*)elem1; + SetupRecord *record2 = (SetupRecord*)elem2; + + if (NULL == record1 || NULL == record2) + return (INT)(INT_PTR)(record1 - record2); + + ifc_omservice *svc1 = record1->GetService(); + ifc_omservice *svc2 = record2->GetService(); + + if (NULL == svc1 || NULL == svc2) + return (INT)(INT_PTR)(svc1 - svc2); + + WCHAR szBuffer1[256] = {0}, szBuffer2[256] = {0}; + if (FAILED(svc1->GetName(szBuffer1, ARRAYSIZE(szBuffer1)))) + szBuffer1[0] = L'\0'; + if (FAILED(svc2->GetName(szBuffer2, ARRAYSIZE(szBuffer2)))) + szBuffer2[0] = L'\0'; + + return CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, szBuffer1, -1, szBuffer2, -1) - 2; +} + +__inline static bool __cdecl SetupGroup_AlphabeticalSorter_V2(const void* elem1, const void* elem2) +{ + return SetupGroup_AlphabeticalSorter(elem1, elem2) < 0; +} +void SetupGroup::OnLoadCompleted() +{ + ifc_omstorage *storage; + HRESULT hr = OMSERVICEMNGR->QueryStorage(&storageId, &storage); + if (SUCCEEDED(hr)) + { + ifc_omserviceenum *serviceEnum; + hr = storage->EndLoad(loadResult, &serviceEnum); + if (SUCCEEDED(hr)) + { + SetupGroupFilter *filter; + if (FAILED(SetupGroupFilter::CreateInstance(&filterId, &filter))) + { + filter = NULL; + } + else if (FAILED(filter->Initialize())) + { + filter->Release(); + filter = NULL; + } + + EnterCriticalSection(&lock); + + ifc_omservice *service; + UINT filterResult, defaultFilter; + defaultFilter = SetupGroupFilter::serviceInclude; + if (0 != (styleDefaultUnsubscribed & style)) + defaultFilter |= SetupGroupFilter::serviceForceUnsubscribe; + else if (0 != (styleDefaultSubscribed & style)) + defaultFilter |= SetupGroupFilter::serviceForceSubscribe; + + while(S_OK == serviceEnum->Next(1, &service, NULL)) + { + + filterResult = defaultFilter; + if (NULL != filter && FAILED(filter->ProcessService(service, &filterResult))) + filterResult = defaultFilter; + + if (0 == (SetupGroupFilter::serviceInclude & filterResult)) + { + service->Release(); + service = NULL; + continue; + } + + if (0 != (SetupGroupFilter::serviceForceUnsubscribe & filterResult)) + ServiceHelper_Subscribe(service, TRUE, 0); + else if (0 != (SetupGroupFilter::serviceForceSubscribe & filterResult)) + ServiceHelper_Subscribe(service, FALSE, 0); + + if (0 != (styleSaveAll & style)) + ServiceHelper_MarkModified(service, (UINT)-1, (UINT)-1); + + SetupRecord *record = SetupRecord::CreateInstance(service); + if (NULL != record) + { + if (0 != (SetupGroupFilter::serviceForceUnsubscribe & filterResult)) + record->SetSelected(FALSE); + else if (0 != (SetupGroupFilter::serviceForceSubscribe & filterResult)) + record->SetSelected(TRUE); + list.push_back(record); + } + + service->Release(); + } + + if (0 != (styleSortAlphabetically & style)) + { + //qsort(list.first(), list.size(), sizeof(SetupRecord*), SetupGroup_AlphabeticalSorter); + std::sort(list.begin(), list.end(), SetupGroup_AlphabeticalSorter_V2); + } + + LeaveCriticalSection(&lock); + + serviceEnum->Release(); + if (NULL != filter) + filter->Release(); + } + + storage->Release(); + } + + EnterCriticalSection(&lock); + + loadResult->Release(); + loadResult = NULL; + + if (NULL != loadComplete) + { + SetEvent(loadComplete); + CloseHandle(loadComplete); + loadComplete = NULL; + } + + LeaveCriticalSection(&lock); + + LPCWSTR pszText = MAKEINTRESOURCE(((FAILED(hr)) ? IDS_SETUP_GROUPLOADFAILED : IDS_SETUP_EMPTYGROUP)); + SetEmptyText( pszText, TRUE); +} + +HRESULT SetupGroup::RequestReload() +{ + if (NULL == OMSERVICEMNGR) + return E_UNEXPECTED; + + HRESULT hr; + + EnterCriticalSection(&lock); + + if (NULL != loadResult) + hr = E_PENDING; + else + { + if (NULL != loadComplete) + { + CloseHandle(loadComplete); + loadComplete = NULL; + } + + Clear(FALSE); + SetEmptyText(MAKEINTRESOURCE(IDS_SETUP_LOADINGGROUP), TRUE); + + ifc_omstorage *storage; + hr = OMSERVICEMNGR->QueryStorage(&storageId, &storage); + if (SUCCEEDED(hr)) + { + ServiceHost *serviceHost; + if (FAILED(ServiceHost::GetCachedInstance(&serviceHost))) + serviceHost = NULL; + + hr = storage->BeginLoad(address, serviceHost, SetupGroup_LoadCallback, this, &loadResult); + storage->Release(); + + if (NULL != serviceHost) + serviceHost->Release(); + } + + if (FAILED(hr)) + { + SetEmptyText(MAKEINTRESOURCE(IDS_SETUP_GROUPLOADFAILED), TRUE); + } + } + + LeaveCriticalSection(&lock); + + return hr; +} + +void SetupGroup::SetPageWnd(HWND hPage) +{ + this->hPage = hPage; +} + +HRESULT SetupGroup::SignalLoadCompleted(HANDLE event) +{ + HRESULT hr; + if (NULL == event) return E_INVALIDARG; + + EnterCriticalSection(&lock); + + if (NULL == loadResult) + { + SetEvent(event); + hr = S_OK; + } + else + { + if (NULL != loadComplete) + CloseHandle(loadComplete); + + if (FALSE == DuplicateHandle(GetCurrentProcess(), event, GetCurrentProcess(), &loadComplete, 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + DWORD error = GetLastError(); + hr = HRESULT_FROM_WIN32(error); + } + + hr = S_OK; + } + + LeaveCriticalSection(&lock); + return hr; +} + +HRESULT SetupGroup::Save(SetupLog *log) +{ + HRESULT hr(S_OK); + size_t index = list.size(); + while(index--) + { + if (FAILED(list[index]->Save(log))) + hr = E_FAIL; + } + return hr; +} + +void SetupGroup::GetColors(HDC hdc, UINT state, COLORREF *rgbBkOut, COLORREF *rgbTextOut) +{ + COLORREF rgbBk, rgbText; + + + if (0 != (ODS_DISABLED & state)) + { + rgbBk = GetBkColor(hdc); + rgbText = GetSysColor(COLOR_GRAYTEXT); + } + else + { + if (0 != (ODS_SELECTED & state)) + { + if (0 == (ODS_INACTIVE & state)) + { + rgbBk = GetSysColor(COLOR_HIGHLIGHT); + rgbText = GetSysColor(COLOR_HIGHLIGHTTEXT); + } + else + { + rgbBk = GetSysColor(COLOR_3DFACE); + rgbText = GetSysColor(COLOR_WINDOWTEXT); + } + } + else + { + rgbBk = GetSysColor(COLOR_WINDOW); + rgbText = GetSysColor(COLOR_WINDOWTEXT); + } + } + + if (NULL != rgbBkOut) *rgbBkOut = rgbBk; + if (NULL != rgbTextOut) *rgbTextOut = rgbText; +} + +HBRUSH SetupGroup::GetBrush(HDC hdc, UINT state) +{ + if (0 != (ODS_DISABLED & state)) + { + return GetSysColorBrush(COLOR_WINDOW); + } + if (0 != (ODS_COMBOBOXEDIT & state)) + { + return GetSysColorBrush(COLOR_WINDOWTEXT); + } + if (0 != (ODS_SELECTED & state)) + { + return GetSysColorBrush( (0 == (ODS_INACTIVE & state)) ? COLOR_HIGHLIGHT : COLOR_3DFACE); + } + + return GetSysColorBrush(COLOR_WINDOW); +} + +BOOL SetupGroup::MeasureItem(SetupListbox *instance, UINT *cx, UINT *cy) +{ + HDC hdc = GetDCEx(instance->GetHwnd(), NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL == hdc) return FALSE; + + HFONT originalFont = (HFONT)SelectObject(hdc, instance->GetFont()); + SIZE imageSize; + if (!instance->GetExpandboxMetrics(hdc, IsExpanded(), &imageSize)) + ZeroMemory(&imageSize, sizeof(SIZE)); + + if (NULL != cy) + { + *cy = 0; + TEXTMETRIC tm; + if (GetTextMetrics(hdc, &tm)) + { + *cy = tm.tmHeight + tm.tmExternalLeading; + if (imageSize.cy > (INT)*cy) *cy = imageSize.cy; + *cy += GROUP_MARGINCY*2; + } + } + + if (NULL != cx) + { + *cx = imageSize.cx; + WCHAR szBuffer[128] = {0}; + if (SUCCEEDED(GetName(szBuffer, ARRAYSIZE(szBuffer)))) + { + INT cchBuffer = lstrlenW(szBuffer); + SIZE textSize; + if (0 != cchBuffer && GetTextExtentPoint32(hdc, szBuffer, cchBuffer, &textSize)) + { + *cx += textSize.cx; + } + } + if (0 != *cx) *cx += GROUP_MARGINCX*2; + } + + SelectObject(hdc, originalFont); + ReleaseDC(instance->GetHwnd(), hdc); + return TRUE; +} + + +static void SetupGroup_DrawFrame(HDC hdc, const RECT *prc, INT width, COLORREF rgbFrame) +{ + if (width > 0) + { + COLORREF rgbOld = SetBkColor(hdc, rgbFrame); + + RECT rcPart; + SetRect(&rcPart, prc->left, prc->top, prc->right, prc->top + width); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcPart, NULL, 0, NULL); + SetRect(&rcPart, prc->left, prc->bottom - width, prc->right, prc->bottom); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcPart, NULL, 0, NULL); + SetRect(&rcPart, prc->left, prc->top + width, prc->left + width, prc->bottom - width); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcPart, NULL, 0, NULL); + SetRect(&rcPart, prc->right - width, prc->top + width, prc->right, prc->bottom - width); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcPart, NULL, 0, NULL); + + if (rgbOld != rgbFrame) + SetBkColor(hdc, rgbOld); + } +} +BOOL SetupGroup::DrawItem(SetupListbox *instance, HDC hdc, const RECT *prc, UINT state) +{ + LONG paintLeft = prc->left + GROUP_MARGINCX; + RECT partRect; + + SetRectEmpty(&partRect); + + COLORREF rgbBk, rgbText; + GetColors(hdc, state, &rgbBk, &rgbText); + + COLORREF origBk = SetBkColor(hdc, rgbBk); + COLORREF origText = SetTextColor(hdc, rgbText); + UINT textAlign = SetTextAlign(hdc, TEXT_ALIGN); + + HRGN backRgn, rgn; + backRgn = CreateRectRgnIndirect(prc); + rgn = CreateRectRgn(0,0,0,0); + + SetRectEmpty(&partRect); + if (instance->GetExpandboxMetrics(hdc, IsExpanded(), (((SIZE*)&partRect) + 1))) + { + INT space = (prc->bottom - prc->top) - (partRect.bottom- partRect.top); + INT offsetY = space / 2 + space%2; + if (offsetY < 0) offsetY = 0; + OffsetRect(&partRect, paintLeft, prc->top + offsetY); + if (instance->DrawExpandbox(hdc, IsExpanded(), &partRect, rgbBk, rgbText)) + { + paintLeft = partRect.right; + if (SetRectRgn(rgn, partRect.left, partRect.top, partRect.right, partRect.bottom)) + CombineRgn(backRgn, backRgn, rgn, RGN_DIFF); + } + } + + WCHAR szBuffer[128] = {0}; + INT cchBuffer = 0; + if (SUCCEEDED(GetName(szBuffer, ARRAYSIZE(szBuffer)))) + cchBuffer = lstrlenW(szBuffer); + + SetRect(&partRect, paintLeft, prc->top, prc->right, prc->bottom); + if (ExtTextOut(hdc, partRect.left + TEXT_OFFSET_LEFT, partRect.bottom - TEXT_OFFSET_BOTTOM, + ETO_OPAQUE | ETO_CLIPPED, &partRect, szBuffer, cchBuffer, NULL)) + { + if (SetRectRgn(rgn, partRect.left, partRect.top, partRect.right, partRect.bottom)) + CombineRgn(backRgn, backRgn, rgn, RGN_DIFF); + } + + + + COLORREF rgbLine = ColorAdjustLuma(rgbBk, -150, TRUE); + if (rgbLine != rgbBk) + { + RECT lineRect; + SetRect(&lineRect, prc->left, prc->bottom - 1, prc->right, prc->bottom); + + SetBkColor(hdc, rgbLine); + if (ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &lineRect, NULL, 0, NULL)) + { + if (SetRectRgn(rgn, lineRect.left, lineRect.top, lineRect.right, lineRect.bottom)) + CombineRgn(backRgn, backRgn, rgn, RGN_DIFF); + } + + SetBkColor(hdc, rgbBk); + } + + if (0 != (flagMenuActive & flags)) + { + COLORREF rgbFrame = rgbLine; //ColorAdjustLuma(GetSysColor(COLOR_HIGHLIGHT), 100, TRUE); + SetupGroup_DrawFrame(hdc, prc, 1, rgbFrame); + if (SetRectRgn(rgn, prc->left + 1, prc->top + 1, prc->right - 1, prc->bottom - 1)) + CombineRgn(backRgn, backRgn, rgn, RGN_AND); + } + + + if (NULL != backRgn) + { + FillRgn(hdc, backRgn, GetBrush(hdc, state)); + DeleteObject(backRgn); + } + if (NULL != rgn) + DeleteObject(rgn); + + + + if (ODS_FOCUS == ((ODS_FOCUS | 0x0200/*ODS_NOFOCUSRECT*/) & state)) + DrawFocusRect(hdc, prc); + + if (TEXT_ALIGN != textAlign) SetTextAlign(hdc, textAlign); + if (origBk != rgbBk) SetBkColor(hdc, origBk); + if (origText != rgbText) SetTextColor(hdc, origText); + return TRUE; +} + +INT_PTR SetupGroup::KeyToItem(SetupListbox *instance, const RECT *prcItem, INT vKey) +{ + switch(vKey) + { + case VK_SPACE: + InvertExpanded(instance); + return -2; + } + return -1; +} +BOOL SetupGroup::MouseMove(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} +BOOL SetupGroup::MouseLeave(SetupListbox *instance, const RECT *prcItem) +{ + return FALSE; +} +BOOL SetupGroup::LButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} +BOOL SetupGroup::LButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} +BOOL SetupGroup::LButtonDblClk(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + InvertExpanded(instance); + return TRUE; +} + +BOOL SetupGroup::RButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return TRUE; +} + +BOOL SetupGroup::RButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + HMENU hMenu = instance->GetContextMenu(SetupListbox::menuGroupContext); + if (NULL == hMenu) + return FALSE; + + hMenu = MenuHelper_DuplcateMenu(hMenu); + if (NULL == hMenu) return FALSE; + + MENUITEMINFO mi; + mi.cbSize = sizeof(MENUITEMINFO); + mi.fMask = MIIM_STATE; + GetMenuItemInfo(hMenu, ID_GROUP_TOGGLE, FALSE, &mi); + + mi.fMask = 0; + if (0 == (MFS_DEFAULT & mi.fState)) + { + mi.fMask |= MIIM_STATE; + mi.fState |= MFS_DEFAULT; + } + + WCHAR szBuffer[128] = {0}; + WASABI_API_LNGSTRINGW_BUF(((IsExpanded()) ? IDS_COLLAPSE : IDS_EXPAND), szBuffer, ARRAYSIZE(szBuffer)); + mi.fMask |= MIIM_STRING; + mi.dwTypeData = szBuffer; + + if (0 != mi.fMask) + SetMenuItemInfo(hMenu, ID_GROUP_TOGGLE, FALSE, &mi); + + if (0 == list.size()) + { + EnableMenuItem(hMenu, ID_GROUP_SELECTALL, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + EnableMenuItem(hMenu, ID_GROUP_UNSELECTALL, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + } + + if (0 != (flagLoading & flags)) + { + EnableMenuItem(hMenu, ID_GROUP_RELOAD, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + } + + MapWindowPoints(instance->GetHwnd(), HWND_DESKTOP, &pt, 1); + + flags |= flagMenuActive; + instance->InvalidateRect(prcItem, TRUE); + + INT cmd = TrackPopupMenuEx(hMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD, pt.x, pt.y, instance->GetHwnd(), NULL); + if (0 != cmd) + { + Command(instance, cmd, 0); + } + + DestroyMenu(hMenu); + + flags &= ~flagMenuActive; + instance->InvalidateRect(prcItem, TRUE); + + return TRUE; +} + +void SetupGroup::CaptureChanged(SetupListbox *instance, const RECT *prcItem, SetupListboxItem *captured) +{ +} + +void SetupGroup::InvertExpanded(SetupListbox *instance) +{ + if (FALSE != IsExpanded()) + ValidateSelection(instance); + + SetExpanded(!IsExpanded()); + if (NULL != instance) + { + instance->UpdateCount(); + UpdateWindow(instance->GetHwnd()); + } +} +void SetupGroup::SelectAll(SetupListbox *instance, BOOL fSelect) +{ + size_t index = list.size(); + + INT baseIndex; + if (NULL == instance || FALSE == instance->GetIndex(this, &baseIndex)) + baseIndex = -1; + else + baseIndex++; + + while(index--) + { + SetupRecord *record = list[index]; + if (NULL != record && !record->IsDisabled()) + { + if ((FALSE == fSelect) != (FALSE == record->IsSelected())) + { + record->SetSelected(fSelect); + if (0 == (flagCollapsed & flags) && NULL != instance && -1 != baseIndex) + { + instance->InvalidateItem((INT)(baseIndex + index), TRUE); + } + } + } + } +} + + +void SetupGroup::SetEmptyText(LPCWSTR pszText, BOOL fInvalidate) +{ + if (NULL == emptyLabel) + emptyLabel = SetupListboxLabel::CreateInstance(pszText); + else + emptyLabel->SetName(pszText); + + if (FALSE != fInvalidate && NULL != hPage) + PostMessage(hPage, SPM_UPDATELIST, (WPARAM)id, NULL); +} + +HWND SetupGroup::CreateDetailsView(HWND hParent) +{ + WCHAR szName[64] = {0}; + if (FALSE == GetUniqueName(szName, ARRAYSIZE(szName))) + szName[0] = L'\0'; + + return SetupDetails_CreateGroupView(hParent, szName, this); +} + +BOOL SetupGroup::GetUniqueName(LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer || + FAILED(StringCchPrintf(pszBuffer, cchBufferMax, L"grp_id_%d", id))) + { + return FALSE; + } + return TRUE; +} + + +void SetupGroup::SetLongName(LPCWSTR pszText) +{ + if (NULL != longName && !IS_INTRESOURCE(longName)) + Plugin_FreeString(longName); + longName = NULL; + + if (NULL != pszText) + longName = (IS_INTRESOURCE(pszText)) ? (LPWSTR)pszText : Plugin_CopyString(pszText); +} + +void SetupGroup::SetDescription(LPCWSTR pszText) +{ + if (NULL != description && !IS_INTRESOURCE(description)) + Plugin_FreeString(description); + description = NULL; + if (NULL != pszText) + description = (IS_INTRESOURCE(pszText)) ? (LPWSTR)pszText : Plugin_CopyString(pszText); +} + +void SetupGroup::ValidateSelection(SetupListbox *instance) +{ + if (NULL == instance) + return; + + SetupListboxItem *selection = instance->GetSelection(); + if (NULL != selection) + { + EnterCriticalSection(&lock); + size_t index = list.size(); + while(index--) + { + if (list[index] == selection) + { + instance->SetSelection(this); + break; + } + } + + LeaveCriticalSection(&lock); + } +} + +void SetupGroup::Command(SetupListbox *instance, INT commandId, INT eventId) +{ + switch(commandId) + { + case ID_GROUP_TOGGLE: + InvertExpanded(instance); + break; + case ID_GROUP_SELECTALL: + SelectAll(instance, TRUE); + break; + case ID_GROUP_UNSELECTALL: + SelectAll(instance, FALSE); + break; + case ID_GROUP_RELOAD: + ValidateSelection(instance); + RequestReload(); + break; + } +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupGroup.h b/Src/Plugins/Library/ml_online/Setup/setupGroup.h new file mode 100644 index 00000000..ce3f3c5f --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupGroup.h @@ -0,0 +1,131 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPGROUP_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPGROUP_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "./setupRecord.h" +#include "./setupListbox.h" +#include <vector> + +class SetupListboxLabel; +class SetupLog; +class SetupPage; +class ifc_omstorage; + +class SetupGroup : public SetupListboxItem +{ +public: + typedef enum + { + styleDefaultUnsubscribed = 0x00000001, + styleDefaultSubscribed = 0x00000002, + styleSortAlphabetically = 0x00000008, + styleSaveAll = 0x00000010, + } GroupStyles; +protected: + typedef enum + { + flagCollapsed = 0x0001, + flagMenuActive = 0x0002, + flagLoading = 0x0004, + } GroupFlags; + +protected: + SetupGroup(INT groupId, LPCWSTR pszName, LPCWSTR pszAddress, const GUID *storageId, const GUID *filterId, UINT fStyle); + ~SetupGroup(); + +public: + static SetupGroup *CreateInstance(INT groupId, LPCWSTR pszName, LPCWSTR pszAddress, const GUID *storageId, const GUID *filterId, UINT fStyle); + +public: + ULONG AddRef(); + ULONG Release(); + + INT GetId() { return id; } + HRESULT GetName(LPWSTR pszBuffer, INT cchBufferMax); + HRESULT GetLongName(LPWSTR pszBuffer, INT cchBufferMax); + HRESULT GetDescription(LPWSTR pszBuffer, INT cchBufferMax); + + size_t GetRecordCount(); + SetupRecord *GetRecord(size_t index) { return list[index]; } + + size_t GetListboxCount(); + SetupListboxItem *GetListboxItem(size_t index); + + BOOL IsModified(); + + BOOL IsExpanded(); + void SetExpanded(BOOL fExpanded); + void SelectAll(SetupListbox *instance, BOOL fSelect); + + HRESULT RequestReload(); + HRESULT Save(SetupLog *log); + + + void SetEmptyText(LPCWSTR pszText, BOOL fInvalidate); + void SetLongName(LPCWSTR pszText); + void SetDescription(LPCWSTR pszText); + + void GetColors(HDC hdc, UINT state, COLORREF *rgbBkOut, COLORREF *rgbTextOut); + HBRUSH GetBrush(HDC hdc, UINT state); + + HRESULT SignalLoadCompleted(HANDLE event); + void ValidateSelection(SetupListbox *instance); + + /* SetupListboxItem */ + BOOL MeasureItem(SetupListbox *instance, UINT *cx, UINT *cy); + BOOL DrawItem(SetupListbox *instance, HDC hdc, const RECT *prc, UINT state); + INT_PTR KeyToItem(SetupListbox *instance, const RECT *prcItem, INT vKey); + BOOL MouseMove(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL MouseLeave(SetupListbox *instance, const RECT *prcItem); + BOOL LButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL LButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL LButtonDblClk(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL RButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL RButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + void CaptureChanged(SetupListbox *instance, const RECT *prcItem, SetupListboxItem *captured); + BOOL IsDisabled() { return FALSE; } + void Command(SetupListbox *instance, INT commandId, INT eventId); + HWND CreateDetailsView(HWND hParent); + BOOL GetUniqueName(LPWSTR pszBuffer, UINT cchBufferMax); + + void SetError(HRESULT code) { errorCode = code; } + HRESULT GetError() { return errorCode; } + + void Clear(BOOL fInvalidate); + + void SetPageWnd(HWND hPage); + +protected: + void InvertExpanded(SetupListbox *instance); + void OnLoadCompleted(); + + +private: + friend static void CALLBACK SetupGroup_LoadCallback(ifc_omstorageasync *result); + + +protected: + ULONG ref; + INT id; + LPWSTR name; + LPWSTR longName; + LPWSTR description; + UINT style; + UINT flags; + LPWSTR address; + GUID storageId; + GUID filterId; + HRESULT errorCode; + std::vector<SetupRecord*> list; + SetupListboxLabel *emptyLabel; + CRITICAL_SECTION lock; + ifc_omstorageasync *loadResult; + HWND hPage; + HANDLE loadComplete; +}; + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPGROUP_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupGroupFilter.cpp b/Src/Plugins/Library/ml_online/Setup/setupGroupFilter.cpp new file mode 100644 index 00000000..c4d4311f --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupGroupFilter.cpp @@ -0,0 +1,226 @@ +#include "./setupGroupFilter.h" +#include "../api__ml_online.h" +#include "../serviceHost.h" +#include "../config.h" + +#include <ifc_omservice.h> +#include <ifc_omstorage.h> +#include <ifc_omserviceenum.h> +#include <ifc_omfilestorage.h> + + +SetupGroupFilter::SetupGroupFilter(const GUID *filterId) + : ref(1) +{ + id = (NULL != filterId) ? *filterId : GUID_NULL; +} + +SetupGroupFilter::~SetupGroupFilter() +{ +} + +HRESULT SetupGroupFilter::CreateInstance(const GUID *filterId, SetupGroupFilter **instance) +{ + if (NULL == filterId) + { + *instance = NULL; + return E_INVALIDARG; + } + + if (FALSE != IsEqualGUID(*filterId, FUID_SetupFeaturedGroupFilter)) + return SetupFeaturedGroupFilter::CreateInstance((SetupFeaturedGroupFilter**)instance); + if (FALSE != IsEqualGUID(*filterId, FUID_SetupKnownGroupFilter)) + return SetupKnownGroupFilter::CreateInstance((SetupKnownGroupFilter**)instance); + + *instance = NULL; + return E_NOINTERFACE; +} + +ULONG SetupGroupFilter::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG SetupGroupFilter::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + return r; +} + +HRESULT SetupGroupFilter::GetId(GUID *filterId) +{ + if (NULL == filterId) + return E_POINTER; + *filterId = id; + return S_OK; +} + +BOOL CALLBACK SetupGroupFilter::AppendServiceIdCallback(UINT serviceId, void *data) +{ + ServiceIdList *list = (ServiceIdList*)data; + if (NULL == list) return FALSE; + list->push_back(serviceId); + return TRUE; +} + +SetupFeaturedGroupFilter::SetupFeaturedGroupFilter() + : SetupGroupFilter(&FUID_SetupFeaturedGroupFilter) +{ +} + +SetupFeaturedGroupFilter::~SetupFeaturedGroupFilter() +{ +} + +HRESULT SetupFeaturedGroupFilter::CreateInstance(SetupFeaturedGroupFilter **instance) +{ + if (NULL == instance) + return E_POINTER; + + *instance = new SetupFeaturedGroupFilter(); + if (NULL == *instance) return E_OUTOFMEMORY; + + return S_OK; +} + +HRESULT SetupFeaturedGroupFilter::Initialize() +{ + HRESULT hr; + ifc_omstorage *storage; + + filterList.clear(); + + if (NULL == OMSERVICEMNGR) + return E_UNEXPECTED; + + hr = OMSERVICEMNGR->QueryStorage(&SUID_OmStorageIni, &storage); + if(FAILED(hr)) + return hr; + + ServiceHost *serviceHost; + if (FAILED(ServiceHost::GetCachedInstance(&serviceHost))) + serviceHost = NULL; + + ifc_omserviceenum *serviceEnum; + hr = storage->Load(L"*.ini", serviceHost, &serviceEnum); + if(SUCCEEDED(hr)) + { + ifc_omservice *service; + while(S_OK == serviceEnum->Next(1, &service, NULL) && NULL != service) + { + filterList.push_back(service->GetId()); + } + serviceEnum->Release(); + } + storage->Release(); + + ServiceIdList promoList; + Config_ReadServiceIdList("Setup", "featuredExtra", ',', AppendServiceIdCallback, &promoList); + + ServiceIdList historyList; + Config_ReadServiceIdList("Setup", "featuredHistory", ',', AppendServiceIdCallback, &historyList); + + size_t index = historyList.size(); + size_t filterIndex, filterSize = filterList.size(); + + while(index--) + { + size_t promoSize = promoList.size(); + for(filterIndex = 0; filterIndex < promoSize; filterIndex++) + { + if (promoList[filterIndex] == historyList[index]) + { + promoList.erase(promoList.begin() + filterIndex); + break; + } + } + if (filterIndex == promoSize) + { + for(filterIndex = 0; filterIndex < filterSize; filterIndex++) + { + if (filterList[filterIndex] == historyList[index]) + break; + } + + if (filterIndex == filterSize) + filterList.push_back(historyList[index]); + } + } + + return hr; +} + +HRESULT SetupFeaturedGroupFilter::ProcessService(ifc_omservice *service, UINT *filterResult) +{ + if (NULL == service) + return E_INVALIDARG; + + if (NULL == filterResult) + return E_POINTER; + + size_t index = filterList.size(); + while(index--) + { + if (filterList[index] == service->GetId()) + { + filterList.erase(filterList.begin() + index); + *filterResult = serviceIgnore; + break; + } + } + return S_OK; +} + +SetupKnownGroupFilter::SetupKnownGroupFilter() + : SetupGroupFilter(&FUID_SetupKnownGroupFilter) +{ +} + +SetupKnownGroupFilter::~SetupKnownGroupFilter() +{ +} + +HRESULT SetupKnownGroupFilter::CreateInstance(SetupKnownGroupFilter **instance) +{ + if (NULL == instance) + return E_POINTER; + + *instance = new SetupKnownGroupFilter(); + if (NULL == *instance) return E_OUTOFMEMORY; + + return S_OK; +} + +HRESULT SetupKnownGroupFilter::Initialize() +{ + Config_ReadServiceIdList("Setup", "featuredExtra", ',', AppendServiceIdCallback, &filterList); + return S_OK; +} + +HRESULT SetupKnownGroupFilter::ProcessService(ifc_omservice *service, UINT *filterResult) +{ + if (NULL == service) + return E_INVALIDARG; + + if (NULL == filterResult) + return E_POINTER; + + size_t index = filterList.size(); + while(index--) + { + if (filterList[index] == service->GetId()) + { + filterList.erase(filterList.begin() + index); + *filterResult &= ~serviceForceUnsubscribe; + *filterResult |= serviceForceSubscribe; + break; + } + } + + return S_OK; +} diff --git a/Src/Plugins/Library/ml_online/Setup/setupGroupList.cpp b/Src/Plugins/Library/ml_online/Setup/setupGroupList.cpp new file mode 100644 index 00000000..9ee1de1f --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupGroupList.cpp @@ -0,0 +1,190 @@ +#include "./setupGroupList.h" +#include "../api__ml_online.h" +#include <strsafe.h> + +SetupGroupList::SetupGroupList() + : ref(1) +{ +} + +SetupGroupList::~SetupGroupList() +{ + size_t index = list.size(); + while(index--) + { + list[index]->Release(); + } +} + +SetupGroupList *SetupGroupList::CreateInstance() +{ + return new SetupGroupList(); +} + +ULONG SetupGroupList::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG SetupGroupList::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + return r; +} + +BOOL SetupGroupList::AddGroup(SetupGroup *group) +{ + if (NULL == group) return FALSE; + list.push_back(group); + group->AddRef(); + return TRUE; +} +size_t SetupGroupList::GetGroupCount() +{ + return list.size(); +} + +BOOL SetupGroupList::IsModified() +{ + size_t index = list.size(); + while(index--) + { + if (list[index]->IsModified()) + return TRUE; + } + + return FALSE; +} + +BOOL SetupGroupList::FindGroupIndex(SetupGroup *group, size_t *groupIndex) +{ + if (NULL == group) return FALSE; + + size_t index = list.size(); + while(index--) + { + if (list[index] == group) + { + if (NULL != groupIndex) + *groupIndex = index; + return TRUE; + } + } + + return FALSE; + +} + +HRESULT SetupGroupList::FindGroupById(UINT groupId, SetupGroup **group) +{ + if (NULL == group) return E_POINTER; + + size_t index = list.size(); + while(index--) + { + if (list[index]->GetId() == groupId) + { + *group = list[index]; + (*group)->AddRef(); + return S_OK; + } + } + return S_FALSE; +} + +size_t SetupGroupList::GetListboxCount() +{ + size_t recordCount = list.size(); + size_t index = recordCount; + while(index--) + { + recordCount += list[index]->GetListboxCount(); + } + return recordCount; +} + +HRESULT SetupGroupList::Save(SetupLog *log) +{ + HRESULT hr(S_OK); + size_t index = list.size(); + while(index--) + { + if (FAILED(list[index]->Save(log))) + hr = E_FAIL; + } + return hr; +} + +HRESULT SetupGroupList::FindListboxItem(size_t listboxId, SetupListboxItem **listboxItem) +{ + if (NULL == listboxItem) return E_POINTER; + + size_t index = 0; + size_t groupCount = list.size(); + + SetupGroup *group; + for (size_t i = 0; i < groupCount; i++) + { + group = list[i]; + if (index == listboxId) + { + *listboxItem = (SetupListboxItem*)group; + return S_OK; + } + index++; + + size_t itemCount; + if (0 != (itemCount = group->GetListboxCount())) + { + if (listboxId < (index + itemCount)) + { + size_t itemIndex = (listboxId - index); + *listboxItem = group->GetListboxItem(itemIndex); + return S_OK; + } + index += itemCount; + } + } + return E_NOTIMPL; +} + +INT SetupGroupList::GetListboxItem(SetupListboxItem *item) +{ + if (NULL == item) return LB_ERR; + size_t index = 0; + size_t groupCount = list.size(); + SetupGroup *group; + SetupListboxItem *groupItem; + + for (size_t i = 0; i < groupCount; i++) + { + group = list[i]; + if (item == group) + return (INT)index; + + index++; + size_t itemCount = group->GetListboxCount(); + for (size_t j = 0; j < itemCount; j++) + { + groupItem = group->GetListboxItem(j); + if (groupItem == item) + return (INT)index; + index++; + } + } + return LB_ERR; +} + +void SetupGroupList::SetPageWnd(HWND hPage) +{ + size_t index = list.size(); + while(index--) + { + list[index]->SetPageWnd(hPage); + } +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupGroupList.h b/Src/Plugins/Library/ml_online/Setup/setupGroupList.h new file mode 100644 index 00000000..0b4445cb --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupGroupList.h @@ -0,0 +1,52 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPGROUPLIST_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPGROUPLIST_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "./setupGroup.h" +#include <vector> + +class SetupListboxItem; +class SetupLog; + +class SetupGroupList +{ + +protected: + SetupGroupList(); + ~SetupGroupList(); + +public: + static SetupGroupList *CreateInstance(); + +public: + ULONG AddRef(); + ULONG Release(); + + BOOL AddGroup(SetupGroup *group); + SetupGroup *GetGroup(size_t index) { return list[index]; } + size_t GetGroupCount(); + BOOL FindGroupIndex(SetupGroup *group, size_t *groupIndex); + HRESULT FindGroupById(UINT groupId, SetupGroup **group); + + + BOOL IsModified(); + + HRESULT Save(SetupLog *log); + + size_t GetListboxCount(); + INT GetListboxItem(SetupListboxItem *item); + HRESULT FindListboxItem(size_t listboxId, SetupListboxItem **listboxItem); + + void SetPageWnd(HWND hPage); + + +protected: + ULONG ref; + std::vector<SetupGroup*> list; +}; + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPGROUPLIST_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupImage.cpp b/Src/Plugins/Library/ml_online/Setup/setupImage.cpp new file mode 100644 index 00000000..46979043 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupImage.cpp @@ -0,0 +1,282 @@ +#include "./setupImage.h" +#include "../api__ml_online.h" + +#include <shlwapi.h> + +static BOOL SetupImage_CopyImage(HDC hdc, HBITMAP bitmapDst, INT x, INT y, INT cx, INT cy, HBITMAP bitmapSrc, INT srcX, INT srcY) +{ + BOOL resultOk = FALSE; + HDC hdcDst = CreateCompatibleDC(hdc); + HDC hdcSrc = CreateCompatibleDC(hdc); + + if (NULL != hdcDst && NULL != hdcSrc) + { + HBITMAP bitmapDstOrig = (HBITMAP)SelectObject(hdcDst, bitmapDst); + HBITMAP bitmapSrcOrig = (HBITMAP)SelectObject(hdcSrc, bitmapSrc); + + resultOk = BitBlt(hdcDst, x, y, cx, cy, hdcSrc, srcX, srcY, SRCCOPY); + + SelectObject(hdcDst, bitmapDstOrig); + SelectObject(hdcSrc, bitmapSrcOrig); + } + + if (NULL != hdcDst) DeleteDC(hdcDst); + if (NULL != hdcSrc) DeleteDC(hdcSrc); + + return resultOk; +} + +static BOOL SetupImage_ColorizeImage(BYTE *pPixels, LONG x, LONG y, LONG cx, LONG cy, WORD bpp, LONG dstX, LONG dstY, COLORREF rgbBk, COLORREF rgbFg, BOOL removeAlpha) +{ + LONG pitch; + INT step; + BYTE rFg, gFg, bFg; + LPBYTE srcCursor, srcLine; + LPBYTE dstLine; + + 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)); + + srcLine = pPixels + pitch * y + x*step; + dstLine = pPixels + pitch * dstY + dstX*step; + + if (24 == bpp) + { + for (; cy-- != 0; srcLine += pitch, dstLine += pitch ) + { + LONG i; + LPBYTE dstCursor; + for (i = cx, srcCursor = srcLine, dstCursor = dstLine ; i-- != 0; srcCursor += 3, dstCursor +=3) + { + dstCursor[0] = bFg - (bK*(255 - srcCursor[0])>>8); + dstCursor[1] = gFg - (gK*(255 - srcCursor[1])>>8); + dstCursor[2] = rFg - (rK*(255 - srcCursor[2])>>8); + } + } + } + else + { + // nothing for now + return FALSE; + } + + return TRUE; +} + + +SetupImage::SetupImage(HDC hdc, HBITMAP bitmapSource, INT maxColors) + : ref(1), bitmap(NULL), pixels(NULL), + table(NULL), tableSize(0), tableCount(0), insertCursor(0), readCursor(0) +{ + ZeroMemory(&header, sizeof(BITMAPINFOHEADER)); + + BITMAP bm; + if (sizeof(BITMAP) != GetObject(bitmapSource, sizeof(BITMAP), &bm)) + return; + + if (bm.bmHeight < 0) + bm.bmHeight = -bm.bmHeight; + + header.biSize = sizeof(BITMAPINFOHEADER); + header.biCompression = BI_RGB; + header.biBitCount = 24; + header.biPlanes = 1; + header.biWidth = bm.bmWidth; + header.biHeight = -(bm.bmHeight * (maxColors + 1)); + + bitmap = CreateDIBSection(hdc, (LPBITMAPINFO)&header, DIB_RGB_COLORS, (void**)&pixels, NULL, 0); + if (NULL == bitmap) + return; + + if (FALSE == SetupImage_CopyImage(hdc, bitmap, 0, 0, bm.bmWidth, bm.bmHeight, bitmapSource, 0, 0)) + { + DeleteObject(bitmap); + bitmap = NULL; + return; + } + + tableSize = maxColors; + table = (IMAGEINDEX*)calloc(tableSize, sizeof(IMAGEINDEX)); + if (NULL == table) + { + DeleteObject(bitmap); + bitmap = NULL; + return; + } +} + +SetupImage::~SetupImage() +{ + if (NULL != bitmap) + { + DeleteObject(bitmap); + bitmap = NULL; + } + + if (NULL != table) + { + free(table); + table = NULL; + } +} + +SetupImage *SetupImage::CreateInstance(HDC hdc, HBITMAP bitmapSource, INT maxColors) +{ + if (NULL == bitmapSource || maxColors < 1 || maxColors > 120) + return NULL; + + SetupImage *instance = new SetupImage(hdc, bitmapSource, maxColors); + if (NULL == instance) return NULL; + if (NULL == instance->bitmap || NULL == instance->table) + { + instance->Release(); + instance = NULL; + } + return instance; +} + +SetupImage *SetupImage::CreateFromPluginBitmap(HDC hdc, LPCWSTR pszModuleName, LPCWSTR resourceName, INT maxColors) +{ + SetupImage *instance = NULL; + WCHAR szPath[MAX_PATH] = {0}; + + if (0 != GetModuleFileName(WASABI_API_ORIG_HINST, szPath, ARRAYSIZE(szPath))) + { + PathRemoveFileSpec(szPath); + PathAppend(szPath, pszModuleName); + HMODULE hModule = LoadLibraryEx(szPath, NULL, LOAD_LIBRARY_AS_DATAFILE | 0x00000020/*LOAD_LIBRARY_AS_IMAGE_RESOURCE*/); + if (NULL != hModule) + { + HBITMAP bitmapSource = (HBITMAP)LoadImage(hModule, resourceName, IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + if (NULL != bitmapSource) + instance = CreateInstance(hdc, bitmapSource, maxColors); + FreeLibrary(hModule); + } + } + return instance; +} + +ULONG SetupImage::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG SetupImage::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +BOOL SetupImage::GetSize(SIZE *pSize) +{ + if (NULL == pSize) return FALSE; + + INT cy = header.biHeight; + if (cy < 0) cy = -cy; + + pSize->cx = header.biWidth; + pSize->cy = cy / (tableSize + 1); + return TRUE; +} + +BOOL SetupImage::DrawImage(HDC hdc, INT x, INT y, INT cx, INT cy, INT srcX, INT srcY, COLORREF rgbBk, COLORREF rgbFg) +{ + BYTE bitmapIndex = 0xFF; + + SIZE imageSize; + if (!GetSize(&imageSize)) + return FALSE; + + for(BYTE i = readCursor; i < tableCount; i++) + { + if (table[i].rgbBk == rgbBk && table[i].rgbFg == rgbFg) + { + bitmapIndex = i; + break; + } + } + + if (0xFF == bitmapIndex) + { + if (readCursor > tableCount) + readCursor = tableCount; + for(BYTE i = 0; i < readCursor; i++) + { + if (table[i].rgbBk == rgbBk && table[i].rgbFg == rgbFg) + { + bitmapIndex = i; + break; + } + } + + if (0xFF == bitmapIndex) + { + if (tableCount < tableSize) + { + insertCursor = tableCount; + tableCount++; + } + else if (++insertCursor == tableCount) + insertCursor = 0; + + INT targetY = (insertCursor + 1) * imageSize.cy; + + if (!SetupImage_ColorizeImage(pixels, 0, 0, imageSize.cx, imageSize.cy, + header.biBitCount, 0, targetY, rgbBk, rgbFg, TRUE)) + { + return FALSE; + } + table[insertCursor].rgbBk = rgbBk; + table[insertCursor].rgbFg = rgbFg; + bitmapIndex = insertCursor; + + } + } + + readCursor = bitmapIndex; + srcY += ((bitmapIndex + 1) * imageSize.cy); + + INT dstY = y; + INT dstCY = cy; + + INT imageHeight = header.biHeight; + if (imageHeight < 0) + { + header.biHeight = -imageHeight; + dstY += (cy - 1); + dstCY = -cy; + } + + BOOL resultOk = StretchDIBits(hdc, x, dstY, cx, dstCY, srcX, srcY, cx, cy, + pixels, (BITMAPINFO*)&header, DIB_RGB_COLORS, SRCCOPY); + + if (imageHeight < 0) + header.biHeight = imageHeight; + + return resultOk; +} + +BOOL SetupImage::ResetCache() +{ + if (NULL != table) + ZeroMemory(&table, sizeof(IMAGEINDEX) * tableSize); + tableCount = 0; + insertCursor = 0; + readCursor = 0; + return TRUE; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupImage.h b/Src/Plugins/Library/ml_online/Setup/setupImage.h new file mode 100644 index 00000000..893e2c93 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupImage.h @@ -0,0 +1,50 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPIMAGE_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPIMAGE_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <windows.h> + +class SetupImage +{ +private: + typedef struct __IMAGEINDEX + { + COLORREF rgbBk; + COLORREF rgbFg; + } IMAGEINDEX; + +protected: + SetupImage(HDC hdc, HBITMAP bitmapSource, INT maxColors); + ~SetupImage(); + +public: + static SetupImage *CreateInstance(HDC hdc, HBITMAP bitmapSource, INT maxColors); + static SetupImage *CreateFromPluginBitmap(HDC hdc, LPCWSTR pszModuleName, LPCWSTR resourceName, INT maxColors); + +public: + ULONG AddRef(); + ULONG Release(); + + BOOL GetSize(SIZE *pSize); + BOOL DrawImage(HDC hdc, INT x, INT y, INT cx, INT cy, INT srcX, INT srcY, COLORREF rgbBk, COLORREF rgbFg); + + BOOL ResetCache(); + +private: + ULONG ref; + HBITMAP bitmap; + BYTE *pixels; + BITMAPINFOHEADER header; + + + IMAGEINDEX *table; + BYTE tableSize; + BYTE tableCount; + BYTE insertCursor; + BYTE readCursor; +}; + +#endif // NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPIMAGE_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupListbox.cpp b/Src/Plugins/Library/ml_online/Setup/setupListbox.cpp new file mode 100644 index 00000000..1035c699 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupListbox.cpp @@ -0,0 +1,878 @@ +#include "./setupPage.h" +#include "./setupListbox.h" +#include "./setupGroupList.h" +#include "./setupImage.h" +#include "../common.h" +#include "../resource.h" +#include "../api__ml_online.h" + +#include "../../nu/windowsTheme.h" + +#include <vssym32.h> + +//#include <tmschema.h> + +static ATOM SERVICELIST_PROP = 0; + +#define SLF_UNICODE 0x0001 +#define SLF_DRAGMOVE 0x0002 + +typedef BOOL (SetupListboxItem::*ITEMMOUSEPROC)(SetupListbox*, const RECT*, UINT, POINT); + +class Listbox : public SetupListbox +{ + +protected: + Listbox(HWND hListbox, SetupGroupList *groupList); + ~Listbox(); + +public: + static HRESULT AttachToWindow(HWND hwndListbox, SetupGroupList *groupList, SetupListbox **pInstance); + +public: + HWND GetHwnd() { return hwnd; } + HFONT GetFont() { return (HFONT)::SendMessage(hwnd, WM_GETFONT, 0, 0L); } + LRESULT CallDefaultProc(UINT uMsg, WPARAM wParam, LPARAM lParam); + LRESULT CallPrevProc(UINT uMsg, WPARAM wParam, LPARAM lParam); + + BOOL MeasureItem(INT itemId, UINT *cx, UINT *cy); + BOOL DrawItem(HDC hdc, const RECT *itemRect, INT itemId, UINT itemState, UINT itemAction); + INT_PTR KeyToItem(INT vKey, INT caretPos); + INT_PTR CharToItem(INT vKey, INT caretPos); + + BOOL DrawCheckbox(HDC hdc, BOOL checked, UINT state, const RECT *pRect, const RECT *pClipRect); + BOOL GetCheckboxMetrics(HDC hdc, BOOL checked, UINT state, SIZE *pSize); + + INT GetCheckboxThemeState(BOOL checked, UINT state); + INT HitTest(POINT pt, RECT *prcItem); + + void SetCapture(SetupListboxItem *item); + SetupListboxItem *GetCapture(); + void ReleaseCapture(); + BOOL InvalidateRect(const RECT *prcInvalidate, BOOL fErase); + BOOL InvalidateItem(INT itemId, BOOL fErase); + void UpdateCount(); + + BOOL DrawExpandbox(HDC hdc, BOOL fExpanded, const RECT *pRect, COLORREF rgbBk, COLORREF rgbFg); + BOOL GetExpandboxMetrics(HDC hdc, BOOL fExpanded, SIZE *pSize); + + INT GetPageCount(); + INT GetNextEnabledItem(INT iItem, SetupListboxItem **itemOut); + INT GetPrevEnabledItem(INT iItem, SetupListboxItem **itemOut); + + SetupListboxItem *GetSelection(); + BOOL SetSelection(SetupListboxItem *item); + BOOL GetIndex(SetupListboxItem *item, INT *iItem); + + BOOL DoDragAndDrop(UINT mouseEvent, UINT mouseFlags, POINT pt); + HMENU GetContextMenu(UINT menuId); + +protected: + friend static LRESULT WINAPI Listbox_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + LRESULT WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam); + + void OnDestroy(); + void GetItemRect(INT itemId, RECT *prcItem); + + SetupImage *GetExpandboxImage(HDC hdc, BOOL fExpanded); + + void OnMouseEvent(UINT mouseEvent, UINT mouseFlags, POINTS pts, BOOL fDefaultHandler, ITEMMOUSEPROC proc); + void OnMouseLeave(); + void OnEraseBkGround(HDC hdc); + void OnCaptureChanged(HWND hwndGained); + void NotifyReleaseCapture(INT itemId, SetupListboxItem *itemGain); + void OnCommand(INT commandId, INT eventId, HWND hControl); + +protected: + HWND hwnd; + UINT flags; + WNDPROC originalProc; + UXTHEME buttonTheme; + SetupGroupList *groups; + INT mouseoverId; + INT capturedId; + SetupImage *expandedImage; + SetupImage *collapsedImage; +}; + +#define GetList(__hwnd) ((Listbox*)GetPropW((__hwnd), MAKEINTATOM(SERVICELIST_PROP))) + + + + +HRESULT SetupListbox::CreateInstance(HWND hListbox, SetupGroupList *groupList, SetupListbox **pInstance) +{ + return Listbox::AttachToWindow(hListbox, groupList, pInstance); +} + +SetupListbox *SetupListbox::GetInstance(HWND hListbox) +{ + return GetList(hListbox); +} + +Listbox::Listbox(HWND hListbox, SetupGroupList *groupList) + : hwnd(hListbox), flags(0), originalProc(NULL), buttonTheme(NULL), groups(groupList), + mouseoverId(LB_ERR), capturedId(LB_ERR), expandedImage(NULL), collapsedImage(NULL) +{ + if (IsWindowUnicode(hwnd)) + flags |= SLF_UNICODE; + + buttonTheme = (UxIsAppThemed()) ? UxOpenThemeData(hwnd, L"Button") : NULL; + + groups->AddRef(); + UpdateCount(); + +} + +Listbox::~Listbox() +{ + if (NULL != hwnd) + { + RemoveProp(hwnd, MAKEINTATOM(SERVICELIST_PROP)); + if (NULL != originalProc) + { + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)originalProc); + CallPrevProc(WM_DESTROY, 0, 0L); + } + } + + if (NULL != groups) + groups->Release(); + + if (NULL != buttonTheme) + UxCloseThemeData(buttonTheme); + + if (NULL != expandedImage) + expandedImage->Release(); + + if (NULL != collapsedImage) + collapsedImage->Release(); +} + +HRESULT Listbox::AttachToWindow(HWND hListbox, SetupGroupList *groupList, SetupListbox **pInstance) +{ + if (0 == SERVICELIST_PROP) + { + SERVICELIST_PROP = GlobalAddAtom(TEXT("omSetupListbox")); + if (0 == SERVICELIST_PROP) return E_UNEXPECTED; + } + + + if(NULL == hListbox || !IsWindow(hListbox) || NULL == groupList) + return E_INVALIDARG; + + Listbox *list = new Listbox(hListbox, groupList); + if (NULL == list) + return E_OUTOFMEMORY; + + list->originalProc = (WNDPROC)(LONG_PTR)SetWindowLongPtr(hListbox, GWLP_WNDPROC, + (LONGX86)(LONG_PTR)Listbox_WindowProc); + + if (NULL == list->originalProc || !SetProp(hListbox, MAKEINTATOM(SERVICELIST_PROP), list)) + { + if (NULL != list->originalProc) + SetWindowLongPtr(hListbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)list->originalProc); + delete(list); + return E_FAIL; + } + + + if (NULL != pInstance) + *pInstance = list; + + return S_OK; +} + +LRESULT Listbox::CallDefaultProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + return (0 != (SLF_UNICODE & flags)) ? + DefWindowProcW(hwnd, uMsg, wParam, lParam) : + DefWindowProcA(hwnd, uMsg, wParam, lParam); +} + +LRESULT Listbox::CallPrevProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + return (0 != (SLF_UNICODE & flags)) ? + CallWindowProcW(originalProc, hwnd, uMsg, wParam, lParam) : + CallWindowProcA(originalProc, hwnd, uMsg, wParam, lParam); +} + + +void Listbox::UpdateCount() +{ + SendMessage(hwnd, WM_SETREDRAW, FALSE, 0L); + + INT iSelected = (INT)SendMessage(hwnd, LB_GETCURSEL, 0, 0L); + + size_t recordCount = (NULL != groups) ? groups->GetListboxCount() : 0; + SendMessage(hwnd, LB_SETCOUNT, (WPARAM)recordCount, 0L); + + SetupListboxItem *item; + UINT cy, maxCY = 0; + for (size_t i = 0; i < recordCount; i++) + { + if (SUCCEEDED(groups->FindListboxItem(i, &item)) && + item->MeasureItem(this, NULL, &cy) && cy > maxCY) + { + maxCY = cy; + } + } + + SendMessage(hwnd, LB_SETITEMHEIGHT, (WPARAM)0, (LPARAM)maxCY); + + if (recordCount > 0) + { + if (iSelected < 0) + iSelected = 0; + + if ((size_t)iSelected >= recordCount) + iSelected = (INT)(recordCount - 1); + + SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iSelected, TRUE); + SendMessage(hwnd, LB_SETANCHORINDEX, (WPARAM)iSelected, 0L); + SendMessage(hwnd, LB_SETCURSEL, (WPARAM)iSelected, 0L); + } + + SendMessage(hwnd, WM_SETREDRAW, TRUE, 0L); +} + +BOOL Listbox::MeasureItem(INT itemId, UINT *cx, UINT *cy) +{ + SetupListboxItem *item; + HRESULT hr = groups->FindListboxItem(itemId, &item); + return (SUCCEEDED(hr)) ? item->MeasureItem(this, cx, cy) : FALSE; +} + +BOOL Listbox::DrawItem(HDC hdc, const RECT *prcItem, INT itemId, UINT itemState, UINT itemAction) +{ + SetupListboxItem *item; + HRESULT hr = groups->FindListboxItem(itemId, &item); + if (FAILED(hr)) return FALSE; + + if (0 != (ODS_SELECTED & itemState) && GetFocus() != hwnd) + itemState |= ODS_INACTIVE; + + if (item->IsDisabled()) + itemState |= ODS_DISABLED; + + return item->DrawItem(this, hdc, prcItem, itemState); +} + +INT Listbox::GetPageCount() +{ + RECT clientRect; + if (NULL == hwnd || !GetClientRect(hwnd, &clientRect)) + return 0; + + INT itemHeight = (INT)SendMessage(hwnd, LB_GETITEMHEIGHT, 0, 0L); + return (clientRect.bottom - clientRect.top) / itemHeight; +} + +INT Listbox::GetNextEnabledItem(INT iItem, SetupListboxItem **itemOut) +{ + INT iLast = (INT)SendMessage(hwnd, LB_GETCOUNT, 0, 0L); + if (iLast >= 0) iLast--; + + SetupListboxItem *testItem; + while(iItem++ < iLast) + { + if (SUCCEEDED(groups->FindListboxItem(iItem, &testItem))) + { + if (FALSE == testItem->IsDisabled()) break; + } + } + if (NULL != itemOut) + { + *itemOut = (iItem <= iLast) ? testItem : NULL; + } + return (iItem <= iLast) ? iItem : LB_ERR; +} + +INT Listbox::GetPrevEnabledItem(INT iItem, SetupListboxItem **itemOut) +{ + SetupListboxItem *testItem; + while(iItem-- > 0) + { + if (SUCCEEDED(groups->FindListboxItem(iItem, &testItem))) + { + if (FALSE == testItem->IsDisabled()) break; + } + } + + if (NULL != itemOut) + { + *itemOut = (iItem >= 0) ? testItem : NULL; + } + return (iItem >= 0) ? iItem : LB_ERR; +} + +SetupListboxItem *Listbox::GetSelection() +{ + INT iSelected = (INT)SendMessage(hwnd, LB_GETCURSEL, 0, 0L); + if (LB_ERR == iSelected) + return NULL; + + SetupListboxItem *item; + return (SUCCEEDED(groups->FindListboxItem(iSelected, &item))) ? item : NULL; +} + +BOOL Listbox::SetSelection(SetupListboxItem *item) +{ + INT iItem = LB_ERR; + if (NULL != item) + { + iItem = groups->GetListboxItem(item); + if (LB_ERR == iItem) + return FALSE; + } + + BOOL resultOk = (LB_ERR != SendMessage(hwnd, LB_SETCURSEL, (WPARAM)iItem, 0L)); + if (LB_ERR == iItem) resultOk = TRUE; + + if (LB_ERR != iItem) + { + HWND hParent = GetParent(hwnd); + if (NULL != hParent) + SendMessage(hParent, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), LBN_SELCHANGE), (LPARAM)hwnd); + } + return resultOk; +} + +BOOL Listbox::GetIndex(SetupListboxItem *item, INT *iItem) +{ + if (NULL == iItem) + return FALSE; + + *iItem = (NULL != item && NULL != groups) ? groups->GetListboxItem(item) : LB_ERR; + return (LB_ERR != *iItem); +} + +INT_PTR Listbox::KeyToItem(INT vKey, INT iCaret) +{ + SetupListboxItem *item; + HRESULT hr = groups->FindListboxItem(iCaret, &item); + if (FAILED(hr)) return -1; + + RECT itemRect; + GetItemRect(iCaret, &itemRect); + INT_PTR result = item->KeyToItem(this, &itemRect, vKey); + if (-1 != result) return result; + + INT iTarget, iCount; + + switch(vKey) + { + case VK_UP: + case VK_LEFT: + iTarget = GetPrevEnabledItem(iCaret, NULL); + if (LB_ERR != iTarget) return iTarget; + + SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)0, 0L); + SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iCaret, FALSE); + return -2; + + case VK_DOWN: + case VK_RIGHT: + iTarget = GetNextEnabledItem(iCaret, NULL); + if (LB_ERR != iTarget) return iTarget; + + SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)iCaret, 0L); + return -2; + + case VK_HOME: + if (iCaret > 0) + { + SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)0, 0L); + iTarget = GetNextEnabledItem(-1, NULL); + if (iTarget >= iCaret) iTarget = LB_ERR; + if (LB_ERR != iTarget) return iTarget; + SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iCaret, FALSE); + } + return -2; + + case VK_PRIOR: + if (iCaret > 0) + { + INT iTop = (INT)SendMessage(hwnd, LB_GETTOPINDEX, 0, 0L); + if (iTop == iCaret) + { + INT iPage = iCaret - GetPageCount() + 1; + iTop = (iPage <= 0) ? 0 : (iPage - 1); + } + + iTarget = GetPrevEnabledItem(iTop + 1, NULL); + + if (LB_ERR == iTarget) + { + SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)0, 0L); + iTarget = GetNextEnabledItem(iTop, NULL); + if (iTarget > iCaret) iTarget = LB_ERR; + } + + if (LB_ERR != iTarget) return iTarget; + SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iCaret, FALSE); + } + return -2; + + case VK_END: + iCount = (INT)SendMessage(hwnd, LB_GETCOUNT, 0, 0L); + if (iCount > 0 && iCaret != (iCount - 1)) + { + SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)(iCount - 1), 0L); + iTarget = GetPrevEnabledItem(iCount, NULL); + if (iTarget <= iCaret) iTarget = LB_ERR; + if (LB_ERR != iTarget) return iTarget; + SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iCaret, FALSE); + } + return -2; + + case VK_NEXT: + iCount = (INT)SendMessage(hwnd, LB_GETCOUNT, 0, 0L); + if (iCount > 0 && iCaret != (iCount - 1)) + { + INT iPage = GetPageCount(); + INT iBottom = (INT)SendMessage(hwnd, LB_GETTOPINDEX, 0, 0L) + iPage - 1; + if (iBottom == iCaret) + { + iBottom += iPage; + if (iBottom >= iCount) iBottom = iCount -1; + } + iTarget = GetNextEnabledItem(iBottom - 1, NULL); + if (LB_ERR == iTarget) + { + SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)(iCount - 1), 0L); + iTarget = GetPrevEnabledItem(iBottom, NULL); + if (iTarget < iCaret) iTarget = LB_ERR; + } + + if (LB_ERR != iTarget) return iTarget; + SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iCaret, FALSE); + } + return -2; + } + + return result; +} + +INT_PTR Listbox::CharToItem(INT vKey, INT caretPos) +{ + return -2; + //SetupListboxItem *item; + //HRESULT hr = groups->FindListboxItem(caretPos, &item); + //return (SUCCEEDED(hr)) ? item->CharToItem(this, vKey) : -1; +} + +INT Listbox::GetCheckboxThemeState(BOOL checked, UINT state) +{ + if (FALSE != checked) + { + if (0 != (ODS_DISABLED & state)) return CBS_CHECKEDDISABLED; + if (0 != (ODS_HOTLIGHT & state)) return CBS_CHECKEDHOT; + if (0 != (ODS_SELECTED & state)) return CBS_CHECKEDPRESSED; + return CBS_CHECKEDNORMAL; + } + + if (0 != (ODS_DISABLED & state)) return CBS_UNCHECKEDDISABLED; + if (0 != (ODS_HOTLIGHT & state)) return CBS_UNCHECKEDHOT; + if (0 != (ODS_SELECTED & state)) return CBS_UNCHECKEDPRESSED; + return CBS_UNCHECKEDNORMAL; +} + +BOOL Listbox::DrawCheckbox(HDC hdc, BOOL checked, UINT state, const RECT *pRect, const RECT *pClipRect) +{ + if (NULL != buttonTheme) + { + INT stateId = GetCheckboxThemeState(checked, state); + if (SUCCEEDED(UxDrawThemeBackground(buttonTheme, hdc, BP_CHECKBOX, stateId, pRect, pClipRect))) + return TRUE; + } + + UINT stateId = DFCS_BUTTONCHECK; + if (FALSE != checked) stateId |= DFCS_CHECKED; + if (0 != (ODS_DISABLED & state)) stateId |= DFCS_INACTIVE; + if (0 != (ODS_HOTLIGHT & state)) stateId |= DFCS_HOT; + if (0 != (ODS_SELECTED & state)) stateId |= DFCS_PUSHED; + + return DrawFrameControl(hdc, (LPRECT)pRect,DFC_BUTTON, stateId); +} + +BOOL Listbox::GetCheckboxMetrics(HDC hdc, BOOL checked, UINT state, SIZE *pSize) +{ + if (NULL != buttonTheme) + { + HDC hdcMine = NULL; + + if (NULL == hdc) + { + hdcMine = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); + hdc = hdcMine; + } + + INT stateId = GetCheckboxThemeState(checked, state); + HRESULT hr = UxGetThemePartSize(buttonTheme, hdc, BP_CHECKBOX, + stateId, NULL, TS_DRAW, pSize); + + if (NULL != hdcMine) + ReleaseDC(hwnd, hdcMine); + if (SUCCEEDED(hr)) return TRUE; + } + pSize->cx = 13; + pSize->cy = 13; + return TRUE; +} + +void Listbox::OnDestroy() +{ + delete(this); +} + + +INT Listbox::HitTest(POINT pt, RECT *prcItem) +{ + RECT itemRect; + INT itemId = (INT)SendMessage(hwnd, LB_ITEMFROMPOINT, 0, MAKELONG(pt.x, pt.y)); + + if (LB_ERR == itemId || + LB_ERR == SendMessage(hwnd, LB_GETITEMRECT, (WPARAM)itemId, (LPARAM)&itemRect) || + FALSE == PtInRect(&itemRect, pt)) + { + return LB_ERR; + } + + if (NULL != prcItem) + CopyRect(prcItem, &itemRect); + + return itemId; +} + +void Listbox::GetItemRect(INT itemId, RECT *prcItem) +{ + if (LB_ERR == ::SendMessage(hwnd, LB_GETITEMRECT, (WPARAM)itemId, (LPARAM)prcItem)) + SetRectEmpty(prcItem); +} + +BOOL Listbox::DoDragAndDrop(UINT mouseEvent, UINT mouseFlags, POINT pt) +{ + if (WM_MOUSEMOVE == mouseEvent && + 0 != ((MK_LBUTTON | MK_MBUTTON | MK_RBUTTON) & mouseFlags)) + { + flags |= SLF_DRAGMOVE; + } + else + { + flags &= ~SLF_DRAGMOVE; + } + return (0 != (SLF_DRAGMOVE & flags)); +} + +void Listbox::OnMouseEvent(UINT mouseEvent, UINT mouseFlags, POINTS pts, BOOL fDefaultHandler, ITEMMOUSEPROC proc) +{ + POINT pt; + POINTSTOPOINT(pt, pts); + SetupListboxItem *item; + RECT itemRect; + + if (LB_ERR != capturedId) + { + if (SUCCEEDED(groups->FindListboxItem(capturedId, &item))) + { + GetItemRect(capturedId, &itemRect); + if (FALSE == ((item->*proc)(this, &itemRect, mouseFlags, pt))) + { + CallPrevProc(mouseEvent, (WPARAM)mouseFlags, *((LPARAM*)&pts)); + } + return; + } + capturedId = LB_ERR; + } + + if (DoDragAndDrop(mouseEvent, mouseFlags, pt)) + return; + + INT itemId = HitTest(pt, &itemRect); + if (mouseoverId != itemId) + { + if (SUCCEEDED(groups->FindListboxItem(mouseoverId, &item))) + { + RECT leaveRect; + GetItemRect(mouseoverId, &leaveRect); + item->MouseLeave(this, &leaveRect); + } + mouseoverId = itemId; + + TRACKMOUSEEVENT tm; + tm.cbSize = sizeof(TRACKMOUSEEVENT); + tm.hwndTrack = hwnd; + tm.dwFlags = TME_LEAVE; + if (LB_ERR == mouseoverId) + tm.dwFlags |= TME_CANCEL; + TrackMouseEvent(&tm); + } + + if (LB_ERR != mouseoverId) + { + if (SUCCEEDED(groups->FindListboxItem(mouseoverId, &item))) + { + BOOL callListbox = FALSE; + if (FALSE != item->IsDisabled()) + { + switch(mouseEvent) + { + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + case 0x020C /*WM_XBUTTONUP*/: + callListbox = TRUE; + break; + } + } + else + { + if (FALSE == ((item->*proc)(this, &itemRect, mouseFlags, pt))) + { + callListbox = TRUE; + } + } + + if (FALSE != callListbox) + { + CallPrevProc(mouseEvent, (WPARAM)mouseFlags, *((LPARAM*)&pts)); + } + return; + } + } + + if (FALSE != fDefaultHandler) + { + CallPrevProc(mouseEvent, (WPARAM)mouseFlags, *((LPARAM*)&pts)); + } +} + +void Listbox::OnMouseLeave() +{ + if (LB_ERR != mouseoverId) + { + SetupListboxItem *item; + INT itemId = mouseoverId; + mouseoverId = LB_ERR; + if (SUCCEEDED(groups->FindListboxItem(itemId, &item))) + { + RECT itemRect; + GetItemRect(itemId, &itemRect); + if (item->MouseLeave(this, &itemRect)) + return; + } + } + CallPrevProc(WM_MOUSELEAVE, 0, 0L); +} + +void Listbox::SetCapture(SetupListboxItem *item) +{ + INT prevCapturedId = capturedId; + capturedId = (NULL != item) ? groups->GetListboxItem(item) : LB_ERR; + + NotifyReleaseCapture(prevCapturedId, item); + + if (LB_ERR != capturedId && ::GetCapture() != hwnd) + ::SetCapture(hwnd); +} + +SetupListboxItem *Listbox::GetCapture() +{ + SetupListboxItem *capturedItem; + if (LB_ERR == capturedId || FAILED(groups->FindListboxItem(capturedId, &capturedItem))) + capturedItem = NULL; + + return capturedItem; +} + +void Listbox::ReleaseCapture() +{ + if (LB_ERR != capturedId) + { + INT prevCapturedId = capturedId; + capturedId = LB_ERR; + + NotifyReleaseCapture(prevCapturedId, NULL); + if (::GetCapture() == hwnd) + ::ReleaseCapture(); + } +} + +void Listbox::NotifyReleaseCapture(INT itemId, SetupListboxItem *itemGain) +{ + if (LB_ERR == itemId) + return; + + SetupListboxItem *item; + if (SUCCEEDED(groups->FindListboxItem(itemId, &item))) + { + RECT itemRect; + GetItemRect(itemId, &itemRect); + item->CaptureChanged(this, &itemRect, itemGain); + } +} + +void Listbox::OnCaptureChanged(HWND hwndGained) +{ + if (hwnd != hwndGained && LB_ERR != capturedId) + { + INT prevCapturedId = capturedId; + capturedId = LB_ERR; + NotifyReleaseCapture(prevCapturedId, NULL); + } +} + +BOOL Listbox::InvalidateRect(const RECT *prcInvalidate, BOOL fErase) +{ + return ::InvalidateRect(hwnd, prcInvalidate, fErase); +} + +BOOL Listbox::InvalidateItem(INT itemId, BOOL fErase) +{ + if (itemId < 0) return FALSE; + + RECT itemRect; + if (LB_ERR == SendMessage(hwnd, LB_GETITEMRECT, (WPARAM)itemId, (LPARAM)&itemRect)) + return FALSE; + + return ::InvalidateRect(hwnd, &itemRect, fErase); +} + +void Listbox::OnEraseBkGround(HDC hdc) +{ + INT iCount = (INT)SendMessage(hwnd, LB_GETCOUNT, 0, 0L); + RECT clientRect, itemRect; + + GetClientRect(hwnd, &clientRect); + if (iCount > 0 && + LB_ERR != SendMessage(hwnd, LB_GETITEMRECT, (WPARAM)(iCount - 1), (LPARAM)&itemRect)) + { + clientRect.top = itemRect.top; + } + + if (clientRect.top < clientRect.bottom) + { + HBRUSH hb = NULL; + HWND hParent = GetParent(hwnd); + if (NULL != hParent) + { + hb = (HBRUSH)SendMessage(hParent, WM_CTLCOLORLISTBOX, (WPARAM)hdc, (LPARAM)hwnd); + } + if (NULL == hb) + { + hb = GetSysColorBrush(COLOR_WINDOW); + } + FillRect(hdc, &clientRect, hb); + } +} + +void Listbox::OnCommand(INT commandId, INT eventId, HWND hControl) +{ + if (NULL == hControl) + { + SetupListboxItem *item = GetSelection(); + if (NULL != item) + { + item->Command(this, commandId, eventId); + } + + } +} +SetupImage *Listbox::GetExpandboxImage(HDC hdc, BOOL fExpanded) +{ + if (fExpanded) + { + if (NULL == expandedImage) + expandedImage = SetupImage::CreateFromPluginBitmap(hdc, L"gen_ml.dll", MAKEINTRESOURCE(137), 3); + return expandedImage; + } + + if (NULL == collapsedImage) + collapsedImage = SetupImage::CreateFromPluginBitmap(hdc, L"gen_ml.dll", MAKEINTRESOURCE(135), 3); + return collapsedImage; +} + +BOOL Listbox::DrawExpandbox(HDC hdc, BOOL fExpanded, const RECT *pRect, COLORREF rgbBk, COLORREF rgbFg) +{ + SetupImage *image = GetExpandboxImage(hdc, fExpanded); + return (NULL != image) ? + image->DrawImage(hdc, pRect->left, pRect->top, + pRect->right - pRect->left, pRect->bottom- pRect->top, + 0, 0, rgbBk, rgbFg) + : FALSE; +} + +BOOL Listbox::GetExpandboxMetrics(HDC hdc, BOOL fExpanded, SIZE *pSize) +{ + SetupImage *image = GetExpandboxImage(hdc, fExpanded); + return (NULL != image) ? image->GetSize(pSize) : FALSE; +} + +HMENU Listbox::GetContextMenu(UINT menuId) +{ + HMENU baseMenu = WASABI_API_LOADMENUW(IDR_SETUPMENU); + if (NULL == baseMenu) + return NULL; + + switch(menuId) + { + case menuGroupContext: + return GetSubMenu(baseMenu, 0); + } + return NULL; +} + +LRESULT Listbox::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_DESTROY: + OnDestroy(); + return 0; + case WM_MOUSEMOVE: + OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), TRUE, &SetupListboxItem::MouseMove); + return 0; + case WM_LBUTTONDOWN: + OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), FALSE, &SetupListboxItem::LButtonDown); + return 0; + case WM_LBUTTONUP: + OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), TRUE, &SetupListboxItem::LButtonUp); + return 0; + case WM_LBUTTONDBLCLK: + OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), FALSE, &SetupListboxItem::LButtonDblClk); + return 0; + case WM_RBUTTONDOWN: + OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), FALSE, &SetupListboxItem::RButtonDown); + return 0; + case WM_RBUTTONUP: + OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), TRUE, &SetupListboxItem::RButtonUp); + return 0; + case WM_MOUSELEAVE: + OnMouseLeave(); + return 0; + case WM_CAPTURECHANGED: + OnCaptureChanged((HWND)lParam); + break; + case WM_ERASEBKGND: + OnEraseBkGround((HDC)wParam); + return TRUE; + case WM_COMMAND: + OnCommand(LOWORD(wParam), HIWORD(wParam), (HWND)lParam); + return 0; + } + + return CallPrevProc(uMsg, wParam, lParam); +} + +static LRESULT WINAPI Listbox_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + Listbox *list = GetList(hwnd); + if (NULL != list) + return list->WindowProc(uMsg, wParam, lParam); + + return (IsWindowUnicode(hwnd)) ? + DefWindowProcW(hwnd, uMsg, wParam, lParam) : + DefWindowProcA(hwnd, uMsg, wParam, lParam); + +} diff --git a/Src/Plugins/Library/ml_online/Setup/setupListbox.h b/Src/Plugins/Library/ml_online/Setup/setupListbox.h new file mode 100644 index 00000000..0fceffc3 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupListbox.h @@ -0,0 +1,84 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPLISTBOX_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPLISTBOX_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <windows.h> + +class SetupGroupList; +class SetupListboxItem; + +class __declspec(novtable) SetupListbox +{ +public: + typedef enum + { + menuGroupContext = 0, + } contextMenu; + +public: + static HRESULT CreateInstance(HWND hListbox, SetupGroupList *groupList, SetupListbox **pInstance); + static SetupListbox *GetInstance(HWND hListbox); + +public: + virtual HWND GetHwnd() = 0; + virtual HFONT GetFont() = 0; + virtual LRESULT CallDefaultProc(UINT uMsg, WPARAM wParam, LPARAM lParam) = 0; + virtual LRESULT CallPrevProc(UINT uMsg, WPARAM wParam, LPARAM lParam) = 0; + + virtual BOOL MeasureItem(INT itemId, UINT *cx, UINT *cy) = 0; + virtual BOOL DrawItem(HDC hdc, const RECT *prcItem, INT itemId, UINT itemState, UINT itemAction) = 0; + virtual INT_PTR KeyToItem(INT vKey, INT caretPos) = 0; + virtual INT_PTR CharToItem(INT vKey, INT caretPos) = 0; + + virtual BOOL DrawCheckbox(HDC hdc, BOOL checked, UINT state, const RECT *pRect, const RECT *pClipRect) = 0; + virtual BOOL GetCheckboxMetrics(HDC hdc, BOOL checked, UINT state, SIZE *pSize) = 0; + virtual void SetCapture(SetupListboxItem *item) = 0; + virtual SetupListboxItem *GetCapture() = 0; + virtual void ReleaseCapture() = 0; + + virtual BOOL InvalidateRect(const RECT *prcInvalidate, BOOL fErase) = 0; + virtual BOOL InvalidateItem(INT iItem, BOOL fErase) = 0; + virtual void UpdateCount() = 0; + + + virtual BOOL DrawExpandbox(HDC hdc, BOOL fExpanded, const RECT *pRect, COLORREF rgbBk, COLORREF rgbFg) = 0; + virtual BOOL GetExpandboxMetrics(HDC hdc, BOOL fExpanded, SIZE *pSize) = 0; + + virtual INT GetPageCount() = 0; + virtual INT GetNextEnabledItem(INT iItem, SetupListboxItem **itemOut) = 0; + virtual INT GetPrevEnabledItem(INT iItem, SetupListboxItem **itemOut) = 0; + virtual SetupListboxItem *GetSelection() = 0; + virtual BOOL SetSelection(SetupListboxItem *item) = 0; + virtual BOOL GetIndex(SetupListboxItem *item, INT *iItem) = 0; + + virtual HMENU GetContextMenu(UINT menuId) = 0; + + +}; + +class __declspec(novtable) SetupListboxItem +{ + +public: + virtual BOOL MeasureItem(SetupListbox *instance, UINT *cx, UINT *cy) = 0; + virtual BOOL DrawItem(SetupListbox *instance, HDC hdc, const RECT *prc, UINT state) = 0; + virtual INT_PTR KeyToItem(SetupListbox *instance, const RECT *prcItem, INT vKey) = 0; + virtual BOOL MouseMove(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) = 0; + virtual BOOL MouseLeave(SetupListbox *instance, const RECT *prcItem) = 0; + virtual BOOL LButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) = 0; + virtual BOOL LButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) = 0; + virtual BOOL LButtonDblClk(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) = 0; + virtual BOOL RButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) = 0; + virtual BOOL RButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) = 0; + virtual void CaptureChanged(SetupListbox *instance, const RECT *prcItem, SetupListboxItem *captured) = 0; + virtual BOOL IsDisabled() = 0; + virtual void Command(SetupListbox *instance, INT commandId, INT eventId) = 0; + + virtual HWND CreateDetailsView(HWND hParent) = 0; + virtual BOOL GetUniqueName(LPWSTR pszBuffer, UINT cchBufferMax) = 0; +}; + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPLISTBOX_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupListboxLabel.cpp b/Src/Plugins/Library/ml_online/Setup/setupListboxLabel.cpp new file mode 100644 index 00000000..0a24b61e --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupListboxLabel.cpp @@ -0,0 +1,228 @@ +#include "./setupListboxLabel.h" +#include "../api__ml_online.h" +#include "../common.h" + +#include <shlwapi.h> +#include <strsafe.h> + +#define LABEL_MARGINCX 0 +#define LABEL_MARGINCY 1 + +#define TEXT_OFFSET_LEFT 2 +#define TEXT_OFFSET_BOTTOM 2 +#define TEXT_ALIGN (TA_CENTER | TA_BOTTOM) + +SetupListboxLabel::SetupListboxLabel(LPCWSTR pszName) + : ref(1), name(NULL) +{ + SetName(pszName); +} + +SetupListboxLabel::~SetupListboxLabel() +{ + SetName(NULL); +} + +SetupListboxLabel *SetupListboxLabel::CreateInstance(LPCWSTR pszName) +{ + return new SetupListboxLabel(pszName); +} + +ULONG SetupListboxLabel::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG SetupListboxLabel::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + return r; +} + +HRESULT SetupListboxLabel::GetName(LPWSTR pszBuffer, INT cchBufferMax) +{ + if (NULL == pszBuffer) + return E_POINTER; + + if (NULL != name && IS_INTRESOURCE(name)) + { + WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)name, pszBuffer, cchBufferMax); + return (L'\0' != *pszBuffer) ? S_OK : E_FAIL; + } + return StringCchCopyExW(pszBuffer, cchBufferMax, name, NULL, NULL, STRSAFE_IGNORE_NULLS); +} +HRESULT SetupListboxLabel::SetName(LPCWSTR pszName) +{ + if (NULL != name && !IS_INTRESOURCE(name)) + Plugin_FreeString(name); + + if (IS_INTRESOURCE(pszName)) + { + name = (LPWSTR)pszName; + } + else + { + name = Plugin_CopyString(pszName); + } + + return S_OK; +} + +BOOL SetupListboxLabel::IsNameNull() +{ + return (NULL == name); +} + +void SetupListboxLabel::GetColors(HDC hdc, UINT state, COLORREF *rgbBkOut, COLORREF *rgbTextOut) +{ + COLORREF rgbBk, rgbText; + + rgbBk = GetSysColor(COLOR_WINDOW); + rgbText = GetSysColor( (0 == (ODS_DISABLED & state)) ? COLOR_GRAYTEXT : COLOR_GRAYTEXT); + + if (NULL != rgbBkOut) *rgbBkOut = rgbBk; + if (NULL != rgbTextOut) *rgbTextOut = rgbText; +} + +HBRUSH SetupListboxLabel::GetBrush(HDC hdc, UINT state) +{ + return GetSysColorBrush(COLOR_WINDOW); +} + +BOOL SetupListboxLabel::MeasureItem(SetupListbox *instance, UINT *cx, UINT *cy) +{ + HDC hdc = GetDCEx(instance->GetHwnd(), NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL == hdc) return FALSE; + + HFONT originalFont = (HFONT)SelectObject(hdc, instance->GetFont()); + + if (NULL != cy) + { + *cy = 0; + TEXTMETRIC tm; + if (GetTextMetrics(hdc, &tm)) + *cy = tm.tmHeight + tm.tmExternalLeading + LABEL_MARGINCY*2; + } + + if (NULL != cx) + { + *cx = 0; + WCHAR szBuffer[128] = {0}; + if (SUCCEEDED(GetName(szBuffer, ARRAYSIZE(szBuffer)))) + { + INT cchBuffer = lstrlenW(szBuffer); + SIZE textSize; + if (0 != cchBuffer && GetTextExtentPoint32(hdc, szBuffer, cchBuffer, &textSize)) + { + *cx = textSize.cx + LABEL_MARGINCX*2; + } + } + } + + SelectObject(hdc, originalFont); + ReleaseDC(instance->GetHwnd(), hdc); + return TRUE; +} + +BOOL SetupListboxLabel::DrawItem(SetupListbox *instance, HDC hdc, const RECT *prc, UINT state) +{ + LONG paintLeft = prc->left + LABEL_MARGINCX; + + COLORREF rgbBk, rgbText; + GetColors(hdc, state, &rgbBk, &rgbText); + + COLORREF origBk = SetBkColor(hdc, rgbBk); + COLORREF origText = SetTextColor(hdc, rgbText); + UINT textAlign = SetTextAlign(hdc, TEXT_ALIGN); + + HRGN backRgn, rgn; + backRgn = CreateRectRgnIndirect(prc); + rgn = CreateRectRgn(0,0,0,0); + + RECT partRect; + WCHAR szBuffer[128] = {0}; + INT cchBuffer = 0; + + if (SUCCEEDED(GetName(szBuffer, ARRAYSIZE(szBuffer)))) + cchBuffer = lstrlenW(szBuffer); + + SetRect(&partRect, paintLeft, prc->top, prc->right - LABEL_MARGINCX, prc->bottom); + if (ExtTextOut(hdc, partRect.left + (partRect.right - partRect.left)/2, partRect.bottom - TEXT_OFFSET_BOTTOM, + ETO_OPAQUE | ETO_CLIPPED, &partRect, szBuffer, cchBuffer, NULL)) + { + if (SetRectRgn(rgn, partRect.left, partRect.top, partRect.right, partRect.bottom)) + CombineRgn(backRgn, backRgn, rgn, RGN_DIFF); + } + + if (NULL != backRgn) + { + FillRgn(hdc, backRgn, GetBrush(hdc, state)); + DeleteObject(backRgn); + } + if (NULL != rgn) + DeleteObject(rgn); + + + if (ODS_FOCUS == ((ODS_FOCUS | 0x0200/*ODS_NOFOCUSRECT*/) & state)) + DrawFocusRect(hdc, prc); + + if (TEXT_ALIGN != textAlign) SetTextAlign(hdc, textAlign); + if (origBk != rgbBk) SetBkColor(hdc, origBk); + if (origText != rgbText) SetTextColor(hdc, origText); + return TRUE; +} + +INT_PTR SetupListboxLabel::KeyToItem(SetupListbox *instance, const RECT *prcItem, INT vKey) +{ + return -1; +} +BOOL SetupListboxLabel::MouseMove(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} +BOOL SetupListboxLabel::MouseLeave(SetupListbox *instance, const RECT *prcItem) +{ + return FALSE; +} +BOOL SetupListboxLabel::LButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} +BOOL SetupListboxLabel::LButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} +BOOL SetupListboxLabel::LButtonDblClk(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} +BOOL SetupListboxLabel::RButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} +BOOL SetupListboxLabel::RButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} +void SetupListboxLabel::CaptureChanged(SetupListbox *instance, const RECT *prcItem, SetupListboxItem *captured) +{ +} + +BOOL SetupListboxLabel::GetUniqueName(LPWSTR pszBuffer, UINT cchBufferMax) +{ + WCHAR szName[128] = {0}; + if (FAILED(GetName(szName, ARRAYSIZE(szName)))) + return FALSE; + + if (NULL == pszBuffer || + FAILED(StringCchPrintf(pszBuffer, cchBufferMax, L"lbl_empty_%s", szName))) + { + return FALSE; + } + return TRUE; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupListboxLabel.h b/Src/Plugins/Library/ml_online/Setup/setupListboxLabel.h new file mode 100644 index 00000000..b1b474e4 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupListboxLabel.h @@ -0,0 +1,57 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPLISTBOX_LABEL_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPLISTBOX_LABEL_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "./setupListbox.h" + + +class SetupListboxLabel: public SetupListboxItem +{ + +protected: + SetupListboxLabel(LPCWSTR pszName); + ~SetupListboxLabel(); + +public: + static SetupListboxLabel *CreateInstance(LPCWSTR pszNamee); + +public: + ULONG AddRef(); + ULONG Release(); + + HRESULT GetName(LPWSTR pszBuffer, INT cchBufferMax); + HRESULT SetName(LPCWSTR pszName); + BOOL IsNameNull(); + + void GetColors(HDC hdc, UINT state, COLORREF *rgbBkOut, COLORREF *rgbTextOut); + HBRUSH GetBrush(HDC hdc, UINT state); + + + /* SetupListboxItem */ + BOOL MeasureItem(SetupListbox *instance, UINT *cx, UINT *cy); + BOOL DrawItem(SetupListbox *instance, HDC hdc, const RECT *prc, UINT state); + INT_PTR KeyToItem(SetupListbox *instance, const RECT *prcItem, INT vKey); + BOOL MouseMove(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL MouseLeave(SetupListbox *instance, const RECT *prcItem); + BOOL LButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL LButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL LButtonDblClk(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL RButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL RButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + void CaptureChanged(SetupListbox *instance, const RECT *prcItem, SetupListboxItem *captured); + BOOL IsDisabled() { return TRUE; } + void Command(SetupListbox *instance, INT commandId, INT eventId) {} + HWND CreateDetailsView(HWND hParent) { return NULL; } + BOOL GetUniqueName(LPWSTR pszBuffer, UINT cchBufferMax); + + +protected: + ULONG ref; + LPWSTR name; +}; + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPLISTBOX_LABEL_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupLog.cpp b/Src/Plugins/Library/ml_online/Setup/setupLog.cpp new file mode 100644 index 00000000..a53c469f --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupLog.cpp @@ -0,0 +1,395 @@ +#include "./setupLog.h" +#include "../common.h" +#include "../api__ml_online.h" +#include "../config.h" + +#include "../../nu/trace.h" + +#include <ifc_omservice.h> +#include <ifc_omwebstorage.h> +#include <ifc_omstorageasync.h> + +#include <shlwapi.h> +#include <strsafe.h> + +#define SETUPLOG_SEPARATOR ',' +#define SETUPLOG_SECTION "Setup" +#define SETUPLOG_KEY_SUBSCRIBED "subscribed" +#define SETUPLOG_KEY_UNSUBSCRIBED "unsubscribed" + +struct LOGPARSERPARAM +{ + LOGPARSERPARAM() : instance(NULL), operation(0) {} + + SetupLog *instance; + UINT operation; +}; + +static size_t SetupLog_GetMaxServiceIdCount(SetupLog::ServiceMap *serviceMap) +{ + SetupLog::ServiceMap::iterator it; + + size_t c1 = 0, c2 = 0; + for (it = serviceMap->begin(); it != serviceMap->end(); it++) + { + switch(it->second) + { + case SetupLog::opServiceAdded: + c1++; + break; + case SetupLog::opServiceRemoved: + c2++; + break; + } + } + return (c1 > c2) ? c1 : c2; +} + +static HRESULT SetupLog_FormatServiceId(SetupLog::ServiceMap *serviceMap, INT operation, LPSTR pszBuffer, size_t cchBufferMax) +{ + if (NULL == pszBuffer) + return E_INVALIDARG; + + *pszBuffer = '\0'; + + if (NULL == serviceMap) + return S_OK; + + HRESULT hr = S_OK; + size_t remaining = cchBufferMax; + LPSTR cursor = pszBuffer; + SetupLog::ServiceMap::iterator it; + + const char format[] = { SETUPLOG_SEPARATOR, '%', 'u', '\0'}; + + for (it = serviceMap->begin(); it != serviceMap->end() && SUCCEEDED(hr); it++) + { + if (it->second == operation) + { + hr = StringCchPrintfExA(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, + ((cursor == pszBuffer) ? (format + 1) : format), it->first); + } + } + return hr; +} + +static LPCSTR SetupLog_GetOperationKey(UINT operation) +{ + switch(operation) + { + case SetupLog::opServiceAdded: return SETUPLOG_KEY_SUBSCRIBED; + case SetupLog::opServiceRemoved: return SETUPLOG_KEY_UNSUBSCRIBED; + } + return NULL; +} + +static LPCWSTR SetupLog_GetOperationAction(UINT operation) +{ + switch(operation) + { + case SetupLog::opServiceAdded: return L"add"; + case SetupLog::opServiceRemoved: return L"remove"; + } + return NULL; +} + +static BOOL SetupLog_WriteOperationLog(UINT operation, LPCSTR pszValue) +{ + LPCSTR pszKey = SetupLog_GetOperationKey(operation); + if (NULL == pszKey) return FALSE; + return Config_WriteStr(SETUPLOG_SECTION, pszKey, pszValue); +} + +static HRESULT SetupLog_ReadOperationLog(UINT operation, LPSTR pszBuffer, UINT cchBufferMax, UINT *cchReaded) +{ + LPCSTR pszKey = SetupLog_GetOperationKey(operation); + if (NULL == pszKey) return E_INVALIDARG; + + DWORD readed = Config_ReadStr(SETUPLOG_SECTION, pszKey, NULL, pszBuffer, cchBufferMax); + + if (NULL != cchReaded) + { + *cchReaded = readed; + } + + return S_OK; +} + +SetupLog::SetupLog() : ref(1) +{ +} + +SetupLog::~SetupLog() +{ + +} + +SetupLog *SetupLog::Open() +{ + SetupLog *instance = new SetupLog(); + if (NULL == instance) return NULL; + + INT cchBuffer = 32000; + LPSTR buffer = Plugin_MallocAnsiString(cchBuffer); + if (NULL == buffer) + { + instance->Release(); + return NULL; + } + + UINT cchReaded = 0; + const UINT szOperations[] = { opServiceAdded, + opServiceRemoved, }; + + UINT serviceId; + for (INT i = 0; i < ARRAYSIZE(szOperations); i++) + { + if (SUCCEEDED(SetupLog_ReadOperationLog(szOperations[i], buffer, cchBuffer, &cchReaded)) && cchReaded > 0) + { + LPSTR cursor = buffer; + LPSTR block = cursor; + + for(;;) + { + if (SETUPLOG_SEPARATOR == *cursor || '\0' == *cursor) + { + while (' ' == *block && block < cursor) block++; + + if (block < cursor && + FALSE != StrToIntExA(block, STIF_SUPPORT_HEX, (INT*)&serviceId) && + 0 != serviceId) + { + instance->LogServiceById(serviceId, szOperations[i]); + } + + if ('\0' == *cursor) + break; + + cursor++; + block = cursor; + } + else + { + cursor++; + } + } + } + } + + Plugin_FreeAnsiString(buffer); + return instance; +} + +ULONG SetupLog::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG SetupLog::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +BOOL SetupLog::IsOperationSupported(UINT operation) +{ + switch(operation) + { + case SetupLog::opServiceAdded: + case SetupLog::opServiceRemoved: + return TRUE; + } + return FALSE; +} + +HRESULT SetupLog::LogServiceById(UINT serviceUid, UINT operation) +{ + if (0 == serviceUid || FALSE == IsOperationSupported(operation)) + return E_INVALIDARG; + + serviceMap[serviceUid] = operation; + return S_OK; +} + +HRESULT SetupLog::LogService(ifc_omservice *service, UINT operation) +{ + if (NULL == service || !IsOperationSupported(operation)) + return E_INVALIDARG; + + return LogServiceById(service->GetId(), operation); +} + +HRESULT SetupLog::Save() +{ + LPSTR buffer = NULL; + size_t cchBuffer = SetupLog_GetMaxServiceIdCount(&serviceMap) * 11; + + if (0 != cchBuffer) + { + cchBuffer += 1; + buffer = Plugin_MallocAnsiString(cchBuffer); + if (NULL == buffer) + return E_OUTOFMEMORY; + } + + const UINT szOperations[] = { opServiceAdded, + opServiceRemoved, }; + + for (INT i = 0; i < ARRAYSIZE(szOperations); i++) + { + LPCSTR value = (NULL != buffer && + SUCCEEDED(SetupLog_FormatServiceId(&serviceMap, szOperations[i], buffer, cchBuffer)) && + '\0' != *buffer) ? buffer : NULL; + SetupLog_WriteOperationLog(szOperations[i], value); + } + + if (NULL != buffer) + Plugin_FreeAnsiString(buffer); + + return S_OK; +} + +HRESULT SetupLog::Erase() +{ + HRESULT hr = S_OK; + if (FALSE == Config_WriteStr(SETUPLOG_SECTION, SETUPLOG_KEY_SUBSCRIBED, NULL)) + hr = E_FAIL; + if (FALSE == Config_WriteStr(SETUPLOG_SECTION, SETUPLOG_KEY_UNSUBSCRIBED, NULL)) + hr = E_FAIL; + + return hr; +} + +struct LOGSENDJOBPARAM +{ + LOGSENDJOBPARAM() : totalJobs(0), storage(NULL), completeEvent(NULL) {} + + ULONG totalJobs; + CRITICAL_SECTION lock; + ifc_omstorage *storage; + HANDLE completeEvent; +}; + +static void CALLBACK SetupLog_SendCompleted(ifc_omstorageasync *async) +{ + if (NULL != async) + { + LOGSENDJOBPARAM *param = NULL; + if (SUCCEEDED(async->GetData((void**)¶m)) && NULL != param) + { + EnterCriticalSection(¶m->lock); + + if (NULL != param->storage) + { + param->storage->EndLoad(async, NULL); + param->storage->Release(); + } + + LONG r = InterlockedDecrement((LONG*)¶m->totalJobs); + if (0 == r) + { + if (NULL != param->completeEvent) + SetEvent(param->completeEvent); + + LeaveCriticalSection(¶m->lock); + DeleteCriticalSection(¶m->lock); + free(param); + param = NULL; + } + else + { + LeaveCriticalSection(¶m->lock); + } + } + } +} + +HRESULT SetupLog::Send(HANDLE completeEvent) +{ + size_t cchAlloc = serviceMap.size(); + if (0 == cchAlloc) + { + if (NULL != completeEvent) SetEvent(completeEvent); + return S_OK; + } + + UINT *buffer = (UINT*)calloc(cchAlloc, sizeof(UINT)); + LOGSENDJOBPARAM *param = (LOGSENDJOBPARAM*)calloc(1, sizeof(LOGSENDJOBPARAM)); + + if (NULL == buffer || NULL == param) + { + if (NULL != buffer) { free(buffer); buffer = NULL; } + if (NULL != param) { free(param); param = NULL; } + if (NULL != completeEvent) { SetEvent(completeEvent); completeEvent = NULL; } + return E_OUTOFMEMORY; + } + + ifc_omstorage *storage = NULL; + HRESULT hr = OMSERVICEMNGR->QueryStorage(&SUID_OmStorageUrl, &storage); + if (SUCCEEDED(hr) && storage != NULL) + { + const UINT szOperations[] = { opServiceAdded, + opServiceRemoved, }; + param->totalJobs = 0; + param->completeEvent = completeEvent; + param->storage = storage; + + InitializeCriticalSection(¶m->lock); + EnterCriticalSection(¶m->lock); + + for (INT i = 0; i < ARRAYSIZE(szOperations); i++) + { + size_t count = 0; + hr = S_OK; + for (SetupLog::ServiceMap::iterator it = serviceMap.begin(); it != serviceMap.end() && SUCCEEDED(hr); it++) + { + if (it->second == szOperations[i]) + { + buffer[count] = it->first; + count++; + } + } + + if (0 != count) + { + LPWSTR url = NULL; + LPCWSTR action = SetupLog_GetOperationAction(szOperations[i]); + if (NULL != action && + SUCCEEDED(Plugin_BuildActionUrl(&url, action, buffer, count))) + { + ifc_omstorageasync *async = NULL;; + if (SUCCEEDED(storage->BeginLoad(url, NULL, SetupLog_SendCompleted, param, &async))) + { + InterlockedIncrement((LONG*)¶m->totalJobs); + storage->AddRef(); + async->Release(); + } + Plugin_FreeString(url); + } + } + } + + if (0 == param->totalJobs) + { + LeaveCriticalSection(¶m->lock); + DeleteCriticalSection(¶m->lock); + hr = E_FAIL; + if (param) { free(param); param = NULL; } + } + else + { + LeaveCriticalSection(¶m->lock); + } + + storage->Release(); + } + + if (buffer) { free(buffer); buffer = NULL; } + return hr; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupLog.h b/Src/Plugins/Library/ml_online/Setup/setupLog.h new file mode 100644 index 00000000..e701046a --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupLog.h @@ -0,0 +1,54 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPLOG_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPLOG_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include <map> + +class ifc_omservice; + +class SetupLog +{ +public: + typedef enum + { + opUnknown = 0, + opServiceAdded = 1, + opServiceRemoved = 2, + }; + +protected: + SetupLog(); + ~SetupLog(); + +public: + static SetupLog *Open(); + static HRESULT Erase(); + +public: + ULONG AddRef(); + ULONG Release(); + + HRESULT LogServiceById(UINT serviceUid, UINT operation); + HRESULT LogService(ifc_omservice *service, UINT operation); + HRESULT Save(); + HRESULT Send(HANDLE completeEvent); + + BOOL IsOperationSupported(UINT operation); + + + +protected: + typedef std::map<UINT, UINT> ServiceMap; + friend static size_t SetupLog_GetMaxServiceIdCount(SetupLog::ServiceMap *serviceMap); + friend static HRESULT SetupLog_FormatServiceId(SetupLog::ServiceMap *serviceMap, INT operation, LPSTR pszBuffer, size_t cchBufferMax); + +protected: + ULONG ref; + ServiceMap serviceMap; +}; + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPLOG_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupPage.cpp b/Src/Plugins/Library/ml_online/Setup/setupPage.cpp new file mode 100644 index 00000000..8b2db86d --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupPage.cpp @@ -0,0 +1,648 @@ +#include "./setupPage.h" +#include "./setupListbox.h" +#include "./setupGroupList.h" +#include "./setupGroupFilter.h" +#include "./setupListboxLabel.h" +#include "../common.h" +#include "../config.h" +#include "../resource.h" +#include "../api__ml_online.h" + +#include "./setupDetails.h" +#include "./setupLog.h" + +#include "../../winamp/setup/svc_setup.h" + +#include <ifc_omservice.h> +#include <ifc_omfilestorage.h> +#include <ifc_omwebstorage.h> + +#include <windows.h> +#include <strsafe.h> +#include <vector> + +#define FEATURED_SERVICES_URL L"http://services.winamp.com/svc/default" + +#define IDC_DETAILS 10000 + +typedef std::vector<ifc_omservice*> ServiceList; +typedef std::vector<UINT> ServiceIdList; + +HWND SetupPage_CreateWindow(HWND hParent, SetupPage *page); +static INT_PTR SetupPage_ModalLoop(HWND hwnd, HACCEL hAccel, HANDLE hCancel); + +struct AppendServiceToStringData +{ + AppendServiceToStringData() : formatFirst(NULL), formatNext(NULL), cursor(NULL), + remaining(0), inserted(0), result(S_OK) {} + + LPCWSTR formatFirst; + LPCWSTR formatNext; + LPWSTR cursor; + size_t remaining; + size_t inserted; + HRESULT result; +}; + +static BOOL CALLBACK SetupPage_AppendServiceToStringCallback(UINT serviceId, void *data) +{ + AppendServiceToStringData *param = (AppendServiceToStringData*)data; + if (NULL == param) return FALSE; + + param->result = StringCchPrintfEx(param->cursor, param->remaining, ¶m->cursor, ¶m->remaining, + STRSAFE_NULL_ON_FAILURE, + ((0 == param->inserted) ? param->formatFirst : param->formatNext), serviceId); + + if (FAILED(param->result)) + return FALSE; + + param->inserted++; + return TRUE; +} + +static BOOL CALLBACK SetupPage_AppendServiceIdCallback(UINT serviceId, void *data) +{ + ServiceIdList *list = (ServiceIdList*)data; + if (NULL == list) return FALSE; + list->push_back(serviceId); + return TRUE; +} + +static HRESULT SetupPage_GetFeaturedServicesUrl(LPWSTR pszBuffer, UINT cchBufferMax) +{ + LPWSTR cursor = pszBuffer; + size_t remaining = cchBufferMax; + + HRESULT hr = StringCchCopyEx(cursor, remaining, FEATURED_SERVICES_URL, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE); + if (FAILED(hr)) + return hr; + + AppendServiceToStringData param; + param.cursor = cursor; + param.remaining = remaining; + param.formatFirst = L"?svc_ids=%u"; + param.formatNext = L",%u"; + param.inserted = 0; + param.result = S_OK; + + hr = Config_ReadServiceIdList("Setup", "featuredExtra", ',', SetupPage_AppendServiceToStringCallback, ¶m); + if (SUCCEEDED(hr)) + hr = param.result; + + return hr; +} + +SetupPage* SetupPage::CreateInstance() +{ + SetupPage *instance = new SetupPage(); + return instance; +} + +SetupPage::SetupPage() + : ref(1), hwnd(NULL), name(NULL), title(NULL), + groupList(NULL), completeEvent(NULL), + servicesInitialized(FALSE) +{ + WasabiApi_AddRef(); + SetupDetails_Initialize(); +} + +SetupPage::~SetupPage() +{ + if (NULL != name) + { + Plugin_FreeString(name); + name = NULL; + } + + if (NULL != title) + { + Plugin_FreeString(title); + title = NULL; + } + + if (NULL != groupList) + { + groupList->Release(); + groupList = NULL; + } + + if (NULL != completeEvent) + { + CloseHandle(completeEvent); + completeEvent = NULL; + } + + SetupDetails_Uninitialize(); + + if (FALSE != servicesInitialized) + { + if (NULL != OMBROWSERMNGR) + OMBROWSERMNGR->Finish(); + } + + WasabiApi_Release(); +} + +size_t SetupPage::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +size_t SetupPage::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +int SetupPage::QueryInterface(GUID interface_guid, void **object) +{ + if (NULL == object) return E_POINTER; + return E_NOTIMPL; +} + +HRESULT SetupPage::GetName(bool bShort, const wchar_t **pszName) +{ + InitializeServices(); + + if (false == bShort) + { + if (NULL == title) + { + WCHAR szBuffer[128] = {0}; + WASABI_API_LNGSTRINGW_BUF(IDS_SETUPPAGE_TITLE, szBuffer, ARRAYSIZE(szBuffer)); + title = Plugin_CopyString(szBuffer); + } + *pszName = title; + } + else + { + if (NULL == name) + { + WCHAR szBuffer[128] = {0}; + WASABI_API_LNGSTRINGW_BUF(IDS_ONLINE_SERVICES, szBuffer, ARRAYSIZE(szBuffer)); + name = Plugin_CopyString(szBuffer); + } + *pszName = name; + } + return S_OK; +} + +HRESULT SetupPage::Save(HWND hwndText) +{ + if (NULL == groupList) + return S_OK; + + SetupLog *log = SetupLog::Open(); + HRESULT hr = groupList->Save(log); + + if (NULL != log) + { + log->Save(); + log->Release(); + } + + return hr; +} + +HRESULT SetupPage::Revert(void) +{ + HRESULT hr(S_OK); + + if (NULL != groupList) + { + groupList->Release(); + groupList = NULL; + } + return hr; +} + +HRESULT SetupPage::IsDirty(void) +{ + return (NULL != groupList && groupList->IsModified()) ? S_OK : S_FALSE; +} + +HRESULT SetupPage::Validate(void) +{ + return S_OK; +} + +HRESULT SetupPage::InitializeServices() +{ + if (FALSE != servicesInitialized) + return S_FALSE; + + HWND hWinamp = NULL; + svc_setup *setupSvc = QueryWasabiInterface(svc_setup, UID_SVC_SETUP); + if (NULL == setupSvc) return E_UNEXPECTED; + HRESULT hr = setupSvc->GetWinampWnd(&hWinamp); + ReleaseWasabiInterface(UID_SVC_SETUP, setupSvc); + + if (SUCCEEDED(hr)) + { + hr = WasabiApi_LoadDefaults(); + if (SUCCEEDED(hr)) + { + if (NULL != OMBROWSERMNGR && + NULL != OMSERVICEMNGR && + NULL != OMUTILITY) + { + hr = OMBROWSERMNGR->Initialize(NULL, hWinamp); + } + else + hr = E_UNEXPECTED; + + if (SUCCEEDED(hr)) + servicesInitialized = TRUE; + } + } + + return hr; +} + +HRESULT SetupPage::CreateView(HWND hParent, HWND *phwnd) +{ + if (NULL == phwnd) + return E_INVALIDARG; + + if (FAILED(InitializeServices())) + { + *phwnd = NULL; + return E_FAIL; + } + + *phwnd = SetupPage_CreateWindow(hParent, this); + return (NULL == phwnd) ? E_FAIL : S_OK; +} + + +BOOL SetupPage::UpdateListAsync(INT groupId) +{ + if (NULL == hwnd) + return FALSE; + + return PostMessage(hwnd, SPM_UPDATELIST, (WPARAM)groupId, NULL); +} + +BOOL SetupPage::AttachWindow(HWND hAttach) +{ + hwnd = hAttach; + + if (NULL == completeEvent) + completeEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + + if (NULL == groupList) + { + groupList = SetupGroupList::CreateInstance(); + if (NULL != groupList) + { + WCHAR szBuffer[4096] = {0}; + SetupPage_GetFeaturedServicesUrl(szBuffer, ARRAYSIZE(szBuffer)); + + SetupGroup *group = SetupGroup::CreateInstance(ID_FEATUREDGROUP, MAKEINTRESOURCE(IDS_SERVICEGROUP_FEATURED), + szBuffer, &SUID_OmStorageUrl, &FUID_SetupFeaturedGroupFilter, + SetupGroup::styleSortAlphabetically | SetupGroup::styleDefaultSubscribed | SetupGroup::styleSaveAll); + if (NULL != group) + { + group->SetLongName(MAKEINTRESOURCE(IDS_SERVICEGROUP_FEATUREDLONG)); + group->SetDescription(MAKEINTRESOURCE(IDS_SERVICEGROUP_FEATURED_DESC)); + groupList->AddGroup(group); + group->RequestReload(); + group->Release(); + } + + group = SetupGroup::CreateInstance(ID_KNOWNGROUP, MAKEINTRESOURCE(IDS_SERVICEGROUP_KNOWN), + L"*.ini", &SUID_OmStorageIni, &FUID_SetupKnownGroupFilter, + SetupGroup::styleSortAlphabetically); + if (NULL != group) + { + group->SetLongName(MAKEINTRESOURCE(IDS_SERVICEGROUP_KNOWNLONG)); + group->SetDescription(MAKEINTRESOURCE(IDS_SERVICEGROUP_KNOWN_DESC)); + group->RequestReload(); + groupList->AddGroup(group); + group->Release(); + } + } + } + + if (NULL != groupList) + groupList->SetPageWnd(hwnd); + + HWND hList = GetDlgItem(hwnd, IDC_SERVICELIST); + if (NULL != hList) + { + SetupListbox *listbox; + if (SUCCEEDED(SetupListbox::CreateInstance(hList, groupList, &listbox))) + { + } + ListboxSelectionChanged(); + } + + return TRUE; +} + +void SetupPage::DetachWindow() +{ + hwnd = NULL; + if (NULL != groupList) + { + groupList->SetPageWnd(NULL); + } +} + + +HRESULT SetupPage_AppendUnselectedServices(LPCSTR pszSection, LPCSTR pszKey, SetupGroup *group) +{ + size_t index = group->GetRecordCount(); + size_t filterIndex, filterSize; + + ServiceIdList list; + Config_ReadServiceIdList(pszSection, pszKey, ',', SetupPage_AppendServiceIdCallback, &list); + filterSize = list.size(); + + while(index--) + { + SetupRecord *record = group->GetRecord(index); + if (NULL == record || FALSE != record->IsSelected()) continue; + + ifc_omservice *service = record->GetService(); + if (NULL == service) continue; + + UINT serviceId = service->GetId(); + for(filterIndex = 0; filterIndex < filterSize; filterIndex++) + { + if (list[filterIndex] == serviceId) + break; + } + + if (filterIndex == filterSize) + list.push_back(serviceId); + } + + if (0 != list.size()) + { + size_t bufferAlloc = (list.size() * 11) * sizeof(CHAR); + LPSTR buffer = Plugin_MallocAnsiString(bufferAlloc); + if (NULL != buffer) + { + filterSize = list.size(); + LPSTR cursor = buffer; + size_t remaining = bufferAlloc; + for(index = 0; index < filterSize; index++) + { + if (FAILED(StringCchPrintfExA(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, + ((0 == index) ? "%u" : ",%u"), list[index]))) + { + break; + } + } + Config_WriteStr(pszSection, pszKey, buffer); + Plugin_FreeAnsiString(buffer); + } + } + else + Config_WriteStr(pszSection, pszKey, NULL); + + return S_OK; +} + +HRESULT SetupPage::Execute(HWND hwndText) +{ + SetupGroup *group = NULL; + SetupLog *log = SetupLog::Open(); + WCHAR szBuffer[128] = {0}; + + if (FAILED(InitializeServices())) + return E_FAIL; + + if (NULL == groupList) + { + groupList = SetupGroupList::CreateInstance(); + if (NULL == groupList) return E_UNEXPECTED; + } + + if (S_OK != groupList->FindGroupById(ID_FEATUREDGROUP, &group) && group != NULL) + { + WCHAR szBuffer[4096] = {0}; + SetupPage_GetFeaturedServicesUrl(szBuffer, ARRAYSIZE(szBuffer)); + + group = SetupGroup::CreateInstance(ID_FEATUREDGROUP, MAKEINTRESOURCE(IDS_SERVICEGROUP_FEATURED), + szBuffer, &SUID_OmStorageUrl, &FUID_SetupFeaturedGroupFilter, + SetupGroup::styleDefaultSubscribed | SetupGroup::styleSaveAll); + + if (NULL != group) + { + group->SetLongName(MAKEINTRESOURCE(IDS_SERVICEGROUP_FEATUREDLONG)); + group->SetDescription(MAKEINTRESOURCE(IDS_SERVICEGROUP_FEATURED_DESC)); + groupList->AddGroup(group); + group->RequestReload(); + } + } + + if (NULL == completeEvent) + completeEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + if (NULL != group) + { + if (SUCCEEDED(group->SignalLoadCompleted(completeEvent))) + { + WASABI_API_LNGSTRINGW_BUF(IDS_DOWNLOADSERVICE_JOB, szBuffer, ARRAYSIZE(szBuffer)); + SetWindowText(hwndText, szBuffer); + SetupPage_ModalLoop(hwndText, NULL, completeEvent); + } + + WASABI_API_LNGSTRINGW_BUF(IDS_SAVESERVICE_JOB, szBuffer, ARRAYSIZE(szBuffer)); + SetWindowText(hwndText, szBuffer); + group->Save(log); + SetupPage_AppendUnselectedServices("Setup", "featuredHistory", group); + group->Release(); + group = NULL; + } + + // ensure that promotions are subscribed + if (S_OK != groupList->FindGroupById(ID_KNOWNGROUP, &group) && group != NULL) + { + group = SetupGroup::CreateInstance(ID_KNOWNGROUP, MAKEINTRESOURCE(IDS_SERVICEGROUP_KNOWN), + L"*.ini", &SUID_OmStorageIni, &FUID_SetupKnownGroupFilter, + SetupGroup::styleSortAlphabetically); + if (NULL != group) + { + group->SetLongName(MAKEINTRESOURCE(IDS_SERVICEGROUP_KNOWNLONG)); + group->SetDescription(MAKEINTRESOURCE(IDS_SERVICEGROUP_KNOWN_DESC)); + group->RequestReload(); + groupList->AddGroup(group); + } + } + + if (NULL != group) + { + WASABI_API_LNGSTRINGW_BUF(IDS_SAVESERVICE_JOB, szBuffer, ARRAYSIZE(szBuffer)); + SetWindowText(hwndText, szBuffer); + + ResetEvent(completeEvent); + if (SUCCEEDED(group->SignalLoadCompleted(completeEvent))) + SetupPage_ModalLoop(hwndText, NULL, completeEvent); + + group->Save(log); + group->Release(); + group = NULL; + } + + if (NULL != log) + { + WASABI_API_LNGSTRINGW_BUF(IDS_REGISTERINGSERVICE_JOB, szBuffer, ARRAYSIZE(szBuffer)); + SetWindowText(hwndText, szBuffer); + ResetEvent(completeEvent); + log->Send(completeEvent); + SetupPage_ModalLoop(hwndText, NULL, completeEvent); + log->Release(); + } + + SetupLog::Erase(); + Config_WriteStr("Setup", "featuredExtra", NULL); // delete promo offer + return S_OK; +} + +HRESULT SetupPage::Cancel(HWND hwndText) +{ + if (NULL != completeEvent) + SetEvent(completeEvent); + return S_OK; +} + +HRESULT SetupPage::IsCancelSupported(void) +{ + return S_OK; +} +void SetupPage::ListboxSelectionChanged() +{ + if (NULL == hwnd) return; + HWND hList = GetDlgItem(hwnd, IDC_SERVICELIST); + if (NULL == hList) return; + + SetupListboxItem *item = NULL; + INT iSelection = (INT)SendMessage(hList, LB_GETCURSEL, 0, 0L); + if (LB_ERR == iSelection || + FAILED(groupList->FindListboxItem(iSelection, &item))) + { + item = NULL; + } + + HWND hDiscard = GetDlgItem(hwnd, IDC_DETAILS); + if (NULL != hDiscard) + { + WCHAR szPanel[64] = {0}, szItem[64] = {0}; + if (FALSE != SetupDetails_GetUniqueName(hDiscard, szPanel, ARRAYSIZE(szPanel)) && + FALSE != item->GetUniqueName(szItem, ARRAYSIZE(szItem)) && + CSTR_EQUAL == CompareString(CSTR_INVARIANT, 0, szPanel, - 1, szItem, -1)) + { + return; + } + } + + HWND hDetails = (NULL != item) ? item->CreateDetailsView(hwnd) : NULL; + if (NULL != hDiscard) + { + SetWindowLongPtr(hDiscard, GWL_STYLE, GetWindowLongPtr(hDiscard, GWL_STYLE) & ~WS_VISIBLE); + } + + if (NULL != hDetails) + { + HWND hPlaceholder = GetDlgItem(hwnd, IDC_PLACEHOLDER); + if (NULL != hPlaceholder) + { + RECT windowRect; + if (GetWindowRect(hPlaceholder, &windowRect)) + { + MapWindowPoints(HWND_DESKTOP,hwnd, (POINT*)&windowRect,2); + SetWindowPos(hDetails, NULL, windowRect.left, windowRect.top, + windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, + SWP_NOACTIVATE | SWP_NOZORDER); + } + SetWindowLongPtr(hDetails, GWLP_ID, IDC_DETAILS); + ShowWindow(hDetails, SW_SHOWNA); + RedrawWindow(hDetails, NULL, NULL, RDW_ERASENOW |RDW_UPDATENOW | RDW_ALLCHILDREN); + } + } + + if (NULL != hDiscard) + { + DestroyWindow(hDiscard); + } +} + +static INT_PTR SetupPage_ModalLoop(HWND hwnd, HACCEL hAccel, HANDLE hCancel) +{ + MSG msg = {0}; + HWND hParent = NULL; + while (NULL != (hParent = GetAncestor(hwnd, GA_PARENT))) + { + hwnd = hParent; + } + + if (NULL == hwnd) + return 0; + + for (;;) + { + DWORD status = MsgWaitForMultipleObjectsEx(1, &hCancel, INFINITE, 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 (!CallMsgFilter(&msg, MSGF_DIALOGBOX)) + { + if (msg.message == WM_QUIT) + { + PostQuitMessage((INT)msg.wParam); + return msg.wParam; + } + + if (!TranslateAcceleratorW(hwnd, hAccel, &msg) && + !IsDialogMessageW(hwnd, &msg)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + } + } + } + return 0; +} + +#define CBCLASS SetupPage +START_MULTIPATCH; + START_PATCH(MPIID_SETUPPAGE) + M_CB(MPIID_SETUPPAGE, ifc_setuppage, ADDREF, AddRef); + M_CB(MPIID_SETUPPAGE, ifc_setuppage, RELEASE, Release); + M_CB(MPIID_SETUPPAGE, ifc_setuppage, QUERYINTERFACE, QueryInterface); + M_CB(MPIID_SETUPPAGE, ifc_setuppage, API_SETUPPAGE_GET_NAME, GetName); + M_CB(MPIID_SETUPPAGE, ifc_setuppage, API_SETUPPAGE_CREATEVIEW, CreateView); + M_CB(MPIID_SETUPPAGE, ifc_setuppage, API_SETUPPAGE_SAVE, Save); + M_CB(MPIID_SETUPPAGE, ifc_setuppage, API_SETUPPAGE_REVERT, Revert); + M_CB(MPIID_SETUPPAGE, ifc_setuppage, API_SETUPPAGE_ISDIRTY, IsDirty); + M_CB(MPIID_SETUPPAGE, ifc_setuppage, API_SETUPPAGE_VALIDATE, Validate); + + NEXT_PATCH(MPIID_SETUPJOB) + M_CB(MPIID_SETUPJOB, ifc_setupjob, ADDREF, AddRef); + M_CB(MPIID_SETUPJOB, ifc_setupjob, RELEASE, Release); + M_CB(MPIID_SETUPJOB, ifc_setupjob, QUERYINTERFACE, QueryInterface); + M_CB(MPIID_SETUPJOB, ifc_setupjob, API_SETUPJOB_EXECUTE, Execute); + M_CB(MPIID_SETUPJOB, ifc_setupjob, API_SETUPJOB_CANCEL, Cancel); + M_CB(MPIID_SETUPJOB, ifc_setupjob, API_SETUPJOB_ISCANCELSUPPORTED, IsCancelSupported); + + END_PATCH +END_MULTIPATCH; +#undef CBCLASS
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupPage.h b/Src/Plugins/Library/ml_online/Setup/setupPage.h new file mode 100644 index 00000000..ea45357f --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupPage.h @@ -0,0 +1,85 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPPAGE_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPPAGE_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include <bfc/multipatch.h> + +#include "../../winamp/setup/ifc_setuppage.h" +#include "../../winamp/setup/ifc_setupjob.h" + +#include "./setupGroupList.h" + +class SetupListboxLabel; + +#define ID_KNOWNGROUP 0 +#define ID_FEATUREDGROUP 1 + +#define MPIID_SETUPPAGE 10 +#define MPIID_SETUPJOB 20 + +#define SPM_FIRST (WM_APP + 2) +#define SPM_UPDATELIST (SPM_FIRST + 0) + +class SetupPage : public MultiPatch<MPIID_SETUPPAGE, ifc_setuppage>, + public MultiPatch<MPIID_SETUPJOB, ifc_setupjob> +{ +protected: + typedef enum + { + flagInitWasabi = 0x00000001, + }; + +protected: + SetupPage(); + virtual ~SetupPage(); + +public: + static SetupPage* CreateInstance(); + +public: + /* Dispatchable */ + size_t AddRef(); + size_t Release(); + int QueryInterface(GUID interface_guid, void **object); + + /* ifc_setuppage */ + HRESULT GetName(bool bShort, const wchar_t **pszName); + HRESULT Save(HWND hText); + HRESULT CreateView(HWND hParent, HWND *phwnd); + HRESULT Revert(void); + HRESULT IsDirty(void); + HRESULT Validate(void); + + /* ifc_setupjob */ + HRESULT Execute(HWND hwndText); + HRESULT Cancel(HWND hwndText); + HRESULT IsCancelSupported(void); + +public: + BOOL AttachWindow(HWND hAttach); + void DetachWindow(); + + void ListboxSelectionChanged(); + BOOL UpdateListAsync(INT groupId); + +protected: + HRESULT InitializeServices(); + +private: + size_t ref; + HWND hwnd; + LPWSTR name; + LPWSTR title; + SetupGroupList *groupList; + HANDLE completeEvent; + BOOL servicesInitialized; + +protected: + RECVS_MULTIPATCH; +}; + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPPAGE_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupPageWnd.cpp b/Src/Plugins/Library/ml_online/Setup/setupPageWnd.cpp new file mode 100644 index 00000000..338df688 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupPageWnd.cpp @@ -0,0 +1,145 @@ +#include "./setupPage.h" +#include "./setupListbox.h" +#include "../common.h" +#include "../resource.h" +#include "../api__ml_online.h" + +static ATOM SETUPPAGE_PROP = 0; + +#define GetPage(__hwnd) ((SetupPage*)GetPropW((__hwnd), MAKEINTATOM(SETUPPAGE_PROP))) + +static INT_PTR WINAPI SetupPage_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + + + +HWND SetupPage_CreateWindow(HWND hParent, SetupPage *page) +{ + return WASABI_API_CREATEDIALOGPARAMW(IDD_SETUPPAGE, hParent, SetupPage_DialogProc, (LPARAM)page); +} + +static INT_PTR SetupPage_OnInitDialog(HWND hwnd, HWND hFocus, LPARAM lParam) +{ + if (0 == SETUPPAGE_PROP) + { + SETUPPAGE_PROP = GlobalAddAtom(L"omSetupPageProp"); + if (0 == SETUPPAGE_PROP) return FALSE; + } + + SetupPage *page = (SetupPage*)lParam; + if (NULL != page && page->AttachWindow(hwnd)) + { + SetProp(hwnd, MAKEINTATOM(SETUPPAGE_PROP), page); + } + + return FALSE; +} + +static void SetupPage_OnDestroy(HWND hwnd) +{ + SetupPage *page = GetPage(hwnd); + if (NULL != page) + { + page->DetachWindow(); + } + RemoveProp(hwnd, MAKEINTATOM(SETUPPAGE_PROP)); +} + +static void SetupPage_OnCommand(HWND hwnd, INT controlId, INT eventId, HWND hControl) +{ + SetupPage *page; + switch(controlId) + { + case IDC_SERVICELIST: + switch(eventId) + { + case LBN_SELCHANGE: + page = GetPage(hwnd); + if (NULL != page) + page->ListboxSelectionChanged(); + break; + } + break; + } +} + +static BOOL SetupPage_OnMeasureItem(HWND hwnd, MEASUREITEMSTRUCT *pmis) +{ + SetupListbox *instance; + switch(pmis->CtlID) + { + case IDC_SERVICELIST: + instance = SetupListbox::GetInstance(GetDlgItem(hwnd, pmis->CtlID)); + if (NULL != instance) + { + return instance->MeasureItem(pmis->itemID, &pmis->itemWidth, &pmis->itemHeight); + } + break; + } + return FALSE; +} + +static BOOL SetupPage_OnDrawItem(HWND hwnd, DRAWITEMSTRUCT *pdis) +{ + SetupListbox *instance; + switch(pdis->CtlID) + { + case IDC_SERVICELIST: + instance = SetupListbox::GetInstance(pdis->hwndItem); + if (NULL != instance) + { + return instance->DrawItem(pdis->hDC, &pdis->rcItem, pdis->itemID, pdis->itemState, pdis->itemAction); + } + break; + } + return FALSE; +} + +static INT_PTR SetupPage_OnCharToItem(HWND hwnd, INT vKey, INT caretPos, HWND hList) +{ + + if (IDC_SERVICELIST == GetDlgCtrlID(hList)) + { + SetupListbox *instance = SetupListbox::GetInstance(hList); + if (NULL != instance) + return instance->CharToItem(vKey, caretPos); + } + return -1; +} + +static INT_PTR SetupPage_OnKeyToItem(HWND hwnd, INT vKey, INT caretPos, HWND hList) +{ + if (IDC_SERVICELIST == GetDlgCtrlID(hList)) + { + SetupListbox *instance = SetupListbox::GetInstance(hList); + if (NULL != instance) + return instance->KeyToItem(vKey, caretPos); + } + return -1; +} +static void SetupPage_OnUpdateList(HWND hwnd, INT groupId) +{ + HWND hList = GetDlgItem(hwnd, IDC_SERVICELIST); + if (NULL != hList) + { + SetupListbox *listbox = SetupListbox::GetInstance(hList); + if (NULL != listbox) + { + listbox->UpdateCount(); + } + } +} +static INT_PTR WINAPI SetupPage_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: return SetupPage_OnInitDialog(hwnd, (HWND)wParam, lParam); + case WM_DESTROY: SetupPage_OnDestroy(hwnd); break; + case WM_COMMAND: SetupPage_OnCommand(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break; + case WM_MEASUREITEM: return SetupPage_OnMeasureItem(hwnd, (MEASUREITEMSTRUCT*)lParam); + case WM_DRAWITEM: return SetupPage_OnDrawItem(hwnd, (DRAWITEMSTRUCT*)lParam); + case WM_CHARTOITEM: return SetupPage_OnCharToItem(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); + case WM_VKEYTOITEM: return SetupPage_OnKeyToItem(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); + case SPM_UPDATELIST: SetupPage_OnUpdateList(hwnd, (INT)wParam); return TRUE; + } + return 0; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupRecord.cpp b/Src/Plugins/Library/ml_online/Setup/setupRecord.cpp new file mode 100644 index 00000000..995ed222 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupRecord.cpp @@ -0,0 +1,567 @@ +#include "./main.h" +#include "../api__ml_online.h" +#include "./setupRecord.h" +#include "./setupDetails.h" +#include "./setupLog.h" +#include "../resource.h" + +#include "./serviceHelper.h" +#include "./serviceHost.h" + +#include <ifc_omservice.h> +#include <ifc_omwebstorage.h> +#include <ifc_omserviceenum.h> +#include <ifc_omservicecopier.h> + +#include <wininet.h> +#include <strsafe.h> + +#define RECORD_MARGINCX 6 +#define RECORD_MARGINCY 2 +#define CHECKBOX_MARGIN_RIGHT 2 + +#define TEXT_OFFSET_LEFT 3 +#define TEXT_OFFSET_BOTTOM RECORD_MARGINCY +#define TEXT_ALIGN (TA_LEFT | TA_BOTTOM) + +SetupRecord::SetupRecord(ifc_omservice *serviceToUse) + : ref(1), service(serviceToUse), flags(0), async(NULL) +{ + if (NULL != service) + { + if (S_OK == ServiceHelper_IsSubscribed(service)) + flags |= recordSelected; + service->AddRef(); + } + + InitializeCriticalSection(&lock); +} + +SetupRecord::~SetupRecord() +{ + EnterCriticalSection(&lock); + + if (NULL != async) + { + ifc_omstorage *storage = NULL; + HRESULT hr = OMSERVICEMNGR->QueryStorage(&SUID_OmStorageUrl, &storage); + if (SUCCEEDED(hr) && storage != NULL) + { + storage->RequestAbort(async, TRUE); + } + + async->Release(); + async = NULL; + } + + if (NULL != service) + service->Release(); + + LeaveCriticalSection(&lock); + DeleteCriticalSection(&lock); +} + +SetupRecord *SetupRecord::CreateInstance(ifc_omservice *serviceToUse) +{ + if (NULL == serviceToUse) return NULL; + return new SetupRecord(serviceToUse); +} + +ULONG SetupRecord::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG SetupRecord::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +HRESULT SetupRecord::GetServiceName(LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == service) return E_UNEXPECTED; + return service->GetName(pszBuffer, cchBufferMax); +} + +HRESULT SetupRecord::GetDisplayName(LPWSTR pszBuffer, UINT cchBufferMax) +{ + HRESULT hr = GetServiceName(pszBuffer, cchBufferMax); + if (SUCCEEDED(hr) && L'\0' == *pszBuffer) + { + WASABI_API_LNGSTRINGW_BUF(IDS_DEFAULT_SERVICENAME, pszBuffer, cchBufferMax); + DownloadDetails(); + } + return hr; +} + +HRESULT SetupRecord::DownloadDetails() +{ + HRESULT hr; + EnterCriticalSection(&lock); + if (NULL == async && 0 == (recordDownloaded & flags)) + { + WCHAR szUrl[INTERNET_MAX_URL_LENGTH] = {0}; + hr = ServiceHelper_GetDetailsUrl(szUrl, ARRAYSIZE(szUrl), service, FALSE); + if (SUCCEEDED(hr)) + { + ifc_omstorage *storage = NULL; + hr = OMSERVICEMNGR->QueryStorage(&SUID_OmStorageUrl, &storage); + if (SUCCEEDED(hr) && storage != NULL) + { + ServiceHost *serviceHost = NULL; + if (FAILED(ServiceHost::GetCachedInstance(&serviceHost))) + serviceHost = NULL; + + hr = storage->BeginLoad(szUrl, serviceHost, SetupRecord_ServiceDownloadedCallback, this, &async); + storage->Release(); + + if (NULL != serviceHost) + serviceHost->Release(); + } + } + } + else + { + hr = S_FALSE; + } + LeaveCriticalSection(&lock); + return hr; +} + +HRESULT SetupRecord::Save(SetupLog *log) +{ + if (NULL == service) return E_POINTER; + + HRESULT hr = ServiceHelper_Subscribe(service, IsSelected(), SHF_SAVE); + if (S_OK == hr) + { + if (NULL != log) + { + INT operation = (IsSelected()) ? SetupLog::opServiceAdded : SetupLog::opServiceRemoved; + log->LogService(service, operation); + } + + } + + return hr; +} + +BOOL SetupRecord::IsModified() +{ + if (NULL == service) + return FALSE; + + if (S_OK == ServiceHelper_IsSubscribed(service) != (FALSE != IsSelected())) + return TRUE; + if (S_OK == ServiceHelper_IsModified(service)) + return TRUE; + + return FALSE; +} + +BOOL SetupRecord::IsSelected() +{ + return (0 != (recordSelected & flags)); +} + +void SetupRecord::SetSelected(BOOL fSelected) +{ + if ((FALSE == fSelected) == !IsSelected()) + return; + + if (FALSE == fSelected) + flags &= ~recordSelected; + else + flags |= recordSelected; +} + +BOOL SetupRecord::AdjustCheckboxRect(SetupListbox *instance, RECT *prcItem) +{ + SIZE checkSize; + if (!instance->GetCheckboxMetrics(NULL, IsSelected(), 0, &checkSize)) + return FALSE; + + prcItem->left += RECORD_MARGINCX; + prcItem->right = prcItem->left + checkSize.cx; + + if (checkSize.cy > (prcItem->bottom - prcItem->top)) + checkSize.cy = (prcItem->bottom - prcItem->top); + prcItem->top += ((prcItem->bottom - prcItem->top) - checkSize.cy) / 2; + prcItem->bottom = prcItem->top + checkSize.cy; + return TRUE; +} + +BOOL SetupRecord::MeasureItem(SetupListbox *instance, UINT *cx, UINT *cy) +{ + HDC hdc = GetDCEx(instance->GetHwnd(), NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL == hdc) return FALSE; + + HFONT originalFont = (HFONT)SelectObject(hdc, instance->GetFont()); + + SIZE checkSize; + instance->GetCheckboxMetrics(hdc, IsSelected(), 0, &checkSize); + + if (NULL != cy) + { + *cy = 0; + TEXTMETRIC tm = {0}; + if (GetTextMetrics(hdc, &tm)) + { + *cy = tm.tmHeight + tm.tmExternalLeading; + if (checkSize.cy > (INT)*cy) *cy = checkSize.cy; + *cy += RECORD_MARGINCY*2; + } + } + + if (NULL != cx) + { + *cx = checkSize.cx; + WCHAR szBuffer[128] = {0}; + if (SUCCEEDED(GetDisplayName(szBuffer, ARRAYSIZE(szBuffer)))) + { + INT cchBuffer = lstrlenW(szBuffer); + SIZE textSize; + if (0 != cchBuffer && GetTextExtentPoint32(hdc, szBuffer, cchBuffer, &textSize)) + { + *cx += textSize.cx; + if (0 != checkSize.cx) + *cx += CHECKBOX_MARGIN_RIGHT + RECORD_MARGINCX; + } + } + if (0 != *cx) *cx += RECORD_MARGINCX*2; + } + + SelectObject(hdc, originalFont); + ReleaseDC(instance->GetHwnd(), hdc); + return TRUE; +} + +void SetupRecord::GetColors(HDC hdc, UINT state, COLORREF *rgbBkOut, COLORREF *rgbTextOut) +{ + COLORREF rgbBk, rgbText; + + if (0 != (ODS_DISABLED & state)) + { + rgbBk = GetBkColor(hdc); + rgbText = GetSysColor(COLOR_GRAYTEXT); + } + else if (0 != (ODS_SELECTED & state)) + { + if (0 == (ODS_INACTIVE & state)) + { + rgbBk = GetSysColor(COLOR_HIGHLIGHT); + rgbText = GetSysColor(COLOR_HIGHLIGHTTEXT); + } + else + { + rgbBk = GetSysColor(COLOR_3DFACE); + rgbText = GetTextColor(hdc); + } + } + else + { + rgbBk = GetBkColor(hdc); + rgbText = GetTextColor(hdc); + } + + if (NULL != rgbBkOut) *rgbBkOut = rgbBk; + if (NULL != rgbTextOut) *rgbTextOut = rgbText; +} + +BOOL SetupRecord::DrawItem(SetupListbox *instance, HDC hdc, const RECT *prc, UINT state) +{ + LONG paintLeft = prc->left + RECORD_MARGINCX; + RECT partRect; + + UINT checkState = state & ~ODS_SELECTED; + if (0 == (checkboxPressed & flags)) + { + if (0 != (checkboxHighlighted & flags)) + checkState |= ODS_HOTLIGHT; + } + else + { + checkState |= ((0 != (checkboxHighlighted & flags)) ? ODS_SELECTED : ODS_HOTLIGHT); + } + + HRGN backRgn, rgn; + backRgn = CreateRectRgnIndirect(prc); + rgn = CreateRectRgn(0,0,0,0); + + SetRectEmpty(&partRect); + instance->GetCheckboxMetrics(hdc, IsSelected(), checkState, (((SIZE*)&partRect) + 1)); + + INT space = (prc->bottom - prc->top) - (partRect.bottom- partRect.top); + INT offsetY = space / 2 + space%2; + if (offsetY < 0) offsetY = 0; + + OffsetRect(&partRect, paintLeft, prc->top + offsetY); + if (instance->DrawCheckbox(hdc, IsSelected(), checkState, &partRect, prc)) + { + paintLeft = partRect.right + CHECKBOX_MARGIN_RIGHT; + if (SetRectRgn(rgn, partRect.left, partRect.top, partRect.right, partRect.bottom)) + CombineRgn(backRgn, backRgn, rgn, RGN_DIFF); + + } + + COLORREF rgbBk, rgbText; + GetColors(hdc, state, &rgbBk, &rgbText); + + COLORREF origBk = SetBkColor(hdc, rgbBk); + COLORREF origText = SetTextColor(hdc, rgbText); + UINT textAlign = SetTextAlign(hdc, TEXT_ALIGN); + + WCHAR szBuffer[128] = {0}; + INT cchBuffer = 0; + if (SUCCEEDED(GetDisplayName(szBuffer, ARRAYSIZE(szBuffer)))) + cchBuffer = lstrlenW(szBuffer); + + SetRect(&partRect, paintLeft, prc->top, prc->right, prc->bottom); + if (ExtTextOut(hdc, partRect.left + TEXT_OFFSET_LEFT, partRect.bottom - TEXT_OFFSET_BOTTOM, + ETO_OPAQUE | ETO_CLIPPED, &partRect, szBuffer, cchBuffer, NULL)) + { + if (SetRectRgn(rgn, partRect.left, partRect.top, partRect.right, partRect.bottom)) + CombineRgn(backRgn, backRgn, rgn, RGN_DIFF); + } + + if (ODS_FOCUS == ((ODS_FOCUS | 0x0200/*ODS_NOFOCUSRECT*/) & state)) + DrawFocusRect(hdc, &partRect); + + if (NULL != backRgn) + { + PaintRgn(hdc, backRgn); + DeleteObject(backRgn); + } + if (NULL != rgn) + DeleteObject(rgn); + + if (TEXT_ALIGN != textAlign) SetTextAlign(hdc, textAlign); + if (origBk != rgbBk) SetBkColor(hdc, origBk); + if (origText != rgbText) SetTextColor(hdc, origText); + + return TRUE; +} + +INT_PTR SetupRecord::KeyToItem(SetupListbox *instance, const RECT *prcItem, INT vKey) +{ + switch(vKey) + { + case VK_SPACE: + InvertCheckbox(instance, prcItem); + return -2; + } + return -1; +} + +BOOL SetupRecord::MouseMove(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + RECT checkboxRect; + BOOL fInvalidate = FALSE; + CopyRect(&checkboxRect, prcItem); + AdjustCheckboxRect(instance, &checkboxRect); + + if (prcItem->top <= pt.y && pt.y < prcItem->bottom && + checkboxRect.left <= pt.x && pt.x < checkboxRect.right) + { + if (0 == (checkboxHighlighted & flags)) + { + flags |= checkboxHighlighted; + fInvalidate = TRUE; + } + } + else + { + if (0 != (checkboxHighlighted & flags)) + { + flags &= ~checkboxHighlighted; + fInvalidate = TRUE; + } + } + + if (FALSE != fInvalidate) + instance->InvalidateRect(&checkboxRect, FALSE); + + return FALSE; +} + +BOOL SetupRecord::MouseLeave(SetupListbox *instance, const RECT *prcItem) +{ + if (0 != (checkboxHighlighted & flags)) + { + flags &= ~checkboxHighlighted; + RECT checkboxRect; + CopyRect(&checkboxRect, prcItem); + AdjustCheckboxRect(instance, &checkboxRect); + instance->InvalidateRect(&checkboxRect, FALSE); + } + return FALSE; +} + +BOOL SetupRecord::LButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + RECT checkboxRect; + BOOL handled = FALSE; + CopyRect(&checkboxRect, prcItem); + AdjustCheckboxRect(instance, &checkboxRect); + + if (prcItem->top <= pt.y && pt.y < prcItem->bottom && + prcItem->left <= pt.x && pt.x < (checkboxRect.right + CHECKBOX_MARGIN_RIGHT)) + { + handled = TRUE; + if (checkboxRect.left <= pt.x && pt.x < checkboxRect.right) + { + flags |= (checkboxHighlighted | checkboxPressed); + instance->SetCapture(this); + instance->InvalidateRect(&checkboxRect, FALSE); + } + } + return handled; +} + +BOOL SetupRecord::LButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + RECT checkboxRect; + BOOL handled = FALSE; + CopyRect(&checkboxRect, prcItem); + AdjustCheckboxRect(instance, &checkboxRect); + + if (0 != (checkboxPressed & flags)) + { + flags &= ~checkboxPressed; + if (this == instance->GetCapture()) + instance->ReleaseCapture(); + + if (prcItem->top <= pt.y && pt.y < prcItem->bottom && + checkboxRect.left <= pt.x && pt.x < checkboxRect.right) + { + SetSelected(!IsSelected()); + handled = TRUE; + } + instance->InvalidateRect(&checkboxRect, FALSE); + } + return handled; +} + +BOOL SetupRecord::LButtonDblClk(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + InvertCheckbox(instance, prcItem); + return TRUE; +} + +BOOL SetupRecord::RButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} + +BOOL SetupRecord::RButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} + +void SetupRecord::CaptureChanged(SetupListbox *instance, const RECT *prcItem, SetupListboxItem *captured) +{ +} + +void SetupRecord::InvertCheckbox(SetupListbox *instance, const RECT *prcItem) +{ + SetSelected(!IsSelected()); + + if (NULL != instance && NULL != prcItem) + { + RECT checkboxRect; + CopyRect(&checkboxRect, prcItem); + AdjustCheckboxRect(instance, &checkboxRect); + instance->InvalidateRect(&checkboxRect, FALSE); + } +} + +HWND SetupRecord::CreateDetailsView(HWND hParent) +{ + DownloadDetails(); + + WCHAR szName[64] = {0}; + if (FALSE == GetUniqueName(szName, ARRAYSIZE(szName))) + szName[0] = L'\0'; + + return SetupDetails_CreateServiceView(hParent, szName, service); +} + +BOOL SetupRecord::GetUniqueName(LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer || + FAILED(StringCchPrintf(pszBuffer, cchBufferMax, L"record_svc_%u", service->GetId()))) + { + return FALSE; + } + return TRUE; +} + +void SetupRecord::OnDownloadCompleted() +{ + ifc_omstorage *storage = NULL; + HRESULT hr = OMSERVICEMNGR->QueryStorage(&SUID_OmStorageUrl, &storage); + if (SUCCEEDED(hr) && service != NULL) + { + ifc_omserviceenum *serviceEnum = NULL; + hr = storage->EndLoad(async, &serviceEnum); + if (SUCCEEDED(hr) && serviceEnum != NULL) + { + EnterCriticalSection(&lock); + + ifc_omservice *result = NULL; + while(S_OK == serviceEnum->Next(1, &result, NULL)) + { + if (result) + { + if (result->GetId() == service->GetId()) + { + ifc_omservicecopier *copier; + if (SUCCEEDED(result->QueryInterface(IFC_OmServiceCopier, (void**)&copier))) + { + copier->CopyTo(service, NULL); + copier->Release(); + } + result->Release(); + flags |= recordDownloaded; + break; + } + else + { + result->Release(); + } + } + result = NULL; + } + + LeaveCriticalSection(&lock); + + serviceEnum->Release(); + } + + storage->Release(); + } + + EnterCriticalSection(&lock); + + async->Release(); + async = NULL; + + LeaveCriticalSection(&lock); +} + +void CALLBACK SetupRecord_ServiceDownloadedCallback(ifc_omstorageasync *result) +{ + if (NULL == result) return; + SetupRecord *record = NULL; + if (SUCCEEDED(result->GetData((void**)&record)) && NULL != record) + { + record->OnDownloadCompleted(); + } +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupRecord.h b/Src/Plugins/Library/ml_online/Setup/setupRecord.h new file mode 100644 index 00000000..b6573e1a --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupRecord.h @@ -0,0 +1,84 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPRECORD_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPRECORD_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "./setupListbox.h" + +class ifc_omservice; +class ifc_omstorageasync; +class SetupLog; + +class SetupRecord : public SetupListboxItem + +{ +protected: + typedef enum + { + recordSelected = 0x0001, + recordDownloaded = 0x0002, + checkboxHighlighted = 0x0100, + checkboxPressed = 0x0200, + } RecordFlags; + +protected: + SetupRecord(ifc_omservice *serviceToUse); + ~SetupRecord(); + +public: + static SetupRecord *CreateInstance(ifc_omservice *serviceToUse); + +public: + ULONG AddRef(); + ULONG Release(); + + ifc_omservice *GetService() { return service; } + + BOOL IsModified(); + BOOL IsSelected(); + void SetSelected(BOOL fSelected); + + HRESULT GetServiceName(LPWSTR pszBuffer, UINT cchBufferMax); + HRESULT GetDisplayName(LPWSTR pszBuffer, UINT cchBufferMax); + HRESULT Save(SetupLog *log); + HRESULT DownloadDetails(); + + /* SetupListboxItem */ + BOOL MeasureItem(SetupListbox *instance, UINT *cx, UINT *cy); + BOOL DrawItem(SetupListbox *instance, HDC hdc, const RECT *prc, UINT state); + INT_PTR KeyToItem(SetupListbox *instance, const RECT *prcItem, INT vKey); + BOOL MouseMove(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL MouseLeave(SetupListbox *instance, const RECT *prcItem); + BOOL LButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL LButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL LButtonDblClk(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL RButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL RButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + void CaptureChanged(SetupListbox *instance, const RECT *prcItem, SetupListboxItem *captured); + BOOL IsDisabled() { return FALSE; } + void Command(SetupListbox *instance, INT commandId, INT eventId) {} + HWND CreateDetailsView(HWND hParent); + BOOL GetUniqueName(LPWSTR pszBuffer, UINT cchBufferMax); + + +protected: + BOOL AdjustCheckboxRect(SetupListbox *instance, RECT *prcItem); + void GetColors(HDC hdc, UINT state, COLORREF *rgbBkOut, COLORREF *rgbTextOut); + void InvertCheckbox(SetupListbox *instance, const RECT *prcItem); + void OnDownloadCompleted(); + +private: + friend static void CALLBACK SetupRecord_ServiceDownloadedCallback(ifc_omstorageasync *result); + +protected: + ULONG ref; + ifc_omservice *service; + ifc_omstorageasync *async; + CRITICAL_SECTION lock; + UINT flags; +}; + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPRECORD_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupServicePanel.cpp b/Src/Plugins/Library/ml_online/Setup/setupServicePanel.cpp new file mode 100644 index 00000000..eb7c2737 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupServicePanel.cpp @@ -0,0 +1,797 @@ +#include "../common.h" +#include "./setupServicePanel.h" +#include "./setupDetails.h" +#include "./setupPage.h" +#include "../resource.h" +#include "../api__ml_online.h" + +#include <ifc_omservice.h> +#include <ifc_omservicedetails.h> +#include <ifc_omcachemanager.h> +#include <ifc_omcachegroup.h> +#include <ifc_omcacherecord.h> +#include <ifc_imageloader.h> +#include <ifc_omgraphics.h> +#include <ifc_omserviceeventmngr.h> +#include <ifc_omserviceeditor.h> + +#include <shlwapi.h> +#include <strsafe.h> + +#define GetPanel(__hwnd) ((ServicePanel*)GetPropW((__hwnd), MAKEINTATOM(DETAILS_PROP))) + +#define GET_IDETAILS(__service, __details)\ + (NULL != (service) && SUCCEEDED((service)->QueryInterface(IFC_OmServiceDetails, (void**)&(__details)))) + + +ServicePanel::ServicePanel(LPCWSTR pszName, ifc_omservice *service) + : ref(1), name(NULL), service(NULL), hwnd(NULL), fontTitle(NULL), fontMeta(NULL), thumbnailCache(NULL) +{ + name = Plugin_CopyString(pszName); + this->service = service; + if (NULL != service) + service->AddRef(); +} + +ServicePanel::~ServicePanel() +{ + Plugin_FreeString(name); + + if (NULL != service) + service->Release(); + + if (NULL != fontTitle) + DeleteObject(fontTitle); + + if (NULL != fontMeta) + DeleteObject(fontMeta); + + if (NULL != thumbnailCache) + thumbnailCache->Release(); +} + +HWND ServicePanel::CreateInstance(HWND hParent, LPCWSTR pszName, ifc_omservice *service, ServicePanel **instance) +{ + ServicePanel *panel = new ServicePanel(pszName, service); + if (NULL == panel) + { + if (NULL != instance) *instance = NULL; + return NULL; + } + + HWND hwnd = WASABI_API_CREATEDIALOGPARAMW(IDD_SETUP_SERVICEDETAILS, hParent, ServicePanel_DialogProc, (LPARAM)panel); + + if (NULL != instance) + { + if (NULL != hwnd) + { + *instance = panel; + panel->AddRef(); + } + else + *instance = NULL; + } + + panel->Release(); + return hwnd; +} + +size_t ServicePanel::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +size_t ServicePanel::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +int ServicePanel::QueryInterface(GUID interface_guid, void **object) +{ + if (NULL == object) return E_POINTER; + + if (IsEqualIID(interface_guid, IFC_OmServiceEvent)) + *object = static_cast<ifc_omserviceevent*>(this); + else + { + *object = NULL; + return E_NOINTERFACE; + } + + if (NULL == *object) + return E_UNEXPECTED; + + AddRef(); + return S_OK; +} + +static void CALLBACK ThreadCallback_ServiceChange(Dispatchable *instance, ULONG_PTR param1, ULONG_PTR param2) +{ + ifc_omserviceevent *panel = (ifc_omserviceevent*)instance; + ifc_omservice *service = (ifc_omservice*)param1; + if (NULL != service) + { + if (NULL != panel) + panel->ServiceChange(service, (UINT)param2); + service->Release(); + } +} +void ServicePanel::ServiceChange(ifc_omservice *service, unsigned int modifiedFlags) +{ + + DWORD currentTID = GetCurrentThreadId(); + DWORD windowTID = GetWindowThreadProcessId(hwnd, NULL); + if (NULL != windowTID && currentTID != windowTID) + { + if(NULL != OMUTILITY) + { + service->AddRef(); + if (FAILED(OMUTILITY->PostMainThreadCallback2(ThreadCallback_ServiceChange, (ifc_omserviceevent*)this, (ULONG_PTR)service, (ULONG_PTR)modifiedFlags))) + service->Release(); + } + return; + } + + + if ( 0 != (ifc_omserviceeditor::modifiedName & modifiedFlags)) + { + UpdateName(); + HWND hPage = GetParent(hwnd); + if (NULL != hPage) + PostMessage(hPage, SPM_UPDATELIST, (WPARAM)service->GetId(), NULL); + } + + if ( 0 != (ifc_omserviceeditor::modifiedDescription & modifiedFlags)) + UpdateDescription(); + + if ( 0 != (ifc_omserviceeditor::modifiedThumbnail& modifiedFlags)) + UpdateThumbnail(); + + if ( 0 != ((ifc_omserviceeditor::modifiedAuthorFirst | + ifc_omserviceeditor::modifiedAuthorLast | + ifc_omserviceeditor::modifiedUpdated | + ifc_omserviceeditor::modifiedPublished) & modifiedFlags)) + { + UpdateMeta(); + } + +} + +HRESULT ServicePanel::LoadLocalThumbnail(LPCWSTR pszPath) +{ + HWND hThumbnail = GetDlgItem(hwnd, IDC_THUMBNAIL); + if (NULL == hThumbnail) return E_UNEXPECTED; + + SendMessage(hThumbnail, WM_SETREDRAW, FALSE, 0L); + + HBITMAP hBitmap = NULL; + + BITMAPINFOHEADER header; + void *pixelData; + + ifc_omimageloader *imageLoader; + if (SUCCEEDED(OMUTILITY->QueryImageLoader(NULL, pszPath, FALSE, &imageLoader))) + { + imageLoader->LoadBitmapEx(&hBitmap, &header, &pixelData); + imageLoader->Release(); + } + + if (NULL == hBitmap && + SUCCEEDED(OMUTILITY->QueryImageLoader(WASABI_API_ORIG_HINST, MAKEINTRESOURCE(IDR_SERVICE64X64_IMAGE), FALSE, &imageLoader))) + { + imageLoader->LoadBitmapEx(&hBitmap, &header, &pixelData); + imageLoader->Release(); + } + + HBITMAP hTest = (HBITMAP)SendMessage(hThumbnail, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap); + if (NULL != hTest) + DeleteObject(hTest); + + if (NULL != hBitmap) + { + hTest = (HBITMAP)SendMessage(hThumbnail, STM_GETIMAGE, IMAGE_BITMAP, 0L); + if (hTest != hBitmap) + { // this is XP and up image copy was created and alpha channel will be handled properly + DeleteObject(hBitmap); + } + else + { // fix alpha channel + if (32 == header.biBitCount) + { + HDC hdcFixed = CreateCompatibleDC(NULL); + if (NULL != hdcFixed) + { + BITMAPINFOHEADER headerFixed; + CopyMemory(&headerFixed, &header, sizeof(BITMAPINFOHEADER)); + BYTE *pixelsFixed; + INT cx = header.biWidth; + INT cy = abs(header.biHeight); + HBITMAP bitmapFixed = CreateDIBSection(NULL, (LPBITMAPINFO)&headerFixed, DIB_RGB_COLORS, (void**)&pixelsFixed, NULL, 0); + + if (NULL != bitmapFixed) + { + HBITMAP bitmapOrig = (HBITMAP)SelectObject(hdcFixed, bitmapFixed); + HBRUSH hb = (HBRUSH)SendMessage(hwnd, WM_CTLCOLORDLG, (WPARAM)hdcFixed, (LPARAM)hwnd); + if (NULL == hb) + hb = GetSysColorBrush(COLOR_3DFACE); + RECT rect; + SetRect(&rect, 0, 0, cx, cy); + FillRect(hdcFixed, &rect, hb); + + ifc_omgraphics *graphics; + if (SUCCEEDED(OMUTILITY->GetGraphics(&graphics))) + { + HDC hdcSrc = CreateCompatibleDC(NULL); + if (NULL != hdcSrc) + { + HBITMAP bitmapSrcOrig = (HBITMAP)SelectObject(hdcSrc, hBitmap); + BLENDFUNCTION bf; + bf.BlendOp = AC_SRC_OVER; + bf.BlendFlags = 0; + bf.SourceConstantAlpha = 0xFF; + bf.AlphaFormat = AC_SRC_ALPHA; + + RECT blendRect; + SetRect(&blendRect, 0, 0, cx, cy); + + graphics->Premultiply((BYTE*)pixelData, cx, cy); + graphics->AlphaBlend(hdcFixed, &blendRect, hdcSrc, &blendRect, bf); + + SelectObject(hdcSrc, bitmapSrcOrig); + DeleteDC(hdcSrc); + } + graphics->Release(); + } + + SelectObject(hdcFixed, bitmapOrig); + SendMessage(hThumbnail, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)bitmapFixed); + DeleteObject(hBitmap); + + } + DeleteDC(hdcFixed); + } + } + } + } + + RECT clientRect; + if (GetClientRect(hThumbnail, &clientRect)) + { + INT cx = clientRect.right - clientRect.left; + INT cy = clientRect.bottom - clientRect.top; + if (64 != cx || 64 != cy) + { + SetWindowPos(hThumbnail, NULL, 0, 0, 64, 64, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER); + } + } + + SendMessage(hThumbnail, WM_SETREDRAW, TRUE, 0L); + + if (0 != ShowWindow(hThumbnail, (NULL != hBitmap) ? SW_SHOWNA : SW_HIDE)) + InvalidateRect(hThumbnail, NULL, TRUE); + + return S_OK; +} + +static void CALLBACK ThreadCallback_PathChanged(Dispatchable *instance, ULONG_PTR param1, ULONG_PTR param2) +{ + ifc_omcachecallback *panel = (ifc_omcachecallback*)instance; + ifc_omcacherecord *record = (ifc_omcacherecord*)param1; + if (NULL != record) + { + if (NULL != panel) + panel->PathChanged(record); + record->Release(); + } +} + +void ServicePanel::PathChanged(ifc_omcacherecord *record) +{ + if (NULL == hwnd || FALSE == IsWindow(hwnd)) + return; + + DWORD currentTID = GetCurrentThreadId(); + DWORD windowTID = GetWindowThreadProcessId(hwnd, NULL); + if (NULL != windowTID && currentTID != windowTID) + { + if(NULL != OMUTILITY) + { + record->AddRef(); + if (FAILED(OMUTILITY->PostMainThreadCallback2(ThreadCallback_PathChanged, (ifc_omcachecallback*)this, (ULONG_PTR)record, 0L))) + record->Release(); + } + return; + } + + WCHAR szPath[2048] = {0}; + if (FAILED(record->GetPath(szPath, ARRAYSIZE(szPath)))) + szPath[0] = L'\0'; + + LoadLocalThumbnail(szPath); +} + +void ServicePanel::Attach(HWND hwnd) +{ + this->hwnd = hwnd; + if (NULL != hwnd && + FALSE != SetProp(hwnd, MAKEINTATOM(DETAILS_PROP), this)) + { + AddRef(); + } +} + +void ServicePanel::Detach() +{ + RemoveProp(hwnd, MAKEINTATOM(DETAILS_PROP)); + + if (NULL != thumbnailCache) + { + thumbnailCache->UnregisterCallback(this); + thumbnailCache->Release(); + thumbnailCache = NULL; + } + + if (NULL != service) + { + ifc_omserviceeventmngr *eventManager; + if (SUCCEEDED(service->QueryInterface(IFC_OmServiceEventMngr, (void**)&eventManager))) + { + eventManager->UnregisterHandler(this); + eventManager->Release(); + } + } + + Release(); +} + +HFONT ServicePanel::PickTitleFont(LPCWSTR pszTitle, INT cchTitle, INT maxWidth) +{ + HFONT dialogFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L); + + LOGFONT lf; + if (0 == GetObject(dialogFont, sizeof(LOGFONT), &lf)) + return NULL; + + HFONT titleFont = NULL; + if (cchTitle > 0) + { + LOGFONT lf; + if (0 != GetObject(dialogFont, sizeof(LOGFONT), &lf)) + { + StringCchCopy(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), L"Arial Bold"); + lf.lfWidth = 0; + lf.lfWeight = FW_DONTCARE; + lf.lfQuality = 5/*ANTIALIASED_QUALITY*/; + + HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL != hdc) + { + HFONT origFont = (HFONT)GetCurrentObject(hdc, OBJ_FONT); + SIZE textSize; + + INT heightLimit = (lf.lfHeight < 0) ? 1 : -1; + lf.lfHeight += (lf.lfHeight < 0) ? -2 : +2; + do + { + textSize.cx = 0; + if (NULL != titleFont) DeleteObject(titleFont); + titleFont = CreateFontIndirect(&lf); + if (NULL != titleFont) + { + SelectObject(hdc, titleFont); + GetTextExtentPoint32(hdc, pszTitle, cchTitle, &textSize); + } + lf.lfHeight += (lf.lfHeight < 0) ? 1 : -1; + + } while(textSize.cx > maxWidth && lf.lfHeight != heightLimit); + + if (0 == textSize.cx) + { + DeleteObject(titleFont); + titleFont = NULL; + } + + SelectObject(hdc, origFont); + ReleaseDC(hwnd, hdc); + } + } + } + + if (NULL == titleFont && + 0 != GetObject(dialogFont, sizeof(LOGFONT), &lf)) + { + titleFont = CreateFontIndirect(&lf); + } + return titleFont; +} + +LPCWSTR ServicePanel::FormatDate(LPCWSTR pszDate, LPWSTR pszBuffer, INT cchBufferMax) +{ + SYSTEMTIME st; + ZeroMemory(&st, sizeof(SYSTEMTIME)); + LPCWSTR cursor; + + cursor = pszDate; + INT index = 0; + + for(;;) + { + + INT iVal; + + if (FALSE == StrToIntEx(cursor, STIF_DEFAULT, &iVal) || iVal < 1) + { + index = 0; + break; + } + + if (0 == index) + { + if (iVal < 2000 || iVal > 2100) + break; + st.wYear = iVal; + index++; + } + else if (1 == index) + { + if (iVal < 1 || iVal > 12) + break; + st.wMonth = iVal; + index++; + } + else if (2 == index) + { + if (iVal < 1 || iVal > 31) + break; + st.wDay = iVal; + index++; + } + else + { + index = 0; + break; + } + + while(L'\0' != *cursor && L'-' != *cursor) cursor++; + if (L'-' == *cursor) cursor++; + if (L'\0' == *cursor) + break; + + } + + if (3 == index && + 0 != GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, pszBuffer, cchBufferMax)) + { + return pszBuffer; + } + + return pszDate; +} + + + +HRESULT ServicePanel::GetFullName(LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer) + return E_POINTER; + *pszBuffer = L'\0'; + + if (NULL == service) return E_UNEXPECTED; + + ifc_omservicedetails *details; + HRESULT hr = service->QueryInterface(IFC_OmServiceDetails, (void**)&details); + if (SUCCEEDED(hr)) + { + hr = details->GetAuthorFirst(pszBuffer, cchBufferMax); + if (SUCCEEDED(hr)) + { + UINT cchBuffer = lstrlen(pszBuffer); + LPWSTR cursor = pszBuffer + cchBuffer; + size_t remaining = cchBufferMax - cchBuffer; + + if (cursor != pszBuffer) + { + hr = StringCchCopyEx(cursor, remaining, L" ", &cursor, &remaining, 0); + if (SUCCEEDED(hr)) + { + hr = details->GetAuthorLast(cursor, (UINT)remaining); + if (FAILED(hr) || L'\0' == *cursor) + { + pszBuffer[cchBuffer] = L'\0'; + } + } + } + } + } + return hr; +} +void ServicePanel::UpdateName() +{ + HWND hTitle = GetDlgItem(hwnd, IDC_TITLE); + if (NULL == hTitle) return; + + WCHAR szBuffer[128] = {0}; + if (NULL == service || + FAILED(service->GetName(szBuffer, ARRAYSIZE(szBuffer)))) + { + szBuffer[0] = L'\0'; + } + + INT cchBuffer = lstrlen(szBuffer); + RECT rc; + GetClientRect(hTitle, &rc); + HFONT font = PickTitleFont(szBuffer, cchBuffer, rc.right - rc.left); + if (NULL != font) + { + if (NULL != fontTitle) + DeleteObject(fontTitle); + + fontTitle = font; + SendMessage(hTitle, WM_SETFONT, (WPARAM)fontTitle, 0L); + } + + + SetWindowText(hTitle, szBuffer); + InvalidateRect(hTitle, NULL, TRUE); +} + + +void ServicePanel::UpdateDescription() +{ + HWND hDescription = GetDlgItem(hwnd, IDC_DESCRIPTION); + if (NULL == hDescription) return; + + WCHAR szBuffer[4096] = {0}; + ifc_omservicedetails *details = 0; + if (GET_IDETAILS(service, details)) + { + details->GetDescription(szBuffer, ARRAYSIZE(szBuffer)); + details->Release(); + } + + SetupDetails_SetDescription(hDescription, szBuffer); +} + +void ServicePanel::UpdateMeta() +{ + HWND hMeta = GetDlgItem(hwnd, IDC_SERVICEMETA); + if (NULL == hMeta) return; + + WCHAR szBuffer[512] = {0}; + ifc_omservicedetails *svcdetails = 0; + if (GET_IDETAILS(service, svcdetails)) + { + WCHAR szValue[256] = {0}, szPrefix[64] = {0}; + HRESULT hr = S_OK; + LPWSTR cursor = szBuffer; + size_t remaining = ARRAYSIZE(szBuffer); + + if (SUCCEEDED(GetFullName(szValue, ARRAYSIZE(szValue))) && L'\0' != szValue[0]) + { + WASABI_API_LNGSTRINGW_BUF(IDS_SERVICE_BYAUTHOR, szPrefix, ARRAYSIZE(szPrefix)); + hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, + L"%s%s", szPrefix, szValue); + } + + if (SUCCEEDED(svcdetails->GetUpdated(szValue, ARRAYSIZE(szValue))) && L'\0' != szValue[0]) + { + if (cursor != szBuffer) + hr = StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE); + + if (SUCCEEDED(hr)) + { + WCHAR szDate[128] = {0}; + WASABI_API_LNGSTRINGW_BUF(IDS_SERVICE_LASTUPDATED, szPrefix, ARRAYSIZE(szPrefix)); + StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, + L"%s%s", szPrefix, FormatDate(szValue, szDate, ARRAYSIZE(szDate))); + } + } + + svcdetails->Release(); + } + + if (NULL == fontMeta) + { + HFONT dialogFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L); + LOGFONT lf; + if (0 != GetObject(dialogFont, sizeof(LOGFONT), &lf)) + { + StringCchCopy(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), L"Tahoma"); + lf.lfWidth = 0; + lf.lfHeight += (lf.lfHeight < 0) ? 1 : -1; + lf.lfQuality = ANTIALIASED_QUALITY; + fontMeta = CreateFontIndirect(&lf); + } + + if (NULL != fontMeta) + { + SendMessage(hMeta, WM_SETFONT, (WPARAM)fontMeta, 0L); + } + } + + SetWindowText(hMeta, szBuffer); + if (0 != ShowWindow(hMeta, (L'\0' != szBuffer[0]) ? SW_SHOWNA : SW_HIDE)) + InvalidateRect(hMeta, NULL, TRUE); +} + +void ServicePanel::UpdateThumbnail() +{ + if (NULL != thumbnailCache) + { + thumbnailCache->UnregisterCallback(this); + thumbnailCache->Release(); + thumbnailCache = NULL; + } + LoadLocalThumbnail(NULL); + + ifc_omservicedetails *details = 0; + if (GET_IDETAILS(service, details)) + { + WCHAR szPath[2048] = {0}; + if (SUCCEEDED(details->GetThumbnail(szPath, ARRAYSIZE(szPath))) && L'\0' != szPath[0]) + { + ifc_omcachemanager *cacheManager; + if (SUCCEEDED(OMUTILITY->GetCacheManager(&cacheManager))) + { + ifc_omcachegroup *cacheGroup; + if (SUCCEEDED(cacheManager->Find(L"thumbnails", TRUE, &cacheGroup, NULL))) + { + + if (SUCCEEDED(cacheGroup->Find(szPath, TRUE, &thumbnailCache, FALSE))) + { + thumbnailCache->RegisterCallback(this); + if (SUCCEEDED(thumbnailCache->GetPath(szPath, ARRAYSIZE(szPath)))) + LoadLocalThumbnail(szPath); + } + cacheGroup->Release(); + } + cacheManager->Release(); + } + } + details->Release(); + } +} + + + + +INT_PTR ServicePanel::OnInitDialog(HWND hFocus, LPARAM lParam) +{ + UpdateName(); + UpdateDescription(); + UpdateThumbnail(); + UpdateMeta(); + + if (NULL != service) + { + ifc_omserviceeventmngr *eventManager; + if (SUCCEEDED(service->QueryInterface(IFC_OmServiceEventMngr, (void**)&eventManager))) + { + eventManager->RegisterHandler(this); + eventManager->Release(); + } + } + + return FALSE; +} + +void ServicePanel::OnDestroy() +{ + + HWND hThumbnail = GetDlgItem(hwnd, IDC_THUMBNAIL); + if (NULL != hThumbnail) + { + HBITMAP hBitmap = (HBITMAP)SendMessage(hThumbnail, STM_SETIMAGE, IMAGE_BITMAP, 0L); + if (NULL != hBitmap) + DeleteObject(hBitmap); + } + + Detach(); +} + + +INT_PTR ServicePanel::OnDialogColor(HDC hdc, HWND hControl) +{ + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if (NULL != hParent && hParent != hwnd) + return (INT_PTR)SendMessage(hParent, WM_CTLCOLORDLG, (WPARAM)hdc, (LPARAM)hControl); + + return 0; +} + + +INT_PTR ServicePanel::OnStaticColor(HDC hdc, HWND hControl) +{ + INT_PTR result = 0; + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if (NULL != hParent && hParent != hwnd) + result = (INT_PTR)SendMessage(hParent, WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hControl); + + INT controlId = GetDlgCtrlID(hControl); + switch(controlId) + { + case IDC_SERVICEMETA: + { + COLORREF rgbBk = GetBkColor(hdc); + COLORREF rgbFg = GetTextColor(hdc); + + ifc_omgraphics *graphics; + if (SUCCEEDED(OMUTILITY->GetGraphics(&graphics))) + { + graphics->BlendColor(rgbFg, rgbBk, 180, &rgbFg); + graphics->Release(); + } + + SetTextColor(hdc, rgbFg); + } + break; + } + return result; +} + + +INT_PTR ServicePanel::OnGetUniqueName(LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer) return FALSE; + return SUCCEEDED(StringCchCopy(pszBuffer, cchBufferMax, (NULL != name) ? name : L"")); +} + +INT_PTR ServicePanel::DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: return OnInitDialog((HWND)wParam, lParam); + case WM_DESTROY: OnDestroy(); break; + case WM_CTLCOLORDLG: return OnDialogColor((HDC)wParam, (HWND)lParam); + case WM_CTLCOLORSTATIC: return OnStaticColor((HDC)wParam, (HWND)lParam); + + case NSDM_GETUNIQUENAME: MSGRESULT(hwnd, OnGetUniqueName((LPWSTR)lParam, (UINT)wParam)); + } + return 0; +} + +static INT_PTR WINAPI ServicePanel_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + ServicePanel *panel = GetPanel(hwnd); + if (NULL == panel) + { + if (WM_INITDIALOG == uMsg) + { + panel = (ServicePanel*)lParam; + if (NULL != panel) + panel->Attach(hwnd); + } + + if (NULL == panel) return 0; + } + + return panel->DialogProc(uMsg, wParam, lParam); +} + + + +#define CBCLASS ServicePanel +START_MULTIPATCH; + START_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); + + + NEXT_PATCH(MPIID_CACHECALLBACK) + M_CB(MPIID_CACHECALLBACK, ifc_omcachecallback, ADDREF, AddRef); + M_CB(MPIID_CACHECALLBACK, ifc_omcachecallback, RELEASE, Release); + M_CB(MPIID_CACHECALLBACK, ifc_omcachecallback, QUERYINTERFACE, QueryInterface); + M_VCB(MPIID_CACHECALLBACK, ifc_omcachecallback, API_PATHCHANGED, PathChanged); + + END_PATCH +END_MULTIPATCH; +#undef CBCLASS diff --git a/Src/Plugins/Library/ml_online/Setup/setupServicePanel.h b/Src/Plugins/Library/ml_online/Setup/setupServicePanel.h new file mode 100644 index 00000000..f60adac1 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupServicePanel.h @@ -0,0 +1,79 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUP_SERVICE_PANEL_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUP_SERVICE_PANEL_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include <bfc/multipatch.h> +#include <ifc_omserviceevent.h> +#include <ifc_omcachecallback.h> + +class ifc_omservice; + +#define MPIID_SERVICEEVENT 10 +#define MPIID_CACHECALLBACK 20 + + +class ServicePanel : public MultiPatch<MPIID_SERVICEEVENT, ifc_omserviceevent>, + public MultiPatch<MPIID_CACHECALLBACK, ifc_omcachecallback> +{ +protected: + ServicePanel(LPCWSTR pszName, ifc_omservice *service); + ~ServicePanel(); + +public: + static HWND CreateInstance(HWND hParent, LPCWSTR pszName, ifc_omservice *service, ServicePanel **instance); + +public: + /* Dispatchable */ + size_t AddRef(); + size_t Release(); + int QueryInterface(GUID interface_guid, void **object); + + /* ifc_omserviceevent */ + void ServiceChange(ifc_omservice *service, unsigned int modifiedFlags); + + /* ifc_omcachecallback */ + void PathChanged(ifc_omcacherecord *record); + +protected: + void Attach(HWND hwnd); + void Detach(); + + void UpdateName(); + void UpdateDescription(); + void UpdateMeta(); + void UpdateThumbnail(); + + HFONT PickTitleFont(LPCWSTR pszTitle, INT cchTitle, INT maxWidth); + LPCWSTR FormatDate(LPCWSTR pszDate, LPWSTR pszBuffer, INT cchBufferMax); + HRESULT GetFullName(LPWSTR pszBuffer, UINT cchBufferMax); + + INT_PTR OnInitDialog(HWND hFocus, LPARAM lParam); + void OnDestroy(); + INT_PTR OnDialogColor(HDC hdc, HWND hControl); + INT_PTR OnStaticColor(HDC hdc, HWND hControl); + INT_PTR DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam); + INT_PTR OnGetUniqueName(LPWSTR pszBuffer, UINT cchBufferMax); + HRESULT LoadLocalThumbnail(LPCWSTR pszPath); + +private: + friend static INT_PTR WINAPI ServicePanel_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +protected: + size_t ref; + HWND hwnd; + LPWSTR name; + ifc_omservice *service; + ifc_omcacherecord *thumbnailCache; + HFONT fontTitle; + HFONT fontMeta; + +private: + RECVS_MULTIPATCH; +}; + + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_SETUP_SERVICE_PANEL_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/api__ml_online.h b/Src/Plugins/Library/ml_online/api__ml_online.h new file mode 100644 index 00000000..e40852bf --- /dev/null +++ b/Src/Plugins/Library/ml_online/api__ml_online.h @@ -0,0 +1,62 @@ +#ifndef NULLOSFT_ONLINEMEDIA_WASABI_API_HEADER +#define NULLOSFT_ONLINEMEDIA_WASABI_API_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +#include <api/service/api_service.h> +extern api_service *wasabiManager; +#define WASABI_API_SVC wasabiManager + +#include <api/application/api_application.h> +#define WASABI_API_APP applicationApi + +#include "../Agave/Config/api_config.h" +#include "../Agave/Language/api_language.h" + +#include <api/memmgr/api_memmgr.h> +extern api_memmgr *memManagerApi; +#define WASABI_API_MEMMNGR memManagerApi + +#include "../Agave/ExplorerFindFile/api_explorerfindfile.h" + +#include "../Winamp/JSAPI2_api_security.h" +extern JSAPI2::api_security *jsapi2_securityApi; +#define AGAVE_API_JSAPI2_SECURITY jsapi2_securityApi + +#include <api/service/svcs/svc_imgload.h> +extern svc_imageLoader *pngLoaderApi; +#define WASABI_API_PNGLOADER pngLoaderApi +EXTERN_C const GUID pngLoaderGUID; + +#include "../auth/api_auth.h" +extern api_auth *authApi; +#define AGAVE_API_AUTH authApi + +#include <obj_ombrowser.h> +extern obj_ombrowser *browserManager; +#define OMBROWSERMNGR browserManager + +#include <ifc_omservicemanager.h> +extern ifc_omservicemanager *serviceManager; +#define OMSERVICEMNGR serviceManager + +#include <ifc_omutility.h> +extern ifc_omutility *omUtility; +#define OMUTILITY omUtility + +HRESULT WasabiApi_Initialize(HINSTANCE hInstance, api_service *serviceApi); +HRESULT WasabiApi_LoadDefaults(); +ULONG WasabiApi_AddRef(void); +ULONG WasabiApi_Release(void); + +void *Wasabi_QueryInterface(REFGUID interfaceGuid); +void Wasabi_ReleaseInterface(REFGUID interfaceGuid, void *pInstance); + +#define QueryWasabiInterface(__interfaceType, __interfaceGuid) ((##__interfaceType*)Wasabi_QueryInterface(__interfaceGuid)) +#define ReleaseWasabiInterface(__interfaceGuid, __interfaceInstance) (Wasabi_ReleaseInterface((__interfaceGuid), (__interfaceInstance))) + +#endif // NULLOSFT_ONLINEMEDIA_WASABI_API_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/browserEvent.cpp b/Src/Plugins/Library/ml_online/browserEvent.cpp new file mode 100644 index 00000000..d24442a7 --- /dev/null +++ b/Src/Plugins/Library/ml_online/browserEvent.cpp @@ -0,0 +1,100 @@ +#include "main.h" +#include "./browserEvent.h" +#include "./serviceHost.h" +#include "./serviceHelper.h" + +#include <ifc_omservice.h> +#include <ifc_omserviceeventmngr.h> +#include <ifc_omservicecommand.h> + +#include <browserView.h> +#include <browserPopup.h> + +BrowserEvent::BrowserEvent() + : ref(1) +{ +} + +BrowserEvent::~BrowserEvent() +{ +} + +HRESULT BrowserEvent::CreateInstance(BrowserEvent **instance) +{ + if (NULL == instance) return E_POINTER; + *instance = new BrowserEvent(); + if (NULL == *instance) return E_OUTOFMEMORY; + return S_OK; +} + +size_t BrowserEvent::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +size_t BrowserEvent::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +int BrowserEvent::QueryInterface(GUID interface_guid, void **object) +{ + if (NULL == object) return E_POINTER; + + if (IsEqualIID(interface_guid, IFC_OmBrowserEvent)) + *object = static_cast<ifc_ombrowserevent*>(this); + else + { + *object = NULL; + return E_NOINTERFACE; + } + + if (NULL == *object) + return E_UNEXPECTED; + + AddRef(); + return S_OK; +} + +void BrowserEvent::WindowCreate(HWND hwnd, const GUID *windowType) +{ + if (NULL != windowType) + { + if (IsEqualGUID(*windowType, WTID_BrowserView) || + IsEqualGUID(*windowType, WTID_BrowserPopup)) + { + ifc_omservice *service; + if (FALSE != BrowserControl_GetService(hwnd, &service)) + { + UINT flags; + if (SUCCEEDED(service->GetFlags(&flags)) && + 0 == ((SVCF_SPECIAL | SVCF_VALIDATED | SVCF_VERSIONCHECK) & flags)) + { + ServiceHelper_BeginVersionCheck(service); + } + service->Release(); + } + } + } +} + +void BrowserEvent::WindowClose(HWND hwnd, const GUID *windowType) +{ +} + +#define CBCLASS BrowserEvent +START_DISPATCH; +CB(ADDREF, AddRef) +CB(RELEASE, Release) +CB(QUERYINTERFACE, QueryInterface) +VCB(API_WINDOWCREATE, WindowCreate) +VCB(API_WINDOWCLOSE, WindowClose) +END_DISPATCH; +#undef CBCLASS diff --git a/Src/Plugins/Library/ml_online/browserEvent.h b/Src/Plugins/Library/ml_online/browserEvent.h new file mode 100644 index 00000000..07d10f52 --- /dev/null +++ b/Src/Plugins/Library/ml_online/browserEvent.h @@ -0,0 +1,41 @@ +#ifndef NULLSOFT_ONLINEMEDIA_PLUGIN_BROWSER_EVENT_HANDLER_HEADER +#define NULLSOFT_ONLINEMEDIA_PLUGIN_BROWSER_EVENT_HANDLER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <ifc_ombrowserevent.h> + +class BrowserEvent : public ifc_ombrowserevent +{ + +protected: + BrowserEvent(); + ~BrowserEvent(); + +public: + static HRESULT CreateInstance(BrowserEvent **instance); + +public: + /* Dispatchable */ + size_t AddRef(); + size_t Release(); + int QueryInterface(GUID interface_guid, void **object); + + /* ifc_ombrowserevent */ + void WindowCreate(HWND hwnd, const GUID *windowType); + void WindowClose(HWND hwnd, const GUID *windowType); + + +protected: + ULONG ref; + +protected: + RECVS_DISPATCH; +}; + + + + +#endif //NULLSOFT_ONLINEMEDIA_PLUGIN_BROWSER_EVENT_HANDLER_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/commands.cpp b/Src/Plugins/Library/ml_online/commands.cpp new file mode 100644 index 00000000..0762991f --- /dev/null +++ b/Src/Plugins/Library/ml_online/commands.cpp @@ -0,0 +1,418 @@ +#include "main.h" +#include "./commands.h" +#include "./api__ml_online.h" +#include "./resource.h" +#include "./navigation.h" +#include "./preferences.h" +#include "./messagebox.h" +#include "./serviceHelper.h" +#include "../winamp/wa_ipc.h" +#include "./import.h" +#include <ifc_omservice.h> +#include <browserView.h> +#include <wininet.h> +#include <shlwapi.h> +#include <strsafe.h> + +#define BEGIN_COMMAND_SELECT(__commandId) switch(commandId) { +#define END_COMMAND_SELECT } + +#define OMCOMMAND(__commandId, __commandCode, __resultOut) case (__commandId):\ + { BOOL result = ##__commandCode; \ + if (NULL != (__resultOut)) { *(__resultOut) = result;}\ + return TRUE;} + +BOOL Command_SetServiceRating(ifc_omservice *service, INT rating) +{ + return SUCCEEDED(ServiceHelper_SetRating(service, rating, SHF_NOTIFY | SHF_VERBAL | SHF_SAVE)); +} + +BOOL Command_OpenServiceView(ifc_omservice *service) +{ + BOOL resultOk = FALSE;; + Navigation *navigation; + if (NULL != service && SUCCEEDED(Plugin_GetNavigation(&navigation))) + { + HNAVITEM hItem = navigation->FindService(service->GetId(), NULL); + if (NULL != hItem) + { + HRESULT hr = navigation->SelectItem(hItem, NULL); + + if (SUCCEEDED(hr)) + resultOk = TRUE; + } + navigation->Release(); + } + + return resultOk; +} + +HRESULT Command_NavigateService(ifc_omservice *service, LPCWSTR pszUrl, BOOL fActiveOnly) +{ + if (NULL == service) + return E_INVALIDARG; + + Navigation *navigation; + if (FAILED(Plugin_GetNavigation(&navigation))) + return E_UNEXPECTED; + + ifc_omservice *activeService; + HWND hView = navigation->GetActiveView(&activeService); + if (NULL == hView || activeService->GetId() != service->GetId()) + hView = NULL; + + if (NULL != activeService) + activeService->Release(); + + HRESULT hr = S_OK; + + if (NULL != hView) + { + if (FALSE == BrowserView_Navigate(hView, pszUrl, TRUE)) + hr = E_FAIL; + } + else + { + hr = (FALSE == fActiveOnly) ? + navigation->ShowService(service->GetId(), pszUrl) : E_NOTIMPL; + } + + navigation->Release(); + + return hr; +} + +HRESULT Command_EditService( ifc_omservice *service ) +{ + if ( NULL == service ) + return E_INVALIDARG; + + WCHAR szBuffer[ 2048 ] = { 0 }; + + HRESULT hr = Plugin_MakeResourcePath( szBuffer, ARRAYSIZE( szBuffer ), RT_HTML, MAKEINTRESOURCE( IDR_HTML_EDITOR ), RESPATH_TARGETIE | RESPATH_COMPACT ); + if ( FAILED( hr ) ) + return hr; + + INT cchUrl = lstrlen( szBuffer ); + LPWSTR pszParam = szBuffer + cchUrl; + INT cchParamMax = ARRAYSIZE( szBuffer ) - cchUrl; + + hr = StringCchPrintf( pszParam, cchParamMax, L"?serviceId=%u", service->GetId() ); + if ( FAILED( hr ) ) + return hr; + + return Command_NavigateService( service, szBuffer, FALSE ); +} + +BOOL Command_OpenServicePopup(ifc_omservice *service) +{ + BOOL resultOk = FALSE;; + Navigation *navigation; + if (NULL != service && SUCCEEDED(Plugin_GetNavigation(&navigation))) + { + HNAVITEM hItem = navigation->FindService(service->GetId(), NULL); + if (NULL != hItem) + { + HWND hPopup; + HRESULT hr = navigation->CreatePopup(hItem, &hPopup); + if (SUCCEEDED(hr)) + { + ShowWindow(hPopup, SW_SHOWNORMAL); + resultOk = TRUE; + } + } + navigation->Release(); + } + + return resultOk; +} + +BOOL Command_ReportService(ifc_omservice *service) +{ + HWND hWinamp = Plugin_GetWinamp(); + if (NULL == hWinamp || !IsWindow(hWinamp)) + return FALSE; + + if (NULL == service) + return FALSE; + + WCHAR szUrl[256] = {0}; + WCHAR szClient[128] = {0}; + + OMBROWSERMNGR->GetClientId(szClient, ARRAYSIZE(szClient)); + + StringCchPrintf(szUrl, ARRAYSIZE(szUrl), L"http://www.winamp.com/legal/abuse?svc_id=%u&unique=%s", + service->GetId(), szClient); + + SENDWAIPC(hWinamp, IPC_OPEN_URL, szUrl); + return TRUE; +} + +BOOL Command_UnsubscribeService(ifc_omservice *service) +{ + return (SUCCEEDED(ServiceHelper_Subscribe(service, FALSE, SHF_NOTIFY | SHF_VERBAL | SHF_SAVE))); +} + +BOOL Command_ShowServiceInfo(ifc_omservice *service) +{ + if (NULL == service) + return FALSE; + + BOOL resultOk = FALSE; + + HRESULT hr; + WCHAR szUrl[INTERNET_MAX_URL_LENGTH] = {0}, szName[INTERNET_MAX_URL_LENGTH] = {0}; + + DWORD cchName = ARRAYSIZE(szName); + if (FAILED(service->GetName(szUrl, ARRAYSIZE(szUrl))) || + FAILED(UrlEscape(szUrl, szName, &cchName, URL_ESCAPE_SEGMENT_ONLY | URL_ESCAPE_PERCENT))) + { + StringCchCopy(szName, ARRAYSIZE(szName), L"Info"); + } + + hr = StringCchPrintf(szUrl, ARRAYSIZE(szUrl), L"http://client.winamp.com/service/detail/%s/%d#", szName, service->GetId()); + if (FAILED(hr)) return hr; + + Navigation *navigation; + hr = Plugin_GetNavigation(&navigation); + if (SUCCEEDED(hr)) + { + HNAVITEM hRoot = navigation->FindService(ROOTSERVICE_ID, NULL); + if (NULL != hRoot) + { + HNAVITEM hActive = navigation->GetActive(NULL); + if (hActive == hRoot) + { + HWND hView = navigation->GetActiveView(NULL); + if (NULL != hView && FALSE != BrowserView_Navigate(hView, szUrl, TRUE)) + resultOk = TRUE; + } + + if (FALSE == resultOk && SUCCEEDED(navigation->SelectItem(hRoot, szUrl))) + resultOk = TRUE; + } + navigation->Release(); + } + return resultOk; +} + +BOOL Command_ResetServicePolicy(ifc_omservice *service) +{ + return (SUCCEEDED(ServiceHelper_ResetPermissions(service, SHF_NOTIFY | SHF_VERBAL))); +} + +BOOL Command_ResetSubscription() +{ + HRESULT hr = ServiceHelper_ResetSubscription(SHF_VERBAL); + return SUCCEEDED(hr); +} + +static BOOL Command_OpenPreferences() +{ + return Preferences_Show(); +} + +static BOOL Command_OpenHelp() +{ + return (BOOL)SENDWAIPC(Plugin_GetWinamp(), IPC_OPEN_URL, L"https://help.winamp.com/hc/articles/8112533645844-Online-Services"); +} + +static BOOL Command_NavigateView(HWND hView, LPCWSTR navigateUrl) +{ + Navigation *navigation; + if (FAILED(Plugin_GetNavigation(&navigation))) + return E_UNEXPECTED; + + HWND hActive = navigation->GetActiveView(NULL); + if (hActive != hView) hView = NULL; + + BOOL resultOk = ( NULL != hView && FALSE != BrowserView_Navigate( hView, navigateUrl, TRUE ) ); + + navigation->Release(); + + return resultOk; +} + +HRESULT Command_ImportFiles() +{ + HWND hOwner = Plugin_GetDialogOwner(); + return ImportService_FromFile(hOwner); +} + +HRESULT Command_ImportUrl() +{ + HWND hOwner = Plugin_GetDialogOwner(); + return ImportService_FromUrl(hOwner); +} + +HRESULT Command_CreateService() +{ + Navigation *navigation; + HRESULT hr = Plugin_GetNavigation(&navigation); + if (FAILED(hr)) return hr; + + HNAVITEM hItem; + hr = navigation->CreateUserService(&hItem); + if (SUCCEEDED(hr)) + { + ifc_omservice *service; + hr= navigation->GetService(hItem, &service); + if (SUCCEEDED(hr)) + { + Command_EditService(service); + service->Release(); + } + } + navigation->Release(); + return hr; +} + +HRESULT Command_LocateService(ifc_omservice *service) +{ + if (NULL == service) + return E_INVALIDARG; + + WCHAR szPath[512]; + + HRESULT hr = service->GetAddress(szPath, ARRAYSIZE(szPath)); + if (FAILED(hr)) return hr; + + if (L'\0' == szPath[0]) + return E_FAIL; + + Navigation *navigation; + if (FAILED(Plugin_GetNavigation(&navigation))) + return E_UNEXPECTED; + + navigation->Release(); + + if (WASABI_API_EXPLORERFINDFILE) + { + WASABI_API_EXPLORERFINDFILE->AddFile(szPath); + WASABI_API_EXPLORERFINDFILE->ShowFiles(); + } + return E_UNEXPECTED; +} + +HRESULT Command_EditServiceExternal(ifc_omservice *service) +{ + if (NULL == service) + return E_INVALIDARG; + + WCHAR szPath[512]; + + HRESULT hr = service->GetAddress(szPath, ARRAYSIZE(szPath)); + if (FAILED(hr)) return hr; + + if (L'\0' == szPath[0]) + return E_FAIL; + + Navigation *navigation; + if (FAILED(Plugin_GetNavigation(&navigation))) + return E_UNEXPECTED; + + HWND hOwner = navigation->GetActiveView(NULL); + navigation->Release(); + + if (NULL == hOwner) + hOwner = Plugin_GetLibrary(); + + HINSTANCE hInst = ShellExecute(hOwner, L"open", szPath, NULL, NULL, SW_SHOWNORMAL); + hr = ((INT_PTR)hInst > 32) ? S_OK : E_FAIL; + return hr; +} + +BOOL Command_ProcessService(HWND hView, ifc_omservice *service, INT commandId, BOOL *fSuccess) +{ + BEGIN_COMMAND_SELECT(commandId) + OMCOMMAND(ID_RATING_VALUE_5, Command_SetServiceRating(service, 5), fSuccess); + OMCOMMAND(ID_RATING_VALUE_4, Command_SetServiceRating(service, 4), fSuccess); + OMCOMMAND(ID_RATING_VALUE_3, Command_SetServiceRating(service, 3), fSuccess); + OMCOMMAND(ID_RATING_VALUE_2, Command_SetServiceRating(service, 2), fSuccess); + OMCOMMAND(ID_RATING_VALUE_1, Command_SetServiceRating(service, 1), fSuccess); + OMCOMMAND(ID_VIEW_OPEN, Command_OpenServiceView(service), fSuccess); + OMCOMMAND(ID_VIEW_OPENPOPUP, Command_OpenServicePopup(service), fSuccess); + //OMCOMMAND(ID_SERVICE_REPORT, Command_ReportService(service), fSuccess); + OMCOMMAND(ID_SERVICE_UNSUBSCRIBE, Command_UnsubscribeService(service), fSuccess); + //OMCOMMAND(ID_SERVICE_GETINFO, Command_ShowServiceInfo(service), fSuccess); + OMCOMMAND(ID_SERVICE_RESETPOLICY, Command_ResetServicePolicy(service), fSuccess); + OMCOMMAND(ID_SERVICE_IMPORT_FILE, Command_ImportFiles(), fSuccess); + OMCOMMAND(ID_SERVICE_IMPORT_URL, Command_ImportUrl(), fSuccess); + OMCOMMAND(ID_NAVIGATION_REFRESH, Command_NavigateView(hView, NAVIGATE_REFRESH), fSuccess); + + OMCOMMAND(ID_SERVICE_NEW, Command_CreateService(), fSuccess); + OMCOMMAND(ID_SERVICE_EDIT, Command_EditService(service), fSuccess); + OMCOMMAND(ID_SERVICE_LOCATE, Command_LocateService(service), fSuccess); + OMCOMMAND(ID_SERVICE_EDITEXTERNAL, Command_EditServiceExternal(service), fSuccess); + + END_COMMAND_SELECT + + return FALSE; +} + +BOOL Command_ProcessGeneral(INT commandId, BOOL *fSuccess) +{ + BEGIN_COMMAND_SELECT(commandId) + //OMCOMMAND(ID_SERVICEMANAGER_RESET, Command_ResetSubscription(), fSuccess); + OMCOMMAND(ID_PLUGIN_PREFERENCES, Command_OpenPreferences(), fSuccess); + OMCOMMAND(ID_PLUGIN_HELP, Command_OpenHelp(), fSuccess); + END_COMMAND_SELECT + + return FALSE; +} + +static void CALLBACK BrowserOptions_Callback(HWND hOptions, UINT type, ULONG_PTR user) +{ + HWND hLibrary = (HWND)user; + switch(type) + { + case BOCALLBACK_INIT: + { + HWND hView = (HWND)SENDMLIPC(hLibrary, ML_IPC_GETCURRENTVIEW, 0); + if (NULL != hView) + { + RECT viewRect, optionsRect; + if (GetWindowRect(hView, &viewRect) && GetWindowRect(hOptions, &optionsRect)) + { + INT x = viewRect.left + ((viewRect.right - viewRect.left) - (optionsRect.right - optionsRect.left))/2; + INT y = viewRect.top + ((viewRect.bottom - viewRect.top) - (optionsRect.bottom - optionsRect.top))/2; + SetWindowPos(hOptions, NULL, x, y, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE); + SendMessage(hOptions, DM_REPOSITION, 0, 0L); + } + } + } + break; + } +} + +HRESULT Command_ShowBrowserOptions() +{ + HWND hWinamp = Plugin_GetWinamp(); + if (NULL == hWinamp || NULL == OMBROWSERMNGR) + return E_UNEXPECTED; + + HRESULT hr = OMBROWSERMNGR->Initialize(NULL, hWinamp); + if (SUCCEEDED(hr)) + { + HWND hOwner = Plugin_GetDialogOwner(); + hr = OMBROWSERMNGR->ShowOptions(hOwner, BOSTYLE_NORMAL | BOSTYLE_SHOWDEBUG, + BrowserOptions_Callback, (ULONG_PTR)hOwner); + } + return hr; +} + +BOOL Command_ProcessView(HWND hView, INT commandId, BOOL *fSuccess) +{ + BEGIN_COMMAND_SELECT(commandId) + OMCOMMAND(ID_NAVIGATION_HOME, Command_NavigateView(hView, NAVIGATE_HOME), fSuccess); + OMCOMMAND(ID_NAVIGATION_BACK, Command_NavigateView(hView, NAVIGATE_BACK), fSuccess); + OMCOMMAND(ID_NAVIGATION_FORWARD, Command_NavigateView(hView, NAVIGATE_FORWARD), fSuccess); + OMCOMMAND(ID_NAVIGATION_REFRESH, Command_NavigateView(hView, NAVIGATE_REFRESH), fSuccess); + OMCOMMAND(ID_NAVIGATION_STOP, Command_NavigateView(hView, NAVIGATE_STOP), fSuccess); + OMCOMMAND(ID_OMBROWSER_OPTIONS, Command_ShowBrowserOptions(), fSuccess); + OMCOMMAND(ID_SERVICE_IMPORT_FILE, Command_ImportFiles(), fSuccess); + OMCOMMAND(ID_SERVICE_IMPORT_URL, Command_ImportUrl(), fSuccess); + OMCOMMAND(ID_SERVICE_NEW, Command_CreateService(), fSuccess); + END_COMMAND_SELECT + return FALSE; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/commands.h b/Src/Plugins/Library/ml_online/commands.h new file mode 100644 index 00000000..79aec555 --- /dev/null +++ b/Src/Plugins/Library/ml_online/commands.h @@ -0,0 +1,29 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_COMMANDS_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_COMMANDS_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +class ifc_omservice; + +// returns TRUE if command was handled (fSuccess will have result code if not NULL). + +HRESULT Command_NavigateService(ifc_omservice *service, LPCWSTR pszUrl, BOOL fActiveOnly); +BOOL Command_ProcessService(HWND hView, ifc_omservice *service, INT commandId, BOOL *fSuccess); +BOOL Command_ProcessView(HWND hView, INT commandId, BOOL *fSuccess); +BOOL Command_ProcessGeneral(INT commandId, BOOL *fSuccess); + +BOOL Command_ReportService(ifc_omservice *service); +BOOL Command_UnsubscribeService(ifc_omservice *service); +BOOL Command_ShowServiceInfo(ifc_omservice *service); +BOOL Command_ResetServicePolicy(ifc_omservice *service); +BOOL Command_ResetSubscription(); +BOOL Command_SetServiceRating(ifc_omservice *service, INT rating); +HRESULT Command_CreateService(void); +BOOL Command_OpenServiceView(ifc_omservice *service); +BOOL Command_OpenServicePopup(ifc_omservice *service); + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_COMMANDS_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/common.cpp b/Src/Plugins/Library/ml_online/common.cpp new file mode 100644 index 00000000..f3d88809 --- /dev/null +++ b/Src/Plugins/Library/ml_online/common.cpp @@ -0,0 +1,374 @@ +#include "./common.h" +#include "./api__ml_online.h" +#include "./main.h" + +#include "../winamp/wa_ipc.h" + +#include <strsafe.h> + +LPWSTR Plugin_MallocString(size_t cchLen) +{ + return (LPWSTR)calloc(cchLen, sizeof(WCHAR)); +} + +void Plugin_FreeString(LPWSTR pszString) +{ + if (NULL != pszString) + { + free(pszString); + pszString = NULL; + } +} + +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); +} + +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; +} + +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)) + { + if (NULL == WASABI_API_LNG) + hr = E_FAIL; + else + WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)pszString, pszBuffer, cchBufferMax); + } + else + { + hr = StringCchCopy(pszBuffer, cchBufferMax, pszString); + } + return hr; +} + +void Plugin_SafeRelease(IUnknown *pUnk) +{ + if (NULL != pUnk) + pUnk->Release(); +} + +HRESULT Plugin_MakeResourcePath(LPWSTR pszBuffer, INT cchBufferMax, LPCWSTR pszType, LPCWSTR pszName, UINT flags) +{ + HINSTANCE hInstance = WASABI_API_LNG_HINST; + if (NULL == hInstance || NULL == FindResource(hInstance, pszName, pszType)) + hInstance = Plugin_GetInstance(); + + if (NULL == OMUTILITY) + return E_UNEXPECTED; + + return OMUTILITY->MakeResourcePath(pszBuffer, cchBufferMax, hInstance, pszType, pszName, flags); +} + +HWND Plugin_GetDialogOwner(void) +{ + HWND hOwner= Plugin_GetLibrary(); + if (NULL == hOwner || FALSE == IsWindowVisible(hOwner) || + FALSE == IsWindowEnabled(hOwner)) + { + hOwner = Plugin_GetWinamp(); + if (NULL != hOwner) + { + HWND hDlgParent = (HWND)SENDWAIPC(hOwner, IPC_GETDIALOGBOXPARENT, 0L); + if (NULL != hDlgParent) + hOwner = hDlgParent; + } + } + return hOwner; +} + +HRESULT Plugin_AppendFileFilter(LPTSTR pszBuffer, size_t cchBufferMax, LPCTSTR pName, LPCTSTR pFilter, LPTSTR *ppBufferOut, size_t *pRemaining, BOOL bShowFilter) +{ + HRESULT hr; + + LPTSTR pCursor = pszBuffer; + + if (NULL != ppBufferOut) + *ppBufferOut = pszBuffer; + + if (NULL != pRemaining) + *pRemaining = cchBufferMax; + + if (NULL == pszBuffer || NULL == pName || NULL == pFilter) + return E_INVALIDARG; + + pszBuffer[0] = TEXT('\0'); + + hr = StringCchCopyEx(pCursor, cchBufferMax, pName, &pCursor, &cchBufferMax, + STRSAFE_IGNORE_NULLS | STRSAFE_NULL_ON_FAILURE); + if (bShowFilter && SUCCEEDED(hr)) + { + LPTSTR p = pCursor; + hr = StringCchPrintfEx(pCursor, cchBufferMax, &pCursor, &cchBufferMax, + STRSAFE_IGNORE_NULLS | STRSAFE_NULL_ON_FAILURE, TEXT(" (%s)"), pFilter); + if (SUCCEEDED(hr) && p != pCursor) + CharLowerBuff(p, (INT)(INT_PTR)(pCursor - p)); + } + if (SUCCEEDED(hr)) + { + pCursor++; + cchBufferMax--; + hr = StringCchCopyEx(pCursor, cchBufferMax, pFilter, &pCursor, &cchBufferMax, + STRSAFE_IGNORE_NULLS | STRSAFE_NULL_ON_FAILURE); + } + + if (cchBufferMax < 1) + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + + pCursor++; + cchBufferMax--; + + if (SUCCEEDED(hr)) + { + pCursor[0] = TEXT('\0'); + if (NULL != ppBufferOut) + *ppBufferOut = pCursor; + if (NULL != pRemaining) + *pRemaining = cchBufferMax; + } + else + { + pszBuffer[0] = TEXT('\0'); + pszBuffer[1] = TEXT('\0'); + } + + return hr; +} + +HRESULT Plugin_BuildActionUrl(LPWSTR *ppStringOut, LPCWSTR pszAction, UINT *pServiceUid, size_t cchServiceUid) +{ + if (NULL == ppStringOut) + return E_POINTER; + + *ppStringOut = NULL; + + if (NULL == pszAction || L'\0' == *pszAction || + NULL == pServiceUid || 0 == cchServiceUid) + { + return E_INVALIDARG; + } + + const WCHAR szPrefix[] = L"http://services.winamp.com/svc/action?action=%s\0"; + const WCHAR szService[] = L"&svc_id=%u\0"; + const WCHAR szClient[] = L"&unique_id=%s\0"; + + size_t cchBuffer = ARRAYSIZE(szPrefix) + ARRAYSIZE(szService) + ARRAYSIZE(szClient); + cchBuffer += lstrlen(pszAction); + cchBuffer += (cchServiceUid * 11); + cchBuffer += 32; // unique id + + LPWSTR buffer = Plugin_MallocString(cchBuffer); + if (NULL == buffer) + return E_OUTOFMEMORY; + + HRESULT hr; + LPWSTR cursor = buffer; + size_t remaining = cchBuffer; + + + hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, + szPrefix, pszAction); + + for (size_t i = 0; i < cchServiceUid && SUCCEEDED(hr); i++) + { + hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, + ((0 == i) ? szService : L",%u"), pServiceUid[i]); + } + + if (SUCCEEDED(hr)) + { + WCHAR szTemp[128] = {0}; + hr = OMBROWSERMNGR->GetClientId(szTemp, ARRAYSIZE(szTemp)); + if (SUCCEEDED(hr)) + { + hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, szClient, szTemp); + } + } + + if (FAILED(hr)) + { + Plugin_FreeString(buffer); + hr = E_FAIL; + } + else + { + *ppStringOut = buffer; + } + return hr; +} + +INT Plugin_ParseKeywords(LPCWSTR input, INT cchInput, WCHAR separator, BOOL eatSpace, KWPARSERPROC callback, ULONG_PTR user) +{ + if (NULL == input) + return 0; + + if (cchInput < 0) + cchInput = lstrlen(input); + + if (cchInput <= 0) + return 0; + + LPCWSTR end = (input + cchInput); + + if(eatSpace) + while(input < end && L' ' == *input) input++; + + if (L'\0' == *input) + return 0; + + INT found = 0; + + for (;;) + { + LPCWSTR pBlock = input; + while(input <= end && separator != *input) input++; + LPCWSTR last = (input - 1); + if (eatSpace) + while(last >= pBlock && L' ' == *last) last--; + + if (last >= pBlock) + { + UINT code = callback(pBlock, (INT)(INT_PTR)(last - pBlock) + 1, user); + if (KWPARSER_FOUND & code) found++; + if (KWPARSER_ABORT == (0x01 & code)) + return found; + } + + if (input >= end || L'\0' == *input) + return found; + + input++; + if(eatSpace) + while(input < end && L' ' == *input) input++; + } + + return found; +} + +INT Plugin_MessageBox(LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) +{ + HWND hHost, hLibrary = Plugin_GetLibrary(); + if (NULL != hLibrary && FALSE != IsWindowVisible(hLibrary)) + { + hHost = (HWND)SENDMLIPC(hLibrary, ML_IPC_GETCURRENTVIEW, 0); + if (NULL == hHost || FALSE == IsWindowVisible(hHost)) + hHost = hLibrary; + } + else + hHost = Plugin_GetDialogOwner(); + + if(IS_INTRESOURCE(lpText) && NULL != lpText) + { + WCHAR szText[2048] = {0}; + lpText = WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)lpText, szText, ARRAYSIZE(szText)); + } + + if(IS_INTRESOURCE(lpCaption) && NULL != lpCaption) + { + WCHAR szCaption[128] = {0}; + lpCaption = WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)lpCaption, szCaption, ARRAYSIZE(szCaption)); + } + + return MessageBox(hHost, lpText, lpCaption, uType); +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/common.h b/Src/Plugins/Library/ml_online/common.h new file mode 100644 index 00000000..7fe1f7a3 --- /dev/null +++ b/Src/Plugins/Library/ml_online/common.h @@ -0,0 +1,81 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_COMMON_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_COMMON_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#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 + +#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 + +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); + +void Plugin_SafeRelease(IUnknown *pUnk); +HRESULT Plugin_MakeResourcePath(LPWSTR pszBuffer, INT cchBufferMax, LPCWSTR pszType, LPCWSTR pszName, UINT uFlags); + +HWND Plugin_GetDialogOwner(void); +HRESULT Plugin_AppendFileFilter(LPTSTR pszBuffer, size_t cchBufferMax, LPCTSTR pName, LPCTSTR pFilter, LPTSTR *ppBufferOut, size_t *pRemaining, BOOL bShowFilter); + + +HRESULT Plugin_BuildActionUrl(LPWSTR *ppStringOut, LPCWSTR pszAction, UINT *pServiceUid, size_t cchServiceUid); + +#define KWPARSER_ABORT ((UINT)0x00000000) +#define KWPARSER_CONTINUE ((UINT)0x00000001) +#define KWPARSER_FOUND ((UINT)0x80000000) // this is additional modifier + +typedef UINT (CALLBACK *KWPARSERPROC)(LPCWSTR /*pszKeyword*/, INT /*cchKeyword*/, ULONG_PTR /*user*/); + +INT Plugin_ParseKeywords(LPCWSTR input, INT cchInput, WCHAR separator, BOOL eatSpace, KWPARSERPROC callback, ULONG_PTR user); + +INT Plugin_MessageBox(LPCTSTR lpText, LPCTSTR lpCaption, UINT uType); + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_COMMON_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/config.cpp b/Src/Plugins/Library/ml_online/config.cpp new file mode 100644 index 00000000..c6e87cb2 --- /dev/null +++ b/Src/Plugins/Library/ml_online/config.cpp @@ -0,0 +1,304 @@ +#include "main.h" +#include "./config.h" +#include "./api__ml_online.h" + +#include <shlwapi.h> +#include <strsafe.h> + +#define CONFIG_SUFFIX L"Plugins\\ml" +#define CONFIG_SECTION "ml_online_config" + +void C_Config::Flush(void) +{ +#ifndef C_CONFIG_WIN32NATIVE + if (!m_dirty) return; + FILE *fp=fopen(m_inifile,"wt"); + if (!fp) return; + + fprintf(fp,"[ml_online_config]\n"); + int x; + if (m_strs) + { + for (x = 0; x < m_num_strs; x ++) + { + char name[17] = {0}; + memcpy(name,m_strs[x].name,16); + name[16]=0; + if (m_strs[x].value) fprintf(fp,"%s=%s\n",name,m_strs[x].value); + } + } + fclose(fp); + m_dirty=0; +#endif +} + +C_Config::~C_Config() +{ +#ifndef C_CONFIG_WIN32NATIVE + int x; + Flush(); + if (m_strs) for (x = 0; x < m_num_strs; x ++) free(m_strs[x].value); + free(m_strs); +#endif + + Plugin_FreeAnsiString(m_inifile); +} + +C_Config::C_Config(char *ini) +{ + memset(m_strbuf,0,sizeof(m_strbuf)); + m_inifile= Plugin_CopyAnsiString(ini); + +#ifndef C_CONFIG_WIN32NATIVE + m_dirty=0; + m_strs=NULL; + m_num_strs=m_num_strs_alloc=0; + + // read config + FILE *fp=fopen(m_inifile,"rt"); + if (!fp) return; + + for (;;) + { + char buf[4096] = {0}; + fgets(buf,sizeof(buf),fp); + if (!buf[0] || feof(fp)) break; + for (;;) + { + int l=strlen(buf); + if (l > 0 && (buf[l-1] == '\n' || buf[l-1] == '\r')) buf[l-1]=0; + else break; + } + if (buf[0] != '[') + { + char *p=strstr(buf,"="); + if (p) + { + *p++=0; + WriteString(buf,p); + } + } + } + m_dirty=0; + fclose(fp); +#endif +} + +void C_Config::WriteInt(char *name, int value) +{ + char buf[32] = {0}; + StringCchPrintfA(buf, ARRAYSIZE(buf), "%d",value); + WriteString(name,buf); +} + +int C_Config::ReadInt(char *name, int defvalue) +{ +#ifndef C_CONFIG_WIN32NATIVE + char *t=ReadString(name,""); + if (*t) return atoi(t); + return defvalue; +#else + return GetPrivateProfileIntA("ml_online_config",name,defvalue,m_inifile); +#endif +} + +char *C_Config::WriteString(char *name, char *string) +{ +#ifndef C_CONFIG_WIN32NATIVE + m_dirty=1; + for (int x = 0; x < m_num_strs; x ++) + { + if (m_strs[x].value && !strncmp(name,m_strs[x].name,16)) + { + unsigned int l=(strlen(m_strs[x].value)+16)&~15; + if (strlen(string)<l) + { + strcpy(m_strs[x].value,string); + } + else + { + free(m_strs[x].value); + m_strs[x].value = (char *)malloc((strlen(string)+16)&~15); + strcpy(m_strs[x].value,string); + } + return m_strs[x].value; + } + } + + // not already in there + if (m_num_strs >= m_num_strs_alloc || !m_strs) + { + m_old_num_strs_alloc = m_num_strs_alloc; + m_num_strs_alloc=m_num_strs*3/2+8; + strType *data = (strType*)::realloc(m_strs, sizeof(strType) * m_num_strs_alloc); + if (data) + { + m_strs = data; + } + else + { + data = (strType*)::malloc(sizeof(strType) * m_num_strs_alloc); + if (data) + { + memcpy(data, m_strs, sizeof(strType) * m_old_num_strs_alloc); + free(m_strs); + m_strs = data; + } + else m_num_strs_alloc = m_old_num_strs_alloc; + } + } + strncpy(m_strs[m_num_strs].name,name,16); + m_strs[m_num_strs].value = (char *)malloc((strlen(string)+16)&~15); + if (m_strs[m_num_strs].value) + { + strcpy(m_strs[m_num_strs].value,string); + return m_strs[m_num_strs++].value; + } + return ""; +#else + WritePrivateProfileStringA("ml_online_config",name,string,m_inifile); + return name; +#endif +} + +char *C_Config::ReadString( char *name, char *defstr ) +{ +#ifndef C_CONFIG_WIN32NATIVE + int x; + for ( x = 0; x < m_num_strs; x++ ) + { + if ( m_strs[ x ].value && !::strncmp( name, m_strs[ x ].name, 16 ) ) + { + return m_strs[ x ].value; + } + } + return defstr; +#else + static char foobuf[] = "___________ml_online_lameness___________"; + m_strbuf[ 0 ] = 0; + GetPrivateProfileStringA( "ml_online_config", name, foobuf, m_strbuf, sizeof( m_strbuf ), m_inifile ); + if ( !strcmp( foobuf, m_strbuf ) || !strcmp( m_strbuf, "" ) ) + { + return defstr; + } + + m_strbuf[ sizeof( m_strbuf ) - 1 ] = 0; + return m_strbuf; +#endif +} + +static LPCSTR Config_GetPath() +{ + static LPSTR configPath = NULL; + if (NULL == configPath) + { + LPCWSTR p = (NULL != WASABI_API_APP) ? WASABI_API_APP->path_getUserSettingsPath() : NULL; + if (NULL != p) + { + WCHAR szBuffer[MAX_PATH * 2] = {0}; + if (0 != PathCombine(szBuffer, p, CONFIG_SUFFIX)) + { + OMUTILITY->EnsurePathExist(szBuffer); + PathAppend(szBuffer, L"ml_online.ini"); + configPath = Plugin_WideCharToMultiByte(CP_UTF8, 0, szBuffer, -1, NULL, NULL); + } + } + } + + return configPath; +} + +DWORD Config_ReadStr(LPCSTR lpSectionName, LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString, DWORD nSize) +{ + if (NULL == lpSectionName) lpSectionName = CONFIG_SECTION; + return GetPrivateProfileStringA(lpSectionName, lpKeyName, lpDefault, lpReturnedString, nSize, Config_GetPath()); +} + +UINT Config_ReadInt(LPCSTR lpSectionName, LPCSTR lpKeyName, INT nDefault) +{ + if (NULL == lpSectionName) lpSectionName = CONFIG_SECTION; + return GetPrivateProfileIntA(lpSectionName, lpKeyName, nDefault, Config_GetPath()); +} + +HRESULT Config_WriteStr(LPCSTR lpSectionName, LPCSTR lpKeyName, LPCSTR lpString) +{ + LPCSTR configPath = Config_GetPath(); + if (NULL == configPath || '\0' == *configPath) + return E_UNEXPECTED; + + if (NULL == lpSectionName) lpSectionName = CONFIG_SECTION; + if (0 != WritePrivateProfileStringA(lpSectionName, lpKeyName, lpString, configPath)) + return S_OK; + + DWORD errorCode = GetLastError(); + return HRESULT_FROM_WIN32(errorCode); +} + +HRESULT Config_WriteInt(LPCSTR lpSectionName, LPCSTR lpKeyName, INT nValue) +{ + char szBuffer[32] = {0}; + HRESULT hr = StringCchPrintfA(szBuffer, ARRAYSIZE(szBuffer), "%d", nValue); + if (FAILED(hr)) return hr; + + if (NULL == lpSectionName) lpSectionName = CONFIG_SECTION; + return Config_WriteStr(lpSectionName, lpKeyName, szBuffer); +} + +HRESULT Config_WriteSection(LPCSTR lpSectionName, LPCSTR lpData) +{ + LPCSTR configPath = Config_GetPath(); + if (NULL == configPath || '\0' == *configPath) + return E_UNEXPECTED; + + if (NULL == lpSectionName) lpSectionName = CONFIG_SECTION; + if (0 == WritePrivateProfileSectionA(lpSectionName, lpData, configPath)) + return S_OK; + + DWORD errorCode = GetLastError(); + return HRESULT_FROM_WIN32(errorCode); +} + +HRESULT Config_ReadServiceIdList(LPCSTR lpSectionName, LPCSTR lpKeyName, CHAR separator, ReadServiceIdCallback callback, void *data) +{ + if (NULL == callback) + return E_INVALIDARG; + + DWORD bufferSize = 16384; + LPSTR buffer = Plugin_MallocAnsiString(bufferSize); + if (NULL == buffer) return E_OUTOFMEMORY; + + DWORD bufferLen = Config_ReadStr(lpSectionName, lpKeyName, NULL, buffer, bufferSize); + if (0 != bufferLen) + { + LPSTR cursor = buffer; + LPSTR block = cursor; + UINT serviceId; + for(;;) + { + if (separator == *cursor || '\0' == *cursor) + { + while (' ' == *block && block < cursor) block++; + + if (block < cursor && + FALSE != StrToIntExA(block, STIF_SUPPORT_HEX, (INT*)&serviceId) && + 0 != serviceId) + { + + if (FALSE == callback(serviceId, data)) + break; + } + + if ('\0' == *cursor) + break; + + cursor = CharNextA(cursor); + block = cursor; + } + else + cursor = CharNextA(cursor); + } + } + + Plugin_FreeAnsiString(buffer); + return S_OK; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/config.h b/Src/Plugins/Library/ml_online/config.h new file mode 100644 index 00000000..a4e3f034 --- /dev/null +++ b/Src/Plugins/Library/ml_online/config.h @@ -0,0 +1,54 @@ +#ifndef NULLSOFT_ONLINEMEDIA_PLUGIN_CONFIG_HEADER +#define NULLSOFT_ONLINEMEDIA_PLUGIN_CONFIG_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + + +#define C_CONFIG_WIN32NATIVE +class C_Config +{ + public: + C_Config(char *ini); + ~C_Config(); + void Flush(void); + void WriteInt(char *name, int value); + char *WriteString(char *name, char *string); + int ReadInt(char *name, int defvalue); + char *ReadString(char *name, char *defvalue); + + const char* GetPath() { return m_inifile; } + + private: +#ifndef C_CONFIG_WIN32NATIVE + typedef struct + { + char name[16]; + char *value; + } strType; + + strType *m_strs; + int m_dirty; + int m_num_strs, m_num_strs_alloc; +#else + char m_strbuf[8192]; +#endif + + char *m_inifile; +}; + +// set lpSectionName = NULL to write to default section; +DWORD Config_ReadStr(LPCSTR lpSectionName, LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString, DWORD nSize); +UINT Config_ReadInt(LPCSTR lpSectionName, LPCSTR lpKeyName, INT nDefault); +HRESULT Config_WriteStr(LPCSTR lpSectionName, LPCSTR lpKeyName, LPCSTR lpString); +HRESULT Config_WriteInt(LPCSTR lpSectionName, LPCSTR lpKeyName, INT nValue); +HRESULT Config_WriteSection(LPCSTR lpSectionName, LPCSTR lpData); + +typedef BOOL (CALLBACK *ReadServiceIdCallback)(UINT /*serviceId*/, void* /*data*/); +HRESULT Config_ReadServiceIdList(LPCSTR lpSectionName, LPCSTR lpKeyName, CHAR separator, ReadServiceIdCallback callback, void *data); + + +#endif //NULLSOFT_ONLINEMEDIA_PLUGIN_CONFIG_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/external.cpp b/Src/Plugins/Library/ml_online/external.cpp new file mode 100644 index 00000000..4fcbfb4d --- /dev/null +++ b/Src/Plugins/Library/ml_online/external.cpp @@ -0,0 +1,273 @@ +#include "main.h" +#include "./resource.h" +#include "./external.h" +#include "./navigation.h" +#include "./commands.h" + +#include "../winamp/jsapi.h" +#include "../winamp/jsapi_CallbackParameters.h" + +#include "./serviceHost.h" +#include "./serviceHelper.h" + +#include <browserView.h> +#include <ifc_omservice.h> +#include <ifc_omserviceeditor.h> + +#define DISPTABLE_CLASS ExternalDispatch + +DISPTABLE_BEGIN() + DISPENTRY_ADD(DISPATCH_SERVICE_OPEN, L"serviceOpen", OnServiceOpen) + DISPENTRY_ADD(DISPATCH_SERVICE_CREATE, L"serviceCreate", OnServiceCreate) + DISPENTRY_ADD(DISPATCH_SERVICE_GETINFO, L"serviceGetInfo", OnServiceGetInfo) + DISPENTRY_ADD(DISPATCH_SERVICE_SETINFO, L"serviceSetInfo", OnServiceSetInfo) +DISPTABLE_END + +#undef DISPTABLE_CLASS + + +static BOOL DispParam_GetStringOpt(LPCWSTR *str, DISPPARAMS *paramInfo, UINT paramNumber, UINT *argErr) +{ + if (paramInfo->cArgs < paramNumber || + VT_NULL == paramInfo->rgvarg[paramInfo->cArgs - paramNumber].vt) + { + *str = NULL; + return FALSE; + } + + JSAPI_GETSTRING((*str), paramInfo, paramNumber, argErr); + return TRUE; +} + +ExternalDispatch::ExternalDispatch() + : ref(1) +{ +} + +ExternalDispatch::~ExternalDispatch() +{ +} + +HRESULT ExternalDispatch::CreateInstance(ExternalDispatch **instance) +{ + if (NULL == instance) return E_POINTER; + + *instance = new ExternalDispatch(); + if (NULL == *instance) return E_OUTOFMEMORY; + + return S_OK; +} + +LPCWSTR ExternalDispatch::GetName() +{ + return L"WebDev"; +} + +ULONG ExternalDispatch::AddRef(void) +{ + return InterlockedIncrement((LONG*)&ref); +} + + +ULONG ExternalDispatch::Release(void) +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +STDMETHODIMP ExternalDispatch::QueryInterface(REFIID riid, void **ppvObject) +{ + if (NULL == ppvObject) return E_POINTER; + + if (IsEqualIID(riid, IID_IDispatch)) + *ppvObject = static_cast<IDispatch*>(this); + else if (IsEqualIID(riid, IID_IUnknown)) + *ppvObject = static_cast<IUnknown*>(this); + else + { + *ppvObject = NULL; + return E_NOINTERFACE; + } + + AddRef(); + return S_OK; +} + +HRESULT ExternalDispatch::OnServiceOpen(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + JSAPI_VERIFY_METHOD(wFlags); + JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 1, 2); + + JSAPI_INIT_RESULT(pvarResult, VT_BOOL); + + UINT serviceId; + JSAPI_GETUNSIGNED_AS_NUMBER(serviceId, pdispparams, 1, puArgErr); + + LPCWSTR forceUrl = NULL; + if (pdispparams->cArgs > 1) + { + switch(pdispparams->rgvarg[0].vt) + { + case VT_BSTR: forceUrl = pdispparams->rgvarg[0].bstrVal; break; + case VT_I4: forceUrl = MAKEINTRESOURCE(pdispparams->rgvarg[0].lVal); break; + } + } + + if (FALSE == DispParam_GetStringOpt(&forceUrl, pdispparams,2, puArgErr)) + forceUrl = NULL; + + HRESULT hr; + + Navigation *navigation; + hr = Plugin_GetNavigation(&navigation); + if (SUCCEEDED(hr)) + { + ifc_omservice *service; + if (NULL != navigation->FindService(serviceId, &service)) + { + hr = Command_NavigateService(service, forceUrl, FALSE); + service->Release(); + } + else + { + hr = E_FAIL; + } + navigation->Release(); + } + + JSAPI_SET_RESULT(pvarResult, boolVal, (SUCCEEDED(hr) ? VARIANT_TRUE : VARIANT_FALSE)); + + return S_OK; +} + +HRESULT ExternalDispatch::OnServiceCreate(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + JSAPI_VERIFY_METHOD(wFlags); + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0); + + HRESULT hr = Command_CreateService(); + + JSAPI_INIT_RESULT(pvarResult, VT_BOOL); + JSAPI_SET_RESULT(pvarResult, boolVal, (SUCCEEDED(hr) ? VARIANT_TRUE : VARIANT_FALSE)); + + return S_OK; +} + +HRESULT ExternalDispatch::OnServiceGetInfo(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + JSAPI_VERIFY_METHOD(wFlags); + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1); + + JSAPI_INIT_RESULT(pvarResult, VT_DISPATCH); + + UINT serviceId; + JSAPI_GETUNSIGNED_AS_NUMBER(serviceId, pdispparams, 1, puArgErr); + + Navigation *navigation; + HRESULT hr = Plugin_GetNavigation(&navigation); + if (SUCCEEDED(hr)) + { + ifc_omservice *service; + if (NULL != navigation->FindService(serviceId, &service)) + { + WCHAR szBuffer[2048]; + JSAPI::CallbackParameters *params = new JSAPI::CallbackParameters; + params->AddLong(L"id", service->GetId()); + + if (FAILED(service->GetName(szBuffer, ARRAYSIZE(szBuffer)))) szBuffer[0] = L'\0'; + params->AddString(L"name", szBuffer); + + if (FAILED(service->GetUrl(szBuffer, ARRAYSIZE(szBuffer)))) szBuffer[0] = L'\0'; + params->AddString(L"url", szBuffer); + + if (FAILED(service->GetIcon(szBuffer, ARRAYSIZE(szBuffer)))) szBuffer[0] = L'\0'; + params->AddString(L"icon", szBuffer); + + params->AddBoolean(L"preauthorized", (S_OK == ServiceHelper_IsPreAuthorized(service))); + + service->Release(); + V_DISPATCH(pvarResult) = params; + } + else + { + hr = E_FAIL; + } + navigation->Release(); + } + + if (FAILED(hr)) + { + V_DISPATCH(pvarResult) = 0; + } + + return S_OK; +} + +HRESULT ExternalDispatch::OnServiceSetInfo(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + JSAPI_VERIFY_METHOD(wFlags); + JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 2, 5); + + UINT serviceId; + JSAPI_GETUNSIGNED_AS_NUMBER(serviceId, pdispparams, 1, puArgErr); + + Navigation *navigation; + HRESULT hr = Plugin_GetNavigation(&navigation); + if (SUCCEEDED(hr)) + { + ifc_omservice *service; + HNAVITEM hItem = navigation->FindService(serviceId, &service); + if (NULL != hItem) + { + ifc_omserviceeditor *editor; + hr = service->QueryInterface(IFC_OmServiceEditor, (void**)&editor); + if (SUCCEEDED(hr)) + { + LPCWSTR value = NULL; + + editor->BeginUpdate(); + + if (FALSE != DispParam_GetStringOpt(&value, pdispparams, 2, puArgErr) && FAILED(editor->SetName(value, FALSE))) + hr = E_FAIL; + + if (FALSE != DispParam_GetStringOpt(&value, pdispparams, 3, puArgErr) && FAILED(ServiceHelper_UpdateIcon(editor, value))) + hr = E_FAIL; + + if (FALSE != DispParam_GetStringOpt(&value, pdispparams, 4, puArgErr) && FAILED(editor->SetUrl(value, FALSE))) + hr = E_FAIL; + + VARIANT_BOOL authorized = JSAPI_PARAM_OPTIONAL(pdispparams, 5, boolVal, VARIANT_FALSE); + if (S_OK == editor->SetFlags((VARIANT_TRUE == authorized) ? SVCF_PREAUTHORIZED : 0, SVCF_PREAUTHORIZED)) + { + if (VARIANT_TRUE == authorized) + ServiceHelper_ResetPermissions(service, 0); + } + + editor->EndUpdate(); + editor->Release(); + } + + if(SUCCEEDED(hr)) + hr = ServiceHelper_Save(service); + + service->Release(); + } + else + { + hr = E_FAIL; + } + + navigation->Release(); + } + + JSAPI_INIT_RESULT(pvarResult, VT_BOOL); + JSAPI_SET_RESULT(pvarResult, boolVal, (SUCCEEDED(hr) ? VARIANT_TRUE : VARIANT_FALSE)); + + return S_OK; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/external.h b/Src/Plugins/Library/ml_online/external.h new file mode 100644 index 00000000..e3dfe6ca --- /dev/null +++ b/Src/Plugins/Library/ml_online/external.h @@ -0,0 +1,49 @@ +#ifndef NULLSOFT_WEBDEV_PLUGIN_EXTERNAL_HEADER +#define NULLSOFT_WEBDEV_PLUGIN_EXTERNAL_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "../nu/dispatchTable.h" + +class ExternalDispatch : public IDispatch +{ + +public: + typedef enum + { + DISPATCH_SERVICE_OPEN = 700, + DISPATCH_SERVICE_CREATE = 701, + DISPATCH_SERVICE_GETINFO = 702, + DISPATCH_SERVICE_SETINFO = 703, + } DispatchCodes; + +protected: + ExternalDispatch(); + ~ExternalDispatch(); + +public: + static HRESULT CreateInstance(ExternalDispatch **instance); + static LPCWSTR GetName(); + +public: + STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject); + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + +protected: + DISPTABLE_INCLUDE(); + DISPHANDLER_REGISTER(OnServiceOpen); + DISPHANDLER_REGISTER(OnServiceCreate); + DISPHANDLER_REGISTER(OnServiceGetInfo); + DISPHANDLER_REGISTER(OnServiceSetInfo); + +protected: + ULONG ref; + +}; + + +#endif //NULLSOFT_WEBDEV_PLUGIN_EXTERNAL_HEADER diff --git a/Src/Plugins/Library/ml_online/forceUrl.cpp b/Src/Plugins/Library/ml_online/forceUrl.cpp new file mode 100644 index 00000000..3ad4a1e9 --- /dev/null +++ b/Src/Plugins/Library/ml_online/forceUrl.cpp @@ -0,0 +1,51 @@ +#include "main.h" +#include "./forceUrl.h" + +ForceUrl::ForceUrl() : id((UINT)-1), url(NULL) +{ +} +ForceUrl::~ForceUrl() +{ + Plugin_FreeString(url); +} + +HRESULT ForceUrl::Set(UINT serviceId, LPCWSTR pszUrl) +{ + Plugin_FreeString(url); + + id = serviceId; + url = Plugin_CopyString(pszUrl); + + return S_OK; +} + +HRESULT ForceUrl::Peek(UINT serviceId, LPWSTR *pszUrl) +{ + if (NULL == pszUrl) return E_POINTER; + if (serviceId == id && NULL != url) + { + *pszUrl = url; + url = NULL; + id = ((UINT)-1); + return S_OK; + } + + return S_FALSE; +} + +HRESULT ForceUrl::Remove(UINT serviceId) +{ + if (id == serviceId) + { + Plugin_FreeString(url); + url = NULL; + id = ((UINT)-1); + return S_OK; + } + return S_FALSE; +} + +void ForceUrl::FreeString(LPWSTR pszValue) +{ + Plugin_FreeString(pszValue); +} diff --git a/Src/Plugins/Library/ml_online/forceUrl.h b/Src/Plugins/Library/ml_online/forceUrl.h new file mode 100644 index 00000000..28a3f863 --- /dev/null +++ b/Src/Plugins/Library/ml_online/forceUrl.h @@ -0,0 +1,27 @@ +#ifndef NULLOSFT_ONLINEMEDIA_FORCE_URL_HEADER +#define NULLOSFT_ONLINEMEDIA_FORCE_URL_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +class ForceUrl +{ +public: + ForceUrl(); + ~ForceUrl(); + +public: + HRESULT Set(UINT serviceId, LPCWSTR pszUrl); + HRESULT Peek(UINT serviceId, LPWSTR *pszUrl); + HRESULT Remove(UINT serviceId); + + void FreeString(LPWSTR pszValue); +private: + UINT id; + LPWSTR url; +}; + +#endif //NULLOSFT_ONLINEMEDIA_FORCE_URL_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/handler.cpp b/Src/Plugins/Library/ml_online/handler.cpp new file mode 100644 index 00000000..2191725e --- /dev/null +++ b/Src/Plugins/Library/ml_online/handler.cpp @@ -0,0 +1,168 @@ +#include "main.h" +#include "navigation.h" +#include "servicehelper.h" +#include "handler.h" +#include "ifc_omservice.h" +#include "../Agave/URIHandler/svc_urihandler.h" +#include <api/service/waservicefactory.h> +#include "api.h" + +#include <shlwapi.h> + +static uint8_t quickhex(wchar_t c) +{ + int hexvalue = c; + if (hexvalue & 0x10) + hexvalue &= ~0x30; + else + { + hexvalue &= 0xF; + hexvalue += 9; + } + return hexvalue; +} + +static uint8_t DecodeEscape(const wchar_t *&str) +{ + uint8_t a = quickhex(*++str); + uint8_t b = quickhex(*++str); + str++; + return a * 16 + b; +} + +static void DecodeEscapedUTF8(wchar_t *&output, const wchar_t *&input) +{ + uint8_t utf8_data[1024] = {0}; // hopefully big enough!! + int num_utf8_words=0; + bool error=false; + + while (input && *input == '%' && num_utf8_words < sizeof(utf8_data)) + { + if (iswxdigit(input[1]) && iswxdigit(input[2])) + { + utf8_data[num_utf8_words++]=DecodeEscape(input); + } + else if (input[1] == '%') + { + input+=2; + utf8_data[num_utf8_words++]='%'; + } + else + { + error = true; + break; + } + } + + int len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)utf8_data, num_utf8_words, 0, 0); + MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)utf8_data, num_utf8_words, output, len); + output += len; + + if (error) + { + *output++ = *input++; + } +} + +static void UrlDecode(const wchar_t *input, wchar_t *output, size_t len) +{ + const wchar_t *stop = output+len-4; // give ourself a cushion large enough to hold a full UTF-16 sequence + const wchar_t *itr = input; + while (itr && *itr) + { + if (output >= stop) + { + *output=0; + return; + } + + switch (*itr) + { + case '%': + DecodeEscapedUTF8(output, itr); + break; + case '&': + *output = 0; + return; + default: + *output++ = *itr++; + break; + } + } + *output = 0; +} +// first parameter has param name either null or = terminated, second is null terminated +static bool ParamCompare(const wchar_t *url_param, const wchar_t *param_name) +{ + while (url_param && *url_param && *param_name && *url_param!=L'=') + { + if (*url_param++ != *param_name++) + return false; + } + return true; +} + +static bool get_request_parm(const wchar_t *params, const wchar_t *param_name, wchar_t *value, size_t value_len) +{ + const wchar_t *t=params; + while (t && *t && *t != L'?') // find start of parameters + t++; + + while (t && *t) + { + t++; // skip ? or & + if (ParamCompare(t, param_name)) + { + while (t && *t && *t != L'=' && *t != '&') // find start of value + t++; + switch(*t) + { + case L'=': + UrlDecode(++t, value, value_len); + return true; + case 0: + case L'&': // no value + *value=0; + return true; + default: // shouldn't get here + return false; + } + } + while (t && *t && *t != L'&') // find next parameter + t++; + } + return false; +} + +int OnlineServicesURIHandler::ProcessFilename(const wchar_t *filename) +{ + if (HANDLED != IsMine(filename)) + return NOT_HANDLED; + + UINT serviceId = 0; + wchar_t szBuffer[512]=L""; + if (get_request_parm(filename, L"id", szBuffer, ARRAYSIZE(szBuffer)) && + L'\0' != szBuffer[0]) + { + if (FALSE == StrToIntEx(szBuffer, STIF_SUPPORT_HEX, (INT*)&serviceId)) + serviceId = 0; + } + + ServiceHelper_ShowService(serviceId, SHOWMODE_ENSUREVISIBLE); + return HANDLED_EXCLUSIVE; +} + +int OnlineServicesURIHandler::IsMine(const wchar_t *filename) +{ + if (!_wcsnicmp(filename, L"winamp://Online Services", 24) || !_wcsnicmp(filename, L"winamp://Online%20Services", 26)) + return HANDLED; + else + return NOT_HANDLED; +} + +#define CBCLASS OnlineServicesURIHandler +START_DISPATCH; +CB(PROCESSFILENAME, ProcessFilename); +CB(ISMINE, IsMine); +END_DISPATCH; +#undef CBCLASS
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/handler.h b/Src/Plugins/Library/ml_online/handler.h new file mode 100644 index 00000000..a228a396 --- /dev/null +++ b/Src/Plugins/Library/ml_online/handler.h @@ -0,0 +1,20 @@ +#pragma once + +#include "../Agave/URIHandler/svc_urihandler.h" + +// {1E8830FA-0BDA-45fa-B106-BDF56C93BADD} +static const GUID ml_online_uri_handler = +{ 0x1e8830fa, 0xbda, 0x45fa, { 0xb1, 0x6, 0xbd, 0xf5, 0x6c, 0x93, 0xba, 0xdd } }; + + +class OnlineServicesURIHandler : public svc_urihandler +{ +public: + static const char *getServiceName() { return "Online Services URI Handler"; } + static GUID getServiceGuid() { return ml_online_uri_handler; } + int ProcessFilename(const wchar_t *filename); + int IsMine(const wchar_t *filename); // just like ProcessFilename but don't actually process + +protected: + RECVS_DISPATCH; +};
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/import.h b/Src/Plugins/Library/ml_online/import.h new file mode 100644 index 00000000..b1c079c7 --- /dev/null +++ b/Src/Plugins/Library/ml_online/import.h @@ -0,0 +1,18 @@ +#ifndef NULLSOFT_WEBDEV_PLUGIN_IMPORT_HEADER +#define NULLSOFT_WEBDEV_PLUGIN_IMPORT_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +HRESULT ImportService_GetFileSupported(); +HRESULT ImportService_GetUrlSupported(); + +HRESULT ImportService_FromFile(HWND hOwner); +HRESULT ImportService_FromUrl(HWND hOwner); + +void ImportService_SaveRecentUrl(); + +#endif //NULLSOFT_WEBDEV_PLUGIN_IMPORT_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/importFile.cpp b/Src/Plugins/Library/ml_online/importFile.cpp new file mode 100644 index 00000000..d186306d --- /dev/null +++ b/Src/Plugins/Library/ml_online/importFile.cpp @@ -0,0 +1,265 @@ +#include "main.h" +#include "./import.h" +#include "./api__ml_online.h" +#include "./resource.h" +#include "./serviceHost.h" +#include "./serviceHelper.h" +#include "./navigation.h" + +#include <ifc_omstorage.h> +#include <ifc_omfilestorage.h> +#include <ifc_omstorageenum.h> +#include <ifc_omservice.h> +#include <ifc_omserviceenum.h> + +#include <strsafe.h> + +static HRESULT ImportFile_GetEnumerator(ifc_omstorageenumerator **enumerator) +{ + if (NULL == OMSERVICEMNGR) return E_UNEXPECTED; + return OMSERVICEMNGR->EnumStorage(&STID_OmFileStorage, ifc_omstorage::capPublic | ifc_omstorage::capLoad, enumerator); +} + +HRESULT ImportService_GetFileSupported() +{ + if (NULL == OMSERVICEMNGR) + return E_UNEXPECTED; + + ifc_omstorageenumerator *enumerator; + HRESULT hr = ImportFile_GetEnumerator(&enumerator); + + if (SUCCEEDED(hr)) + { + ifc_omstorage *storage; + if(S_OK == enumerator->Next(1, &storage, NULL)) + { + storage->Release(); + hr = S_OK; + } + else + { + hr = S_FALSE; + } + + enumerator->Release(); + } + return hr; +} + +static HRESULT ImportFile_GetFilter(LPWSTR pszBuffer, UINT cchBufferMax, DWORD *defaultIndex) +{ + if (NULL != defaultIndex) + *defaultIndex = 0; + + if (NULL == pszBuffer) + return E_POINTER; + + HRESULT hr; + WCHAR szName[128] = {0}, szList[512] = {0}; + + LPWSTR cursor = pszBuffer; + size_t remaining = cchBufferMax; + + LPWSTR listC = szList; + size_t listR = ARRAYSIZE(szList); + + DWORD counter = 0; + + szList[0] = L'\0'; + pszBuffer[0] = L'\0'; + + WASABI_API_LNGSTRINGW_BUF(IDS_FILEFILTER_ALL, szName, ARRAYSIZE(szName)); + hr = Plugin_AppendFileFilter(cursor, remaining, szName, L"*.*", &cursor, &remaining, TRUE); + if (FAILED(hr)) return hr; + counter++; + + ifc_omstorageenumerator *enumerator; + hr = ImportFile_GetEnumerator(&enumerator); + if (SUCCEEDED(hr)) + { + ifc_omstorage *storage; + ifc_omfilestorage *fileStorage; + while(S_OK == enumerator->Next(1, &storage, NULL)) + { + if (SUCCEEDED(storage->QueryInterface(IFC_OmFileStorage, (void**)&fileStorage))) + { + WCHAR szFilter[64] = {0}; + if (SUCCEEDED(fileStorage->GetFilter(szFilter, ARRAYSIZE(szFilter))) && + L'\0' != szFilter[0] && + SUCCEEDED(storage->GetDescription(szName, ARRAYSIZE(szName)))) + { + hr = Plugin_AppendFileFilter(cursor, remaining, szName, szFilter, &cursor, &remaining, TRUE); + if (FAILED(hr)) break; + + counter++; + + if (listC == szList || SUCCEEDED(StringCchCopyEx(listC, listR, L";", &listC, &listR, 0))) + StringCchCopyEx(listC, listR, szFilter, &listC, &listR, 0); + } + fileStorage->Release(); + } + storage->Release(); + } + enumerator->Release(); + } + + if (SUCCEEDED(hr) && L'\0' != szList[0]) + { + WASABI_API_LNGSTRINGW_BUF(IDS_FILEFILTER_ALLKNOWN, szName, ARRAYSIZE(szName)); + hr = Plugin_AppendFileFilter(cursor, remaining, szName, szList, &cursor, &remaining, TRUE); + if (FAILED(hr)) return hr; + + counter++; + + if (NULL != defaultIndex) + *defaultIndex = counter; + } + + return hr; +} + +static HRESULT ImportFile_ProcessFile(HWND hOwner, ifc_omstorageenumerator *enumerator, + ifc_omservicehost *serviceHost, ifc_omstorage *serviceStorage, + LPCWSTR pszFile, ULONG *converted) +{ + ifc_omstorage *storage; + enumerator->Reset(); + + Navigation *navigation; + if (FAILED(Plugin_GetNavigation(&navigation))) + return E_FAIL; + + ULONG loaded(0), saved(0); + while(S_OK == enumerator->Next(1, &storage, NULL)) + { + ifc_omserviceenum *serviceEnum; + HRESULT hr = storage->Load(pszFile, serviceHost, &serviceEnum); + if(SUCCEEDED(hr)) + { + ifc_omservice *service; + while(S_OK == serviceEnum->Next(1, &service, NULL)) + { + loaded++; + if (SUCCEEDED(service->SetAddress(NULL))) + { + service->UpdateFlags(SVCF_SUBSCRIBED | SVCF_PREAUTHORIZED); + + ULONG savedOk; + if (SUCCEEDED(serviceStorage->Save(&service, 1, ifc_omstorage::saveClearModified, &savedOk))) + { + navigation->CreateItem(service, 1); + saved += savedOk; + } + } + service->Release(); + } + serviceEnum->Release(); + break; + } + else if (OMSTORAGE_E_UNKNOWN_FORMAT != hr) + { + break; + } + + storage->Release(); + } + + if (NULL != converted) + *converted = saved; + + navigation->Release(); + + return S_OK; +} + +static HRESULT ImportFile_ProcessList(HWND hOwner, LPCWSTR pszList) +{ + if (NULL == pszList) + return E_INVALIDARG; + + LPCWSTR base, block, c; + base = pszList; + c = base; + block = NULL; + ULONG converted; + + ifc_omstorageenumerator *enumerator; + HRESULT hr = ImportFile_GetEnumerator(&enumerator); + if (FAILED(hr)) return hr; + + ServiceHost *serviceHost; + hr = ServiceHost::GetCachedInstance(&serviceHost); + if (SUCCEEDED(hr)) + { + ifc_omstorage *serviceStorage; + hr = ServiceHelper_QueryStorage(&serviceStorage); + if (SUCCEEDED(hr)) + { + ULONG scanned(0); + while(L'\0' != *c) + { + block = c; + while (L'\0' != *c) c++; + if (c != block && block != base) + { + WCHAR szBuffer[MAX_PATH * 2] = {0}; + scanned++; + if (SUCCEEDED(StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), L"%s\\%s", base, block)) && + SUCCEEDED(ImportFile_ProcessFile(hOwner, enumerator, serviceHost, serviceStorage, szBuffer, &converted))) + { + } + } + c++; + } + + if (pszList == block && c != pszList && + SUCCEEDED(ImportFile_ProcessFile(hOwner, enumerator, serviceHost, serviceStorage, pszList, &converted))) + { + } + serviceStorage->Release(); + } + serviceHost->Release(); + } + + enumerator->Release(); + return hr; +} + +HRESULT ImportService_FromFile(HWND hOwner) +{ + if (NULL == OMSERVICEMNGR) + return E_UNEXPECTED; + + OPENFILENAME of = {0}; + of.lStructSize = sizeof(of); + + WCHAR szFilter[1024] = {0}; + HRESULT hr = ImportFile_GetFilter(szFilter, ARRAYSIZE(szFilter), &of.nFilterIndex); + if (FAILED(hr)) return hr; + + UINT cchResultMax = 16384; + LPWSTR pszResult = Plugin_MallocString(cchResultMax); + if (NULL == pszResult) return E_OUTOFMEMORY; + *pszResult = L'\0'; + + of.hwndOwner = hOwner; + of.lpstrFilter = szFilter; + of.lpstrFile = pszResult; + of.nMaxFile = cchResultMax; + of.lpstrInitialDir = WASABI_API_APP->path_getUserSettingsPath(); + of.lpstrTitle = WASABI_API_LNGSTRINGW(IDS_IMPORT_FILES); + of.Flags = OFN_ENABLESIZING | OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_ALLOWMULTISELECT; + + if (0 == GetOpenFileName(&of)) + { + INT err = CommDlgExtendedError(); + hr = (0 == err) ? S_FALSE : E_FAIL; + } + else + { + hr = ImportFile_ProcessList(hOwner, pszResult); + } + + Plugin_FreeString(pszResult); + return hr; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/importUrl.cpp b/Src/Plugins/Library/ml_online/importUrl.cpp new file mode 100644 index 00000000..201bea1c --- /dev/null +++ b/Src/Plugins/Library/ml_online/importUrl.cpp @@ -0,0 +1,321 @@ +#include "main.h" +#include "./import.h" +#include "./api__ml_online.h" +#include "./serviceHost.h" +#include "./serviceHelper.h" +#include "./navigation.h" +#include "./resource.h" +#include "./config.h" + +#include <ifc_omstorage.h> +#include <ifc_omwebstorage.h> +#include <ifc_omstorageenum.h> +#include <ifc_omservice.h> +#include <ifc_omserviceenum.h> + +#include <vector> + +#include <strsafe.h> + + +typedef std::vector<WCHAR*> StringList; + +static StringList recentList; +static BOOL recentListModified = FALSE; + +typedef struct __OPENURLDLG +{ + HWND hOwner; + LPCWSTR pszAddress; + LPWSTR pszBuffer; + UINT cchBufferMax; +} OPENURLDLG; + +static INT_PTR ImportUrlDlg_Show(OPENURLDLG *poud); + +static HRESULT ImportUrl_GetEnumerator(ifc_omstorageenumerator **enumerator) +{ + if (NULL == OMSERVICEMNGR) return E_UNEXPECTED; + return OMSERVICEMNGR->EnumStorage(&STID_OmWebStorage, ifc_omstorage::capPublic | ifc_omstorage::capLoad, enumerator); +} + +HRESULT ImportService_GetUrlSupported() +{ + if (NULL == OMSERVICEMNGR) + return E_UNEXPECTED; + + ifc_omstorageenumerator *enumerator; + HRESULT hr = ImportUrl_GetEnumerator(&enumerator); + + if (SUCCEEDED(hr)) + { + ifc_omstorage *storage; + if(S_OK == enumerator->Next(1, &storage, NULL)) + { + storage->Release(); + hr = S_OK; + } + else + { + hr = S_FALSE; + } + + enumerator->Release(); + } + return hr; +} + +HRESULT ImportUrl_LoadAddress(HWND hOwner, LPCWSTR pszAddress, ifc_omstorageenumerator *enumerator, + ServiceHost *serviceHost, ifc_omstorage *serviceStorage, Navigation *navigation) +{ + HRESULT hr = S_OK; + ULONG loaded(0); + + ifc_omstorage *storage; + enumerator->Reset(); + + while(S_OK == enumerator->Next(1, &storage, NULL)) + { + ifc_omstorageasync *async; + hr = storage->BeginLoad(pszAddress, serviceHost, NULL, NULL, &async); + if(SUCCEEDED(hr)) + { + ifc_omserviceenum *serviceEnum; + hr = storage->EndLoad(async, &serviceEnum); + async->Release(); + + if (SUCCEEDED(hr)) + { + ifc_omservice *service; + while(S_OK == serviceEnum->Next(1, &service, NULL)) + { + loaded++; + if (SUCCEEDED(service->SetAddress(NULL))) + { + ULONG savedOk; + if (SUCCEEDED(serviceStorage->Save(&service, 1, ifc_omstorage::saveClearModified, &savedOk))) + { + navigation->CreateItem(service, 1); + } + } + service->Release(); + } + serviceEnum->Release(); + } + break; + } + else if (OMSTORAGE_E_UNKNOWN_FORMAT != hr) + { + break; + } + storage->Release(); + } + + return hr; +} + +HRESULT ImportService_FromUrl(HWND hOwner) +{ + OPENURLDLG dlg = {0}; + WCHAR szBuffer[4096] = {0}; + + dlg.hOwner = hOwner; + dlg.pszAddress = NULL; + dlg.pszBuffer = szBuffer; + dlg.cchBufferMax = ARRAYSIZE(szBuffer); + if (IDOK != ImportUrlDlg_Show(&dlg)) + return S_FALSE; + + ifc_omstorageenumerator *enumerator; + HRESULT hr = ImportUrl_GetEnumerator(&enumerator); + if (SUCCEEDED(hr)) + { + Navigation *navigation; + hr = Plugin_GetNavigation(&navigation); + if (SUCCEEDED(hr)) + { + ifc_omstorage *serviceStorage; + hr = ServiceHelper_QueryStorage(&serviceStorage); + if (SUCCEEDED(hr)) + { + ServiceHost *serviceHost; + hr = ServiceHost::GetCachedInstance(&serviceHost); + if (SUCCEEDED(hr)) + { + hr = ImportUrl_LoadAddress(hOwner, szBuffer, enumerator, serviceHost, serviceStorage, navigation); + serviceHost->Release(); + } + serviceStorage->Release(); + } + navigation->Release(); + } + enumerator->Release(); + } + return hr; +} + +static INT_PTR ImportUrlDlg_OnInit(HWND hwnd, HWND hFocus, LPARAM param) +{ + OPENURLDLG *poud = (OPENURLDLG*)param; + if (NULL != poud) + { + SetProp(hwnd, L"OPENURLDLG", poud); + + HWND hAddress = GetDlgItem(hwnd, IDC_ADDRESS); + if (NULL != hAddress) + { + LPWSTR p; + + size_t count = recentList.size(); + if (0 == count) + { + char szKey[32] = {0}, szBuffer[4096] = {0}; + for(int i = 1; i < 101; i++) + { + if (FAILED(StringCchPrintfA(szKey, ARRAYSIZE(szKey), "entry%d", i)) || + 0 == Config_ReadStr("RecentUrl", szKey, NULL, szBuffer, ARRAYSIZE(szBuffer)) || + '\0' == szBuffer[0]) + { + break; + } + + p = Plugin_MultiByteToWideChar(CP_UTF8, 0, szBuffer, -1); + if (NULL != p) recentList.push_back(p); + } + count = recentList.size(); + } + + for (size_t i = 0; i < count; i ++) + { + p = recentList[i]; + if(NULL != p && L'\0' != *p) + SendMessage(hAddress, CB_ADDSTRING, 0, (LPARAM)p); + } + + if (NULL != poud->pszAddress) + SetWindowText(hAddress, poud->pszAddress); + } + + RECT ownerRect; + if (NULL != poud->hOwner && IsWindowVisible(poud->hOwner) && + GetWindowRect(poud->hOwner, &ownerRect)) + { + RECT myRect; + GetWindowRect(hwnd, &myRect); + LONG x = ownerRect.left + ((ownerRect.right - ownerRect.left) - (myRect.right - myRect.left))/2; + LONG y = ownerRect.top + ((ownerRect.bottom - ownerRect.top) - (myRect.bottom - myRect.top))/2; + SetWindowPos(hwnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + } + } + + return 0; +} + +static void ImportUrlDlg_OnDestroy(HWND hwnd) +{ + RemoveProp(hwnd, L"OPENURLDLG"); + +} +static INT_PTR ImportUrlDlg_ReturnAddress(HWND hwnd) +{ + OPENURLDLG *poud = (OPENURLDLG*)GetProp(hwnd, L"OPENURLDLG"); + if (NULL == poud) return -1; + + HWND hAddress = GetDlgItem(hwnd, IDC_ADDRESS); + if (NULL == hAddress) return -2; + + if (0 == GetWindowText(hAddress, poud->pszBuffer, poud->cchBufferMax)) + return -3; + + if (NULL != poud->pszBuffer && L'\0' != *poud->pszBuffer) + { + LPWSTR p; + size_t index = recentList.size(); + while(index--) + { + p = recentList[index]; + if (CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, poud->pszBuffer, -1, p, -1)) + { + Plugin_FreeString(p); + recentList.erase(recentList.begin() + index); + } + } + + p = Plugin_CopyString(poud->pszBuffer); + if (NULL != p) + { + recentList.insert(recentList.begin(), p); + recentListModified = TRUE; + } + } + return IDOK; +} + +static void ImportUrlDlg_OnCommand(HWND hwnd, INT commandId, INT eventId, HWND hControl) +{ + switch(commandId) + { + case IDOK: + EndDialog(hwnd, ImportUrlDlg_ReturnAddress(hwnd)); + break; + case IDCANCEL: + EndDialog(hwnd, IDCANCEL); + break; + } + +} +static INT_PTR WINAPI ImportUrlDlg_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: return ImportUrlDlg_OnInit(hwnd, (HWND)wParam, lParam); + case WM_DESTROY: ImportUrlDlg_OnDestroy(hwnd); break; + case WM_COMMAND: ImportUrlDlg_OnCommand(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break; + } + + return 0; + +} + + +static INT_PTR ImportUrlDlg_Show(OPENURLDLG *poud) +{ + if (NULL == poud || NULL == poud->pszBuffer) + return -1; + + HWND hParent = poud->hOwner; + if (NULL == poud->hOwner) + hParent = Plugin_GetLibrary(); + + return WASABI_API_DIALOGBOXPARAMW(IDD_OPENURL, hParent, ImportUrlDlg_DialogProc, (LPARAM)poud); + +} + +void ImportService_SaveRecentUrl() +{ + if (FALSE == recentListModified) + return; + + Config_WriteSection("RecentUrl", NULL); + + size_t count = recentList.size(); + if (count > 100) count = 100; + + char szKey[32], szBuffer[4096]; + UINT entry = 1; + + for (size_t i = 0; i < count; i++) + { + LPCWSTR p = recentList[i]; + if (NULL != p && L'\0' != *p && + 0 != WideCharToMultiByte(CP_UTF8, 0, p, -1, szBuffer, ARRAYSIZE(szBuffer), NULL, NULL) && + SUCCEEDED(StringCchPrintfA(szKey, ARRAYSIZE(szKey), "entry%d", entry)) && + SUCCEEDED(Config_WriteStr("RecentUrl", szKey, szBuffer))) + { + entry++; + } + } + + recentListModified = FALSE; + +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/jsapi2_omcom.cpp b/Src/Plugins/Library/ml_online/jsapi2_omcom.cpp new file mode 100644 index 00000000..bebe30d3 --- /dev/null +++ b/Src/Plugins/Library/ml_online/jsapi2_omcom.cpp @@ -0,0 +1,136 @@ +#include "./main.h" +#include "./api__ml_online.h" +#include "./jsapi2_omcom.h" +#include "./navigation.h" + +#include <ifc_omservice.h> +#include <browserView.h> + +#include "../Winamp/JSAPI.h" + + +JSAPI2::OnlineServicesAPI::OnlineServicesAPI(const wchar_t *_key, JSAPI::ifc_info *_info) +{ + info = _info; + key = _key; + refCount = 1; +} + +#define DISP_TABLE \ + CHECK_ID(Login)\ + + +#define CHECK_ID(str) JSAPI_DISP_ENUMIFY(str), +enum { + DISP_TABLE +}; + +#undef CHECK_ID +#define CHECK_ID(str) if (wcscmp(rgszNames[i], L## #str) == 0) { rgdispid[i] = JSAPI_DISP_ENUMIFY(str); continue; } +HRESULT JSAPI2::OnlineServicesAPI::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid) +{ + bool unknowns = false; + for (unsigned int i = 0;i != cNames;i++) + { + DISP_TABLE + + rgdispid[i] = DISPID_UNKNOWN; + unknowns = true; + + } + if (unknowns) + return DISP_E_UNKNOWNNAME; + else + return S_OK; +} + +HRESULT JSAPI2::OnlineServicesAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo) +{ + return E_NOTIMPL; +} + +HRESULT JSAPI2::OnlineServicesAPI::GetTypeInfoCount(unsigned int FAR * pctinfo) +{ + return E_NOTIMPL; +} + +HRESULT JSAPI2::OnlineServicesAPI::Login(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr) +{ + JSAPI_VERIFY_METHOD(wFlags); + JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1); + JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr); + JSAPI_INIT_RESULT(pvarResult, VT_BOOL); + JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE); + const wchar_t *url = JSAPI_PARAM(pdispparams, 1).bstrVal; + +// if (AGAVE_API_JSAPI2_SECURITY->GetActionAuthorization(L"onlineservices", L"login", key, info, JSAPI2::api_security::ACTION_DISALLOWED) == JSAPI2::api_security::ACTION_ALLOWED) + { + HWND hBrowser = info->GetHWND(); + if (NULL != hBrowser && IsWindow(hBrowser)) + { + ifc_omservice *service; + if (FALSE != BrowserControl_GetService(hBrowser, &service)) + { + wchar_t szBuffer[4096] = {0}; + LPCWSTR navigateUrl; + + if (NULL != AGAVE_API_AUTH && + 0 == AGAVE_API_AUTH->ClientToWeb(GUID_NULL, url, szBuffer, ARRAYSIZE(szBuffer))) + { + navigateUrl = szBuffer; + } + else + navigateUrl = url; + + BrowserControl_Navigate(hBrowser, navigateUrl, TRUE); + + JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE); + service->Release(); + } + } + } + return S_OK; +} + +#undef CHECK_ID +#define CHECK_ID(str) case JSAPI_DISP_ENUMIFY(str): return str(wFlags, pdispparams, pvarResult, puArgErr); +HRESULT JSAPI2::OnlineServicesAPI::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr) +{ + switch (dispid) + { + DISP_TABLE + } + return DISP_E_MEMBERNOTFOUND; +} + +STDMETHODIMP JSAPI2::OnlineServicesAPI::QueryInterface(REFIID riid, PVOID *ppvObject) +{ + if (!ppvObject) + return E_POINTER; + + else if (IsEqualIID(riid, IID_IDispatch)) + *ppvObject = (IDispatch *)this; + else if (IsEqualIID(riid, IID_IUnknown)) + *ppvObject = this; + else + { + *ppvObject = NULL; + return E_NOINTERFACE; + } + + AddRef(); + return S_OK; +} + +ULONG JSAPI2::OnlineServicesAPI::AddRef(void) +{ + return InterlockedIncrement(&refCount); +} + + +ULONG JSAPI2::OnlineServicesAPI::Release(void) +{ + LONG lRef = InterlockedDecrement(&refCount); + if (lRef == 0) delete this; + return lRef; +} diff --git a/Src/Plugins/Library/ml_online/jsapi2_omcom.h b/Src/Plugins/Library/ml_online/jsapi2_omcom.h new file mode 100644 index 00000000..970ef323 --- /dev/null +++ b/Src/Plugins/Library/ml_online/jsapi2_omcom.h @@ -0,0 +1,27 @@ +#pragma once +#include <ocidl.h> +#include "../Winamp/JSAPI_Info.h" + +namespace JSAPI2 +{ + class OnlineServicesAPI : public IDispatch + { + public: + OnlineServicesAPI(const wchar_t *_key, JSAPI::ifc_info *info); + STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject); + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + // *** IDispatch Methods *** + STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid); + STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo); + STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo); + STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr); + private: + const wchar_t *key; + volatile LONG refCount; + JSAPI::ifc_info *info; + + STDMETHOD (Login)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr); + }; +} + diff --git a/Src/Plugins/Library/ml_online/local_menu.cpp b/Src/Plugins/Library/ml_online/local_menu.cpp new file mode 100644 index 00000000..2548ad18 --- /dev/null +++ b/Src/Plugins/Library/ml_online/local_menu.cpp @@ -0,0 +1,379 @@ +#include "./main.h" +#include "./local_menu.h" +#include "../nu/menuHelpers.h" +#include "./resource.h" +#include "./api__ml_online.h" +#include "../../General/gen_ml/menu.h" + +#include <windows.h> +#include <strsafe.h> + +#define MENU_SERVICECONTEXT 0 +#define MENU_GALERYCONTEXT 1 +#define MENU_RATING 2 +#define MENU_VIEW 3 +#define MENU_NAVIGATION 4 +#define MENU_TOOLBAR 5 + +#define RATING_MARKER MAKELONG(MAKEWORD('R','A'),MAKEWORD('T','E')) + +#define RATING_MINSPACECX 16 + + + +typedef BOOL (__cdecl *MLISSKINNEDPOPUPENABLED)(void); +typedef HANDLE (__cdecl *MLINITSKINNEDPOPUPHOOK)(HWND /*hwnd*/, HMLIMGLST /*hmlil*/, INT /*width*/, UINT /*skinStyle*/, + MENUCUSTOMIZEPROC /*customProc*/, ULONG_PTR /*customParam*/); +typedef HANDLE (__cdecl *MLREMOVESKINNEDPOPUPHOOK)(HANDLE /*hPopupHook*/); + +#if 0 +static BOOL Menu_IsRatingStar(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 BOOL Menu_MeasureRating(HMENU hMenu, HDC hdc, MEASUREITEMSTRUCT *pmis) +{ + if (NULL == hdc || !Menu_IsRatingStar(hMenu, pmis->itemID, NULL)) + return FALSE; + + RECT rect; + if (!MLRating_CalcRect(Plugin_GetLibrary(), NULL, 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; +} + +static BOOL Menu_DrawRating(HMENU hMenu, HDC hdc, DRAWITEMSTRUCT *pdis) +{ + INT ratingValue; + if (NULL == hdc || !Menu_IsRatingStar(hMenu, pdis->itemID, &ratingValue)) + return FALSE; + + INT spaceCX = ((pdis->rcItem.bottom - pdis->rcItem.top) > RATING_MINSPACECX) ? + (pdis->rcItem.bottom - pdis->rcItem.top) : + RATING_MINSPACECX; + + RATINGDRAWPARAMS rdp = {0}; + rdp.cbSize = sizeof(RATINGDRAWPARAMS); + rdp.hdcDst = hdc; + rdp.rc = pdis->rcItem; + rdp.rc.left += spaceCX; + rdp.value = ratingValue; + rdp.maxValue = 5; + + UINT menuState = GetMenuState(hMenu, pdis->itemID, MF_BYCOMMAND); + rdp.trackingValue = (0 == ((MF_DISABLED | MF_GRAYED) & menuState)) ? rdp.value : 0; + + rdp.fStyle = RDS_LEFT | RDS_VCENTER | RDS_HOT; + rdp.hMLIL = NULL; + rdp.index = 0; + + return MLRating_Draw(Plugin_GetLibrary(), &rdp); +} + +static BOOL CALLBACK Menu_CustomDrawProc(INT action, HMENU hMenu, HDC hdc, LPARAM param, ULONG_PTR user) +{ + switch(action) + { + case MLMENU_ACTION_MEASUREITEM: + if (hMenu == (HMENU)user) + return Menu_MeasureRating(hMenu, hdc, (MEASUREITEMSTRUCT*)param); + break; + case MLMENU_ACTION_DRAWITEM: + if (hMenu == (HMENU)user) + return MLMENU_WANT_DRAWPART; + break; + case MLMENU_ACTION_DRAWBACK: + break; + case MLMENU_ACTION_DRAWICON: + break; + case MLMENU_ACTION_DRAWTEXT: + if (hMenu == (HMENU)user) + return Menu_DrawRating(hMenu, hdc, (DRAWITEMSTRUCT*)param); + break; + } + return FALSE; +} +#endif + +BOOL Menu_SetRatingValue(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, state; + 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; +} + +static HMENU Menu_FindRatingMenuRecur(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 = Menu_FindRatingMenuRecur(pmii->hSubMenu, pmi, pmii); + if (NULL != hRating) + return hRating; + } + } + return NULL; +} + +HMENU Menu_FindRatingMenu(HMENU hMenu) +{ + if (NULL == hMenu) + return NULL; + + MENUITEMINFO mii; + mii.cbSize = sizeof(MENUITEMINFO); + mii.fMask = MIIM_SUBMENU; + + MENUINFO mi; + mi.cbSize = sizeof(MENUINFO); + mi.fMask = MIM_MENUDATA; + + return Menu_FindRatingMenuRecur(hMenu, &mi, &mii); +} + +static BOOL Menu_InsertRatingMenu(HMENU hDest, INT iPos, HMENU baseMenu, INT ratingValue) +{ + if ( 0 == MenuHelper_CopyMenuEx(hDest, iPos, baseMenu, MENU_RATING, 1)) + return FALSE; + + MENUITEMINFO mii = {0}; + mii.cbSize = sizeof(MENUITEMINFO); + mii.fMask = MIIM_SUBMENU; + if (GetMenuItemInfo(hDest, iPos, TRUE, &mii)) + { + if (NULL != mii.hSubMenu) + { + MENUINFO mi = {0}; + mi.cbSize = sizeof(MENUINFO); + mi.fMask = MIM_MENUDATA; + mi.dwMenuData = RATING_MARKER; + SetMenuInfo(mii.hSubMenu, &mi); + + Menu_SetRatingValue(mii.hSubMenu, ratingValue); + } + } + return TRUE; +} + +static HMENU Menu_CreateRatingMenu(HMENU baseMenu, INT ratingValue) +{ + HMENU menu = GetSubMenu(baseMenu, MENU_RATING); + if (NULL == menu) return NULL; + + menu = MenuHelper_DuplcateMenu(menu); + if (NULL == menu) return NULL; + + MENUINFO mi = {0}; + mi.cbSize = sizeof(MENUINFO); + mi.fMask = MIM_MENUDATA; + mi.dwMenuData = RATING_MARKER; + SetMenuInfo(menu, &mi); + + Menu_SetRatingValue(menu, ratingValue); + return menu; +} + +static HMENU Menu_GetServiceContext(HMENU baseMenu, UINT flags, BOOL fGaleryMode) +{ + HMENU menu = GetSubMenu(baseMenu, (FALSE == fGaleryMode) ? MENU_SERVICECONTEXT : MENU_GALERYCONTEXT); + if (NULL == menu) return NULL; + + menu = MenuHelper_DuplcateMenu(menu); + if (NULL == menu) return NULL; + + HMENU embedMenu; + INT inserted; + INT total = GetMenuItemCount(menu); + + if (FALSE == fGaleryMode) + { + // rating + if (Menu_InsertRatingMenu(menu, 0, baseMenu, RATINGFROMMCF(flags))) + total++; + } + + if (0 != (MCF_NAVIGATION & flags)) + {// navigation + embedMenu = GetSubMenu(baseMenu, MENU_NAVIGATION); + if (NULL != embedMenu) + { + inserted = MenuHelper_CopyMenu(menu, 0, embedMenu); + if (inserted > 0 && total > 0 && MenuHelper_InsertSeparator(menu, inserted)) + inserted++; + total += inserted; + } + } + + if (0 != (MCF_VIEW & flags)) + {// view + embedMenu = GetSubMenu(baseMenu, MENU_VIEW); + if (NULL != embedMenu) + { + inserted = MenuHelper_CopyMenu(menu, 0, embedMenu); + if (inserted > 0 && total > 0 && MenuHelper_InsertSeparator(menu, inserted)) + { + inserted++; + } + total += inserted; + } + + EnableMenuItem(menu, ID_VIEW_OPEN , MF_BYCOMMAND | ((0 == (MCF_VIEWACTIVE & flags)) ? MF_ENABLED : MF_DISABLED)); + if ( 0 == (MCF_VIEWACTIVE & flags)) + SetMenuDefaultItem(menu, ID_VIEW_OPEN, FALSE); + } + + return menu; +} + +static HMENU Menu_GetToolbarContext(HMENU baseMenu, UINT flags) +{ + HMENU hMenu = GetSubMenu(baseMenu, MENU_TOOLBAR); + return hMenu; +} + +void Menu_ConvertRatingMenuStar(HMENU menu, UINT menu_id) +{ + MENUITEMINFOW mi = {sizeof(mi), MIIM_DATA | MIIM_TYPE, MFT_STRING}; + wchar_t rateBuf[32], *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 = WASABI_API_LOADMENUW(IDR_CONTEXTMENU); + if (NULL == baseMenu) + return NULL; + + HMENU rate_hmenu = GetSubMenu(baseMenu,2); + 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 OMMENU_SERVICECONTEXT: + case OMMENU_GALERYCONTEXT: + return Menu_GetServiceContext(baseMenu, flags, (OMMENU_GALERYCONTEXT == menuKind)); + case OMMENU_RATING: + return Menu_CreateRatingMenu(baseMenu, RATINGFROMMCF(flags)); + case OMMENU_TOOLBAR: + return Menu_GetToolbarContext(baseMenu, flags); + } + return NULL; +} + +void Menu_ReleaseMenu(HMENU hMenu, INT menuKind) +{ + if (NULL == hMenu) + return; + + switch(menuKind) + { + case OMMENU_SERVICECONTEXT: + DestroyMenu(hMenu); + break; + case OMMENU_GALERYCONTEXT: + DestroyMenu(hMenu); + break; + case OMMENU_RATING: + DestroyMenu(hMenu); + break; + case OMMENU_TOOLBAR: + break; + } +} + +INT DoTrackPopup(HMENU hMenu, UINT fuFlags, INT x, INT y, HWND hwnd, LPTPMPARAMS lptpm) +{ + if (NULL == hMenu) + return NULL; + + return Menu_TrackPopupParam(Plugin_GetLibrary(), hMenu, fuFlags, x, y, + hwnd, lptpm, (ULONG_PTR)Menu_FindRatingMenu(hMenu)); +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/local_menu.h b/Src/Plugins/Library/ml_online/local_menu.h new file mode 100644 index 00000000..bf4257e1 --- /dev/null +++ b/Src/Plugins/Library/ml_online/local_menu.h @@ -0,0 +1,40 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_MENU_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_MENU_HEADER + + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "../../General/gen_ml/ml_ipc_0313.h" + +class OmService; + +#define OMMENU_SERVICECONTEXT 0 +#define OMMENU_GALERYCONTEXT 1 +#define OMMENU_RATING 2 +#define OMMENU_TOOLBAR 3 + +#define MCF_VIEW 0x00000001 +#define MCF_NAVIGATION 0x00000004 +#define MCF_VIEWACTIVE 0x00000008 + +#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); + +HMENU Menu_FindRatingMenu(HMENU hMenu); +BOOL Menu_SetRatingValue(HMENU ratingMenu, INT ratingValue); +INT DoTrackPopup(HMENU hMenu, UINT fuFlags, INT x, INT y, HWND hwnd, LPTPMPARAMS lptpm); + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_MENU_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/messageBox.cpp b/Src/Plugins/Library/ml_online/messageBox.cpp new file mode 100644 index 00000000..03a850e1 --- /dev/null +++ b/Src/Plugins/Library/ml_online/messageBox.cpp @@ -0,0 +1,193 @@ +#include "main.h" +#include "./api__ml_online.h" +#include "./resource.h" + +#include <windows.h> +#include <strsafe.h> + +typedef struct __MESSAGEBOX +{ + HWND hParent; + LPCWSTR pszText; + LPCWSTR pszCaption; + UINT uType; + LPCWSTR pszCheck; + INT *checked; +} MESSAGEBOX; + +static INT_PTR CALLBACK OmMessageBox_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +INT OmMessageBox(HWND hParent, LPCWSTR pszText, LPCWSTR pszCaption, UINT uType, LPCWSTR pszCheck, INT *checked) +{ + MESSAGEBOX instance; + instance.hParent = hParent; + instance.pszText = pszText; + instance.pszCaption = pszCaption; + instance.uType = uType; + instance.pszCheck = pszCheck; + instance.checked = checked; + + return (INT)WASABI_API_DIALOGBOXPARAMW(IDD_MESSAGEBOX, hParent, OmMessageBox_DialogProc, (LPARAM)&instance); +} + +static void OmMessgageBox_CenterWindow(HWND hwnd, HWND hCenter) +{ + if (NULL == hwnd || NULL == hCenter) + return; + + RECT centerRect, windowRect; + if (!GetWindowRect(hwnd, &windowRect) || !GetWindowRect(hCenter, ¢erRect)) + return; + windowRect.left = centerRect.left + ((centerRect.right - centerRect.left) - (windowRect.right - windowRect.left))/2; + windowRect.top = centerRect.top + ((centerRect.bottom - centerRect.top) - (windowRect.bottom - windowRect.top))/2; + + SetWindowPos(hwnd, NULL, windowRect.left, windowRect.top, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); +} + +static BOOL OmMessageBox_GetTextBox(HWND hwnd, LPCWSTR pszText, INT cchText, SIZE *sizeText) +{ + HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL == hdc) return FALSE; + + HFONT font = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L); + HFONT fontOrig = (HFONT)SelectObject(hdc, font); + + if (cchText < 0) + cchText = lstrlen(pszText); + + BOOL resultOk = GetTextExtentPoint32(hdc, pszText, cchText, sizeText); + + SelectObject(hdc, fontOrig); + ReleaseDC(hwnd, hdc); + + return resultOk; +} +static HICON OmMessageBox_GetIcon(UINT flags) +{ + LPCWSTR iconName = NULL; + switch(0x000000F0 & flags) + { + case MB_ICONHAND: iconName = IDI_HAND; break; + case MB_ICONQUESTION: iconName = IDI_QUESTION; break; + case MB_ICONEXCLAMATION:iconName = IDI_EXCLAMATION; break; + case MB_ICONASTERISK: iconName = IDI_ASTERISK; break; + } + return (NULL != iconName) ? LoadIcon(NULL, iconName) : NULL; +} + +static BOOL OmMessageBox_GetIconSize(UINT flags, SIZE *iconSize) +{ + if (NULL == iconSize) return FALSE; + + iconSize->cx = 0; + iconSize->cy = 0; + + HICON hIcon = OmMessageBox_GetIcon(flags); + if (NULL == hIcon) + return TRUE; + + ICONINFO iconInfo; + + if (!GetIconInfo(hIcon, &iconInfo) || FALSE == iconInfo.fIcon) + return FALSE; + + BITMAP bm; + if (NULL != iconInfo.hbmColor) + { + if (FALSE == GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bm)) + return FALSE; + + iconSize->cx = bm.bmWidth; + iconSize->cy = bm.bmHeight; + } + else if (NULL != iconInfo.hbmMask) + { + if (FALSE == GetObject(iconInfo.hbmMask, sizeof(BITMAP), &bm)) + return FALSE; + + iconSize->cx = bm.bmWidth; + iconSize->cy = bm.bmHeight/2; + } + + return TRUE; +} + +static BOOL OmMessageBox_GetButtonSize(HWND hwnd, SIZE *buttonSize) +{ + if (NULL == buttonSize) + return FALSE; + + if (FALSE != SendMessage(hwnd, (0x1600 + 0x0001) /*BCM_GETIDEALSIZE*/, 0, (LPARAM)buttonSize)) + return TRUE; + + return FALSE; +} +static INT_PTR OmMessageBox_OnInitDialog(HWND hwnd, HWND hFocus, LPARAM lParam) +{ + MESSAGEBOX *pmb = (MESSAGEBOX*)lParam; + SetWindowText(hwnd, pmb->pszCaption); + + SIZE textSize; + SIZE maxSize; + MONITORINFO mi; + mi.cbSize = sizeof(MONITORINFO); + + HMONITOR hMonitor = MonitorFromWindow(pmb->hParent, MONITOR_DEFAULTTONEAREST); + if (NULL != hMonitor && + GetMonitorInfo(hMonitor, &mi)) + { + RECT rcFrame; + SetRectEmpty(&rcFrame); + AdjustWindowRectEx(&rcFrame, GetWindowStyle(hwnd), FALSE, GetWindowStyleEx(hwnd)); + maxSize.cx = mi.rcWork.right - mi.rcWork.left - (rcFrame.right - rcFrame.left) - 8*2; + maxSize.cy = mi.rcWork.bottom - mi.rcWork.top - (rcFrame.bottom - rcFrame.top) - 8*2; + } + else + { + maxSize.cx = 1200; + maxSize.cy = 800; + } + + HWND hText = GetDlgItem(hwnd, IDC_TEXT); + if (NULL != hText) + { + if (!OmMessageBox_GetTextBox(hText, pmb->pszText, -1, &textSize)) + ZeroMemory(&textSize, sizeof(SIZE)); + + SetWindowPos(hText, NULL, 0, 0, textSize.cx, textSize.cy, SWP_NOACTIVATE | SWP_NOZORDER); + } + else + ZeroMemory(&textSize, sizeof(SIZE)); + + + + OmMessgageBox_CenterWindow(hwnd, pmb->hParent); + SendMessage(hwnd, DM_REPOSITION, 0, 0L); + return FALSE; +} + +static void OmMessageBox_OnDestroy(HWND hwnd) +{ + +} + +static void OmMessageBox_OnCommand(HWND hwnd, INT commandId, INT eventId, HWND hControl) +{ + switch(commandId) + { + case IDOK: + case IDCANCEL: + EndDialog(hwnd, commandId); + break; + } +} +static INT_PTR CALLBACK OmMessageBox_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: return OmMessageBox_OnInitDialog(hwnd, (HWND)wParam, lParam); + case WM_DESTROY: OmMessageBox_OnDestroy(hwnd); break; + case WM_COMMAND: OmMessageBox_OnCommand(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break; + } + return 0; +} diff --git a/Src/Plugins/Library/ml_online/messageBox.h b/Src/Plugins/Library/ml_online/messageBox.h new file mode 100644 index 00000000..4becf7f8 --- /dev/null +++ b/Src/Plugins/Library/ml_online/messageBox.h @@ -0,0 +1,13 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_MESSAGEBOX_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_MESSAGEBOX_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + + +INT OmMessageBox(HWND hParent, LPCWSTR pszText, LPCWSTR pszCaption, UINT uType, LPCWSTR pszCheck, INT *checked); + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_MESSAGEBOX_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/ml_online.rc b/Src/Plugins/Library/ml_online/ml_online.rc new file mode 100644 index 00000000..133a9988 --- /dev/null +++ b/Src/Plugins/Library/ml_online/ml_online.rc @@ -0,0 +1,453 @@ +// 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 + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_MAINDIALOG DIALOGEX 0, 0, 225, 92 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Back",IDC_BACK,"Button",BS_OWNERDRAW | WS_TABSTOP,0,81,32,11 + CONTROL "Forward",IDC_FORWARD,"Button",BS_OWNERDRAW | WS_TABSTOP,36,81,40,11 + CONTROL "Home",IDC_HOME,"Button",BS_OWNERDRAW | WS_TABSTOP,80,81,32,11 + CONTROL "Stop",IDC_STOP,"Button",BS_OWNERDRAW | WS_TABSTOP,116,81,24,11 + CONTROL "Refresh",IDC_REFRESH,"Button",BS_OWNERDRAW | WS_TABSTOP,144,81,32,11 +END + +IDD_OMPREF DIALOGEX 0, 0, 272, 247 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "'Now Playing' Service",IDC_STATIC,0,0,272,72 + LTEXT "This allows you to specify an alternative Now Playing service to use in the 'Now Playing' node (if installed). Leave blank to reset to the default service.",IDC_STATIC,6,11,260,18 + EDITTEXT IDC_NOWPLAYINGURL,6,33,260,13,ES_AUTOHSCROLL + LTEXT "Note: For now playing lookups to work when using an alternative Now Playing service, the service will need to use the available Winamp Javascript API.",IDC_STATIC,6,51,260,18,WS_DISABLED + GROUPBOX "Online Media",IDC_STATIC,0,76,272,146 + GROUPBOX "General Settings",IDC_STATIC,5,87,260,30 + CONTROL "Allow sections to auto-resize",IDC_AUTOSIZE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,100,107,10 + GROUPBOX "Cache Preferences",IDC_STATIC,5,120,260,40 + LTEXT "Keep pages cached for:",IDC_STATIC,11,132,78,8 + CONTROL "Never",IDC_RADIO_NEVER,"Button",BS_AUTORADIOBUTTON | WS_GROUP,20,144,35,10 + CONTROL "One Hour",IDC_RADIO_HOURLY,"Button",BS_AUTORADIOBUTTON,62,144,47,10 + CONTROL "One Day",IDC_RADIO_DAILY,"Button",BS_AUTORADIOBUTTON,116,144,44,10 + CONTROL "One Week",IDC_RADIO_WEEKLY,"Button",BS_AUTORADIOBUTTON,167,144,51,10 + GROUPBOX "Bandwidth Control",IDC_STATIC,5,164,260,52 + LTEXT "Maximum bandwidth for media in Kbytes",IDC_STATIC,11,175,131,10,SS_CENTERIMAGE + EDITTEXT IDC_RADIO_MAXBW,154,174,30,12,ES_AUTOHSCROLL + LTEXT "Minimum bandwidth for media in Kbytes\n(not used by some sections)",IDC_STATIC,11,190,129,16 + EDITTEXT IDC_RADIO_MINBW,154,190,31,12,ES_AUTOHSCROLL +END + +IDD_MESSAGEBOX DIALOGEX 0, 0, 186, 90 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "",IDC_TEXT,7,7,172,35 +END + +IDD_SETUPPAGE DIALOGEX 0, 0, 256, 158 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Choose Winamp's web services to experience premium media services online.",IDC_LABEL_HEADER,5,6,251,8 + LISTBOX IDC_SERVICELIST,5,24,99,126,LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | LBS_NODATA | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_PLACEHOLDER,"Static",SS_BLACKRECT | NOT WS_VISIBLE,107,24,148,126 +END + +IDD_SETUP_SERVICEDETAILS DIALOGEX 0, 0, 148, 126 +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 + CONTROL "",IDC_THUMBNAIL,"Static",SS_BITMAP,0,0,45,45 + LTEXT "",IDC_TITLE,46,0,95,10 + EDITTEXT 1316,1,46,140,80,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP + LTEXT "line1\r\nline2",IDC_SERVICEMETA,46,10,102,26,NOT WS_VISIBLE +END + +IDD_SETUP_GROUPDETAILS DIALOGEX 0, 0, 148, 126 +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 + LTEXT "Group Title",IDC_TITLE,4,0,144,13 + EDITTEXT IDC_DESCRIPTION,2,15,145,97,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | NOT WS_VISIBLE | NOT WS_BORDER | NOT WS_TABSTOP + LTEXT "to read about Winamp policies.",IDC_HELPTEXT,0,117,147,8 +END + +IDD_OPENURL DIALOGEX 0, 0, 220, 54 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Open Url" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Enter service list address:",IDC_STATIC,5,4,210,10 + COMBOBOX IDC_ADDRESS,5,18,210,30,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "OK",IDOK,111,36,50,13 + PUSHBUTTON "Cancel",IDCANCEL,165,36,50,13 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_CONTEXTMENU MENU +BEGIN + POPUP "ServiceContextMenu" + BEGIN + MENUITEM SEPARATOR + POPUP "&Service Management" + BEGIN + MENUITEM "&New", ID_SERVICE_NEW + POPUP "&Import" + BEGIN + MENUITEM "&File...", ID_SERVICE_IMPORT_FILE + MENUITEM "&Url..", ID_SERVICE_IMPORT_URL + END + MENUITEM SEPARATOR + MENUITEM "&Edit", ID_SERVICE_EDIT + MENUITEM SEPARATOR + MENUITEM "Open Containing &Folder", ID_SERVICE_LOCATE + MENUITEM "Open in E&xternal Editor", ID_SERVICE_EDITEXTERNAL + END + MENUITEM SEPARATOR + MENUITEM "Re&move", ID_SERVICE_UNSUBSCRIBE + MENUITEM "Reset Permi&ssions", ID_SERVICE_RESETPOLICY + END + POPUP "GaleryContextMenu" + BEGIN + POPUP "&Service Management" + BEGIN + MENUITEM "&New", ID_SERVICE_NEW + MENUITEM SEPARATOR + MENUITEM "Import &File...", ID_SERVICE_IMPORT_FILE + MENUITEM "Import &Url..", ID_SERVICE_IMPORT_URL + END + MENUITEM SEPARATOR + MENUITEM "&Preferences...", ID_PLUGIN_PREFERENCES + MENUITEM "&omBrowser Options...", ID_OMBROWSER_OPTIONS + MENUITEM SEPARATOR + MENUITEM "&Help", ID_PLUGIN_HELP + END + 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 "View" + BEGIN + MENUITEM "&Open", ID_VIEW_OPEN + MENUITEM "Open in &New Window", ID_VIEW_OPENPOPUP + END + POPUP "Navigation" + BEGIN + MENUITEM "Back", ID_NAVIGATION_BACK + MENUITEM "Forward", ID_NAVIGATION_FORWARD + MENUITEM "Refresh", ID_NAVIGATION_REFRESH + MENUITEM "Stop", ID_NAVIGATION_STOP + 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 +END + +IDR_SETUPMENU MENU +BEGIN + POPUP "GroupContext" + BEGIN + MENUITEM "Expand", ID_GROUP_TOGGLE + MENUITEM SEPARATOR + MENUITEM "&Select All", ID_GROUP_SELECTALL + MENUITEM "&Unselect All", ID_GROUP_UNSELECTALL + MENUITEM SEPARATOR + MENUITEM "&Reload", ID_GROUP_RELOAD + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_MESSAGEBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 83 + END + + IDD_SETUPPAGE, DIALOG + BEGIN + LEFTMARGIN, 5 + VERTGUIDE, 104 + TOPMARGIN, 6 + BOTTOMMARGIN, 150 + HORZGUIDE, 24 + END + + IDD_SETUP_SERVICEDETAILS, DIALOG + BEGIN + RIGHTMARGIN, 142 + VERTGUIDE, 46 + HORZGUIDE, 10 + HORZGUIDE, 46 + END + + IDD_OPENURL, DIALOG + BEGIN + LEFTMARGIN, 5 + RIGHTMARGIN, 215 + TOPMARGIN, 4 + BOTTOMMARGIN, 49 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_BROWSERACCEL ACCELERATORS +BEGIN + VK_F5, ID_NAVIGATION_REFRESH, VIRTKEY, NOINVERT + "R", ID_NAVIGATION_REFRESH, VIRTKEY, CONTROL, NOINVERT + VK_F11, ID_WINDOW_FULLSCREEN, VIRTKEY, NOINVERT + VK_F4, ID_WINDOW_CLOSE, VIRTKEY, CONTROL, NOINVERT + VK_F5, ID_NAVIGATION_REFRESH_COMPLETELY, VIRTKEY, CONTROL, NOINVERT + "R", ID_NAVIGATION_REFRESH_COMPLETELY, VIRTKEY, SHIFT, CONTROL, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// HTML +// + +IDR_HTML_EDITOR HTML "resources\\pages\\serviceEditor.htm" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_ONLINE_SERVICES "Online Services" + IDS_NO_INTERNET_CONNECTION + "The media library feature you are attempting to use requires an internet connection. Please make sure you are connected to the internet and try again." + IDS_SORRY "Sorry" +END + +STRINGTABLE +BEGIN + IDS_PLUGIN_NAME "Nullsoft Online Services v%d.%02d" + 65535 "{D006C700-557E-43c7-A580-B4C50C56957A}" +END + +STRINGTABLE +BEGIN + IDS_DEFAULT_SERVICENAME "Unknown name" + 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_CHECKINGVERSION "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_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_SETUPPAGE_TITLE "Choose Online Services" + IDS_SETUP_EMPTYGROUP "( empty )" + IDS_SETUP_LOADINGGROUP "Loading..." + IDS_SERVICEGROUP_FEATURED "Featured" +END + +STRINGTABLE +BEGIN + IDS_SERVICEGROUP_KNOWN "Already Subscribed" + IDS_SETUP_GROUPLOADFAILED "Error loading data" + IDS_SERVICE_BYAUTHOR " by: " + IDS_SERVICE_LASTUPDATED " updated: " + IDS_SERVICEGROUP_FEATUREDLONG "Featured Services" + IDS_SERVICEGROUP_KNOWNLONG "Already Subscribed Services" + IDS_SERVICEGROUP_FEATURED_DESC + "This group contains some great services that we handpicked especially for you - including Winamp Charts & Add-ons. Also, if at any time you would like to try some other services, feel free to discover them by selecting the Online Services page in the Media Library." + IDS_SERVICEGROUP_KNOWN_DESC + "Services that you have already subscribed to." + IDS_MESSAGEBOX_UNSUBSCRIBE + "Are you sure you want to remove %s from your Online Services?" + IDS_MESSAGEBOX_UNSUBSCRIBE_CAPTION "Confirm Service Remove" + IDS_MESSAGEBOX_RESETTODEFAULT + "Are you sure you want to remove your current Online Services and restore the default Online Services?" + IDS_MESSAGEBOX_RESETTODEFAULT_CAPTION + "Confirm Restore to Default Services" + IDS_DOWNLOADSERVICE_JOB "Loading featured services" + IDS_SAVESERVICE_JOB "Saving services" + IDS_CACHEICONS_JOB "Caching service icons" +END + +STRINGTABLE +BEGIN + IDS_REGISTERINGSERVICE_JOB "Registering services" + IDS_MESSAGEBOX_NAMECHANGED_CAPTION "Service Name Changed" + IDS_MESSAGEBOX_NAMECHANGED "The service %s has been renamed to %s." + IDS_MESSAGEBOX_POLICYRESET_CAPTION "Confirm Permissions Reset" + IDS_MESSAGEBOX_POLICYRESET + "Are you sure you want to reset permissions for %s service?" + IDS_COLLAPSE "Collapse" + IDS_EXPAND "Expand" + IDS_SECURE_CONNECTION "Show Page Identification" + IDS_SCRIPT_ERROR "Show Script Errors" + IDS_SCRIPT_ERROR_DESCRIPTION "Page executed with some errors" + IDS_ENCRYPTION_MIXED "Mixed security" +END + +STRINGTABLE +BEGIN + 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_NAVIGATING "Navigating..." + IDS_MESSAGEBOX_FORCEREMOVE + "Service %s was cancelled and will be removed from your Online Services." + IDS_MESSAGEBOX_FORCEREMOVE_CAPTION "Service Cancelled" + IDS_HISTORY "Recent pages" + IDS_HISTORY_DESCRIPTION "Recent pages" + IDS_CURRENT_PAGE "Current Page" + IDS_CLICKHERE "Click here" +END + +STRINGTABLE +BEGIN + IDS_MESSAGEBOX_DISCOVERBUSY + "Service discovery in progress. Please wait till completion and try again." + IDS_MESSAGEBOX_DISCOVERBUSY_CAPTION "Operation In Progress" +END + +STRINGTABLE +BEGIN + IDS_USERSERVICE_NAME "My Service" + IDS_FILEFILTER_ALL "All Files" + IDS_FILEFILTER_ALLKNOWN "All Supported Files" + IDS_IMPORT_FILES "Import Service..." +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/Plugins/Library/ml_online/ml_online.sln b/Src/Plugins/Library/ml_online/ml_online.sln new file mode 100644 index 00000000..733c80a3 --- /dev/null +++ b/Src/Plugins/Library/ml_online/ml_online.sln @@ -0,0 +1,30 @@ +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}") = "ml_online", "ml_online.vcxproj", "{E40EADDB-F488-43CE-A451-B0D805C09A94}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E40EADDB-F488-43CE-A451-B0D805C09A94}.Debug|Win32.ActiveCfg = Debug|Win32 + {E40EADDB-F488-43CE-A451-B0D805C09A94}.Debug|Win32.Build.0 = Debug|Win32 + {E40EADDB-F488-43CE-A451-B0D805C09A94}.Debug|x64.ActiveCfg = Debug|x64 + {E40EADDB-F488-43CE-A451-B0D805C09A94}.Debug|x64.Build.0 = Debug|x64 + {E40EADDB-F488-43CE-A451-B0D805C09A94}.Release|Win32.ActiveCfg = Release|Win32 + {E40EADDB-F488-43CE-A451-B0D805C09A94}.Release|Win32.Build.0 = Release|Win32 + {E40EADDB-F488-43CE-A451-B0D805C09A94}.Release|x64.ActiveCfg = Release|x64 + {E40EADDB-F488-43CE-A451-B0D805C09A94}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {87AC7BBF-61AD-484A-A3A1-FA39CE18F1E7} + EndGlobalSection +EndGlobal diff --git a/Src/Plugins/Library/ml_online/ml_online.vcxproj b/Src/Plugins/Library/ml_online/ml_online.vcxproj new file mode 100644 index 00000000..8475fcd7 --- /dev/null +++ b/Src/Plugins/Library/ml_online/ml_online.vcxproj @@ -0,0 +1,395 @@ +<?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>{E40EADDB-F488-43CE-A451-B0D805C09A94}</ProjectGuid> + <RootNamespace>ml_online</RootNamespace> + <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|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)'=='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|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> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + <EmbedManifest>true</EmbedManifest> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <EmbedManifest>true</EmbedManifest> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + <EmbedManifest>true</EmbedManifest> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <EmbedManifest>true</EmbedManifest> + </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> + <AdditionalIncludeDirectories>.;..;..\..\..\;..\..\..\wasabi;..\..\..\agave;..\..\..\ombrowser;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_DEBUG;_WINDOWS;_USRDLL;ML_ONLINE_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4091;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <BufferSecurityCheck>true</BufferSecurityCheck> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <Link> + <AdditionalDependencies>shlwapi.lib;comctl32.lib;rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <SubSystem>Windows</SubSystem> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <TargetMachine>MachineX86</TargetMachine> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <ModuleDefinitionFile> + </ModuleDefinitionFile> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ +xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message> + </PostBuildEvent> + <ResourceCompile> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ResourceCompile> + <Manifest> + <OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile> + </Manifest> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>.;..;..\..\..\;..\..\..\wasabi;..\..\..\agave;..\..\..\ombrowser;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN64;_DEBUG;_WINDOWS;_USRDLL;ML_ONLINE_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4091;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <BufferSecurityCheck>true</BufferSecurityCheck> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <Link> + <AdditionalDependencies>shlwapi.lib;comctl32.lib;rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <SubSystem>Windows</SubSystem> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ +xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message> + </PostBuildEvent> + <ResourceCompile> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ResourceCompile> + <Manifest> + <OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile> + </Manifest> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MinSpace</Optimization> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <AdditionalIncludeDirectories>.;..;..\..\..\;..\..\..\wasabi;..\..\..\agave;..\..\..\ombrowser;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;NDEBUG;_WINDOWS;_USRDLL;ML_ONLINE_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>None</DebugInformationFormat> + <DisableSpecificWarnings>4091;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <Link> + <AdditionalDependencies>shlwapi.lib;comctl32.lib;rpcrt4.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>$(IntDir)$(TargetName).lib</ImportLibrary> + <TargetMachine>MachineX86</TargetMachine> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message> + </PostBuildEvent> + <ResourceCompile> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ResourceCompile> + <Manifest> + <OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile> + </Manifest> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <Optimization>MinSpace</Optimization> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <AdditionalIncludeDirectories>.;..;..\..\..\;..\..\..\wasabi;..\..\..\agave;..\..\..\ombrowser;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN64;NDEBUG;_WINDOWS;_USRDLL;ML_ONLINE_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>None</DebugInformationFormat> + <DisableSpecificWarnings>4091;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <Link> + <AdditionalDependencies>shlwapi.lib;comctl32.lib;rpcrt4.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>$(IntDir)$(TargetName).lib</ImportLibrary> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message> + </PostBuildEvent> + <ResourceCompile> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ResourceCompile> + <Manifest> + <OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile> + </Manifest> + </ItemDefinitionGroup> + <ItemGroup> + <ResourceCompile Include="ml_online.rc" /> + <ResourceCompile Include="png.rc" /> + <ResourceCompile Include="testPages.rc" /> + </ItemGroup> + <ItemGroup> + <None Include="resources\pages\serviceEditor.htm"> + <DeploymentContent>true</DeploymentContent> + </None> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\..\General\gen_ml\menu.cpp" /> + <ClCompile Include="..\..\..\nu\ConfigCOM.cpp"> + <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)%(Filename)1.obj</ObjectFileName> + <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)%(Filename)1.obj</ObjectFileName> + <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName> + <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)1.obj</ObjectFileName> + </ClCompile> + <ClCompile Include="..\..\..\nu\MediaLibraryInterface.cpp"> + <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)%(Filename)2.obj</ObjectFileName> + <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)%(Filename)2.obj</ObjectFileName> + <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)%(Filename)2.obj</ObjectFileName> + <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)%(Filename)2.obj</ObjectFileName> + </ClCompile> + <ClCompile Include="..\..\..\nu\menuHelpers.cpp" /> + <ClCompile Include="..\..\..\nu\menushortcuts.cpp" /> + <ClCompile Include="..\..\..\nu\sort.cpp" /> + <ClCompile Include="..\..\..\nu\trace.cpp" /> + <ClCompile Include="..\..\..\nu\windowsTheme.cpp" /> + <ClCompile Include="..\..\..\Winamp\JSAPI_CallbackParameters.cpp" /> + <ClCompile Include="browserEvent.cpp" /> + <ClCompile Include="commands.cpp" /> + <ClCompile Include="common.cpp" /> + <ClCompile Include="config.cpp" /> + <ClCompile Include="external.cpp" /> + <ClCompile Include="forceUrl.cpp" /> + <ClCompile Include="handler.cpp" /> + <ClCompile Include="importFile.cpp" /> + <ClCompile Include="importUrl.cpp" /> + <ClCompile Include="JnetCOM.cpp" /> + <ClCompile Include="JSAPI2_Creator.cpp" /> + <ClCompile Include="jsapi2_omcom.cpp" /> + <ClCompile Include="local_menu.cpp" /> + <ClCompile Include="Main.cpp" /> + <ClCompile Include="messageBox.cpp" /> + <ClCompile Include="navigation.cpp" /> + <ClCompile Include="OMCOM.cpp" /> + <ClCompile Include="Preferences.cpp" /> + <ClCompile Include="serviceHelper.cpp" /> + <ClCompile Include="serviceHost.cpp" /> + <ClCompile Include="Setup\setup.cpp" /> + <ClCompile Include="Setup\setupDetails.cpp" /> + <ClCompile Include="Setup\setupDetailsGroup.cpp" /> + <ClCompile Include="Setup\setupGroup.cpp" /> + <ClCompile Include="Setup\setupGroupFilter.cpp" /> + <ClCompile Include="Setup\setupGroupList.cpp" /> + <ClCompile Include="Setup\setupImage.cpp" /> + <ClCompile Include="Setup\setupListbox.cpp" /> + <ClCompile Include="Setup\setupListboxLabel.cpp" /> + <ClCompile Include="Setup\setupLog.cpp" /> + <ClCompile Include="Setup\setupPage.cpp" /> + <ClCompile Include="Setup\setupPageWnd.cpp" /> + <ClCompile Include="Setup\setupRecord.cpp" /> + <ClCompile Include="Setup\setupServicePanel.cpp" /> + <ClCompile Include="wasabi.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\..\General\gen_ml\menu.h" /> + <ClInclude Include="..\..\..\jnetlib\asyncdns.h" /> + <ClInclude Include="..\..\..\jnetlib\connection.h" /> + <ClInclude Include="..\..\..\jnetlib\httpget.h" /> + <ClInclude Include="..\..\..\jnetlib\listen.h" /> + <ClInclude Include="..\..\..\jnetlib\netinc.h" /> + <ClInclude Include="..\..\..\jnetlib\util.h" /> + <ClInclude Include="..\..\..\nu\ConfigCOM.h" /> + <ClInclude Include="browserEvent.h" /> + <ClInclude Include="BufferCache.h" /> + <ClInclude Include="commands.h" /> + <ClInclude Include="common.h" /> + <ClInclude Include="config.h" /> + <ClInclude Include="external.h" /> + <ClInclude Include="forceUrl.h" /> + <ClInclude Include="handler.h" /> + <ClInclude Include="import.h" /> + <ClInclude Include="JnetCOM.h" /> + <ClInclude Include="JSAPI2_Creator.h" /> + <ClInclude Include="jsapi2_omcom.h" /> + <ClInclude Include="local_menu.h" /> + <ClInclude Include="Main.h" /> + <ClInclude Include="messageBox.h" /> + <ClInclude Include="navigation.h" /> + <ClInclude Include="OMCOM.h" /> + <ClInclude Include="Preferences.h" /> + <ClInclude Include="resource.h" /> + <ClInclude Include="serviceHelper.h" /> + <ClInclude Include="serviceHost.h" /> + <ClInclude Include="Setup\setupDetails.h" /> + <ClInclude Include="Setup\setupGroup.h" /> + <ClInclude Include="Setup\SetupGroupFilter.h" /> + <ClInclude Include="Setup\setupGroupList.h" /> + <ClInclude Include="Setup\setupImage.h" /> + <ClInclude Include="Setup\setupListbox.h" /> + <ClInclude Include="Setup\setupListboxLabel.h" /> + <ClInclude Include="Setup\setupLog.h" /> + <ClInclude Include="Setup\setupPage.h" /> + <ClInclude Include="Setup\setupRecord.h" /> + <ClInclude Include="Setup\setupServicePanel.h" /> + <ClInclude Include="api__ml_online.h" /> + </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> +</Project>
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/ml_online.vcxproj.filters b/Src/Plugins/Library/ml_online/ml_online.vcxproj.filters new file mode 100644 index 00000000..6963e519 --- /dev/null +++ b/Src/Plugins/Library/ml_online/ml_online.vcxproj.filters @@ -0,0 +1,301 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <ClCompile Include="browserEvent.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="commands.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="common.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="config.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="external.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="forceUrl.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="handler.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="importFile.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="importUrl.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="JnetCOM.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="jsapi2_omcom.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="JSAPI2_Creator.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="local_menu.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Main.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="messageBox.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="navigation.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="OMCOM.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Preferences.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="serviceHelper.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="serviceHost.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Setup\setup.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Setup\setupDetails.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Setup\setupDetailsGroup.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Setup\setupGroup.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Setup\setupGroupFilter.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Setup\setupGroupList.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="wasabi.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Setup\setupServicePanel.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Setup\setupRecord.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Setup\setupPageWnd.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Setup\setupPage.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Setup\setupLog.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Setup\setupListboxLabel.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Setup\setupListbox.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Setup\setupImage.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\nu\ConfigCOM.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\Winamp\JSAPI_CallbackParameters.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\nu\MediaLibraryInterface.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\General\gen_ml\menu.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\nu\menuHelpers.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\nu\menushortcuts.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\nu\sort.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\nu\trace.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\nu\windowsTheme.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="browserEvent.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="BufferCache.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="commands.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="common.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="external.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="forceUrl.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="handler.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="import.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="JnetCOM.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="JSAPI2_Creator.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="jsapi2_omcom.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="local_menu.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Main.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="messageBox.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="navigation.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="OMCOM.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Preferences.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="resource.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="serviceHelper.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="api__ml_online.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Setup\setupServicePanel.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Setup\setupRecord.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Setup\setupPage.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Setup\setupLog.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Setup\setupListboxLabel.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Setup\setupListbox.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Setup\setupImage.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Setup\setupGroupList.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Setup\SetupGroupFilter.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Setup\setupGroup.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Setup\setupDetails.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="serviceHost.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\..\jnetlib\listen.h"> + <Filter>Header Files\jnetlibws</Filter> + </ClInclude> + <ClInclude Include="..\..\..\jnetlib\asyncdns.h"> + <Filter>Header Files\jnetlibws</Filter> + </ClInclude> + <ClInclude Include="..\..\..\jnetlib\connection.h"> + <Filter>Header Files\jnetlibws</Filter> + </ClInclude> + <ClInclude Include="..\..\..\jnetlib\httpget.h"> + <Filter>Header Files\jnetlibws</Filter> + </ClInclude> + <ClInclude Include="..\..\..\nu\ConfigCOM.h"> + <Filter>Header Files\nu</Filter> + </ClInclude> + <ClInclude Include="..\..\General\gen_ml\menu.h"> + <Filter>Header Files\gen_ml</Filter> + </ClInclude> + <ClInclude Include="..\..\..\jnetlib\netinc.h"> + <Filter>Header Files\jnetlibws</Filter> + </ClInclude> + <ClInclude Include="..\..\..\jnetlib\util.h"> + <Filter>Header Files\jnetlibws</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="ml_online.rc"> + <Filter>Ressource Files</Filter> + </ResourceCompile> + <ResourceCompile Include="png.rc"> + <Filter>Ressource Files</Filter> + </ResourceCompile> + <ResourceCompile Include="testPages.rc"> + <Filter>Ressource Files</Filter> + </ResourceCompile> + </ItemGroup> + <ItemGroup> + <Filter Include="Header Files"> + <UniqueIdentifier>{e3d16f42-4b26-4321-936a-0243e6c4f69c}</UniqueIdentifier> + </Filter> + <Filter Include="Ressource Files"> + <UniqueIdentifier>{cd0589d8-5b12-49c6-9677-6d79580e8c60}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files"> + <UniqueIdentifier>{92b2e12e-b041-4908-b10a-e7156ed3fc62}</UniqueIdentifier> + </Filter> + <Filter Include="HTM Files"> + <UniqueIdentifier>{4b199e78-6958-4855-8ac9-9d3e16a24d84}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\jnetlibws"> + <UniqueIdentifier>{888befc6-d04c-4686-907e-b74a8a1742f8}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\nu"> + <UniqueIdentifier>{981def8f-a0e5-4e28-a401-8dcf96712819}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\gen_ml"> + <UniqueIdentifier>{b7e447b3-b0b4-48d9-9da1-a65fb3f61161}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <None Include="resources\pages\serviceEditor.htm"> + <Filter>HTM Files</Filter> + </None> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/navigation.cpp b/Src/Plugins/Library/ml_online/navigation.cpp new file mode 100644 index 00000000..72019329 --- /dev/null +++ b/Src/Plugins/Library/ml_online/navigation.cpp @@ -0,0 +1,1472 @@ +#include "main.h" +#include "./navigation.h" +#include "./resource.h" +#include "./api__ml_online.h" +#include "./local_menu.h" +#include "./commands.h" +#include "./config.h" + +#include "../omBrowser/browserView.h" +#include "../winamp/wa_ipc.h" + +#include "./serviceHost.h" +#include "./serviceHelper.h" +#include "./browserEvent.h" + +#include <ifc_omservice.h> +#include <ifc_omserviceeditor.h> +#include <storageIni.h> +#include <ifc_omserviceenum.h> +#include <ifc_mlnavigationhelper.h> +#include <ifc_omserviceeventmngr.h> +#include <ifc_ombrowserwndmngr.h> +#include <ifc_ombrowserwndenum.h> +#include <ifc_ombrowsereventmngr.h> + +#include "../../General/gen_ml/menu.h" +#include "../../General/gen_ml/ml_ipc_0313.h" + +#include <vector> +#include "../nu/sort.h" + +#include <shlwapi.h> +#include <strsafe.h> +#include <algorithm> + +#define NAVITEM_PREFIX L"om_svc_" +#define E_NAVITEM_UNKNOWN E_NOINTERFACE + +typedef struct __NAVASYNCPARAM +{ + Navigation *instance; + NavigationCallback callback; + ULONG_PTR param; +}NAVASYNCPARAM; + + + +static BOOL Navigation_CheckInvariantName(LPCWSTR pszInvarian) +{ + INT cchInvariant = (NULL != pszInvarian) ? lstrlen(pszInvarian) : 0; + INT cchPrefix = ARRAYSIZE(NAVITEM_PREFIX) - 1; + return (cchInvariant > cchPrefix && + CSTR_EQUAL == CompareString(CSTR_INVARIANT, 0, NAVITEM_PREFIX, cchPrefix, pszInvarian, cchPrefix)); +} + + +Navigation::Navigation() + : ref(1), cookie(0), hRoot(NULL), hLibrary(NULL) +{ +} + +Navigation::~Navigation() +{ +} + +HRESULT Navigation::CreateInstance(Navigation **instance) +{ + if (NULL == instance) return E_POINTER; + + HRESULT hr; + + Navigation *navigation = new Navigation(); + if (NULL != navigation) + { + hr = navigation->Initialize(); + if (FAILED(hr)) + { + navigation->Release(); + navigation = NULL; + } + } + else + { + hr = E_OUTOFMEMORY; + } + + *instance = navigation; + return hr; +} + +size_t Navigation::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +size_t Navigation::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +int Navigation::QueryInterface(GUID interface_guid, void **object) +{ + if (NULL == object) return E_POINTER; + + if (IsEqualIID(interface_guid, IFC_MlNavigationCallback)) + *object = static_cast<ifc_mlnavigationcallback*>(this); + else + { + *object = NULL; + return E_NOINTERFACE; + } + if (NULL == *object) + return E_UNEXPECTED; + + AddRef(); + return S_OK; +} + +HRESULT Navigation::Initialize() +{ + hLibrary = Plugin_GetLibrary(); + if (NULL == hLibrary) return E_UNEXPECTED; + + if (0 == cookie) + { + ifc_mlnavigationhelper *navHelper; + if (NULL != OMUTILITY && SUCCEEDED(OMUTILITY->GetMlNavigationHelper(Plugin_GetLibrary(), &navHelper))) + { + navHelper->RegisterCallback(this, &cookie); + navHelper->Release(); + } + } + + ifc_omservice *service; + + MLNavCtrl_BeginUpdate(hLibrary, NUF_LOCK_TOP); + + // TODO make thie configurable? + if (SUCCEEDED(ServiceHelper_Create(ROOTSERVICE_ID, MAKEINTRESOURCE(IDS_ONLINE_SERVICES), + NULL, L"http://client.winamp.com/services", SVCF_SPECIAL | SVCF_SUBSCRIBED, 1, FALSE, &service))) + { + hRoot = CreateItemInt(NULL, service); + service->Release(); + } + + if (NULL == hRoot) + { + MLNavCtrl_EndUpdate(hLibrary); + return E_FAIL; + } + + + ifc_omserviceenum *enumerator; + if (SUCCEEDED(ServiceHelper_Load(&enumerator))) + { + ifc_omservice *service; + std::vector<ifc_omservice*> serviceList; + while (S_OK == enumerator->Next(1, &service, NULL)) + { + if (S_OK == ServiceHelper_IsSubscribed(service)) + { + serviceList.push_back(service); + } + else + service->Release(); + } + enumerator->Release(); + + size_t count = serviceList.size(); + Order(serviceList); + for(size_t i =0; i < count; i++) + { + service = serviceList[i]; + CreateItemInt(hRoot, service); + service->Release(); + } + } + + MLNavCtrl_EndUpdate(hLibrary); + + return S_OK; +} + +HRESULT Navigation::Finish() +{ + if (0 != cookie) + { + ifc_mlnavigationhelper *navHelper; + if (NULL != OMUTILITY && SUCCEEDED(OMUTILITY->GetMlNavigationHelper(Plugin_GetLibrary(), &navHelper))) + { + navHelper->UnregisterCallback(cookie); + navHelper->Release(); + } + } + + if (NULL != OMBROWSERMNGR) + { + OMBROWSERMNGR->Finish(); + } + + return S_OK; +} + +HRESULT Navigation::SaveOrder() +{ + if (NULL == hRoot || NULL == hLibrary) + return E_UNEXPECTED; + + LPSTR buffer = NULL; + INT count = MLNavItem_GetChildrenCount(hLibrary, hRoot); + if (count > 0) + { + size_t bufferMax = 11 * count; + buffer = Plugin_MallocAnsiString(bufferMax); + if (NULL == buffer) return E_OUTOFMEMORY; + *buffer = '\0'; + + LPSTR cursor = buffer; + size_t remaining = bufferMax; + + NAVITEM item; + item.cbSize = sizeof(item); + item.mask = NIMF_PARAM; + item.hItem = MLNavItem_GetChild(hLibrary, hRoot); + while (NULL != item.hItem) + { + if (FALSE != MLNavItem_GetInfo(hLibrary, &item)) + { + ifc_omservice *service = (ifc_omservice*)item.lParam; + if (NULL != service) + { + UINT serviceFlags; + if (SUCCEEDED(service->GetFlags(&serviceFlags)) && + 0 == (SVCF_SPECIAL & serviceFlags)) + { + if (cursor == buffer || + SUCCEEDED(StringCchCopyExA(cursor, remaining, ";", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE))) + { + StringCchPrintfExA(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, "%d", service->GetId()); + } + } + } + } + item.hItem = MLNavItem_GetNext(hLibrary, item.hItem); + } + + } + + Config_WriteStr("Navigation", "order", buffer); + Plugin_FreeAnsiString(buffer); + + return S_OK; +} + +//static int __fastcall Navigation_OrderComparer(const void *elem1, const void *elem2, const void *context) +//{ +// std::vector<UINT> *orderList = (std::vector<UINT>*)context; +// +// UINT serviceId; +// size_t index1, index2; +// size_t count = orderList->size(); +// +// serviceId = (*(ifc_omservice**)elem1)->GetId(); +// for (index1 = 0; index1 < count && serviceId != orderList->at(index1); index1++); +// +// serviceId = (*(ifc_omservice**)elem2)->GetId(); +// for (index2 = 0; index2 < count && serviceId != orderList->at(index2); index2++); +// +// return (INT)(index1 - index2); +//} +class Navigation_OrderComparer +{ +public: + Navigation_OrderComparer(const void* ctx) + : context(ctx) + { + } + + bool operator()(const void* elem1, const void* elem2) + { + std::vector<UINT>* orderList = (std::vector<UINT>*)context; + + UINT serviceId; + size_t index1, index2; + size_t count = orderList->size(); + + serviceId = ((ifc_omservice*)elem1)->GetId(); + for (index1 = 0; index1 < count && serviceId != orderList->at(index1); index1++); + + serviceId = ((ifc_omservice*)elem2)->GetId(); + for (index2 = 0; index2 < count && serviceId != orderList->at(index2); index2++); + + return (INT)(index1 - index2) < 0; + } + + +private: + const void* context; +}; + +HRESULT Navigation::Order(std::vector<ifc_omservice*> &list) +{ + size_t listSize = list.size(); + + if (listSize < 2) + return S_FALSE; + + //if (NULL == list) return E_INVALIDARG; + + size_t bufferMax = 16384; + LPSTR buffer = Plugin_MallocAnsiString(bufferMax); + if (NULL == buffer) return E_OUTOFMEMORY; + + UINT len = Config_ReadStr("Navigation", "order", NULL, buffer, (UINT)bufferMax); + std::vector<UINT> orderList; + + LPCSTR end = buffer + len; + LPCSTR block = buffer; + LPCSTR cursor = block; + for(;;) + { + if (cursor == end || ';' == *cursor) + { + if (block != cursor) + { + INT serviceId; + if (FALSE != StrToIntExA(block, STIF_DEFAULT, &serviceId)) + orderList.push_back(serviceId); + } + + if (cursor == end) break; + cursor++; + block = cursor; + } + cursor++; + } + + + if (0 != orderList.size()) + { + //nu::qsort(list, listSize, sizeof(ifc_omservice*), &orderList, Navigation_OrderComparer); + std::sort(list.begin(), list.end(), Navigation_OrderComparer(&orderList)); + } + + Plugin_FreeAnsiString(buffer); + return S_OK; +} + +typedef struct __IMAGEAPCPARAM +{ + LPWSTR name; + INT index; +} IMAGEAPCPARAM; + +static void CALLBACK Navigtaion_ImageChangedApc(Navigation *instance, ULONG_PTR param) +{ + IMAGEAPCPARAM *image = (IMAGEAPCPARAM*)param; + if (NULL == image) return; + + instance->ImageChanged(image->name, image->index); + + Plugin_FreeString(image->name); + free(image); +} + + +void Navigation::ImageChanged(LPCWSTR pszName, INT index) +{ + if (NULL == hRoot || NULL == hLibrary || NULL == pszName) + return; + + + DWORD libraryTID = GetWindowThreadProcessId(hLibrary, NULL); + DWORD currentTID = GetCurrentThreadId(); + if (libraryTID != currentTID) + { + if (NULL != OMUTILITY) + { + IMAGEAPCPARAM *param = (IMAGEAPCPARAM*)calloc(1, sizeof(IMAGEAPCPARAM)); + if (NULL != param) + { + param->name = Plugin_CopyString(pszName); + param->index = index; + if (FAILED(PostMainThreadCallback(Navigtaion_ImageChangedApc, (ULONG_PTR)param))) + { + free(param); + } + } + } + return; + } + + WCHAR szBuffer[2048] = {0}; + NAVITEM item = {0}; + item.cbSize = sizeof(item); + item.mask = NIMF_TEXTINVARIANT | NIMF_PARAM; + item.pszInvariant = szBuffer; + item.cchInvariantMax = ARRAYSIZE(szBuffer); + + item.hItem = hRoot; + + while (NULL != item.hItem) + { + if (FALSE != MLNavItem_GetInfo(hLibrary, &item) && + FALSE != Navigation_CheckInvariantName(item.pszInvariant)) + { + ifc_omservice *service = (ifc_omservice*)item.lParam; + if (NULL != service && + SUCCEEDED(service->GetIcon(szBuffer, ARRAYSIZE(szBuffer))) && + CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, szBuffer, -1, pszName, -1)) + { + + item.iImage = index; + item.iSelectedImage = index; + item.mask = NIMF_IMAGE | NIMF_IMAGESEL; + MLNavItem_SetInfo(hLibrary, &item); + return; + } + } + + item.hItem = (HNAVITEM)SENDMLIPC(hLibrary, + (item.hItem == hRoot) ? ML_IPC_NAVITEM_GETCHILD : ML_IPC_NAVITEM_GETNEXT, + (WPARAM)item.hItem); + + } +} + + + +BOOL Navigation::ProcessMessage(INT msg, INT_PTR param1, INT_PTR param2, INT_PTR param3, INT_PTR *result) +{ + if (msg < ML_MSG_TREE_BEGIN || msg > ML_MSG_TREE_END) + return FALSE; + + HRESULT hr; + + switch(msg) + { + case ML_MSG_TREE_ONCREATEVIEW: + { + HWND hView; + hr = OnCreateView(GetMessageItem(msg, param1), (HWND)param2, &hView); + *result = (SUCCEEDED(hr)) ? (INT_PTR)hView : NULL; + } + return TRUE; + + case ML_MSG_NAVIGATION_CONTEXTMENU: + hr = OnContextMenu(GetMessageItem(msg, param1), (HWND)param2, MAKEPOINTS(param3)); + *result = SUCCEEDED(hr); + return TRUE; + + case ML_MSG_NAVIGATION_ONDELETE: + hr = OnDeleteItem(GetMessageItem(msg, param1)); + *result = SUCCEEDED(hr); + return TRUE; + + case ML_MSG_NAVIGATION_ONENDTITLEEDIT: + hr = OnEndTitleEdit(GetMessageItem(msg, param1), (LPCWSTR)param2); + *result = SUCCEEDED(hr); + return TRUE; + + case ML_MSG_TREE_ONKEYDOWN: + hr = OnKeyDown(GetMessageItem(msg, param1), (NMTVKEYDOWN*)param2); + *result = SUCCEEDED(hr); + return TRUE; + + case ML_MSG_NAVIGATION_ONDESTROY: + OnControlDestroy(); + *result = 0; + return TRUE; + } + + return FALSE; +} + +HNAVITEM Navigation::GetActive(ifc_omservice **serviceOut) +{ + ifc_omservice *service; + HNAVITEM hActive = (NULL != hLibrary) ? MLNavCtrl_GetSelection(hLibrary) : NULL; + if (NULL == hActive || FAILED(GetService(hActive, &service))) + { + hActive = NULL; + service = NULL; + } + + if (NULL != serviceOut) + *serviceOut = service; + else if (NULL != service) + service->Release(); + + return hActive; +} + +HWND Navigation::GetActiveView(ifc_omservice **serviceOut) +{ + HWND hView = (NULL != hLibrary) ? ((HWND)SENDMLIPC(hLibrary, ML_IPC_GETCURRENTVIEW, 0)) : NULL; + if (NULL != hView) + { + WCHAR szBuffer[128] = {0}; + if (!GetClassName(hView, szBuffer, ARRAYSIZE(szBuffer)) || + CSTR_EQUAL != CompareStringW(CSTR_INVARIANT, NORM_IGNORECASE, szBuffer, -1, + L"Nullsoft_omBrowserView", -1)) + { + hView = NULL; + } + } + + ifc_omservice *service; + if (NULL == hView || FALSE == BrowserView_GetService(hView, &service)) + { + hView = NULL; + service = NULL; + } + + if (NULL != serviceOut) + *serviceOut = service; + else if (NULL != service) + service->Release(); + + return hView; +} + +HRESULT Navigation::SelectItem(HNAVITEM hItem, LPCWSTR pszUrl) +{ + if (NULL == hItem) return E_INVALIDARG; + + ifc_omservice *service; + HRESULT hr = GetService(hItem, &service); + if (FAILED(hr)) return hr; + + hr = SelectItemInt(hItem, service->GetId(), pszUrl); + service->Release(); + + return hr; +} + +HRESULT Navigation::DeleteItem(HNAVITEM hItem) +{ + if (NULL == hItem) return E_INVALIDARG; + if (NULL == hLibrary) return E_UNEXPECTED; + + ifc_omservice *service; + if (FAILED(GetService(hItem, &service))) + return E_FAIL; + + HRESULT hr; + UINT serviceFlags; + if (FAILED(service->GetFlags(&serviceFlags))) serviceFlags = 0; + if (0 == (SVCF_SPECIAL & serviceFlags)) + { + MLNavCtrl_BeginUpdate(hLibrary, 0); + HNAVITEM hSelection = MLNavCtrl_GetSelection(hLibrary); + if (hSelection == hItem) + { + HNAVITEM hNext = MLNavItem_GetNext(hLibrary, hItem); + if (NULL == hNext) + hNext = MLNavItem_GetPrevious(hLibrary, hItem); + + if (NULL != hNext) + { + MLNavItem_Select(hLibrary, hNext); + } + } + + BOOL result = MLNavCtrl_DeleteItem(hLibrary, hItem); + hr = (FALSE != result) ? S_OK : E_FAIL; + + MLNavCtrl_EndUpdate(hLibrary); + } + else + { + hr = E_FAIL; + } + + service->Release(); + + return hr; +} + +HRESULT Navigation::DeleteAll() +{ + if (NULL == hRoot || NULL == hLibrary) return E_UNEXPECTED; + + std::vector<HNAVITEM> itemList; + HNAVITEM hItem = MLNavItem_GetChild(hLibrary, hRoot); + while (NULL != hItem) + { + itemList.push_back(hItem); + hItem = MLNavItem_GetNext(hLibrary, hItem); + } + + MLNavCtrl_BeginUpdate(hLibrary, 0); + + NAVITEM item; + item.cbSize = sizeof(item); + item.mask = NIMF_PARAM; + + size_t index = itemList.size(); + while(index--) + { + item.hItem = itemList[index]; + if (FALSE != MLNavItem_GetInfo(hLibrary, &item)) + { + ifc_omservice *service = (ifc_omservice*)item.lParam; + if (NULL != service) + { + service->AddRef(); + + UINT serviceFlags; + if (SUCCEEDED(service->GetFlags(&serviceFlags)) && + 0 == (SVCF_SPECIAL & serviceFlags) && + FALSE != MLNavCtrl_DeleteItem(hLibrary, item.hItem)) + { + } + + service->Release(); + } + } + } + + MLNavCtrl_EndUpdate(hLibrary); + return S_OK; +} +HRESULT Navigation::InitializeBrowser() +{ + if (NULL == OMBROWSERMNGR) + return E_UNEXPECTED; + + HWND hWinamp = Plugin_GetWinamp(); + + HRESULT hr = OMBROWSERMNGR->Initialize(NULL, hWinamp); + if (SUCCEEDED(hr)) + { + if (S_OK == hr) + { + ifc_ombrowsereventmngr *eventManager; + if (SUCCEEDED(OMBROWSERMNGR->QueryInterface(IFC_OmBrowserEventManager, (void**)&eventManager))) + { + BrowserEvent *eventHandler; + if (SUCCEEDED(BrowserEvent::CreateInstance(&eventHandler))) + { + eventManager->RegisterHandler(eventHandler); + eventHandler->Release(); + } + eventManager->Release(); + } + } + } + return hr; +} + +HRESULT Navigation::CreatePopup(HNAVITEM hItem, HWND *hwnd) +{ + if (NULL == hwnd) return E_POINTER; + *hwnd = NULL; + + if (NULL == hLibrary) return E_UNEXPECTED; + if (NULL == hItem) return E_INVALIDARG; + + HRESULT hr; + + ifc_omservice *service; + hr = GetService(hItem, &service); + if (SUCCEEDED(hr)) + { + HWND hWinamp = Plugin_GetWinamp(); + + hr = InitializeBrowser(); + if (SUCCEEDED(hr)) + { + RECT rect; + HWND hFrame = (HWND)SENDMLIPC(hLibrary, ML_IPC_GETCURRENTVIEW, 0); + if (NULL == hFrame) hFrame = hLibrary; + if (NULL == hFrame || FALSE == GetWindowRect(hFrame, &rect)) + { + hr = E_FAIL; + } + + if (SUCCEEDED(hr)) + { + rect.left += 16; + rect.top += 16; + + hr = OMBROWSERMNGR->CreatePopup(service, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, hWinamp, NULL, 0, hwnd); + } + } + service->Release(); + } + return hr; +} + +static void CALLBACK Navigation_AsyncCallback(ULONG_PTR data) +{ + NAVASYNCPARAM *async = (NAVASYNCPARAM*)data; + if (NULL == async) return; + + async->callback(async->instance, async->param); + if (NULL != async->instance) + async->instance->Release(); + free(async); +} + +HRESULT Navigation::PostMainThreadCallback(NavigationCallback callback, ULONG_PTR param) +{ + if (NULL == callback) + return E_INVALIDARG; + + NAVASYNCPARAM *async = (NAVASYNCPARAM*)calloc(1, sizeof(NAVASYNCPARAM)); + if (NULL == async) return E_OUTOFMEMORY; + + async->instance = this; + async->callback = callback; + async->param = param; + this->AddRef(); + + HRESULT hr; + if (NULL == OMUTILITY) + hr = E_FAIL; + else + { + hr = OMUTILITY->PostMainThreadCallback(Navigation_AsyncCallback, (ULONG_PTR)async); + if (FAILED(hr)) + { + Release(); + free(async); + } + } + + return hr; +} + +static void CALLBACK Navigation_CreateItemAsyncCallback(Navigation *instance, ULONG_PTR param) +{ + ifc_omservice *service= (ifc_omservice*)param; + + if (NULL != service) + { + if (NULL != instance) + instance->CreateItem(service); + + service->Release(); + } +} + +HRESULT Navigation::CreateItemAsync(ifc_omservice *service) +{ + if (NULL == service) + return E_INVALIDARG;; + + service->AddRef(); + + HRESULT hr = PostMainThreadCallback(Navigation_CreateItemAsyncCallback, (ULONG_PTR)service); + if (FAILED(hr)) + service->Release(); + + return hr; +} + + +HRESULT Navigation::GetService(HNAVITEM hItem, ifc_omservice **service) +{ + WCHAR szBuffer[64] = {0}; + + if (NULL == service) return E_POINTER; + *service = NULL; + + if (NULL == hLibrary || NULL == hItem) + return E_INVALIDARG; + + NAVITEM itemInfo; + itemInfo.cbSize = sizeof(NAVITEM); + itemInfo.hItem = hItem; + itemInfo.pszInvariant = szBuffer; + itemInfo.cchInvariantMax = ARRAYSIZE(szBuffer); + itemInfo.mask = NIMF_PARAM | NIMF_TEXTINVARIANT; + + if (FALSE == MLNavItem_GetInfo(hLibrary, &itemInfo)) + return E_FAIL; + + if (FALSE == Navigation_CheckInvariantName(szBuffer)) + return E_NAVITEM_UNKNOWN; + + *service = (ifc_omservice*)itemInfo.lParam; + (*service)->AddRef(); + return S_OK; +} + +static void CALLBACK Navigtaion_UpdateServiceApc(Dispatchable *object, ULONG_PTR param1, ULONG_PTR param2) +{ + Navigation *navigation = (Navigation*)object; + if (NULL != navigation) + { + ifc_omservice *service = (ifc_omservice*)param1; + navigation->UpdateService(service, (UINT)param2); + if (NULL != service) service->Release(); + } +} + +HRESULT Navigation::UpdateService(ifc_omservice *service, UINT modifiedFlags) +{ + if (NULL == hLibrary) return E_UNEXPECTED; + + DWORD libraryTID = GetWindowThreadProcessId(hLibrary, NULL); + DWORD currentTID = GetCurrentThreadId(); + if (libraryTID != currentTID) + { + if (NULL != OMUTILITY) + { + service->AddRef(); + if (FAILED(OMUTILITY->PostMainThreadCallback2(Navigtaion_UpdateServiceApc, this, (ULONG_PTR)service, (ULONG_PTR)modifiedFlags))) + service->Release(); + } + return E_PENDING; + } + + HNAVITEM hItem = FindService(service->GetId(), NULL); + if (NULL == hItem) + return E_FAIL; + + if (0 != (ifc_omserviceeditor::modifiedFlags & modifiedFlags) && + S_FALSE == ServiceHelper_IsSubscribed(service)) + { + DeleteItem(hItem); + return S_OK; + } + + NAVITEM itemInfo; + itemInfo.cbSize = sizeof(NAVITEM); + itemInfo.hItem = hItem; + + itemInfo.mask = NIMF_IMAGE; + if (FALSE == MLNavItem_GetInfo(hLibrary, &itemInfo)) + itemInfo.iImage= -1; + + itemInfo.mask = 0; + + WCHAR szName[512] = {0}; + if (0 != (ifc_omserviceeditor::modifiedName & modifiedFlags) && + SUCCEEDED(service->GetName(szName, ARRAYSIZE(szName)))) + { + itemInfo.mask |= NIMF_TEXT; + itemInfo.pszText = szName; + } + + + if (0 != (ifc_omserviceeditor::modifiedIcon & modifiedFlags)) + { + ifc_mlnavigationhelper *navHelper; + if (SUCCEEDED(OMUTILITY->GetMlNavigationHelper(Plugin_GetLibrary(), &navHelper))) + { + INT iImage; + WCHAR szIcon[1024] = {0}; + if (FAILED(service->GetIcon(szIcon, ARRAYSIZE(szIcon))) || + FAILED(navHelper->QueryIndex(szIcon, &iImage, NULL))) + { + iImage = -1; + } + + if (itemInfo.iImage != iImage) + { + itemInfo.mask |= NIMF_IMAGE | NIMF_IMAGESEL; + itemInfo.iImage = iImage; + itemInfo.iSelectedImage = iImage; + } + + navHelper->Release(); + } + } + + if (0 != itemInfo.mask) + { + if (FALSE == MLNavItem_SetInfo(hLibrary, &itemInfo)) + return E_FAIL; + } + + NAVITEMINAVLIDATE invalidate; + invalidate.hItem = hItem; + invalidate.fErase = FALSE; + invalidate.prc = NULL; + MLNavItem_Invalidate(hLibrary, &invalidate); + + return S_OK; +} + +HNAVITEM Navigation::FindService(UINT serviceId, ifc_omservice **serviceOut) +{ + if (NULL == hRoot || NULL == hLibrary) + { + if (NULL != serviceOut) *serviceOut = NULL; + return NULL; + } + + WCHAR szBuffer[128] = {0}; + NAVITEM item = {0}; + item.cbSize = sizeof(item); + item.mask = NIMF_TEXTINVARIANT | NIMF_PARAM; + item.pszInvariant = szBuffer; + item.cchInvariantMax = ARRAYSIZE(szBuffer); + + item.hItem = hRoot; + + while (NULL != item.hItem) + { + if (FALSE != MLNavItem_GetInfo(hLibrary, &item) && + FALSE != Navigation_CheckInvariantName(item.pszInvariant)) + { + ifc_omservice *service = (ifc_omservice*)item.lParam; + if (NULL != service && serviceId == service->GetId()) + { + if (NULL != serviceOut) + { + *serviceOut = service; + service->AddRef(); + } + return item.hItem; + } + } + + item.hItem = (HNAVITEM)SENDMLIPC(hLibrary, + (item.hItem == hRoot) ? ML_IPC_NAVITEM_GETCHILD : ML_IPC_NAVITEM_GETNEXT, + (WPARAM)item.hItem); + + } + + if (NULL != serviceOut) *serviceOut = NULL; + return NULL; +} + +HRESULT Navigation::ShowService(UINT serviceId, LPCWSTR pszUrl) +{ + ifc_omservice *service; + HNAVITEM hItem = FindService(serviceId, &service); + if (NULL == hItem) return E_FAIL; + + HRESULT hr = SelectItemInt(hItem, serviceId, pszUrl); + service->Release(); + + return hr; +} + +HNAVITEM Navigation::CreateItem(ifc_omservice *service, int altMode) +{ + if (NULL == hLibrary || NULL == hRoot) return NULL; + return CreateItemInt(hRoot, service, altMode); +} + +HRESULT Navigation::GenerateServiceName(LPWSTR pszBuffer, INT cchBufferMax) +{ + if (NULL == pszBuffer) return E_POINTER; + *pszBuffer = L'\0'; + + if (NULL == hLibrary || NULL == hRoot) return E_UNEXPECTED; + + if (FAILED(Plugin_CopyResString(pszBuffer, cchBufferMax, MAKEINTRESOURCE(IDS_USERSERVICE_NAME)))) + return E_UNEXPECTED; + + INT cchName = lstrlen(pszBuffer); + LPWSTR pszFormat = pszBuffer + cchName; + INT cchFormatMax = cchBufferMax - cchName; + + WCHAR szText[512] = {0}; + NAVITEM item = {0}; + + item.cbSize = sizeof(item); + item.mask = NIMF_TEXT; + item.pszText = szText; + item.cchTextMax = ARRAYSIZE(szText); + + BOOL fFound = TRUE; + + for(INT index = 1; FALSE != fFound; index++) + { + fFound = FALSE; + if (FAILED(StringCchPrintf(pszFormat, cchFormatMax, L" %d", index))) + { + pszFormat = L'\0'; + return E_FAIL; + } + + item.hItem = MLNavItem_GetChild(hLibrary, hRoot); + while(NULL != item.hItem) + { + if (FALSE != MLNavItem_GetInfo(hLibrary, &item) && + CSTR_EQUAL == CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, item.pszText, -1, pszBuffer, -1)) + { + fFound = TRUE; + break; + } + item.hItem = MLNavItem_GetNext(hLibrary, item.hItem); + } + } + + return S_OK; +} + +HRESULT Navigation::CreateUserService(HNAVITEM *itemOut) +{ + HRESULT hr; + + if (NULL != itemOut) + *itemOut = NULL; + + if (NULL == hRoot) return E_FAIL; + + INT serviceId = 710; + while(NULL != FindService(serviceId, NULL)) serviceId++; + + WCHAR szName[256] = {0}; + if (FAILED(GenerateServiceName(szName, ARRAYSIZE(szName)))) + return E_FAIL; + + ifc_omservice *service; + hr = ServiceHelper_Create(serviceId, szName, NULL, L"about:blank", SVCF_SUBSCRIBED | SVCF_PREAUTHORIZED, 2, TRUE, &service); + + if (SUCCEEDED(hr)) + { + HNAVITEM hItem = CreateItem(service, 1); + if (NULL == hItem) + { + hr = E_FAIL; + } + else + { + if (NULL != itemOut) + *itemOut = hItem; + } + + service->Release(); + } + + return hr; +} + +typedef struct __ICONPATCHREC +{ + LPCWSTR iconName; + LPCWSTR resourceName; +} ICONPATCHREC; + +const static ICONPATCHREC szIconPatch[] = +{ + //{ L"11000", MAKEINTRESOURCEW(IDR_ICON_AOL)}, + { L"11001", MAKEINTRESOURCEW(IDR_ICON_SHOUTCASTRADIO)}, + /*{ L"11002", MAKEINTRESOURCEW(IDR_ICON_SHOUTCASTTV)}, + { L"11003", MAKEINTRESOURCEW(IDR_ICON_WINAMPMUSIC)}, + { L"11004", MAKEINTRESOURCEW(IDR_ICON_SINGINGFISH)}, + { L"11005", MAKEINTRESOURCEW(IDR_ICON_MUSICNOW)}, + { L"11006", MAKEINTRESOURCEW(IDR_ICON_AOL_GAMES)}, + { L"11007", MAKEINTRESOURCEW(IDR_ICON_IN2TV)}, + { L"11008", MAKEINTRESOURCEW(IDR_ICON_WINAMREMOTE)},*/ +}; + +HRESULT Navigation::PatchIconName(LPWSTR pszIcon, UINT cchMaxIconLen, ifc_omservice *service) +{ + if (NULL == pszIcon) return E_INVALIDARG; + if (L'\0' == *pszIcon) return S_FALSE; + + for(INT i = 0; i < ARRAYSIZE(szIconPatch); i++) + { + if (CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, szIconPatch[i].iconName, -1, pszIcon, -1)) + { + if (IS_INTRESOURCE(szIconPatch[i].resourceName)) + { + return Plugin_MakeResourcePath(pszIcon, cchMaxIconLen, RT_RCDATA, szIconPatch[i].resourceName, RESPATH_COMPACT); + } + return StringCchCopy(pszIcon, cchMaxIconLen, szIconPatch[i].resourceName); + } + } + + if (FALSE == PathIsURL(pszIcon) && FALSE != PathIsRelative(pszIcon)) + { + WCHAR szTemp[2048] = {0}; + HRESULT hr = StringCchCopy(szTemp, ARRAYSIZE(szTemp), pszIcon); + if (SUCCEEDED(hr)) + { + ServiceHost *serviceHost; + hr = ServiceHost::GetCachedInstance(&serviceHost); + if (SUCCEEDED(hr)) + { + WCHAR szBase[MAX_PATH] = {0}; + if (SUCCEEDED(serviceHost->GetBasePath(service, szBase, ARRAYSIZE(szBase)))) + { + if (L'\0' != szBase[0] && FALSE != PathIsRelative(szBase)) + { + LPCWSTR pszUser = (NULL != WASABI_API_APP) ? WASABI_API_APP->path_getUserSettingsPath() : NULL; + if (NULL != pszUser) + { + StringCchCopy(pszIcon, cchMaxIconLen, pszUser); + } + PathAppend(pszIcon, szBase); + } + else + { + StringCchCopy(pszIcon, cchMaxIconLen, szBase); + } + + PathAppend(pszIcon, szTemp); + } + serviceHost->Release(); + } + } + if (FAILED(hr)) + return hr; + } + + return S_FALSE; +} + +HNAVITEM Navigation::CreateItemInt(HNAVITEM hParent, ifc_omservice *service, int altMode) +{ + if (!altMode && (S_OK != ServiceHelper_IsSubscribed(service))) + return NULL; + + WCHAR szName[256] = {0}, szInvariant[64] = {0}; + if (FAILED(service->GetName(szName, ARRAYSIZE(szName)))) + return NULL; + + if (L'\0' == szName[0]) + WASABI_API_LNGSTRINGW_BUF(IDS_DEFAULT_SERVICENAME, szName, ARRAYSIZE(szName)); + + if (FAILED(StringCchPrintf(szInvariant, ARRAYSIZE(szInvariant), NAVITEM_PREFIX L"%u", service->GetId()))) + return NULL; + + NAVINSERTSTRUCT nis = {0}; + nis.hInsertAfter = NULL; + nis.hParent = hParent; + + INT iIcon = -1; + ifc_mlnavigationhelper *navHelper; + if (NULL != OMUTILITY && SUCCEEDED(OMUTILITY->GetMlNavigationHelper(Plugin_GetLibrary(), &navHelper))) + { + WCHAR szIcon[2048] = {0}; + if (FAILED(service->GetIcon(szIcon, ARRAYSIZE(szIcon))) || + FAILED(PatchIconName(szIcon, ARRAYSIZE(szIcon), service)) || + FAILED(navHelper->QueryIndex(szIcon, &iIcon, NULL))) + { + iIcon = -1; + } + navHelper->Release(); + } + + nis.item.cbSize = sizeof(NAVITEM); + nis.item.mask = NIMF_TEXT | NIMF_STYLE | NIMF_TEXTINVARIANT | NIMF_PARAM | NIMF_IMAGE | NIMF_IMAGESEL; + + nis.item.id = 0; + nis.item.pszText = szName; + nis.item.pszInvariant = szInvariant; + nis.item.lParam = (LPARAM)service; + + nis.item.style = 0; + UINT serviceFlags; + if (FAILED(service->GetFlags(&serviceFlags))) + serviceFlags = 0; + + if (0 != (SVCF_SPECIAL & serviceFlags)) + { + nis.item.style |= (NIS_HASCHILDREN | NIS_ALLOWCHILDMOVE); + iIcon = -1; + } + + nis.item.styleMask = nis.item.style; + + nis.item.iImage = iIcon; + nis.item.iSelectedImage = iIcon; + + + HNAVITEM hItem = MLNavCtrl_InsertItem(hLibrary, &nis); + if (NULL != hItem) + { + ServiceHost *serviceHost; + if (SUCCEEDED(ServiceHost::GetCachedInstance(&serviceHost))) + { + ifc_omserviceeventmngr *eventManager; + if (SUCCEEDED(service->QueryInterface(IFC_OmServiceEventMngr, (void**)&eventManager))) + { + eventManager->RegisterHandler(serviceHost); + eventManager->Release(); + } + + serviceHost->Release(); + } + + service->AddRef(); + } + + return hItem; +} + +HRESULT Navigation::SelectItemInt(HNAVITEM hItem, UINT serviceId, LPCWSTR pszUrl) +{ + if (NULL == hLibrary) return E_UNEXPECTED; + + if (NULL != pszUrl && L'\0' != *pszUrl) + { + HRESULT hr = forceUrl.Set(serviceId, pszUrl); + if (FAILED(hr)) return hr; + } + else + { + forceUrl.Remove(serviceId); + } + + if (FALSE == MLNavItem_Select(hLibrary, hItem)) + { + forceUrl.Remove(serviceId); + return E_FAIL; + } + + return S_OK; + +} +HNAVITEM Navigation::GetMessageItem(INT msg, INT_PTR param1) +{ + return (msg < ML_MSG_NAVIGATION_FIRST) ? + MLNavCtrl_FindItemById(hLibrary, param1) : + (HNAVITEM)param1; +} + +HRESULT Navigation::OnCreateView(HNAVITEM hItem, HWND hParent, HWND *hView) +{ + if (NULL == hView) return E_POINTER; + *hView = NULL; + + if (NULL == hLibrary) return E_UNEXPECTED; + if (NULL == hItem || NULL == hParent) return E_INVALIDARG; + + HRESULT hr; + + ifc_omservice *service; + hr = GetService(hItem, &service); + if (SUCCEEDED(hr)) + { + hr = InitializeBrowser(); + if (SUCCEEDED(hr)) + { + LPWSTR pszUrl; + if (S_OK != forceUrl.Peek(service->GetId(), &pszUrl)) + pszUrl = NULL; + + hr = OMBROWSERMNGR->CreateView(service, hParent, pszUrl, 0, hView); + forceUrl.FreeString(pszUrl); + } + + service->Release(); + } + return hr; +} + +HRESULT Navigation::OnContextMenu(HNAVITEM hItem, HWND hHost, POINTS pts) +{ + if (NULL == hItem || NULL == hHost) + return E_INVALIDARG; + + HWND hLibrary = Plugin_GetLibrary(); + if (NULL == hLibrary) return E_UNEXPECTED; + + HRESULT hr; + ifc_omservice *service, *activeService; + hr = GetService(hItem, &service); + if (FAILED(hr)) return hr; + + POINT pt; + POINTSTOPOINT(pt, pts); + if (-1 == pt.x || -1 == pt.y) + { + NAVITEMGETRECT itemRect; + itemRect.fItem = FALSE; + itemRect.hItem = hItem; + if (MLNavItem_GetRect(hLibrary, &itemRect)) + { + MapWindowPoints(hHost, HWND_DESKTOP, (POINT*)&itemRect.rc, 2); + pt.x = itemRect.rc.left + 2; + pt.y = itemRect.rc.top + 2; + } + } + + HWND activeView = GetActiveView(&activeService); + if (NULL == activeView) activeService = NULL; + + INT menuKind = (hItem == hRoot) ? OMMENU_GALERYCONTEXT : OMMENU_SERVICECONTEXT; + + UINT menuFlags = MCF_VIEW; + if (NULL != activeService && activeService->GetId() == service->GetId()) + menuFlags |= MCF_VIEWACTIVE; + + UINT rating; + if (OMMENU_SERVICECONTEXT == menuKind && SUCCEEDED(service->GetRating(&rating))) + menuFlags |= RATINGTOMCF(rating); + + HMENU hMenu = Menu_GetMenu(menuKind, menuFlags); + if (NULL != hMenu) + { + INT commandId = DoTrackPopup(hMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD, + pt.x, pt.y, hHost, NULL); + + Menu_ReleaseMenu(hMenu, menuKind); + + if (0 != commandId && FALSE != Command_ProcessService(activeView, service, commandId, NULL)) + commandId = 0; + + if (0 != commandId && NULL != activeView && FALSE != Command_ProcessView(activeView, commandId, NULL)) + commandId = 0; + + if (0 != commandId && FALSE != Command_ProcessGeneral(commandId, NULL)) + commandId = 0; + } + + if (NULL != activeService) + activeService->Release(); + + service->Release(); + + return hr; +} + +HRESULT Navigation::OnEndTitleEdit(HNAVITEM hItem, LPCWSTR pszNewTitle) +{ + if (NULL == hItem) return E_INVALIDARG; + if (NULL == hLibrary) return E_UNEXPECTED; + + HRESULT hr; + + ifc_omservice *service; + hr = GetService(hItem, &service); + if (SUCCEEDED(hr)) + { + if (NULL != pszNewTitle) + { + ifc_omserviceeditor *editor; + hr = service->QueryInterface(IFC_OmServiceEditor, (void**)&editor); + if (SUCCEEDED(hr)) + { + hr = editor->SetName(pszNewTitle, FALSE); + editor->Release(); + } + } + + if (SUCCEEDED(hr)) + ServiceHelper_Save(service); + + service->Release(); + } + return hr; +} + +HRESULT Navigation::OnDeleteItem(HNAVITEM hItem) +{ + if (NULL == hItem) return E_INVALIDARG; + if (NULL == hLibrary) return E_UNEXPECTED; + + WCHAR szBuffer[2048] = {0}; + NAVITEM itemInfo = {0}; + + itemInfo.cbSize = sizeof(itemInfo); + itemInfo.hItem = hItem; + itemInfo.pszInvariant = szBuffer; + itemInfo.cchInvariantMax = ARRAYSIZE(szBuffer); + itemInfo.mask = NIMF_PARAM | NIMF_TEXTINVARIANT | NIMF_IMAGE; + + if (FALSE == MLNavItem_GetInfo(hLibrary, &itemInfo)) + return E_FAIL; + if (FALSE == Navigation_CheckInvariantName(szBuffer)) + return E_NAVITEM_UNKNOWN; + + ifc_omservice *service = (ifc_omservice*)itemInfo.lParam; + + if (NULL != service) + { + if (SUCCEEDED(service->GetIcon(szBuffer, ARRAYSIZE(szBuffer)))) + { + ifc_mlnavigationhelper *navHelper; + if (SUCCEEDED(OMUTILITY->GetMlNavigationHelper(Plugin_GetLibrary(), &navHelper))) + { + navHelper->ReleaseIndex(szBuffer); + navHelper->Release(); + } + } + + ifc_ombrowserwndmngr *windowManager; + if (NULL != OMBROWSERMNGR && SUCCEEDED(OMBROWSERMNGR->QueryInterface(IFC_OmBrowserWindowManager, (void**)&windowManager))) + { + UINT serviceId = service->GetId(); + + ifc_ombrowserwndenum *windowEnum; + if (SUCCEEDED(windowManager->Enumerate(NULL, &serviceId, &windowEnum))) + { + HWND hwnd; + while (S_OK == windowEnum->Next(1, &hwnd, NULL)) + { + DestroyWindow(hwnd); + } + windowEnum->Release(); + } + + windowManager->Release(); + } + + ServiceHost *serviceHost; + if (SUCCEEDED(ServiceHost::GetCachedInstance(&serviceHost))) + { + ifc_omserviceeventmngr *eventManager; + if (SUCCEEDED(service->QueryInterface(IFC_OmServiceEventMngr, (void**)&eventManager))) + { + eventManager->UnregisterHandler(serviceHost); + eventManager->Release(); + } + serviceHost->Release(); + } + + itemInfo.mask = NIMF_PARAM; + itemInfo.lParam = 0L; + MLNavItem_SetInfo(hLibrary, &itemInfo); + + service->Release(); + } + + + + return S_OK; +} + +HRESULT Navigation::OnKeyDown(HNAVITEM hItem, NMTVKEYDOWN *pnmkd) +{ + if (NULL == hItem) return E_INVALIDARG; + if (NULL == hLibrary) return E_UNEXPECTED; + + ifc_omservice *service; + HRESULT hr = GetService(hItem, &service); + if (SUCCEEDED(hr)) + { + switch(pnmkd->wVKey) + { + case VK_DELETE: + { + BOOL fSuccess; + ifc_omservice *activeService; + HWND activeView = GetActiveView(&activeService); + if (IsWindow(activeView)) + { + Command_ProcessService(activeView, service, ID_SERVICE_UNSUBSCRIBE, &fSuccess); + } + } + break; + } + + service->Release(); + } + return hr; +} + +HRESULT Navigation::OnControlDestroy() +{ + SaveOrder(); + return S_OK; +} + +#define CBCLASS Navigation +START_DISPATCH; +CB(ADDREF, AddRef) +CB(RELEASE, Release) +CB(QUERYINTERFACE, QueryInterface) +VCB(API_IMAGECHANGED, ImageChanged) +END_DISPATCH; +#undef CBCLASS
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/navigation.h b/Src/Plugins/Library/ml_online/navigation.h new file mode 100644 index 00000000..c25682df --- /dev/null +++ b/Src/Plugins/Library/ml_online/navigation.h @@ -0,0 +1,96 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_NAVIGATION_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_NAVIGATION_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include <ifc_mlnavigationcallback.h> +#include "./forceUrl.h" +#include <vector> + +class ifc_omservice; +class forceUrl; +typedef LPVOID HNAVITEM; + +#define ROOTSERVICE_ID 777 + +typedef void (CALLBACK *NavigationCallback)(Navigation* /*instance*/, ULONG_PTR /*param*/); + +class Navigation : public ifc_mlnavigationcallback +{ +protected: + Navigation(); + ~Navigation(); + +public: + static HRESULT CreateInstance(Navigation **instance); + +public: + /* Dispatchable */ + size_t AddRef(); + size_t Release(); + int QueryInterface(GUID interface_guid, void **object); + + /* ifc_mlnavigationcallback */ + void ImageChanged(LPCWSTR pszName, INT index); + +public: + HRESULT Finish(); + + BOOL ProcessMessage(INT msg, INT_PTR param1, INT_PTR param2, INT_PTR param3, INT_PTR *result); + + HNAVITEM GetActive(ifc_omservice **serviceOut); + HWND GetActiveView(ifc_omservice **serviceOut); + + HRESULT SelectItem(HNAVITEM hItem, LPCWSTR pszUrl); + HRESULT DeleteItem(HNAVITEM hItem); + HRESULT DeleteAll(); + + HRESULT GenerateServiceName(LPWSTR pszBuffer, INT cchBufferMax); + + HRESULT CreatePopup(HNAVITEM hItem, HWND *hwnd); + + HRESULT GetService(HNAVITEM hItem, ifc_omservice **service); + HRESULT UpdateService(ifc_omservice *service, UINT modifiedFlags); + HNAVITEM FindService(UINT serviceId, ifc_omservice **serviceOut); + HRESULT ShowService(UINT serviceId, LPCWSTR pszUrl); + + HNAVITEM CreateItem(ifc_omservice *service, int altMode = 0); + HRESULT CreateItemAsync(ifc_omservice *service); + HRESULT CreateUserService(HNAVITEM *itemOut); + +protected: + HRESULT Initialize(); + HRESULT InitializeBrowser(); + HRESULT SaveOrder(); + HRESULT Order(std::vector<ifc_omservice *> &list); + + HNAVITEM GetMessageItem(INT msg, INT_PTR param1); + HNAVITEM CreateItemInt(HNAVITEM hParent, ifc_omservice *service, int altMode = 0); + HRESULT SelectItemInt(HNAVITEM hItem, UINT serviceId, LPCWSTR pszUrl); + + HRESULT PatchIconName(LPWSTR pszIcon, UINT cchMaxIconLen, ifc_omservice *service); + + HRESULT OnCreateView(HNAVITEM hItem, HWND hParent, HWND *hView); + HRESULT OnContextMenu(HNAVITEM hItem, HWND hHost, POINTS pts); + HRESULT OnEndTitleEdit(HNAVITEM hItem, LPCWSTR pszNewTitle); + HRESULT OnDeleteItem(HNAVITEM hItem); + HRESULT OnKeyDown(HNAVITEM hItem, NMTVKEYDOWN *pnmkd); + HRESULT OnControlDestroy(); + + HRESULT PostMainThreadCallback(NavigationCallback callback, ULONG_PTR param); + +protected: + size_t ref; + HNAVITEM hRoot; + HWND hLibrary; + UINT cookie; + ForceUrl forceUrl; + +protected: + RECVS_DISPATCH; +}; + +#endif // NULLOSFT_ONLINEMEDIA_PLUGIN_NAVIGATION_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/png.rc b/Src/Plugins/Library/ml_online/png.rc new file mode 100644 index 00000000..a1468d05 --- /dev/null +++ b/Src/Plugins/Library/ml_online/png.rc @@ -0,0 +1,27 @@ +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// +// Data +// +IDR_SERVICE64X64_IMAGE RCDATA +".\\resources\\service64x64.png" +IDR_ICON_DEFAULT RCDATA +".\\resources\\iconDefault.png" +//IDR_ICON_AOL RCDATA +//".\\resources\\iconAol.png" +//IDR_ICON_AOL_GAMES RCDATA +//".\\resources\\iconAolGames.png" +//IDR_ICON_IN2TV RCDATA +//".\\resources\\iconIn2Tv.png" +//IDR_ICON_MUSICNOW RCDATA +//".\\resources\\iconMusicNow.png" +IDR_ICON_SHOUTCASTRADIO RCDATA +".\\resources\\iconShoutcastRadio.png" +//IDR_ICON_SHOUTCASTTV RCDATA +//".\\resources\\iconShoutcastTv.png" +//IDR_ICON_SINGINGFISH RCDATA +//".\\resources\\iconSingingfish.png" +//IDR_ICON_WINAMPMUSIC RCDATA +//".\\resources\\iconWaMusic.png" +//IDR_ICON_WINAMREMOTE RCDATA +//".\\resources\\iconWaRemote.png" diff --git a/Src/Plugins/Library/ml_online/resource.h b/Src/Plugins/Library/ml_online/resource.h new file mode 100644 index 00000000..db9fbbde --- /dev/null +++ b/Src/Plugins/Library/ml_online/resource.h @@ -0,0 +1,206 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ml_online.rc +// +#define IDS_NULLSOFT_ONLINE_SERVICES 0 +#define IDS_ONLINE_SERVICES 1 +#define IDOK 1 +#define IDS_NO_INTERNET_CONNECTION 2 +#define IDCANCEL 2 +#define IDS_SORRY 3 +#define IDR_CONTEXTMENU 4 +#define IDD_MAINDIALOG 101 +#define IDD_OMPREF 102 +#define IDD_OPENURL 103 +#define IDS_USERSERVICE_NAME 104 +#define IDS_FILEFILTER_ALL 105 +#define IDS_FILEFILTER_ALLKNOWN 106 +#define IDS_IMPORT_FILES 109 +#define IDS_DEFAULT_SERVICENAME 148 +#define IDS_MORE 151 +#define IDS_HOME 152 +#define IDS_HOME_DESCRIPTION 153 +#define IDS_BACK 154 +#define IDS_BACK_DESCRIPTION 155 +#define IDS_FORWARD 156 +#define IDS_FORWARD_DESCRIPTION 157 +#define IDS_REFRESH 158 +#define IDS_REFRESH_DESCRIPTION 159 +#define IDS_STOP 160 +#define IDS_STOP_DESCRIPTION 161 +#define IDS_SEPARATOR 162 +#define IDS_SPACE 163 +#define IDS_FLEXSPACE 164 +#define IDS_MORE_DESCRIPTION 165 +#define IDS_RATED 166 +#define IDS_PLEASE_WAIT 167 +#define IDS_SERVICE_CHECKINGVERSION 168 +#define IDS_SERVICE_GETINFO 169 +#define IDS_SERVICE_GETINFO_DESCRIPTION 170 +#define IDS_SERVICE_REPORT 171 +#define IDS_SERVICE_REPORT_DESCRIPTION 172 +#define IDS_SERVICE_UNSUBSCRIBE 173 +#define IDS_SERVICE_UNSUBSCRIBE_DESCRIPTION 174 +#define IDS_RATING_0 175 +#define IDS_RATING_1 176 +#define IDS_RATING_2 177 +#define IDS_RATING_3 178 +#define IDS_RATING_4 179 +#define IDS_RATING_5 180 +#define IDS_RATING_CHANGETO 181 +#define IDS_RATING_CURRENT 183 +#define IDD_MESSAGEBOX 186 +#define IDD_SETUPPAGE 187 +#define IDS_SETUPPAGE_TITLE 188 +#define IDS_SETUP_EMPTYGROUP 189 +#define IDS_SETUP_LOADINGGROUP 190 +#define IDS_SERVICEGROUP_FEATURED 191 +#define IDS_SERVICEGROUP_KNOWN 192 +#define IDD_SETUP_SERVICEDETAILS 192 +#define IDS_SETUP_GROUPLOADFAILED 193 +#define IDS_SERVICE_BYAUTHOR 194 +#define IDS_SERVICE_LASTUPDATED 195 +#define IDD_SETUP_GROUPDETAILS 196 +#define IDS_SERVICEGROUP_FEATUREDLONG 197 +#define IDS_SERVICEGROUP_KNOWNLONG 198 +#define IDS_SERVICEGROUP_FEATURED_DESC 199 +#define IDS_SERVICEGROUP_KNOWN_DESC 200 +#define IDS_MESSAGEBOX_UNSUBSCRIBE 201 +#define IDS_MESSAGEBOX_UNSUBSCRIBE_CAPTION 202 +#define IDS_MESSAGEBOX_RESETTODEFAULT 203 +#define IDS_MESSAGEBOX_RESETTODEFAULT_CAPTION 204 +#define IDS_DOWNLOADSERVICE_JOB 205 +#define IDS_SAVESERVICE_JOB 206 +#define IDS_CACHEICONS_JOB 207 +#define IDS_REGISTERINGSERVICE_JOB 210 +#define IDS_MESSAGEBOX_NAMECHANGED_CAPTION 212 +#define IDS_MESSAGEBOX_NAMECHANGED 213 +#define IDR_SETUPMENU 213 +#define IDS_MESSAGEBOX_POLICYRESET_CAPTION 214 +#define IDS_MESSAGEBOX_POLICYRESET 215 +#define IDS_COLLAPSE 216 +#define IDS_EXPAND 217 +#define IDS_SECURE_CONNECTION 219 +#define IDS_SCRIPT_ERROR 220 +#define IDS_SCRIPT_ERROR_DESCRIPTION 221 +#define IDS_ENCRYPTION_UNSECURE 222 +#define IDS_ENCRYPTION_MIXED 223 +#define IDS_ENCRYPTION_40BIT 224 +#define IDS_ENCRYPTION_56BIT 225 +#define IDS_ENCRYPTION_FORTEZZA 226 +#define IDS_ENCRYPTION_128BIT 227 +#define IDS_CONNECTION_UNSECURE 229 +#define IDS_CONNECTION_ENCRYPTED 230 +#define IDR_HTML1 230 +#define IDS_NAVIGATING 231 +#define IDS_MESSAGEBOX_FORCEREMOVE 232 +#define IDS_MESSAGEBOX_FORCEREMOVE_CAPTION 233 +#define IDS_HISTORY 234 +#define IDS_HISTORY_DESCRIPTION 235 +#define IDS_CURRENT_PAGE 236 +#define IDR_BROWSERACCEL 237 +#define IDS_READMORE 238 +#define IDS_CLICKHERE 239 +#define IDS_MESSAGEBOX_DISCOVERBUSY 240 +#define IDS_MESSAGEBOX_DISCOVERBUSY_CAPTION 241 +#define IDR_HTML_EDITOR 243 +#define IDC_ADDRESS 1000 +#define IDC_REFRESH 1007 +#define IDC_RADIO_DAILY 1035 +#define IDC_RADIO_WEEKLY 1036 +#define IDC_RADIO_NEVER 1037 +#define IDC_AUTOSIZE 1052 +#define IDC_RADIO_HOURLY 1060 +#define IDC_NOWPLAYINGURL 1069 +#define IDC_RADIO_MAXBW 1071 +#define IDC_RADIO_MINBW 1072 +#define IDC_BACK 1310 +#define IDC_FORWARD 1311 +#define IDC_TEXT 1311 +#define IDC_HOME 1312 +#define IDC_SERVICELIST 1312 +#define IDC_STOP 1313 +#define IDC_LABEL_HEADER 1313 +#define IDC_PLACEHOLDER 1315 +#define IDC_DESCRIPTION 1316 +#define IDC_TITLE 1317 +#define IDC_THUMBNAIL 1318 +#define IDC_SERVICEMETA 1319 +#define IDC_STATUS 1321 +#define IDC_BUTTON1 1322 +#define IDC_HELPTEXT 1323 +#define IDR_CURTAINPROGRESS_IMAGE 20000 +#define IDR_TOOLBARLARGE_IMAGE 20001 +#define IDR_TOOLBARPROGRESS_IMAGE 20002 +#define IDR_SERVICE64X64_IMAGE 20003 +#define IDR_ICON_DEFAULT 20010 +#define IDR_ICON_AOL 20011 +#define IDR_ICON_AOL_GAMES 20012 +#define IDR_ICON_IN2TV 20013 +#define IDR_ICON_MUSICNOW 20014 +#define IDR_ICON_SHOUTCASTRADIO 20015 +#define IDR_ICON_SHOUTCASTTV 20016 +#define IDR_ICON_SINGINGFISH 20017 +#define IDR_ICON_WINAMPMUSIC 20018 +#define IDR_ICON_WINAMREMOTE 20019 +#define IDR_MENUARROW_IMAGE 20020 +#define ID_RATING_VALUE_5 40106 +#define ID_RATING_VALUE_4 40107 +#define ID_RATING_VALUE_3 40108 +#define ID_RATING_VALUE_2 40109 +#define ID_RATING_VALUE_1 40110 +#define ID_SERVICE_REPORT 40112 +#define ID_SERVICE_UNSUBSCRIBE 40113 +#define ID_SERVICE_GETINFO 40114 +#define ID_GALERY_OPENVIEW 40119 +#define ID_PLUGIN_PREFERENCES 40123 +#define ID_VIEW_OPEN 40127 +#define ID_NAVIGATION_HOME 40134 +#define ID_NAVIGATION_BACK 40135 +#define ID_NAVIGATION_FORWARD 40136 +#define ID_NAVIGATION_STOP 40138 +#define ID_SERVICEMANAGER_RESET 40141 +#define ID_NAVIGATION_REFRESH 40142 +#define ID_NAVIGATION_HISTORY 40143 +#define ID_TOOLBAR_DOCKTOP 40147 +#define ID_TOOLBAR_DOCKBOTTOM 40148 +#define ID_TOOLBAR_AUTOHIDE 40149 +#define ID_TOOLBAR_TABSTOP 40151 +#define ID_SERVICE_RESETPOLICY 40154 +#define ID_GROUP_COLLAPSE 40161 +#define ID_GROUP_SELECTALL 40162 +#define ID_GROUP_UNSELECTALL 40163 +#define ID_GROUP_TOGGLE 40164 +#define ID_GROUP_RELOAD 40166 +#define ID_BROWSER_SECURECONNECTION 40167 +#define ID_BROWSER_SCRIPTERROR 40168 +#define ID_WINDOW_FULLSCREEN 40169 +#define ID_WINDOW_CLOSE 40170 +#define ID_NAVIGATION_REFRESH_COMPLETELY 40171 +#define ID_VIEW_OPENINNEWWINDOW 40174 +#define ID_VIEW_OPENPOPUP 40175 +#define ID_GALERYCONTEXTMENU_HELP 40176 +#define ID_PLUGIN_HELP 40177 +#define ID_SERVICE_NEW 40178 +#define ID_SERVICE_IMPORT_FILE 40179 +#define ID_SERVICE_IMPORT_URL 40180 +#define ID_SERVICE_EDIT 40181 +#define ID_SERVICE_RELOAD 40182 +#define ID_SERVICE_RESETPERMISSIONS 40183 +#define ID_SERVICE_DELETE 40184 +#define ID_SERVICE_DELETEALL 40185 +#define ID_SERVICE_LOCATE 40186 +#define ID_SERVICE_EDITEXTERNAL 40187 +#define ID_OMBROWSER_OPTIONS 40188 +#define IDS_PLUGIN_NAME 65534 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 244 +#define _APS_NEXT_COMMAND_VALUE 40189 +#define _APS_NEXT_CONTROL_VALUE 1324 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Src/Plugins/Library/ml_online/resources/iconAol.png b/Src/Plugins/Library/ml_online/resources/iconAol.png Binary files differnew file mode 100644 index 00000000..c48a9cda --- /dev/null +++ b/Src/Plugins/Library/ml_online/resources/iconAol.png diff --git a/Src/Plugins/Library/ml_online/resources/iconAolGames.png b/Src/Plugins/Library/ml_online/resources/iconAolGames.png Binary files differnew file mode 100644 index 00000000..d5dce983 --- /dev/null +++ b/Src/Plugins/Library/ml_online/resources/iconAolGames.png diff --git a/Src/Plugins/Library/ml_online/resources/iconDefault.png b/Src/Plugins/Library/ml_online/resources/iconDefault.png Binary files differnew file mode 100644 index 00000000..6a2d99e6 --- /dev/null +++ b/Src/Plugins/Library/ml_online/resources/iconDefault.png diff --git a/Src/Plugins/Library/ml_online/resources/iconIn2Tv.png b/Src/Plugins/Library/ml_online/resources/iconIn2Tv.png Binary files differnew file mode 100644 index 00000000..5df2581b --- /dev/null +++ b/Src/Plugins/Library/ml_online/resources/iconIn2Tv.png diff --git a/Src/Plugins/Library/ml_online/resources/iconMusicNow.png b/Src/Plugins/Library/ml_online/resources/iconMusicNow.png Binary files differnew file mode 100644 index 00000000..ca645c9e --- /dev/null +++ b/Src/Plugins/Library/ml_online/resources/iconMusicNow.png diff --git a/Src/Plugins/Library/ml_online/resources/iconShoutcastRadio.png b/Src/Plugins/Library/ml_online/resources/iconShoutcastRadio.png Binary files differnew file mode 100644 index 00000000..72ea4648 --- /dev/null +++ b/Src/Plugins/Library/ml_online/resources/iconShoutcastRadio.png diff --git a/Src/Plugins/Library/ml_online/resources/iconShoutcastTv.png b/Src/Plugins/Library/ml_online/resources/iconShoutcastTv.png Binary files differnew file mode 100644 index 00000000..85fcfbca --- /dev/null +++ b/Src/Plugins/Library/ml_online/resources/iconShoutcastTv.png diff --git a/Src/Plugins/Library/ml_online/resources/iconSingingfish.png b/Src/Plugins/Library/ml_online/resources/iconSingingfish.png Binary files differnew file mode 100644 index 00000000..a3b7c57f --- /dev/null +++ b/Src/Plugins/Library/ml_online/resources/iconSingingfish.png diff --git a/Src/Plugins/Library/ml_online/resources/iconWaMusic.png b/Src/Plugins/Library/ml_online/resources/iconWaMusic.png Binary files differnew file mode 100644 index 00000000..32ea227a --- /dev/null +++ b/Src/Plugins/Library/ml_online/resources/iconWaMusic.png diff --git a/Src/Plugins/Library/ml_online/resources/iconWaRemote.png b/Src/Plugins/Library/ml_online/resources/iconWaRemote.png Binary files differnew file mode 100644 index 00000000..70143fe1 --- /dev/null +++ b/Src/Plugins/Library/ml_online/resources/iconWaRemote.png diff --git a/Src/Plugins/Library/ml_online/resources/pages/serviceEditor.htm b/Src/Plugins/Library/ml_online/resources/pages/serviceEditor.htm new file mode 100644 index 00000000..ea7c3bf2 --- /dev/null +++ b/Src/Plugins/Library/ml_online/resources/pages/serviceEditor.htm @@ -0,0 +1,30 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <title>Online Services Editor</title> + <meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema"/> + <meta content="True" name="vs_snapToGrid"/> + <meta content="False" name="vs_showGrid"/> + <meta http-equiv="content-type" content="text/html;charset=utf-8"/> + <script src="webdev.js" type="text/javascript"></script> + <style type="text/css">#Checkbox1 {width: 321px; top: 160px; left: 64px;}</style> +</head> +<body style="overflow-y: auto; overflow-x: auto; overflow: visible; FONT-FAMILY: MS Shell Dlg 2;" onload="WebDevEditor_Init();"> + <h2 align="center">Online Services Editor</h2> + <div align="left" nowrap> + <div id="DIV1" style="border: 1px solid gray; clear: both; DISPLAY: block; left: 50%; float: none; visibility: visible; margin-left: -204px; overflow: visible; width: 408px; color: black; position: absolute; height: 150px; background-color: dimgray; top: 126px;" align="center" nowrap ms_positioning="GridLayout"> + <div style="z-index: 110; left: 16px; position: absolute; top: 14px">Id:</div> + <input id="scvedt_edt_id" style="z-index: 101; left: 64px; position: absolute; top: 14px" readonly maxlength="16" size="9" tabindex="1"/> + <div style="z-index: 102; left: 16px; position: absolute; top: 46px">Name:</div> + <input id="scvedt_edt_name" style="z-index: 103; left: 64px; position: absolute; top: 46px; width: 322px;" maxlength="512" size="48" tabindex="2"/> + <div style="z-index: 104; left: 16px; position: absolute; top: 78px">Url:</div> + <input id="scvedt_edt_url" style="z-index: 105; left: 64px; position: absolute; top: 78px; width: 321px;" maxlength="2048" size="48" name="Text1" tabindex="3"/> + <div style="z-index: 106; left: 16px; position: absolute; top: 110px">Icon:</div> + <input id="scvedt_edt_icon" style="z-index: 107; left: 64px; position: absolute; top: 110px; width: 321px;" maxlength="512" size="48" name="Text2" tabindex="4"/> + <div align = "left" style="z-index: 108; position: absolute; width: 320px; left: 25px;" > + <input id="svcedt_btn_save" style="z-index: 109; left: 200px; width: 88px; position: absolute; top: 180px; height: 24px; right: 118px;" onclick="WebDevEditor_Save();" type="submit" value="Save" name="buttonOk" tabindex="6"/> + <input id="svcedt_btn_close" style="z-index: 110; left: 297px; width: 88px; position: absolute; top: 180px; height: 24px" onclick="WebDevEditor_Close();" type="button" value="Cancel" name="buttonCancel" tabindex="7"/> + </div> + </div> +</body> +</html>
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/resources/pages/webdev.js b/Src/Plugins/Library/ml_online/resources/pages/webdev.js new file mode 100644 index 00000000..96eb0ab9 --- /dev/null +++ b/Src/Plugins/Library/ml_online/resources/pages/webdev.js @@ -0,0 +1,95 @@ +function GetUrlParam(name) +{ + name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]"); + var regexS = "[\\?&]"+name+"=([^&#]*)"; + var regex = new RegExp( regexS ); + var results = regex.exec( window.location.href ); + if( results == null ) + return ""; + else + return results[1]; +} + +function WebDev_OpenService(serviceId, forceUrl) +{ + if (typeof(window.external.WebDev) == "undefined") + alert("Cannot access Webdev Api"); + else if (false == window.external.WebDev.serviceOpen(serviceId, forceUrl)) + alert("Unable to open service"); +} +function WebDev_OpenDocumentation() +{ + WebDev_OpenService(701, null); +} + +function WebDev_OpenJSAPI2Test() +{ + WebDev_OpenService(702, null); +} + +function WebDev_CreateService() +{ + if (typeof(window.external.WebDev) == "undefined") + alert("Cannot access Webdev Api"); + else if (false == window.external.WebDev.serviceCreate()) + alert("Unable to create service"); +} + +function WebDevEditor_Init(url) +{ + var serviceId = parseInt(GetUrlParam("serviceId"), 10); + + if (typeof(window.external.WebDev) == "undefined") + alert("Cannot access Webdev Api"); + else + { + var info = window.external.WebDev.serviceGetInfo(serviceId); + if (null == info) + { + alert("Unable to get service information"); + } + else + { + document.getElementById("scvedt_edt_id").value = info.id; + document.getElementById("scvedt_edt_name").value = info.name; + document.getElementById("scvedt_edt_url").value = info.url; + document.getElementById("scvedt_edt_icon").value = info.icon; + } + } +} + +function WebDevEditor_Save() +{ + if (typeof(window.external.WebDev) == "undefined") + alert("Cannot access Webdev Api"); + else + { + var serviceId = parseInt(document.getElementById("scvedt_edt_id").value, 10); + if (0 != serviceId) + { + var serviceName = document.getElementById("scvedt_edt_name").value; + var serviceUrl = document.getElementById("scvedt_edt_url").value; + var serviceIcon = document.getElementById("scvedt_edt_icon").value; + if (false == window.external.WebDev.serviceSetInfo(serviceId, serviceName, serviceIcon, serviceUrl, true)) + { + alert("Unable to set service info"); + } + if (false == window.external.WebDev.serviceOpen(serviceId, 1)) + { + alert("Unable to navigate"); + } + } + } +} + +function WebDevEditor_Close() +{ + if (typeof(window.external.WebDev) == "undefined") + alert("Cannot access Webdev Api"); + else + { + var serviceId = parseInt(document.getElementById("scvedt_edt_id").value, 10); + if (0 == serviceId || false == window.external.WebDev.serviceOpen(serviceId, 1)) + alert("Unable to navigate"); + } +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/resources/service64x64.png b/Src/Plugins/Library/ml_online/resources/service64x64.png Binary files differnew file mode 100644 index 00000000..8aaea002 --- /dev/null +++ b/Src/Plugins/Library/ml_online/resources/service64x64.png diff --git a/Src/Plugins/Library/ml_online/serviceHelper.cpp b/Src/Plugins/Library/ml_online/serviceHelper.cpp new file mode 100644 index 00000000..e2f24bea --- /dev/null +++ b/Src/Plugins/Library/ml_online/serviceHelper.cpp @@ -0,0 +1,1232 @@ +#include "main.h" +#include "./serviceHelper.h" +#include "./navigation.h" +#include "./api__ml_online.h" +#include "./resource.h" +#include "./serviceHost.h" + +#include <ifc_omservice.h> +#include <ifc_omfilestorage.h> +#include <ifc_omwebstorage.h> +#include <ifc_omserviceeditor.h> +#include <ifc_omserviceeventmngr.h> +#include <ifc_omservicecommand.h> +#include <ifc_omserviceenum.h> +#include <ifc_omxmlserviceenum.h> +#include <ifc_omservicecopier.h> +#include <ifc_mlnavigationhelper.h> +#include <browserUiCommon.h> + +#include <vector> + +#include <wininet.h> +#include <strsafe.h> + +typedef std::vector<ifc_omstorageasync*> AsyncList; + +struct SERVICEHELPER +{ + SERVICEHELPER() + : discoverAsync(NULL) + {} + + ifc_omstorageasync *discoverAsync; + AsyncList versionChecks; + CRITICAL_SECTION lock; +}; + +static SERVICEHELPER *serviceHelper = NULL; + +static void ServiceHelper_Lock() +{ + if (NULL != serviceHelper) + EnterCriticalSection(&serviceHelper->lock); +} + +static void ServiceHelper_Unlock() +{ + if (NULL != serviceHelper) + LeaveCriticalSection(&serviceHelper->lock); +} + +static void CALLBACK ServiceHelper_Uninitialize() +{ + if (NULL == serviceHelper) + return; + + ServiceHelper_Lock(); + + ifc_omstorage *storage = NULL;; + if (SUCCEEDED(ServiceHelper_QueryWebStorage(&storage))) + { + if (NULL != serviceHelper->discoverAsync) + { + storage->RequestAbort(serviceHelper->discoverAsync, TRUE); + storage->EndLoad(serviceHelper->discoverAsync, NULL); + serviceHelper->discoverAsync->Release(); + serviceHelper->discoverAsync = NULL; + } + + size_t index = serviceHelper->versionChecks.size(); + while(index--) + { + ifc_omstorageasync *async = serviceHelper->versionChecks[index]; + storage->RequestAbort(async, TRUE); + storage->EndLoad(async, NULL); + } + serviceHelper->versionChecks.clear(); + + storage->Release(); + } + + ServiceHelper_Unlock(); + DeleteCriticalSection(&serviceHelper->lock); + + //free(serviceHelper); + delete serviceHelper; + serviceHelper = NULL; +} + +HRESULT ServiceHelper_Initialize() +{ + if (NULL != serviceHelper) + return S_FALSE; + + //serviceHelper = (SERVICEHELPER*)calloc(1, sizeof(SERVICEHELPER)); + serviceHelper = new SERVICEHELPER(); + + if (NULL == serviceHelper) + return E_OUTOFMEMORY; + InitializeCriticalSection(&serviceHelper->lock); + + Plugin_RegisterUnloadCallback(ServiceHelper_Uninitialize); + + return S_OK; +} + +HRESULT ServiceHelper_QueryStorage(ifc_omstorage **storage) +{ + if (NULL == storage) return E_POINTER; + + if (NULL == OMSERVICEMNGR) + { + *storage = NULL; + return E_UNEXPECTED; + } + + return OMSERVICEMNGR->QueryStorage(&SUID_OmStorageIni, storage); +} + +HRESULT ServiceHelper_QueryWebStorage(ifc_omstorage **storage) +{ + if (NULL == storage) return E_POINTER; + + if (NULL == OMSERVICEMNGR) + { + *storage = NULL; + return E_UNEXPECTED; + } + + return OMSERVICEMNGR->QueryStorage(&SUID_OmStorageUrl, storage); +} + +HRESULT ServiceHelper_Create(UINT serviceId, LPCWSTR pszName, LPCWSTR pszIcon, LPCWSTR pszUrl, UINT flags, UINT generation, BOOL fSave, ifc_omservice **serviceOut) +{ + if (NULL == serviceOut) + return E_POINTER; + + *serviceOut = NULL; + + if (NULL == OMSERVICEMNGR) + return E_UNEXPECTED; + + ServiceHost *serviceHost; + if (FAILED(ServiceHost::GetCachedInstance(&serviceHost))) + serviceHost = NULL; + + HRESULT hr = OMSERVICEMNGR->CreateService(serviceId, serviceHost, serviceOut); + if (SUCCEEDED(hr)) + { + ifc_omserviceeditor *editor; + if (SUCCEEDED((*serviceOut)->QueryInterface(IFC_OmServiceEditor, (void**)&editor))) + { + WCHAR szBuffer[4096] = {0}; + editor->BeginUpdate(); + if (NULL != pszName && IS_INTRESOURCE(pszName)) + { + if (NULL != WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)pszName, szBuffer, ARRAYSIZE(szBuffer))) + editor->SetName(szBuffer, FALSE); + } + else + editor->SetName(pszName, FALSE); + + if (NULL != pszIcon && IS_INTRESOURCE(pszIcon)) + { + if (SUCCEEDED(Plugin_MakeResourcePath(szBuffer, ARRAYSIZE(szBuffer), RT_RCDATA, pszIcon, RESPATH_COMPACT))) + editor->SetIcon(szBuffer, FALSE); + } + else + editor->SetIcon(pszIcon, FALSE); + + if (NULL != pszUrl && IS_INTRESOURCE(pszUrl)) + { + if (SUCCEEDED(Plugin_MakeResourcePath(szBuffer, ARRAYSIZE(szBuffer), RT_HTML, pszUrl, RESPATH_TARGETIE | RESPATH_COMPACT))) + editor->SetUrl(szBuffer, FALSE); + } + else + editor->SetUrl(pszUrl, FALSE); + + editor->SetGeneration(generation); + + editor->SetFlags(flags, 0xFFFFFFFF); + + if (FALSE != fSave) + { + hr = ServiceHelper_Save(*serviceOut); + if (FAILED(hr)) + { + (*serviceOut)->Release(); + *serviceOut = NULL; + } + } + else + { + editor->SetModified(0, (UINT)-1); + } + editor->EndUpdate(); + editor->Release(); + } + } + + if (NULL != serviceHost) + serviceHost->Release(); + + return hr; +} + +HRESULT ServiceHelper_Save(ifc_omservice *service) +{ + if (NULL == service) + return E_INVALIDARG; + + if (NULL == OMSERVICEMNGR) + return E_UNEXPECTED; + + if (S_OK == ServiceHelper_IsSpecial(service)) + return S_FALSE; + + HRESULT hr; + ifc_omstorage *storage; + hr = ServiceHelper_QueryStorage(&storage); + if (SUCCEEDED(hr)) + { + + UINT serviceFlags; + if (SUCCEEDED(service->GetFlags(&serviceFlags)) && 0 != (SVCF_AUTOUPGRADE & serviceFlags)) + { + hr = storage->Save(&service, 1, ifc_omstorage::saveClearModified, NULL); + if (SUCCEEDED(hr)) + { + ifc_omserviceeditor *editor; + if (SUCCEEDED(service->QueryInterface(IFC_OmServiceEditor, (void**)&editor))) + { + editor->BeginUpdate(); + editor->SetFlags(0, SVCF_AUTOUPGRADE); + editor->SetModified(0, ifc_omserviceeditor::modifiedFlags); + editor->EndUpdate(); + editor->Release(); + } + } + } + else + { + hr = storage->Save(&service, 1, ifc_omstorage::saveClearModified | ifc_omstorage::saveModifiedOnly, NULL); + } + + storage->Release(); + } + return hr; +} + +HRESULT ServiceHelper_Delete(ifc_omservice *service, UINT flags) +{ + if (NULL == service) + return E_INVALIDARG; + + if (NULL == OMSERVICEMNGR) + return E_UNEXPECTED; + + if (S_OK == ServiceHelper_IsSpecial(service)) + return S_FALSE; + + HRESULT hr; + + if (S_OK == ServiceHelper_IsSubscribed(service)) + { + hr = ServiceHelper_Subscribe(service, FALSE, ((SHF_NOTIFY | SHF_VERBAL) & flags)); + if (S_OK != hr) return hr; + } + + ifc_omstorage *storage = NULL; + hr = ServiceHelper_QueryStorage(&storage); + if (SUCCEEDED(hr) && storage) + { + hr = storage->Delete(&service, 1, NULL); + storage->Release(); + } + return hr; +} + +HRESULT ServiceHelper_SetFlags(ifc_omservice *service, UINT flags, UINT flagsMask) +{ + if (NULL ==service) + return E_INVALIDARG; + + UINT serviceFlags; + HRESULT hr = service->GetFlags(&serviceFlags); + if (FAILED(hr)) return hr; + + if ((flags & flagsMask) == (serviceFlags & flagsMask)) + return S_FALSE; + + ifc_omserviceeditor *editor; + hr = service->QueryInterface(IFC_OmServiceEditor, (void**)&editor); + if (SUCCEEDED(hr)) + { + editor->SetFlags(flags, flagsMask); + editor->Release(); + } + + return hr; +} +HRESULT ServiceHelper_IsSpecial(ifc_omservice *service) +{ + if (NULL == service) return E_INVALIDARG; + + UINT flags; + HRESULT hr = service->GetFlags(&flags); + if (FAILED(hr)) return hr; + + return (0 != (SVCF_SPECIAL & flags)) ? S_OK : S_FALSE; +} + +HRESULT ServiceHelper_IsSubscribed(ifc_omservice *service) +{ + if (NULL == service) return E_INVALIDARG; + + //return S_OK; + + UINT flags; + HRESULT hr = service->GetFlags(&flags); + if (FAILED(hr)) return hr; + + return (0 != (SVCF_SUBSCRIBED & flags)) ? S_OK : S_FALSE; +} + +HRESULT ServiceHelper_IsModified(ifc_omservice *service) +{ + if (NULL == service) return E_INVALIDARG; + + HRESULT hr; + ifc_omserviceeditor *editor; + hr = service->QueryInterface(IFC_OmServiceEditor, (void**)&editor); + if (SUCCEEDED(hr)) + { + UINT modified; + hr = editor->GetModified(&modified); + if (SUCCEEDED(hr)) + { + hr = (0 == modified) ? S_FALSE : S_OK; + } + editor->Release(); + } + + return hr; +} + +HRESULT ServiceHelper_MarkModified(ifc_omservice *service, UINT modifiedFlag, UINT modifiedMask) +{ + if (NULL == service) + return E_INVALIDARG; + + HRESULT hr; + ifc_omserviceeditor *editor; + hr = service->QueryInterface(IFC_OmServiceEditor, (void**)&editor); + if (SUCCEEDED(hr)) + { + hr = editor->SetModified(modifiedFlag, modifiedMask); + editor->Release(); + } + return hr; +} +HRESULT ServiceHelper_Load(ifc_omserviceenum **enumerator) +{ + if (NULL == enumerator) + return E_POINTER; + + HRESULT hr; + ifc_omstorage *storage; + hr = ServiceHelper_QueryStorage(&storage); + if (SUCCEEDED(hr)) + { + ServiceHost *serviceHost; + if (FAILED(ServiceHost::GetCachedInstance(&serviceHost))) + serviceHost = NULL; + + hr = storage->Load(L"*.ini", serviceHost, enumerator); + + if (NULL != serviceHost) + serviceHost->Release(); + + storage->Release(); + } + + if (FAILED(hr)) + *enumerator = NULL; + + return hr; +} + +HRESULT ServiceHelper_UpdateIcon(ifc_omserviceeditor *editor, LPCWSTR pszImage) +{ + WCHAR szBuffer[8192]; + szBuffer[0] = L'\0'; + + if (NULL == editor) + return E_INVALIDARG; + + ifc_omservice *service; + if (SUCCEEDED(editor->QueryInterface(IFC_OmService, (void**)&service))) + { + if (FAILED(service->GetIcon(szBuffer, ARRAYSIZE(szBuffer)))) + szBuffer[0] = L'\0'; + service->Release(); + } + + HRESULT hr = editor->SetIcon(pszImage, FALSE); + if (FAILED(hr) || S_FALSE == hr) return hr; + + if (L'\0' != szBuffer) + { + ifc_mlnavigationhelper *navHelper; + if (SUCCEEDED(OMUTILITY->GetMlNavigationHelper(Plugin_GetLibrary(), &navHelper))) + { + navHelper->ReleaseIndex(szBuffer); + navHelper->Release(); + } + } + + return S_OK; +} + +HRESULT ServiceHelper_Find(UINT serviceId, ifc_omservice **serviceOut) +{ + if (NULL == serviceOut) return E_POINTER; + *serviceOut = NULL; + + if (0 == serviceId) + return E_INVALIDARG; + + + Navigation *navigation; + if (SUCCEEDED(Plugin_GetNavigation(&navigation))) + { + HNAVITEM hItem = navigation->FindService(serviceId, serviceOut); + navigation->Release(); + if (NULL != hItem) + return S_OK; + } + + ifc_omserviceenum *enumerator; + HRESULT hr = ServiceHelper_Load(&enumerator); + if (SUCCEEDED(hr)) + { + ifc_omservice *service; + hr = S_FALSE; + while (S_OK == enumerator->Next(1, &service, NULL)) + { + if (service->GetId() == serviceId) + { + *serviceOut = service; + hr = S_OK; + break; + } + service->Release(); + } + enumerator->Release(); + } + return hr; +} + +HRESULT ServiceHelper_SetRating(ifc_omservice *service, UINT rating, UINT flags) +{ + if (NULL == service) + return E_POINTER; + + ifc_omserviceeditor *editor; + HRESULT hr; + hr = service->QueryInterface(IFC_OmServiceEditor, (void**)&editor); + if (SUCCEEDED(hr)) + { + hr = editor->SetRating(rating); + if (S_OK == hr) + { + if (0 != (SHF_NOTIFY & flags)) + { + // send notification + + WCHAR szUrl[2048] = {0}, szClient[128] = {0}; + if (NULL == OMBROWSERMNGR || FAILED(OMBROWSERMNGR->GetClientId(szClient, ARRAYSIZE(szClient)))) + szClient[0] = L'\0'; + + hr = StringCchPrintf(szUrl, ARRAYSIZE(szUrl), + L"http://services.winamp.com/svc/rating?svc_id=%u&unique_id=%s&rating=%d", + service->GetId(), szClient, rating*2); + + if (SUCCEEDED(hr)) + { + hr = ServiceHelper_PostNotificationUrl(szUrl); + } + + } + + if (0 != (SHF_SAVE & flags)) + ServiceHelper_Save(service); + + } + editor->Release(); + } + + return hr; +} + +HRESULT ServiceHelper_PostNotificationUrl(LPCWSTR pszUrl) +{ + HRESULT hr; + ifc_omstorage *storage; + hr = ServiceHelper_QueryWebStorage(&storage); + if (SUCCEEDED(hr)) + { + ifc_omstorageasync *async; + hr = storage->BeginLoad(pszUrl, NULL, NULL, NULL, &async); + if(SUCCEEDED(hr)) + { + async->Release(); + } + storage->Release(); + } + + return hr; +} +HRESULT ServiceHelper_ResetPermissions(ifc_omservice *service, UINT flags) +{ + if (NULL == service) + return E_INVALIDARG; + + if (0 != (SHF_VERBAL & flags)) + { + WCHAR szText[1024] = {0}, szFormat[512] = {0}, szName[128] = {0}; + + service->GetName(szName, ARRAYSIZE(szName)); + WASABI_API_LNGSTRINGW_BUF(IDS_MESSAGEBOX_POLICYRESET, szFormat, ARRAYSIZE(szFormat)); + StringCchPrintf(szText, ARRAYSIZE(szText), szFormat, szName); + + if (IDNO == Plugin_MessageBox(szText, MAKEINTRESOURCE(IDS_MESSAGEBOX_POLICYRESET_CAPTION), + MB_ICONQUESTION | MB_YESNO)) + { + return S_FALSE; + } + } + + if (NULL == AGAVE_API_JSAPI2_SECURITY) + return E_UNEXPECTED; + + WCHAR szBuffer[64] = {0}; + if (FAILED(StringCchPrintfW(szBuffer, ARRAYSIZE(szBuffer), L"%u", service->GetId()))) + return E_FAIL; + + AGAVE_API_JSAPI2_SECURITY->ResetAuthorization(szBuffer); + return S_OK; +} + +HRESULT ServiceHelper_IsPreAuthorized(ifc_omservice *service) +{ + if (NULL == service) + return E_INVALIDARG; + + UINT serviceFlags; + HRESULT hr = service->GetFlags(&serviceFlags); + if (SUCCEEDED(hr)) + { + hr = (0 != (SVCF_PREAUTHORIZED & serviceFlags)) ? S_OK : S_FALSE; + } + + return hr; +} + +HRESULT ServiceHelper_Subscribe(ifc_omservice *service, BOOL subscribe, UINT flags) +{ + if (NULL == service) + return E_POINTER; + + if ((TRUE == subscribe) == (S_OK == ServiceHelper_IsSubscribed(service))) + return S_FALSE; + + HRESULT hr; + + if (FALSE == subscribe && 0 != (SHF_VERBAL & flags)) + { + WCHAR szText[1024] = {0}, szFormat[512] = {0}, szName[128] = {0}; + if (FAILED(service->GetName(szName, ARRAYSIZE(szName)))) + szName[0] = L'\0'; + + WASABI_API_LNGSTRINGW_BUF(IDS_MESSAGEBOX_UNSUBSCRIBE, szFormat, ARRAYSIZE(szFormat)); + StringCchPrintf(szText,ARRAYSIZE(szText), szFormat, szName); + + if (IDNO == Plugin_MessageBox(szText, MAKEINTRESOURCE(IDS_MESSAGEBOX_UNSUBSCRIBE_CAPTION), + MB_ICONQUESTION | MB_YESNO)) + { + return S_FALSE; + } + } + + ifc_omserviceeditor *editor = NULL; + hr = service->QueryInterface(IFC_OmServiceEditor, (void**)&editor); + if (SUCCEEDED(hr) && editor) + { + hr = editor->SetFlags((FALSE == subscribe) ? 0 : SVCF_SUBSCRIBED, SVCF_SUBSCRIBED); + if (S_OK == hr) + { + if (0 != (SHF_SAVE & flags)) + ServiceHelper_Save(service); + } + editor->Release(); + + if (FALSE == subscribe) + ServiceHelper_Delete(service, 0); + } + + if (S_OK == hr) + { + if (NULL == AGAVE_API_JSAPI2_SECURITY) + { + WCHAR szBuffer[64] = {0}; + if (SUCCEEDED(StringCchPrintfW(szBuffer, ARRAYSIZE(szBuffer), L"%u", service->GetId()))) + { + AGAVE_API_JSAPI2_SECURITY->ResetAuthorization(szBuffer); + } + } + + if (0 != (SHF_NOTIFY & flags)) + { + LPWSTR pszUrl; + UINT serviceId = service->GetId(); + LPCWSTR action = (FALSE != subscribe) ? L"add" : L"remove";; + if (NULL != action && SUCCEEDED(Plugin_BuildActionUrl(&pszUrl, action, &serviceId, 1))) + { + hr = ServiceHelper_PostNotificationUrl(pszUrl); + Plugin_FreeString(pszUrl); + } + } + } + + return hr; +} + +HRESULT ServiceHelper_ResetSubscription(UINT flags) +{ + if (S_OK == ServiceHelper_IsDiscovering()) + { + if (0 != (SHF_VERBAL & flags)) + { + Plugin_MessageBox(MAKEINTRESOURCE(IDS_MESSAGEBOX_DISCOVERBUSY), + MAKEINTRESOURCE(IDS_MESSAGEBOX_DISCOVERBUSY_CAPTION), + MB_ICONASTERISK | MB_OK); + } + + return E_PENDING; + } + + if (0 != (SHF_VERBAL & flags)) + { + if (IDNO == Plugin_MessageBox(MAKEINTRESOURCE(IDS_MESSAGEBOX_RESETTODEFAULT), + MAKEINTRESOURCE(IDS_MESSAGEBOX_RESETTODEFAULT_CAPTION), + MB_ICONQUESTION | MB_YESNO)) + { + return S_FALSE; + } + } + + HRESULT hr; + + Navigation *navigation; + if (SUCCEEDED(Plugin_GetNavigation(&navigation))) + { + navigation->DeleteAll(); + navigation->Release(); + } + + ifc_omstorage *storage; + hr = ServiceHelper_QueryStorage(&storage); + if (SUCCEEDED(hr)) + { + ifc_omserviceenum *enumerator; + hr = ServiceHelper_Load(&enumerator); + if (SUCCEEDED(hr)) + { + ifc_omservice *service; + std::vector<UINT> removeList; + while(S_OK == enumerator->Next(1, &service, NULL)) + { + if (S_OK == ServiceHelper_IsSubscribed(service)) + removeList.push_back(service->GetId()); + + ServiceHelper_ResetPermissions(service, 0); + storage->Delete(&service, 1, NULL); + service->Release(); + } + enumerator->Release(); + + if (0 != removeList.size()) + { + LPWSTR pszUrl; + if (SUCCEEDED(Plugin_BuildActionUrl(&pszUrl, L"remove", removeList.data(), removeList.size()))) + { + ServiceHelper_PostNotificationUrl(pszUrl); + Plugin_FreeString(pszUrl); + } + } + } + storage->Release(); + } + + if (SUCCEEDED(hr)) + { + // discover new services + hr = ServiceHelper_BeginDiscover(L"http://services.winamp.com/svc/default.php"); + } + + return hr; +} + +HRESULT ServiceHelper_IsDiscovering() +{ + HRESULT hr; + ServiceHelper_Lock(); + + if (NULL == serviceHelper) + { + hr = E_UNEXPECTED; + } + else + { + hr = (NULL != serviceHelper->discoverAsync) ? S_OK : S_FALSE; + } + + ServiceHelper_Unlock(); + + return hr; +} + +static void CALLBACK ServiceHelper_DiscoverComplete(ifc_omstorageasync *result) +{ + if (NULL == result) + return; + + SERVICEHELPER *helper; + if (FAILED(result->GetData((void**)&helper)) || NULL == helper) + return; + + ServiceHelper_Lock(); + + ifc_omstorage *webStorage; + HRESULT hr = ServiceHelper_QueryWebStorage(&webStorage); + if (SUCCEEDED(hr)) + { + ifc_omserviceenum *serviceEnum; + if (SUCCEEDED(webStorage->EndLoad(result, &serviceEnum))) + { + Navigation *navigation; + if (FAILED(Plugin_GetNavigation(&navigation))) + navigation = NULL; + + ifc_omstorage *localStorage; + if (SUCCEEDED(ServiceHelper_QueryStorage(&localStorage))) + { + std::vector<UINT> registerList; + + ifc_omservice *service; + while(S_OK == serviceEnum->Next(1, &service, NULL)) + { + ifc_omserviceeditor *editor; + if (SUCCEEDED(service->QueryInterface(IFC_OmServiceEditor, (void**)&editor))) + { + if (SUCCEEDED(editor->SetFlags(SVCF_SUBSCRIBED, SVCF_SUBSCRIBED))) + registerList.push_back(service->GetId()); + + editor->Release(); + } + + if (SUCCEEDED(localStorage->Save(&service, 1, ifc_omstorage::saveClearModified, NULL))) + { + navigation->CreateItemAsync(service); + } + + service->Release(); + } + + if (0 != registerList.size()) + { + LPWSTR pszUrl; + if (SUCCEEDED(Plugin_BuildActionUrl(&pszUrl, L"add", registerList.data(), registerList.size()))) + { + ServiceHelper_PostNotificationUrl(pszUrl); + Plugin_FreeString(pszUrl); + } + } + } + + if (NULL != navigation) + navigation->Release(); + + serviceEnum->Release(); + } + webStorage->Release(); + } + + + if (serviceHelper->discoverAsync == result) + { + serviceHelper->discoverAsync->Release(); + serviceHelper->discoverAsync = NULL; + } + + ServiceHelper_Unlock(); +} + +HRESULT ServiceHelper_BeginDiscover(LPCWSTR address) +{ + ifc_omstorage *storage; + HRESULT hr = ServiceHelper_QueryWebStorage(&storage); + if (FAILED(hr)) return hr; + + ServiceHost *serviceHost; + if (FAILED(ServiceHost::GetCachedInstance(&serviceHost))) + serviceHost = NULL; + + ServiceHelper_Lock(); + + if (NULL == serviceHelper->discoverAsync) + hr = storage->BeginLoad(address, serviceHost, ServiceHelper_DiscoverComplete, serviceHelper, &serviceHelper->discoverAsync); + else + hr = E_PENDING; + + ServiceHelper_Unlock(); + + storage->Release(); + + if (NULL != serviceHost) + serviceHost->Release(); + + return hr; +} +HRESULT ServiceHelper_GetDetailsUrl(LPWSTR pszBuffer, UINT cchBufferMax, ifc_omservice *service, BOOL fLite) +{ + if (NULL == pszBuffer) + return E_POINTER; + + if (0 == service) + return E_INVALIDARG; + + HRESULT hr; + size_t remaining = cchBufferMax; + LPWSTR cursor = pszBuffer; + + hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, + L"http://services.winamp.com/svc/details?svc_id=%u", service->GetId()); + + WCHAR szClient[128] = {0}; + if (SUCCEEDED(hr) && + NULL != OMBROWSERMNGR && + SUCCEEDED(OMBROWSERMNGR->GetClientId(szClient, ARRAYSIZE(szClient))) && + L'\0' != szClient[0]) + { + hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, + L"&unique_id=%s", szClient); + } + + if (FALSE != fLite && SUCCEEDED(hr)) + { + hr = StringCchCopyEx(cursor, remaining, L"&detail=lite", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE); + } + return hr; +} +static void CALLBACK ServiceHelper_VersionCheckComplete(ifc_omstorageasync *result) +{ + if (NULL == result) + return; + + ifc_omservice *target; + if (FAILED(result->GetData((void**)&target)) || NULL == target) + return; + + ServiceHelper_Lock(); + + size_t index = serviceHelper->versionChecks.size(); + while(index--) + { + if (result == serviceHelper->versionChecks[index]) + { + auto it = serviceHelper->versionChecks.begin() + index; + if (it < serviceHelper->versionChecks.end()) + { + it = serviceHelper->versionChecks.erase(it); + } + break; + } + } + + ServiceHelper_Unlock(); + + UINT originalFlags; + if (FAILED(target->GetFlags(&originalFlags))) + originalFlags = 0; + + ifc_omserviceeditor *editor; + if (SUCCEEDED(target->QueryInterface(IFC_OmServiceEditor, (void**)&editor))) + editor->BeginUpdate(); + else + editor = NULL; + + + ifc_omstorage *storage; + HRESULT hr = ServiceHelper_QueryWebStorage(&storage); + if (SUCCEEDED(hr)) + { + ifc_omserviceenum *serviceEnum; + if (SUCCEEDED(storage->EndLoad(result, &serviceEnum))) + { + ifc_omservice *source = NULL; + while(S_OK == serviceEnum->Next(1, &source, NULL)) + { + if (source->GetId() == target->GetId()) + break; + + source->Release(); + source = NULL; + } + + ifc_omxmlserviceenum *xmlServiceEnum; + if (SUCCEEDED(serviceEnum->QueryInterface(IFC_OmXmlServiceEnum, (void**)&xmlServiceEnum))) + { + UINT statusCode; + if (SUCCEEDED(xmlServiceEnum->GetStatusCode(&statusCode))) + { + switch(statusCode) + { + case 410: // force remove + if (NULL != target) + { + WCHAR szText[1024] = {0}, szFormat[512] = {0}, szName[128] = {0}; + target->GetName(szName, ARRAYSIZE(szName)); + WASABI_API_LNGSTRINGW_BUF(IDS_MESSAGEBOX_FORCEREMOVE, szFormat, ARRAYSIZE(szFormat)); + StringCchPrintf(szText,ARRAYSIZE(szText), szFormat, szName); + Plugin_MessageBox(szText, MAKEINTRESOURCE(IDS_MESSAGEBOX_FORCEREMOVE_CAPTION), MB_ICONINFORMATION | MB_OK); + ServiceHelper_Delete(target, 0); + target->Release(); + target = NULL; + } + break; + + case 200: + if (NULL != source) + { + ifc_omservicecopier *copier; + if (SUCCEEDED(source->QueryInterface(IFC_OmServiceCopier, (void**)&copier))) + { + UINT targetFlags, sourceFlags; + if (FAILED(target->GetFlags(&targetFlags))) targetFlags = 0; + if (SUCCEEDED(source->GetFlags(&sourceFlags))) + targetFlags |= sourceFlags; + + copier->CopyTo(target, NULL); + copier->Release(); + + editor->SetFlags(targetFlags, targetFlags); + } + + } + break; + } + } + xmlServiceEnum->Release(); + } + + if (NULL != source) + source->Release(); + + serviceEnum->Release(); + } + storage->Release(); + } + + if (NULL != target && NULL != AGAVE_API_JSAPI2_SECURITY) + { + WCHAR szBuffer[64] = {0}; + if (SUCCEEDED(StringCchPrintf(szBuffer, ARRAYSIZE(szBuffer), L"%u", target->GetId()))) + { + UINT flags = 0; + if (SUCCEEDED(target->GetFlags(&flags))) + { + bool bypassEnabled = (0 != (SVCF_PREAUTHORIZED & flags)); + AGAVE_API_JSAPI2_SECURITY->SetBypass(szBuffer, bypassEnabled); + } + } + } + + if (NULL != editor) + { + editor->SetFlags(SVCF_VALIDATED, SVCF_VALIDATED | SVCF_VERSIONCHECK); + + if (NULL != target) + { + UINT targetFlags; + if (FAILED(target->GetFlags(&targetFlags))) + targetFlags = 0; + + if ((targetFlags & ~ifc_omservice::RuntimeFlagsMask) == (originalFlags & ~ifc_omservice::RuntimeFlagsMask)) + editor->SetModified(0, ifc_omserviceeditor::modifiedFlags); + } + editor->EndUpdate(); + editor->Release(); + } + + if (NULL != target) + { + ifc_omserviceeventmngr *eventManager; + if (SUCCEEDED(target->QueryInterface(IFC_OmServiceEventMngr, (void**)&eventManager))) + { + eventManager->Signal_CommandStateChange(&CMDGROUP_SERVICE, SVCCOMMAND_BLOCKNAV); + eventManager->Release(); + } + + ServiceHelper_Save(target); + target->Release(); + } + +} + +HRESULT ServiceHelper_BeginVersionCheck(ifc_omservice *service) +{ + if (NULL == service) + return E_INVALIDARG; + + if (NULL == serviceHelper) + return E_UNEXPECTED; + + HRESULT hr = S_OK; + ServiceHelper_Lock(); + size_t index = serviceHelper->versionChecks.size(); + while(index--) + { + ifc_omstorageasync *async = serviceHelper->versionChecks[index]; + UINT serviceId; + if (SUCCEEDED(async->GetData((void**)&serviceId))) + { + if (serviceId == service->GetId()) + { + hr = S_FALSE; + } + } + } + + if (S_OK == hr) + { + ifc_omstorage *storage; + HRESULT hr = ServiceHelper_QueryWebStorage(&storage); + if (SUCCEEDED(hr)) + { + WCHAR szAddress[2048] = {0}; + hr = ServiceHelper_GetDetailsUrl(szAddress, ARRAYSIZE(szAddress), service, TRUE); + if (SUCCEEDED(hr)) + { + ServiceHost *serviceHost; + if (FAILED(ServiceHost::GetCachedInstance(&serviceHost))) + serviceHost = NULL; + + ifc_omserviceeditor *editor; + if (FAILED(service->QueryInterface(IFC_OmServiceEditor, (void**)&editor))) + editor = NULL; + else + { + editor->BeginUpdate(); + editor->SetFlags(SVCF_VERSIONCHECK, SVCF_VERSIONCHECK); + } + service->AddRef(); + serviceHelper->versionChecks.push_back(NULL); + //ifc_omstorageasync **pAsync = serviceHelper->versionChecks.end() - 1; + ifc_omstorageasync** pAsync = (serviceHelper->versionChecks.size() ? + &serviceHelper->versionChecks.at(serviceHelper->versionChecks.size() - 1) : 0); + hr = storage->BeginLoad(szAddress, serviceHost, ServiceHelper_VersionCheckComplete, service, pAsync); + if (FAILED(hr)) + { + service->Release(); + serviceHelper->versionChecks.pop_back(); + if (NULL != editor) + editor->SetFlags(0, SVCF_VERSIONCHECK); + } + + if (NULL != serviceHost) + serviceHost->Release(); + + if (NULL != editor) + { + editor->EndUpdate(); + editor->Release(); + } + } + storage->Release(); + } + + } + + ServiceHelper_Unlock(); + + return hr; +} +static void CALLBACK ServiceHelper_UpdateOperationInfoApc(ULONG_PTR param) +{ + HWND hBrowser = (HWND)param; + if (NULL != hBrowser && IsWindow(hBrowser)) + { + ServiceHelper_UpdateOperationInfo(hBrowser); + } +} + +HRESULT ServiceHelper_UpdateOperationInfo(HWND hBrowser) +{ + if (NULL == hBrowser) + return E_INVALIDARG; + + DWORD currentTID = GetCurrentThreadId(); + DWORD winampTID = GetWindowThreadProcessId(Plugin_GetWinamp(), NULL); + if (NULL != winampTID && winampTID != currentTID) + { + HRESULT hr; + if (NULL != OMUTILITY) + hr = OMUTILITY->PostMainThreadCallback(ServiceHelper_UpdateOperationInfoApc, (ULONG_PTR)hBrowser); + else + hr = E_FAIL; + return hr; + } + + ifc_omservice *service; + if (FALSE == BrowserControl_GetService(hBrowser, &service)) + return E_FAIL; + + UINT flags; + if (SUCCEEDED(service->GetFlags(&flags))) + { + WCHAR szText[128] = {0}, szTitle[128] = {0}; + OPERATIONINFO operation = {0}; + operation.cbSize = sizeof(operation); + operation.mask = NBCOM_FLAGS; + + if (0 == (SVCF_VERSIONCHECK & flags)) + { + operation.flags = NBCOF_HIDEWIDGET; + } + else + { + operation.mask |= (NBCOM_TITLE | NBCOM_TEXT); + operation.flags = NBCOF_SHOWWIDGET; + + WASABI_API_LNGSTRINGW_BUF(IDS_SERVICE_CHECKINGVERSION, szTitle, ARRAYSIZE(szTitle)); + operation.title = szTitle; + + WASABI_API_LNGSTRINGW_BUF(IDS_PLEASE_WAIT, szText, ARRAYSIZE(szText)); + operation.text = szText; + } + BrowserControl_ShowOperation(hBrowser, &operation); + } + service->Release(); + + return S_OK; +} +static void CALLBACK ServiceHelper_ShowWindowTimer(UINT_PTR eventId, DWORD elapsedMs, ULONG_PTR data) +{ + Plugin_KillTimer(eventId); + HWND hTarget = (HWND)data; + + if (hTarget == Plugin_GetLibrary()) + PostMessage(hTarget, WM_ML_IPC, 0, ML_IPC_ENSURE_VISIBLE); + else + ShowWindow(hTarget, SW_SHOWNORMAL); +} + +HRESULT ServiceHelper_ShowService(UINT serviceId, UINT showMode) +{ + HRESULT hr; + + BOOL serviceFound = FALSE; + ifc_omservice *service; + if (0 != serviceId && ROOTSERVICE_ID != serviceId && + S_OK == ServiceHelper_Find(serviceId, &service) && + NULL != service) + { + if (S_OK == ServiceHelper_IsSubscribed(service)) + serviceFound = TRUE; + + service->Release(); + } + + WCHAR szBuffer[INTERNET_MAX_URL_LENGTH] = {0}; + LPCWSTR pszUrl = NULL; + + if (FALSE == serviceFound) + { + if (0 != serviceId && ROOTSERVICE_ID != serviceId && + SUCCEEDED(StringCchPrintfW(szBuffer, ARRAYSIZE(szBuffer), + L"http://client.winamp.com/service/detail/gallery/%u", serviceId))) + { + pszUrl = szBuffer; + } + serviceId = ROOTSERVICE_ID; + } + + Navigation *navigation; + hr = Plugin_GetNavigation(&navigation); + if (FAILED(hr)) return hr; + + if (SHOWMODE_POPUP == showMode) + { + showMode = SHOWMODE_ENSUREVISIBLE; + if (FALSE != serviceFound) + { + HNAVITEM hItem = navigation->FindService(serviceId, NULL); + if (NULL != hItem) + { + HWND hPopup; + hr = navigation->CreatePopup(hItem, &hPopup); + if (SUCCEEDED(hr)) + { + Plugin_SetTimer(100, ServiceHelper_ShowWindowTimer, (ULONG_PTR)hPopup); + showMode = SHOWMODE_POPUP; + } + } + } + } + + if (SHOWMODE_POPUP != showMode) + { + hr = navigation->ShowService(serviceId, pszUrl); + if (SUCCEEDED(hr)) + { + if (SHOWMODE_ENSUREVISIBLE == showMode) + Plugin_SetTimer(100, ServiceHelper_ShowWindowTimer, (ULONG_PTR)Plugin_GetLibrary()); + } + } + + navigation->Release(); + return hr; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/serviceHelper.h b/Src/Plugins/Library/ml_online/serviceHelper.h new file mode 100644 index 00000000..fe09a685 --- /dev/null +++ b/Src/Plugins/Library/ml_online/serviceHelper.h @@ -0,0 +1,57 @@ +#ifndef NULLSOFT_ONLINEMEDIA_PLUGIN_SERVICE_HELPER_HEADER +#define NULLSOFT_ONLINEMEDIA_PLUGIN_SERVICE_HELPER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +class ifc_omservice; +class ifc_omserviceenum; +class ifc_omserviceeditor; +class ifc_omstorage; + +#include <ifc_omstorageasync.h> + +#define SHF_VERBAL 0x00000001 +#define SHF_NOTIFY 0x00000002 +#define SHF_SAVE 0x00000004 + +HRESULT ServiceHelper_Initialize(); + +HRESULT ServiceHelper_QueryStorage(ifc_omstorage **storage); +HRESULT ServiceHelper_QueryWebStorage(ifc_omstorage **storage); +HRESULT ServiceHelper_Load(ifc_omserviceenum **enumerator); + +HRESULT ServiceHelper_Create(UINT serviceId, LPCWSTR pszName, LPCWSTR pszIcon, LPCWSTR pszUrl, UINT flags, UINT generation, BOOL fSave, ifc_omservice **serviceOut); +HRESULT ServiceHelper_Save(ifc_omservice *service); +HRESULT ServiceHelper_Delete(ifc_omservice *service, UINT flags); +HRESULT ServiceHelper_UpdateIcon(ifc_omserviceeditor *editor, LPCWSTR pszImage); +HRESULT ServiceHelper_Find(UINT serviceId, ifc_omservice **serviceOut); + +HRESULT ServiceHelper_SetFlags(ifc_omservice *service, UINT flags, UINT flagsMask); +HRESULT ServiceHelper_IsSpecial(ifc_omservice *service); +HRESULT ServiceHelper_IsPreAuthorized(ifc_omservice *service); +HRESULT ServiceHelper_IsSubscribed(ifc_omservice *service); +HRESULT ServiceHelper_IsModified(ifc_omservice *service); +HRESULT ServiceHelper_MarkModified(ifc_omservice *service, UINT modifiedFlag, UINT modifiedMask); + +HRESULT ServiceHelper_SetRating(ifc_omservice *service, UINT rating, UINT flags); +HRESULT ServiceHelper_Subscribe(ifc_omservice *service, BOOL subscribe, UINT flags); +HRESULT ServiceHelper_ResetPermissions(ifc_omservice *service, UINT flags); +HRESULT ServiceHelper_ResetSubscription(UINT flags); +HRESULT ServiceHelper_BeginDiscover(LPCWSTR address); +HRESULT ServiceHelper_IsDiscovering(); +HRESULT ServiceHelper_BeginVersionCheck(ifc_omservice *service); + +HRESULT ServiceHelper_GetDetailsUrl(LPWSTR pszBuffer, UINT cchBufferMax, ifc_omservice *service, BOOL fLite); +HRESULT ServiceHelper_PostNotificationUrl(LPCWSTR pszUrl); +HRESULT ServiceHelper_UpdateOperationInfo(HWND hBrowser); + +#define SHOWMODE_NORMAL 0 +#define SHOWMODE_ENSUREVISIBLE 1 +#define SHOWMODE_POPUP 2 +HRESULT ServiceHelper_ShowService(UINT serviceId, UINT showMode); + +#endif //NULLSOFT_ONLINEMEDIA_PLUGIN_SERVICE_HELPER_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/serviceHost.cpp b/Src/Plugins/Library/ml_online/serviceHost.cpp new file mode 100644 index 00000000..e907e345 --- /dev/null +++ b/Src/Plugins/Library/ml_online/serviceHost.cpp @@ -0,0 +1,394 @@ +#include "main.h" +#include "./serviceHost.h" +#include "./api__ml_online.h" +#include "./resource.h" +#include "./external.h" +#include "./navigation.h" +#include "./commands.h" +#include "./serviceHelper.h" + +#include <ifc_omservice.h> +#include <ifc_omserviceeditor.h> +#include <ifc_omservicecommand.h> + +#include <ifc_omstoragehelper.h> +#include <ifc_omstoragehandlerenum.h> +#include <ifc_omfilestorage.h> + +#include "../winamp/IWasabiDispatchable.h" +#include "../winamp/JSAPI_Info.h" + +#include <shlwapi.h> +#include <strsafe.h> + + +#define IS_INVALIDISPATCH(__disp) (((IDispatch *)1) == (__disp) || NULL == (__disp)) + +static ServiceHost *cachedInstance = NULL; + +static void CALLBACK StorageHandler_ReadAuth(ifc_omservice *service, LPCWSTR pszKey, LPCWSTR pszValue) +{ + INT iVal; + UINT flags = (NULL != pszValue && + FALSE != StrToIntEx(pszValue, STIF_SUPPORT_HEX, &iVal) && + 0 != iVal) ? + SVCF_USECLIENTOWEB : 0; + + ServiceHelper_SetFlags(service, flags, SVCF_USECLIENTOWEB); +} + + +static void CALLBACK StorageHandler_ReadBypass(ifc_omservice *service, LPCWSTR pszKey, LPCWSTR pszValue) +{ + INT iVal; + UINT flags = (NULL != pszValue && + FALSE != StrToIntEx(pszValue, STIF_SUPPORT_HEX, &iVal) && + 0 != iVal) ? + SVCF_PREAUTHORIZED : 0; + + ServiceHelper_SetFlags(service, flags, SVCF_PREAUTHORIZED); + +} + +static void CALLBACK StorageHandler_ReadSubscribed(ifc_omservice *service, LPCWSTR pszKey, LPCWSTR pszValue) +{ + INT iVal; + UINT flags = (NULL != pszValue && + FALSE != StrToIntEx(pszValue, STIF_SUPPORT_HEX, &iVal) && + 0 != iVal) ? + SVCF_SUBSCRIBED : 0; + + flags |= SVCF_AUTOUPGRADE; + ServiceHelper_SetFlags(service, flags, SVCF_SUBSCRIBED | SVCF_AUTOUPGRADE); + +} + +static const ifc_omstoragehelper::TemplateRecord szStorageExtXml[] = +{ + { L"auth", StorageHandler_ReadAuth }, + { L"bypass", StorageHandler_ReadBypass }, +}; + +static const ifc_omstoragehelper::TemplateRecord szStorageExtIni[] = +{ + { L"subscribed", StorageHandler_ReadSubscribed }, +}; + +ServiceHost::ServiceHost() + : ref(1), storageExtXml(NULL), storageExtIni(NULL) +{ + +} + +ServiceHost::~ServiceHost() +{ + if (NULL != storageExtXml) + storageExtXml->Release(); + + if (NULL != storageExtIni) + storageExtIni->Release(); +} + +HRESULT ServiceHost::CreateInstance(ServiceHost **instance) +{ + if (NULL == instance) + return E_POINTER; + + *instance = new ServiceHost(); + if (NULL == instance) return E_OUTOFMEMORY; + + return S_OK; +} + +HRESULT ServiceHost::GetCachedInstance(ServiceHost **instance) +{ + if (NULL == instance) + return E_POINTER; + + + if (NULL == cachedInstance) + { + HRESULT hr = CreateInstance(&cachedInstance); + if (FAILED(hr)) + { + *instance = NULL; + return hr; + } + } + + cachedInstance->AddRef(); + *instance = cachedInstance; + return S_OK; +} + +HRESULT ServiceHost::ReleseCache() +{ + if (NULL == cachedInstance) + return S_FALSE; + + ServiceHost *t = cachedInstance; + cachedInstance = NULL; + t->Release(); + + return S_OK; +} + +size_t ServiceHost::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +size_t ServiceHost::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +int ServiceHost::QueryInterface(GUID interface_guid, void **object) +{ + if (NULL == object) return E_POINTER; + + if (IsEqualIID(interface_guid, IFC_OmServiceHost)) + *object = static_cast<ifc_omservicehost*>(this); + else if (IsEqualIID(interface_guid, IFC_OmServiceEvent)) + *object = static_cast<ifc_omserviceevent*>(this); + else if (IsEqualIID(interface_guid, IFC_OmStorageExt)) + *object = static_cast<ifc_omstorageext*>(this); + else + { + *object = NULL; + return E_NOINTERFACE; + } + + if (NULL == *object) + return E_UNEXPECTED; + + AddRef(); + return S_OK; +} + + +HRESULT ServiceHost::GetExternal(ifc_omservice *service, IDispatch **ppDispatch) +{ + if (NULL == ppDispatch) + return E_POINTER; + + if (NULL != *ppDispatch) + { + // try to connect our external + IWasabiDispatchable *pWasabi; + if (SUCCEEDED((*ppDispatch)->QueryInterface(IID_IWasabiDispatchable, (void**)&pWasabi))) + { + JSAPI::ifc_info *pInfo; + if (SUCCEEDED(pWasabi->QueryDispatchable(JSAPI::IID_JSAPI_ifc_info, (Dispatchable**)&pInfo))) + { + ExternalDispatch *pExternal; + if (SUCCEEDED(ExternalDispatch::CreateInstance(&pExternal))) + { + pInfo->AddAPI(pExternal->GetName(), pExternal); + pExternal->Release(); + } + pInfo->Release(); + } + pWasabi->Release(); + } + } + + return S_OK; +} + +HRESULT ServiceHost::GetBasePath(ifc_omservice *service, LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer) + return E_POINTER; + + return StringCchCopy(pszBuffer, cchBufferMax, L".\\Plugins\\ml\\omServices"); +} + +HRESULT ServiceHost::GetDefaultName(ifc_omservice *service, LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer) + return E_POINTER; + + if (NULL == service) + return E_INVALIDARG; + + return StringCchPrintf(pszBuffer, cchBufferMax, L"omService_{%010u}.ini", service->GetId()); +} + +HRESULT ServiceHost::QueryCommandState(ifc_omservice *service, HWND hBrowser, const GUID *commandGroup, UINT commandId) +{ + if (NULL == service || NULL == commandGroup) + return E_NOTIMPL; + + if (IsEqualGUID(*commandGroup, CMDGROUP_SERVICE)) + { + switch(commandId) + { + case SVCCOMMAND_SHOWINFO: + case SVCCOMMAND_REPORT: + case SVCCOMMAND_UNSUBSCRIBE: + case SVCCOMMAND_RATE: + if (S_FALSE == ServiceHelper_IsSpecial(service)) + { + return CMDSTATE_ENABLED; + } + return CMDSTATE_UNKNOWN; + + case SVCCOMMAND_BLOCKNAV: + { + UINT flags; + if (FAILED(service->GetFlags(&flags))) + flags = 0; + + HRESULT state = (0 == (SVCF_VERSIONCHECK & flags)) ? + CMDSTATE_DISABLED : CMDSTATE_ENABLED; + + ServiceHelper_UpdateOperationInfo(hBrowser); + return state; + } + break; + } + } + return E_NOTIMPL; +} + +HRESULT ServiceHost::ExecuteCommand(ifc_omservice *service, HWND hBrowser, const GUID *commandGroup, UINT commandId, ULONG_PTR commandArg) +{ + if (IsEqualGUID(CMDGROUP_SERVICE, *commandGroup)) + { + if (S_OK != ServiceHelper_IsSpecial(service)) + { + switch(commandId) + { + case SVCCOMMAND_SHOWINFO: Command_ShowServiceInfo(service); return S_OK; + case SVCCOMMAND_REPORT: Command_ReportService(service); return S_OK; + case SVCCOMMAND_UNSUBSCRIBE: Command_UnsubscribeService(service); return S_OK; + case SVCCOMMAND_RATE: Command_SetServiceRating(service, (UINT)commandArg); return S_OK; + } + } + } + + return E_NOTIMPL; +} + +void ServiceHost::ServiceChange(ifc_omservice *service, UINT nModified) +{ + if (NULL == service) return; + + Navigation *navigation; + if (SUCCEEDED(Plugin_GetNavigation(&navigation))) + { + navigation->UpdateService(service, nModified); + navigation->Release(); + } + +} + +HRESULT ServiceHost::EnumerateStorageExt(const GUID *storageId, ifc_omstoragehandlerenum **enumerator) +{ + if (NULL == storageId) + return E_INVALIDARG; + + if (IsEqualGUID(SUID_OmStorageXml, *storageId)) + { + if (NULL == storageExtXml) + { + ifc_omstoragehelper *storageHelper; + if (NULL != OMUTILITY && SUCCEEDED(OMUTILITY->GetStorageHelper(&storageHelper))) + { + if (FAILED(storageHelper->CreateEnumerator(szStorageExtXml, ARRAYSIZE(szStorageExtXml), &storageExtXml))) + storageExtXml = NULL; + storageHelper->Release(); + + } + + if (NULL == storageExtXml) + return E_FAIL; + } + + *enumerator = storageExtXml; + storageExtXml->AddRef(); + return S_OK; + } + else if (IsEqualGUID(SUID_OmStorageIni, *storageId)) + { + if (NULL == storageExtIni) + { + ifc_omstoragehelper *storageHelper; + if (NULL != OMUTILITY && SUCCEEDED(OMUTILITY->GetStorageHelper(&storageHelper))) + { + if (FAILED(storageHelper->CreateEnumerator(szStorageExtIni, ARRAYSIZE(szStorageExtIni), &storageExtIni))) + storageExtIni = NULL; + storageHelper->Release(); + + } + + if (NULL == storageExtIni) + return E_FAIL; + } + + *enumerator = storageExtIni; + storageExtIni->AddRef(); + return S_OK; + + } + return E_NOTIMPL; +} + +HRESULT ServiceHost::GetUrl(ifc_omservice *service, LPWSTR pszBuffer, UINT cchBufferMax) +{ + UINT flags; + if (NULL != service && SUCCEEDED(service->GetFlags(&flags)) && + 0 != (SVCF_USECLIENTOWEB & flags) && NULL != AGAVE_API_AUTH) + { + LPWSTR pszUrl = Plugin_CopyString(pszBuffer); + if (NULL == pszUrl) return E_OUTOFMEMORY; + + HRESULT hr(E_NOTIMPL); + + if (0 == AGAVE_API_AUTH->ClientToWeb(GUID_NULL, pszUrl, pszBuffer, cchBufferMax)) + hr = S_OK; + + Plugin_FreeString(pszUrl); + return hr; + } + + return E_NOTIMPL; +} + +#define CBCLASS ServiceHost +START_MULTIPATCH; + START_PATCH(MPIID_OMSVCHOST) + M_CB(MPIID_OMSVCHOST, ifc_omservicehost, ADDREF, AddRef); + M_CB(MPIID_OMSVCHOST, ifc_omservicehost, RELEASE, Release); + M_CB(MPIID_OMSVCHOST, ifc_omservicehost, QUERYINTERFACE, QueryInterface); + M_CB(MPIID_OMSVCHOST, ifc_omservicehost, API_GETEXTERNAL, GetExternal); + M_CB(MPIID_OMSVCHOST, ifc_omservicehost, API_GETBASEPATH, GetBasePath); + M_CB(MPIID_OMSVCHOST, ifc_omservicehost, API_GETDEFAULTNAME, GetDefaultName); + M_CB(MPIID_OMSVCHOST, ifc_omservicehost, API_QUERYCOMMANDSTATE, QueryCommandState); + M_CB(MPIID_OMSVCHOST, ifc_omservicehost, API_EXECUTECOMMAND, ExecuteCommand); + M_CB(MPIID_OMSVCHOST, ifc_omservicehost, API_GETURL, GetUrl); + + NEXT_PATCH(MPIID_OMSVCEVENT) + M_CB(MPIID_OMSVCEVENT, ifc_omserviceevent, ADDREF, AddRef); + M_CB(MPIID_OMSVCEVENT, ifc_omserviceevent, RELEASE, Release); + M_CB(MPIID_OMSVCEVENT, ifc_omserviceevent, QUERYINTERFACE, QueryInterface); + M_VCB(MPIID_OMSVCEVENT, ifc_omserviceevent, API_SERVICECHANGE, ServiceChange); + + NEXT_PATCH(MPIID_OMSTRGEXT) + M_CB(MPIID_OMSTRGEXT, ifc_omstorageext, ADDREF, AddRef); + M_CB(MPIID_OMSTRGEXT, ifc_omstorageext, RELEASE, Release); + M_CB(MPIID_OMSTRGEXT, ifc_omstorageext, QUERYINTERFACE, QueryInterface); + M_CB(MPIID_OMSTRGEXT, ifc_omstorageext, API_ENUMERATE, EnumerateStorageExt); + + + END_PATCH +END_MULTIPATCH; +#undef CBCLASS diff --git a/Src/Plugins/Library/ml_online/serviceHost.h b/Src/Plugins/Library/ml_online/serviceHost.h new file mode 100644 index 00000000..1e292b9f --- /dev/null +++ b/Src/Plugins/Library/ml_online/serviceHost.h @@ -0,0 +1,75 @@ +#ifndef NULLSOFT_ONLINEMEDIA_PLUGIN_SERVICE_HOST_HEADER +#define NULLSOFT_ONLINEMEDIA_PLUGIN_SERVICE_HOST_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <ifc_omservicehost.h> +#include <ifc_omserviceevent.h> +#include <ifc_omstorageext.h> +#include <bfc/multipatch.h> + +#define SVCF_SUBSCRIBED 0x00000001 + +// runtime flags +#define SVCF_SPECIAL 0x00010000 +#define SVCF_USECLIENTOWEB 0x00020000 +#define SVCF_VALIDATED 0x00040000 +#define SVCF_VERSIONCHECK 0x00080000 +#define SVCF_PREAUTHORIZED 0x00100000 +#define SVCF_AUTOUPGRADE 0x00200000 + +#define MPIID_OMSVCHOST 10 +#define MPIID_OMSVCEVENT 20 +#define MPIID_OMSTRGEXT 30 + +class ifc_omstoragehandlerenum; + +class ServiceHost : public MultiPatch<MPIID_OMSVCHOST, ifc_omservicehost>, + public MultiPatch<MPIID_OMSVCEVENT, ifc_omserviceevent>, + public MultiPatch<MPIID_OMSTRGEXT, ifc_omstorageext> +{ + +protected: + ServiceHost(); + ~ServiceHost(); + +public: + static HRESULT CreateInstance(ServiceHost **instance); + static HRESULT GetCachedInstance(ServiceHost **instance); + static HRESULT ReleseCache(); + +public: + /* Dispatchable */ + size_t AddRef(); + size_t Release(); + int QueryInterface(GUID interface_guid, void **object); + + /* ifc_omservicehost */ + HRESULT GetExternal(ifc_omservice *service, IDispatch **ppDispatch); + HRESULT GetBasePath(ifc_omservice *service, LPWSTR pszBuffer, UINT cchBufferMax); + HRESULT GetDefaultName(ifc_omservice *service, LPWSTR pszBuffer, UINT cchBufferMax); + 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); + HRESULT GetUrl(ifc_omservice *service, LPWSTR pszBuffer, UINT cchBufferMax); + + /* ifc_omsvceventhandler */ + void ServiceChange(ifc_omservice *service, UINT nModified); + + /* ifc_omstorageext */ + HRESULT EnumerateStorageExt(const GUID *storageId, ifc_omstoragehandlerenum **enumerator); + +protected: + ULONG ref; + ifc_omstoragehandlerenum *storageExtXml; + ifc_omstoragehandlerenum *storageExtIni; + +protected: + RECVS_MULTIPATCH; +}; + + + + +#endif //NULLSOFT_ONLINEMEDIA_PLUGIN_SERVICE_HOST_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/testPages.rc b/Src/Plugins/Library/ml_online/testPages.rc new file mode 100644 index 00000000..9ea955e3 --- /dev/null +++ b/Src/Plugins/Library/ml_online/testPages.rc @@ -0,0 +1,7 @@ +#include "./resource.h" +///////////////////////////////////////////////////////////////////////////// +// +// HTML +// + +WEBDEV.JS HTML ".\\resources\\pages\\webdev.js"
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/version.rc2 b/Src/Plugins/Library/ml_online/version.rc2 new file mode 100644 index 00000000..dfc40599 --- /dev/null +++ b/Src/Plugins/Library/ml_online/version.rc2 @@ -0,0 +1,39 @@ + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// +#include "../../../Winamp/buildType.h" +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,0,3,0 + 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 Media Library Plug-in" + VALUE "FileVersion", "2,0,3,0" + VALUE "InternalName", "Nullsoft Online Services" + VALUE "LegalCopyright", "Copyright © 2006-2023 Winamp SA" + VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA" + VALUE "OriginalFilename", "ml_online.dll" + VALUE "ProductName", "Winamp" + VALUE "ProductVersion", STR_WINAMP_PRODUCTVER + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/Src/Plugins/Library/ml_online/wasabi.cpp b/Src/Plugins/Library/ml_online/wasabi.cpp new file mode 100644 index 00000000..e6edf6ae --- /dev/null +++ b/Src/Plugins/Library/ml_online/wasabi.cpp @@ -0,0 +1,144 @@ +#include "main.h" +#include "./api__ml_online.h" +#include <api/service/waservicefactory.h> +#include "../nu/Singleton.h" +#include "handler.h" +#include "JSAPI2_Creator.h" + +static ULONG wasabiRef = 0; + +api_service *WASABI_API_SVC = NULL; +api_application *WASABI_API_APP = NULL; +api_config *AGAVE_API_CONFIG = NULL; +api_language *WASABI_API_LNG = NULL; +api_explorerfindfile *WASABI_API_EXPLORERFINDFILE = NULL; +api_memmgr *WASABI_API_MEMMNGR = NULL; +svc_imageLoader *pngLoaderApi = NULL; +obj_ombrowser *browserManager = NULL; +ifc_omservicemanager *serviceManager = NULL; +ifc_omutility *omUtility = NULL; +JSAPI2::api_security *AGAVE_API_JSAPI2_SECURITY = NULL; +api_auth *AGAVE_API_AUTH = 0; +static JSAPI2Factory jsapi2Factory; +HINSTANCE WASABI_API_LNG_HINST = NULL; +HINSTANCE WASABI_API_ORIG_HINST = NULL; +static BOOL fDefaultsLoaded = FALSE; +static OnlineServicesURIHandler uri_handler; +static SingletonServiceFactory<svc_urihandler, OnlineServicesURIHandler> uri_handler_factory; + +EXTERN_C const GUID pngLoaderGUID = +{ 0x5e04fb28, 0x53f5, 0x4032, { 0xbd, 0x29, 0x3, 0x2b, 0x87, 0xec, 0x37, 0x25 } }; + +void *Wasabi_QueryInterface(REFGUID interfaceGuid) +{ + waServiceFactory *serviceFactory = WASABI_API_SVC->service_getServiceByGuid(interfaceGuid); + return (NULL != serviceFactory) ? serviceFactory->getInterface() : NULL; +} + +void Wasabi_ReleaseInterface(REFGUID interfaceGuid, void *pInstance) +{ + if (NULL == pInstance) return; + waServiceFactory *serviceFactory = WASABI_API_SVC->service_getServiceByGuid(interfaceGuid); + if (NULL != serviceFactory) serviceFactory->releaseInterface(pInstance); +} + + +HRESULT WasabiApi_Initialize(HINSTANCE hInstance, api_service *serviceApi) +{ + if (NULL != WASABI_API_SVC) + return S_FALSE; + + fDefaultsLoaded = FALSE; + + WASABI_API_SVC = serviceApi; + if ((api_service *)1 == WASABI_API_SVC) + WASABI_API_SVC = NULL; + + if (NULL == WASABI_API_SVC) + return E_FAIL; + + WASABI_API_ORIG_HINST = hInstance; + WASABI_API_LNG_HINST = WASABI_API_ORIG_HINST; + + WasabiApi_AddRef(); + return S_OK; +} + +HRESULT WasabiApi_LoadDefaults() +{ + if (NULL == WASABI_API_SVC) + return E_UNEXPECTED; + + if (FALSE != fDefaultsLoaded) + return S_FALSE; + + WASABI_API_APP = QueryWasabiInterface(api_application, applicationApiServiceGuid); + WASABI_API_LNG = QueryWasabiInterface(api_language, languageApiGUID); + WASABI_API_EXPLORERFINDFILE = QueryWasabiInterface(api_explorerfindfile, ExplorerFindFileApiGUID); + AGAVE_API_CONFIG = QueryWasabiInterface(api_config, AgaveConfigGUID); + AGAVE_API_JSAPI2_SECURITY = QueryWasabiInterface(JSAPI2::api_security, JSAPI2::api_securityGUID); + OMBROWSERMNGR = QueryWasabiInterface(obj_ombrowser, OBJ_OmBrowser); + OMSERVICEMNGR = QueryWasabiInterface(ifc_omservicemanager, IFC_OmServiceManager); + OMUTILITY = QueryWasabiInterface(ifc_omutility, IFC_OmUtility); + AGAVE_API_AUTH = QueryWasabiInterface(api_auth, AuthApiGUID); + + if (NULL != WASABI_API_LNG) + WASABI_API_LNG_HINST = WASABI_API_LNG->StartLanguageSupport(WASABI_API_ORIG_HINST, MlOnlineLangGUID); + + WASABI_API_SVC->service_register(&jsapi2Factory); + uri_handler_factory.Register(WASABI_API_SVC, &uri_handler); + + fDefaultsLoaded = TRUE; + return S_OK; +} + +static void WasabiApi_Uninitialize() +{ + if (NULL != WASABI_API_SVC) + { + ReleaseWasabiInterface(applicationApiServiceGuid, WASABI_API_APP); + ReleaseWasabiInterface(languageApiGUID, WASABI_API_LNG); + ReleaseWasabiInterface(ExplorerFindFileApiGUID, WASABI_API_EXPLORERFINDFILE); + ReleaseWasabiInterface(AgaveConfigGUID, AGAVE_API_CONFIG); + ReleaseWasabiInterface(memMgrApiServiceGuid, WASABI_API_MEMMNGR); + ReleaseWasabiInterface(pngLoaderGUID, WASABI_API_PNGLOADER); + ReleaseWasabiInterface(JSAPI2::api_securityGUID, AGAVE_API_JSAPI2_SECURITY); + ReleaseWasabiInterface(AuthApiGUID, AGAVE_API_AUTH); + ReleaseWasabiInterface(OBJ_OmBrowser, OMBROWSERMNGR); + ReleaseWasabiInterface(IFC_OmServiceManager, OMSERVICEMNGR); + ReleaseWasabiInterface(IFC_OmUtility, OMUTILITY); + WASABI_API_SVC->service_deregister(&jsapi2Factory); + uri_handler_factory.Deregister(WASABI_API_SVC); + } + + WASABI_API_SVC = NULL; + WASABI_API_APP = NULL; + WASABI_API_LNG = NULL; + WASABI_API_EXPLORERFINDFILE = NULL; + AGAVE_API_CONFIG = NULL; + AGAVE_API_JSAPI2_SECURITY = NULL; + AGAVE_API_AUTH = NULL; + OMBROWSERMNGR = NULL; + OMSERVICEMNGR = NULL; + OMUTILITY = NULL; + + fDefaultsLoaded = FALSE; +} + +ULONG WasabiApi_AddRef() +{ + return InterlockedIncrement((LONG*)&wasabiRef); +} + +ULONG WasabiApi_Release() +{ + if (0 == wasabiRef) + return wasabiRef; + + LONG r = InterlockedDecrement((LONG*)&wasabiRef); + if (0 == r) + { + WasabiApi_Uninitialize(); + } + return r; +}
\ No newline at end of file |