123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571 |
- //#define PLUGIN_NAME "Nullsoft PlaysForSure Plug-in"
- #define PLUGIN_VERSION L"0.99.1"
- //#define _WIN32_WINNT 0x0400
- #define _WIN32_DCOM
- #define INITGUID
- #include "P4SDevice.h"
- #include "..\..\General\gen_ml/itemlist.h"
- #include "key-sub-523.c" // This key is the authentication key.
- #include "mswmdm.h"
- #include "deviceprovider.h"
- #include "../nu/threadpool/api_threadpool.h"
- //#include "key.c"
- C_ItemList devices;
- // wasabi based services for localisation support
- api_language *WASABI_API_LNG = 0;
- HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
- api_memmgr *memoryManager=0;
- api_albumart *AGAVE_API_ALBUMART=0;
- api_threadpool *WASABI_API_THREADPOOL = 0;
- api_devicemanager *AGAVE_API_DEVICEMANAGER = 0;
- int init();
- void quit();
- intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3);
- PMPDevicePlugin plugin = {PMPHDR_VER,0,init,quit,MessageProc};
- void checkForDevices(BOOL *killSwitch);
- void gotDevice(IWMDMDevice* pIDevice);
- CRITICAL_SECTION csTransfers;
- static DeviceProvider *deviceProvider = NULL;
- static IWMDeviceManager3* pIdvMgr=NULL;
- static DWORD ConnectionNotificationCookie = 0;
- CSecureChannelClient SAC;
- IWMDRMDeviceApp * DRMDeviceApp = NULL;
- HANDLE killEvent = 0;
- static int ThreadInitFunc(HANDLE handle, void *user_data, intptr_t param);
- static int ThreadQuitFunc(HANDLE handle, void *user_data, intptr_t param);
- HANDLE hWinampThread=NULL;
- class MyNotification : public IWMDMNotification {
- public:
- virtual HRESULT STDMETHODCALLTYPE WMDMMessage(DWORD dwMessageType, LPCWSTR pwszCanonicalName) {
- switch(dwMessageType) {
- case WMDM_MSG_DEVICE_ARRIVAL: // WMDM device has been plugged in
- //OutputDebugString(L"Device arrived (IWMN)");
- if (NULL == deviceProvider ||
- FAILED(deviceProvider->BeginDiscovery(AGAVE_API_DEVICEMANAGER)))
- {
- checkForDevices(NULL);
- }
- break;
- case WMDM_MSG_DEVICE_REMOVAL: // WMDM device has been removed
- //OutputDebugString(L"Device removed (IWMN)");
- for(int i=0; i<devices.GetSize(); i++) {
- wchar_t devName[256] = {0};
- ((P4SDevice *)devices.Get(i))->WMDevice->GetCanonicalName(devName,256);
- if(wcscmp(pwszCanonicalName,devName) == 0) {
- ((P4SDevice *)devices.Get(i))->Close();
- }
- }
- break;
- case WMDM_MSG_MEDIA_ARRIVAL: // Media has been inserted in WMDM device
- WMDMMessage(WMDM_MSG_DEVICE_REMOVAL,pwszCanonicalName);
- WMDMMessage(WMDM_MSG_DEVICE_ARRIVAL,pwszCanonicalName);
- break;
- case WMDM_MSG_MEDIA_REMOVAL: // Media is removed from WMDM device
- WMDMMessage(WMDM_MSG_DEVICE_REMOVAL,pwszCanonicalName);
- WMDMMessage(WMDM_MSG_DEVICE_ARRIVAL,pwszCanonicalName);
- break;
- }
- return S_OK;
- }
- // COM shit
- ULONG refs;
- MyNotification() {refs=1;}
- #define IMPLEMENTS(ifc) if (riid == IID_ ## ifc) { ++refs; *ppvObject = static_cast<ifc *>(this); return S_OK; }
- virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,void __RPC_FAR *__RPC_FAR *ppvObject) {
- IMPLEMENTS(IWMDMNotification);
- IMPLEMENTS(IUnknown);
- *ppvObject = NULL;
- return E_NOINTERFACE;
- }
- virtual ULONG STDMETHODCALLTYPE AddRef() { return ++refs; }
- virtual ULONG STDMETHODCALLTYPE Release() { int x = --refs; if(!x) delete this; return x; }
- #undef IMPLEMENTS
- };
- IWMDMNotification * myNotify=NULL;
- template <class api_T>
- void ServiceBuild(api_T *&api_t, GUID factoryGUID_t)
- {
- if (plugin.service)
- {
- waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
- if (factory)
- api_t = reinterpret_cast<api_T *>( factory->getInterface() );
- }
- }
- template <class api_T>
- void ServiceRelease(api_T *api_t, GUID factoryGUID_t)
- {
- if (plugin.service && api_t)
- {
- waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
- if (factory)
- factory->releaseInterface(api_t);
- }
- api_t = NULL;
- }
- BOOL
- QueueThreadFunction(api_threadpool::ThreadPoolFunc func, void *user, intptr_t id)
- {
- BOOL result;
- ThreadID *thread;
- if (NULL == WASABI_API_THREADPOOL)
- return FALSE;
- thread = WASABI_API_THREADPOOL->ReserveThread(api_threadpool::FLAG_REQUIRE_COM_MT);
- if (NULL == thread)
- return FALSE;
- result = (0 == WASABI_API_THREADPOOL->RunFunction(thread, func, user, id,
- api_threadpool::FLAG_REQUIRE_COM_MT));
- WASABI_API_THREADPOOL->ReleaseThread(thread);
- return result;
- }
- static int init2(BOOL runCheck)
- {
- HRESULT hr;
- IComponentAuthenticate* pICompAuth;
-
- DWORD dwNumProtCount;
- DWORD* pdwProt=NULL; // This will always be SAC_PROTOCOL_V1.
- hr = CoCreateInstance(CLSID_MediaDevMgr, NULL, CLSCTX_ALL, IID_IComponentAuthenticate, (void **)&pICompAuth);
-
- // After getting IComponentAuthenticate, the authentication progression follows.
- if (SUCCEEDED(hr))
- {
- hr = SAC.SetCertificate(SAC_CERT_V1, (BYTE*) abCert, sizeof(abCert), (BYTE*) abPVK, sizeof(abPVK));
- if (SUCCEEDED(hr))
- {
- // Set interface for Secure Authenticated Channel
- // operations. The return value of this function is void.
- SAC.SetInterface(pICompAuth);
- hr = pICompAuth->SACGetProtocols(&pdwProt, &dwNumProtCount);
- if (SUCCEEDED(hr))
- SAC.Authenticate(*pdwProt); //SAC_PROTOCOL_V1
- //if (SUCCEEDED(hr)) OutputDebugString(L"CSecureChannelClient.Authenticate succeeded\n");
- }
- if(pdwProt)
- CoTaskMemFree(pdwProt);
- // After authentication has succeeded, call QueryInterface to
- // get IID_IWMDeviceManager.
-
- if (FAILED(pICompAuth->QueryInterface(IID_IWMDeviceManager3, (void**)&pIdvMgr)))
- pIdvMgr = NULL;
- pICompAuth->Release();
- pICompAuth = NULL;
- if (NULL != pIdvMgr)
- {
- pIdvMgr->SetDeviceEnumPreference(ALLOW_OUTOFBAND_NOTIFICATION);
- IConnectionPointContainer *pIcpc = NULL;
- if (SUCCEEDED(pIdvMgr->QueryInterface(IID_IConnectionPointContainer,(void**)&pIcpc)))
- {
- IConnectionPoint * pICP=NULL;
- if (SUCCEEDED(pIcpc->FindConnectionPoint(IID_IWMDMNotification,&pICP)))
- {
- myNotify = new MyNotification;
-
- if (FAILED(pICP->Advise(myNotify, &ConnectionNotificationCookie)))
- ConnectionNotificationCookie = 0;
- pICP->Release();
- }
- pIcpc->Release();
- pIcpc=0;
- }
- }
- }
- if (FALSE != runCheck)
- checkForDevices(NULL);
- return 0;
- }
- static void quit2()
- {
- if(pIdvMgr)
- {
- if (0 != ConnectionNotificationCookie)
- {
- IConnectionPointContainer *pIcpc;
- if (SUCCEEDED(pIdvMgr->QueryInterface(IID_IConnectionPointContainer,(void**)&pIcpc)))
- {
- IConnectionPoint * pICP;
- if (SUCCEEDED(pIcpc->FindConnectionPoint(IID_IWMDMNotification,&pICP)))
- {
- pICP->Unadvise(ConnectionNotificationCookie);
- ConnectionNotificationCookie = 0;
- pICP->Release();
- }
- pIcpc->Release();
- }
- }
- pIdvMgr->Release();
- pIdvMgr = NULL;
- }
-
- if(myNotify)
- {
- myNotify->Release();
- myNotify=0;
- }
- if(DRMDeviceApp)
- {
- DRMDeviceApp->Release();
- DRMDeviceApp=0;
- }
- }
- int init()
- {
- CoInitialize(0);
- // check OS version
- OSVERSIONINFO osvi = {0};
- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- GetVersionEx(&osvi);
- if(osvi.dwMajorVersion < 5) return -1;
- if(osvi.dwMajorVersion == 5 && osvi.dwMinorVersion < 1) return -1;
- hWinampThread = GetCurrentThread();
- InitializeCriticalSection(&csTransfers);
-
- Tataki::Init(plugin.service);
- ServiceBuild(WASABI_API_LNG, languageApiGUID);
- ServiceBuild(WASABI_API_MEMMGR, memMgrApiServiceGuid);
- ServiceBuild(WASABI_API_THREADPOOL, ThreadPoolGUID);
- ServiceBuild(AGAVE_API_ALBUMART, albumArtGUID);
- ServiceBuild(AGAVE_API_DEVICEMANAGER, DeviceManagerGUID);
- // need to have this initialised before we try to do anything with localisation features
- WASABI_API_START_LANG(plugin.hDllInstance,PmpP4SLangGUID);
- static wchar_t szDescription[256];
- StringCchPrintfW(szDescription, ARRAYSIZE(szDescription),
- WASABI_API_LNGSTRINGW(IDS_NULLSOFT_P4S_PLUGIN), PLUGIN_VERSION);
- plugin.description = szDescription;
- if (NULL != AGAVE_API_DEVICEMANAGER &&
- NULL == deviceProvider)
- {
- if (SUCCEEDED(DeviceProvider::CreateInstance(&deviceProvider)) &&
- FAILED(deviceProvider->Register(AGAVE_API_DEVICEMANAGER)))
- {
- deviceProvider->Release();
- deviceProvider = NULL;
- }
- }
- // set up thread
- killEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
- if (FALSE == QueueThreadFunction(ThreadInitFunc, NULL, (NULL == deviceProvider)))
- init2(NULL == deviceProvider);
- if (NULL != deviceProvider &&
- FAILED(deviceProvider->BeginDiscovery(AGAVE_API_DEVICEMANAGER)))
- {
- checkForDevices(NULL);
- }
- return 0;
- }
- void quit()
- {
- SetEvent(killEvent);
- if (NULL != deviceProvider)
- {
- deviceProvider->Unregister();
- deviceProvider->Release();
- deviceProvider = NULL;
- }
- HANDLE doneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (FALSE != QueueThreadFunction(ThreadQuitFunc, doneEvent, 0))
- WaitForSingleObject(doneEvent, INFINITE);
- else
- quit2();
- CloseHandle(doneEvent);
- CloseHandle(killEvent);
- DeleteCriticalSection(&csTransfers);
- Tataki::Quit();
- ServiceRelease(WASABI_API_LNG, languageApiGUID);
- ServiceRelease(WASABI_API_MEMMGR, memMgrApiServiceGuid);
- ServiceRelease(WASABI_API_THREADPOOL, ThreadPoolGUID);
- ServiceRelease(AGAVE_API_ALBUMART, albumArtGUID);
- ServiceRelease(AGAVE_API_DEVICEMANAGER, DeviceManagerGUID);
- CoUninitialize();
- }
- void newDeviceAvaliable(IWMDMDevice3* pIDevice)
- {
- HRESULT hr;
- DWORD dwTypeDev = 0;
- wchar_t buffer[1024] = {0};
-
- hr = pIDevice->GetType(&dwTypeDev);
- if (SUCCEEDED(hr))
- {
- if(0 == (WMDM_DEVICE_TYPE_PLAYBACK & dwTypeDev))
- {
- return;
- if (FAILED(pIDevice->GetName(buffer,ARRAYSIZE(buffer))))
- buffer[0] = L'\0';
- int l = wcslen(buffer);
-
- if(l > 5 &&
- buffer[l-5] == L' ' &&
- buffer[l-4] == L'(' &&
- buffer[l-2] == L':' &&
- buffer[l-1] == L')')
- {
- return;
- }
- }
- if(0 == (WMDM_DEVICE_TYPE_STORAGE & dwTypeDev))
- return;
- }
- else
- return;
-
- // make sure it's not just a simple mass storage device (we have a separate plugin for this!)
- PROPVARIANT protocol; // VARIANTs can kiss my ass
- hr = pIDevice->GetProperty(g_wszWMDMDeviceProtocol, &protocol);
- if (SUCCEEDED(hr))
- {
- bool isUsb = !!(*protocol.puuid == WMDM_DEVICE_PROTOCOL_MSC);
- PropVariantClear(&protocol);
- if (isUsb)
- return;
- }
- if (SUCCEEDED(pIDevice->GetCanonicalName(buffer, ARRAYSIZE(buffer))))
- {
- wchar_t buffer2[ARRAYSIZE(buffer)] = {0};
- for(int i=0; i < devices.GetSize(); i++)
- {
- P4SDevice *device = (P4SDevice*)devices.Get(i);
- if (NULL != device &&
- NULL != device->WMDevice &&
- SUCCEEDED(device->WMDevice->GetCanonicalName(buffer2, ARRAYSIZE(buffer2))))
- {
- if(wcscmp(buffer, buffer2) == 0)
- return;
- }
- }
- }
-
- if(!DRMDeviceApp)
- CoCreateInstance(CLSID_WMDRMDeviceApp, NULL, CLSCTX_ALL, IID_IWMDRMDeviceApp, (void **)&DRMDeviceApp);
-
- bool noMetadata;
- if (0 == (WMDM_DEVICE_TYPE_PLAYBACK & dwTypeDev))
- {
- noMetadata = true;
- }
- else if (SUCCEEDED(pIDevice->GetManufacturer(buffer, ARRAYSIZE(buffer))) &&
- NULL != wcsstr(buffer, L"Nokia"))
- {
- noMetadata = true;
- }
- else
- noMetadata = false;
- P4SDevice *dev = new P4SDevice(pIDevice,noMetadata);
- //return dev;
- }
- void checkForDevices(BOOL *killSwitch)
- {
- HRESULT hr = S_OK;
- IWMDMEnumDevice* pIEnumDev;
- IWMDMDevice* pIDeviceOld;
- IWMDMDevice3* pIDevice = NULL;
- unsigned long fetched;
- if (!pIdvMgr)
- return;
- hr = pIdvMgr->EnumDevices2(&pIEnumDev); // Query for device enumerator.
- if (SUCCEEDED(hr))
- {
- // If no device is found, S_FALSE is returned, which is still
- // a success case. Do not use the SUCCEEDED macro.
- while ((NULL == killSwitch || FALSE == *killSwitch) &&
- S_OK == pIEnumDev->Next(1, &pIDeviceOld, &fetched))
- {
- if(SUCCEEDED(pIDeviceOld->QueryInterface(IID_IWMDMDevice3,(void**)&pIDevice)))
- {
- newDeviceAvaliable(pIDevice);
- pIDevice->Release();
- }
- pIDeviceOld->Release();
- }
- // We should release this pointer but it appears to make winamp not shut down properly if we do.
- // This function will only be called a small number of times, so I propose that we don't free it
- // until this error can be better investigated. --will
- pIEnumDev->Release();
- }
- }
- static int ThreadInitFunc(HANDLE handle, void *user_data, intptr_t param)
- {
- init2((BOOL)param);
- return 0;
- }
- static int ThreadQuitFunc(HANDLE handle, void *user_data, intptr_t param)
- {
- quit2();
-
- if (NULL != user_data)
- SetEvent((HANDLE)user_data);
- return 0;
- }
- intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3) {
- switch(msg) {
- case PMP_DEVICECHANGE:
- return 0;
- case PMP_NO_CONFIG:
- return TRUE;
- case PMP_CONFIG:
- return 0;
- }
- return 0;
- }
- typedef struct { ULONG_PTR param; void * proc; int state; CRITICAL_SECTION lock;} spc ;
- static VOID CALLBACK spc_caller(ULONG_PTR dwParam) {
- spc * s = (spc*)dwParam;
- if(!s) return;
- EnterCriticalSection(&s->lock);
- if(s->state == -1) { LeaveCriticalSection(&s->lock); DeleteCriticalSection(&s->lock); free(s); return; }
- s->state = 2;
- void (CALLBACK *p)(ULONG_PTR dwParam);
- p = (void (CALLBACK *)(ULONG_PTR dwParam))s->proc;
- if(p) p(s->param);
- s->state=1;
- LeaveCriticalSection(&s->lock);
- }
- // p must be of type void (CALLBACK *)(ULONG_PTR dwParam). Returns 0 for success.
- int SynchronousProcedureCall(void * p, ULONG_PTR dwParam) {
- if(!p) return 1;
- spc * s = (spc*)calloc(1, sizeof(spc));
- InitializeCriticalSection(&s->lock);
- s->param = dwParam;
- s->proc = p;
- s->state = 0;
- if(!QueueUserAPC(spc_caller,hWinampThread,(ULONG_PTR)s)) { DeleteCriticalSection(&s->lock); free(s); return 1; } //failed
- int i=0, state;
- do {
- SleepEx(10,true);
- EnterCriticalSection(&s->lock);
- state = s->state;
- if(i++ == 100) {s->state = -1; return 1;}
- LeaveCriticalSection(&s->lock);
- }
- while(state!=1);
- DeleteCriticalSection(&s->lock);
- free(s);
- return 0;
- }
- BOOL FormatResProtocol(const wchar_t *resourceName, const wchar_t *resourceType, wchar_t *buffer, size_t bufferMax)
- {
- unsigned long filenameLength;
- if (NULL == resourceName)
- return FALSE;
- if (FAILED(StringCchCopyExW(buffer, bufferMax, L"res://", &buffer, &bufferMax, 0)))
- return FALSE;
- filenameLength = GetModuleFileNameW(plugin.hDllInstance, buffer, bufferMax);
- if (0 == filenameLength || bufferMax == filenameLength)
- return FALSE;
- buffer += filenameLength;
- bufferMax -= filenameLength;
- if (NULL != resourceType)
- {
- if (FALSE != IS_INTRESOURCE(resourceType))
- {
- if (FAILED(StringCchPrintfExW(buffer, bufferMax, &buffer, &bufferMax, 0, L"/#%d", (int)(INT_PTR)resourceType)))
- return FALSE;
- }
- else
- {
- if (FAILED(StringCchPrintfExW(buffer, bufferMax, &buffer, &bufferMax, 0, L"/%s", resourceType)))
- return FALSE;
- }
- }
- if (FALSE != IS_INTRESOURCE(resourceName))
- {
- if (FAILED(StringCchPrintfExW(buffer, bufferMax, &buffer, &bufferMax, 0, L"/#%d", (int)(INT_PTR)resourceName)))
- return FALSE;
- }
- else
- {
- if (FAILED(StringCchPrintfExW(buffer, bufferMax, &buffer, &bufferMax, 0, L"/%s", resourceName)))
- return FALSE;
- }
- return TRUE;
- }
- extern "C" {
- __declspec( dllexport ) PMPDevicePlugin * winampGetPMPDevicePlugin(){return &plugin;}
- __declspec( dllexport ) int winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param) {
- int i = devices.GetSize();
- while(i-- > 0) ((Device*)devices.Get(i))->Close();
- return PMP_PLUGIN_UNINSTALL_NOW;
- }
- };
|