winamp/Src/Plugins/Library/ml_devices/gen_deviceprovider/device.cpp
2024-09-24 14:54:57 +02:00

871 lines
14 KiB
C++

#include "main.h"
#include "./device.h"
#include <strsafe.h>
Device::Device()
: ref(1), name(NULL), type(NULL), connection(NULL), displayName(NULL),
totalSpace(0), usedSpace(0), attached(FALSE), hidden(FALSE),
connected(FALSE), activity(NULL), model(NULL), status(NULL)
{
InitializeCriticalSection(&lock);
if (NULL == WASABI_API_DEVICES ||
FAILED(WASABI_API_DEVICES->CreateDeviceEventManager(&eventManager)))
{
eventManager = NULL;
}
if (NULL == WASABI_API_DEVICES ||
FAILED(WASABI_API_DEVICES->CreateIconStore(&iconStore)))
{
iconStore = NULL;
}
if (NULL == WASABI_API_DEVICES ||
FAILED(WASABI_API_DEVICES->CreateSupportedCommandStore(&commands)))
{
commands = NULL;
}
}
Device::~Device()
{
DeviceActivity *activityCopy;
Lock();
if (NULL != activity)
{
activity->SetUser(NULL);
activityCopy = activity;
activityCopy->AddRef();
}
else
activityCopy = NULL;
AnsiString_Free(name);
AnsiString_Free(type);
AnsiString_Free(connection);
String_Free(displayName);
String_Free(model);
String_Free(status);
if (NULL != commands)
commands->Release();
if (NULL != iconStore)
iconStore->Release();
if (NULL != eventManager)
eventManager->Release();
Unlock();
if (NULL != activityCopy)
{
activityCopy->Stop();
activityCopy->Release();
}
DeleteCriticalSection(&lock);
}
HRESULT Device::CreateInstance(const char *name, const char *type, const char *connection, Device**instance)
{
Device *self;
if (NULL == instance)
return E_POINTER;
*instance = NULL;
self = new Device();
if (NULL == self)
return E_OUTOFMEMORY;
self->name = AnsiString_Duplicate(name);
self->type = AnsiString_Duplicate(type);
self->connection = AnsiString_Duplicate(connection);
*instance = self;
return S_OK;
}
size_t Device::AddRef()
{
return InterlockedIncrement((LONG*)&ref);
}
size_t Device::Release()
{
if (0 == ref)
return ref;
LONG r = InterlockedDecrement((LONG*)&ref);
if (0 == r)
delete(this);
return r;
}
int Device::QueryInterface(GUID interface_guid, void **object)
{
if (NULL == object)
return E_POINTER;
if (IsEqualIID(interface_guid, IFC_Device))
*object = static_cast<ifc_device*>(this);
else
{
*object = NULL;
return E_NOINTERFACE;
}
if (NULL == *object)
return E_UNEXPECTED;
AddRef();
return S_OK;
}
void Device::Lock()
{
EnterCriticalSection(&lock);
}
void Device::Unlock()
{
LeaveCriticalSection(&lock);
}
const char *Device::GetName()
{
return name;
}
const char *Device::GetType()
{
return type;
}
const char *Device::GetConnection()
{
return connection;
}
HRESULT Device::GetIcon(wchar_t *buffer, size_t bufferSize, int width, int height)
{
if (NULL == buffer)
return E_POINTER;
if (NULL == iconStore)
return E_UNEXPECTED;
return iconStore->Get(buffer, bufferSize, width, height);
}
HRESULT Device::GetDisplayName(wchar_t *buffer, size_t bufferSize)
{
HRESULT hr;
if (NULL == buffer)
return E_POINTER;
Lock();
if (0 == String_CopyTo(buffer, displayName, bufferSize) &&
FALSE == IS_STRING_EMPTY(displayName))
{
hr = E_FAIL;
}
else
hr = S_OK;
Unlock();
return hr;
}
BOOL Device::GetHidden()
{
return hidden;
}
HRESULT Device::GetTotalSpace(uint64_t *size)
{
if (NULL == size)
return E_POINTER;
Lock();
*size = totalSpace;
Unlock();
return S_OK;
}
HRESULT Device::GetUsedSpace(uint64_t *size)
{
if (NULL == size)
return E_POINTER;
Lock();
*size = usedSpace;
Unlock();
return S_OK;
}
BOOL Device::GetAttached()
{
return attached;
}
HRESULT Device::Attach(HWND hostWindow)
{
HRESULT hr;
Lock();
if (FALSE != attached)
hr = S_FALSE;
else
{
attached = TRUE;
hr = S_OK;
}
Unlock();
if (S_OK == hr && NULL != eventManager)
eventManager->Notify_AttachmentChanged(this, attached);
return hr;
}
HRESULT Device::Detach(HWND hostWindow)
{
HRESULT hr;
Lock();
if (FALSE == attached)
hr = S_FALSE;
else
{
attached = FALSE;
hr = S_OK;
}
Unlock();
if (S_OK == hr && NULL != eventManager)
eventManager->Notify_AttachmentChanged(this, attached);
return hr;
}
HRESULT Device::EnumerateCommands(ifc_devicesupportedcommandenum **enumerator, DeviceCommandContext context)
{
if (NULL == commands)
return E_UNEXPECTED;
return commands->Enumerate(enumerator);
}
HRESULT Device::SendCommand(const char *command, HWND hostWindow, ULONG_PTR param)
{
const wchar_t *commandName;
wchar_t message[1024];
if (NULL == command)
return E_POINTER;
if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, NORM_IGNORECASE, command, -1, "sync", -1))
{
StartSyncActivity(hostWindow);
return S_OK;
}
else if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, NORM_IGNORECASE, command, -1, "eject", -1))
commandName = L"Eject";
else if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, NORM_IGNORECASE, command, -1, "detach", -1))
{
Detach(hostWindow);
return S_OK;
}
else if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, NORM_IGNORECASE, command, -1, "settings", -1))
commandName = L"Settings";
else
return E_NOTIMPL;
StringCchPrintf(message, ARRAYSIZE(message), L"%s command received", commandName);
MessageBox(hostWindow, message, L"Device command test", MB_OK | MB_ICONINFORMATION);
return S_OK;
}
HRESULT Device::GetCommandFlags(const char *command, DeviceCommandFlags *flags)
{
if (NULL == commands)
return E_UNEXPECTED;
return commands->GetFlags(command, flags);
}
HRESULT Device::GetActivity(ifc_deviceactivity **activityOut)
{
HRESULT hr;
if (NULL == activityOut)
return E_POINTER;
Lock();
*activityOut = activity;
if (NULL != activity)
{
activity->AddRef();
hr = S_OK;
}
else
hr = S_FALSE;
Unlock();
return hr;
}
HRESULT Device::Advise(ifc_deviceevent *handler)
{
if (NULL == eventManager)
return E_UNEXPECTED;
return eventManager->Advise(handler);
}
HRESULT Device::Unadvise(ifc_deviceevent *handler)
{
if (NULL == eventManager)
return E_UNEXPECTED;
return eventManager->Unadvise(handler);
}
HWND Device::CreateView(HWND parentWindow)
{
return DeviceView_CreateWindow(parentWindow, this);
}
void Device::SetNavigationItem(void *navigationItem)
{
}
HRESULT Device::GetModel(wchar_t *buffer, size_t bufferSize)
{
HRESULT hr;
if (NULL == buffer)
return E_POINTER;
Lock();
if (0 == String_CopyTo(buffer, model, bufferSize) &&
FALSE == IS_STRING_EMPTY(model))
{
hr = E_FAIL;
}
else
hr = S_OK;
Unlock();
return hr;
}
HRESULT Device::GetStatus(wchar_t *buffer, size_t bufferSize)
{
HRESULT hr;
if (NULL == buffer)
return E_POINTER;
Lock();
if (0 == String_CopyTo(buffer, status, bufferSize) &&
FALSE == IS_STRING_EMPTY(status))
{
hr = E_FAIL;
}
else
hr = S_OK;
Unlock();
return hr;
}
HRESULT Device::SetConnection(const char *con)
{
Lock();
AnsiString_Free(connection);
connection = AnsiString_Duplicate(con);
Unlock();
return S_OK;
}
HRESULT Device::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;
if (NULL != eventManager)
eventManager->Notify_DisplayNameChanged(this, displayName);
hr = S_OK;
}
}
}
Unlock();
return hr;
}
HRESULT Device::SetTotalSpace(uint64_t size)
{
Lock();
totalSpace = size;
if (NULL != eventManager)
eventManager->Notify_TotalSpaceChanged(this, totalSpace);
Unlock();
return S_OK;
}
HRESULT Device::SetUsedSpace(uint64_t size)
{
Lock();
usedSpace = size;
if (NULL != eventManager)
eventManager->Notify_UsedSpaceChanged(this, usedSpace);
Unlock();
return S_OK;
}
HRESULT Device::SetModel(const wchar_t *deviceModel)
{
HRESULT hr;
Lock();
if (NULL == deviceModel && NULL == model)
hr = S_FALSE;
else
{
if (NULL != model &&
CSTR_EQUAL == CompareString(LOCALE_USER_DEFAULT, 0, deviceModel, -1, model, -1))
{
hr = S_FALSE;
}
else
{
wchar_t *string;
string = String_Duplicate(deviceModel);
if (NULL == string && NULL != deviceModel)
hr = E_FAIL;
else
{
String_Free(model);
model = string;
if (NULL != eventManager)
eventManager->Notify_ModelChanged(this, model);
hr = S_OK;
}
}
}
Unlock();
return hr;
}
HRESULT Device::SetStatus(const wchar_t *deviceStatus)
{
HRESULT hr;
Lock();
if (NULL == deviceStatus && NULL == status)
hr = S_FALSE;
else
{
if (NULL != status &&
CSTR_EQUAL == CompareString(LOCALE_USER_DEFAULT, 0, deviceStatus, -1, status, -1))
{
hr = S_FALSE;
}
else
{
wchar_t *string;
string = String_Duplicate(deviceStatus);
if (NULL == string && NULL != deviceStatus)
hr = E_FAIL;
else
{
String_Free(status);
status = string;
if (NULL != eventManager)
eventManager->Notify_StatusChanged(this, status);
hr = S_OK;
}
}
}
Unlock();
return hr;
}
HRESULT Device::AddIcon(const wchar_t *path, unsigned int width, unsigned int height)
{
HRESULT hr;
if (NULL == iconStore)
return E_UNEXPECTED;
hr = iconStore->Add(path, width, height, TRUE);
if (SUCCEEDED(hr))
{
if (NULL != eventManager)
eventManager->Notify_IconChanged(this);
}
return hr;
}
HRESULT Device::EnumerateIcons(ifc_deviceiconstore::EnumeratorCallback callback, void *user)
{
if (NULL == iconStore)
return E_UNEXPECTED;
return iconStore->Enumerate(callback, user);
}
HRESULT Device::RemoveIcon(unsigned int width, unsigned int height)
{
HRESULT hr;
if (NULL == iconStore)
return E_UNEXPECTED;
hr = iconStore->Remove(width, height);
if (SUCCEEDED(hr))
{
if (NULL != eventManager)
eventManager->Notify_IconChanged(this);
}
return hr;
}
HRESULT Device::SetHidden(BOOL hiddenState)
{
HRESULT hr;
Lock();
if (hidden == (FALSE != hiddenState))
hr = S_FALSE;
else
{
hidden = (FALSE != hiddenState);
hr = S_OK;
}
Unlock();
if (S_OK == hr && NULL != eventManager)
eventManager->Notify_VisibilityChanged(this, TRUE);
return hr;
}
HRESULT Device::IsConnected()
{
HRESULT hr;
Lock();
hr = (FALSE != connected) ? S_OK : S_FALSE;
Unlock();
return hr;
}
HRESULT Device::Connect()
{
HRESULT hr;
Lock();
if (FALSE != connected)
hr = S_FALSE;
else
{
connected = TRUE;
hr = S_OK;
}
Unlock();
return hr;
}
HRESULT Device::Disconnect()
{
HRESULT hr;
Lock();
if (FALSE == connected)
hr = S_FALSE;
else
{
connected = FALSE;
hr = S_OK;
}
Unlock();
return hr;
}
HRESULT Device::CopyTo(Device *target)
{
if (NULL == target)
return E_POINTER;
Lock();
target->SetDisplayName(displayName);
if (NULL != target->iconStore)
target->iconStore->Release();
if (NULL == iconStore || FAILED(iconStore->Clone(&target->iconStore)))
target->iconStore = NULL;
target->usedSpace = usedSpace;
target->totalSpace = totalSpace;
target->hidden = hidden;
target->attached = attached;
target->connected = connected;
if (NULL != target->commands)
target->commands->Release();
if (NULL == commands || FAILED(commands->Clone(&target->commands, TRUE)))
target->commands = NULL;
Unlock();
return S_OK;
}
HRESULT Device::SetIconBase(const wchar_t *path)
{
if (NULL == iconStore)
return E_UNEXPECTED;
return iconStore->SetBasePath(path);
}
HRESULT Device::AddCommand(const char *command, DeviceCommandFlags flags)
{
if (NULL == commands)
return E_UNEXPECTED;
return commands->Add(command, flags);
}
HRESULT Device::RemoveCommand(const char *command)
{
if (NULL == commands)
return E_UNEXPECTED;
return commands->Remove(command);
}
HRESULT Device::SetCommandFlags(const char *command, DeviceCommandFlags mask, DeviceCommandFlags flags)
{
if (NULL == commands)
return E_UNEXPECTED;
return commands->SetFlags(command, mask, flags);
}
void Device::ActivityStartedCb(DeviceActivity *activity)
{
Device *device;
if(FAILED(activity->GetUser((void**)&device)) || NULL == device)
return;
if (NULL != device->eventManager)
device->eventManager->Notify_ActivityStarted(device, activity);
}
void Device::ActivityFinishedCb(DeviceActivity *activity)
{
Device *device;
if(FAILED(activity->GetUser((void**)&device)) || NULL == device)
return;
device->Lock();
if (activity == device->activity)
device->activity = NULL;
device->Unlock();
if (NULL != device->eventManager)
device->eventManager->Notify_ActivityFinished(device, activity);
activity->Release();
}
void Device::ActivityProgressCb(DeviceActivity *activity, unsigned int progress, unsigned int duration)
{
Device *device;
uint64_t space;
if(FAILED(activity->GetUser((void**)&device)) || NULL == device)
return;
device->Lock();
space = device->usedSpace;
space++;
if (space > device->totalSpace)
space = 0;
device->Unlock();
device->SetUsedSpace(space);
if (NULL != device->eventManager)
device->eventManager->Notify_ActivityChanged(device, activity);
}
HRESULT Device::StartSyncActivity(HWND hostWindow)
{
HRESULT hr;
Lock();
if (NULL != activity)
hr = E_PENDING;
else
{
hr = DeviceActivity::CreateInstance(DeviceActivityFlag_Cancelable | DeviceActivityFlag_SupportProgress,
ActivityStartedCb, ActivityFinishedCb, ActivityProgressCb,
this, &activity);
if (SUCCEEDED(hr))
{
activity->SetDisplayName(L"Synchronizing...");
activity->SetStatus(L"Performing synchronization...");
hr = activity->Start(60000, 20);
if (FAILED(hr))
{
activity->Release();
activity = NULL;
}
}
}
Unlock();
return S_OK;
}
#define CBCLASS Device
START_DISPATCH;
CB(ADDREF, AddRef)
CB(RELEASE, Release)
CB(QUERYINTERFACE, QueryInterface)
CB(API_GETNAME, GetName)
CB(API_GETTYPE, GetType)
CB(API_GETCONNECTION, GetConnection)
CB(API_GETICON, GetIcon)
CB(API_GETDISPLAYNAME, GetDisplayName)
CB(API_GETHIDDEN, GetHidden)
CB(API_GETTOTALSPACE, GetTotalSpace)
CB(API_GETUSEDSPACE, GetUsedSpace)
CB(API_GETATTACHED, GetAttached)
CB(API_ATTACH, Attach)
CB(API_DETACH, Detach)
CB(API_ENUMERATECOMMANDS, EnumerateCommands)
CB(API_SENDCOMMAND, SendCommand)
CB(API_GETCOMMANDFLAGS, GetCommandFlags)
CB(API_GETACTIVITY, GetActivity)
CB(API_ADVISE, Advise)
CB(API_UNADVISE, Unadvise)
CB(API_CREATEVIEW, CreateView)
VCB(API_SETNAVIGATIONITEM, SetNavigationItem)
CB(API_SETDISPLAYNAME, SetDisplayName)
CB(API_GETMODEL, GetModel)
CB(API_GETSTATUS, GetStatus)
END_DISPATCH;
#undef CBCLASS