mirror of
https://github.com/WinampDesktop/winamp.git
synced 2024-12-20 08:45:53 +01:00
520 lines
8.2 KiB
C++
520 lines
8.2 KiB
C++
|
#include "main.h"
|
||
|
#include "./deviceActivity.h"
|
||
|
|
||
|
#include <strsafe.h>
|
||
|
|
||
|
typedef struct DeviceActivityThreadParam
|
||
|
{
|
||
|
DeviceActivity *activity;
|
||
|
unsigned int duration;
|
||
|
unsigned int interval;
|
||
|
HANDLE readyEvent;
|
||
|
}DeviceActivityThreadParam;
|
||
|
|
||
|
DeviceActivity::DeviceActivity(DeviceActivityFlags flags,
|
||
|
DeviceActivityCallback startCb, DeviceActivityCallback finishCb,
|
||
|
DeviceActivityProgressCallback progressCb, void *user)
|
||
|
: ref(1), displayName(NULL), status(NULL), activityThread(FALSE), cancelEvent(NULL), progress(0)
|
||
|
{
|
||
|
InitializeCriticalSection(&lock);
|
||
|
|
||
|
this->flags = flags;
|
||
|
callbackStart = startCb;
|
||
|
callbackFinish = finishCb;
|
||
|
callbackProgress = progressCb;
|
||
|
this->user = user;
|
||
|
}
|
||
|
|
||
|
DeviceActivity::~DeviceActivity()
|
||
|
{
|
||
|
Stop();
|
||
|
|
||
|
String_Free(displayName);
|
||
|
String_Free(status);
|
||
|
|
||
|
DeleteCriticalSection(&lock);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT DeviceActivity::CreateInstance(DeviceActivityFlags flags,
|
||
|
DeviceActivityCallback startCb, DeviceActivityCallback finishCb,
|
||
|
DeviceActivityProgressCallback progressCb, void *user,
|
||
|
DeviceActivity **instance)
|
||
|
{
|
||
|
DeviceActivity *self;
|
||
|
|
||
|
if (NULL == instance)
|
||
|
return E_POINTER;
|
||
|
|
||
|
*instance = NULL;
|
||
|
|
||
|
self = new DeviceActivity(flags, startCb, finishCb, progressCb, user);
|
||
|
if (NULL == self)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
*instance = self;
|
||
|
return S_OK;
|
||
|
|
||
|
}
|
||
|
|
||
|
size_t DeviceActivity::AddRef()
|
||
|
{
|
||
|
return InterlockedIncrement((LONG*)&ref);
|
||
|
}
|
||
|
|
||
|
size_t DeviceActivity::Release()
|
||
|
{
|
||
|
if (0 == ref)
|
||
|
return ref;
|
||
|
|
||
|
LONG r = InterlockedDecrement((LONG*)&ref);
|
||
|
if (0 == r)
|
||
|
delete(this);
|
||
|
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
int DeviceActivity::QueryInterface(GUID interface_guid, void **object)
|
||
|
{
|
||
|
if (NULL == object)
|
||
|
return E_POINTER;
|
||
|
|
||
|
if (IsEqualIID(interface_guid, IFC_DeviceActivity))
|
||
|
*object = static_cast<ifc_deviceactivity*>(this);
|
||
|
else
|
||
|
{
|
||
|
*object = NULL;
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
if (NULL == *object)
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
void DeviceActivity::Lock()
|
||
|
{
|
||
|
EnterCriticalSection(&lock);
|
||
|
}
|
||
|
|
||
|
void DeviceActivity::Unlock()
|
||
|
{
|
||
|
LeaveCriticalSection(&lock);
|
||
|
}
|
||
|
|
||
|
BOOL DeviceActivity::GetActive()
|
||
|
{
|
||
|
BOOL running;
|
||
|
|
||
|
Lock();
|
||
|
running = (NULL != activityThread);
|
||
|
Unlock();
|
||
|
|
||
|
return running;
|
||
|
}
|
||
|
|
||
|
BOOL DeviceActivity::GetCancelable()
|
||
|
{
|
||
|
BOOL cancelable;
|
||
|
|
||
|
Lock();
|
||
|
cancelable = (0 != (DeviceActivityFlag_Cancelable & flags));
|
||
|
Unlock();
|
||
|
|
||
|
return cancelable;
|
||
|
}
|
||
|
|
||
|
HRESULT DeviceActivity::GetProgress(unsigned int *percentCompleted)
|
||
|
{
|
||
|
|
||
|
if (NULL == percentCompleted)
|
||
|
return E_POINTER;
|
||
|
|
||
|
Lock();
|
||
|
|
||
|
*percentCompleted = progress;
|
||
|
|
||
|
Unlock();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT DeviceActivity::GetDisplayName(wchar_t *buffer, size_t bufferMax)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (NULL == buffer)
|
||
|
return E_POINTER;
|
||
|
|
||
|
Lock();
|
||
|
|
||
|
if (0 == String_CopyTo(buffer, displayName, bufferMax) &&
|
||
|
FALSE == IS_STRING_EMPTY(displayName))
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
}
|
||
|
else
|
||
|
hr = S_OK;
|
||
|
|
||
|
Unlock();
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT DeviceActivity::GetStatus(wchar_t *buffer, size_t bufferMax)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (NULL == buffer)
|
||
|
return E_POINTER;
|
||
|
|
||
|
Lock();
|
||
|
|
||
|
if (0 == String_CopyTo(buffer, status, bufferMax) &&
|
||
|
FALSE == IS_STRING_EMPTY(status))
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
}
|
||
|
else
|
||
|
hr = S_OK;
|
||
|
|
||
|
Unlock();
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT DeviceActivity::Cancel(HWND hostWindow)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
Lock();
|
||
|
|
||
|
if (0 == (DeviceActivityFlag_Cancelable & flags))
|
||
|
hr = E_NOTIMPL;
|
||
|
else
|
||
|
hr = E_FAIL;
|
||
|
|
||
|
Unlock();
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT DeviceActivity::Start(unsigned int duration, unsigned int interval)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
Lock();
|
||
|
|
||
|
if (NULL != activityThread)
|
||
|
hr = E_PENDING;
|
||
|
else
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
|
||
|
if (NULL == cancelEvent)
|
||
|
{
|
||
|
cancelEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||
|
if (NULL == cancelEvent)
|
||
|
hr = E_FAIL;
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
DeviceActivityThreadParam param;
|
||
|
|
||
|
param.activity = this;
|
||
|
param.duration = duration;
|
||
|
param.interval = interval;
|
||
|
param.readyEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||
|
|
||
|
if (NULL == param.readyEvent)
|
||
|
hr = E_FAIL;
|
||
|
else
|
||
|
{
|
||
|
DWORD threadId;
|
||
|
|
||
|
activityThread = CreateThread(NULL, 0, DeviceActivity_ActivityThreadStarter,
|
||
|
¶m, 0, &threadId);
|
||
|
if (NULL == activityThread)
|
||
|
hr = E_FAIL;
|
||
|
else
|
||
|
WaitForSingleObject(param.readyEvent, INFINITE);
|
||
|
|
||
|
CloseHandle(param.readyEvent);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
Stop();
|
||
|
}
|
||
|
|
||
|
Unlock();
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT DeviceActivity::Stop()
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
HANDLE threadHandle, eventHandle;
|
||
|
|
||
|
Lock();
|
||
|
|
||
|
threadHandle = activityThread;
|
||
|
eventHandle = cancelEvent;
|
||
|
|
||
|
activityThread = NULL;
|
||
|
cancelEvent = NULL;
|
||
|
|
||
|
Unlock();
|
||
|
|
||
|
if (NULL != threadHandle)
|
||
|
{
|
||
|
if (NULL != eventHandle)
|
||
|
SetEvent(eventHandle);
|
||
|
|
||
|
WaitForSingleObject(threadHandle, INFINITE);
|
||
|
CloseHandle(threadHandle);
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
else
|
||
|
hr = S_FALSE;
|
||
|
|
||
|
if (NULL != eventHandle)
|
||
|
CloseHandle(eventHandle);
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT DeviceActivity::SetDisplayName(const wchar_t *name)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
Lock();
|
||
|
|
||
|
if (NULL == name && NULL == displayName)
|
||
|
hr = S_FALSE;
|
||
|
else
|
||
|
{
|
||
|
if (NULL != displayName &&
|
||
|
CSTR_EQUAL == CompareString(LOCALE_USER_DEFAULT, 0, name, -1, displayName, -1))
|
||
|
{
|
||
|
hr = S_FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
wchar_t *string;
|
||
|
|
||
|
string = String_Duplicate(name);
|
||
|
if (NULL == string && NULL != name)
|
||
|
hr = E_FAIL;
|
||
|
else
|
||
|
{
|
||
|
String_Free(displayName);
|
||
|
displayName = string;
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Unlock();
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT DeviceActivity::SetStatus(const wchar_t *newStatus)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (NULL == newStatus && NULL == status)
|
||
|
return S_FALSE;
|
||
|
|
||
|
Lock();
|
||
|
|
||
|
if (NULL != status &&
|
||
|
CSTR_EQUAL == CompareString(LOCALE_USER_DEFAULT, 0, newStatus, -1, status, -1))
|
||
|
{
|
||
|
hr = S_FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
wchar_t *string;
|
||
|
|
||
|
string = String_Duplicate(newStatus);
|
||
|
if (NULL == string && NULL != newStatus)
|
||
|
hr = E_FAIL;
|
||
|
else
|
||
|
{
|
||
|
String_Free(status);
|
||
|
status = string;
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Unlock();
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT DeviceActivity::SetUser(void *data)
|
||
|
{
|
||
|
Lock();
|
||
|
user = data;
|
||
|
Unlock();
|
||
|
|
||
|
return S_OK;
|
||
|
|
||
|
}
|
||
|
HRESULT DeviceActivity::GetUser(void **data)
|
||
|
{
|
||
|
if (NULL == data)
|
||
|
return E_POINTER;
|
||
|
|
||
|
Lock();
|
||
|
|
||
|
*data = user;
|
||
|
|
||
|
Unlock();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
DWORD DeviceActivity::ActivityThread(unsigned int duration, unsigned int interval)
|
||
|
{
|
||
|
DWORD waitResult, waitTime;
|
||
|
HANDLE cancelEventCopy;
|
||
|
unsigned int position;
|
||
|
|
||
|
if (interval > duration)
|
||
|
interval = duration;
|
||
|
|
||
|
|
||
|
position = 0;
|
||
|
|
||
|
Lock();
|
||
|
|
||
|
progress = 0;
|
||
|
|
||
|
if (NULL == cancelEvent ||
|
||
|
0 == DuplicateHandle(GetCurrentProcess(), cancelEvent, GetCurrentProcess(),
|
||
|
&cancelEventCopy, 0, FALSE, DUPLICATE_SAME_ACCESS))
|
||
|
{
|
||
|
cancelEventCopy = NULL;
|
||
|
}
|
||
|
|
||
|
Unlock();
|
||
|
|
||
|
if(NULL == cancelEventCopy)
|
||
|
return -3;
|
||
|
|
||
|
Lock();
|
||
|
|
||
|
if (NULL != callbackStart)
|
||
|
callbackStart(this);
|
||
|
|
||
|
if (NULL != callbackProgress)
|
||
|
callbackProgress(this, position, duration);
|
||
|
|
||
|
Unlock();
|
||
|
|
||
|
for(;;)
|
||
|
{
|
||
|
waitTime = interval;
|
||
|
if ((position + waitTime) > duration)
|
||
|
waitTime = duration - position;
|
||
|
|
||
|
waitResult = WaitForSingleObject(cancelEventCopy, waitTime);
|
||
|
if (WAIT_TIMEOUT == waitResult)
|
||
|
{
|
||
|
position += waitTime;
|
||
|
|
||
|
Lock();
|
||
|
|
||
|
if (duration != 0)
|
||
|
{
|
||
|
progress = 100 * position / duration;
|
||
|
if (progress > 100)
|
||
|
progress = 100;
|
||
|
}
|
||
|
else
|
||
|
progress = 100;
|
||
|
|
||
|
|
||
|
if (NULL != callbackProgress)
|
||
|
callbackProgress(this, position, duration);
|
||
|
Unlock();
|
||
|
|
||
|
if (position >= duration)
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
AddRef();
|
||
|
|
||
|
Lock();
|
||
|
|
||
|
if (NULL != activityThread)
|
||
|
{
|
||
|
CloseHandle(activityThread);
|
||
|
activityThread = NULL;
|
||
|
}
|
||
|
|
||
|
if (NULL != cancelEvent)
|
||
|
{
|
||
|
CloseHandle(cancelEvent);
|
||
|
cancelEvent = NULL;
|
||
|
}
|
||
|
|
||
|
if (NULL != callbackFinish)
|
||
|
callbackFinish(this);
|
||
|
|
||
|
Unlock();
|
||
|
|
||
|
Release();
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static DWORD CALLBACK
|
||
|
DeviceActivity_ActivityThreadStarter(void *user)
|
||
|
{
|
||
|
DeviceActivityThreadParam *param;
|
||
|
DeviceActivity *activity;
|
||
|
unsigned int duration, interval;
|
||
|
DWORD result;
|
||
|
|
||
|
param = (DeviceActivityThreadParam*)user;
|
||
|
activity = param->activity;
|
||
|
duration = param->duration;
|
||
|
interval = param->interval;
|
||
|
|
||
|
if (NULL != param->readyEvent)
|
||
|
SetEvent(param->readyEvent);
|
||
|
|
||
|
if (NULL != activity)
|
||
|
result = activity->ActivityThread(duration, interval);
|
||
|
else
|
||
|
result = -2;
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
#define CBCLASS DeviceActivity
|
||
|
START_DISPATCH;
|
||
|
CB(ADDREF, AddRef)
|
||
|
CB(RELEASE, Release)
|
||
|
CB(QUERYINTERFACE, QueryInterface)
|
||
|
CB(API_GETACTIVE, GetActive)
|
||
|
CB(API_GETCANCELABLE, GetCancelable)
|
||
|
CB(API_GETPROGRESS, GetProgress)
|
||
|
CB(API_GETDISPLAYNAME, GetDisplayName)
|
||
|
CB(API_GETSTATUS, GetStatus)
|
||
|
CB(API_CANCEL, Cancel)
|
||
|
END_DISPATCH;
|
||
|
#undef CBCLASS
|