main.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. //#define PLUGIN_NAME "Nullsoft ActiveSync Plug-in"
  2. #define PLUGIN_VERSION L"0.25"
  3. #include "ASDevice.h"
  4. int init();
  5. void quit();
  6. intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3);
  7. extern PMPDevicePlugin plugin = {PMPHDR_VER,0,init,quit,MessageProc};
  8. static HANDLE killEvent=0, hThread=0;
  9. static DWORD WINAPI ThreadFunc(LPVOID lpParam);
  10. IRAPIDesktop *pIRapiDesktop = NULL;
  11. // wasabi based services for localisation support
  12. api_language *WASABI_API_LNG = 0;
  13. HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
  14. std::vector<ASDevice*> devices;
  15. std::vector<ejectedDevice*> ejected;
  16. static RAPIDEVICEID lastDevId;
  17. class MyRAPISink : public IRAPISink {
  18. public:
  19. virtual HRESULT STDMETHODCALLTYPE OnDeviceConnected(IRAPIDevice *pIDevice) {
  20. RAPI_DEVICEINFO devInfo;
  21. if(!SUCCEEDED(pIDevice->GetDeviceInfo(&devInfo))) return S_OK;
  22. SysFreeString(devInfo.bstrName);
  23. SysFreeString(devInfo.bstrPlatform);
  24. EnterCriticalSection(&cs);
  25. lastDevId = devInfo.DeviceId;
  26. for(unsigned int i=0; i<ejected.size(); i++) {
  27. if(devInfo.DeviceId == ejected[i]->id) {
  28. ejected[i]->marked=true;
  29. LeaveCriticalSection(&cs);
  30. return S_OK;
  31. }
  32. }
  33. for(unsigned int i=0; i<devices.size(); i++) {
  34. if(devInfo.DeviceId == devices[i]->devInfo.DeviceId || devices[i]->pIDevice == pIDevice) {
  35. LeaveCriticalSection(&cs);
  36. return S_OK;
  37. }
  38. }
  39. IRAPISession *pISession = NULL;
  40. if (SUCCEEDED(pIDevice->CreateSession(&pISession))) {
  41. if (SUCCEEDED(pISession->CeRapiInit())) devices.push_back(new ASDevice(pIDevice,pISession));
  42. else pISession->Release();
  43. }
  44. LeaveCriticalSection(&cs);
  45. return S_OK;
  46. }
  47. virtual HRESULT STDMETHODCALLTYPE OnDeviceDisconnected(IRAPIDevice *pIDevice) {
  48. EnterCriticalSection(&cs);
  49. RAPI_DEVICEINFO devInfo;
  50. if(!SUCCEEDED(pIDevice->GetDeviceInfo(&devInfo))) return S_OK;
  51. for(unsigned int i=0; i<devices.size(); i++) {
  52. if(devInfo.DeviceId == devices[i]->devInfo.DeviceId || devices[i]->pIDevice == pIDevice) {
  53. SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)devices[i],PMP_IPC_DEVICEDISCONNECTED);
  54. delete devices[i];
  55. }
  56. }
  57. SysFreeString(devInfo.bstrName);
  58. SysFreeString(devInfo.bstrPlatform);
  59. LeaveCriticalSection(&cs);
  60. return S_OK;
  61. }
  62. DWORD RAPISinkContext;
  63. CRITICAL_SECTION cs;
  64. ULONG refs;
  65. MyRAPISink() {refs=1; InitializeCriticalSection(&cs);}
  66. ~MyRAPISink() { DeleteCriticalSection(&cs); }
  67. #define IMPLEMENTS(ifc) if (riid == IID_ ## ifc) { ++refs; *ppvObject = static_cast<ifc *>(this); return S_OK; }
  68. virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,void __RPC_FAR *__RPC_FAR *ppvObject) {
  69. IMPLEMENTS(IRAPISink);
  70. IMPLEMENTS(IUnknown);
  71. *ppvObject = NULL;
  72. return E_NOINTERFACE;
  73. }
  74. virtual ULONG STDMETHODCALLTYPE AddRef() { return ++refs; }
  75. virtual ULONG STDMETHODCALLTYPE Release() { int x = --refs; if(!x) delete this; return x; }
  76. #undef IMPLEMENTS
  77. };
  78. MyRAPISink *pMyRapiSink=NULL;
  79. int init() {
  80. CoInitializeEx(NULL, COINIT_MULTITHREADED);
  81. HRESULT hr = CoCreateInstance(CLSID_RAPI,NULL,CLSCTX_INPROC_SERVER,IID_IRAPIDesktop,(void**)&pIRapiDesktop);
  82. if(!SUCCEEDED(hr) || !pIRapiDesktop) return -1; // no activesync on this computer!
  83. // loader so that we can get the localisation service api for use
  84. waServiceFactory *sf = plugin.service->service_getServiceByGuid(languageApiGUID);
  85. if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface());
  86. // need to have this initialised before we try to do anything with localisation features
  87. WASABI_API_START_LANG(plugin.hDllInstance,PmpACTIVESYNCLangGUID);
  88. static wchar_t szDescription[256];
  89. swprintf(szDescription, ARRAYSIZE(szDescription),
  90. WASABI_API_LNGSTRINGW(IDS_NULLSOFT_ACTIVESYNC_PLUGIN), PLUGIN_VERSION);
  91. plugin.description = szDescription;
  92. killEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
  93. DWORD dwThreadId;
  94. hThread = CreateThread(NULL, 0, ThreadFunc, NULL, 0, &dwThreadId);
  95. return 0;
  96. }
  97. static void enumDevices() {
  98. // find all the currently connected devices
  99. IRAPIEnumDevices* pIRapiEnumDevices = NULL;
  100. HRESULT hr = pIRapiDesktop->EnumDevices(&pIRapiEnumDevices);
  101. for (unsigned int i = 0; i < ejected.size(); i++) ejected[i]->marked = false;
  102. while (SUCCEEDED(hr) && pIRapiEnumDevices) {
  103. IRAPIDevice* pIRapiDevice = NULL;
  104. hr = pIRapiEnumDevices->Next(&pIRapiDevice);
  105. if (SUCCEEDED(hr) && pIRapiDevice) {
  106. pMyRapiSink->OnDeviceConnected(pIRapiDevice);
  107. pIRapiDevice->Release();
  108. }
  109. else {
  110. pIRapiEnumDevices->Release();
  111. pIRapiEnumDevices = NULL;
  112. }
  113. }
  114. //for (unsigned int i = 0; i < ejected.size(); i++)
  115. //{
  116. // if (!ejected[i]->marked)
  117. // {
  118. // free(ejected[i]);
  119. // ejected.eraseindex(i);
  120. // }
  121. //}
  122. auto it = ejected.begin();
  123. while (it != ejected.end())
  124. {
  125. ejectedDevice* dev = *it;
  126. if (!dev->marked)
  127. {
  128. free(dev);
  129. it = ejected.erase(it);
  130. }
  131. else
  132. {
  133. it++;
  134. }
  135. }
  136. }
  137. static void init2() {
  138. // set up device connection/disconnection notifications
  139. pMyRapiSink = new MyRAPISink();
  140. pIRapiDesktop->Advise(pMyRapiSink,(DWORD_PTR*)&pMyRapiSink->RAPISinkContext);
  141. // find currently attached devices
  142. enumDevices();
  143. }
  144. void quit() {
  145. SetEvent(killEvent);
  146. if (hThread) {
  147. for(;;) {
  148. int val = WaitForSingleObjectEx(hThread,15000,TRUE);
  149. if(val == WAIT_OBJECT_0) { CloseHandle(hThread); break; }
  150. else if(val == WAIT_TIMEOUT) { TerminateThread(hThread, 0); break; }
  151. else continue;
  152. }
  153. }
  154. CloseHandle(killEvent);
  155. pIRapiDesktop->UnAdvise(pMyRapiSink->RAPISinkContext);
  156. pIRapiDesktop->Release();
  157. pMyRapiSink->Release();
  158. CoUninitialize();
  159. for(unsigned int i=0; i<ejected.size(); i++) free(ejected[i]);
  160. }
  161. static DWORD WINAPI ThreadFunc(LPVOID lpParam) {
  162. CoInitializeEx(0,COINIT_MULTITHREADED);
  163. init2();
  164. while (WaitForSingleObjectEx(killEvent,5000,TRUE) != WAIT_OBJECT_0) {
  165. // FUCKO: For some reason I'm not getting the device connected notifications, so lets just enum for devices on a regular basis.
  166. enumDevices();
  167. }
  168. CoUninitialize();
  169. return 0;
  170. }
  171. intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3) {
  172. if (msg == PMP_NO_CONFIG)
  173. return TRUE;
  174. return FALSE;
  175. }
  176. extern "C" {
  177. __declspec( dllexport ) PMPDevicePlugin * winampGetPMPDevicePlugin(){return &plugin;}
  178. __declspec( dllexport ) int winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param) {
  179. int i = (int)devices.size();
  180. while(i-- > 0) devices[i]->Close();
  181. return PMP_PLUGIN_UNINSTALL_NOW;
  182. }
  183. };