Initial community commit
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,45 @@
|
||||
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
|
||||
** Filename:
|
||||
** Project:
|
||||
** Description:
|
||||
** Author: Ben Allison benski@nullsoft.com
|
||||
** Created:
|
||||
**/
|
||||
#include "main.h"
|
||||
|
||||
void loadasxv2fn(const wchar_t *filename, int whattodo)
|
||||
{
|
||||
if (PlayList_getlength())
|
||||
{
|
||||
if (whattodo < 1)
|
||||
PlayList_delete();
|
||||
}
|
||||
|
||||
int i=1;
|
||||
wchar_t ref[FILENAME_SIZE];
|
||||
wchar_t key[100];
|
||||
while (1)
|
||||
{
|
||||
StringCchPrintfW(key, 100, L"Ref%d", i++);
|
||||
GetPrivateProfileStringW(L"Reference", key, L"?", ref, FILENAME_SIZE, filename);
|
||||
if (!lstrcmpiW(ref, L"?"))
|
||||
break;
|
||||
else
|
||||
{
|
||||
if (!_wcsnicmp(ref, L"http://", 7))
|
||||
{
|
||||
wchar_t *end = scanstr_backW(ref, L"/.", 0);
|
||||
if (!end || *end == L'/')
|
||||
{
|
||||
if (wcschr(ref, L'?'))
|
||||
StringCchCatW(ref, FILENAME_SIZE, L"&=.wma");
|
||||
else
|
||||
StringCchCatW(ref, FILENAME_SIZE, L"?.wma");
|
||||
}
|
||||
}
|
||||
|
||||
PlayList_append(ref);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#include "main.h"
|
||||
#include "AccessibilityConfigGroup.h"
|
||||
#include "WinampAttributes.h"
|
||||
|
||||
|
||||
ifc_configitem *AccessibilityConfigGroup::GetItem(const wchar_t *name)
|
||||
{
|
||||
if (!wcscmp(name, L"modalbeep"))
|
||||
return &config_accessibility_modalbeep;
|
||||
else if (!wcscmp(name, L"modalflash"))
|
||||
return &config_accessibility_modalflash;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define CBCLASS AccessibilityConfigGroup
|
||||
START_DISPATCH;
|
||||
CB(IFC_CONFIGGROUP_GETITEM, GetItem)
|
||||
CB(IFC_CONFIGGROUP_GETGUID, GetGUID)
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef NULLSOFT_WINAMP_ACCESSIBILITYCONFIGGROUP_H
|
||||
#define NULLSOFT_WINAMP_ACCESSIBILITYCONFIGGROUP_H
|
||||
|
||||
//#include "main.h"
|
||||
#include "../Agave/Config/ifc_configgroup.h"
|
||||
|
||||
// {0E2E7F4A-7C51-478f-8774-ABBCF6D5A857}
|
||||
static const GUID accessibilityConfigGroupGUID =
|
||||
{ 0xe2e7f4a, 0x7c51, 0x478f, { 0x87, 0x74, 0xab, 0xbc, 0xf6, 0xd5, 0xa8, 0x57 } };
|
||||
|
||||
|
||||
class AccessibilityConfigGroup : public ifc_configgroup
|
||||
{
|
||||
public:
|
||||
ifc_configitem *GetItem(const wchar_t *name);
|
||||
GUID GetGUID() { return accessibilityConfigGroupGUID; }
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
||||
|
||||
extern AccessibilityConfigGroup accessibilityConfigGroup;
|
||||
|
||||
#endif //NULLSOFT_WINAMP_ACCESSIBILITYCONFIGGROUP_H
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "main.h"
|
||||
#include "AdData.h"
|
||||
|
||||
ad_data::ad_data()
|
||||
:strCurtain(0), cbCurtain(0)/*, strBrowser(0), cbBrowser(0)*/
|
||||
{
|
||||
}
|
||||
|
||||
ad_data::~ad_data()
|
||||
{
|
||||
delete[] strCurtain; cbCurtain=0;
|
||||
/*delete[] strBrowser; cbBrowser=0;*/
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef NULLSOFT_ADDATAH
|
||||
#define NULLSOFT_ADDATAH
|
||||
|
||||
struct ad_data
|
||||
{
|
||||
ad_data();
|
||||
~ad_data();
|
||||
char *strCurtain;
|
||||
int cbCurtain;
|
||||
/*
|
||||
char *strBrowser;
|
||||
size_t cbBrowser;
|
||||
*/
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,693 @@
|
||||
// disabled 30 May 2012 as per email from Tejas w.r.t. to Rovi deal ending
|
||||
#if 0
|
||||
#include "main.h"
|
||||
#include "../nu/AutoUrl.h"
|
||||
#include "../nu/AutoWide.h"
|
||||
#include "../nu/GrowBuf.h"
|
||||
#include "api.h"
|
||||
#include "../xml/obj_xml.h"
|
||||
#include "../xml/ifc_xmlreadercallback.h"
|
||||
#include "..\Components\wac_network\wac_network_http_receiver_api.h"
|
||||
#include <api/service/waservicefactory.h>
|
||||
#include <api/service/svcs/svc_imgload.h>
|
||||
#include "XMLString.h"
|
||||
#include <tataki/export.h>
|
||||
#include <tataki/bitmap/bitmap.h>
|
||||
#include <tataki/canvas/bltcanvas.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
static INT_PTR CALLBACK artDownloader(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
|
||||
static INT_PTR CALLBACK scrollChildHostProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
|
||||
static INT_PTR CALLBACK scrollChildProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
|
||||
static INT_PTR CALLBACK imageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
|
||||
|
||||
#define HTTP_BUFFER_SIZE 32768
|
||||
|
||||
#define WM_ADDCHILD WM_USER+0
|
||||
#define WM_SELECTED WM_USER+1
|
||||
#define WM_UPDATESTATUS WM_USER+2
|
||||
#define AddImageToList(hChild, param) SendMessageW(hChild,WM_ADDCHILD,0,(LPARAM)param)
|
||||
#define GetParam(hwndDlg) (ArtParser*)GetWindowLongPtrW(hwndDlg,GWLP_USERDATA)
|
||||
#define GetParamC(hwndDlg) (ImgDownloader*)GetWindowLongPtrW(hwndDlg,GWLP_USERDATA)
|
||||
#define UpdateStatus(hwndDlg) PostMessageW(hwndDlg,WM_UPDATESTATUS,0,0)
|
||||
|
||||
class ImgDownloader
|
||||
{
|
||||
public:
|
||||
ImgDownloader(const wchar_t *_desc, const char *_url) : done(false), http(0), started(false), error(false), imgbuf(0), imgbufsize(0), imgbufused(0)
|
||||
{
|
||||
desc = _wcsdup(_desc);
|
||||
url = _strdup(_url);
|
||||
}
|
||||
~ImgDownloader()
|
||||
{
|
||||
free(desc);
|
||||
free(url);
|
||||
free(imgbuf);
|
||||
waServiceFactory *httpFactory = WASABI_API_SVC->service_getServiceByGuid(httpreceiverGUID);
|
||||
if(httpFactory && http)
|
||||
httpFactory->releaseInterface(http);
|
||||
}
|
||||
bool run();
|
||||
|
||||
wchar_t *desc;
|
||||
char *url;
|
||||
bool done, error;
|
||||
api_httpreceiver *http;
|
||||
|
||||
BYTE *imgbuf;
|
||||
int imgbufsize;
|
||||
int imgbufused;
|
||||
private:
|
||||
bool started;
|
||||
};
|
||||
|
||||
class ArtParser : public ifc_xmlreadercallback
|
||||
{
|
||||
public:
|
||||
ArtParser(artFetchData * data);
|
||||
~ArtParser();
|
||||
|
||||
wchar_t curAlbumStr[512] = {0};
|
||||
void ArtParser::StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params);
|
||||
void ArtParser::TextHandler(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *str);
|
||||
|
||||
int run();
|
||||
|
||||
artFetchData * data;
|
||||
|
||||
bool doneXML;
|
||||
int curImage, numImages, failedImages;
|
||||
|
||||
bool error;
|
||||
HWND hwndDlg;
|
||||
obj_xml *parser;
|
||||
waServiceFactory *parserFactory, *httpFactory;
|
||||
api_httpreceiver *http;
|
||||
std::vector<ImgDownloader*> imgDownload;
|
||||
|
||||
protected:
|
||||
#define CBCLASS ArtParser
|
||||
START_DISPATCH_INLINE;
|
||||
VCB(ONSTARTELEMENT, StartTag);
|
||||
VCB(ONCHARDATA, TextHandler);
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
};
|
||||
|
||||
wchar_t tmp_album[512] = {0}, tmp_artist[512] = {0}, tmp_year[5] = {0};
|
||||
int RetrieveAlbumArt(artFetchData * data)
|
||||
{
|
||||
if(!data || data->size < sizeof(artFetchData))
|
||||
return 1;
|
||||
|
||||
int ret = 1;
|
||||
Tataki::Init(serviceManager);
|
||||
{
|
||||
ArtParser param(data);
|
||||
if(!param.error)
|
||||
ret = LPDialogBoxParamW(IDD_ARTDOWNLOADER,data->parent,artDownloader,(LPARAM)¶m);
|
||||
|
||||
while (ret == 2) // Keep in loop till user aborts custom search
|
||||
{
|
||||
// TODO: benski> maybe we should save the old values and restore at the end
|
||||
data->album = tmp_album;
|
||||
data->artist = tmp_artist;
|
||||
data->year = _wtoi(tmp_year);
|
||||
// Martin> we should also set the other values back to null
|
||||
// benski> i'm not sure if we want to set these id fields to NULL
|
||||
// but we'll go with it for now
|
||||
data->amgAlbumId = NULL;
|
||||
data->amgArtistId = NULL;
|
||||
data->gracenoteFileId = NULL;
|
||||
WASABI_API_MEMMGR->sysFree(data->imgData);
|
||||
data->imgData = NULL;
|
||||
data->imgDataLen = NULL;
|
||||
|
||||
ArtParser param(data);
|
||||
ret = LPDialogBoxParamW(IDD_ARTDOWNLOADER,data->parent,artDownloader,(LPARAM)¶m);
|
||||
}
|
||||
}
|
||||
Tataki::Quit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define USER_AGENT_SIZE (10 /*User-Agent*/ + 2 /*: */ + 6 /*Winamp*/ + 1 /*/*/ + 1 /*5*/ + 3/*.21*/ + 1 /*Null*/)
|
||||
static void SetUserAgent(api_httpreceiver *http)
|
||||
{
|
||||
char user_agent[USER_AGENT_SIZE] = {0};
|
||||
StringCchCopyA(user_agent, USER_AGENT_SIZE, "User-Agent: Winamp/"APP_VERSION); // as a nice side effect, this will cut off any extra digits after the first two. e.g. 5.111 becomes 5.11
|
||||
http->addheader(user_agent);
|
||||
}
|
||||
|
||||
class UrlBuilder : private GrowBuf
|
||||
{
|
||||
public:
|
||||
UrlBuilder(const char * base) : first(1) { set(base); }
|
||||
~UrlBuilder(){}
|
||||
void AddParam(const char * key, const wchar_t * value) { AddParamI(key,(char*)AutoUrl(value)); }
|
||||
void AddParam(const char * key, int value) { char buf[16]; StringCchPrintfA(buf,16,"%d",value); AddParamI(key,buf); }
|
||||
void Finish() { GrowBuf::add((void*)"",1); }
|
||||
const char * Get() { return (const char*)get(); } // don't call this without first calling finish!
|
||||
private:
|
||||
void AddParamI(const char * key, const char * value) { if(first){ first=0; add("?");} else add("&"); add(key); add("="); add(value); }
|
||||
void add(const char * x) { GrowBuf::add((char*)x,strlen(x)); }
|
||||
void set(const char * x) { GrowBuf::set((char*)x,strlen(x)); }
|
||||
int first;
|
||||
};
|
||||
|
||||
static wchar_t* format(const wchar_t *in, wchar_t *buf, int len)
|
||||
{
|
||||
wchar_t *p = buf;
|
||||
int inbracket = 0;
|
||||
while(in && *in)
|
||||
{
|
||||
if(p >= buf + len - 1) break;
|
||||
else if(*in == L'[' || *in == L'(' || *in == L'<') inbracket++;
|
||||
else if(*in == L']' || *in == L')' || *in == L'>') inbracket--;
|
||||
else if(!inbracket) *(p++) = *in;
|
||||
in++;
|
||||
}
|
||||
*p=0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
ArtParser::ArtParser(artFetchData * data) : data(data), error(false), parserFactory(0), parser(0), http(0), httpFactory(0), doneXML(false), curImage(0), numImages(0), failedImages(0)
|
||||
{
|
||||
curAlbumStr[0]=0;
|
||||
|
||||
parserFactory = WASABI_API_SVC->service_getServiceByGuid(obj_xmlGUID);
|
||||
if (parserFactory)
|
||||
parser = (obj_xml *)parserFactory->getInterface();
|
||||
|
||||
if (parser)
|
||||
{
|
||||
parser->xmlreader_registerCallback(L"document\fartwork", this);
|
||||
parser->xmlreader_registerCallback(L"response\fdata\fartwork", this);
|
||||
parser->xmlreader_open();
|
||||
}
|
||||
else
|
||||
{
|
||||
error=true;
|
||||
return;
|
||||
}
|
||||
|
||||
// construct xml url
|
||||
UrlBuilder url("http://client.winamp.com/metadata/artwork.php");
|
||||
|
||||
wchar_t temp[2048] = {0};
|
||||
|
||||
if(data->artist && data->artist[0] && _wcsicmp(data->artist, L"Various Artists") && _wcsicmp(data->artist, L"VA") && _wcsicmp(data->artist, L"OST"))
|
||||
url.AddParam("artist",format(data->artist,temp,2048));
|
||||
|
||||
if(data->album && data->album[0])
|
||||
url.AddParam("album",format(data->album,temp,2048));
|
||||
|
||||
if(data->year)
|
||||
url.AddParam("recorddate",data->year);
|
||||
|
||||
if(data->amgAlbumId)
|
||||
url.AddParam("amgalbumid",data->amgAlbumId);
|
||||
|
||||
if(data->amgArtistId)
|
||||
url.AddParam("amgartistid",data->amgArtistId);
|
||||
|
||||
if(data->gracenoteFileId && data->gracenoteFileId[0])
|
||||
url.AddParam("tagid",data->gracenoteFileId);
|
||||
|
||||
url.Finish();
|
||||
|
||||
httpFactory = WASABI_API_SVC->service_getServiceByGuid(httpreceiverGUID);
|
||||
if(httpFactory) http = (api_httpreceiver *)httpFactory->getInterface();
|
||||
|
||||
if(http)
|
||||
{
|
||||
http->AllowCompression();
|
||||
http->open(API_DNS_AUTODNS, HTTP_BUFFER_SIZE, config_proxy);
|
||||
SetUserAgent(http);
|
||||
http->connect(url.Get());
|
||||
}
|
||||
else error = true;
|
||||
}
|
||||
|
||||
ArtParser::~ArtParser()
|
||||
{
|
||||
imgDownload.deleteAll();
|
||||
if(parser)
|
||||
{
|
||||
parser->xmlreader_unregisterCallback(this);
|
||||
parser->xmlreader_close();
|
||||
if(parserFactory)
|
||||
parserFactory->releaseInterface(parser);
|
||||
}
|
||||
parser = 0;
|
||||
parserFactory = 0;
|
||||
if(http && httpFactory)
|
||||
httpFactory->releaseInterface(http);
|
||||
http = 0;
|
||||
httpFactory = 0;
|
||||
}
|
||||
|
||||
void ArtParser::StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params)
|
||||
{
|
||||
const wchar_t* artist = params->getItemValue(L"amgArtistDispName");
|
||||
const wchar_t* album = params->getItemValue(L"amgDispName");
|
||||
const wchar_t* year = params->getItemValue(L"recordDate");
|
||||
StringCchPrintfW(curAlbumStr,512,L"%s - %s (%s)",artist?artist:L"",album?album:L"",year?year:L"");
|
||||
}
|
||||
|
||||
void ArtParser::TextHandler(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *str)
|
||||
{
|
||||
numImages++;
|
||||
imgDownload.push_back(new ImgDownloader(curAlbumStr,AutoChar(str)));
|
||||
UpdateStatus(hwndDlg);
|
||||
}
|
||||
|
||||
int ArtParser::run()
|
||||
{
|
||||
int ret = http->run();
|
||||
if (ret == -1) // connection failed
|
||||
{
|
||||
error=true;
|
||||
UpdateStatus(hwndDlg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int replycode = http->getreplycode();
|
||||
switch (replycode)
|
||||
{
|
||||
case 0:
|
||||
case 100:
|
||||
return 1;
|
||||
case 200:
|
||||
{
|
||||
char downloadedData[HTTP_BUFFER_SIZE] = {0};
|
||||
int xmlResult = API_XML_SUCCESS;
|
||||
int downloadSize = http->get_bytes(downloadedData, HTTP_BUFFER_SIZE);
|
||||
if(downloadSize)
|
||||
xmlResult = parser->xmlreader_feed((void *)downloadedData, downloadSize);
|
||||
else if(!downloadSize && ret == 1)
|
||||
{ // we're finished!
|
||||
xmlResult = parser->xmlreader_feed(0,0);
|
||||
doneXML=true;
|
||||
UpdateStatus(hwndDlg);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error=true;
|
||||
UpdateStatus(hwndDlg);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool ImgDownloader::run()
|
||||
{
|
||||
if(!started)
|
||||
{
|
||||
started = true;
|
||||
waServiceFactory *httpFactory = WASABI_API_SVC->service_getServiceByGuid(httpreceiverGUID);
|
||||
if(httpFactory) http = (api_httpreceiver *)httpFactory->getInterface();
|
||||
if(http)
|
||||
{
|
||||
http->open(API_DNS_AUTODNS, HTTP_BUFFER_SIZE, config_proxy);
|
||||
SetUserAgent(http);
|
||||
http->connect(url);
|
||||
}
|
||||
imgbuf = (BYTE*)malloc(HTTP_BUFFER_SIZE);
|
||||
imgbufsize = HTTP_BUFFER_SIZE;
|
||||
}
|
||||
if(!http || !imgbuf)
|
||||
{
|
||||
error=true;
|
||||
return 0;
|
||||
}
|
||||
int ret = http->run();
|
||||
if(ret == -1) //error
|
||||
{
|
||||
error=true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int replycode = http->getreplycode();
|
||||
switch (replycode)
|
||||
{
|
||||
case 0:
|
||||
case 100:
|
||||
return 1;
|
||||
case 200:
|
||||
{
|
||||
int downloadSize = http->get_bytes(imgbuf+imgbufused, imgbufsize - imgbufused);
|
||||
imgbufused += downloadSize;
|
||||
if(imgbufused + 4096 >= imgbufsize)
|
||||
{
|
||||
imgbufsize += HTTP_BUFFER_SIZE;
|
||||
imgbuf = (BYTE*)realloc(imgbuf,imgbufsize);
|
||||
}
|
||||
|
||||
if(!downloadSize && ret == 1)
|
||||
done=true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
static INT_PTR CALLBACK artDownloader(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
|
||||
{
|
||||
static HWND m_child;
|
||||
switch(uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
m_child = LPCreateDialogW(IDD_ARTDOWNLOADER_SCROLLHOST,hwndDlg,(WNDPROC)scrollChildHostProc);
|
||||
SetWindowLong(hwndDlg,GWLP_USERDATA,lParam);
|
||||
ArtParser * parser = (ArtParser *)lParam;
|
||||
parser->hwndDlg = hwndDlg;
|
||||
SetTimer(hwndDlg,0,50,NULL);
|
||||
SetTimer(hwndDlg,1,50,NULL);
|
||||
UpdateStatus(hwndDlg);
|
||||
if(parser->data->showCancelAll) ShowWindow(GetDlgItem(hwndDlg,IDC_CANCELALL),SW_SHOWNA);
|
||||
wchar_t old[100]=L"";
|
||||
GetWindowTextW(hwndDlg,old,100);
|
||||
wchar_t buf[256]=L"";
|
||||
if(parser->data->artist && parser->data->artist[0] && parser->data->album && parser->data->album[0])
|
||||
StringCchPrintfW(buf,256,L"%s: %s - %s",old,parser->data->artist,parser->data->album);
|
||||
else if(parser->data->album && parser->data->album[0])
|
||||
StringCchPrintfW(buf,256,L"%s: %s",old,parser->data->album);
|
||||
else if(parser->data->artist && parser->data->artist[0])
|
||||
StringCchPrintfW(buf,256,L"%s: %s",old,parser->data->artist);
|
||||
|
||||
if(buf[0])
|
||||
SetWindowTextW(hwndDlg,buf);
|
||||
|
||||
SetWindowTextW(GetDlgItem(hwndDlg,IDC_SEARCHREFINE_ARTIST), parser->data->artist);
|
||||
SetWindowTextW(GetDlgItem(hwndDlg,IDC_SEARCHREFINE_ALBUM), parser->data->album);
|
||||
wchar_t yearbuf[5]=L"";
|
||||
_itow(parser->data->year,yearbuf,10);
|
||||
SetWindowTextW(GetDlgItem(hwndDlg,IDC_SEARCHREFINE_YEAR), (parser->data->year?yearbuf:L""));
|
||||
}
|
||||
break;
|
||||
case WM_SELECTED:
|
||||
{
|
||||
ArtParser * parser = GetParam(hwndDlg);
|
||||
HWND selchild = (HWND)wParam;
|
||||
ImgDownloader *d = (ImgDownloader *)lParam;
|
||||
if(parser && d && d->imgbuf && d->imgbufused)
|
||||
{
|
||||
if (!AGAVE_API_AMGSUCKS || AGAVE_API_AMGSUCKS->WriteAlbumArt(d->imgbuf, d->imgbufused, &parser->data->imgData, &parser->data->imgDataLen) != 0)
|
||||
{
|
||||
void * img = WASABI_API_MEMMGR->sysMalloc(d->imgbufused);
|
||||
memcpy(img,d->imgbuf,d->imgbufused);
|
||||
parser->data->imgData = img;
|
||||
parser->data->imgDataLen = d->imgbufused;
|
||||
}
|
||||
char * dot = strrchr(d->url,'.');
|
||||
if(dot) lstrcpynW(parser->data->type,AutoWide(dot+1),10);
|
||||
EndDialog(hwndDlg,0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_UPDATESTATUS:
|
||||
{
|
||||
ArtParser * parser = GetParam(hwndDlg);
|
||||
if(parser)
|
||||
{
|
||||
wchar_t s[100] = {0};
|
||||
if(parser->error) getStringW(IDS_ART_SEARCH_FAILED,s,100);
|
||||
else if(parser->doneXML) getStringW(IDS_ART_SEARCH_FINISHED,s,100);
|
||||
else getStringW(IDS_ART_SEARCH_PROGRESS,s,100);
|
||||
wchar_t buf[512] = {0};
|
||||
StringCchPrintfW(buf,512,getStringW(IDS_ART_SEARCH_STATUS,0,0),s,parser->numImages,parser->curImage - parser->failedImages,parser->failedImages,parser->numImages - parser->curImage);
|
||||
SetDlgItemTextW(hwndDlg,IDC_STATUS,buf);
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_TIMER:
|
||||
{
|
||||
ArtParser * parser = GetParam(hwndDlg);
|
||||
switch(wParam)
|
||||
{
|
||||
case 0:
|
||||
if(parser && !parser->run())
|
||||
KillTimer(hwndDlg,0);
|
||||
break;
|
||||
case 1:
|
||||
if(parser && parser->imgDownload.size())
|
||||
{
|
||||
ImgDownloader *d = parser->imgDownload.at(0);
|
||||
if(d->error)
|
||||
{
|
||||
parser->failedImages++;
|
||||
parser->curImage++;
|
||||
parser->imgDownload.eraseindex(0);
|
||||
delete d;
|
||||
UpdateStatus(hwndDlg);
|
||||
}
|
||||
else if(d->done)
|
||||
{
|
||||
parser->curImage++;
|
||||
parser->imgDownload.eraseindex(0);
|
||||
AddImageToList(m_child,d);
|
||||
UpdateStatus(hwndDlg);
|
||||
}
|
||||
else d->run();
|
||||
}
|
||||
if(parser->error || parser->doneXML)
|
||||
{
|
||||
if(parser->curImage == parser->numImages)
|
||||
{
|
||||
KillTimer(hwndDlg,1);
|
||||
if(!parser->numImages)
|
||||
{
|
||||
wchar_t title[100] = {0};
|
||||
getStringW(IDS_ART_SEARCH_NOT_FOUND_TITLE,title,100);
|
||||
MessageBoxW(hwndDlg,getStringW(IDS_ART_SEARCH_NOT_FOUND,0,0),title,0);
|
||||
//EndDialog(hwndDlg,-1); //CUT, since we have now a custom search
|
||||
}
|
||||
EnableWindow(GetDlgItem(hwndDlg, IDC_SEARCHAGAIN), true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
{
|
||||
SetWindowLong(hwndDlg,GWLP_USERDATA,0);
|
||||
}
|
||||
break;
|
||||
case WM_CLOSE:
|
||||
EndDialog(hwndDlg,-1);
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
switch(LOWORD(wParam))
|
||||
{
|
||||
case IDCANCEL:
|
||||
EndDialog(hwndDlg,-1);
|
||||
break;
|
||||
case IDC_CANCELALL:
|
||||
EndDialog(hwndDlg,-2);
|
||||
break;
|
||||
case IDC_SEARCHAGAIN: // copy text field params to parser
|
||||
ArtParser * parser = GetParam(hwndDlg);
|
||||
|
||||
// Let the first search process finish
|
||||
if (!(parser->doneXML || parser->error))
|
||||
{
|
||||
//TODO change this string
|
||||
MessageBoxW(hwndDlg, L"Please wait till the current retrieval is finished", L"", 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
GetDlgItemTextW(hwndDlg,IDC_SEARCHREFINE_ALBUM, tmp_album, 512);
|
||||
GetDlgItemTextW(hwndDlg,IDC_SEARCHREFINE_ARTIST, tmp_artist, 512);
|
||||
GetDlgItemTextW(hwndDlg,IDC_SEARCHREFINE_YEAR, tmp_year, 5);
|
||||
|
||||
// End Dialog w/ returning 2: indicates that teh users wants to start a custom search
|
||||
EndDialog(hwndDlg,2);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// from FileInfo.cpp
|
||||
extern HBITMAP getBitmap(ARGB32 * data, int dw, int dh, int targetW, int targetH, HWND parent);
|
||||
extern ARGB32 * decompressImage(const void *data, int datalen, int * dataW, int * dataH);
|
||||
|
||||
HBITMAP loadImage(const void * data, int datalen, int w, int h, HWND parent, int *dw=0, int *dh=0)
|
||||
{
|
||||
int dataW=0, dataH=0;
|
||||
ARGB32* ret = decompressImage(data,datalen,&dataW,&dataH);
|
||||
|
||||
if(dw) *dw = dataW;
|
||||
if(dh) *dh = dataH;
|
||||
if(!ret) return 0;
|
||||
HBITMAP r = getBitmap(ret, dataW, dataH, w, h, parent);
|
||||
WASABI_API_MEMMGR->sysFree(ret);
|
||||
return r;
|
||||
}
|
||||
|
||||
#define GetDlgParent(hwndDlg) GetParent(GetParent(GetParent(hwndDlg)))
|
||||
static INT_PTR CALLBACK imageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
|
||||
{
|
||||
switch(uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
SetWindowLong(hwndDlg,GWLP_USERDATA,lParam);
|
||||
ImgDownloader *d = (ImgDownloader *)lParam;
|
||||
int w=0,h=0;
|
||||
HBITMAP bm = loadImage(d->imgbuf,d->imgbufused,140,140,hwndDlg,&w,&h);
|
||||
SendDlgItemMessage(hwndDlg,IDC_IMAGE,STM_SETIMAGE,IMAGE_BITMAP,(LPARAM)bm);
|
||||
wchar_t buf[1024] = {0};
|
||||
StringCchPrintfW(buf,1024,L"%s: %dx%d (%d kB)",d->desc,w,h,(d->imgbufused/1024));
|
||||
SetDlgItemTextW(hwndDlg,IDC_IMGTEXT,buf);
|
||||
}
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
{
|
||||
ImgDownloader *d = GetParamC(hwndDlg);
|
||||
SetWindowLong(hwndDlg,GWLP_USERDATA,0);
|
||||
if(d) delete d;
|
||||
HBITMAP bm = (HBITMAP)SendDlgItemMessage(hwndDlg,IDC_IMAGE,STM_SETIMAGE,IMAGE_BITMAP,0);
|
||||
if(bm) DeleteObject(bm);
|
||||
}
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
if(LOWORD(wParam) != IDC_SELECT)
|
||||
break;
|
||||
// else run through
|
||||
case WM_LBUTTONDBLCLK:
|
||||
SendMessageW(GetDlgParent(hwndDlg),WM_SELECTED,(WPARAM)hwndDlg,(LPARAM)GetParamC(hwndDlg));
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// scroll shit, nothing interesting is happening down here...
|
||||
|
||||
static INT_PTR CALLBACK scrollChildHostProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
|
||||
{
|
||||
//static HWND m_child;
|
||||
switch(uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
RECT r;
|
||||
HWND hw = GetParent(hwndDlg);
|
||||
GetWindowRect(GetDlgItem(hw,IDC_PLACEHOLDER),&r);
|
||||
ScreenToClient(hw,(LPPOINT)&r);
|
||||
ScreenToClient(hw,((LPPOINT)&r)+1);
|
||||
SetWindowPos(hwndDlg,NULL,r.left,r.top,r.right-r.left,r.bottom-r.top,SWP_NOZORDER|SWP_NOACTIVATE);
|
||||
LPCreateDialogW(IDD_ARTDOWNLOADER_SCROLLCHILD,hwndDlg,(WNDPROC)scrollChildProc);
|
||||
|
||||
SCROLLINFO si={sizeof(si),SIF_RANGE|SIF_PAGE,0};
|
||||
si.nPage = (r.right - r.left);
|
||||
SetScrollInfo(hwndDlg,SB_HORZ,&si,TRUE);
|
||||
}
|
||||
break;
|
||||
case WM_ADDCHILD:
|
||||
{
|
||||
HWND m_child = GetWindow(hwndDlg,GW_CHILD);
|
||||
HWND newChild = (HWND)SendMessageW(m_child,uMsg,wParam,lParam);
|
||||
RECT r,r2;
|
||||
GetClientRect(m_child,&r);
|
||||
GetClientRect(hwndDlg,&r2);
|
||||
SCROLLINFO si={sizeof(si),SIF_RANGE|SIF_PAGE,0};
|
||||
si.nMin = 0;
|
||||
si.nMax = (r.right - r.left);
|
||||
si.nPage = (r2.right - r2.left);
|
||||
if(si.nMax < 0) si.nMax = 0;
|
||||
SetScrollInfo(hwndDlg,SB_HORZ,&si,TRUE);
|
||||
return (INT_PTR)newChild;
|
||||
}
|
||||
break;
|
||||
case WM_HSCROLL:
|
||||
{
|
||||
HWND m_child = GetWindow(hwndDlg,GW_CHILD);
|
||||
int v=0;
|
||||
RECT r;
|
||||
RECT r2;
|
||||
GetClientRect(hwndDlg,&r2);
|
||||
GetClientRect(m_child,&r);
|
||||
int action = LOWORD(wParam);
|
||||
|
||||
if (r2.right < r.right) {
|
||||
if (action == SB_THUMBPOSITION || action == SB_THUMBTRACK) {
|
||||
SCROLLINFO si={sizeof(si),SIF_TRACKPOS|SIF_POS};
|
||||
GetScrollInfo(hwndDlg,SB_HORZ,&si);
|
||||
v=si.nTrackPos;
|
||||
}
|
||||
else if (action == SB_TOP)
|
||||
v=0;
|
||||
else if (action == SB_BOTTOM)
|
||||
v=r.right-r2.right;
|
||||
else if (action == SB_PAGEDOWN || action == SB_LINEDOWN) {
|
||||
SCROLLINFO si={sizeof(si),SIF_TRACKPOS|SIF_POS};
|
||||
GetScrollInfo(hwndDlg,SB_HORZ,&si);
|
||||
if(action == SB_LINEDOWN)
|
||||
v=si.nPos + (r2.right)/10;
|
||||
else
|
||||
v=si.nPos + r2.right;
|
||||
if (v > r.right-r2.right) v=r.right-r2.right;
|
||||
}
|
||||
else if (action == SB_PAGEUP || action == SB_LINEUP) {
|
||||
SCROLLINFO si={sizeof(si),SIF_TRACKPOS|SIF_POS};
|
||||
GetScrollInfo(hwndDlg,SB_HORZ,&si);
|
||||
if(action == SB_LINEUP)
|
||||
v=si.nPos - (r2.right)/10;
|
||||
else
|
||||
v=si.nPos - r2.right;
|
||||
if (v < 0) v=0;
|
||||
}
|
||||
else return 0;
|
||||
|
||||
SetScrollPos(hwndDlg,SB_HORZ,v,!(action == SB_THUMBPOSITION || action == SB_THUMBTRACK));
|
||||
SetWindowPos(m_child,NULL,0-v,0,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
|
||||
}
|
||||
else {
|
||||
SetScrollPos(hwndDlg,SB_HORZ,0,!(action == SB_THUMBPOSITION || action == SB_THUMBTRACK));
|
||||
SetWindowPos(m_child,NULL,0,0,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INT_PTR CALLBACK scrollChildProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
|
||||
{
|
||||
switch(uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
RECT r;
|
||||
GetClientRect(hwndDlg,&r);
|
||||
SetWindowPos(hwndDlg,0,0,0,0,r.bottom,SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
|
||||
}
|
||||
break;
|
||||
case WM_ADDCHILD:
|
||||
{
|
||||
HWND newChild = LPCreateDialogParamW(IDD_ARTDOWNLOADER_IMAGE,hwndDlg,imageProc,lParam);
|
||||
RECT r,r2;
|
||||
GetClientRect(hwndDlg,&r);
|
||||
GetClientRect(newChild,&r2);
|
||||
SetWindowPos(hwndDlg,0,0,0,r.right + r2.right,r.bottom,SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
|
||||
SetWindowPos(newChild,0,r.right,0,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
|
||||
ShowWindow(newChild,SW_SHOWNA);
|
||||
return (INT_PTR)newChild;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,52 @@
|
||||
#include "AppRefCount.h"
|
||||
|
||||
AppRefCount appRefCount;
|
||||
AppRefCount::AppRefCount()
|
||||
{
|
||||
refCount = 1;
|
||||
m_dwThread = 0;
|
||||
}
|
||||
|
||||
STDMETHODIMP AppRefCount::QueryInterface(REFIID riid, PVOID *ppvObject)
|
||||
{
|
||||
if (!ppvObject)
|
||||
return E_POINTER;
|
||||
else if (IsEqualIID(riid, IID_IUnknown))
|
||||
*ppvObject = this;
|
||||
else
|
||||
{
|
||||
*ppvObject = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
ULONG AppRefCount::AddRef(void)
|
||||
{
|
||||
return InterlockedIncrement(&refCount);
|
||||
}
|
||||
|
||||
ULONG AppRefCount::Release(void)
|
||||
{
|
||||
LONG lRef = InterlockedDecrement(&refCount);
|
||||
if (lRef == 0) PostThreadMessage(m_dwThread, WM_NULL, 0, 0);
|
||||
return lRef;
|
||||
}
|
||||
|
||||
int AppRefCount_CanQuit()
|
||||
{
|
||||
return appRefCount.refCount == 0;
|
||||
}
|
||||
|
||||
void *InitAppRefCounterObject(DWORD threadId)
|
||||
{
|
||||
appRefCount.m_dwThread = threadId;
|
||||
return (IUnknown *)&appRefCount;
|
||||
}
|
||||
|
||||
void AppRefCount_Release()
|
||||
{
|
||||
appRefCount.Release();
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#ifdef __cplusplus
|
||||
#include <unknwn.h>
|
||||
class ThreadRefCount : public IUnknown
|
||||
{
|
||||
public:
|
||||
ThreadRefCount();
|
||||
STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
|
||||
STDMETHOD_(ULONG, AddRef)(void);
|
||||
STDMETHOD_(ULONG, Release)(void);
|
||||
|
||||
LONG refCount;
|
||||
};
|
||||
|
||||
class AppRefCount : public IUnknown
|
||||
{
|
||||
public:
|
||||
AppRefCount();
|
||||
STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
|
||||
STDMETHOD_(ULONG, AddRef)(void);
|
||||
STDMETHOD_(ULONG, Release)(void);
|
||||
|
||||
LONG refCount;
|
||||
DWORD m_dwThread;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
void *InitAppRefCounterObject(DWORD threadId);
|
||||
void *GetAppRefCounterObject();
|
||||
void AppRefCount_Release();
|
||||
int AppRefCount_CanQuit();
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,321 @@
|
||||
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
|
||||
** Filename:
|
||||
** Project:
|
||||
** Description:
|
||||
** Author: Ben Allison benski@nullsoft.com
|
||||
** Created:
|
||||
**/
|
||||
#include "main.h"
|
||||
#include "ApplicationCOM.h"
|
||||
#include "../nu/AutoWide.h"
|
||||
#include "../nu/AutoChar.h"
|
||||
#include "../nu/ns_wc.h"
|
||||
#include "api.h"
|
||||
#include "../Plugins/General/gen_ml/ml.h"
|
||||
#include <api/syscb/callbacks/browsercb.h>
|
||||
#include "../Agave/Language/api_language.h"
|
||||
HINSTANCE WASABI_API_LNG_HINST;
|
||||
HINSTANCE WASABI_API_ORIG_HINST;
|
||||
#include <shlwapi.h>
|
||||
#include "TempFileCOM.h"
|
||||
#include "resource.h"
|
||||
#include "JSAPI.h"
|
||||
|
||||
#define CSTR_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)
|
||||
|
||||
bool FilterUrl(const wchar_t *url)
|
||||
{
|
||||
const wchar_t filterNowPlaying[] = L"http://client.winamp.com/nowplaying";
|
||||
size_t urlLength, filterLength;
|
||||
if (NULL == url)
|
||||
return false;
|
||||
|
||||
urlLength = lstrlenW(url);
|
||||
filterLength = ARRAYSIZE(filterNowPlaying) - 1;
|
||||
if (urlLength >= filterLength &&
|
||||
CSTR_EQUAL == CompareStringW(CSTR_INVARIANT, NORM_IGNORECASE,
|
||||
url, (int)filterLength, filterNowPlaying, (int)filterLength))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void myOpenURL(HWND hwnd, const wchar_t *loc)
|
||||
{
|
||||
if (loc)
|
||||
{
|
||||
bool override=false;
|
||||
WASABI_API_SYSCB->syscb_issueCallback(SysCallback::BROWSER, BrowserCallback::ONOPENURL, reinterpret_cast<intptr_t>(loc), reinterpret_cast<intptr_t>(&override));
|
||||
if (!override && false == FilterUrl(loc))
|
||||
ShellExecuteW(hwnd, L"open", loc, NULL, NULL, SW_SHOWNORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
void myOpenURLWithFallback(HWND hwnd, wchar_t *loc, wchar_t *fallbackLoc)
|
||||
{
|
||||
bool override=false;
|
||||
if (loc)
|
||||
{
|
||||
WASABI_API_SYSCB->syscb_issueCallback(SysCallback::BROWSER, BrowserCallback::ONOPENURL, reinterpret_cast<intptr_t>(loc), reinterpret_cast<intptr_t>(&override));
|
||||
}
|
||||
if (!override && false == FilterUrl(loc) && fallbackLoc)
|
||||
ShellExecuteW(hwnd, L"open", fallbackLoc, NULL, NULL, SW_SHOWNORMAL);
|
||||
}
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
DISP_APPLICATION_IDLE = 777,
|
||||
DISP_APPLICATION_GETLANGUAGE,
|
||||
DISP_APPLICATION_ISWINAMPPRO,
|
||||
DISP_APPLICATION_GETCOUNTRY,
|
||||
DISP_APPLICATION_GETLOCALE,
|
||||
DISP_APPLICATION_LAUNCHURL,
|
||||
DISP_APPLICATION_VERSION,
|
||||
DISP_APPLICATION_SPECIALBUILD,
|
||||
DISP_APPLICATION_DOWNLOADMEDIA,
|
||||
DISP_APPLICATION_CREATETEMPFILE,
|
||||
};
|
||||
|
||||
#define CHECK_ID(str, id)\
|
||||
if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
|
||||
{ rgdispid[i] = id; continue; }
|
||||
|
||||
HRESULT ApplicationCOM::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("Idle", DISP_APPLICATION_IDLE)
|
||||
CHECK_ID("GetLanguage", DISP_APPLICATION_GETLANGUAGE)
|
||||
CHECK_ID("IsWinampPro", DISP_APPLICATION_ISWINAMPPRO)
|
||||
CHECK_ID("GetCountry", DISP_APPLICATION_GETCOUNTRY)
|
||||
CHECK_ID("GetLocale", DISP_APPLICATION_GETLOCALE)
|
||||
CHECK_ID("LaunchURL", DISP_APPLICATION_LAUNCHURL)
|
||||
CHECK_ID("Version", DISP_APPLICATION_VERSION)
|
||||
CHECK_ID("GetSpecialBuildName", DISP_APPLICATION_SPECIALBUILD)
|
||||
CHECK_ID("DownloadMedia", DISP_APPLICATION_DOWNLOADMEDIA)
|
||||
CHECK_ID("CreateTempFile", DISP_APPLICATION_CREATETEMPFILE)
|
||||
rgdispid[i] = DISPID_UNKNOWN;
|
||||
unknowns = true;
|
||||
}
|
||||
if (unknowns)
|
||||
return DISP_E_UNKNOWNNAME;
|
||||
else
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT ApplicationCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT ApplicationCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
void GetLanguage(wchar_t *language, size_t size)
|
||||
{
|
||||
StringCchCopyW(language, size, WASABI_API_LNG->GetLanguageIdentifier(LANG_LANG_CODE));
|
||||
}
|
||||
|
||||
void GetCountry(wchar_t *language, size_t size)
|
||||
{
|
||||
// language packs aren't country-specific enough to use them for country info, yet
|
||||
int err = GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME , language, (int)size);
|
||||
if (err == 0) // win95 doesn't support this flag, so we'll check for an error
|
||||
lstrcpynW(language, L"US", (int)size); // and default to english
|
||||
}
|
||||
|
||||
void CALLBACK OpenURLAPC(ULONG_PTR param)
|
||||
{
|
||||
wchar_t *url = (wchar_t *)param;
|
||||
myOpenURL(NULL, url);
|
||||
free(url);
|
||||
}
|
||||
|
||||
void GetPathToStore(wchar_t path_to_store[MAX_PATH])
|
||||
{
|
||||
if (FAILED(SHGetFolderPathW(NULL, CSIDL_MYMUSIC, NULL, SHGFP_TYPE_CURRENT, path_to_store)))
|
||||
{
|
||||
if (FAILED(SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path_to_store)))
|
||||
{
|
||||
// and if that all fails then do a reasonable default
|
||||
GetPrivateProfileStringW(L"gen_ml_config", L"extractpath", L"C:\\My Music", path_to_store, MAX_PATH, ML_INI_FILE);
|
||||
}
|
||||
// if there's no valid My Music folder (typically win2k) then default to %my_documents%\my music
|
||||
else
|
||||
{
|
||||
PathCombineW(path_to_store, path_to_store, L"My Music");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void CALLBACK SendOpenUrl_Callback(HWND hwnd, UINT uMsg, ULONG_PTR dwData, LRESULT lResult)
|
||||
{
|
||||
if (NULL != dwData)
|
||||
free((void*)dwData);
|
||||
}
|
||||
|
||||
HRESULT ApplicationCOM::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_APPLICATION_CREATETEMPFILE:
|
||||
{
|
||||
IDispatch *tempFile =0;
|
||||
if (pdispparams->cArgs == 1)
|
||||
tempFile = new TempFileCOM(pdispparams->rgvarg[0].bstrVal);
|
||||
else
|
||||
tempFile = new TempFileCOM(0);
|
||||
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_DISPATCH;
|
||||
V_DISPATCH(pvarResult) = tempFile;
|
||||
return S_OK;
|
||||
}
|
||||
case DISP_APPLICATION_DOWNLOADMEDIA:
|
||||
{
|
||||
const wchar_t *url = pdispparams->rgvarg[0].bstrVal;
|
||||
if (url)
|
||||
{
|
||||
const wchar_t *destFileSpec=PathFindFileNameW(url);
|
||||
wchar_t path_to_store[MAX_PATH] = {0};
|
||||
GetPathToStore(path_to_store);
|
||||
wchar_t destfile[MAX_PATH] = {0};
|
||||
wchar_t dlgtitle[256] = {0};
|
||||
|
||||
CreateDirectoryW(path_to_store, NULL);
|
||||
|
||||
PathCombineW(destfile, path_to_store, destFileSpec);
|
||||
httpRetrieveFileW(hMainWindow, AutoChar(url), destfile, getStringW(IDS_DOWNLOADING, dlgtitle,256));
|
||||
LMDB_FILE_ADD_INFOW fi = {const_cast<wchar_t *>(destfile), -1, -1};
|
||||
sendMlIpc(ML_IPC_DB_ADDORUPDATEFILEW, (WPARAM)&fi);
|
||||
sendMlIpc(ML_IPC_DB_SYNCDB, 0);
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
case DISP_APPLICATION_IDLE:
|
||||
//Idle();
|
||||
return S_OK;
|
||||
case DISP_APPLICATION_GETLANGUAGE:
|
||||
{
|
||||
wchar_t langName[8] = {0};
|
||||
GetLanguage(langName, 8);
|
||||
|
||||
BSTR language = SysAllocString(langName);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BSTR;
|
||||
V_BSTR(pvarResult) = language;
|
||||
return S_OK;
|
||||
}
|
||||
case DISP_APPLICATION_GETCOUNTRY:
|
||||
{
|
||||
wchar_t countryName[8] = {0};
|
||||
GetCountry(countryName, 8);
|
||||
|
||||
BSTR country = SysAllocString(countryName);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BSTR;
|
||||
V_BSTR(pvarResult) = country;
|
||||
return S_OK;
|
||||
}
|
||||
case DISP_APPLICATION_GETLOCALE:
|
||||
{
|
||||
wchar_t countryName[8] = {0};
|
||||
GetCountry(countryName, 8);
|
||||
|
||||
wchar_t langName[8] = {0};
|
||||
GetLanguage(langName, 8);
|
||||
|
||||
wchar_t language_country[16] = {0};
|
||||
StringCchPrintfW(language_country, 16, L"%s-%s", langName, countryName);
|
||||
|
||||
BSTR languageAndCountryCode = SysAllocString(language_country);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BSTR;
|
||||
V_BSTR(pvarResult) = languageAndCountryCode;
|
||||
return S_OK;
|
||||
}
|
||||
case DISP_APPLICATION_ISWINAMPPRO:
|
||||
{
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BOOL;
|
||||
V_BOOL(pvarResult) = VARIANT_TRUE;
|
||||
return S_OK;
|
||||
}
|
||||
case DISP_APPLICATION_LAUNCHURL:
|
||||
if (pdispparams->cArgs == 1 || pdispparams->cArgs == 2)
|
||||
{
|
||||
if (JSAPI_PARAM_OPTIONAL(pdispparams, 2, boolVal, FALSE) == TRUE)
|
||||
ShellExecuteW(NULL, L"open", JSAPI_PARAM(pdispparams, 1).bstrVal, NULL, L".", 0);
|
||||
else
|
||||
{
|
||||
LPWSTR url = _wcsdup(JSAPI_PARAM(pdispparams, 1).bstrVal);
|
||||
if ( 0 == SendMessageCallback(hMainWindow, WM_WA_IPC, (WPARAM)url, (LPARAM)IPC_OPEN_URL, SendOpenUrl_Callback, (ULONG_PTR)url) &&
|
||||
0 == QueueUserAPC(OpenURLAPC, hMainThread, (ULONG_PTR)url))
|
||||
{
|
||||
free(url);
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
return DISP_E_BADPARAMCOUNT;
|
||||
case DISP_APPLICATION_VERSION:
|
||||
{
|
||||
AutoWide versionW(APP_VERSION);
|
||||
BSTR versionB = SysAllocString(versionW);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BSTR;
|
||||
V_BSTR(pvarResult) = versionB;
|
||||
return S_OK;
|
||||
}
|
||||
case DISP_APPLICATION_SPECIALBUILD:
|
||||
{
|
||||
BSTR special = SysAllocString(SPECIAL_BUILD_NAME);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BSTR;
|
||||
V_BSTR(pvarResult) = special;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
STDMETHODIMP ApplicationCOM::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 ApplicationCOM::AddRef(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ULONG ApplicationCOM::Release(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ApplicationCOM::Idle()
|
||||
{
|
||||
WASABI_API_APP->app_messageLoopStep();
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef NULLSOFT_APPLICATIONCOM_H
|
||||
#define NULLSOFT_APPLICATIONCOM_H
|
||||
|
||||
#include <ocidl.h>
|
||||
|
||||
class ApplicationCOM : public IDispatch
|
||||
{
|
||||
public:
|
||||
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);
|
||||
|
||||
void Idle();
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,134 @@
|
||||
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
|
||||
** Filename:
|
||||
** Project:
|
||||
** Description:
|
||||
** Author: Ben Allison benski@nullsoft.com
|
||||
** Created:
|
||||
**/
|
||||
#include "main.h"
|
||||
#include "BookmarksCOM.h"
|
||||
#include "../nu/AutoChar.h"
|
||||
#include "../nu/AutoWide.h"
|
||||
#include "api.h"
|
||||
|
||||
enum
|
||||
{
|
||||
DISP_BOOKMARK_ADD = 777,
|
||||
DISP_BOOKMARK_GETXML,
|
||||
};
|
||||
|
||||
#define CHECK_ID(str, id)\
|
||||
if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
|
||||
{ rgdispid[i] = id; continue; }
|
||||
|
||||
HRESULT BookmarksCOM::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("Add", DISP_BOOKMARK_ADD)
|
||||
CHECK_ID("GetXML", DISP_BOOKMARK_GETXML)
|
||||
rgdispid[i] = DISPID_UNKNOWN;
|
||||
unknowns = true;
|
||||
}
|
||||
if (unknowns)
|
||||
return DISP_E_UNKNOWNNAME;
|
||||
else
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT BookmarksCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT BookmarksCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
void Bookmark_WriteAsXML(const wchar_t *filename, int max);
|
||||
|
||||
HRESULT BookmarksCOM::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_BOOKMARK_ADD:
|
||||
switch (pdispparams->cArgs)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
Bookmark_additem(pdispparams->rgvarg[0].bstrVal,
|
||||
pdispparams->rgvarg[0].bstrVal);
|
||||
return S_OK;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
Bookmark_additem(pdispparams->rgvarg[1].bstrVal,
|
||||
pdispparams->rgvarg[0].bstrVal);
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DISP_BOOKMARK_GETXML:
|
||||
{
|
||||
int max=0;
|
||||
if (pdispparams->cArgs == 1)
|
||||
{
|
||||
max = _wtoi(pdispparams->rgvarg[0].bstrVal);
|
||||
}
|
||||
wchar_t tempPath[MAX_PATH] = {0};
|
||||
GetTempPathW(MAX_PATH, tempPath);
|
||||
wchar_t tempFile[MAX_PATH] = {0};
|
||||
GetTempFileNameW(tempPath, L"bmx.b4s", 0, tempFile);
|
||||
Bookmark_WriteAsXML(tempFile, max);
|
||||
|
||||
HANDLE plFile = CreateFileW(tempFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
|
||||
size_t flen = SetFilePointer(plFile, 0, NULL, FILE_END);
|
||||
SetFilePointer(plFile, 0, NULL, FILE_BEGIN);
|
||||
|
||||
SAFEARRAY *bufferArray=SafeArrayCreateVector(VT_UI1, 0, (ULONG)flen);
|
||||
void *data = 0;
|
||||
SafeArrayAccessData(bufferArray, &data);
|
||||
DWORD bytesRead = 0;
|
||||
ReadFile(plFile, data, (DWORD)flen, &bytesRead, 0);
|
||||
SafeArrayUnaccessData(bufferArray);
|
||||
CloseHandle(plFile);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_ARRAY|VT_UI1;
|
||||
V_ARRAY(pvarResult) = bufferArray;
|
||||
DeleteFileW(tempFile);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
STDMETHODIMP BookmarksCOM::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 BookmarksCOM::AddRef(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ULONG BookmarksCOM::Release(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef NULLSOFT_BOOKMARKSCOM_H
|
||||
#define NULLSOFT_BOOKMARKSCOM_H
|
||||
|
||||
#include <ocidl.h>
|
||||
|
||||
class BookmarksCOM : public IDispatch
|
||||
{
|
||||
public:
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,87 @@
|
||||
#include "main.h"
|
||||
#include "attributes.h"
|
||||
|
||||
_bool_base::_bool_base() : value(false) {}
|
||||
|
||||
bool _bool_base::GetBool()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
void _bool_base::SetBool(bool boolValue)
|
||||
{
|
||||
value = boolValue;
|
||||
}
|
||||
|
||||
intptr_t _bool_base::GetInt()
|
||||
{
|
||||
return value ? 1 : 0;
|
||||
}
|
||||
|
||||
void _bool_base::SetInt(intptr_t intValue)
|
||||
{
|
||||
value = !!intValue;
|
||||
}
|
||||
|
||||
_bool_base::operator intptr_t()
|
||||
{
|
||||
return GetInt();
|
||||
}
|
||||
|
||||
intptr_t _bool_base::operator =(intptr_t intValue)
|
||||
{
|
||||
value = !!intValue;
|
||||
return GetInt();
|
||||
}
|
||||
|
||||
bool _bool_base::operator =(bool boolValue)
|
||||
{
|
||||
value = boolValue;
|
||||
return GetBool();
|
||||
}
|
||||
|
||||
|
||||
_bool_base::operator bool()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
_bool_base::operator UINT()
|
||||
{
|
||||
return value?1:0;
|
||||
}
|
||||
|
||||
bool _bool_base::operator !()
|
||||
{
|
||||
return !value;
|
||||
}
|
||||
|
||||
/* --------------------- */
|
||||
|
||||
_bool::_bool(bool defaultValue)
|
||||
{
|
||||
value = defaultValue;
|
||||
}
|
||||
|
||||
#define CBCLASS _bool
|
||||
START_DISPATCH;
|
||||
CB(IFC_CONFIGITEM_GETBOOL, GetBool)
|
||||
CB(IFC_CONFIGITEM_GETINT, GetInt)
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
|
||||
/* --------------------- */
|
||||
|
||||
_mutable_bool::_mutable_bool(bool defaultValue)
|
||||
{
|
||||
value = defaultValue;
|
||||
}
|
||||
|
||||
#define CBCLASS _mutable_bool
|
||||
START_DISPATCH;
|
||||
CB(IFC_CONFIGITEM_GETBOOL, GetBool)
|
||||
CB(IFC_CONFIGITEM_GETINT, GetInt)
|
||||
VCB(IFC_CONFIGITEM_SETINT, SetInt)
|
||||
VCB(IFC_CONFIGITEM_SETBOOL, SetBool)
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
@@ -0,0 +1,368 @@
|
||||
#include "Main.h"
|
||||
#include "Browser.h"
|
||||
#include "menuv5.h"
|
||||
#include "ExternalCOM.h"
|
||||
#include "wa_dlg.h"
|
||||
#include "resource.h"
|
||||
#include "../nu/ns_wc.h"
|
||||
|
||||
Browser *browser = 0;
|
||||
static WNDPROC oldBrowserProc = 0;
|
||||
static DWORD browserThreadId=0;
|
||||
static HANDLE killBrowserEvent=0;
|
||||
static HANDLE browserThreadHandle=0;
|
||||
static BOOL fUnicode = FALSE;
|
||||
static LRESULT WINAPI BrowserSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
case WM_PAINT:
|
||||
{
|
||||
HDC out = GetDC(hwnd);
|
||||
RECT r;
|
||||
GetClientRect(hwnd, &r);
|
||||
r.left = 11;
|
||||
r.top = 20;
|
||||
r.right -= 8;
|
||||
r.bottom -= 14;
|
||||
|
||||
HBRUSH b = CreateSolidBrush(WADlg_getColor(WADLG_WNDBG));
|
||||
FillRect(out, &r, b);
|
||||
DeleteObject(b);
|
||||
ValidateRect(hwnd, &r);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_USER + 0x100:
|
||||
if (wParam == 1 && lParam)
|
||||
{
|
||||
config_si_wx = ((POINT *)lParam)->x;
|
||||
config_si_wy = ((POINT *)lParam)->y;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_USER + 0x101:
|
||||
if (wParam == 1 && lParam)
|
||||
{
|
||||
config_si_width = ((POINT *)lParam)->x;
|
||||
config_si_height = ((POINT *)lParam)->y;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_USER + 0x102:
|
||||
{
|
||||
if (wParam == 1)
|
||||
{
|
||||
if (!config_minimized)
|
||||
ShowWindow(browser->m_hwnd, SW_SHOW);
|
||||
config_si_open = 1;
|
||||
const char *url = PlayList_getbrowser(PlayList_getPosition());
|
||||
if (url && *url)
|
||||
browser->NavigateToName(url);
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowWindow(browser->m_hwnd, SW_HIDE);
|
||||
config_si_open = 0;
|
||||
}
|
||||
browser->SetMenuCheckMark();
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_USER + 101:
|
||||
{
|
||||
ShowWindow(hwnd, SW_HIDE);
|
||||
ShowWindow(browser->m_hwnd, SW_HIDE);
|
||||
config_si_open = 0;
|
||||
browser->SetMenuCheckMark();
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_DESTROY:
|
||||
browser->m_hwnd = 0;
|
||||
SetEvent(killBrowserEvent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (oldBrowserProc) return (fUnicode) ? CallWindowProcW(oldBrowserProc, hwnd, msg, wParam, lParam) : CallWindowProcA(oldBrowserProc, hwnd, msg, wParam, lParam);
|
||||
else return (fUnicode) ? DefWindowProcW(hwnd, msg, wParam, lParam) : DefWindowProcA(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
// {25CE50EF-3EE2-4356-A638-6E495C44BFB8}
|
||||
static const GUID StationInfoGUID =
|
||||
{ 0x25ce50ef, 0x3ee2, 0x4356, { 0xa6, 0x38, 0x6e, 0x49, 0x5c, 0x44, 0xbf, 0xb8 } };
|
||||
|
||||
Browser::Browser()
|
||||
: minimised(false), threadId(0), state(0)
|
||||
{
|
||||
}
|
||||
|
||||
Browser::~Browser()
|
||||
{
|
||||
}
|
||||
|
||||
HWND Browser::CreateHWND()
|
||||
{
|
||||
if (!m_hwnd)
|
||||
{
|
||||
threadId = GetCurrentThreadId();
|
||||
|
||||
state.flags = EMBED_FLAGS_NOWINDOWMENU;
|
||||
state.me = 0;
|
||||
state.r.left = config_si_wx;
|
||||
state.r.right = config_si_wx + config_si_width;
|
||||
state.r.top = config_si_wy;
|
||||
state.r.bottom = config_si_wy + config_si_height;
|
||||
|
||||
state.flags |= EMBED_FLAGS_GUID;
|
||||
void *blah = state.extra_data+4;
|
||||
memcpy(blah, &StationInfoGUID, sizeof(GUID));
|
||||
|
||||
HWND owner = (HWND)SendMessage(hMainWindow, WM_WA_IPC, (WPARAM)&state, IPC_GET_EMBEDIF);
|
||||
|
||||
m_hwnd = owner;
|
||||
setLocation(11, 20, config_si_width - 19, config_si_height - 34);
|
||||
fUnicode = IsWindowUnicode(owner);
|
||||
oldBrowserProc = (WNDPROC) ((fUnicode) ? SetWindowLongPtrW(owner, GWLP_WNDPROC, (LONG_PTR)BrowserSubclassProc) :
|
||||
SetWindowLongPtrA(owner, GWLP_WNDPROC, (LONG_PTR)BrowserSubclassProc));
|
||||
wchar_t langBuf[1024];
|
||||
SetWindowTextW(owner, getStringW(IDS_STATIONINFOCAPTION, langBuf, 1024));
|
||||
}
|
||||
EnableMenuItem(main_menu, WINAMP_BROWSER_ID, MF_BYCOMMAND | MF_ENABLED);
|
||||
|
||||
if (config_si_autoshow || (config_si_open/* && !visible*/))
|
||||
{
|
||||
if(g_showcode!=SW_SHOWMINIMIZED && !config_minimized)
|
||||
ShowWindow(m_hwnd, SW_SHOW);
|
||||
else
|
||||
browser->minimised = 1;
|
||||
config_si_open = 1;
|
||||
browser->SetMenuCheckMark();
|
||||
}
|
||||
|
||||
return m_hwnd;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void Browser::NavigateToName(LPCTSTR pszUrl)
|
||||
{
|
||||
if (!config_si_open)
|
||||
return ;
|
||||
if (!m_pweb) return ;
|
||||
DWORD dwChars = lstrlen (pszUrl) + 1;
|
||||
LPWSTR pwszUrl = (LPWSTR)LocalAlloc (LPTR, dwChars * sizeof (WCHAR));
|
||||
long moptions = navNoReadFromCache | navNoWriteToCache | navNoHistory;
|
||||
VARIANT options;
|
||||
memset( (void*)&options, 0, sizeof(VARIANT));
|
||||
V_VT(&options) = VT_I4;
|
||||
V_I4(&options) = moptions;
|
||||
if (pwszUrl)
|
||||
{
|
||||
MultiByteToWideCharSZ(CP_ACP, 0, pszUrl, -1, pwszUrl, dwChars);
|
||||
m_pweb->Navigate (pwszUrl, &options , 0, 0, 0);
|
||||
LocalFree (pwszUrl);
|
||||
}
|
||||
}
|
||||
|
||||
#define VIDEO_GENFF_SIZEREQUEST (WM_USER+2048)
|
||||
void Browser::Resized(unsigned long width, unsigned long height)
|
||||
{
|
||||
if (!config_si_autosize)
|
||||
return ;
|
||||
setLocation(11, 20, width, height);
|
||||
config_si_width = width + 19;
|
||||
config_si_height = height + 34;
|
||||
if (GetParent(m_hwnd))
|
||||
SendMessage(GetParent(m_hwnd), VIDEO_GENFF_SIZEREQUEST, width, height);
|
||||
else
|
||||
SetWindowPos(m_hwnd, 0, 0, 0, width + 19, height + 34, SWP_NOMOVE | SWP_ASYNCWINDOWPOS);
|
||||
|
||||
InvalidateRect(m_hwnd, NULL, TRUE);
|
||||
}
|
||||
|
||||
HRESULT Browser::GetExternal(IDispatch __RPC_FAR *__RPC_FAR *ppDispatch)
|
||||
{
|
||||
*ppDispatch = (IDispatch *) & externalCOM;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void Browser::ToggleVisible(int showing)
|
||||
{
|
||||
if ((!config_si_open && !showing) || (showing && minimised))
|
||||
{
|
||||
if(minimised) minimised = 0;
|
||||
CreateHWND();
|
||||
if (m_hwnd)
|
||||
PostMessage(m_hwnd, WM_USER + 0x102, 1, 0);
|
||||
}
|
||||
else if(!showing)
|
||||
{
|
||||
if(minimised) minimised = 0;
|
||||
if (m_hwnd)
|
||||
PostMessage(m_hwnd, WM_USER + 0x102, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Browser::OnNavigateComplete()
|
||||
{
|
||||
setVisible(TRUE);
|
||||
RECT r;
|
||||
GetClientRect(m_hwnd, &r);
|
||||
setLocation(11, 20, r.right - 19, r.bottom - 34);
|
||||
}
|
||||
|
||||
void Browser::SetMenuCheckMark()
|
||||
{
|
||||
MENUITEMINFO i = {sizeof(i), MIIM_STATE , MFT_STRING, config_si_open ? MFS_CHECKED : MFS_UNCHECKED, WINAMP_BROWSER_ID};
|
||||
SetMenuItemInfo(main_menu, WINAMP_BROWSER_ID, FALSE, &i);
|
||||
}
|
||||
|
||||
/* ---- APCs ---- */
|
||||
VOID CALLBACK ToggleVisibleAPC(ULONG_PTR param)
|
||||
{
|
||||
browser->ToggleVisible(param);
|
||||
}
|
||||
|
||||
VOID CALLBACK SetVisibleAPC(ULONG_PTR param)
|
||||
{
|
||||
BOOL visible = (BOOL)param;
|
||||
browser->setVisible(visible);
|
||||
}
|
||||
|
||||
VOID CALLBACK NavigateAPC(ULONG_PTR param)
|
||||
{
|
||||
char *url = (char *)param;
|
||||
browser->NavigateToName(url);
|
||||
free(url);
|
||||
}
|
||||
|
||||
VOID CALLBACK CreateHWNDAPC(ULONG_PTR param)
|
||||
{
|
||||
browser->CreateHWND();
|
||||
}
|
||||
|
||||
HANDLE browserEvent=0;
|
||||
/* ---- ---- */
|
||||
static DWORD CALLBACK BrowserThread(LPVOID param)
|
||||
{
|
||||
if (!browser)
|
||||
browser = new Browser;
|
||||
killBrowserEvent = CreateEvent(0, TRUE, FALSE, 0);
|
||||
SetEvent(browserEvent);
|
||||
|
||||
while (1)
|
||||
{
|
||||
DWORD dwStatus = MsgWaitForMultipleObjectsEx(1, &killBrowserEvent,
|
||||
INFINITE, QS_ALLINPUT,
|
||||
MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
|
||||
if (dwStatus == WAIT_OBJECT_0)
|
||||
{
|
||||
browser->remove();
|
||||
browser->close();
|
||||
browser->Release();
|
||||
CloseHandle(killBrowserEvent);
|
||||
return 0;
|
||||
}
|
||||
else if (dwStatus == WAIT_OBJECT_0 + 1)
|
||||
{
|
||||
MSG msg;
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
{
|
||||
if (msg.message == WM_QUIT)
|
||||
{
|
||||
browser->remove();
|
||||
browser->close();
|
||||
browser->Release();
|
||||
CloseHandle(killBrowserEvent);
|
||||
return 0;
|
||||
}
|
||||
if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN ||
|
||||
msg.message == WM_KEYUP || msg.message == WM_SYSKEYUP)
|
||||
{
|
||||
if (!browser->translateKey(&msg))
|
||||
{
|
||||
PostMessage(hMainWindow, msg.message, msg.wParam, msg.lParam);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!browser->translateKey(&msg))
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void CreateBrowser()
|
||||
{
|
||||
if (!browser)
|
||||
{
|
||||
browserEvent = CreateEvent(0, TRUE, FALSE, 0);
|
||||
browserThreadHandle = CreateThread(0, 0, BrowserThread, 0, 0, &browserThreadId);
|
||||
WaitForSingleObject(browserEvent, INFINITE);
|
||||
}
|
||||
}
|
||||
|
||||
static void CallAPC(PAPCFUNC func, ULONG_PTR param)
|
||||
{
|
||||
if (browserThreadHandle)
|
||||
{
|
||||
DWORD curThreadId = GetCurrentThreadId();
|
||||
if (curThreadId == browserThreadId)
|
||||
func(param);
|
||||
else
|
||||
{
|
||||
QueueUserAPC(func, browserThreadHandle, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Browser_toggleVisible(int showing)
|
||||
{
|
||||
CreateBrowser();
|
||||
CallAPC(ToggleVisibleAPC, showing);
|
||||
}
|
||||
|
||||
void CloseBrowser()
|
||||
{
|
||||
if (!browser || !browser->m_hwnd)
|
||||
return ;
|
||||
if (config_si_autohide)
|
||||
PostMessage(browser->m_hwnd, WM_USER + 0x102, 0, 0);
|
||||
else
|
||||
CallAPC(SetVisibleAPC, FALSE);
|
||||
}
|
||||
|
||||
void LaunchBrowser(const char *url)
|
||||
{
|
||||
OpenBrowser();
|
||||
CallAPC(NavigateAPC, (ULONG_PTR)_strdup(url));
|
||||
}
|
||||
|
||||
void OpenBrowser()
|
||||
{
|
||||
CreateBrowser();
|
||||
CallAPC(CreateHWNDAPC, 0);
|
||||
}
|
||||
|
||||
void Browser_init()
|
||||
{
|
||||
MENUITEMINFO i = {sizeof(i), MIIM_ID | MIIM_STATE | MIIM_TYPE, MFT_STRING, MFS_UNCHECKED, WINAMP_BROWSER_ID};
|
||||
i.dwTypeData = getString(IDS_STATIONINFO_MENU,NULL,0);;
|
||||
InsertMenuItem(main_menu, 10 + g_mm_optionsbase_adj, TRUE, &i);
|
||||
g_mm_optionsbase_adj++;
|
||||
}
|
||||
|
||||
void Browser_kill()
|
||||
{
|
||||
if (browserThreadHandle)
|
||||
{
|
||||
SetEvent(killBrowserEvent); // just in case, so we don't hang here
|
||||
WaitForSingleObject(browserThreadHandle, INFINITE);
|
||||
CloseHandle(browserThreadHandle);
|
||||
browserThreadHandle=0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef NULLSOFT_BROWSERH
|
||||
#define NULLSOFT_BROWSERH
|
||||
|
||||
#include "../nu/HTMLContainer.h"
|
||||
#include "wa_ipc.h"
|
||||
|
||||
class Browser : public HTMLContainer
|
||||
{
|
||||
public:
|
||||
Browser();
|
||||
~Browser();
|
||||
static WNDCLASS *wc;
|
||||
static HRESULT CALLBACK WindowProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
void NavigateToName(LPCTSTR pszUrl);
|
||||
void Resized(unsigned long width, unsigned long height);
|
||||
STDMETHOD (GetExternal)(IDispatch __RPC_FAR *__RPC_FAR *ppDispatch);
|
||||
void ToggleVisible(int showing);
|
||||
embedWindowState state;
|
||||
bool minimised;
|
||||
void SetMenuCheckMark();
|
||||
virtual void OnNavigateComplete();
|
||||
HWND CreateHWND();
|
||||
DWORD threadId;
|
||||
};
|
||||
|
||||
class UpdateBrowser : public HTMLContainer
|
||||
{
|
||||
public:
|
||||
HWND CreateHWND();
|
||||
static WNDCLASS *wc;
|
||||
static HRESULT CALLBACK WindowProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
void NavigateToName(LPCTSTR pszUrl);
|
||||
void Resized(unsigned long width, unsigned long height);
|
||||
STDMETHOD (GetExternal)(IDispatch __RPC_FAR *__RPC_FAR *ppDispatch);
|
||||
embedWindowState state;
|
||||
virtual void OnNavigateComplete();
|
||||
|
||||
};
|
||||
|
||||
HRESULT UpdateWindow_Show(LPCSTR pszUrl);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,101 @@
|
||||
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
|
||||
** Filename:
|
||||
** Project:
|
||||
** Description:
|
||||
** Author: Ben Allison benski@nullsoft.com
|
||||
** Created:
|
||||
**/
|
||||
#include "main.h"
|
||||
#include "BrowserCOM.h"
|
||||
#include "Browser.h"
|
||||
#include "../nu/AutoChar.h"
|
||||
|
||||
//extern Browser *browser;
|
||||
extern UpdateBrowser *updateBrowser;
|
||||
enum
|
||||
{
|
||||
DISP_BROWSER_SETSIZE = 777,
|
||||
DISP_BROWSER_SETTITLE,
|
||||
DISP_BROWSER_SETUPDATESIZE,
|
||||
DISP_BROWSER_HIDDEN,
|
||||
};
|
||||
|
||||
#define CHECK_ID(str, id) if (wcscmp(rgszNames[i], L##str) == 0) { rgdispid[i] = id; continue; }
|
||||
HRESULT BrowserCOM::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("SetSize", DISP_BROWSER_SETSIZE)
|
||||
CHECK_ID("SetUpdateSize", DISP_BROWSER_SETUPDATESIZE)
|
||||
//CHECK_ID("SetTitle", DISP_BROWSER_SETTITLE)
|
||||
//CHECK_ID("hidden", DISP_BROWSER_HIDDEN)
|
||||
|
||||
rgdispid[i] = DISPID_UNKNOWN;
|
||||
unknowns = true;
|
||||
|
||||
}
|
||||
if (unknowns)
|
||||
return DISP_E_UNKNOWNNAME;
|
||||
else
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT BrowserCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT BrowserCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
|
||||
HRESULT BrowserCOM::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_BROWSER_SETUPDATESIZE:
|
||||
if (pdispparams->cArgs == 2 && updateBrowser)
|
||||
{
|
||||
updateBrowser->Resized(pdispparams->rgvarg[1].lVal, pdispparams->rgvarg[0].lVal);
|
||||
return S_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
STDMETHODIMP BrowserCOM::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 BrowserCOM::AddRef(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ULONG BrowserCOM::Release(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef NULLSOFT_BROWSERCOMH
|
||||
#define NULLSOFT_BROWSERCOMH
|
||||
|
||||
#include <ocidl.h>
|
||||
|
||||
class BrowserCOM : public IDispatch
|
||||
{
|
||||
public:
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,67 @@
|
||||
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
|
||||
** Filename:
|
||||
** Project:
|
||||
** Description:
|
||||
** Author:
|
||||
** Created:
|
||||
**/
|
||||
#include "../Agave/DecodeFile/ifc_audiostream.h"
|
||||
#include "../Agave/DecodeFile/api_decodefile.h"
|
||||
|
||||
#include "./BurnManager.h"
|
||||
|
||||
BurnManager::BurnManager(void) : decodeFile(NULL), context(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
BurnManager::~BurnManager()
|
||||
{
|
||||
}
|
||||
|
||||
void BurnManager::SetDecodeAPI(api_decodefile *decoderAPI)
|
||||
{
|
||||
decodeFile = decoderAPI;
|
||||
}
|
||||
|
||||
api_decodefile *BurnManager::GetDecodeAPI(void)
|
||||
{
|
||||
return decodeFile;
|
||||
}
|
||||
void BurnManager::SetFiles(size_t numFiles, const wchar_t **filenames, BurnManagerCallback *callback)
|
||||
{
|
||||
WRESULT *results = new WRESULT[numFiles];
|
||||
memset(results, 0, numFiles * sizeof(WRESULT));
|
||||
callback->OnLicenseCallback(numFiles, results);
|
||||
delete [] results;
|
||||
}
|
||||
|
||||
ifc_audiostream* BurnManager::CreateDecoder(const wchar_t *filename)
|
||||
{
|
||||
AudioParameters parameters;
|
||||
parameters.bitsPerSample = 16;
|
||||
parameters.channels = 2;
|
||||
parameters.sampleRate = 44100;
|
||||
|
||||
ifc_audiostream *decoder = decodeFile->OpenAudio(filename, ¶meters);
|
||||
if (decoder && (parameters.bitsPerSample != 16 || parameters.channels != 2 || parameters.sampleRate != 44100))
|
||||
{
|
||||
parameters.errorCode = API_DECODEFILE_BAD_RESAMPLE;
|
||||
decodeFile->CloseAudio(decoder);
|
||||
decoder=0;
|
||||
}
|
||||
return decoder;
|
||||
}
|
||||
|
||||
void BurnManager::CloseDecoder(ifc_audiostream *decoder)
|
||||
{
|
||||
decodeFile->CloseAudio(decoder);
|
||||
}
|
||||
|
||||
void BurnManager::CancelBurn()
|
||||
{
|
||||
}
|
||||
|
||||
void BurnManager::BurnFinished()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Agave/DecodeFile/ifc_audiostream.h"
|
||||
#include "../Agave/DecodeFile/api_decodefile.h"
|
||||
|
||||
#include "../burnlib/manager.h"
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef NULLSOFT_WINAMP_COMMONREADER_H
|
||||
#define NULLSOFT_WINAMP_COMMONREADER_H
|
||||
|
||||
class CommonReader : public ifc_audiostream
|
||||
{
|
||||
public:
|
||||
virtual ~CommonReader() {}
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,317 @@
|
||||
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
|
||||
** Filename:
|
||||
** Project:
|
||||
** Description:
|
||||
** Author: Ben Allison benski@nullsoft.com
|
||||
** Created:
|
||||
**/
|
||||
#include "Main.h"
|
||||
#include "CurrentSongCOM.h"
|
||||
#include "../nu/AutoWide.h"
|
||||
#include "Browser.h"
|
||||
#include "JSAPI.h"
|
||||
#include <malloc.h>
|
||||
|
||||
HANDLE DuplicateCurrentThread()
|
||||
{
|
||||
HANDLE fakeHandle = GetCurrentThread();
|
||||
HANDLE copiedHandle = 0;
|
||||
HANDLE processHandle = GetCurrentProcess();
|
||||
DuplicateHandle(processHandle, fakeHandle, processHandle, &copiedHandle, 0, FALSE, DUPLICATE_SAME_ACCESS);
|
||||
return copiedHandle;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
DISP_CURRENTSONG_GETFILENAME = 777,
|
||||
DISP_CURRENTSONG_GETFILETITLE ,
|
||||
DISP_CURRENTSONG_GETFILELENGTH,
|
||||
DISP_CURRENTSONG_GETMETADATA ,
|
||||
DISP_CURRENTSONG_GETPLAYPOSITION ,
|
||||
DISP_CURRENTSONG_ISPLAYING ,
|
||||
DISP_CURRENTSONG_ISSTOPPED ,
|
||||
DISP_CURRENTSONG_ISPAUSED ,
|
||||
DISP_CURRENTSONG_PAUSE ,
|
||||
DISP_CURRENTSONG_RESUME,
|
||||
DISP_CURRENTSONG_REGISTERMETADATACALLBACK,
|
||||
DISP_CURRENTSONG_UNREGISTERMETADATACALLBACK,
|
||||
DISP_CURRENTSONG_REGISTERTITLECHANGECALLBACK,
|
||||
DISP_CURRENTSONG_UNREGISTERTITLECHANGECALLBACK,
|
||||
DISP_CURRENTSONG_REFRESHTITLE,
|
||||
};
|
||||
|
||||
|
||||
#define CHECK_ID(str, id)\
|
||||
if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
|
||||
{ rgdispid[i] = id; continue; }
|
||||
|
||||
HRESULT CurrentSongCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(riid);
|
||||
|
||||
bool unknowns = false;
|
||||
for (unsigned int i = 0;i != cNames;i++)
|
||||
{
|
||||
CHECK_ID("GetFilename", DISP_CURRENTSONG_GETFILENAME) // July 27, 2005
|
||||
CHECK_ID("GetFileTitle", DISP_CURRENTSONG_GETFILETITLE) // July 27, 2005
|
||||
CHECK_ID("GetFileLength", DISP_CURRENTSONG_GETFILELENGTH) // July 27, 2005
|
||||
CHECK_ID("GetMetadata", DISP_CURRENTSONG_GETMETADATA) // July 27, 2005
|
||||
CHECK_ID("GetPlayPosition", DISP_CURRENTSONG_GETPLAYPOSITION) // July 27, 2005
|
||||
CHECK_ID("IsPlaying", DISP_CURRENTSONG_ISPLAYING) // July 27, 2005
|
||||
CHECK_ID("IsStopped", DISP_CURRENTSONG_ISSTOPPED) // July 27, 2005
|
||||
CHECK_ID("IsPaused", DISP_CURRENTSONG_ISPAUSED) // July 27, 2005
|
||||
CHECK_ID("Pause", DISP_CURRENTSONG_PAUSE)
|
||||
CHECK_ID("Resume", DISP_CURRENTSONG_RESUME)
|
||||
CHECK_ID("RegisterMetadataCallback", DISP_CURRENTSONG_REGISTERMETADATACALLBACK)
|
||||
CHECK_ID("UnregisterMetadataCallback", DISP_CURRENTSONG_UNREGISTERMETADATACALLBACK)
|
||||
CHECK_ID("RegisterTitleChangeCallback", DISP_CURRENTSONG_REGISTERTITLECHANGECALLBACK)
|
||||
CHECK_ID("UnregisterTitleChangeCallback", DISP_CURRENTSONG_UNREGISTERTITLECHANGECALLBACK)
|
||||
CHECK_ID("RefreshTitle", DISP_CURRENTSONG_REFRESHTITLE)
|
||||
|
||||
rgdispid[i] = DISPID_UNKNOWN;
|
||||
unknowns = true;
|
||||
}
|
||||
if (unknowns)
|
||||
return DISP_E_UNKNOWNNAME;
|
||||
else
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CurrentSongCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(itinfo);
|
||||
UNREFERENCED_PARAMETER(lcid);
|
||||
UNREFERENCED_PARAMETER(pptinfo);
|
||||
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT CurrentSongCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(pctinfo);
|
||||
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CurrentSongCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(riid);
|
||||
UNREFERENCED_PARAMETER(lcid);
|
||||
UNREFERENCED_PARAMETER(wFlags);
|
||||
UNREFERENCED_PARAMETER(pexecinfo);
|
||||
|
||||
switch (dispid)
|
||||
{
|
||||
case DISP_CURRENTSONG_REFRESHTITLE:
|
||||
|
||||
SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_UPDTITLE);
|
||||
return S_OK;
|
||||
|
||||
case DISP_CURRENTSONG_REGISTERTITLECHANGECALLBACK:
|
||||
return titleChangeCallbacks.RegisterFromDispParam(pdispparams, 0, puArgErr);
|
||||
case DISP_CURRENTSONG_UNREGISTERTITLECHANGECALLBACK:
|
||||
return titleChangeCallbacks.UnregisterFromDispParam(pdispparams, 0, puArgErr);
|
||||
case DISP_CURRENTSONG_REGISTERMETADATACALLBACK:
|
||||
return metadataCallbacks.RegisterFromDispParam(pdispparams, 0, puArgErr);
|
||||
case DISP_CURRENTSONG_UNREGISTERMETADATACALLBACK:
|
||||
return metadataCallbacks.UnregisterFromDispParam(pdispparams, 0, puArgErr);
|
||||
case DISP_CURRENTSONG_GETMETADATA:
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
|
||||
{
|
||||
wchar_t buffer[4096] = {0};
|
||||
extendedFileInfoStructW info;
|
||||
|
||||
info.filename = FileName;
|
||||
info.metadata = pdispparams->rgvarg[0].bstrVal;
|
||||
info.ret = buffer;
|
||||
info.retlen = sizeof(buffer)/sizeof(wchar_t);
|
||||
|
||||
if (NULL != info.filename &&
|
||||
NULL != info.metadata)
|
||||
{
|
||||
if (0 == SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&info, IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE))
|
||||
info.ret = NULL;
|
||||
|
||||
JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(info.ret));
|
||||
}
|
||||
else
|
||||
JSAPI_EMPTY_RESULT(pvarResult);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case DISP_CURRENTSONG_GETFILENAME:
|
||||
{
|
||||
BSTR name = SysAllocString(FileName);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BSTR;
|
||||
V_BSTR(pvarResult) = name;
|
||||
return S_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case DISP_CURRENTSONG_GETFILETITLE:
|
||||
{
|
||||
BSTR title = SysAllocString(FileTitle);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BSTR;
|
||||
V_BSTR(pvarResult) = title;
|
||||
return S_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case DISP_CURRENTSONG_GETFILELENGTH:
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_I4;
|
||||
V_I4(pvarResult) = in_getlength();
|
||||
return S_OK;
|
||||
|
||||
case DISP_CURRENTSONG_GETPLAYPOSITION:
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_I4;
|
||||
V_I4(pvarResult) = in_getouttime();
|
||||
return S_OK;
|
||||
|
||||
case DISP_CURRENTSONG_ISPLAYING:
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BOOL;
|
||||
V_BOOL(pvarResult) = (0 != playing) ? VARIANT_TRUE : VARIANT_FALSE;
|
||||
return S_OK;
|
||||
|
||||
case DISP_CURRENTSONG_ISSTOPPED:
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BOOL;
|
||||
V_BOOL(pvarResult) = (0 == playing) ? VARIANT_TRUE : VARIANT_FALSE;
|
||||
return S_OK;
|
||||
|
||||
case DISP_CURRENTSONG_ISPAUSED:
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BOOL;
|
||||
V_BOOL(pvarResult) = (0 != paused) ? VARIANT_TRUE : VARIANT_FALSE;
|
||||
return S_OK;
|
||||
case DISP_CURRENTSONG_PAUSE:
|
||||
PausePlaying();
|
||||
return S_OK;
|
||||
case DISP_CURRENTSONG_RESUME:
|
||||
UnPausePlaying();
|
||||
return S_OK;
|
||||
|
||||
}
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
STDMETHODIMP CurrentSongCOM::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 CurrentSongCOM::AddRef(void)
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ULONG CurrentSongCOM::Release(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void TitleChanged_NotifyCb(IDispatch *dispatch, void *param)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(param);
|
||||
|
||||
DISPPARAMS params;
|
||||
unsigned int ret;
|
||||
|
||||
if (NULL == dispatch)
|
||||
return;
|
||||
|
||||
params.cArgs = 0;
|
||||
params.cNamedArgs = 0;
|
||||
params.rgdispidNamedArgs = 0;
|
||||
params.rgvarg = 0;
|
||||
|
||||
if (!(config_no_visseh&8))
|
||||
{
|
||||
try
|
||||
{
|
||||
dispatch->Invoke(0, GUID_NULL, 0, DISPATCH_METHOD, ¶ms, 0, 0, &ret);
|
||||
}
|
||||
catch (...)
|
||||
{}
|
||||
}
|
||||
else
|
||||
dispatch->Invoke(0, GUID_NULL, 0, DISPATCH_METHOD, ¶ms, 0, 0, &ret);
|
||||
}
|
||||
|
||||
void CurrentSongCOM::TitleChanged()
|
||||
{
|
||||
titleChangeCallbacks.Notify(TitleChanged_NotifyCb, NULL, NULL);
|
||||
}
|
||||
|
||||
static void MetadataChanged_NotifyCb(IDispatch *dispatch, void *param)
|
||||
{
|
||||
VARIANT argument;
|
||||
DISPPARAMS params;
|
||||
|
||||
if (NULL == dispatch)
|
||||
return;
|
||||
|
||||
VariantInit(&argument);
|
||||
V_VT(&argument) = VT_BSTR;
|
||||
V_BSTR(&argument) = (BSTR)param;
|
||||
|
||||
params.cArgs = 1;
|
||||
params.cNamedArgs = 0;
|
||||
params.rgdispidNamedArgs = NULL;
|
||||
params.rgvarg = &argument;
|
||||
unsigned int ret;
|
||||
|
||||
if (!(config_no_visseh&8))
|
||||
{
|
||||
try
|
||||
{
|
||||
dispatch->Invoke(0, GUID_NULL, 0, DISPATCH_METHOD, ¶ms, 0, 0, &ret);
|
||||
}
|
||||
catch (...)
|
||||
{}
|
||||
}
|
||||
else
|
||||
dispatch->Invoke(0, GUID_NULL, 0, DISPATCH_METHOD, ¶ms, 0, 0, &ret);
|
||||
|
||||
}
|
||||
|
||||
static void MetadataChanged_FreeCb(void *param)
|
||||
{
|
||||
BSTR bstr = (BSTR)param;
|
||||
SysFreeString(bstr);
|
||||
}
|
||||
|
||||
void CurrentSongCOM::MetadataChanged(char *metadataString)
|
||||
{
|
||||
AutoWide wideMetadata(metadataString);
|
||||
BSTR bstr = SysAllocString(wideMetadata);
|
||||
|
||||
metadataCallbacks.Notify(MetadataChanged_NotifyCb, MetadataChanged_FreeCb, bstr);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef NULLSOFT_CURRENTSONGCOM
|
||||
#define NULLSOFT_CURRENTSONGCOM
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "./dispatchCallback.h"
|
||||
//#include <ocidl.h>
|
||||
|
||||
class CurrentSongCOM : public IDispatch
|
||||
{
|
||||
public:
|
||||
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);
|
||||
|
||||
void MetadataChanged(char *metadataString);
|
||||
void TitleChanged();
|
||||
|
||||
DispatchCallbackStore metadataCallbacks;
|
||||
DispatchCallbackStore titleChangeCallbacks;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,233 @@
|
||||
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
|
||||
** Filename:
|
||||
** Project:
|
||||
** Description:
|
||||
** Author:
|
||||
** Created:
|
||||
**/
|
||||
|
||||
#include "main.h"
|
||||
|
||||
void FixMainWindowRect(RECT *r)
|
||||
{
|
||||
if (r->right-r->left > 280)
|
||||
{
|
||||
if (r->bottom-r->top < 200)
|
||||
r->bottom=r->top+14*2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (r->bottom-r->top < 100)
|
||||
r->bottom=r->top+14;
|
||||
}
|
||||
}
|
||||
|
||||
void EstMainWindowRect( RECT *r )
|
||||
{
|
||||
r->left = config_wx;
|
||||
r->top = config_wy;
|
||||
r->right = config_wx + ( WINDOW_WIDTH << ( config_dsize ? 1 : 0 ) );
|
||||
r->bottom = config_wy + ( ( config_windowshade ? 14 : WINDOW_HEIGHT ) << ( config_dsize ? 1 : 0 ) );
|
||||
}
|
||||
|
||||
void EstEQWindowRect( RECT *r )
|
||||
{
|
||||
r->left = config_eq_wx;
|
||||
r->top = config_eq_wy;
|
||||
r->right = config_eq_wx + ( WINDOW_WIDTH << ( config_dsize && config_eqdsize ? 1 : 0 ) );
|
||||
r->bottom = config_eq_wy + ( ( config_eq_ws ? 14 : WINDOW_HEIGHT ) << ( config_dsize && config_eqdsize ? 1 : 0 ) );
|
||||
}
|
||||
|
||||
void EstPLWindowRect( RECT *r )
|
||||
{
|
||||
r->left = config_pe_wx;
|
||||
r->top = config_pe_wy;
|
||||
r->right = config_pe_wx + config_pe_width;
|
||||
r->bottom = config_pe_wy + config_pe_height;
|
||||
}
|
||||
|
||||
void EstVidWindowRect( RECT *r )
|
||||
{
|
||||
r->left = config_video_wx;
|
||||
r->top = config_video_wy;
|
||||
r->right = config_video_wx + config_video_width;
|
||||
r->bottom = config_video_wy + config_video_height;
|
||||
}
|
||||
|
||||
void SetMainWindowRect(RECT *r)
|
||||
{
|
||||
config_wx=r->left;
|
||||
config_wy=r->top;
|
||||
}
|
||||
|
||||
void SetEQWindowRect(RECT *r)
|
||||
{
|
||||
config_eq_wx=r->left;
|
||||
config_eq_wy=r->top;
|
||||
}
|
||||
|
||||
void SetPLWindowRect(RECT *r)
|
||||
{
|
||||
config_pe_wx=r->left;
|
||||
config_pe_wy=r->top;
|
||||
}
|
||||
|
||||
void SetVidWindowRect(RECT *r)
|
||||
{
|
||||
config_video_wx=r->left;
|
||||
config_video_wy=r->top;
|
||||
}
|
||||
|
||||
void MoveRect(RECT *r, int x, int y)
|
||||
{
|
||||
r->left+=x;
|
||||
r->right+=x;
|
||||
r->top+=y;
|
||||
r->bottom+=y;
|
||||
}
|
||||
|
||||
int IsWindowAttached(RECT rc, RECT rc2)
|
||||
{
|
||||
#define INREG(x,l,h) ((x) >= (l) && (x) <= (h))
|
||||
int r=0;
|
||||
if (rc2.right == rc.left || rc2.left == rc.right)
|
||||
{
|
||||
if (INREG(rc.top,rc2.top,rc2.bottom) || INREG(rc.bottom,rc2.top,rc2.bottom) ||
|
||||
INREG(rc2.top,rc.top,rc.bottom) || INREG(rc2.bottom,rc.top,rc.bottom))
|
||||
r|=1;
|
||||
}
|
||||
if (rc2.bottom == rc.top || rc2.top == rc.bottom)
|
||||
{
|
||||
if (INREG(rc2.left,rc.left,rc.right) || INREG(rc2.right,rc.left,rc.right) ||
|
||||
INREG(rc.left,rc2.left,rc2.right) || INREG(rc.right,rc2.left,rc2.right))
|
||||
r|=2;
|
||||
}
|
||||
#undef INREG
|
||||
return r;
|
||||
}
|
||||
|
||||
void SnapWindowToWindow(RECT *rcSrc, RECT rcDest)
|
||||
{
|
||||
|
||||
#define INREG(x,l,h) ((x) >= (l) && (x) <= (h))
|
||||
#define IRR(l1,r1,l2,r2) (INREG(l1,l2,r2)||INREG(r1,l2,r2)||INREG(l2,l1,r1)||INREG(r2,l1,r1))
|
||||
#define CLOSETO(x,t) INREG(x,t-config_snaplen,t+config_snaplen)
|
||||
if (IRR(rcDest.left,rcDest.right,rcSrc->left,rcSrc->right))
|
||||
{
|
||||
if (CLOSETO(rcSrc->top,rcDest.bottom))
|
||||
{
|
||||
rcSrc->bottom+=rcDest.bottom-rcSrc->top;
|
||||
rcSrc->top=rcDest.bottom;
|
||||
}
|
||||
else if (CLOSETO(rcSrc->bottom,rcDest.top))
|
||||
{
|
||||
rcSrc->top=rcDest.top-(rcSrc->bottom-rcSrc->top);
|
||||
rcSrc->bottom=rcDest.top;
|
||||
}
|
||||
}
|
||||
|
||||
if (IRR(rcDest.top,rcDest.bottom,rcSrc->top,rcSrc->bottom))
|
||||
{
|
||||
if (CLOSETO(rcSrc->right,rcDest.left))
|
||||
{
|
||||
rcSrc->left = rcDest.left-(rcSrc->right-rcSrc->left);
|
||||
rcSrc->right= rcDest.left;
|
||||
}
|
||||
else if (CLOSETO(rcSrc->left,rcDest.right))
|
||||
{
|
||||
rcSrc->right += (rcDest.right-rcSrc->left);
|
||||
rcSrc->left=rcDest.right;
|
||||
}
|
||||
}
|
||||
|
||||
if (rcSrc->right == rcDest.left || rcSrc->left== rcDest.right)
|
||||
{
|
||||
if (CLOSETO(rcSrc->top,rcDest.top))
|
||||
{
|
||||
rcSrc->bottom += rcDest.top-rcSrc->top;
|
||||
rcSrc->top = rcDest.top;
|
||||
}
|
||||
else if (CLOSETO(rcSrc->bottom,rcDest.bottom))
|
||||
{
|
||||
rcSrc->top += rcDest.bottom-rcSrc->bottom;
|
||||
rcSrc->bottom=rcDest.bottom;
|
||||
}
|
||||
}
|
||||
|
||||
if (rcSrc->bottom == rcDest.top || rcSrc->top == rcDest.bottom)
|
||||
{
|
||||
if (CLOSETO(rcSrc->left,rcDest.left))
|
||||
{
|
||||
rcSrc->right += rcDest.left-rcSrc->left;
|
||||
rcSrc->left = rcDest.left;
|
||||
}
|
||||
else if (CLOSETO(rcSrc->right,rcDest.right))
|
||||
{
|
||||
rcSrc->left += rcDest.right-rcSrc->right;
|
||||
rcSrc->right = rcDest.right;
|
||||
}
|
||||
}
|
||||
#undef INREG
|
||||
#undef IRR
|
||||
#undef CLOSETO
|
||||
}
|
||||
|
||||
void AdjustSnap(RECT old1, RECT old2, RECT *new1, RECT *new2)
|
||||
{
|
||||
#define INREG(x,l,h) ((x) >= (l) && (x) < (h))
|
||||
if (INREG(old1.top,old2.top,old2.bottom) || INREG(old2.top,old1.top,old1.bottom)) {
|
||||
#undef INREG
|
||||
// xpos
|
||||
if (old1.right >= old2.left && old1.left < old2.right) // old1/old2
|
||||
{
|
||||
MoveRect(new1,(new2->left-(new1->right-new1->left)) - new1->left,0);
|
||||
}
|
||||
else if (old2.right >= old1.left && old2.left < old1.right) // old2/old1
|
||||
{
|
||||
MoveRect(new2,(new1->left-(new2->right-new2->left)) - new2->left,0);
|
||||
}
|
||||
}
|
||||
#define INREG(x,l,h) ((x) >= (l) && (x) < (h))
|
||||
if (INREG(old1.left,old2.left,old2.right) || INREG(old2.left,old1.left,old1.right)) {
|
||||
#undef INREG
|
||||
// ypos
|
||||
if (old1.bottom >= old2.top && old1.top < old2.bottom) // old1/old2
|
||||
{
|
||||
MoveRect(new1,0,(new2->top-(new1->bottom-new1->top)) - new1->top);
|
||||
}
|
||||
else if (old2.bottom >= old1.top && old2.top < old1.bottom) // old2/old1
|
||||
{
|
||||
MoveRect(new2,0,(new1->top-(new2->bottom-new2->top)) - new2->top);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int IsPointInRect(int x, int y, RECT *r)
|
||||
{
|
||||
if (x >= r->left && x < r->right && y >= r->top && y < r->bottom)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FixOverlaps(RECT *r1, RECT *r2)
|
||||
{
|
||||
if (r1->left >= r2->left) // r1 - r2
|
||||
{
|
||||
RECT *t=r1;
|
||||
r1=r2;
|
||||
r2=t;
|
||||
}
|
||||
{
|
||||
if (IsPointInRect(r2->left,r2->top,r1))
|
||||
{
|
||||
if (r1->right-r2->left < r1->bottom-r2->top)
|
||||
{
|
||||
MoveRect(r2,r1->right-r2->left,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
MoveRect(r2,0,r1->bottom-r2->top);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
#ifndef NULLSOFT_WINAMP_DSP_H
|
||||
#define NULLSOFT_WINAMP_DSP_H
|
||||
// DSP plugin interface
|
||||
|
||||
typedef struct winampDSPModule
|
||||
{
|
||||
char *description; // description
|
||||
HWND hwndParent; // parent window (filled in by calling app)
|
||||
HINSTANCE hDllInstance; // instance handle to this DLL (filled in by calling app)
|
||||
|
||||
void( __cdecl *Config )( struct winampDSPModule *this_mod ); // configuration dialog (if needed)
|
||||
int( __cdecl *Init )( struct winampDSPModule *this_mod ); // 0 on success, creates window, etc (if needed)
|
||||
|
||||
// modify waveform samples: returns number of samples to actually write
|
||||
// (typically numsamples, but no more than twice numsamples, and no less than half numsamples)
|
||||
// numsamples should always be at least 128. should, but I'm not sure
|
||||
int( __cdecl *ModifySamples )( struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate );
|
||||
|
||||
void( __cdecl *Quit )( struct winampDSPModule *this_mod ); // called when unloading
|
||||
|
||||
void *userData; // user data, optional
|
||||
} winampDSPModule;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int version; // DSP_HDRVER
|
||||
char *description; // description of library
|
||||
winampDSPModule *( __cdecl *getModule )( int ); // module retrieval function
|
||||
int( __cdecl *sf )( int key ); // DSP_HDRVER == 0x21
|
||||
} winampDSPHeader;
|
||||
|
||||
// exported symbols
|
||||
#ifdef USE_DSP_HDR_HWND
|
||||
typedef winampDSPHeader *( __cdecl *winampDSPGetHeaderType )( HWND );
|
||||
#define DSP_HDRVER 0x22
|
||||
#else
|
||||
// Note: Unless using USE_DSP_HDR_HWND or a Winamp 5.5+ client then winampDSPGetHeaderType(..)
|
||||
// will not receive a HWND parameter & with be called as winampDSPGetHeaderType(void).
|
||||
// This is only defined with an HWND to allow for correct compiling of the client exe.
|
||||
typedef winampDSPHeader *( __cdecl *winampDSPGetHeaderType )( HWND );
|
||||
// header version: 0x20 == 0.20 == winamp 2.0
|
||||
#define DSP_HDRVER 0x20
|
||||
#endif
|
||||
|
||||
// These are the return values to be used with the uninstall plugin export function:
|
||||
// __declspec(dllexport) int __cdecl winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param)
|
||||
// which determines if Winamp can uninstall the plugin immediately or on winamp restart.
|
||||
// If this is not exported then Winamp will assume an uninstall with reboot is the only way.
|
||||
//
|
||||
#define DSP_PLUGIN_UNINSTALL_NOW 0x0
|
||||
#define DSP_PLUGIN_UNINSTALL_REBOOT 0x1
|
||||
//
|
||||
// Uninstall support was added from 5.0+ and uninstall now support from 5.5+ though note
|
||||
// that it is down to you to ensure that if uninstall now is returned that it will not
|
||||
// cause a crash i.e. don't use if you've been subclassing the main window.
|
||||
//
|
||||
// The HWND passed in the calling of winampUninstallPlugin(..) is the preference page HWND.
|
||||
//
|
||||
//
|
||||
// Version note:
|
||||
//
|
||||
// Added passing of Winamp's main hwnd in the call to the exported winampDSPHeader()
|
||||
// which allows for primarily the use of localisation features with the bundled plugins.
|
||||
// If you want to use the new version then either you can edit you version of dsp.h or
|
||||
// you can add USE_DSP_HDR_HWND to your project's defined list or before use of dsp.h
|
||||
//
|
||||
|
||||
// For a DSP plugin to be correctly detected by Winamp you need to ensure that
|
||||
// the exported winampDSPGetHeader2(..) is exported as an undecorated function
|
||||
// e.g.
|
||||
// #ifdef __cplusplus
|
||||
// extern "C" {
|
||||
// #endif
|
||||
// __declspec(dllexport) winampDSPGetHeaderType * __cdecl winampDSPGetHeader2(){ return &plugin; }
|
||||
// #ifdef __cplusplus
|
||||
// }
|
||||
// #endif
|
||||
//
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,85 @@
|
||||
#include "Main.h"
|
||||
#include "dsp.h"
|
||||
|
||||
static int initted=0;
|
||||
static HINSTANCE hLib=0;
|
||||
static winampDSPModule *mod=0;
|
||||
|
||||
void dsp_init(void)
|
||||
{
|
||||
if (g_safeMode)
|
||||
return;
|
||||
|
||||
wchar_t str[1024] = {0};
|
||||
|
||||
if (initted)
|
||||
dsp_quit();
|
||||
|
||||
if (!config_dspplugin_name[0])
|
||||
return;
|
||||
|
||||
PathCombineW(str,DSPDIR,config_dspplugin_name);
|
||||
hLib = LoadLibraryW(str);
|
||||
|
||||
if (!hLib)
|
||||
return;
|
||||
|
||||
winampDSPGetHeaderType pr = (winampDSPGetHeaderType) GetProcAddress(hLib,"winampDSPGetHeader2");
|
||||
|
||||
if (!pr || (pr(hMainWindow)->version < DSP_HDRVER && pr(hMainWindow)->version >= DSP_HDRVER+0x10) || !(mod = pr(hMainWindow)->getModule(config_dspplugin_num)))
|
||||
{
|
||||
FreeLibrary(hLib);
|
||||
hLib=0;
|
||||
return;
|
||||
}
|
||||
|
||||
mod->hwndParent=hMainWindow;
|
||||
mod->hDllInstance=hLib;
|
||||
mod->Init(mod);
|
||||
initted=1;
|
||||
}
|
||||
|
||||
void dsp_quit(void)
|
||||
{
|
||||
if (!initted)
|
||||
return;
|
||||
|
||||
initted=0;
|
||||
if (mod)
|
||||
{
|
||||
if (!(config_no_visseh&2))
|
||||
{
|
||||
try
|
||||
{
|
||||
mod->Quit(mod);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mod->Quit(mod);
|
||||
}
|
||||
}
|
||||
|
||||
FreeLibrary(hLib);
|
||||
hLib=0;
|
||||
mod=0;
|
||||
}
|
||||
|
||||
int dsp_isactive(void)
|
||||
{
|
||||
return (in_mod && initted && mod);
|
||||
}
|
||||
|
||||
int dsp_dosamples(short int *samples, int numsamples, int bps, int nch, int srate)
|
||||
{
|
||||
if (dsp_isactive())
|
||||
{
|
||||
if (mod)
|
||||
return (mod->ModifySamples(mod,samples,numsamples,bps,nch,srate));
|
||||
}
|
||||
|
||||
return numsamples;
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
#include "DataStoreCOM.h"
|
||||
|
||||
enum
|
||||
{
|
||||
DISP_DATASTORE_STORE,
|
||||
DISP_DATASTORE_RETRIEVE,
|
||||
DISP_DATASTORE_GENERATE_GUID,
|
||||
};
|
||||
|
||||
#define CHECK_ID(str, id)\
|
||||
if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
|
||||
{ rgdispid[i] = id; continue; }
|
||||
|
||||
HRESULT DataStoreCOM::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("Store", DISP_DATASTORE_STORE);
|
||||
CHECK_ID("Retrieve", DISP_DATASTORE_RETRIEVE);
|
||||
CHECK_ID("GenerateGUID", DISP_DATASTORE_GENERATE_GUID);
|
||||
|
||||
rgdispid[i] = DISPID_UNKNOWN;
|
||||
unknowns = true;
|
||||
|
||||
}
|
||||
if (unknowns)
|
||||
return DISP_E_UNKNOWNNAME;
|
||||
else
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT DataStoreCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT DataStoreCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT DataStoreCOM::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_DATASTORE_GENERATE_GUID:
|
||||
{
|
||||
GUID guid;
|
||||
UuidCreate(&guid);
|
||||
wchar_t *guid_string;
|
||||
UuidToStringW(&guid, (unsigned short **)&guid_string);
|
||||
BSTR tag = SysAllocString(guid_string);
|
||||
RpcStringFreeW((unsigned short **)&guid_string);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BSTR;
|
||||
V_BSTR(pvarResult) = tag;
|
||||
return S_OK;
|
||||
}
|
||||
case DISP_DATASTORE_STORE:
|
||||
if (pdispparams->cArgs == 2)
|
||||
{
|
||||
GUID guid;
|
||||
UuidFromStringW((unsigned short *)pdispparams->rgvarg[1].bstrVal, &guid);
|
||||
|
||||
SAFEARRAY *bufferArray=pdispparams->rgvarg[0].parray;
|
||||
SAFEARRAY *store;
|
||||
HRESULT hr = SafeArrayCopy(bufferArray, &store);
|
||||
dataStore[guid]=store;
|
||||
return hr;
|
||||
|
||||
}
|
||||
else
|
||||
return DISP_E_BADPARAMCOUNT;
|
||||
case DISP_DATASTORE_RETRIEVE:
|
||||
if (pdispparams->cArgs == 1)
|
||||
{
|
||||
GUID guid;
|
||||
UuidFromStringW((unsigned short *)pdispparams->rgvarg[0].bstrVal, &guid);
|
||||
|
||||
SAFEARRAY *store = dataStore[guid];
|
||||
if (store)
|
||||
{
|
||||
SAFEARRAY *bufferArray;
|
||||
SafeArrayCopy(store, &bufferArray);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_ARRAY|VT_UI1;
|
||||
V_ARRAY(pvarResult) = bufferArray;
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
return E_FAIL;
|
||||
|
||||
}
|
||||
else
|
||||
return DISP_E_BADPARAMCOUNT;
|
||||
}
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
STDMETHODIMP DataStoreCOM::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 DataStoreCOM::AddRef(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ULONG DataStoreCOM::Release(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include <ocidl.h>
|
||||
#include "replicant/foundation/guid.h"
|
||||
|
||||
|
||||
class DataStoreCOM : public IDispatch
|
||||
{
|
||||
public:
|
||||
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);
|
||||
|
||||
std::map<GUID, SAFEARRAY *> dataStore;
|
||||
};
|
||||
@@ -0,0 +1,327 @@
|
||||
#include "Main.h"
|
||||
|
||||
/*
|
||||
static HDDEDATA CALLBACK GroupDDECallback (UINT uiType, UINT uiFmt, HANDLE hConv,
|
||||
HSZ sz1, HSZ sz2, HDDEDATA hData, LONG lData1, LONG lData2) {
|
||||
return ((HDDEDATA) NULL);
|
||||
}
|
||||
static BOOL CreateGroup(HWND hwnd);
|
||||
static BOOL AddProgramItems (HWND hwnd, LPSTR szDummy);
|
||||
|
||||
static CONVCONTEXT CCFilter = { sizeof (CONVCONTEXT), 0, 0, 0, 0L, 0L };
|
||||
static LONG lIdInst;
|
||||
static LONG lIdInst2;
|
||||
*/
|
||||
|
||||
//CreateShortCut(hwnd,"D:\\WINNT\\Profiles\\Administrator\\Application Data\\Microsoft\\Internet Explorer\\Quick Launch\\Winamp.lnk","C:\\winamp\\winamp.exe");
|
||||
//CreateShortCut(hwnd,"D:\\WINNT\\Profiles\\Administrator\\Desktop\\Winamp.lnk","C:\\winamp\\winamp.exe");
|
||||
|
||||
|
||||
#if 0
|
||||
void dde_adddesktop(HWND hwnd)
|
||||
{
|
||||
HKEY mp3Key;
|
||||
char name[MAX_PATH]="";
|
||||
if (RegOpenKey(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",&mp3Key) == ERROR_SUCCESS)
|
||||
{
|
||||
int s=sizeof(name);
|
||||
if (RegQueryValueEx(mp3Key,"Desktop",0,NULL,name,&s) == ERROR_SUCCESS)
|
||||
{
|
||||
}
|
||||
RegCloseKey(mp3Key);
|
||||
}
|
||||
if (lstrlen(name))
|
||||
{
|
||||
char exe[MAX_PATH];
|
||||
GetModuleFileName(NULL,exe,sizeof(exe));
|
||||
lstrcat(name,"\\WINAMP.LNK");
|
||||
CreateShortCut(hwnd,name,exe,NULL,0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dde_addquicklaunch(HWND hwnd)
|
||||
{
|
||||
HKEY mp3Key;
|
||||
char name[MAX_PATH]="";
|
||||
if (RegOpenKey(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",&mp3Key) == ERROR_SUCCESS)
|
||||
{
|
||||
int s=sizeof(name);
|
||||
if (RegQueryValueEx(mp3Key,"AppData",0,NULL,name,&s) == ERROR_SUCCESS)
|
||||
{
|
||||
}
|
||||
RegCloseKey(mp3Key);
|
||||
}
|
||||
if (lstrlen(name))
|
||||
{
|
||||
char exe[MAX_PATH];
|
||||
GetModuleFileName(NULL,exe,sizeof(exe));
|
||||
lstrcat(name,"\\Microsoft\\Internet Explorer\\Quick Launch\\WINAMP.LNK");
|
||||
CreateShortCut(hwnd,name,exe,NULL,0);
|
||||
}
|
||||
}
|
||||
|
||||
int dde_isquicklaunchavailable(void)
|
||||
{
|
||||
HKEY mp3Key;
|
||||
char name[MAX_PATH]="";
|
||||
if (RegOpenKey(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",&mp3Key) == ERROR_SUCCESS)
|
||||
{
|
||||
int s=sizeof(name);
|
||||
if (RegQueryValueEx(mp3Key,"AppData",0,NULL,name,&s) == ERROR_SUCCESS)
|
||||
{
|
||||
}
|
||||
RegCloseKey(mp3Key);
|
||||
}
|
||||
if (lstrlen(name))
|
||||
{
|
||||
HANDLE h;
|
||||
WIN32_FIND_DATA fd;
|
||||
lstrcat(name,"\\Microsoft\\Internet Explorer\\Quick Launch");
|
||||
h=FindFirstFile(name,&fd);
|
||||
if (h != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
FindClose(h);
|
||||
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) return 1;
|
||||
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if 1
|
||||
int dde_addstart(HWND hwnd)
|
||||
{
|
||||
HKEY mp3Key;
|
||||
char startMenu[MAX_PATH]="";
|
||||
if (RegOpenKey(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",&mp3Key) == ERROR_SUCCESS)
|
||||
{
|
||||
int s=sizeof(startMenu)/sizeof(startMenu[0]);
|
||||
if (RegQueryValueEx(mp3Key, "Programs", 0, NULL, startMenu, &s) == ERROR_SUCCESS)
|
||||
{
|
||||
char exe[MAX_PATH], shortcut[MAX_PATH], target[MAX_PATH];
|
||||
GetModuleFileName(NULL,exe,sizeof(exe));
|
||||
|
||||
// create Winamp folder
|
||||
PathAppend(startMenu, "Winamp");
|
||||
CreateDirectory(startMenu, NULL);
|
||||
|
||||
// winamp.exe
|
||||
PathCombine(shortcut, startMenu, "Winamp.lnk");
|
||||
CreateShortCut(hwnd, shortcut, exe, NULL, 0);
|
||||
|
||||
// we don't need the executable filename anymore, but we need its path
|
||||
PathRemoveFileSpec(exe);
|
||||
|
||||
// whatsnew.txt
|
||||
PathCombine(target, exe, "whatsnew.txt");
|
||||
PathCombine(shortcut, startMenu, "What's new.lnk");
|
||||
CreateShortCut(hwnd, startMenu, target, NULL, 0);
|
||||
|
||||
// uninstwa.exe
|
||||
PathCombine(shortcut, startMenu, "Uninstall Winamp.lnk");
|
||||
PathAppend(target, exe, "uninstwa.exe");
|
||||
CreateShortCut(hwnd, shortcut, target, NULL, 0);
|
||||
}
|
||||
RegCloseKey(mp3Key);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
int dde_addstart(HWND hwnd)
|
||||
{
|
||||
CreateGroup(hwnd);
|
||||
AddProgramItems (hwnd, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dde_delstart(void)
|
||||
{
|
||||
HDDEDATA hData;
|
||||
LPSTR szText;
|
||||
LPSTR szCommand;
|
||||
HCONV hConv;
|
||||
HSZ szProgMan;
|
||||
LONG lResult;
|
||||
szText = VirtualAlloc (NULL, 64, MEM_COMMIT, PAGE_READWRITE);
|
||||
szCommand = VirtualAlloc (NULL, 128, MEM_COMMIT, PAGE_READWRITE);
|
||||
if (szText) {
|
||||
if (DdeInitialize(&lIdInst, (PFNCALLBACK) GroupDDECallback,
|
||||
(DWORD) APPCMD_CLIENTONLY, 0L)) {
|
||||
VirtualFree (szText, 128, MEM_DECOMMIT);
|
||||
return;
|
||||
}
|
||||
szProgMan = DdeCreateStringHandle (lIdInst, "PROGMAN", CP_WINANSI);
|
||||
if (szProgMan) {
|
||||
hConv = DdeConnect (lIdInst, szProgMan, szProgMan, &CCFilter);
|
||||
lstrcpy(szText,app_name);
|
||||
wsprintf (szCommand, "[DeleteGroup(%s)]", szText);
|
||||
hData = DdeCreateDataHandle (lIdInst, szCommand,
|
||||
lstrlen (szCommand) + 1, 0, (HSZ) NULL, CF_TEXT, 0L);
|
||||
if (!DdeClientTransaction ((LPBYTE) hData, 0xFFFFFFFF, hConv,
|
||||
(HSZ) NULL, 0, XTYP_EXECUTE, 10000, &lResult)) {
|
||||
lResult = DdeGetLastError (lIdInst);
|
||||
}
|
||||
|
||||
DdeFreeStringHandle (lIdInst, szProgMan);
|
||||
DdeDisconnect (hConv);
|
||||
} else {
|
||||
lResult = DdeGetLastError (lIdInst);
|
||||
}
|
||||
VirtualFree (szText, 64, MEM_DECOMMIT);
|
||||
VirtualFree (szCommand, 64, MEM_DECOMMIT);
|
||||
DdeUninitialize (lIdInst);
|
||||
lIdInst = 0L;
|
||||
return;
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL CreateGroup(HWND hwnd) {
|
||||
HDDEDATA hData;
|
||||
LPSTR szText;
|
||||
LPSTR szCommand;
|
||||
HCONV hConv;
|
||||
HSZ szProgMan;
|
||||
LONG lResult;
|
||||
szText = VirtualAlloc (NULL, 64, MEM_COMMIT, PAGE_READWRITE);
|
||||
szCommand = VirtualAlloc (NULL, 128, MEM_COMMIT, PAGE_READWRITE);
|
||||
if (szText) {
|
||||
if (DdeInitialize(&lIdInst, (PFNCALLBACK) GroupDDECallback,
|
||||
(DWORD) APPCMD_CLIENTONLY, 0L)) {
|
||||
// MessageBox (hwnd, "DDEML Initialization Failure", "Error", MB_OK);
|
||||
VirtualFree (szText, 128, MEM_DECOMMIT);
|
||||
return (FALSE);
|
||||
}
|
||||
szProgMan = DdeCreateStringHandle (lIdInst, "PROGMAN", CP_WINANSI);
|
||||
if (szProgMan) {
|
||||
hConv = DdeConnect (lIdInst, szProgMan, szProgMan, &CCFilter);
|
||||
lstrcpy(szText,app_name);
|
||||
wsprintf (szCommand, "[CreateGroup(%s)]", szText);
|
||||
hData = DdeCreateDataHandle (lIdInst, szCommand,
|
||||
lstrlen (szCommand) + 1, 0, (HSZ) NULL, CF_TEXT, 0L);
|
||||
if (!DdeClientTransaction ((LPBYTE) hData, 0xFFFFFFFF, hConv,
|
||||
(HSZ) NULL, 0, XTYP_EXECUTE, 10000, &lResult)) {
|
||||
lResult = DdeGetLastError (lIdInst);
|
||||
// MessageBox (hwnd, "DdeClientTransaction Failed", "Error",
|
||||
// MB_OK);
|
||||
}
|
||||
|
||||
DdeFreeStringHandle (lIdInst, szProgMan);
|
||||
DdeDisconnect (hConv);
|
||||
} else {
|
||||
lResult = DdeGetLastError (lIdInst);
|
||||
}
|
||||
VirtualFree (szText, 64, MEM_DECOMMIT);
|
||||
VirtualFree (szCommand, 64, MEM_DECOMMIT);
|
||||
DdeUninitialize (lIdInst);
|
||||
lIdInst = 0L;
|
||||
return (TRUE);
|
||||
} else {
|
||||
// MessageBox (hwnd, "Memory Allocation failure", "Error", MB_OK);
|
||||
}
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
|
||||
static BOOL AddProgramItems (HWND hwnd, LPSTR szDummy) {
|
||||
HDDEDATA hData;
|
||||
HCONV hConv;
|
||||
HSZ szProgMan;
|
||||
int lSelCount;
|
||||
LONG lResult;
|
||||
LPLONG lpSelection;
|
||||
LPSTR szProgName;
|
||||
LPSTR szExePath;
|
||||
LPSTR szExecuteString;
|
||||
int iIndex;
|
||||
int iGroupCount;
|
||||
|
||||
iGroupCount = 2;
|
||||
lSelCount = 3;
|
||||
|
||||
lpSelection = VirtualAlloc (NULL, lSelCount * sizeof (int), MEM_COMMIT,PAGE_READWRITE);
|
||||
if (lpSelection) {
|
||||
if (DdeInitialize (&lIdInst2, (PFNCALLBACK) GroupDDECallback,
|
||||
(DWORD) APPCMD_CLIENTONLY, 0L)) {
|
||||
VirtualFree (lpSelection, lSelCount * sizeof (int), MEM_DECOMMIT);
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
szProgMan = DdeCreateStringHandle (lIdInst2, "PROGMAN", CP_WINANSI);
|
||||
hConv = DdeConnect (lIdInst2, szProgMan, szProgMan, &CCFilter);
|
||||
DdeFreeStringHandle (lIdInst2, szProgMan);
|
||||
szProgName = VirtualAlloc (NULL, MAX_PATH * 2, MEM_COMMIT, PAGE_READWRITE);
|
||||
szExePath = szProgName + MAX_PATH;
|
||||
|
||||
szExecuteString = VirtualAlloc (NULL, MAX_PATH * 4, MEM_COMMIT,
|
||||
PAGE_READWRITE);
|
||||
|
||||
for (iIndex = 0; iIndex < lSelCount; iIndex++) {
|
||||
{
|
||||
static char *paths[4] = {
|
||||
"Winamp.exe",
|
||||
"WhatsNew.txt",
|
||||
"Winamp.exe"
|
||||
};
|
||||
static char *names[4] =
|
||||
{
|
||||
"Winamp",
|
||||
"What's New",
|
||||
"Uninstall Winamp",
|
||||
|
||||
};
|
||||
lstrcpy(szProgName,names[iIndex]);
|
||||
{
|
||||
szExePath[0] = '\"';
|
||||
GetModuleFileName(NULL,szExePath+1,MAX_PATH);
|
||||
scanstr_back(szExePath,"\\",szExePath-1)[1]=0;
|
||||
lstrcat(szExePath,paths[iIndex]);
|
||||
lstrcat(szExePath,"\"");
|
||||
if (iIndex==2) lstrcat(szExePath," /UNINSTALL");
|
||||
}
|
||||
}
|
||||
|
||||
// Create the command string to add the item.
|
||||
wsprintf (szExecuteString, "[AddItem(%s,%s)]", szExePath,
|
||||
(LPARAM) szProgName);
|
||||
|
||||
// Create a DDEML Data handle for the command string.
|
||||
hData = DdeCreateDataHandle (lIdInst2, szExecuteString,
|
||||
lstrlen (szExecuteString) + 1, 0, (HSZ) NULL, CF_TEXT, 0L);
|
||||
|
||||
// Send the command over to the program manager.
|
||||
if (!DdeClientTransaction ((LPBYTE) hData, 0xFFFFFFFF,
|
||||
hConv, (HSZ) NULL, 0, XTYP_EXECUTE, 1000, &lResult)) {
|
||||
lResult = DdeGetLastError (lIdInst2);
|
||||
}/*endIf*/
|
||||
}/*endFor*/
|
||||
|
||||
// Release the memory allocated for path and name retrieval.
|
||||
VirtualFree (szProgName, MAX_PATH * 2, MEM_DECOMMIT);
|
||||
|
||||
// Release the command line memory.
|
||||
VirtualFree (szExecuteString, MAX_PATH * 4, MEM_DECOMMIT);
|
||||
|
||||
// Disoconnect the DDEML Conversation
|
||||
DdeDisconnect (hConv);
|
||||
|
||||
// Release the memory allocate for the list selections.
|
||||
VirtualFree (lpSelection, lSelCount * sizeof (int), MEM_DECOMMIT);
|
||||
}/*endIf*/
|
||||
|
||||
// Clear the selection in the lists.
|
||||
|
||||
// Uninitialize the local conversation.
|
||||
DdeUninitialize (lIdInst2);
|
||||
|
||||
lIdInst2 = 0L;
|
||||
return (TRUE);
|
||||
}/* end AddProgramItems */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,202 @@
|
||||
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
|
||||
** Filename:
|
||||
** Project:
|
||||
** Description:
|
||||
** Author: Ben Allison benski@nullsoft.com
|
||||
** Created:
|
||||
**/
|
||||
#include "main.h"
|
||||
#include <stddef.h>
|
||||
#include "DecodeFile.h"
|
||||
#include "ExtendedReader.h"
|
||||
#include "OutputPluginAudioStream.h"
|
||||
#include "ResamplingReader.h"
|
||||
#include "CommonReader.h"
|
||||
|
||||
// "input" means input FROM the decoder, "output" means output TO the person using the ifc_audiostream
|
||||
static bool RequiresResampling(const AudioParameters *input, size_t outputChannels, size_t outputBits, size_t outputSampleRate)
|
||||
{
|
||||
if (outputChannels != input->channels)
|
||||
return true; // need to up or downmix
|
||||
|
||||
if (outputBits != input->bitsPerSample)
|
||||
return true;
|
||||
|
||||
if (outputSampleRate != input->sampleRate)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void SetResamplingParameters(const AudioParameters *input, size_t &outputChannels, size_t &outputBits, size_t &outputSampleRate)
|
||||
{
|
||||
// channels
|
||||
if (!outputChannels)
|
||||
outputChannels=input->channels;
|
||||
else if ((input->flags & AUDIOPARAMETERS_MAXCHANNELS) && input->channels <= outputChannels)
|
||||
outputChannels = input->channels;
|
||||
|
||||
// bits
|
||||
if (!outputBits) outputBits = input->bitsPerSample;
|
||||
|
||||
// samplerate
|
||||
if (!outputSampleRate)
|
||||
outputSampleRate = input->sampleRate;
|
||||
else if ((input->flags & AUDIOPARAMETERS_MAXSAMPLERATE) && input->sampleRate <= outputSampleRate)
|
||||
outputSampleRate = input->sampleRate;
|
||||
|
||||
}
|
||||
|
||||
ifc_audiostream *DecodeFile::OpenAudio(const wchar_t *filename, AudioParameters *parameters)
|
||||
{
|
||||
// save some info
|
||||
size_t outputChannels = parameters->channels;
|
||||
size_t outputBits = parameters->bitsPerSample;
|
||||
size_t outputSampleRate = parameters->sampleRate;
|
||||
|
||||
CommonReader *reader = MakeReader(filename, parameters, true);
|
||||
if (!reader)
|
||||
return 0;
|
||||
|
||||
// check if they've requested certain output parameters
|
||||
if (outputChannels || outputBits || outputSampleRate)
|
||||
{
|
||||
SetResamplingParameters(parameters, outputChannels, outputBits, outputSampleRate);
|
||||
|
||||
// check if we need any resampling/conversion
|
||||
if (RequiresResampling(parameters, outputChannels, outputBits, outputSampleRate))
|
||||
{
|
||||
Resampler *resampler = new Resampler(parameters->bitsPerSample, parameters->channels, parameters->sampleRate,
|
||||
outputBits, outputChannels, outputSampleRate, parameters->flags & AUDIOPARAMETERS_FLOAT);
|
||||
|
||||
if (!resampler->OK())
|
||||
{
|
||||
parameters->errorCode = API_DECODEFILE_BAD_RESAMPLE;
|
||||
delete resampler;
|
||||
return 0;
|
||||
}
|
||||
|
||||
parameters->bitsPerSample = (uint32_t)outputBits;
|
||||
parameters->channels = (uint32_t)outputChannels;
|
||||
parameters->sampleRate = (uint32_t)outputSampleRate;
|
||||
parameters->sizeBytes =(size_t)((double)parameters->sizeBytes * resampler->sizeFactor);
|
||||
ResamplingReader *resampleReader = new ResamplingReader(resampler, reader, outputChannels * outputBits / 8);
|
||||
|
||||
return resampleReader;
|
||||
}
|
||||
|
||||
}
|
||||
return reader;
|
||||
}
|
||||
|
||||
ifc_audiostream *DecodeFile::OpenAudioBackground(const wchar_t *filename, AudioParameters *parameters)
|
||||
{
|
||||
// save some info
|
||||
size_t outputChannels = parameters->channels;
|
||||
size_t outputBits = parameters->bitsPerSample;
|
||||
size_t outputSampleRate = parameters->sampleRate;
|
||||
|
||||
CommonReader *reader = MakeReader(filename, parameters, false);
|
||||
if (!reader)
|
||||
return 0;
|
||||
|
||||
// check if they've requested certain output parameters
|
||||
if (outputChannels || outputBits || outputSampleRate)
|
||||
{
|
||||
SetResamplingParameters(parameters, outputChannels, outputBits, outputSampleRate);
|
||||
|
||||
// check if we need any resampling/conversion
|
||||
if (RequiresResampling(parameters, outputChannels, outputBits, outputSampleRate))
|
||||
{
|
||||
Resampler *resampler = new Resampler(parameters->bitsPerSample, parameters->channels, parameters->sampleRate,
|
||||
outputBits, outputChannels, outputSampleRate, parameters->flags & AUDIOPARAMETERS_FLOAT);
|
||||
|
||||
if (!resampler->OK())
|
||||
{
|
||||
parameters->errorCode = API_DECODEFILE_BAD_RESAMPLE;
|
||||
delete resampler;
|
||||
delete reader;
|
||||
return 0;
|
||||
}
|
||||
|
||||
parameters->bitsPerSample = (uint32_t)outputBits;
|
||||
parameters->channels = (uint32_t)outputChannels;
|
||||
parameters->sampleRate = (uint32_t)outputSampleRate;
|
||||
|
||||
ResamplingReader *resampleReader = new ResamplingReader(resampler, reader, outputChannels * outputBits / 8);
|
||||
|
||||
return resampleReader;
|
||||
}
|
||||
|
||||
}
|
||||
return reader;
|
||||
}
|
||||
|
||||
CommonReader *DecodeFile::MakeReader(const wchar_t *filename, AudioParameters *parameters, bool useUnagi)
|
||||
{
|
||||
In_Module *in;
|
||||
int a = 0;
|
||||
bool found = false;
|
||||
|
||||
while (a >= 0)
|
||||
{
|
||||
OpenFunc open = 0, openFloat=0;
|
||||
OpenWFunc openW=0, openWFloat=0;
|
||||
GetDataFunc getData = 0;
|
||||
CloseFunc close = 0;
|
||||
SetTimeFunc setTime = 0;
|
||||
|
||||
in = in_setmod_noplay(filename, &a);
|
||||
if (!in) break;
|
||||
if (a >= 0) a++;
|
||||
|
||||
found = true;
|
||||
|
||||
open = (OpenFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_open");
|
||||
openFloat = (OpenFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_open_float");
|
||||
openW = (OpenWFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_openW");
|
||||
openWFloat = (OpenWFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_openW_float");
|
||||
getData = (GetDataFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_getData");
|
||||
close = (CloseFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_close");
|
||||
setTime = (SetTimeFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_setTime"); //optional!
|
||||
if ((open || openW) && getData && close)
|
||||
{
|
||||
ExtendedReader *reader = new ExtendedReader(open, openW, openFloat, openWFloat, getData, close, setTime);
|
||||
if (reader->Open(filename, parameters))
|
||||
return reader;
|
||||
else
|
||||
delete reader;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!found || !useUnagi)
|
||||
{
|
||||
parameters->errorCode = API_DECODEFILE_UNSUPPORTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputPluginAudioStream *reader = new OutputPluginAudioStream;
|
||||
in = in_setmod_noplay(filename, 0);
|
||||
if (reader->Open(in, filename, parameters))
|
||||
return reader;
|
||||
delete reader;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DecodeFile::CloseAudio(ifc_audiostream *audioStream)
|
||||
{
|
||||
CommonReader *reader = static_cast<CommonReader *>(audioStream);
|
||||
delete reader;
|
||||
//audioStream=0;
|
||||
}
|
||||
|
||||
|
||||
#define CBCLASS DecodeFile
|
||||
START_DISPATCH;
|
||||
CB(API_DECODEFILE_OPENAUDIO, OpenAudio)
|
||||
CB(API_DECODEFILE_OPENAUDIO2, OpenAudioBackground)
|
||||
VCB(API_DECODEFILE_CLOSEAUDIO, CloseAudio)
|
||||
END_DISPATCH;
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef NULLSOFT_WINAMP_DECODEFILE_H
|
||||
#define NULLSOFT_WINAMP_DECODEFILE_H
|
||||
|
||||
#include "api_decodefile.h"
|
||||
#include "CommonReader.h"
|
||||
class DecodeFile : public api_decodefile
|
||||
{
|
||||
public:
|
||||
static const char *getServiceName() { return "File Decode API"; }
|
||||
static const GUID getServiceGuid() { return decodeFileGUID; }
|
||||
public:
|
||||
ifc_audiostream *OpenAudio(const wchar_t *filename, AudioParameters *parameters);
|
||||
ifc_audiostream *OpenAudioBackground(const wchar_t *filename, AudioParameters *parameters);
|
||||
void CloseAudio(ifc_audiostream *audioStream);
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
private:
|
||||
CommonReader *MakeReader(const wchar_t *filename, AudioParameters *parameters, bool useUnagi);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
|
||||
** Filename:
|
||||
** Project:
|
||||
** Description:
|
||||
** Author: Ben Allison benski@nullsoft.com
|
||||
** Created:
|
||||
**/
|
||||
#include "main.h"
|
||||
#include "DeveloperConfigGroup.h"
|
||||
|
||||
#include "../Agave/Config/ifc_configitem.h"
|
||||
#include "WinampAttributes.h"
|
||||
|
||||
class MaskBoolConfigItem : public ifc_configitem
|
||||
{
|
||||
public:
|
||||
MaskBoolConfigItem(int _mask) : mask(_mask) {}
|
||||
bool GetBool()
|
||||
{
|
||||
return !!(config_no_visseh&mask);
|
||||
}
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
|
||||
private:
|
||||
int mask;
|
||||
};
|
||||
|
||||
#define CBCLASS MaskBoolConfigItem
|
||||
START_DISPATCH;
|
||||
CB(IFC_CONFIGITEM_GETBOOL, GetBool)
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
|
||||
static MaskBoolConfigItem sehVisItem(1), sehDSPItem(2), sehGenItem(4), sehIEItem(8);
|
||||
|
||||
ifc_configitem *DeveloperConfigGroup::GetItem(const wchar_t *name)
|
||||
{
|
||||
if (!wcscmp(name, L"no_visseh"))
|
||||
return &sehVisItem;
|
||||
else if (!wcscmp(name, L"no_dspseh"))
|
||||
return &sehDSPItem;
|
||||
else if (!wcscmp(name, L"no_genseh"))
|
||||
return &sehGenItem;
|
||||
else if (!wcscmp(name, L"no_ieseh"))
|
||||
return &sehIEItem;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define CBCLASS DeveloperConfigGroup
|
||||
START_DISPATCH;
|
||||
CB(IFC_CONFIGGROUP_GETITEM, GetItem)
|
||||
CB(IFC_CONFIGGROUP_GETGUID, GetGUID)
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "main.h"
|
||||
#include "../Agave/Config/ifc_configgroup.h"
|
||||
|
||||
|
||||
// {113D413A-5D1F-4f4c-8AB7-5BDED46033A4}
|
||||
static const GUID developerConfigGroupGUID=
|
||||
{ 0x113d413a, 0x5d1f, 0x4f4c, { 0x8a, 0xb7, 0x5b, 0xde, 0xd4, 0x60, 0x33, 0xa4 } };
|
||||
|
||||
|
||||
class DeveloperConfigGroup : public ifc_configgroup
|
||||
{
|
||||
public:
|
||||
ifc_configitem *GetItem(const wchar_t *name);
|
||||
GUID GetGUID() { return developerConfigGroupGUID; }
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
||||
|
||||
extern DeveloperConfigGroup developerConfigGroup;
|
||||
@@ -0,0 +1,33 @@
|
||||
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
|
||||
** Filename:
|
||||
** Project:
|
||||
** Description:
|
||||
** Author: Ben Allison benski@nullsoft.com
|
||||
** Created:
|
||||
**/
|
||||
#include "main.h"
|
||||
#include "EqConfigGroup.h"
|
||||
#include "WinampAttributes.h"
|
||||
|
||||
|
||||
ifc_configitem *EQConfigGroup::GetItem(const wchar_t *name)
|
||||
{
|
||||
if (!wcscmp(name, L"frequencies"))
|
||||
return &config_eq_frequencies;
|
||||
else if (!wcscmp(name, L"type"))
|
||||
return &config_eq_type;
|
||||
else if (!wcscmp(name, L"limiter"))
|
||||
return &config_eq_limiter;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define CBCLASS EQConfigGroup
|
||||
START_DISPATCH;
|
||||
CB(IFC_CONFIGGROUP_GETITEM, GetItem)
|
||||
CB(IFC_CONFIGGROUP_GETGUID, GetGUID)
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef NULLSOFT_WINAMP_EQCONFIGGROUP_H
|
||||
#define NULLSOFT_WINAMP_EQCONFIGGROUP_H
|
||||
|
||||
#include "main.h"
|
||||
#include "../Agave/Config/ifc_configgroup.h"
|
||||
|
||||
// {72409F84-BAF1-4448-8211-D84A30A1591A}
|
||||
static const GUID eqConfigGroupGUID =
|
||||
{ 0x72409f84, 0xbaf1, 0x4448, { 0x82, 0x11, 0xd8, 0x4a, 0x30, 0xa1, 0x59, 0x1a } };
|
||||
|
||||
|
||||
class EQConfigGroup : public ifc_configgroup
|
||||
{
|
||||
public:
|
||||
ifc_configitem *GetItem(const wchar_t *name);
|
||||
GUID GetGUID() { return eqConfigGroupGUID; }
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
||||
|
||||
extern EQConfigGroup eqConfigGroup;
|
||||
|
||||
#endif
|
||||
+1025
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,421 @@
|
||||
#include "Main.h"
|
||||
#include "WinampAttributes.h"
|
||||
#include "resource.h"
|
||||
|
||||
#define inreg(x,y,x2,y2) \
|
||||
((mouse_x <= ( x2 ) && mouse_x >= ( x ) && \
|
||||
mouse_y <= ( y2 ) && mouse_y >= ( y )))
|
||||
|
||||
static int mouse_x, mouse_y, mouse_type, mouse_stats;
|
||||
|
||||
static int which_cap=0;
|
||||
enum { NO_CAP,TITLE_CAP,TB_CAP,QB_CAP,TOGBUTS_CAP,PB_CAP, PAN_CAP,VOL_CAP, SLID_CAP=100 };
|
||||
|
||||
static void do_titlebar();
|
||||
static void do_titlebuttons();
|
||||
static void do_quickbuts();
|
||||
static void do_sliders(int which);
|
||||
static void do_togbuts();
|
||||
static void do_volctrl();
|
||||
static void do_panctrl();
|
||||
static void do_presetbutton();
|
||||
|
||||
void equi_handlemouseevent(int x, int y, int type, int stats)
|
||||
{
|
||||
mouse_x = x;
|
||||
mouse_y = y;
|
||||
mouse_type = type;
|
||||
mouse_stats = stats;
|
||||
switch (which_cap)
|
||||
{
|
||||
case PAN_CAP:
|
||||
do_panctrl();
|
||||
return;
|
||||
case VOL_CAP:
|
||||
do_volctrl();
|
||||
return;
|
||||
case PB_CAP:
|
||||
do_presetbutton();
|
||||
return;
|
||||
case TOGBUTS_CAP:
|
||||
do_togbuts();
|
||||
return;
|
||||
case TITLE_CAP:
|
||||
do_titlebar();
|
||||
return;
|
||||
case TB_CAP:
|
||||
do_titlebuttons();
|
||||
return;
|
||||
case QB_CAP:
|
||||
do_quickbuts();
|
||||
return;
|
||||
default:
|
||||
if (which_cap >= SLID_CAP)
|
||||
{
|
||||
do_sliders(which_cap-SLID_CAP);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (config_eq_ws)
|
||||
{
|
||||
do_volctrl();
|
||||
do_panctrl();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (x = 0; x < 11; x ++)
|
||||
do_sliders(x);
|
||||
}
|
||||
do_titlebuttons();
|
||||
do_quickbuts();
|
||||
do_togbuts();
|
||||
do_presetbutton();
|
||||
do_titlebar();
|
||||
}
|
||||
|
||||
static void do_volctrl()
|
||||
{
|
||||
extern int do_volbar_active;
|
||||
if (inreg(61,3,162,11) || which_cap==VOL_CAP)
|
||||
{
|
||||
if (mouse_type == 1 && !which_cap) which_cap=VOL_CAP;
|
||||
if (which_cap==VOL_CAP && mouse_stats & MK_LBUTTON)
|
||||
{
|
||||
int t=mouse_x-61;
|
||||
if (t < 0) t=0;
|
||||
if (t > 157-61) t=157-61;
|
||||
config_volume=(t*255)/(157-61);
|
||||
in_setvol(config_volume);
|
||||
draw_volumebar(config_volume,0);
|
||||
update_volume_text(-1);
|
||||
do_volbar_active=1;
|
||||
}
|
||||
if (mouse_type == -1 && which_cap == VOL_CAP)
|
||||
{
|
||||
which_cap=0;
|
||||
do_volbar_active=0;
|
||||
draw_songname(FileTitle,&ui_songposition,playing?in_getlength():PlayList_getcurrentlength());
|
||||
}
|
||||
}
|
||||
else if (which_cap==VOL_CAP)
|
||||
{
|
||||
which_cap=0;
|
||||
draw_songname(FileTitle,&ui_songposition,playing?in_getlength():PlayList_getcurrentlength());
|
||||
do_volbar_active=0;
|
||||
}
|
||||
}
|
||||
|
||||
static void do_panctrl()
|
||||
{
|
||||
extern int do_volbar_active;
|
||||
if (inreg(163,3,206,11) || which_cap==PAN_CAP)
|
||||
{
|
||||
if (mouse_type == 1 && !which_cap) which_cap=PAN_CAP;
|
||||
if (which_cap==PAN_CAP && mouse_stats & MK_LBUTTON)
|
||||
{
|
||||
int t=mouse_x-164;
|
||||
if (t < 0) t=0;
|
||||
if (t > 206-164) t=206-164;
|
||||
int p = (t*255)/(206-164)-127;
|
||||
config_pan = (p > 127 ? 127 : p);
|
||||
// changed in 5.64 to have a lower limit (~18% vs 9%) and for
|
||||
// holding shift to drop the central clamp (allows 4% balance)
|
||||
// and the above change fixes the balance to be even going +/-
|
||||
if (!(mouse_stats & MK_SHIFT)) if (config_pan < 9 && config_pan > -9) config_pan=0;
|
||||
in_setpan(config_pan);
|
||||
draw_panbar(config_pan,0);
|
||||
update_panning_text(-1);
|
||||
do_volbar_active=1;
|
||||
}
|
||||
if (mouse_type == -1 && which_cap == PAN_CAP)
|
||||
{
|
||||
draw_songname(FileTitle,&ui_songposition,playing?in_getlength():PlayList_getcurrentlength());
|
||||
do_volbar_active=0;
|
||||
which_cap=0;
|
||||
}
|
||||
}
|
||||
else if (which_cap==PAN_CAP)
|
||||
{
|
||||
draw_songname(FileTitle,&ui_songposition,playing?in_getlength():PlayList_getcurrentlength());
|
||||
do_volbar_active=0;
|
||||
which_cap=0;
|
||||
}
|
||||
}
|
||||
|
||||
static void do_presetbutton()
|
||||
{
|
||||
if (inreg(217,18,217+44,18+12))
|
||||
{
|
||||
if (!which_cap && mouse_stats & MK_LBUTTON)
|
||||
{
|
||||
draw_eq_presets(1);
|
||||
which_cap = PB_CAP;
|
||||
}
|
||||
if (mouse_type == -1 && which_cap == PB_CAP)
|
||||
{
|
||||
draw_eq_presets(0);
|
||||
which_cap=0;
|
||||
SendMessageW(hEQWindow,WM_COMMAND,EQ_PRESETS,0);
|
||||
}
|
||||
} else if (which_cap == PB_CAP)
|
||||
{
|
||||
which_cap=0;
|
||||
draw_eq_presets(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_togbuts()
|
||||
{
|
||||
if (inreg(14,18,14+25+33,18+12))
|
||||
{
|
||||
int w=mouse_x >= 14+25 ? 1 : 0;
|
||||
if (mouse_type == -1)
|
||||
{
|
||||
if (w)
|
||||
{
|
||||
config_autoload_eq=!config_autoload_eq;
|
||||
}
|
||||
else
|
||||
{
|
||||
config_use_eq=!config_use_eq;
|
||||
}
|
||||
eq_set(config_use_eq, (char*)eq_tab,config_preamp);
|
||||
draw_eq_onauto(config_use_eq, config_autoload_eq, 0,0);
|
||||
PostMessageW(hMainWindow,WM_WA_IPC,IPC_CB_MISC_EQ,IPC_CB_MISC);
|
||||
}
|
||||
else if (mouse_stats & MK_LBUTTON)
|
||||
{
|
||||
which_cap = TOGBUTS_CAP;
|
||||
draw_eq_onauto(config_use_eq, config_autoload_eq, w?0:1,w?1:0);
|
||||
}
|
||||
} else if (which_cap == TOGBUTS_CAP)
|
||||
{
|
||||
which_cap=0;
|
||||
draw_eq_onauto(config_use_eq, config_autoload_eq, 0,0);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_sliders(int which)
|
||||
{
|
||||
int top=39,bottom=98;
|
||||
int xoffs,w=33-21;
|
||||
|
||||
if (!which) xoffs=21;
|
||||
else xoffs=78+(which-1)*(96-78);
|
||||
|
||||
if (which_cap == SLID_CAP+which || inreg(xoffs,top,xoffs+w,bottom))
|
||||
{
|
||||
unsigned char *b = (which?eq_tab+which-1:&config_preamp);
|
||||
if (mouse_type == 1 || which_cap == SLID_CAP+which || (!which_cap && mouse_stats & MK_LBUTTON))
|
||||
{
|
||||
static int click_yoffs=5;
|
||||
int num_pos=63-11;
|
||||
int d;
|
||||
int p;
|
||||
int t= (mouse_type == -1 || (!(mouse_x >= xoffs-3 && mouse_x <= xoffs+w+3) && (mouse_y >= top && mouse_y <= bottom && mouse_x >= 78 && mouse_x <= 180+78) && which));
|
||||
p=63-12-((63-*b)*num_pos)/64;
|
||||
if (mouse_type == 1 && mouse_y-top >= p-1 && mouse_y-top < p + 11)
|
||||
{
|
||||
click_yoffs=mouse_y-top - p;
|
||||
} else if (mouse_type == 1)
|
||||
click_yoffs=5;
|
||||
d=((mouse_y-click_yoffs-top)*64)/num_pos;
|
||||
if (d < 0) d = 0;
|
||||
if (d > 63) d = 63;
|
||||
|
||||
// changed in 5.66 for holding shift to drop the central clamp (allows 7% balance)
|
||||
if (!(mouse_stats & MK_SHIFT)) if (d >= 30 && d <= 32) d=31;
|
||||
|
||||
*b = d;
|
||||
draw_eq_slid(which,*b,t? 0 : 1);
|
||||
draw_eq_graphthingy();
|
||||
if (t)
|
||||
{
|
||||
do_posbar_active=0;
|
||||
draw_songname(FileTitle,&ui_songposition,playing?in_getlength():PlayList_getcurrentlength());
|
||||
which_cap=0;
|
||||
} else
|
||||
{
|
||||
wchar_t buf[128] = {0};
|
||||
float v=(float)d;
|
||||
static wchar_t preampStr[64];
|
||||
static wchar_t *bands[11] =
|
||||
{
|
||||
preampStr, // PREAMP
|
||||
L"70",L"180",L"320",L"600", // Hz
|
||||
L"1",L"3",L"6",L"12",L"14",L"16" // KHz
|
||||
};
|
||||
static wchar_t *bandsISO[11] =
|
||||
{
|
||||
preampStr, // PREAMP
|
||||
L"31.5",L"63",L"125",L"250", // Hz
|
||||
L"500",L"1",L"2",L"4",L"8",L"16" // KHz
|
||||
};
|
||||
getStringW(IDS_PREAMP,preampStr,64);
|
||||
v -= 31.5f;
|
||||
v /= 31.5f;
|
||||
v *= -12.0f;
|
||||
if (v >= -0.32 && v <= 0.32) v=0.0;
|
||||
|
||||
wchar_t HZStr[16] = {0};
|
||||
getStringW((which<5+!(config_eq_frequencies==EQ_FREQUENCIES_WINAMP)?IDS_EQ_HZ:IDS_EQ_KHZ),HZStr,16);
|
||||
StringCchPrintfW(buf,128,L"EQ: %s%s: %s%0.01f %s",
|
||||
((config_eq_frequencies==EQ_FREQUENCIES_WINAMP)?bands[which]:bandsISO[which]),
|
||||
(!which?L"":HZStr),
|
||||
v>=0.0?L"+":L"", v,
|
||||
getStringW(IDS_EQ_DB,NULL,0));
|
||||
|
||||
d=0;
|
||||
do_posbar_active=1;
|
||||
draw_songname(buf,&d,-1);
|
||||
which_cap = SLID_CAP+which;
|
||||
}
|
||||
eq_set(config_use_eq, (char*)eq_tab,config_preamp);
|
||||
PostMessageW(hMainWindow,WM_WA_IPC,IPC_CB_MISC_EQ,IPC_CB_MISC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void do_quickbuts()
|
||||
{
|
||||
int l=42, r=67;
|
||||
if (inreg(l,65,r,74) || inreg(l,33,r,42) || inreg(l,92,r,101)) // +0
|
||||
{
|
||||
if (mouse_type == -1 && which_cap == QB_CAP)
|
||||
{
|
||||
int v;
|
||||
which_cap=0;
|
||||
if (mouse_y <= 42) v=0;
|
||||
else if (mouse_y <= 74) v=31;
|
||||
else v=63;
|
||||
|
||||
memset(eq_tab,v,10);
|
||||
{
|
||||
int x;
|
||||
for (x = 1; x <= 10; x ++)
|
||||
draw_eq_slid(x,eq_tab[x-1],0);
|
||||
}
|
||||
eq_set(config_use_eq, (char*)eq_tab,config_preamp);
|
||||
draw_eq_graphthingy();
|
||||
PostMessageW(hMainWindow,WM_WA_IPC,IPC_CB_MISC_EQ,IPC_CB_MISC);
|
||||
}
|
||||
else if (mouse_stats & MK_LBUTTON)
|
||||
{
|
||||
which_cap=QB_CAP;
|
||||
}
|
||||
}
|
||||
else if (which_cap == QB_CAP)
|
||||
{
|
||||
which_cap=0;
|
||||
}
|
||||
}
|
||||
|
||||
static void do_titlebar()
|
||||
{
|
||||
if (which_cap == TITLE_CAP || (!which_cap && (config_easymove || mouse_y < 14)))
|
||||
{
|
||||
static int clickx, clicky;
|
||||
switch (mouse_type)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
which_cap=TITLE_CAP;
|
||||
clickx=mouse_x;
|
||||
clicky=mouse_y;
|
||||
}
|
||||
break;
|
||||
case -1:
|
||||
which_cap=0;
|
||||
break;
|
||||
case 0:
|
||||
if (which_cap == TITLE_CAP && mouse_stats & MK_LBUTTON)
|
||||
{
|
||||
POINT p = { mouse_x,mouse_y};
|
||||
ClientToScreen(hEQWindow,&p);
|
||||
config_eq_wx = p.x-clickx;
|
||||
config_eq_wy = p.y-clicky;
|
||||
if ((!!config_snap) ^ (!!(mouse_stats & MK_SHIFT)))
|
||||
{
|
||||
RECT rr;
|
||||
EstEQWindowRect(&rr);
|
||||
SnapWindowToAllWindows(&rr,hEQWindow);
|
||||
SetEQWindowRect(&rr);
|
||||
}
|
||||
SetWindowPos(hEQWindow,0,config_eq_wx,config_eq_wy,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void do_titlebuttons()
|
||||
{
|
||||
if (inreg(253,3,264+9,3+9)) // kill button
|
||||
{
|
||||
int ws;
|
||||
if (mouse_x < 264) ws=1;
|
||||
else ws=0;
|
||||
if (mouse_type == -1 && which_cap == TB_CAP)
|
||||
{
|
||||
which_cap=0;
|
||||
draw_eq_tbutton(0,0);
|
||||
if (ws==0) SendMessageW(hMainWindow,WM_COMMAND,WINAMP_OPTIONS_EQ,0);
|
||||
else SendMessageW(hMainWindow,WM_COMMAND,WINAMP_OPTIONS_WINDOWSHADE_EQ,0);
|
||||
}
|
||||
else if (mouse_stats & MK_LBUTTON)
|
||||
{
|
||||
which_cap=TB_CAP;
|
||||
if (ws) draw_eq_tbutton(0,1);
|
||||
else draw_eq_tbutton(1,0);
|
||||
}
|
||||
}
|
||||
else if (which_cap == TB_CAP)
|
||||
{
|
||||
which_cap=0;
|
||||
draw_eq_tbutton(0,0);
|
||||
}
|
||||
}
|
||||
|
||||
void eq_ui_handlecursor(void)
|
||||
{
|
||||
int mouse_x, mouse_y;
|
||||
POINT p;
|
||||
static RECT b[] =
|
||||
{
|
||||
{264,3,272,12},//close
|
||||
{0,0,275,13},// titelbar
|
||||
};
|
||||
int b_len;
|
||||
int x;
|
||||
if (!config_usecursors || disable_skin_cursors) return;
|
||||
b_len = sizeof(b)/sizeof(b[0]);
|
||||
GetCursorPos(&p);
|
||||
ScreenToClient(hEQWindow,&p);
|
||||
mouse_x=p.x;
|
||||
mouse_y=p.y;
|
||||
if (config_dsize && config_eqdsize) { mouse_x/=2; mouse_y/=2;}
|
||||
|
||||
{
|
||||
int y;
|
||||
x=1;
|
||||
for (y = 0; y < 11; y ++)
|
||||
{
|
||||
int top=39,bottom=98;
|
||||
int xoffs,w=33-21;
|
||||
if (!y) xoffs=21;
|
||||
else xoffs=78+(y-1)*(96-78);
|
||||
if (inreg(xoffs,top,xoffs+w,bottom))
|
||||
{
|
||||
x=0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (x) for (x = 1; x <= b_len; x ++)
|
||||
if (inreg(b[x-1].left,b[x-1].top,b[x-1].right,b[x-1].bottom)) break;
|
||||
}
|
||||
|
||||
x+=25;
|
||||
|
||||
if (Skin_Cursors[x]) SetCursor(Skin_Cursors[x]);
|
||||
else SetCursor(LoadCursor(NULL,IDC_ARROW));
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
#include "main.h"
|
||||
#include "ExplorerFindFile.h"
|
||||
|
||||
ExplorerFindFile::ExplorerFindFile()
|
||||
{
|
||||
}
|
||||
|
||||
ExplorerFindFile::~ExplorerFindFile()
|
||||
{
|
||||
}
|
||||
|
||||
void ExplorerFindFile::Reset()
|
||||
{
|
||||
pidlList.clear();
|
||||
}
|
||||
|
||||
// still need to make this handle zip:// entries natively to get them working as needed
|
||||
BOOL ExplorerFindFile::AddFile( wchar_t *file )
|
||||
{
|
||||
LPSHELLFOLDER pDesktopFolder = 0;
|
||||
if ( SUCCEEDED( SHGetDesktopFolder( &pDesktopFolder ) ) )
|
||||
{
|
||||
LPITEMIDLIST filepidl = 0, folderpidl = 0;
|
||||
wchar_t folder[ MAX_PATH ] = { 0 },
|
||||
param[ 512 ] = { 0 },
|
||||
*filews = 0;
|
||||
int zip = 0;
|
||||
|
||||
// doing this to handle zip:// entries where there is a valid file
|
||||
// path included in the entry so extract it (from FFOD plugin code)
|
||||
lstrcpynW( param, file, 7 );
|
||||
if ( !lstrcmpiW( param, L"zip://" ) )
|
||||
{
|
||||
file += 6;
|
||||
zip = 1;
|
||||
}
|
||||
|
||||
filews = file + lstrlenW( file ) - 1;
|
||||
if ( wcsstr( filews, L"." ) != 0 )
|
||||
{
|
||||
while ( filews && *filews && ( *filews != L'.' ) && ( filews != file ) )
|
||||
{
|
||||
filews = CharPrevW( file, filews );
|
||||
if ( zip && *filews == L',' )
|
||||
{
|
||||
zip = 0;
|
||||
}
|
||||
|
||||
if ( zip && *filews == L'.' )
|
||||
{
|
||||
zip = 0;
|
||||
filews = CharPrevW( file, filews );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while ( filews && *filews && ( *filews != L',' && *filews != L':' && *filews != L'|' ) )
|
||||
filews = CharNextW( filews );
|
||||
|
||||
if ( filews )
|
||||
*filews = 0;
|
||||
|
||||
// doing this to handle foo.rsn\bar.spc so it'll just
|
||||
// find foo.rsn (which should then be a valid entry)
|
||||
filews = wcsstr( file, L".rsn\\" );
|
||||
if ( filews )
|
||||
{
|
||||
*( filews + 4 ) = 0;
|
||||
}
|
||||
|
||||
// and now get the folder path of the file
|
||||
lstrcpynW( folder, file, MAX_PATH );
|
||||
|
||||
if ( PathIsRelativeW( folder ) )
|
||||
{
|
||||
// sort out relative files based against winamp.exe
|
||||
wchar_t szTemp[ MAX_PATH ] = { 0 }, szTemp2[ MAX_PATH ] = { 0 };
|
||||
GetModuleFileNameW( hMainInstance, szTemp, sizeof( szTemp ) );
|
||||
PathRemoveFileSpecW( szTemp );
|
||||
PathCombineW( szTemp2, szTemp, folder );
|
||||
PathCanonicalizeW( folder, szTemp2 );
|
||||
// and once calculated then we copy the file back
|
||||
lstrcpynW( file, folder, MAX_PATH );
|
||||
}
|
||||
|
||||
PathRemoveFileSpecW( folder );
|
||||
|
||||
HRESULT hr = pDesktopFolder->ParseDisplayName( NULL, 0, folder, 0, &folderpidl, 0 );
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
pDesktopFolder->Release();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
hr = pDesktopFolder->ParseDisplayName( NULL, 0, file, 0, &filepidl, 0 );
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
pDesktopFolder->Release();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PIDLListMap::iterator itr = pidlList.begin();
|
||||
for ( ; itr != pidlList.end(); itr++ )
|
||||
{
|
||||
wchar_t tmp[ MAX_PATH ] = { 0 };
|
||||
SHGetPathFromIDListW( itr->first, tmp );
|
||||
// the LPITEMIDLIST isn't consistant for all calls it seems and
|
||||
// so it requires doing a physical check against the folder path
|
||||
// rather than comparing LPITEMIDLIST values which would be nice
|
||||
if ( !_wcsnicmp( folder, tmp, wcslen( folder ) ) )
|
||||
{
|
||||
itr->second.push_back( filepidl );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if we got here then there was no match with the currently parsed
|
||||
// folder and so we need to add it to the pidllist for use later on
|
||||
if ( itr == pidlList.end() )
|
||||
{
|
||||
std::vector<LPCITEMIDLIST> list;
|
||||
list.push_back( filepidl );
|
||||
//PIDLListMap::MapPair p(folderpidl, list);
|
||||
pidlList.insert( { folderpidl, list } );
|
||||
}
|
||||
|
||||
pDesktopFolder->Release();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL ExplorerFindFile::ShowFiles()
|
||||
{
|
||||
if(pidlList.size())
|
||||
{
|
||||
BOOL ret = TRUE;
|
||||
for (PIDLListMap::iterator itr=pidlList.begin();itr!=pidlList.end();itr++)
|
||||
{
|
||||
if(FAILED(SHOpenFolderAndSelectItems(itr->first,(UINT)itr->second.size(),itr->second.data(),NULL))){
|
||||
ret = FALSE;
|
||||
}
|
||||
}
|
||||
Reset();
|
||||
return ret;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#ifdef CBCLASS
|
||||
#undef CBCLASS
|
||||
#endif
|
||||
|
||||
#define CBCLASS ExplorerFindFile
|
||||
START_DISPATCH;
|
||||
CB(API_EXPLORERFINDFILE_ADDFILE, AddFile)
|
||||
CB(API_EXPLORERFINDFILE_SHOWFILES, ShowFiles)
|
||||
VCB(API_EXPLORERFINDFILE_RESET, Reset)
|
||||
END_DISPATCH
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef NULLSOFT_WINAMP_EXPLORERFINDFILE_H
|
||||
#define NULLSOFT_WINAMP_EXPLORERFINDFILE_H
|
||||
|
||||
#include "../Agave/ExplorerFindFile/api_explorerfindfile.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
class ExplorerFindFile : public api_explorerfindfile
|
||||
{
|
||||
public:
|
||||
ExplorerFindFile();
|
||||
~ExplorerFindFile();
|
||||
static const char *getServiceName() { return "ExplorerFindFile API"; }
|
||||
static const GUID getServiceGuid() { return ExplorerFindFileApiGUID; }
|
||||
BOOL AddFile(wchar_t* file);
|
||||
BOOL ShowFiles();
|
||||
void Reset();
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
|
||||
typedef std::map<LPITEMIDLIST, std::vector<LPCITEMIDLIST>> PIDLListMap;
|
||||
PIDLListMap pidlList;
|
||||
};
|
||||
|
||||
extern ExplorerFindFile *explorerFindFileManager;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,363 @@
|
||||
#include "main.h"
|
||||
#include "api.h"
|
||||
#include "../nu/AutoWide.h"
|
||||
#include "../nu/AutoWideFn.h"
|
||||
#include "../nu/AutoChar.h"
|
||||
#include "../nu/AutoCharFn.h"
|
||||
#include "../nu/AutoLock.h"
|
||||
#include "../nu/ns_wc.h"
|
||||
#include <malloc.h>
|
||||
|
||||
using namespace Nullsoft::Utility;
|
||||
/* Get Extended File Info */
|
||||
|
||||
typedef int (__cdecl *GetANSIInfo)(const char *fn, const char *data, char *dest, size_t destlen);
|
||||
typedef int (__cdecl *GetUnicodeInfo)(const wchar_t *fn, const char *data, wchar_t *dest, size_t destlen);
|
||||
|
||||
int ConvertGetExtendedFileInfo(GetUnicodeInfo getter, const char *fn, const char *data, char *dest, size_t destlen)
|
||||
{
|
||||
wchar_t *destW = 0;
|
||||
|
||||
if (dest && destlen)
|
||||
{
|
||||
destW = (wchar_t *)_malloca(destlen * sizeof(wchar_t));
|
||||
memset(destW, 0, destlen * sizeof(wchar_t));
|
||||
}
|
||||
|
||||
int retVal = getter(AutoWideFn(fn), data, destW, destlen);
|
||||
if (retVal && dest && destlen)
|
||||
WideCharToMultiByteSZ(CP_ACP, 0, destW, -1, dest, (int)destlen, 0, 0);
|
||||
|
||||
if (destW) _freea(destW);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
int ConvertGetExtendedFileInfo(GetANSIInfo getter, const char *fn, const char *data, wchar_t *dest, size_t destlen)
|
||||
{
|
||||
char *destA = 0;
|
||||
|
||||
if (dest && destlen)
|
||||
{
|
||||
destA = (char *)_malloca(destlen * sizeof(char));
|
||||
memset(destA, 0, destlen * sizeof(char));
|
||||
}
|
||||
|
||||
int retVal = getter(fn, data, destA, destlen);
|
||||
if (retVal && dest && destlen)
|
||||
MultiByteToWideCharSZ(CP_ACP, 0, destA, -1, dest, (int)destlen);
|
||||
|
||||
if (destA) _freea(destA);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static GetANSIInfo gefi;
|
||||
static GetUnicodeInfo gefiW;
|
||||
static char cachedExt[16];
|
||||
LockGuard getMetadataGuard;
|
||||
|
||||
int in_get_extended_fileinfo(const char *fn, const char *metadata, char *dest, size_t destlen)
|
||||
{
|
||||
AutoLock lock(getMetadataGuard);
|
||||
|
||||
In_Module *i=0;
|
||||
char ext[16] = {0};
|
||||
int a = 0;
|
||||
|
||||
// do some extra checks on the params as quite a few clients crash when accessing here
|
||||
try {
|
||||
if (destlen > 65536 || destlen == 0 || !fn || (unsigned int)(ULONG_PTR)fn < 65536 ||
|
||||
fn && !*fn || !metadata || (unsigned int)(ULONG_PTR)metadata < 65536 ||
|
||||
metadata && !*metadata || !dest || (unsigned int)(ULONG_PTR)dest < 65536)
|
||||
return 0;
|
||||
} catch (...) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dest)
|
||||
memset(dest, 0, destlen);
|
||||
|
||||
extension_ex(fn, ext, sizeof(ext));
|
||||
|
||||
if (!_stricmp(cachedExt, ext) && *ext)
|
||||
{
|
||||
if (gefi)
|
||||
return gefi(fn, metadata, dest, destlen);
|
||||
else if (gefiW) // should always be true if we got this far
|
||||
return ConvertGetExtendedFileInfo(gefiW, fn, metadata, dest, destlen);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (a >= 0)
|
||||
{
|
||||
i = in_setmod_noplay(AutoWideFn(fn), &a);
|
||||
if (!i)
|
||||
break;
|
||||
|
||||
if (a >= 0) a++;
|
||||
|
||||
lstrcpynA(cachedExt, ext, sizeof(cachedExt)/sizeof(*cachedExt));
|
||||
|
||||
gefi = (GetANSIInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfo");
|
||||
gefiW = (GetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfoW");
|
||||
if (gefi || gefiW)
|
||||
break;
|
||||
}
|
||||
|
||||
// if no one claimed it, then check if it's the currently playing track
|
||||
// benski> TODO: there is a race condition here. In theory, in_mod could change between the lstrcmpiW and the assignment
|
||||
if (!i && !lstrcmpiW(FileName, AutoWide(fn)))
|
||||
{
|
||||
i=in_mod;
|
||||
if (i)
|
||||
{
|
||||
cachedExt[0]=0;
|
||||
gefi = (GetANSIInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfo");
|
||||
gefiW = (GetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfoW");
|
||||
}
|
||||
}
|
||||
|
||||
if (!i)
|
||||
return 0;
|
||||
|
||||
if (gefi)
|
||||
return gefi(fn, metadata, dest, destlen);
|
||||
else if (gefiW)
|
||||
return ConvertGetExtendedFileInfo(gefiW, fn, metadata, dest, destlen);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int in_get_extended_fileinfoW(const wchar_t *fn, const wchar_t *metadata, wchar_t *dest, size_t destlen)
|
||||
{
|
||||
AutoLock lock(getMetadataGuard);
|
||||
|
||||
In_Module *i=0;
|
||||
char ext[16] = {0};
|
||||
int a = 0;
|
||||
|
||||
// do some extra checks on the params as quite a few clients crash when accessing here
|
||||
try {
|
||||
if (destlen > 65536 || destlen == 0 || !fn || (unsigned int)(ULONG_PTR)fn < 65536 ||
|
||||
fn && !*fn || !metadata || (unsigned int)(ULONG_PTR)metadata < 65536 ||
|
||||
metadata && !*metadata || !dest || (unsigned int)(ULONG_PTR)dest < 65536)
|
||||
return 0;
|
||||
} catch (...) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dest)
|
||||
memset(dest, 0, destlen);
|
||||
|
||||
AutoCharFn charFn(fn);
|
||||
extension_ex(charFn, ext, sizeof(ext));
|
||||
|
||||
if (!_stricmp(cachedExt, ext) && *ext)
|
||||
{
|
||||
if (gefiW) // should always be true if we got this far
|
||||
return gefiW(fn, AutoChar(metadata), dest, destlen);
|
||||
if (gefi)
|
||||
return ConvertGetExtendedFileInfo(gefi, charFn, AutoChar(metadata), dest, destlen);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (a >= 0)
|
||||
{
|
||||
i = in_setmod_noplay(fn, &a);
|
||||
if (!i)
|
||||
break;
|
||||
|
||||
if (a >= 0) a++;
|
||||
|
||||
lstrcpynA(cachedExt, ext, sizeof(cachedExt)/sizeof(*cachedExt));
|
||||
|
||||
gefi = (GetANSIInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfo");
|
||||
gefiW = (GetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfoW");
|
||||
if (gefi || gefiW)
|
||||
break;
|
||||
}
|
||||
|
||||
// if no one claimed it, then check if it's the currently playing track
|
||||
// benski> TODO: there is a race condition here. In theory, in_mod could change between the lstrcmpiW and the assignment
|
||||
if (!i && !lstrcmpiW(FileName, fn)) // currently playing file?
|
||||
{
|
||||
i=in_mod;
|
||||
if (i)
|
||||
{
|
||||
cachedExt[0]=0;
|
||||
gefi = (GetANSIInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfo");
|
||||
gefiW = (GetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampGetExtendedFileInfoW");
|
||||
}
|
||||
}
|
||||
|
||||
if (!i)
|
||||
return 0;
|
||||
|
||||
if (gefiW)
|
||||
return gefiW(fn, AutoChar(metadata), dest, destlen);
|
||||
else if (gefi)
|
||||
return ConvertGetExtendedFileInfo(gefi, charFn, AutoChar(metadata), dest, destlen);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set Extended File Info */
|
||||
|
||||
typedef int (__cdecl *SetANSIInfo)(const char *fn, const char *metadata, const char *data);
|
||||
typedef int (__cdecl *SetUnicodeInfo)(const wchar_t *fn, const char *metadata, const wchar_t *data);
|
||||
|
||||
static SetANSIInfo sefi;
|
||||
static SetUnicodeInfo sefiW;
|
||||
static int (*wefi)();
|
||||
static char cachedExtSet[16];
|
||||
|
||||
static int ConvertSetExtendedFileInfo(SetUnicodeInfo setter, const char *fn, const char *metadata, const char *data)
|
||||
{
|
||||
return setter(AutoWide(fn), metadata, AutoWide(data));
|
||||
}
|
||||
|
||||
static int ConvertSetExtendedFileInfo(SetANSIInfo setter, const char *fn, const char *metadata, const wchar_t *data)
|
||||
{
|
||||
return setter(fn, metadata, AutoChar(data));
|
||||
}
|
||||
|
||||
int in_set_extended_fileinfo(const char *fn, const char *metadata, char *data)
|
||||
{
|
||||
AutoLock lock(getMetadataGuard);
|
||||
char ext[16] = {0};
|
||||
int a = 0;
|
||||
|
||||
extension_ex(fn, ext, sizeof(ext));
|
||||
if (!_stricmp(cachedExtSet, ext) && *ext)
|
||||
{
|
||||
if (sefi)
|
||||
return sefi(fn, metadata, data);
|
||||
else if (sefiW)
|
||||
return ConvertSetExtendedFileInfo(sefiW, fn, metadata, data);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (a >= 0)
|
||||
{
|
||||
wefi = NULL;
|
||||
sefi = NULL; // if we fail finding an input plugin, dont let in_write_extended_fileinfo work :)
|
||||
sefiW = NULL;
|
||||
In_Module *i = in_setmod_noplay(AutoWideFn(fn), &a);
|
||||
if (a >= 0) a++;
|
||||
cachedExtSet[0] = 0;
|
||||
if (!i) return 0;
|
||||
lstrcpynA(cachedExtSet, ext, 16);
|
||||
|
||||
sefi = (SetANSIInfo)GetProcAddress(i->hDllInstance, "winampSetExtendedFileInfo");
|
||||
sefiW = (SetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampSetExtendedFileInfoW");
|
||||
wefi = (int (__cdecl *)())GetProcAddress(i->hDllInstance, "winampWriteExtendedFileInfo");
|
||||
if (sefi || sefiW) break;
|
||||
}
|
||||
|
||||
if (sefi)
|
||||
return sefi(fn, metadata, data);
|
||||
else if (sefiW)
|
||||
return ConvertSetExtendedFileInfo(sefiW, fn, metadata, data);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int in_set_extended_fileinfoW(const wchar_t *fn, const wchar_t *metadata, wchar_t *data)
|
||||
{
|
||||
AutoLock lock(getMetadataGuard);
|
||||
|
||||
char ext[16] = {0};
|
||||
int a = 0;
|
||||
|
||||
AutoCharFn charFn(fn);
|
||||
extension_ex(charFn, ext, sizeof(ext));
|
||||
if (!_stricmp(cachedExtSet, ext) && *ext)
|
||||
{
|
||||
if (sefiW)
|
||||
return sefiW(fn, AutoChar(metadata), data);
|
||||
else if (sefi)
|
||||
return ConvertSetExtendedFileInfo(sefi, charFn, AutoChar(metadata), data);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (a >= 0)
|
||||
{
|
||||
wefi = NULL;
|
||||
sefi = NULL; // if we fail finding an input plugin, dont let in_write_extended_fileinfo work :)
|
||||
sefiW = NULL;
|
||||
In_Module *i = in_setmod_noplay(fn, &a);
|
||||
if (a >= 0) a++;
|
||||
cachedExtSet[0] = 0;
|
||||
if (!i) return 0;
|
||||
lstrcpynA(cachedExtSet, ext, 16);
|
||||
|
||||
sefi = (SetANSIInfo)GetProcAddress(i->hDllInstance, "winampSetExtendedFileInfo");
|
||||
sefiW = (SetUnicodeInfo)GetProcAddress(i->hDllInstance, "winampSetExtendedFileInfoW");
|
||||
wefi = (int (__cdecl *)())GetProcAddress(i->hDllInstance, "winampWriteExtendedFileInfo");
|
||||
if (sefi || sefiW) break;
|
||||
}
|
||||
if (sefiW)
|
||||
return sefiW(fn, AutoChar(metadata), data);
|
||||
else if (sefi)
|
||||
return ConvertSetExtendedFileInfo(sefi, charFn, AutoChar(metadata), data);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int in_write_extended_fileinfo()
|
||||
{
|
||||
AutoLock lock(getMetadataGuard);
|
||||
if (!wefi)
|
||||
return 0;
|
||||
return
|
||||
wefi();
|
||||
}
|
||||
|
||||
inline void COPY_METADATA(const wchar_t *src, const wchar_t *dest, const wchar_t *item, wchar_t *buf, size_t buflen)
|
||||
{
|
||||
if (NULL != src && NULL != item && NULL != buf)
|
||||
{
|
||||
buf[0]=0;
|
||||
extendedFileInfoStructW efis=
|
||||
{
|
||||
src,
|
||||
item,
|
||||
buf,
|
||||
buflen,
|
||||
};
|
||||
|
||||
if (SendMessageW(hMainWindow,WM_WA_IPC,(WPARAM)&efis,IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE))
|
||||
in_set_extended_fileinfoW(dest, item, buf);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//#define COPY_METADATA(src, dest, item, buf, buflen) { buf[0]=0; if (in_get_extended_fileinfoW(src, item, buf, buflen)) in_set_extended_fileinfoW(dest, item, buf); }
|
||||
void CopyExtendedFileInfo(const wchar_t *source, const wchar_t *destination)
|
||||
{
|
||||
wchar_t bigData[32768] = {0}; // hopefully big enough for all reasonable metadata
|
||||
|
||||
COPY_METADATA(source, destination, L"title", bigData, 32768);
|
||||
COPY_METADATA(source, destination, L"artist", bigData, 32768);
|
||||
COPY_METADATA(source, destination, L"albumartist", bigData, 32768);
|
||||
COPY_METADATA(source, destination, L"album", bigData, 32768);
|
||||
COPY_METADATA(source, destination, L"genre", bigData, 32768);
|
||||
COPY_METADATA(source, destination, L"year", bigData, 32768);
|
||||
COPY_METADATA(source, destination, L"disc", bigData, 32768);
|
||||
COPY_METADATA(source, destination, L"publisher", bigData, 32768);
|
||||
COPY_METADATA(source, destination, L"comment", bigData, 32768);
|
||||
COPY_METADATA(source, destination, L"track", bigData, 32768);
|
||||
COPY_METADATA(source, destination, L"tool", bigData, 32768);
|
||||
COPY_METADATA(source, destination, L"composer", bigData, 32768);
|
||||
COPY_METADATA(source, destination, L"conductor", bigData, 32768);
|
||||
COPY_METADATA(source, destination, L"bpm", bigData, 32768);
|
||||
COPY_METADATA(source, destination, L"GracenoteFileID", bigData, 32768);
|
||||
COPY_METADATA(source, destination, L"GracenoteExtData", bigData, 32768);
|
||||
in_write_extended_fileinfo();
|
||||
|
||||
//albumArt->CopyAlbumArt(source, destination);
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
|
||||
** Filename:
|
||||
** Project:
|
||||
** Description:
|
||||
** Author: Ben Allison benski@nullsoft.com
|
||||
** Created:
|
||||
**/
|
||||
#include "main.h"
|
||||
#include "ExtendedReader.h"
|
||||
#include "../nu/AutoCharFn.h"
|
||||
|
||||
ExtendedReader::ExtendedReader(OpenFunc _open, OpenWFunc _openW, OpenFunc _openFloat, OpenWFunc _openWFloat, GetDataFunc _getData, CloseFunc _close, SetTimeFunc _setTime)
|
||||
: open(_open), openFloat(_openFloat), openW(_openW), openWFloat(_openWFloat), getData(_getData), close(_close), setTime(_setTime), handle(0)
|
||||
{}
|
||||
|
||||
bool ExtendedReader::Open(const wchar_t *filename, AudioParameters *parameters)
|
||||
{
|
||||
if (parameters->flags & AUDIOPARAMETERS_FLOAT)
|
||||
{
|
||||
if (this->openWFloat)
|
||||
handle = this->openWFloat(filename, (int *) & parameters->sizeBytes, (int *) & parameters->bitsPerSample, (int *) & parameters->channels, (int *) & parameters->sampleRate);
|
||||
else if (this->openFloat)
|
||||
handle = this->openFloat(AutoCharFn(filename), (int *) & parameters->sizeBytes, (int *) & parameters->bitsPerSample, (int *) & parameters->channels, (int *) & parameters->sampleRate);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this->openW)
|
||||
handle = this->openW(filename, (int *) & parameters->sizeBytes, (int *) & parameters->bitsPerSample, (int *) & parameters->channels, (int *) & parameters->sampleRate);
|
||||
else
|
||||
handle = this->open(AutoCharFn(filename), (int *) & parameters->sizeBytes, (int *) & parameters->bitsPerSample, (int *) & parameters->channels, (int *) & parameters->sampleRate);
|
||||
}
|
||||
if (handle > 0)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
if (handle == -1)
|
||||
parameters->errorCode = API_DECODEFILE_FAIL_NO_WARN;
|
||||
else
|
||||
parameters->errorCode = API_DECODEFILE_FAILURE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
size_t ExtendedReader::ReadAudio(void *buffer, size_t sizeBytes)
|
||||
{
|
||||
int killswitch = 0;
|
||||
return this->getData(handle, buffer, sizeBytes, &killswitch);
|
||||
}
|
||||
|
||||
size_t ExtendedReader::ReadAudio_kill(void *buffer, size_t sizeBytes, int *killswitch, int *error)
|
||||
{
|
||||
*error=0;
|
||||
intptr_t ret = this->getData(handle, buffer, sizeBytes, killswitch);
|
||||
if (ret < 0)
|
||||
{
|
||||
*error=1;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return static_cast<size_t>(ret);
|
||||
}
|
||||
|
||||
BOOL ExtendedReader::SeekToTimeMs(int millisecs)
|
||||
{
|
||||
if (!setTime)
|
||||
return FALSE;
|
||||
return this->setTime(handle, millisecs);
|
||||
}
|
||||
|
||||
int ExtendedReader::CanSeek()
|
||||
{
|
||||
return setTime?1:0;
|
||||
}
|
||||
|
||||
ExtendedReader::~ExtendedReader()
|
||||
{
|
||||
if (handle)
|
||||
this->close(handle);
|
||||
}
|
||||
|
||||
#define CBCLASS ExtendedReader
|
||||
START_DISPATCH;
|
||||
CB(IFC_AUDIOSTREAM_READAUDIO, ReadAudio)
|
||||
CB(IFC_AUDIOSTREAM_READAUDIO2, ReadAudio_kill)
|
||||
CB(IFC_AUDIOSTREAM_SEEKTOTIMEMS, SeekToTimeMs)
|
||||
CB(IFC_AUDIOSTREAM_CANSEEK, CanSeek)
|
||||
END_DISPATCH;
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef NULLSOFT_WINAMP_EXTENDEDREADER_H
|
||||
#define NULLSOFT_WINAMP_EXTENDEDREADER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include "../Agave/DecodeFile/ifc_audiostream.h"
|
||||
#include "../Agave/DecodeFile/api_decodefile.h"
|
||||
#include "CommonReader.h"
|
||||
|
||||
typedef intptr_t (__cdecl *OpenFunc)(const char *filename, int *size, int *bps, int *nch, int *srate);
|
||||
typedef intptr_t (__cdecl *OpenWFunc)(const wchar_t *filename, int *size, int *bps, int *nch, int *srate);
|
||||
typedef size_t (__cdecl *GetDataFunc)(intptr_t handle, void *buffer, size_t bufferBytes, int *killswitch);
|
||||
typedef void (__cdecl *CloseFunc)(intptr_t);
|
||||
typedef int (__cdecl *SetTimeFunc)(intptr_t handle, int millisecs);
|
||||
|
||||
class ExtendedReader : public CommonReader
|
||||
{
|
||||
public:
|
||||
ExtendedReader(OpenFunc _open, OpenWFunc _openW, OpenFunc _openFloat, OpenWFunc _openWFloat, GetDataFunc _getData, CloseFunc _close, SetTimeFunc _setTime = 0);
|
||||
~ExtendedReader();
|
||||
bool Open(const wchar_t *filename, AudioParameters *parameters);
|
||||
size_t ReadAudio(void *buffer, size_t sizeBytes);
|
||||
size_t ReadAudio_kill(void *buffer, size_t sizeBytes, int *killswitch, int *error);
|
||||
BOOL SeekToTimeMs(int millisecs);
|
||||
int CanSeek();
|
||||
|
||||
OpenFunc open, openFloat;
|
||||
OpenWFunc openW, openWFloat;
|
||||
GetDataFunc getData;
|
||||
CloseFunc close;
|
||||
SetTimeFunc setTime;
|
||||
intptr_t handle;
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,520 @@
|
||||
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
|
||||
** Filename:
|
||||
** Project:
|
||||
** Description:
|
||||
** Author: Ben Allison benski@nullsoft.com
|
||||
** Created:
|
||||
**/
|
||||
#include "Main.h"
|
||||
#include "ExternalCOM.h"
|
||||
#include "BrowserCOM.h"
|
||||
#include "CurrentSongCOM.h"
|
||||
#include "SkinCOM.h"
|
||||
#include "ApplicationCOM.h"
|
||||
#include "BookmarksCOM.h"
|
||||
#include "MediaCoreCOM.h"
|
||||
#include "DataStoreCOM.h"
|
||||
#include "JNetCOM.h"
|
||||
#include "SecurityCOM.h"
|
||||
#include "../nu/ConfigCOM.h"
|
||||
#include "../nu/AutoChar.h"
|
||||
#include "../nu/AutoCharFn.h"
|
||||
#include "./Winamp/JSAPI.h"
|
||||
#include "JSAPI2_ExternalObject.h"
|
||||
#include "JSAPI2_Security.h"
|
||||
|
||||
static volatile LONG unique_dispid;
|
||||
|
||||
enum
|
||||
{
|
||||
DISPID_CONFIG = 0,
|
||||
DISPID_JNET = 1,
|
||||
INITIAL_DISPID = 776,
|
||||
};
|
||||
|
||||
static ExternalCOM *externalCOM = NULL;
|
||||
|
||||
HRESULT __cdecl JSAPI1_Initialize()
|
||||
{
|
||||
if (NULL != externalCOM)
|
||||
return S_FALSE;
|
||||
|
||||
ExternalCOM *temp = new ExternalCOM();
|
||||
if (NULL == temp)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
externalCOM = temp;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT __cdecl JSAPI1_Uninitialize()
|
||||
{
|
||||
if (NULL == externalCOM)
|
||||
return S_FALSE;
|
||||
|
||||
ExternalCOM *temp = externalCOM;
|
||||
externalCOM = NULL;
|
||||
temp->Release();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT __cdecl JSAPI1_GetExternal(ExternalCOM **instance)
|
||||
{
|
||||
if (NULL == instance)
|
||||
return E_POINTER;
|
||||
|
||||
if (NULL == externalCOM)
|
||||
{
|
||||
*instance = NULL;
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
externalCOM->AddRef();
|
||||
*instance = externalCOM;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT __cdecl JSAPI1_GetSkinCOM(SkinCOM **instance)
|
||||
{
|
||||
ExternalCOM *external = 0;
|
||||
HRESULT hr = JSAPI1_GetExternal(&external);
|
||||
if (SUCCEEDED(hr) && external)
|
||||
{
|
||||
hr = external->GetSkinCOM(instance);
|
||||
external->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NULL == instance) hr = E_POINTER;
|
||||
else *instance = NULL;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT __cdecl JSAPI1_GetMediaCoreCOM(MediaCoreCOM **instance)
|
||||
{
|
||||
ExternalCOM *external = 0;
|
||||
HRESULT hr = JSAPI1_GetExternal(&external);
|
||||
if (SUCCEEDED(hr) && external)
|
||||
{
|
||||
hr = external->GetMediaCoreCOM(instance);
|
||||
external->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NULL == instance) hr = E_POINTER;
|
||||
else *instance = NULL;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT __cdecl JSAPI1_GetCurrentSongCOM(CurrentSongCOM **instance)
|
||||
{
|
||||
ExternalCOM *external = 0;
|
||||
HRESULT hr = JSAPI1_GetExternal(&external);
|
||||
if (SUCCEEDED(hr) && external)
|
||||
{
|
||||
hr = external->GetCurrentSongCOM(instance);
|
||||
external->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NULL == instance) hr = E_POINTER;
|
||||
else *instance = NULL;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT __cdecl JSAPI1_SkinChanged()
|
||||
{
|
||||
SkinCOM *skinCOM = 0;
|
||||
HRESULT hr = JSAPI1_GetSkinCOM(&skinCOM);
|
||||
if (SUCCEEDED(hr) && skinCOM)
|
||||
{
|
||||
skinCOM->SkinChanged();
|
||||
skinCOM->Release();
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT __cdecl JSAPI1_CurrentTitleChanged()
|
||||
{
|
||||
CurrentSongCOM *songCOM = 0;
|
||||
HRESULT hr = JSAPI1_GetCurrentSongCOM(&songCOM);
|
||||
if (SUCCEEDED(hr) && songCOM)
|
||||
{
|
||||
songCOM->TitleChanged();
|
||||
songCOM->Release();
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
DISPID __cdecl JSAPI1_GenerateUniqueDispatchId()
|
||||
{
|
||||
return (DISPID)InterlockedIncrement(&unique_dispid);
|
||||
}
|
||||
|
||||
#define REGISTER_DISPATCH_EX(__name, __creator, __dispId, __pDisp)\
|
||||
{ __pDisp = new __creator;\
|
||||
if (NULL != __pDisp) {\
|
||||
__dispId = AddDispatch(__name, __pDisp);\
|
||||
if (0 == __dispId) { (__pDisp)->Release(); (__pDisp) = NULL;}\
|
||||
}\
|
||||
}
|
||||
|
||||
#define REGISTER_DISPATCH(__name, __creator)\
|
||||
{ DISPID __dispId; IDispatch *pDisp; \
|
||||
REGISTER_DISPATCH_EX(__name, __creator, __dispId, pDisp);\
|
||||
if (NULL != pDisp) pDisp->Release(); }
|
||||
|
||||
static const wchar_t *api1_api2_key = L"1";
|
||||
|
||||
ExternalCOM::ExternalCOM() : ref(1), mediaCoreCOM(NULL), skinCOM(NULL), songCOM(NULL), api2(0)
|
||||
{
|
||||
InitializeCriticalSection(&tableLock);
|
||||
unique_dispid = INITIAL_DISPID; // we can't count on the CRT to have initialized this yet.
|
||||
configFilename[0]=0;
|
||||
|
||||
DISPID dispId = 0;
|
||||
REGISTER_DISPATCH(L"Browser", BrowserCOM());
|
||||
REGISTER_DISPATCH_EX(L"CurrentSong", CurrentSongCOM(), dispId, songCOM);
|
||||
REGISTER_DISPATCH_EX(L"CurrentSkin", SkinCOM(), dispId, skinCOM);
|
||||
REGISTER_DISPATCH(L"Application", ApplicationCOM());
|
||||
REGISTER_DISPATCH(L"Bookmarks", BookmarksCOM());
|
||||
REGISTER_DISPATCH_EX(L"MediaCore", MediaCoreCOM(), dispId, mediaCoreCOM);
|
||||
REGISTER_DISPATCH(L"DataStore", DataStoreCOM());
|
||||
REGISTER_DISPATCH(L"Security", SecurityCOM());
|
||||
JSAPI2::security.SetBypass(api1_api2_key, true);
|
||||
REGISTER_DISPATCH_EX(L"API2", JSAPI2::ExternalObject(api1_api2_key), dispId, api2);
|
||||
}
|
||||
|
||||
ExternalCOM::~ExternalCOM()
|
||||
{
|
||||
EnterCriticalSection(&tableLock);
|
||||
|
||||
for ( JSAPI::Dispatcher *l_dispatch_table : dispatchTable )
|
||||
delete l_dispatch_table;
|
||||
|
||||
for ( ConfigCOM *l_config : configs )
|
||||
l_config->Release();
|
||||
|
||||
LeaveCriticalSection(&tableLock);
|
||||
|
||||
DeleteCriticalSection(&tableLock);
|
||||
|
||||
if (NULL != mediaCoreCOM) mediaCoreCOM->Release();
|
||||
if (NULL != songCOM) songCOM->Release();
|
||||
if (NULL != skinCOM) skinCOM->Release();
|
||||
if (NULL != api2) api2->Release();
|
||||
}
|
||||
|
||||
#define CHECK_ID(str, id)\
|
||||
if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
|
||||
{ rgdispid[i] = id; continue; }
|
||||
|
||||
STDMETHODIMP ExternalCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
|
||||
{
|
||||
UINT unknowns = 0;
|
||||
|
||||
EnterCriticalSection(&tableLock);
|
||||
size_t tableCount = dispatchTable.size();
|
||||
|
||||
for (unsigned int i = 0;i != cNames; i++)
|
||||
{
|
||||
rgdispid[i]=DISPID_UNKNOWN;
|
||||
|
||||
for (size_t entry = 0; entry < tableCount; entry++)
|
||||
{
|
||||
if (!wcscmp(rgszNames[i], dispatchTable[entry]->name))
|
||||
{
|
||||
rgdispid[i] = dispatchTable[entry]->id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rgdispid[i] == DISPID_UNKNOWN && !wcscmp(rgszNames[i], L"Config"))
|
||||
rgdispid[i] = DISPID_CONFIG;
|
||||
else if (rgdispid[i] == DISPID_UNKNOWN && !wcscmp(rgszNames[i], L"JNetLib"))
|
||||
rgdispid[i] = DISPID_JNET;
|
||||
else if (rgdispid[i] == DISPID_UNKNOWN)
|
||||
unknowns++;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&tableLock);
|
||||
|
||||
if (0 != unknowns)
|
||||
return DISP_E_UNKNOWNNAME;
|
||||
else
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP ExternalCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP ExternalCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP ExternalCOM::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 DISPID_CONFIG:
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
|
||||
|
||||
LPCWSTR configName;
|
||||
JSAPI_GETSTRING(configName, pdispparams, 1, puArgErr);
|
||||
|
||||
if (NULL != pvarResult)
|
||||
{
|
||||
VariantInit(pvarResult);
|
||||
|
||||
ConfigCOM *config;
|
||||
if (SUCCEEDED(GetConfig(configName, &config)))
|
||||
{
|
||||
V_VT(pvarResult) = VT_DISPATCH;
|
||||
V_DISPATCH(pvarResult) = config;
|
||||
}
|
||||
else
|
||||
{
|
||||
V_VT(pvarResult) = VT_NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
|
||||
case DISPID_JNET:
|
||||
{
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_DISPATCH;
|
||||
V_DISPATCH(pvarResult) = new JNetCOM(pdispparams->rgvarg[0].pdispVal);
|
||||
return S_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&tableLock);
|
||||
size_t index = dispatchTable.size();
|
||||
while(index--)
|
||||
{
|
||||
if (dispatchTable[index]->id == dispid)
|
||||
{
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_DISPATCH;
|
||||
V_DISPATCH(pvarResult) = dispatchTable[index]->object;
|
||||
dispatchTable[index]->object->AddRef();
|
||||
break;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&tableLock);
|
||||
if (((size_t)-1) != index) return S_OK;
|
||||
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
STDMETHODIMP ExternalCOM::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;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG) ExternalCOM::AddRef(void)
|
||||
{
|
||||
return InterlockedIncrement((LONG*)&ref);
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG) ExternalCOM::Release(void)
|
||||
{
|
||||
if (0 == ref)
|
||||
return ref;
|
||||
|
||||
LONG r = InterlockedDecrement((LONG*)&ref);
|
||||
if (0 == r)
|
||||
delete(this);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
STDMETHODIMP ExternalCOM::QueryDispatchable(REFIID riid, Dispatchable **ppDispatchable)
|
||||
{
|
||||
if (IsEqualIID(riid, JSAPI::IID_JSAPI_ifc_info))
|
||||
{
|
||||
*ppDispatchable = (JSAPI::ifc_info *)this;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppDispatchable = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
(*ppDispatchable)->AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
const wchar_t *ExternalCOM::GetUserAgent()
|
||||
{
|
||||
return L"JSAPI1";
|
||||
}
|
||||
|
||||
HRESULT ExternalCOM::GetConfig(LPCWSTR configName, ConfigCOM **config)
|
||||
{
|
||||
if (NULL == config) return E_POINTER;
|
||||
|
||||
AutoChar nameAnsi(configName);
|
||||
if (NULL == (const char*)nameAnsi)
|
||||
{
|
||||
*config = NULL;
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&tableLock);
|
||||
|
||||
// check if there's already an open config object
|
||||
size_t index = configs.size();
|
||||
while (index-- && FALSE != configs[index]->IsEqual(nameAnsi));
|
||||
|
||||
if ((size_t)-1 == index)
|
||||
{
|
||||
if (L'\0' != configFilename[0] ||
|
||||
NULL != PathCombineW(configFilename, CONFIGDIR, L"jscfg.ini"))
|
||||
{
|
||||
if (SUCCEEDED(ConfigCOM::CreateInstanceA(nameAnsi, AutoCharFn(configFilename), config)))
|
||||
configs.push_back(*config);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*config = configs[index];
|
||||
}
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
if (NULL != *config)
|
||||
{
|
||||
(*config)->AddRef();
|
||||
}
|
||||
else
|
||||
hr = E_FAIL;
|
||||
|
||||
LeaveCriticalSection(&tableLock);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT ExternalCOM::FindDispatch(DISPID dispId, IDispatch **instance)
|
||||
{
|
||||
if (NULL == instance)
|
||||
return E_POINTER;
|
||||
|
||||
EnterCriticalSection(&tableLock);
|
||||
size_t index = dispatchTable.size();
|
||||
while(index--)
|
||||
{
|
||||
if (dispatchTable[index]->id == dispId)
|
||||
{
|
||||
*instance = dispatchTable[index]->object;
|
||||
break;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&tableLock);
|
||||
|
||||
if (((size_t)-1) != index)
|
||||
return S_OK;
|
||||
|
||||
*instance = NULL;
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
DISPID ExternalCOM::AddDispatch(const wchar_t *name, IDispatch *object)
|
||||
{
|
||||
if (NULL == object)
|
||||
return 0;
|
||||
|
||||
DISPID id = JSAPI1_GenerateUniqueDispatchId();
|
||||
|
||||
JSAPI::Dispatcher *dispatcher = new JSAPI::Dispatcher(name, id, object);
|
||||
if (NULL == dispatcher) return 0;
|
||||
|
||||
EnterCriticalSection(&tableLock);
|
||||
dispatchTable.push_back(dispatcher);
|
||||
LeaveCriticalSection(&tableLock);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
BOOL ExternalCOM::RemoveDispatch(DISPID dispatchId)
|
||||
{
|
||||
EnterCriticalSection(&tableLock);
|
||||
size_t index = dispatchTable.size();
|
||||
while(index--)
|
||||
{
|
||||
if (dispatchTable[index]->id == dispatchId)
|
||||
{
|
||||
JSAPI::Dispatcher *dispatcher = dispatchTable[index];
|
||||
dispatchTable.erase(dispatchTable.begin() + index);
|
||||
delete dispatcher;
|
||||
break;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&tableLock);
|
||||
return (((size_t)-1) != index);
|
||||
}
|
||||
|
||||
HRESULT ExternalCOM::GetSkinCOM(SkinCOM **instance)
|
||||
{
|
||||
if (NULL == instance)
|
||||
return E_POINTER;
|
||||
|
||||
*instance = skinCOM;
|
||||
if (NULL != *instance)
|
||||
(*instance)->AddRef();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT ExternalCOM::GetMediaCoreCOM(MediaCoreCOM **instance)
|
||||
{
|
||||
if (NULL == instance)
|
||||
return E_POINTER;
|
||||
|
||||
*instance = mediaCoreCOM;
|
||||
if (NULL != *instance)
|
||||
(*instance)->AddRef();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT ExternalCOM::GetCurrentSongCOM(CurrentSongCOM **instance)
|
||||
{
|
||||
if (NULL == instance)
|
||||
return E_POINTER;
|
||||
|
||||
*instance = songCOM;
|
||||
if (NULL != *instance)
|
||||
(*instance)->AddRef();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#define CBCLASS ExternalCOM
|
||||
START_DISPATCH;
|
||||
CB(JSAPI_IFC_INFO_GETUSERAGENT, GetUserAgent)
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
@@ -0,0 +1,89 @@
|
||||
#ifndef NULLSOFT_EXTERNALCOMH
|
||||
#define NULLSOFT_EXTERNALCOMH
|
||||
|
||||
#include <ocidl.h>
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
||||
#include <vector>
|
||||
#include "JSAPI_DispatchTable.h"
|
||||
#include "IWasabiDispatchable.h"
|
||||
#include "JSAPI_Info.h"
|
||||
|
||||
class SkinCOM;
|
||||
class MediaCoreCOM;
|
||||
class CurrentSongCOM;
|
||||
class ExternalCOM;
|
||||
class ConfigCOM;
|
||||
namespace JSAPI2 { class ExternalObject; }
|
||||
|
||||
HRESULT __cdecl JSAPI1_GetExternal(ExternalCOM **instance);
|
||||
HRESULT __cdecl JSAPI1_GetSkinCOM(SkinCOM **instance);
|
||||
HRESULT __cdecl JSAPI1_GetMediaCoreCOM(MediaCoreCOM **instance);
|
||||
HRESULT __cdecl JSAPI1_GetCurrentSongCOM(CurrentSongCOM **instance);
|
||||
|
||||
class ExternalCOM : public IDispatch,
|
||||
public IWasabiDispatchable,
|
||||
public JSAPI::ifc_info
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
DISP_EXTERNAL_SIDECAR = 777,
|
||||
DISP_EXTERNAL_BROWSER,
|
||||
DISP_EXTERNAL_CURRENTSONG,
|
||||
DISP_EXTERNAL_CURRENTSKIN,
|
||||
DISP_EXTERNAL_NEW_ENTRIES_MARKER,
|
||||
};
|
||||
|
||||
public:
|
||||
ExternalCOM();
|
||||
~ExternalCOM();
|
||||
|
||||
// *** IUnknown ***
|
||||
STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
|
||||
STDMETHOD_(ULONG, AddRef)(void);
|
||||
STDMETHOD_(ULONG, Release)(void);
|
||||
// *** IDispatch ***
|
||||
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);
|
||||
|
||||
JSAPI::DispatchTable dispatchTable;
|
||||
DISPID AddDispatch(const wchar_t *name, IDispatch *object);
|
||||
BOOL RemoveDispatch(DISPID dispatchId);
|
||||
|
||||
|
||||
// *** IWasabiDispatchable Methods ***
|
||||
STDMETHOD(QueryDispatchable)(REFIID riid, Dispatchable **ppDispatchable);
|
||||
|
||||
// *** JSAPI::ifc_info Methods ***
|
||||
const wchar_t *GetUserAgent();
|
||||
|
||||
HRESULT FindDispatch(DISPID dispId, IDispatch **instance);
|
||||
HRESULT GetSkinCOM(SkinCOM **instance);
|
||||
HRESULT GetMediaCoreCOM(MediaCoreCOM **instance);
|
||||
HRESULT GetCurrentSongCOM(CurrentSongCOM **instance);
|
||||
|
||||
HRESULT GetConfig(LPCWSTR configName, ConfigCOM **config);
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
|
||||
private:
|
||||
typedef std::vector<ConfigCOM*> ConfigsList;
|
||||
|
||||
private:
|
||||
ULONG ref;
|
||||
CRITICAL_SECTION tableLock;
|
||||
wchar_t configFilename[MAX_PATH];
|
||||
MediaCoreCOM *mediaCoreCOM;
|
||||
SkinCOM *skinCOM;
|
||||
CurrentSongCOM *songCOM;
|
||||
JSAPI2::ExternalObject *api2;
|
||||
ConfigsList configs;
|
||||
};
|
||||
#endif // __cplusplus
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void fft_init();
|
||||
void fft_9(float wave[512]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
|
||||
** Filename:
|
||||
** Project:
|
||||
** Description:
|
||||
** Author:
|
||||
** Created:
|
||||
**/
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include "main.h"
|
||||
#include "fft.h"
|
||||
#include "../nsutil/fft.h"
|
||||
|
||||
static nsutil_fft_t fft9;
|
||||
|
||||
|
||||
void fft_init()
|
||||
{
|
||||
if (!fft9)
|
||||
nsutil_fft_Create_F32R(&fft9, 9, nsutil_fft_fast);
|
||||
}
|
||||
|
||||
void fft_9(float wave[512])
|
||||
{
|
||||
fft_init(); // getting crash reports of this not being created. strange
|
||||
nsutil_fft_Forward_F32R_IP(fft9, wave);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,449 @@
|
||||
#ifndef _WAFE_H_
|
||||
#define _WAFE_H_
|
||||
/*
|
||||
** Winamp frontend/plug-in control API documentation v1.1.
|
||||
** By Justin Frankel. Updates by Christophe Thibault.
|
||||
** Copyright (C) 1997-2000, Nullsoft Inc.
|
||||
** Last updated: JUL.12.2000.
|
||||
**
|
||||
** Introduction
|
||||
** -----------------------
|
||||
** This file describes a means to easily communicate to Winamp
|
||||
** via the classic Win32 Message API.
|
||||
**
|
||||
** These definitions/code assume C/C++. Porting to VB/Delphi shouldn't
|
||||
** be too hard.
|
||||
**
|
||||
** First, you find the HWND of the Winamp main window. From a plug-in
|
||||
** you can easily extract this from the plug-in structure (hMainWindow,
|
||||
** hwndParent, whatever). For external apps, use:
|
||||
**
|
||||
** HWND hwnd_winamp = FindWindow("Winamp v1.x",NULL);
|
||||
**
|
||||
** (note: I know, we're in Winamp 2.x, but it's 1.x for compatibility)
|
||||
**
|
||||
** Once you have the hwnd_winamp, it's a good idea to check the version
|
||||
** number. To do this, you send a WM_WA_IPC message to hwnd_winamp.
|
||||
** Note that WM_WA_IPC is defined as Win32's WM_USER.
|
||||
**
|
||||
** Note that sometimes you might want to use PostMessage instead of
|
||||
** SendMessageW.
|
||||
*/
|
||||
|
||||
#define WM_WA_IPC WM_USER
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
#define IPC_GETVERSION 0
|
||||
|
||||
/*
|
||||
** int version = SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETVERSION);
|
||||
**
|
||||
** Version will be 0x20yx for winamp 2.yx. versions previous to Winamp 2.0
|
||||
** typically (but not always) use 0x1zyx for 1.zx versions. Weird, I know.
|
||||
**
|
||||
** The basic format for sending messages to Winamp is:
|
||||
** int result=SendMessageW(hwnd_winamp,WM_WA_IPC,command_data,command);
|
||||
** (for the version check, command_data is 0).
|
||||
*/
|
||||
|
||||
|
||||
#define IPC_DELETE 101
|
||||
|
||||
/*
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_DELETE);
|
||||
**
|
||||
** You can use IPC_DELETE to clear Winamp's internal playlist.
|
||||
*/
|
||||
|
||||
|
||||
#define IPC_STARTPLAY 102
|
||||
|
||||
/*
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_STARTPLAY);
|
||||
**
|
||||
** Using IPC_STARTPLAY is like hitting 'Play' in Winamp, mostly.
|
||||
*/
|
||||
|
||||
|
||||
#define IPC_ISPLAYING 104
|
||||
|
||||
/*
|
||||
** int res = SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_ISPLAYING);
|
||||
**
|
||||
** IPC_ISPLAYING returns the status of playback.
|
||||
** If it returns 1, it is playing. if it returns 3, it is paused,
|
||||
** if it returns 0, it is not playing.
|
||||
*/
|
||||
|
||||
|
||||
#define IPC_GETOUTPUTTIME 105
|
||||
|
||||
/*
|
||||
** int res = SendMessageW(hwnd_winamp,WM_WA_IPC,mode,IPC_GETOUTPUTTIME);
|
||||
**
|
||||
** IPC_GETOUTPUTTIME returns the position in milliseconds of the
|
||||
** current song (mode = 0), or the song length, in seconds (mode = 1).
|
||||
** Returns -1 if not playing or error.
|
||||
*/
|
||||
|
||||
|
||||
#define IPC_JUMPTOTIME 106
|
||||
|
||||
/* (requires Winamp 1.60+)
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,ms,IPC_JUMPTOTIME);
|
||||
** IPC_JUMPTOTIME sets the position in milliseconds of the
|
||||
** current song (approximately).
|
||||
** Returns -1 if not playing, 1 on eof, or 0 if successful
|
||||
*/
|
||||
|
||||
|
||||
#define IPC_WRITEPLAYLIST 120
|
||||
|
||||
/* (requires Winamp 1.666+)
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_WRITEPLAYLIST);
|
||||
**
|
||||
** IPC_WRITEPLAYLIST writes the current playlist to <winampdir>\\Winamp.m3u,
|
||||
** and returns the current playlist position.
|
||||
** Kinda obsoleted by some of the 2.x new stuff, but still good for when
|
||||
** using a front-end (instead of a plug-in)
|
||||
*/
|
||||
|
||||
|
||||
#define IPC_SETPLAYLISTPOS 121
|
||||
|
||||
/* (requires Winamp 2.0+)
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,position,IPC_SETPLAYLISTPOS)
|
||||
**
|
||||
** IPC_SETPLAYLISTPOS sets the playlsit position to 'position'.
|
||||
*/
|
||||
|
||||
|
||||
#define IPC_SETVOLUME 122
|
||||
|
||||
/* (requires Winamp 2.0+)
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,volume,IPC_SETVOLUME);
|
||||
**
|
||||
** IPC_SETVOLUME sets the volume of Winamp (from 0-255).
|
||||
*/
|
||||
|
||||
|
||||
#define IPC_SETPANNING 123
|
||||
|
||||
/* (requires Winamp 2.0+)
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,panning,IPC_SETPANNING);
|
||||
**
|
||||
** IPC_SETPANNING sets the panning of Winamp (from 0 (left) to 255 (right)).
|
||||
*/
|
||||
|
||||
|
||||
#define IPC_GETLISTLENGTH 124
|
||||
|
||||
/* (requires Winamp 2.0+)
|
||||
** int length = SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTLENGTH);
|
||||
**
|
||||
** IPC_GETLISTLENGTH returns the length of the current playlist, in
|
||||
** tracks.
|
||||
*/
|
||||
|
||||
|
||||
#define IPC_SETSKIN 200
|
||||
|
||||
/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)"skinname",IPC_SETSKIN);
|
||||
**
|
||||
** IPC_SETSKIN sets the current skin to "skinname". Note that skinname
|
||||
** can be the name of a skin, a skin .zip file, with or without path.
|
||||
** If path isn't specified, the default search path is the winamp skins
|
||||
** directory.
|
||||
*/
|
||||
|
||||
|
||||
#define IPC_GETSKIN 201
|
||||
|
||||
/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)skinname_buffer,IPC_GETSKIN);
|
||||
**
|
||||
** IPC_GETSKIN puts the directory where skin bitmaps can be found
|
||||
** into skinname_buffer.
|
||||
** skinname_buffer must be MAX_PATH characters in length.
|
||||
** When using a .zip'd skin file, it'll return a temporary directory
|
||||
** where the ZIP was decompressed.
|
||||
*/
|
||||
|
||||
|
||||
#define IPC_EXECPLUG 202
|
||||
|
||||
/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)"vis_file.dll",IPC_EXECPLUG);
|
||||
**
|
||||
** IPC_EXECPLUG executes a visualization plug-in pointed to by WPARAM.
|
||||
** the format of this string can be:
|
||||
** "vis_whatever.dll"
|
||||
** "vis_whatever.dll,0" // (first mod, file in winamp plug-in dir)
|
||||
** "C:\\dir\\vis_whatever.dll,1"
|
||||
*/
|
||||
|
||||
|
||||
#define IPC_GETPLAYLISTFILE 211
|
||||
|
||||
/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
|
||||
** char *name=SendMessageW(hwnd_winamp,WM_WA_IPC,index,IPC_GETPLAYLISTFILE);
|
||||
**
|
||||
** IPC_GETPLAYLISTFILE gets the filename of the playlist entry [index].
|
||||
** returns a pointer to it. returns NULL on error.
|
||||
*/
|
||||
|
||||
|
||||
#define IPC_GETPLAYLISTTITLE 212
|
||||
|
||||
/* (requires Winamp 2.04+, only usable from plug-ins (not external apps))
|
||||
** char *name=SendMessageW(hwnd_winamp,WM_WA_IPC,index,IPC_GETPLAYLISTTITLE);
|
||||
**
|
||||
** IPC_GETPLAYLISTTITLE gets the title of the playlist entry [index].
|
||||
** returns a pointer to it. returns NULL on error.
|
||||
*/
|
||||
|
||||
|
||||
#define IPC_GETLISTPOS 125
|
||||
|
||||
/* (requires Winamp 2.05+)
|
||||
** int pos=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTPOS);
|
||||
**
|
||||
** IPC_GETLISTPOS returns the playlist position. A lot like IPC_WRITEPLAYLIST
|
||||
** only faster since it doesn't have to write out the list. Heh, silly me.
|
||||
*/
|
||||
|
||||
|
||||
#define IPC_GETINFO 126
|
||||
|
||||
/* (requires Winamp 2.05+)
|
||||
** int inf=SendMessageW(hwnd_winamp,WM_WA_IPC,mode,IPC_GETINFO);
|
||||
**
|
||||
** IPC_GETINFO returns info about the current playing song. The value
|
||||
** it returns depends on the value of 'mode'.
|
||||
** Mode Meaning
|
||||
** ------------------
|
||||
** 0 Samplerate (i.e. 44100)
|
||||
** 1 Bitrate (i.e. 128)
|
||||
** 2 Channels (i.e. 2)
|
||||
*/
|
||||
|
||||
|
||||
#define IPC_GETEQDATA 127
|
||||
|
||||
/* (requires Winamp 2.05+)
|
||||
** int data=SendMessageW(hwnd_winamp,WM_WA_IPC,pos,IPC_GETEQDATA);
|
||||
**
|
||||
** IPC_GETEQDATA queries the status of the EQ.
|
||||
** The value returned depends on what 'pos' is set to:
|
||||
** Value Meaning
|
||||
** ------------------
|
||||
** 0-9 The 10 bands of EQ data. 0-63 (+20db - -20db)
|
||||
** 10 The preamp value. 0-63 (+20db - -20db)
|
||||
** 11 Enabled. zero if disabled, nonzero if enabled.
|
||||
** 12 Autoload. zero if disabled, nonzero if enabled.
|
||||
*/
|
||||
|
||||
|
||||
#define IPC_SETEQDATA 128
|
||||
/* (requires Winamp 2.05+)
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,pos,IPC_GETEQDATA);
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,value,IPC_SETEQDATA);
|
||||
**
|
||||
** IPC_SETEQDATA sets the value of the last position retrieved
|
||||
** by IPC_GETEQDATA.
|
||||
*/
|
||||
|
||||
#define IPC_ADDBOOKMARK 129
|
||||
/* (requires Winamp 2.4+)
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)file,IPC_ADDBOOKMARK);
|
||||
**
|
||||
** IPC_ADDBOOKMARK will add the specified file to the Winamp bookmark list.
|
||||
*/
|
||||
|
||||
#define IPC_RESTARTWINAMP 135
|
||||
/* (requires Winamp 2.2+)
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_RESTARTWINAMP);
|
||||
**
|
||||
** IPC_RESTARTWINAMP will restart Winamp (isn't that obvious ? :)
|
||||
*/
|
||||
|
||||
#define IPC_MBOPEN 241
|
||||
/* (requires Winamp 2.05+)
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_MBOPEN);
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)url,IPC_MBOPEN);
|
||||
**
|
||||
** IPC_MBOPEN will open a new URL in the minibrowser. if url is NULL, it will open the Minibrowser window.
|
||||
*/
|
||||
|
||||
#define IPC_INETAVAILABLE 242
|
||||
/* (requires Winamp 2.05+)
|
||||
** val=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_INETAVAILABLE);
|
||||
**
|
||||
** IPC_INETAVAILABLE will return 1 if the Internet connection is available for Winamp.
|
||||
*/
|
||||
|
||||
#define IPC_UPDTITLE 243
|
||||
/* (requires Winamp 2.2+)
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_UPDTITLE);
|
||||
**
|
||||
** IPC_UPDTITLE will ask Winamp to update the informations about the current title.
|
||||
*/
|
||||
|
||||
#define IPC_CHANGECURRENTFILE 245
|
||||
/* (requires Winamp 2.05+)
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)file,IPC_CHANGECURRENTFILE);
|
||||
**
|
||||
** IPC_CHANGECURRENTFILE will set the current playlist item.
|
||||
*/
|
||||
|
||||
#define IPC_GETMBURL 246
|
||||
/* (requires Winamp 2.2+)
|
||||
** char buffer[4096]; // Urls can be VERY long
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)buffer,IPC_GETMBURL);
|
||||
**
|
||||
** IPC_GETMBURL will retrieve the current Minibrowser URL into buffer.
|
||||
*/
|
||||
|
||||
#define IPC_REFRESHPLCACHE 247
|
||||
/* (requires Winamp 2.2+)
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_REFRESHPLCACHE);
|
||||
**
|
||||
** IPC_REFRESHPLCACHE will flush the playlist cache buffer.
|
||||
*/
|
||||
|
||||
#define IPC_MBBLOCK 248
|
||||
/* (requires Winamp 2.4+)
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,value,IPC_MBBLOCK);
|
||||
**
|
||||
** IPC_MBBLOCK will block the Minibrowser from updates if value is set to 1
|
||||
*/
|
||||
|
||||
#define IPC_MBOPENREAL 249
|
||||
/* (requires Winamp 2.4+)
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,(WPARAM)url,IPC_MBOPENREAL);
|
||||
**
|
||||
** IPC_MBOPENREAL works the same as IPC_MBOPEN except that it will works even if
|
||||
** IPC_MBBLOCK has been set to 1
|
||||
*/
|
||||
|
||||
#define IPC_GET_SHUFFLE 250
|
||||
/* (requires Winamp 2.4+)
|
||||
** val=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GET_SHUFFLE);
|
||||
**
|
||||
** IPC_GET_SHUFFLE returns the status of the Shuffle option (1 if set)
|
||||
*/
|
||||
|
||||
#define IPC_GET_REPEAT 251
|
||||
/* (requires Winamp 2.4+)
|
||||
** val=SendMessageW(hwnd_winamp,WM_WA_IPC,0,IPC_GET_REPEAT);
|
||||
**
|
||||
** IPC_GET_REPEAT returns the status of the Repeat option (1 if set)
|
||||
*/
|
||||
|
||||
#define IPC_SET_SHUFFLE 252
|
||||
/* (requires Winamp 2.4+)
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,value,IPC_SET_SHUFFLE);
|
||||
**
|
||||
** IPC_SET_SHUFFLE sets the status of the Shuffle option (1 to turn it on)
|
||||
*/
|
||||
|
||||
#define IPC_SET_REPEAT 253
|
||||
/* (requires Winamp 2.4+)
|
||||
** SendMessageW(hwnd_winamp,WM_WA_IPC,value,IPC_SET_REPEAT);
|
||||
**
|
||||
** IPC_SET_REPEAT sets the status of the Repeat option (1 to turn it on)
|
||||
*/
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
/*
|
||||
** Some API calls tend to require that you send data via WM_COPYDATA
|
||||
** instead of WM_USER. Such as IPC_PLAYFILE:
|
||||
*/
|
||||
|
||||
#define IPC_PLAYFILE 100
|
||||
|
||||
/*
|
||||
** COPYDATASTRUCT cds;
|
||||
** cds.dwData = IPC_PLAYFILE;
|
||||
** cds.lpData = (void *) "file.mp3";
|
||||
** cds.cbData = strlen((char *) cds.lpData)+1; // include space for null char
|
||||
** SendMessageW(hwnd_winamp,WM_COPYDATA,(WPARAM)NULL,(LPARAM)&cds);
|
||||
**
|
||||
** This will play the file "file.mp3".
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#define IPC_CHDIR 103
|
||||
|
||||
/*
|
||||
** COPYDATASTRUCT cds;
|
||||
** cds.dwData = IPC_CHDIR;
|
||||
** cds.lpData = (void *) "c:\\download";
|
||||
** cds.cbData = strlen((char *) cds.lpData)+1; // include space for null char
|
||||
** SendMessageW(hwnd_winamp,WM_COPYDATA,(WPARAM)NULL,(LPARAM)&cds);
|
||||
**
|
||||
** This will make Winamp change to the directory C:\\download
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
/*
|
||||
** Finally there are some WM_COMMAND messages that you can use to send
|
||||
** Winamp misc commands.
|
||||
**
|
||||
** To send these, use:
|
||||
**
|
||||
** SendMessageW(hwnd_winamp, WM_COMMAND,command_name,0);
|
||||
*/
|
||||
|
||||
#define WINAMP_OPTIONS_EQ 40036 // toggles the EQ window
|
||||
#define WINAMP_OPTIONS_PLEDIT 40040 // toggles the playlist window
|
||||
#define WINAMP_VOLUMEUP 40058 // turns the volume up a little
|
||||
#define WINAMP_VOLUMEDOWN 40059 // turns the volume down a little
|
||||
#define WINAMP_FFWD5S 40060 // fast forwards 5 seconds
|
||||
#define WINAMP_REW5S 40061 // rewinds 5 seconds
|
||||
|
||||
// the following are the five main control buttons, with optionally shift
|
||||
// or control pressed
|
||||
// (for the exact functions of each, just try it out)
|
||||
#define WINAMP_BUTTON1 40044
|
||||
#define WINAMP_BUTTON2 40045
|
||||
#define WINAMP_BUTTON3 40046
|
||||
#define WINAMP_BUTTON4 40047
|
||||
#define WINAMP_BUTTON5 40048
|
||||
#define WINAMP_BUTTON1_SHIFT 40144
|
||||
#define WINAMP_BUTTON2_SHIFT 40145
|
||||
#define WINAMP_BUTTON3_SHIFT 40146
|
||||
#define WINAMP_BUTTON4_SHIFT 40147
|
||||
#define WINAMP_BUTTON5_SHIFT 40148
|
||||
#define WINAMP_BUTTON1_CTRL 40154
|
||||
#define WINAMP_BUTTON2_CTRL 40155
|
||||
#define WINAMP_BUTTON3_CTRL 40156
|
||||
#define WINAMP_BUTTON4_CTRL 40157
|
||||
#define WINAMP_BUTTON5_CTRL 40158
|
||||
|
||||
#define WINAMP_FILE_PLAY 40029 // pops up the load file(s) box
|
||||
#define WINAMP_FILE_DIR 40187 // pops up the load directory box
|
||||
#define WINAMP_OPTIONS_PREFS 40012 // pops up the preferences
|
||||
#define WINAMP_OPTIONS_AOT 40019 // toggles always on top
|
||||
#define WINAMP_HELP_ABOUT 40041 // pops up the about box :)
|
||||
|
||||
#define ID_MAIN_PLAY_AUDIOCD1 40323 // starts playing the audio CD in the first CD reader
|
||||
#define ID_MAIN_PLAY_AUDIOCD2 40323 // plays the 2nd
|
||||
#define ID_MAIN_PLAY_AUDIOCD3 40323 // plays the 3nd
|
||||
#define ID_MAIN_PLAY_AUDIOCD4 40323 // plays the 4nd
|
||||
|
||||
// IDs 42000 to 45000 are reserved for gen_ff
|
||||
// IDs from 45000 to 57000 are reserved for library
|
||||
|
||||
/*
|
||||
** EOF.. Enjoy.
|
||||
*/
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "main.h"
|
||||
#include "FeedBase.h"
|
||||
#include <assert.h>
|
||||
|
||||
void FeedBase::dependent_regViewer(api_dependentviewer *viewer, int add)
|
||||
{
|
||||
if (viewer)
|
||||
{
|
||||
if (add)
|
||||
{
|
||||
//if (!viewers.contains(viewer))
|
||||
if(viewers.end() == std::find(viewers.begin(), viewers.end(), viewer))
|
||||
{
|
||||
viewers.push_back(viewer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//viewers.eraseObject(viewer);
|
||||
auto it = std::find(viewers.begin(), viewers.end(), viewer);
|
||||
if (it != viewers.end())
|
||||
{
|
||||
viewers.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *FeedBase::dependent_getInterface(const GUID *classguid)
|
||||
{
|
||||
HANDLEGETINTERFACE(svc_textFeed);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
api_dependent *FeedBase::getDependencyPtr()
|
||||
{
|
||||
return static_cast<api_dependent *>(this);
|
||||
}
|
||||
|
||||
void FeedBase::CallViewers( const wchar_t *feedid, const wchar_t *text, size_t length )
|
||||
{
|
||||
for ( api_dependentviewer *l_viewer : viewers )
|
||||
l_viewer->dependentViewer_callback( static_cast<api_dependent *>( this ), svc_textFeed::depend_getClassGuid(), DependentCB::DEPCB_EVENT, Event_TEXTCHANGE, (intptr_t)feedid, (void *)text, length );
|
||||
}
|
||||
|
||||
#ifdef CBCLASS
|
||||
#undef CBCLASS
|
||||
#endif
|
||||
|
||||
#define CBCLASS FeedBase
|
||||
START_MULTIPATCH;
|
||||
START_PATCH(DependentPatch)
|
||||
M_VCB(DependentPatch, api_dependent, API_DEPENDENT_REGVIEWER, dependent_regViewer);
|
||||
M_CB(DependentPatch, api_dependent, API_DEPENDENT_GETINTERFACE, dependent_getInterface);
|
||||
NEXT_PATCH(TextFeedPatch)
|
||||
M_CB(TextFeedPatch, svc_textFeed, SVCTEXTFEED_HASFEED, hasFeed);
|
||||
M_CB(TextFeedPatch, svc_textFeed, SVCTEXTFEED_GETFEEDTEXT, getFeedText);
|
||||
M_CB(TextFeedPatch, svc_textFeed, SVCTEXTFEED_GETFEEDDESC, getFeedDescription);
|
||||
M_CB(TextFeedPatch, svc_textFeed, SVCTEXTFEED_GETDEPENDENCYPTR, getDependencyPtr);
|
||||
END_PATCH
|
||||
END_MULTIPATCH;
|
||||
#undef CBCLASS
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef NULLSOFT_WINAMP_FEEDBASE_H
|
||||
#define NULLSOFT_WINAMP_FEEDBASE_H
|
||||
|
||||
#include <api/dependency/api_dependent.h>
|
||||
#include <api/skin/feeds/api_textfeed.h>
|
||||
#include <vector>
|
||||
#include <bfc/multipatch.h>
|
||||
|
||||
enum {DependentPatch = 10, TextFeedPatch = 20 };
|
||||
|
||||
class FeedBase
|
||||
: public MultiPatch<DependentPatch, api_dependent>,
|
||||
public MultiPatch<TextFeedPatch, svc_textFeed>
|
||||
{
|
||||
private:
|
||||
void dependent_regViewer(api_dependentviewer *viewer, int add);
|
||||
void *dependent_getInterface(const GUID *classguid);
|
||||
|
||||
virtual int hasFeed(const wchar_t *name)=0;
|
||||
virtual const wchar_t *getFeedText(const wchar_t *name)=0;
|
||||
virtual const wchar_t *getFeedDescription(const wchar_t *name)=0;
|
||||
api_dependent *getDependencyPtr();
|
||||
protected:
|
||||
void CallViewers(const wchar_t *feedid, const wchar_t *text, size_t length);
|
||||
|
||||
protected:
|
||||
std::vector<api_dependentviewer*> viewers;
|
||||
|
||||
protected:
|
||||
RECVS_MULTIPATCH;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
||||
#include "main.h"
|
||||
#include "attributes.h"
|
||||
|
||||
_float::_float()
|
||||
{
|
||||
value = 0;
|
||||
}
|
||||
|
||||
_float::_float(float defaultValue)
|
||||
{
|
||||
value = defaultValue;
|
||||
}
|
||||
|
||||
intptr_t _float::operator =(intptr_t uintValue)
|
||||
{
|
||||
value = static_cast<float>(uintValue);
|
||||
return static_cast<intptr_t>(value);
|
||||
}
|
||||
|
||||
float _float::operator =(float uintValue)
|
||||
{
|
||||
value = uintValue;
|
||||
return value;
|
||||
}
|
||||
|
||||
#define CBCLASS _float
|
||||
START_DISPATCH;
|
||||
CB(IFC_CONFIGITEM_GETINT, GetInt)
|
||||
CB(IFC_CONFIGITEM_GETFLOAT, GetFloat)
|
||||
END_DISPATCH;
|
||||
@@ -0,0 +1,86 @@
|
||||
#ifndef NULLSOFT_WINAMP_GEN_H
|
||||
#define NULLSOFT_WINAMP_GEN_H
|
||||
// General Purpose plugin interface
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
typedef struct {
|
||||
int version;
|
||||
char* description;
|
||||
int(__cdecl* init)();
|
||||
void(__cdecl* config)();
|
||||
void(__cdecl* quit)();
|
||||
HWND hwndParent;
|
||||
HINSTANCE hDllInstance;
|
||||
} winampGeneralPurposePlugin;
|
||||
|
||||
// return values from the init(..) which determines if Winamp will continue loading
|
||||
// and handling the plugin or if it will disregard the load attempt. If GEN_INIT_FAILURE
|
||||
// is returned then the plugin will be listed as [NOT LOADED] on the plug-in prefs page.
|
||||
#define GEN_INIT_SUCCESS 0
|
||||
#define GEN_INIT_FAILURE 1
|
||||
|
||||
#define GPPHDR_VER 0x10
|
||||
|
||||
// added 5.64+
|
||||
#define GPPHDR_VER_U 0x11
|
||||
// specify GPPHDR_VER_U if you want to provide a unicode (wchar_t*) description and only work on 5.64+
|
||||
// specify GPPHDR_VER to use the original (char*) description as before
|
||||
// note: we are using the fact that sizeof(char*) == sizeof(wchar_t*) to be able to allow this
|
||||
// so when using GPPHDR_VER_U you will need to cast description to (wchar_t*) to set
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
typedef winampGeneralPurposePlugin* (__cdecl* winampGeneralPurposePluginGetter)();
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// These are the return values to be used with the uninstall plugin export function:
|
||||
// __declspec(dllexport) int __cdecl winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param)
|
||||
// which determines if Winamp can uninstall the plugin immediately or on winamp restart.
|
||||
// If this is not exported then Winamp will assume an uninstall with reboot is the only way.
|
||||
//
|
||||
#define GEN_PLUGIN_UNINSTALL_NOW 0x1
|
||||
#define GEN_PLUGIN_UNINSTALL_REBOOT 0x0
|
||||
//
|
||||
// Uninstall support was added from 5.0+ and uninstall now support from 5.5+ though note
|
||||
// that it is down to you to ensure that if uninstall now is returned that it will not
|
||||
// cause a crash i.e. don't use if you've been subclassing the main window.
|
||||
//
|
||||
// The HWND passed in the calling of winampUninstallPlugin(..) is the preference page HWND.
|
||||
//
|
||||
// The following is a psuedo example of using winampUninstallPlugin(..) which shows its usage:
|
||||
//
|
||||
//
|
||||
// // use this as a control on saving settings as quit(..) will be called afterwards
|
||||
// int no_uninstall = 1;
|
||||
// __declspec(dllexport) int __cdecl winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param){
|
||||
// // prompt to remove our settings with default as no (just incase)
|
||||
// if(MessageBox(hwndDlg,"Do you also want to remove the saved settings for this plugin?",
|
||||
// plugin.description,MB_YESNO|MB_DEFBUTTON2) == IDYES)
|
||||
// {
|
||||
// // PLUGIN_NAME is the name of the section you save settings into
|
||||
// // and this call will make the OS remove the setion passed
|
||||
// WritePrivateProfileString(PLUGIN_NAME,0,0,ini_file);
|
||||
// no_uninstall = 0;
|
||||
// }
|
||||
// // as we're doing too much in subclasses, etc we cannot allow for on-the-fly removal so need to do a normal reboot
|
||||
// return GEN_PLUGIN_UNINSTALL_REBOOT;
|
||||
// }
|
||||
//
|
||||
|
||||
// For a general purpose plugin to be correctly detected by Winamp you need to ensure that
|
||||
// the exported winampGetGeneralPurposePlugin(..) is exported as an undecorated function
|
||||
// e.g.
|
||||
// #ifdef __cplusplus
|
||||
// extern "C" {
|
||||
// #endif
|
||||
// __declspec(dllexport) winampGeneralPurposePlugin * __cdecl winampGetGeneralPurposePlugin(){ return &plugin; }
|
||||
// #ifdef __cplusplus
|
||||
// }
|
||||
// #endif
|
||||
//
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,226 @@
|
||||
#include "GammaFilter.h"
|
||||
#include "api.h"
|
||||
|
||||
int GammaFilter::filterBitmap(uint8_t *bits, int w, int h, int bpp, const wchar_t *element_id, const wchar_t *forcegroup)
|
||||
{
|
||||
int r = 0, g = 0, b = 0;
|
||||
int gray = 0;
|
||||
int boost = 0;
|
||||
|
||||
const wchar_t *gammagroup;
|
||||
|
||||
if (forcegroup && *forcegroup)
|
||||
gammagroup = forcegroup;
|
||||
else
|
||||
gammagroup = WASABI_API_PALETTE->getGammaGroupFromId(element_id);
|
||||
|
||||
WASABI_API_COLORTHEMES->getGammaForGroup(gammagroup, &r, &g, &b, &gray, &boost);
|
||||
|
||||
if (!r && !g && !b && !gray && !boost) return 1;
|
||||
|
||||
if (bpp != 32) return 0;
|
||||
|
||||
int *p;
|
||||
int l = w * h;
|
||||
int c;
|
||||
|
||||
if (gray == 1)
|
||||
{
|
||||
int r, g, b;
|
||||
p = (int *)bits;
|
||||
while (l--)
|
||||
{
|
||||
r = (*p & 0xff0000) >> 16;
|
||||
g = (*p & 0xff00) >> 8;
|
||||
b = (*p & 0xff);
|
||||
c = MAX(MAX(r, g), b);
|
||||
c = (c << 16) | (c << 8) | c;
|
||||
*p = (*p & 0xff000000) | c;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
if (gray == 2)
|
||||
{
|
||||
int r, g, b;
|
||||
p = (int *)bits;
|
||||
while (l--)
|
||||
{
|
||||
r = (*p & 0xff0000) >> 16;
|
||||
g = (*p & 0xff00) >> 8;
|
||||
b = (*p & 0xff);
|
||||
c = (r + g + b) / 3;
|
||||
c = (c << 16) | (c << 8) | c;
|
||||
*p = (*p & 0xff000000) | c;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
if (boost)
|
||||
{
|
||||
l = w * h;
|
||||
int r, g, b, a;
|
||||
p = (int *)bits;
|
||||
while (l--)
|
||||
{
|
||||
a = (*p & 0xff000000) >> 25;
|
||||
r = ((*p & 0xff0000) >> 17) + a;
|
||||
g = ((*p & 0xff00) >> 9) + a;
|
||||
b = ((*p & 0xff) >> 1) + a;
|
||||
*p = (*p & 0xff000000) | (r << 16) | (g << 8) | b;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
int rm = 65535 + (r << 4);
|
||||
int gm = 65535 + (g << 4);
|
||||
int bm = 65535 + (b << 4);
|
||||
|
||||
l = w * h;
|
||||
|
||||
p = (int *)bits;
|
||||
while (l--)
|
||||
{
|
||||
r = ((((*p & 0xff0000) >> 16) * rm)) & 0xffff0000;
|
||||
c = MAX(0, MIN(r, 0xFF0000));
|
||||
r = ((((*p & 0xff00) >> 8) * gm) >> 8) & 0xffff00;
|
||||
c |= MAX(0, MIN(r, 0xFF00));
|
||||
r = (((*p & 0xff) * bm) >> 16) & 0xffff;
|
||||
c |= MAX(0, MIN(r, 0xFF));
|
||||
c = (c & 0xFFFFFF) | (*p & 0xFF000000);
|
||||
*p = c;
|
||||
p++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
ARGB32 GammaFilter::filterColor(ARGB32 color, const wchar_t *element_id, const wchar_t *forcegroup)
|
||||
{
|
||||
int r = 0, g = 0, b = 0, gray = 0, boost = 0;
|
||||
|
||||
const wchar_t *gammagroup;
|
||||
if (forcegroup && *forcegroup)
|
||||
gammagroup = forcegroup;
|
||||
else
|
||||
gammagroup = WASABI_API_PALETTE->getGammaGroupFromId(element_id);
|
||||
|
||||
WASABI_API_COLORTHEMES->getGammaForGroup(gammagroup, &r, &g, &b, &gray, &boost);
|
||||
|
||||
if (!r && !g && !b && !gray && !boost) return color;
|
||||
|
||||
ARGB32 c;
|
||||
|
||||
if (gray == 1)
|
||||
{
|
||||
int r, g, b;
|
||||
r = (color & 0xff0000) >> 16;
|
||||
g = (color & 0xff00) >> 8;
|
||||
b = (color & 0xff);
|
||||
c = MAX(MAX(r, g), b);
|
||||
c = (c << 16) | (c << 8) | c;
|
||||
color = (color & 0xff000000) | c;
|
||||
}
|
||||
|
||||
if (gray == 2)
|
||||
{
|
||||
int r, g, b;
|
||||
r = (color & 0xff0000) >> 16;
|
||||
g = (color & 0xff00) >> 8;
|
||||
b = (color & 0xff);
|
||||
c = (r + g + b) / 3;
|
||||
c = (c << 16) | (c << 8) | c;
|
||||
color = (color & 0xff000000) | c;
|
||||
}
|
||||
|
||||
if (boost)
|
||||
{
|
||||
int r, g, b;
|
||||
r = ((color & 0xff0000) >> 17) + 0x80;
|
||||
g = ((color & 0xff00) >> 9) + 0x80;
|
||||
b = ((color & 0xff) >> 1) + 0x80;
|
||||
color = (color & 0xff000000) | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
|
||||
int bm = 65536 + (r << 4);
|
||||
int gm = 65536 + (g << 4);
|
||||
int rm = 65536 + (b << 4);
|
||||
|
||||
r = ((((color & 0xff0000) >> 16) * rm)) & 0xffff0000;
|
||||
c = MAX(0, MIN(r, 0xFF0000));
|
||||
r = ((((color & 0xff00) >> 8) * gm) >> 8) & 0xffff00;
|
||||
c |= MAX(0, MIN(r, 0xFF00));
|
||||
r = (((color & 0xff) * bm) >> 16) & 0xffff;
|
||||
c |= MAX(0, MIN(r, 0xFF));
|
||||
c = (c & 0xFFFFFF) | (color & 0xFF000000);
|
||||
return c;
|
||||
}
|
||||
|
||||
#define CBCLASS GammaFilter
|
||||
START_DISPATCH;
|
||||
CB(FILTERBITMAP, filterBitmap);
|
||||
CB(FILTERCOLOR, filterColor);
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
|
||||
|
||||
static GammaFilter gammaFilterService;
|
||||
// {B092B4BD-32E1-4c35-B4AE-90B34565D9D6}
|
||||
static const GUID gammaFilterGUID =
|
||||
{ 0xb092b4bd, 0x32e1, 0x4c35, { 0xb4, 0xae, 0x90, 0xb3, 0x45, 0x65, 0xd9, 0xd6 } };
|
||||
|
||||
FOURCC GammaFilterFactory::GetServiceType()
|
||||
{
|
||||
return gammaFilterService.getServiceType();
|
||||
}
|
||||
|
||||
const char *GammaFilterFactory::GetServiceName()
|
||||
{
|
||||
return gammaFilterService.getServiceName();
|
||||
}
|
||||
|
||||
GUID GammaFilterFactory::GetGUID()
|
||||
{
|
||||
return gammaFilterGUID;
|
||||
}
|
||||
|
||||
void *GammaFilterFactory::GetInterface(int global_lock)
|
||||
{
|
||||
// if (global_lock)
|
||||
// WASABI_API_SVC->service_lock(this, (void *)ifc);
|
||||
return &gammaFilterService;
|
||||
}
|
||||
|
||||
int GammaFilterFactory::SupportNonLockingInterface()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GammaFilterFactory::ReleaseInterface(void *ifc)
|
||||
{
|
||||
//WASABI_API_SVC->service_unlock(ifc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *GammaFilterFactory::GetTestString()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GammaFilterFactory::ServiceNotify(int msg, int param1, int param2)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define CBCLASS GammaFilterFactory
|
||||
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
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include <api/service/svcs/svc_skinfilter.h>
|
||||
#include <api/service/waservicefactory.h>
|
||||
class GammaFilter : public svc_skinFilter
|
||||
{
|
||||
public:
|
||||
int filterBitmap(uint8_t *bits, int w, int h, int bpp, const wchar_t *element_id, const wchar_t *forcegroup=NULL);
|
||||
ARGB32 filterColor(ARGB32 color, const wchar_t *element_id, const wchar_t *forcegroup=NULL);
|
||||
static const char *getServiceName() { return "Gamma skin filter"; }
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
||||
|
||||
class GammaFilterFactory : 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;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,361 @@
|
||||
#include "GammaManagerAPI.h"
|
||||
#include "api.h"
|
||||
#include <api/syscb/callbacks/skincb.h>
|
||||
|
||||
GammaManagerAPI::GammaManagerAPI()
|
||||
{
|
||||
curSetSel = NULL;
|
||||
inTransaction=0;
|
||||
}
|
||||
|
||||
void GammaManagerAPI::StartTransaction()
|
||||
{
|
||||
inTransaction++;
|
||||
}
|
||||
|
||||
void GammaManagerAPI::EndTransaction()
|
||||
{
|
||||
inTransaction--;
|
||||
if (inTransaction == 0)
|
||||
WASABI_API_SYSCB->syscb_issueCallback(SysCallback::SKINCB, SkinCallback::COLORTHEMESLISTCHANGED);
|
||||
}
|
||||
|
||||
size_t GammaManagerAPI::getNumGammaSets()
|
||||
{
|
||||
return gammasets.size();
|
||||
}
|
||||
|
||||
const wchar_t *GammaManagerAPI::enumGammaSet(size_t n)
|
||||
{
|
||||
return gammasets[n]->name;
|
||||
}
|
||||
|
||||
int GammaManagerAPI::getNumGammaGroups(const wchar_t *gammaset)
|
||||
{
|
||||
if (gammaset == NULL || !*gammaset) return 0;
|
||||
for (size_t i = 0;i != gammasets.size();i++)
|
||||
{
|
||||
if (IsKeyword(gammasets[i]->name, gammaset))
|
||||
return (int)gammasets[i]->gammagroups.size();
|
||||
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
const wchar_t *GammaManagerAPI::enumGammaGroup(const wchar_t *gammaset, int n)
|
||||
{
|
||||
if (gammaset == NULL || !*gammaset) return 0;
|
||||
for (size_t i = 0;i != gammasets.size();i++)
|
||||
{
|
||||
if (IsKeyword(gammaset, gammasets[i]->name))
|
||||
{
|
||||
if (n < 0 || n >= (int)gammasets[i]->gammagroups.size())
|
||||
{
|
||||
return gammasets[i]->generalgroup.getName();
|
||||
}
|
||||
const wchar_t * ret = gammasets[i]->gammagroups[n]->getName();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ColorThemeGroup *GammaManagerAPI::enumColorThemeGroup(int colorset, int colorgroup)
|
||||
{
|
||||
GammaSet *set = gammasets[colorset];
|
||||
if (set != NULL)
|
||||
{
|
||||
if (colorgroup < 0 || colorgroup >= (int)set->gammagroups.size())
|
||||
{
|
||||
return &set->generalgroup;
|
||||
}
|
||||
ColorThemeGroup *grp = set->gammagroups[colorgroup];
|
||||
return grp;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ColorThemeGroup *GammaManagerAPI::getColorThemeGroup(const wchar_t *colorset, const wchar_t *colorgroup)
|
||||
{
|
||||
for (size_t i = 0;i < gammasets.size();i++)
|
||||
{
|
||||
GammaSet *s = gammasets[i];
|
||||
if (IsKeyword(s->name, colorset))
|
||||
{
|
||||
if (IsKeyword(s->generalgroup.getName(), colorgroup))
|
||||
{
|
||||
ColorThemeGroupI *g = &s->generalgroup;
|
||||
return g;
|
||||
}
|
||||
for (size_t j = 0;j < s->gammagroups.size();j++)
|
||||
{
|
||||
ColorThemeGroupI *g = s->gammagroups[j];
|
||||
if (IsKeyword(g->getName(), colorgroup))
|
||||
{
|
||||
return g;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void GammaManagerAPI::deleteAllGammaSets()
|
||||
{
|
||||
//gammasets.deleteAll();
|
||||
for (auto obj : gammasets)
|
||||
{
|
||||
delete obj;
|
||||
}
|
||||
gammasets.clear();
|
||||
|
||||
curSetSel = NULL;
|
||||
}
|
||||
|
||||
void GammaManagerAPI::deleteGammaSet(const wchar_t *set)
|
||||
{
|
||||
for (size_t i = 0;i < gammasets.size();i++)
|
||||
{
|
||||
if (IsKeyword(gammasets[i]->name, set))
|
||||
{
|
||||
GammaSet *s = gammasets[i];
|
||||
delete s;
|
||||
gammasets.erase(gammasets.begin() + i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
if (!inTransaction)
|
||||
WASABI_API_SYSCB->syscb_issueCallback(SysCallback::SKINCB, SkinCallback::COLORTHEMESLISTCHANGED);
|
||||
}
|
||||
|
||||
void GammaManagerAPI::renameGammaSet( const wchar_t *set, const wchar_t *newname )
|
||||
{
|
||||
for ( GammaSet *l_gammaset : gammasets )
|
||||
{
|
||||
if ( IsKeyword( l_gammaset->name, set ) )
|
||||
{
|
||||
l_gammaset->SetName( newname );
|
||||
if ( !inTransaction )
|
||||
WASABI_API_SYSCB->syscb_issueCallback( SysCallback::SKINCB, SkinCallback::COLORTHEMESLISTCHANGED );
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t GammaManagerAPI::newGammaSet(const wchar_t *set)
|
||||
{
|
||||
for (size_t i = 0;i != gammasets.size();i++)
|
||||
{
|
||||
if (IsKeyword(gammasets[i]->name, set))
|
||||
return i;
|
||||
}
|
||||
|
||||
GammaSet *curset = new GammaSet(set);/*
|
||||
for (size_t i = 0;i < gammasets.size();i++)
|
||||
{
|
||||
for (size_t j = 0;j < gammasets[i]->gammagroups.size();j++)
|
||||
{
|
||||
ColorThemeGroup * g = gammasets[i]->gammagroups[j];
|
||||
if (curset->haveGroup(g->getName()))
|
||||
continue;
|
||||
curset->gammagroups.push_back(new ColorThemeGroupI(g->getName(), 0, 0, 0, 0, 0));
|
||||
}
|
||||
}*/
|
||||
size_t index = gammasets.size();
|
||||
gammasets.push_back(curset); //Martin> better add set after the loop than before
|
||||
if (!inTransaction)
|
||||
WASABI_API_SYSCB->syscb_issueCallback(SysCallback::SKINCB, SkinCallback::COLORTHEMESLISTCHANGED);
|
||||
return index;
|
||||
}
|
||||
|
||||
void GammaManagerAPI::updateGammaSet(const wchar_t *set)
|
||||
{
|
||||
for (size_t i = 0;i < gammasets.size();i++)
|
||||
{
|
||||
GammaSet *s = gammasets[i];
|
||||
if (IsKeyword(s->name, set))
|
||||
{
|
||||
for (size_t i = 0;i < gammasets.size();i++)
|
||||
{
|
||||
for (size_t j = 0;j < gammasets[i]->gammagroups.size();j++)
|
||||
{
|
||||
ColorThemeGroup * g = gammasets[i]->gammagroups[j];
|
||||
if (s->haveGroup(g->getName())) continue;
|
||||
s->gammagroups.push_back(new ColorThemeGroupI(g->getName(), 0, 0, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GammaManagerAPI::setGammaSet(const wchar_t *set)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0;i != gammasets.size();i++)
|
||||
{
|
||||
if (IsKeyword(gammasets[i]->name, set))
|
||||
{
|
||||
setGammaSetInternal(gammasets[i]);
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
if (i) // i will still be 0 if getNumItems() was 0
|
||||
setGammaSetInternal(gammasets[0]);
|
||||
}
|
||||
|
||||
void GammaManagerAPI::setGammaSetInternal(GammaSet *set)
|
||||
{
|
||||
//if (curSetSel == set) return;
|
||||
curSetSel = set;
|
||||
|
||||
//PORT
|
||||
#ifdef WIN32
|
||||
SetCursor(LoadCursor(NULL, IDC_WAIT));
|
||||
#endif
|
||||
#ifdef LINUX
|
||||
XDefineCursor( Linux::getDisplay(), WASABI_API_WND->main_getRootWnd()->gethWnd(),
|
||||
XCreateFontCursor( Linux::getDisplay(), XC_watch ) );
|
||||
#endif
|
||||
|
||||
if (WASABI_API_SKIN)
|
||||
WASABI_API_SKIN->reapplySkinFilters();
|
||||
//PORT
|
||||
#ifdef WIN32
|
||||
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
||||
#endif
|
||||
#ifdef LINUX
|
||||
XUndefineCursor( Linux::getDisplay(), WASABI_API_WND->main_getRootWnd()->gethWnd() );
|
||||
#endif
|
||||
WASABI_API_SYSCB->syscb_issueCallback(SysCallback::SKINCB, SkinCallback::COLORTHEMECHANGED);
|
||||
}
|
||||
|
||||
int GammaManagerAPI::getGammaForGroup(const wchar_t *group, int *r, int *g, int *b, int *gray, int *boost)
|
||||
{
|
||||
if (curSetSel)
|
||||
{
|
||||
size_t l = curSetSel->gammagroups.size();
|
||||
for (size_t i = 0;i < l;i++)
|
||||
{
|
||||
if (group && IsKeyword(group, curSetSel->gammagroups[i]->getName()))
|
||||
{
|
||||
*r = min(4095, max( -4095, curSetSel->gammagroups[i]->getRed() + curSetSel->generalgroup.getRed()));
|
||||
*g = min(4095, max( -4095, curSetSel->gammagroups[i]->getGreen() + curSetSel->generalgroup.getGreen()));
|
||||
*b = min(4095, max( -4095, curSetSel->gammagroups[i]->getBlue() + curSetSel->generalgroup.getBlue()));
|
||||
*gray = curSetSel->gammagroups[i]->getGray() | curSetSel->generalgroup.getGray();
|
||||
*boost = curSetSel->gammagroups[i]->getBoost() || curSetSel->generalgroup.getBoost();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
*r = min(4095, max( -4095, curSetSel->generalgroup.getRed()));
|
||||
*g = min(4095, max( -4095, curSetSel->generalgroup.getGreen()));
|
||||
*b = min(4095, max( -4095, curSetSel->generalgroup.getBlue()));
|
||||
*gray = curSetSel->generalgroup.getGray();
|
||||
*boost = curSetSel->generalgroup.getBoost();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GammaManagerAPI::resetGammaSet( const wchar_t *set )
|
||||
{
|
||||
for ( GammaSet *l_gammaset : gammasets )
|
||||
{
|
||||
if ( IsKeyword( l_gammaset->name, set ) )
|
||||
{
|
||||
//gammasets[i]->gammagroups.deleteAll();
|
||||
for ( ColorThemeGroupI *obj : l_gammaset->gammagroups )
|
||||
delete obj;
|
||||
|
||||
l_gammaset->gammagroups.clear();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GammaManagerAPI::addGammaGroup( const wchar_t *set, ColorThemeGroup *group )
|
||||
{
|
||||
for ( GammaSet *l_gammaset : gammasets )
|
||||
{
|
||||
if ( IsKeyword( l_gammaset->name, set ) )
|
||||
{
|
||||
for ( size_t j = 0; j < l_gammaset->gammagroups.size(); j++ )
|
||||
{
|
||||
ColorThemeGroupI *g = l_gammaset->gammagroups[ j ];
|
||||
if ( IsKeyword( g->getName(), group->getName() ) )
|
||||
{
|
||||
l_gammaset->gammagroups[ j ] = new ColorThemeGroupI( *group );
|
||||
delete g;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
l_gammaset->gammagroups.push_back( new ColorThemeGroupI( *group ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GammaManagerAPI::addGammaGroup2(size_t i, ColorThemeGroup *group)
|
||||
{
|
||||
for (size_t j = 0;j < gammasets[i]->gammagroups.size();j++)
|
||||
{
|
||||
ColorThemeGroupI * g = gammasets[i]->gammagroups[j];
|
||||
if (IsKeyword(g->getName(), group->getName()))
|
||||
{
|
||||
gammasets[i]->gammagroups[j] = new ColorThemeGroupI(*group);
|
||||
delete g;
|
||||
return;
|
||||
}
|
||||
}
|
||||
gammasets[i]->gammagroups.push_back(new ColorThemeGroupI(*group));
|
||||
}
|
||||
|
||||
const wchar_t *GammaManagerAPI::getGammaSet()
|
||||
{
|
||||
return curSetSel ? curSetSel->name : NULL;
|
||||
}
|
||||
|
||||
#define CBCLASS ColorThemeGroupI
|
||||
START_DISPATCH;
|
||||
CB(COLORTHEMEGROUPGETNAME, getName);
|
||||
CB(COLORTHEMEGROUPGETRED, getRed);
|
||||
CB(COLORTHEMEGROUPGETGREEN, getGreen);
|
||||
CB(COLORTHEMEGROUPGETBLUE, getBlue);
|
||||
CB(COLORTHEMEGROUPGETGRAY, getGray);
|
||||
CB(COLORTHEMEGROUPGETBOOST, getBoost);
|
||||
VCB(COLORTHEMEGROUPSETNAME, setName);
|
||||
VCB(COLORTHEMEGROUPSETRED, setRed);
|
||||
VCB(COLORTHEMEGROUPSETGREEN, setGreen);
|
||||
VCB(COLORTHEMEGROUPSETBLUE, setBlue);
|
||||
VCB(COLORTHEMEGROUPSETGRAY, setGray);
|
||||
VCB(COLORTHEMEGROUPSETBOOST, setBoost);
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
|
||||
#define CBCLASS GammaManagerAPI
|
||||
START_DISPATCH;
|
||||
CB(API_COLORTHEMES_GETNUMGAMMASETS, getNumGammaSets);
|
||||
CB(API_COLORTHEMES_ENUMGAMMASET, enumGammaSet);
|
||||
VCB(API_COLORTHEMES_DELETEGAMMASET, deleteGammaSet);
|
||||
VCB(API_COLORTHEMES_DELETEALLGAMMASETS, deleteAllGammaSets);
|
||||
VCB(API_COLORTHEMES_RESETGAMMASET, resetGammaSet);
|
||||
VCB(API_COLORTHEMES_RENAMEGAMMASET, renameGammaSet);
|
||||
CB(API_COLORTHEMES_NEWGAMMASET, newGammaSet);
|
||||
VCB(API_COLORTHEMES_UPDATEGAMMASET, updateGammaSet);
|
||||
CB(API_COLORTHEMES_GETNUMGAMMAGROUPS, getNumGammaGroups);
|
||||
CB(API_COLORTHEMES_ENUMGAMMAGROUP, enumGammaGroup);
|
||||
CB(API_COLORTHEMES_ENUMCOLORTHEMEGROUP, enumColorThemeGroup);
|
||||
CB(API_COLORTHEMES_GETCOLORTHEMEGROUP, getColorThemeGroup);
|
||||
CB(API_COLORTHEMES_GETGAMMAFORGROUP, getGammaForGroup);
|
||||
VCB(API_COLORTHEMES_ADDGAMMAGROUP, addGammaGroup);
|
||||
VCB(API_COLORTHEMES_ADDGAMMAGROUP2, addGammaGroup2);
|
||||
CB(API_COLORTHEMES_GETGAMMASET, getGammaSet);
|
||||
VCB(API_COLORTHEMES_SETGAMMASET, setGammaSet);
|
||||
VCB(API_COLORTHEMES_STARTTRANSACTION, StartTransaction);
|
||||
VCB(API_COLORTHEMES_ENDTRANSACTION, EndTransaction);
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
@@ -0,0 +1,145 @@
|
||||
#pragma once
|
||||
#include <api/skin/colorthemes.h>
|
||||
#include <api/service/svcs/svc_skinfilter.h>
|
||||
#include <vector>
|
||||
#include <api/skin/api_colorthemes.h>
|
||||
|
||||
class ColorThemeGroupI : public ColorThemeGroup
|
||||
{
|
||||
public:
|
||||
ColorThemeGroupI(const wchar_t *pname, int pred, int pgreen, int pblue, int pgray, int pboost)
|
||||
: name(0), red(pred), green(pgreen), blue(pblue), make_grayscale(pgray), boost_levels(pboost)
|
||||
{
|
||||
name = _wcsdup(pname);
|
||||
}
|
||||
~ColorThemeGroupI()
|
||||
{
|
||||
free(name);
|
||||
}
|
||||
ColorThemeGroupI(ColorThemeGroup ©_group)
|
||||
{
|
||||
name = _wcsdup(copy_group.getName());
|
||||
red = copy_group.getRed();
|
||||
green = copy_group.getGreen();
|
||||
blue = copy_group.getBlue();
|
||||
make_grayscale = copy_group.getGray();
|
||||
boost_levels = copy_group.getBoost();
|
||||
}
|
||||
const wchar_t *getName() { return name; }
|
||||
int getRed() { return red; }
|
||||
int getGreen() { return green; }
|
||||
int getBlue() { return blue; }
|
||||
int getGray() { return make_grayscale; }
|
||||
int getBoost() { return boost_levels; }
|
||||
void setName(const wchar_t *pname) { free(name); name = _wcsdup(pname); }
|
||||
void setRed(int r) { red = r; }
|
||||
void setGreen(int g) { green = g; }
|
||||
void setBlue(int b) { blue = b; }
|
||||
void setGray(int g) { make_grayscale = g; }
|
||||
void setBoost(int b) { boost_levels = b; }
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
|
||||
wchar_t *name;
|
||||
int red;
|
||||
int green;
|
||||
int blue;
|
||||
int make_grayscale;
|
||||
int boost_levels;
|
||||
};
|
||||
|
||||
static bool IsKeyword(const wchar_t *a, const wchar_t *b)
|
||||
{
|
||||
return (CompareStringW(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), NORM_IGNORECASE, a, -1, b, -1) == CSTR_EQUAL);
|
||||
|
||||
}
|
||||
class GammaSet
|
||||
{
|
||||
public:
|
||||
GammaSet( const wchar_t *pname ) : name( 0 ), generalgroup( L"General", 0, 0, 0, 0, 0 )
|
||||
{
|
||||
name = _wcsdup( pname );
|
||||
}
|
||||
|
||||
~GammaSet()
|
||||
{
|
||||
//gammagroups.deleteAll();
|
||||
for ( ColorThemeGroupI *obj : gammagroups )
|
||||
delete obj;
|
||||
|
||||
gammagroups.clear();
|
||||
|
||||
free( name );
|
||||
}
|
||||
|
||||
int haveGroup( const wchar_t *grp )
|
||||
{
|
||||
if ( !grp )
|
||||
return 0;
|
||||
|
||||
for ( ColorThemeGroupI *obj : gammagroups )
|
||||
{
|
||||
if ( IsKeyword( grp, obj->getName() ) )
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SetName( const wchar_t *newname )
|
||||
{
|
||||
free( name );
|
||||
name = _wcsdup( newname );
|
||||
}
|
||||
wchar_t *name;
|
||||
std::vector<ColorThemeGroupI *> gammagroups;
|
||||
ColorThemeGroupI generalgroup;
|
||||
};
|
||||
|
||||
|
||||
class GammaManagerAPI : public api_colorthemes
|
||||
{
|
||||
public:
|
||||
static const char *getServiceName() { return "Color Themes API"; }
|
||||
static const GUID getServiceGuid() { return ColorThemesAPIGUID; }
|
||||
GammaManagerAPI();
|
||||
|
||||
void StartTransaction();
|
||||
void EndTransaction();
|
||||
|
||||
/* Gamma Sets */
|
||||
size_t getNumGammaSets();
|
||||
const wchar_t *enumGammaSet(size_t n);
|
||||
void deleteGammaSet(const wchar_t *set);
|
||||
void deleteAllGammaSets();
|
||||
void resetGammaSet(const wchar_t *set);
|
||||
void renameGammaSet(const wchar_t *set, const wchar_t *newname);
|
||||
size_t newGammaSet(const wchar_t *set); // returns index of your new gamma group
|
||||
void updateGammaSet(const wchar_t *set);
|
||||
|
||||
|
||||
/* Gamma Groups */
|
||||
int getNumGammaGroups(const wchar_t *gammaset);
|
||||
const wchar_t *enumGammaGroup(const wchar_t *gammaset, int n);
|
||||
ColorThemeGroup *enumColorThemeGroup(int colorset, int colorgroup);
|
||||
ColorThemeGroup *getColorThemeGroup(const wchar_t *colorset, const wchar_t *colorgroup);
|
||||
int getGammaForGroup(const wchar_t *group, int *r, int *g, int *b, int *gray, int *boost);
|
||||
void addGammaGroup(const wchar_t *set, ColorThemeGroup *group);
|
||||
void addGammaGroup2(size_t gammaSetIndex, ColorThemeGroup *group);
|
||||
|
||||
/* Active Gamma Set */
|
||||
const wchar_t *getGammaSet();
|
||||
void setGammaSet(const wchar_t *set);
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
|
||||
private:
|
||||
void setGammaSetInternal(GammaSet *set);
|
||||
|
||||
std::vector<GammaSet*> gammasets;
|
||||
GammaSet *curSetSel; // current color theme
|
||||
size_t inTransaction;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
|
||||
** Filename:
|
||||
** Project:
|
||||
** Description: HTML generation from playlist
|
||||
** Author:
|
||||
** Created:
|
||||
**/
|
||||
|
||||
#include "main.h"
|
||||
#include <stdio.h>
|
||||
#include "../nu/AutoChar.h"
|
||||
#include "resource.h"
|
||||
|
||||
void doHtmlPlaylist(void)
|
||||
{
|
||||
FILE *fp = 0;
|
||||
wchar_t filename[MAX_PATH] = {0}, tp[MAX_PATH] = {0};
|
||||
if (!GetTempPathW(MAX_PATH,tp)) StringCchCopyW(tp, MAX_PATH, L".");
|
||||
if (GetTempFileNameW(tp, L"WHT", 0, filename)){
|
||||
DeleteFileW(filename);
|
||||
StringCchCatW(filename, MAX_PATH, L".html");
|
||||
}
|
||||
else StringCchCopyW(filename, MAX_PATH, L"wahtml_tmp.html");
|
||||
|
||||
fp = _wfopen(filename, L"wt");
|
||||
if (!fp)
|
||||
{
|
||||
LPMessageBox(hPLWindow, IDS_HTML_ERROR_WRITE, IDS_ERROR, MB_OK | MB_ICONWARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(fp, "<!DOCTYPE html>\n"
|
||||
"<html lang=\"en\"><head>\n"
|
||||
"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"
|
||||
"<meta name=\"generator\" content=\"Winamp 5.9\">\n"
|
||||
"<style>body{background:#000040;font-family:arial,helvetica;font-size:9pt;font-weight:normal;}"
|
||||
".name{margin-top:-1em;margin-left:15px;font-size:40pt;color:#004080;text-align:left;font-weight:900;}"
|
||||
".name-small{margin-top:-3em;margin-left:140px;font-size:22pt;color:#E1E1E1;text-align:left;}"
|
||||
"table{font-size:9pt;color:#004080;text-align:left;border-width:0px;padding:0px;letter-spacing:normal;}"
|
||||
"hr{border:0;background-color:#FFBF00;height:1px;}"
|
||||
"ol{color:#FFFFFF;font-size:11pt;}"
|
||||
"table{margin-left:15px;color:#409FFF;border-width:0px;}"
|
||||
".val{color:#FFBF00;}"
|
||||
".header{color:#FFBF00;font-size:14pt;}"
|
||||
"</style>\n"
|
||||
"<title>Winamp Generated PlayList</title></head>\n"
|
||||
"<body>"
|
||||
"<div>"
|
||||
"<div class=\"name\"><p>WINAMP</p></div>"
|
||||
"<div class=\"name-small\"><p>playlist</p></div>"
|
||||
"</div>"
|
||||
"<hr><div>\n"
|
||||
"<table><tr><td>\n");
|
||||
|
||||
int x, t = PlayList_getlength(), t_in_pl = 0, n_un = 0;
|
||||
for (x = 0; x < t; x ++)
|
||||
{
|
||||
int a = PlayList_getsonglength(x);
|
||||
if (a >= 0) t_in_pl += a;
|
||||
else n_un++;
|
||||
}
|
||||
if (t != n_un)
|
||||
{
|
||||
int old_t_in_pl=t_in_pl;
|
||||
t_in_pl += (n_un * t_in_pl) / (t - n_un);
|
||||
|
||||
fprintf(fp, "<span class=\"val\">%d</span> track%s in playlist, ", t, t == 1 ? "" : "s");
|
||||
fprintf(fp, "average track length: <span class=\"val\">%d:%02d",
|
||||
old_t_in_pl / (t-n_un) / 60, (old_t_in_pl / (t - n_un)) % 60);
|
||||
|
||||
fprintf(fp, "</span><br>%slaylist length: ",
|
||||
n_un ? "Estimated p" : "P");
|
||||
|
||||
if (t_in_pl / 3600)
|
||||
{
|
||||
fprintf(fp, "<span class=\"val\">%d</span> hour%s ",
|
||||
t_in_pl / 3600, t_in_pl / 3600 == 1 ? "" : "s");
|
||||
t_in_pl %= 3600;
|
||||
}
|
||||
|
||||
if (t_in_pl / 60)
|
||||
{
|
||||
fprintf(fp, "<span class=\"val\">%d</span> minute%s ",
|
||||
t_in_pl / 60, t_in_pl / 60 == 1 ? "" : "s");
|
||||
t_in_pl %= 60;
|
||||
}
|
||||
fprintf(fp, "<span class=\"val\">%d</span> second%s %s",
|
||||
t_in_pl, t_in_pl == 1 ? "" : "s", n_un ? "<br>(" : "");
|
||||
if (n_un) fprintf(fp, "<span class=\"val\">%d</span> track%s of unknown length)",
|
||||
n_un, n_un == 1 ? "" : "s");
|
||||
|
||||
fprintf(fp,
|
||||
"<br>Right-click <a href=\"file://%s\">here</a> to save this HTML file."
|
||||
"</td></tr>",
|
||||
(char *)AutoChar(filename, CP_UTF8));
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(fp, "There are no tracks in the current playlist.<br>");
|
||||
}
|
||||
|
||||
fprintf(fp, "</table></div>\n");
|
||||
|
||||
if (t > 0)
|
||||
{
|
||||
fprintf(fp,
|
||||
"<blockquote><span class=\"header\">Playlist files:</span><ol>\n");
|
||||
|
||||
for (x = 0; x < t; x++)
|
||||
{
|
||||
wchar_t fn[FILENAME_SIZE] = {0}, ft[FILETITLE_SIZE] = {0};
|
||||
int l;
|
||||
PlayList_getitem2W(x, fn, ft);
|
||||
AutoChar narrowFt(ft, CP_UTF8);
|
||||
char *p = narrowFt;
|
||||
l = PlayList_getsonglength(x);
|
||||
fprintf(fp, "<li>");
|
||||
while (p && *p)
|
||||
{
|
||||
if (*p == '&') fprintf(fp, "&");
|
||||
else if (*p == '<') fprintf(fp, "<");
|
||||
else if (*p == '>') fprintf(fp, ">");
|
||||
else if (*p == '\'') fprintf(fp, "'");
|
||||
else if (*p == '"') fprintf(fp, """);
|
||||
else fputc(*p, fp);
|
||||
p++;
|
||||
}
|
||||
|
||||
if(l > 0) fprintf(fp, " (%d:%02d) \n", l / 60, l % 60);
|
||||
else fprintf(fp, " \n");
|
||||
}
|
||||
|
||||
fprintf(fp, "</ol></blockquote>\n");
|
||||
}
|
||||
fprintf(fp, "<hr><br></body></html>");
|
||||
fclose(fp);
|
||||
|
||||
myOpenURL(hPLWindow, filename);
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
|
||||
** Filename:
|
||||
** Project:
|
||||
** Description:
|
||||
** Author: Ben Allison benski@nullsoft.com
|
||||
** Created:
|
||||
**/
|
||||
|
||||
#include "Main.h"
|
||||
#include "api.h"
|
||||
#include "..\Components\wac_network\wac_network_http_receiver_api.h"
|
||||
|
||||
#include "api/service/waServiceFactory.h"
|
||||
|
||||
|
||||
void GetMIMEType(const char *url, char *mimeType, int mimeTypeCch)
|
||||
{
|
||||
api_httpreceiver *http = 0;
|
||||
waServiceFactory *sf = 0;
|
||||
if (WASABI_API_SVC)
|
||||
{
|
||||
sf = WASABI_API_SVC->service_getServiceByGuid(httpreceiverGUID);
|
||||
if (sf)
|
||||
http = (api_httpreceiver *)sf->getInterface();
|
||||
}
|
||||
|
||||
if (!http)
|
||||
return ;
|
||||
|
||||
int ret;
|
||||
http->open(API_DNS_AUTODNS, 2048, config_proxy);
|
||||
http->connect(url, 0, "HEAD");
|
||||
|
||||
do
|
||||
{
|
||||
Sleep(10);
|
||||
ret = http->run();
|
||||
if (ret == -1) // connection failed
|
||||
break;
|
||||
|
||||
// ---- check our reply code ----
|
||||
int replycode = http->getreplycode();
|
||||
switch (replycode)
|
||||
{
|
||||
case 0:
|
||||
case 100:
|
||||
break;
|
||||
case 200:
|
||||
{
|
||||
const char *contentType = http->getheader("Content-Type");
|
||||
if (contentType)
|
||||
lstrcpynA(mimeType, contentType, mimeTypeCch);
|
||||
else
|
||||
mimeType[0] = 0;
|
||||
|
||||
sf->releaseInterface(http);
|
||||
return ;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sf->releaseInterface(http);
|
||||
return ;
|
||||
}
|
||||
}
|
||||
while (ret == HTTPRECEIVER_RUN_OK);
|
||||
|
||||
sf->releaseInterface(http);
|
||||
}
|
||||
|
||||
#if 0
|
||||
#define WM_HRF_READINGHTTP WM_USER
|
||||
#define WM_HRF_DOWNLOADING (WM_USER+1)
|
||||
struct RFData
|
||||
{
|
||||
public:
|
||||
char *url, *file;
|
||||
HWND hwnd;
|
||||
};
|
||||
|
||||
bool killswitch;
|
||||
static DWORD WINAPI rf_ThreadProc(void *p)
|
||||
{
|
||||
RFData *rfData = (RFData *)p;
|
||||
char *url = rfData->url, *file = rfData->file;
|
||||
waServiceFactory *sf = 0;
|
||||
api_httpreceiver *http = 0;
|
||||
if (WASABI_API_SVC)
|
||||
{
|
||||
sf = WASABI_API_SVC->service_getServiceByGuid(httpreceiverGUID);
|
||||
if (sf)
|
||||
http = (api_httpreceiver *)sf->getInterface();
|
||||
}
|
||||
|
||||
if (!http)
|
||||
return 1;
|
||||
|
||||
HANDLE hFile = CreateFile(file, GENERIC_WRITE, 0,
|
||||
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
sf->releaseInterface(http);
|
||||
return 1;
|
||||
}
|
||||
|
||||
http->Open(API_DNS_AUTODNS, 16384);
|
||||
http->AddHeader("User-Agent: Winamp/" APP_VERSION);
|
||||
http->Connect(url);
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
Sleep(50);
|
||||
http->Run();
|
||||
ret = http->GetStatus();
|
||||
if (ret == HTTPRECEIVER_STATUS_ERROR)
|
||||
killswitch = true;
|
||||
|
||||
if (killswitch)
|
||||
break;
|
||||
}
|
||||
while (ret == HTTPRECEIVER_STATUS_CONNECTING);
|
||||
|
||||
if (ret == HTTPRECEIVER_STATUS_READING_HEADERS || ret == HTTPRECEIVER_STATUS_READING_CONTENT)
|
||||
{
|
||||
PostMessageW(rfData->hwnd, WM_HRF_READINGHTTP, 0, 0);
|
||||
int replycode = http->GetReplyCode();
|
||||
switch (replycode)
|
||||
{
|
||||
case 0: case 100: // shouldn't really get here
|
||||
break;
|
||||
case 200:
|
||||
break;
|
||||
default:
|
||||
killswitch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool error = false;
|
||||
char block[16384] = {0};
|
||||
size_t downloadSize;
|
||||
size_t currentSize = 0, totalSize = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if (killswitch)
|
||||
{
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
// ---- Pause a bit and then run the http downloader ----
|
||||
Sleep(50);
|
||||
ret = http->Run();
|
||||
|
||||
if (ret == -1) // connection failed
|
||||
{
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// ---- download ----
|
||||
downloadSize = http->GetBytesAvailable();
|
||||
if (downloadSize)
|
||||
{
|
||||
totalSize = http->GetContentLength();
|
||||
|
||||
downloadSize = http->GetBytes(block, downloadSize);
|
||||
currentSize += downloadSize;
|
||||
PostMessageW(rfData->hwnd, WM_HRF_DOWNLOADING, currentSize, totalSize);
|
||||
|
||||
// ---- write to disk ----
|
||||
if (downloadSize) // WriteFile doesn't like 0 byte writes
|
||||
{
|
||||
DWORD numWritten = 0;
|
||||
WriteFile(hFile, block, downloadSize, &numWritten, FALSE);
|
||||
if (numWritten != downloadSize) // make sure that the block was actually written
|
||||
{
|
||||
error = true;
|
||||
break; // failed writing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (ret != 1 || downloadSize); // http may be closed, but make sure we get all the data.
|
||||
|
||||
CloseHandle(hFile);
|
||||
if (error)
|
||||
DeleteFile(file);
|
||||
sf->releaseInterface(http);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK rf_DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
SetDlgItemText(hwndDlg, IDC_STATUS, getString(IDS_HTTP_INIT,NULL,0));
|
||||
return FALSE;
|
||||
case WM_HRF_READINGHTTP:
|
||||
SetDlgItemText(hwndDlg, IDC_STATUS, getString(IDS_HTTP_READ_REQUEST,NULL,0));
|
||||
return TRUE;
|
||||
case WM_HRF_DOWNLOADING:
|
||||
{
|
||||
char temp[128] = {0};
|
||||
if (!lParam)
|
||||
StringCchPrintf(temp, 128, getString(IDS_HTTP_RET_FILE,NULL,0), wParam);
|
||||
else
|
||||
StringCchPrintf(temp, 128, getString(IDS_HTTP_RET_FILE_PERCENT,NULL,0), (100*wParam) / lParam, wParam, lParam);
|
||||
SetDlgItemText(hwndDlg, IDC_STATUS, temp);
|
||||
}
|
||||
return TRUE;
|
||||
case WM_DESTROY:
|
||||
if (GetParent(hwndDlg) == hMainWindow)
|
||||
{
|
||||
if (hMainWindow) EnableWindow(hMainWindow, 1);
|
||||
if (hPLWindow) EnableWindow(hPLWindow, 1);
|
||||
if (hEQWindow) EnableWindow(hEQWindow, 1);
|
||||
//if (hMBWindow) EnableWindow(hMBWindow,1);
|
||||
}
|
||||
else
|
||||
EnableWindow(GetParent(hwndDlg), 1);
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case IDCANCEL:
|
||||
DestroyWindow(hwndDlg);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int httpRetrieveFile(HWND hwnd, char *url, char *file, char *dlgtitle)
|
||||
{
|
||||
killswitch = false;
|
||||
RECT r;
|
||||
HANDLE hThread = 0;
|
||||
if (!hwnd) hwnd = hMainWindow;
|
||||
|
||||
if (hwnd == hMainWindow && g_dialog_box_parent) hwnd = g_dialog_box_parent;
|
||||
|
||||
GetWindowRect(hwnd, &r);
|
||||
HWND dlgWnd = LPCreateDialog(IDD_HTTPGET, hwnd, rf_DlgProc);
|
||||
SetWindowText(dlgWnd, dlgtitle);
|
||||
SetDlgItemText(dlgWnd, IDC_URL, url);
|
||||
|
||||
RFData data = {url, file, dlgWnd};
|
||||
DWORD id;
|
||||
hThread = CreateThread(NULL, 0, rf_ThreadProc, (void *) & data, CREATE_SUSPENDED, &id);
|
||||
if (NULL)
|
||||
return 1;
|
||||
|
||||
ResumeThread(hThread);
|
||||
if (r.bottom > GetSystemMetrics(SM_CXSCREEN) / 2 && r.bottom - r.top < 100)
|
||||
{
|
||||
RECT r2;
|
||||
GetWindowRect(dlgWnd, &r2);
|
||||
r.top = r.bottom - (r2.bottom - r2.top);
|
||||
}
|
||||
SetWindowPos(dlgWnd, NULL, r.left, r.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
|
||||
if (GetForegroundWindow() == hwnd)
|
||||
ShowWindow(dlgWnd, SW_SHOW);
|
||||
else
|
||||
ShowWindow(dlgWnd, SW_SHOWNA);
|
||||
|
||||
if (hwnd == hMainWindow)
|
||||
{
|
||||
if (hMainWindow) EnableWindow(hMainWindow, 0);
|
||||
if (hPLWindow) EnableWindow(hPLWindow, 0);
|
||||
if (hEQWindow) EnableWindow(hEQWindow, 0);
|
||||
//if (hMBWindow) EnableWindow(hMBWindow,0);
|
||||
}
|
||||
else
|
||||
EnableWindow(hwnd, 0);
|
||||
|
||||
while (1)
|
||||
{
|
||||
MSG msg;
|
||||
if (!IsWindow(dlgWnd))
|
||||
{
|
||||
killswitch = true;
|
||||
break;
|
||||
}
|
||||
if (WaitForSingleObject(hThread, 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
DestroyWindow(dlgWnd);
|
||||
break;
|
||||
}
|
||||
GetMessage(&msg, NULL, 0, 0);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
WaitForSingleObject(hThread, 5000);
|
||||
DWORD exitCode;
|
||||
if (GetExitCodeThread(hThread, &exitCode))
|
||||
return exitCode;
|
||||
else
|
||||
{
|
||||
// CUT: TerminateThread(hThread, 0);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,795 @@
|
||||
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
|
||||
** Filename:
|
||||
** Project:
|
||||
** Description:
|
||||
** Author:
|
||||
** Created:
|
||||
**/
|
||||
|
||||
#include "Main.h"
|
||||
#include <cstdint>
|
||||
#if 1
|
||||
#include <sys/types.h>
|
||||
#include <winsock.h>
|
||||
#include "../nu/threadname.h"
|
||||
#include "Wa_dlg.h"
|
||||
#include "../nu/AutoWide.h"
|
||||
|
||||
static void createDirForFileW(wchar_t *str)
|
||||
{
|
||||
wchar_t *p = str;
|
||||
if ((p[0] ==L'\\' || p[0] ==L'/') && (p[1] ==L'\\' || p[1] ==L'/'))
|
||||
{
|
||||
p += 2;
|
||||
while (p && *p && *p !=L'\\' && *p !=L'/') p++;
|
||||
if (!*p) return ;
|
||||
p++;
|
||||
while (p && *p && *p !=L'\\' && *p !=L'/') p++;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (p && *p && *p !=L'\\' && *p !=L'/') p++;
|
||||
}
|
||||
|
||||
while (p && *p)
|
||||
{
|
||||
while (p && *p !=L'\\' && *p !=L'/' && *p) p = CharNextW(p);
|
||||
if (*p)
|
||||
{
|
||||
wchar_t lp = *p;
|
||||
*p = 0;
|
||||
CreateDirectoryW(str, NULL);
|
||||
*p++ = lp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const wchar_t *rf_file, *rf_dlgtitle;
|
||||
static const char *rf_url;
|
||||
static int rf_in;
|
||||
static HWND rf_dlgWnd, rf_statusWnd;
|
||||
static volatile int rf_rv=-1;
|
||||
static volatile int rf_abort;
|
||||
static int g_rv;
|
||||
|
||||
static int _rftabort(int r, char *s)
|
||||
{
|
||||
if (s) SetWindowTextA(rf_statusWnd,s);
|
||||
if (rf_dlgWnd) SendMessageW(rf_dlgWnd,WM_USER+1,r,0);
|
||||
else rf_rv=r;
|
||||
return r;
|
||||
}
|
||||
|
||||
#define rfta(s) return _rftabort(!success,s)
|
||||
#define sets(s) SetWindowTextA(rf_statusWnd,s)
|
||||
|
||||
typedef int (__stdcall *waP_RECV)(SOCKET s, char FAR* buf, int len, int flags);
|
||||
waP_RECV p_recv;
|
||||
|
||||
static void encodeMimeStr(char *in, char *out)
|
||||
{
|
||||
char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
int shift = 0;
|
||||
int accum = 0;
|
||||
|
||||
while (in && *in)
|
||||
{
|
||||
if (*in)
|
||||
{
|
||||
accum <<= 8;
|
||||
shift += 8;
|
||||
accum |= *in++;
|
||||
}
|
||||
while ( shift >= 6 )
|
||||
{
|
||||
shift -= 6;
|
||||
*out++ = alphabet[(accum >> shift) & 0x3F];
|
||||
}
|
||||
}
|
||||
if (shift == 4)
|
||||
{
|
||||
*out++ = alphabet[(accum & 0xF)<<2];
|
||||
*out++='=';
|
||||
}
|
||||
else if (shift == 2)
|
||||
{
|
||||
*out++ = alphabet[(accum & 0x3)<<4];
|
||||
*out++='=';
|
||||
*out++='=';
|
||||
}
|
||||
|
||||
*out++=0;
|
||||
}
|
||||
|
||||
static int recv_string(SOCKET s, char *str, int maxlen)
|
||||
{
|
||||
int p=0;
|
||||
do
|
||||
{
|
||||
int t=0;
|
||||
while (t!=1)
|
||||
{
|
||||
t=p_recv(s,str+p,1,0);
|
||||
if (t != 1)
|
||||
{
|
||||
if (rf_abort || !t) { str[0]=0; return -1; }
|
||||
Sleep(100);
|
||||
}
|
||||
if (str[p] == '\r') t=0;
|
||||
}
|
||||
} while (str[p] != '\n' && ++p < maxlen-1);
|
||||
str[p--]=0;
|
||||
while (str[p] == '\n' && p > 0)
|
||||
{
|
||||
str[p--]=0;
|
||||
}
|
||||
if (p < 0) p = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
static int g_in_resolve;
|
||||
|
||||
static DWORD WINAPI rf_ThreadProc(LPVOID p666)
|
||||
{
|
||||
char locbuf[1024]={0};
|
||||
int redirect=0;
|
||||
HINSTANCE hws = LoadLibraryA("wsock32.dll");
|
||||
int total_bytes;
|
||||
uint64_t content_length;
|
||||
SOCKET sock;
|
||||
char proxytmp[256]={0};
|
||||
char *proxy;
|
||||
char connect_host[MAX_PATH]={0};
|
||||
unsigned short connect_port;
|
||||
int success=0;
|
||||
|
||||
typedef int (__stdcall *waSELECT)(int nfds,fd_set FAR * readfds,fd_set FAR * writefds,fd_set FAR * exceptfds,const struct timeval FAR * timeout);
|
||||
typedef int (__stdcall *waWSAGETLASTERROR)(void);
|
||||
typedef int (__stdcall *waWSACLEANUP)(void);
|
||||
typedef int (__stdcall *waWSASTARTUP)(WORD wVersionRequested,LPWSADATA lpWSAData);
|
||||
typedef int (__stdcall *waCLOSESOCKET)(SOCKET s);
|
||||
typedef int (__stdcall *waSEND)(SOCKET s,const char FAR *buf,int len,int flags);
|
||||
typedef SOCKET (__stdcall *waSOCKET)(int af, int type,int protocol);
|
||||
typedef int (__stdcall *waCONNECT)( SOCKET s, const struct sockaddr FAR *name, int namelen );
|
||||
typedef unsigned long (__stdcall *waINET_ADDR)(const char FAR *cp );
|
||||
typedef struct hostent FAR * (__stdcall *waGETHOSTBYNAME)(const char FAR *name);
|
||||
typedef int (__stdcall *waIOCTLSOCKET)(SOCKET s,long cmd,u_long FAR *argp);
|
||||
typedef u_short (__stdcall *waHTONS)(u_short hostshort);
|
||||
|
||||
waSELECT select;
|
||||
waWSAGETLASTERROR WSAGetLastError;
|
||||
waWSACLEANUP WSACleanup;
|
||||
waWSASTARTUP WSAStartup;
|
||||
waCLOSESOCKET closesocket;
|
||||
waSEND send;
|
||||
waSOCKET socket;
|
||||
waCONNECT connect;
|
||||
waINET_ADDR inet_addr;
|
||||
waGETHOSTBYNAME gethostbyname;
|
||||
waIOCTLSOCKET ioctlsocket;
|
||||
waHTONS htons;
|
||||
|
||||
char buf[ 4096 ] = { 0 };
|
||||
char errorStr[ 1024 ] = { 0 };
|
||||
char *p;
|
||||
char url_buf[ 1024 ] = { 0 };
|
||||
char *url_lp = NULL;
|
||||
char *url_host = NULL;
|
||||
int url_port = 80;
|
||||
char *url_url = NULL;
|
||||
char authstr[ 1024 ] = { 0 };
|
||||
char proxy_lp[ 1024 ] = { 0 };
|
||||
const char *t;
|
||||
|
||||
SetThreadName((DWORD)-1, "HTTP Retrieve File");
|
||||
if ( hws )
|
||||
{
|
||||
WSAGetLastError = (waWSAGETLASTERROR)GetProcAddress( hws, "WSAGetLastError" );
|
||||
WSACleanup = (waWSACLEANUP)GetProcAddress( hws, "WSACleanup" );
|
||||
WSAStartup = (waWSASTARTUP)GetProcAddress( hws, "WSAStartup" );
|
||||
closesocket = (waCLOSESOCKET)GetProcAddress( hws, "closesocket" );
|
||||
send = (waSEND)GetProcAddress( hws, "send" );
|
||||
p_recv = (waP_RECV)GetProcAddress( hws, "recv" );
|
||||
select = (waSELECT)GetProcAddress( hws, "select" );
|
||||
connect = (waCONNECT)GetProcAddress( hws, "connect" );
|
||||
socket = (waSOCKET)GetProcAddress( hws, "socket" );
|
||||
inet_addr = (waINET_ADDR)GetProcAddress( hws, "inet_addr" );
|
||||
gethostbyname = (waGETHOSTBYNAME)GetProcAddress( hws, "gethostbyname" );
|
||||
ioctlsocket = (waIOCTLSOCKET)GetProcAddress( hws, "ioctlsocket" );
|
||||
htons = (waHTONS)GetProcAddress( hws, "htons" );
|
||||
}
|
||||
|
||||
if (!hws || !p_recv || !WSACleanup ||
|
||||
!WSAStartup || !closesocket || !send ||
|
||||
!connect || !socket || !inet_addr ||
|
||||
!gethostbyname || !ioctlsocket || !htons || !select || !WSAGetLastError)
|
||||
{
|
||||
if (hws)
|
||||
FreeLibrary(hws);
|
||||
|
||||
rfta(getString(IDS_HTTP_LOAD_ERROR,errorStr,1024));
|
||||
}
|
||||
|
||||
sets(getString(IDS_HTTP_INIT_SOCKET,errorStr,1024));
|
||||
{
|
||||
WSADATA wsaData;
|
||||
if (WSAStartup(MAKEWORD(1, 1), &wsaData))
|
||||
{
|
||||
FreeLibrary(hws);
|
||||
rfta(getString(IDS_HTTP_INIT_SOCKET_ERROR,errorStr,1024));
|
||||
}
|
||||
}
|
||||
|
||||
_redirect_goto:
|
||||
total_bytes=0;
|
||||
content_length=0;
|
||||
|
||||
// parse out l/p, host, port, and url from loc
|
||||
authstr[0]=0;
|
||||
url_lp=NULL;
|
||||
url_host=NULL;
|
||||
url_port=80;
|
||||
url_url=NULL;
|
||||
|
||||
t= strstr(rf_url,"://");
|
||||
if (t)
|
||||
{
|
||||
StringCchCopyA(url_buf,1024,t+3);
|
||||
}
|
||||
else
|
||||
{
|
||||
StringCchCopyA(url_buf,1024,rf_url);
|
||||
}
|
||||
|
||||
p=url_buf;
|
||||
while (p && *p != '/' && *p) p++;
|
||||
if (p && *p) *p++=0;
|
||||
url_url=p;
|
||||
|
||||
p=url_buf;
|
||||
while (p && *p) p++;
|
||||
while (p>=url_buf && *p != '@') p--;
|
||||
if (p>=url_buf)
|
||||
{
|
||||
*p++=0;
|
||||
url_host=p;
|
||||
url_lp=url_buf;
|
||||
if (lstrlenA(url_lp)>0)
|
||||
{
|
||||
StringCchCopyA(authstr,1024,"Authorization: Basic ");
|
||||
encodeMimeStr(url_lp,authstr+lstrlenA(authstr));
|
||||
StringCchCatA(authstr,1024,"\r\n");
|
||||
}
|
||||
}
|
||||
else url_host=url_buf;
|
||||
|
||||
p=url_host;
|
||||
while (p && *p != ':' && *p) p++;
|
||||
if (p && *p)
|
||||
{
|
||||
*p++=0;
|
||||
if (*p) url_port=atoi(p);
|
||||
}
|
||||
|
||||
// determine if proxy server used
|
||||
{
|
||||
StringCchCopyA(proxytmp,256,config_proxy);
|
||||
proxy=proxytmp;
|
||||
while (proxy && (*proxy == ' ' || *proxy == '\t')) proxy++;
|
||||
|
||||
if (url_port != 80 && GetPrivateProfileIntW(L"Winamp",L"proxyonly80",0,INI_FILE))
|
||||
proxy="";
|
||||
}
|
||||
|
||||
if (*proxy)
|
||||
{
|
||||
p=proxy;
|
||||
while (p && *p && *p != '@') p++;
|
||||
if (p && *p)
|
||||
{
|
||||
*p++=0;
|
||||
StringCchCopyA(proxy_lp,1024,"Proxy-Authorization: Basic ");
|
||||
encodeMimeStr(proxy,proxy_lp+lstrlenA(proxy_lp));
|
||||
StringCchCatA(proxy_lp,1024,"\r\n");
|
||||
proxy=p;
|
||||
}
|
||||
|
||||
lstrcpynA(connect_host,proxy,sizeof(connect_host)/sizeof(*connect_host));
|
||||
p=connect_host;
|
||||
while (p && *p && *p != ':') p++;
|
||||
if (p && *p)
|
||||
{
|
||||
*p++=0;
|
||||
if (*p) connect_port=(unsigned short)atoi(p);
|
||||
else connect_port=80;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lstrcpynA(connect_host,url_host,sizeof(connect_host)/sizeof(*connect_host));
|
||||
connect_port=(unsigned short)url_port;
|
||||
}
|
||||
|
||||
sets(getString(IDS_HTTP_SOCKET_CREATE,errorStr,1024));
|
||||
if (rf_abort || (sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))==INVALID_SOCKET)
|
||||
{
|
||||
WSACleanup();
|
||||
FreeLibrary(hws);
|
||||
rfta(getString(IDS_HTTP_SOCKET_ERROR,errorStr,1024));
|
||||
}
|
||||
|
||||
{
|
||||
int t;
|
||||
struct sockaddr_in blah;
|
||||
memset((char *)&blah,0,sizeof(blah));
|
||||
blah.sin_family=AF_INET;
|
||||
blah.sin_addr.s_addr=inet_addr(connect_host);
|
||||
blah.sin_port=htons(connect_port);
|
||||
|
||||
if ( blah.sin_addr.s_addr == INADDR_NONE )
|
||||
{
|
||||
struct hostent *he;
|
||||
g_in_resolve = 1;
|
||||
sets( *proxy ? getString( IDS_HTTP_RESOLVE_PROXY, errorStr, 1024 ) : getString( IDS_HTTP_RESOLVE_HOST, errorStr, 1024 ) );
|
||||
if ( ( he = gethostbyname( connect_host ) ) != NULL )
|
||||
memcpy( (char *)&blah.sin_addr, he->h_addr, he->h_length );
|
||||
else if ( ( blah.sin_addr.s_addr = inet_addr( connect_host ) ) == INADDR_NONE )
|
||||
{
|
||||
g_in_resolve = 0;
|
||||
closesocket( sock );
|
||||
WSACleanup();
|
||||
FreeLibrary( hws );
|
||||
rfta( *proxy ? getString( IDS_HTTP_RESOLVE_PROXY_ERROR, errorStr, 1024 ) : getString( IDS_HTTP_RESOLVE_HOST_ERROR, errorStr, 1024 ) );
|
||||
}
|
||||
|
||||
g_in_resolve = 0;
|
||||
}
|
||||
|
||||
sets(*proxy?getString(IDS_HTTP_CONNECT_PROXY,errorStr,1024):getString(IDS_HTTP_CONNECT_HOST,errorStr,1024));
|
||||
{
|
||||
unsigned long arg=1;
|
||||
ioctlsocket(sock,FIONBIO,&arg);
|
||||
}
|
||||
|
||||
t=connect(sock,(struct sockaddr *)&blah,16);
|
||||
if (t == -1 && WSAGetLastError()==WSAEWOULDBLOCK)
|
||||
{
|
||||
int a=0;
|
||||
while (!rf_abort && t==-1)
|
||||
{
|
||||
TIMEVAL to={0,250*1000};
|
||||
fd_set f;
|
||||
FD_ZERO(&f);
|
||||
FD_SET(sock,&f);
|
||||
switch (select(0,NULL,&f,NULL,&to))
|
||||
{
|
||||
case 1: t=0; break;
|
||||
case 0: if (a++ > 40) rf_abort =1; break;
|
||||
case -1: rf_abort =1; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rf_abort || t==-1)
|
||||
{
|
||||
closesocket(sock);
|
||||
WSACleanup();
|
||||
FreeLibrary(hws);
|
||||
rfta(*proxy?getString(IDS_HTTP_CONNECT_PROXY_ERROR,errorStr,1024):getString(IDS_HTTP_CONNECT_HOST_ERROR,errorStr,1024));
|
||||
}
|
||||
}
|
||||
|
||||
sets(getString(IDS_HTTP_SEND_REQUEST,errorStr,1024));
|
||||
{
|
||||
if ( *proxy )
|
||||
StringCchPrintfA( buf, 4096, "GET http://%s:%d/%s", url_host, url_port, url_url );
|
||||
else
|
||||
StringCchPrintfA( buf, 4096, "GET /%s", url_url );
|
||||
|
||||
if (url_port != 80)
|
||||
StringCchPrintfA( buf + lstrlenA( buf ), 4096 - lstrlenA( buf ), " HTTP/1.0\r\nHost: %s:%d\r\n", url_host, url_port );
|
||||
else
|
||||
StringCchPrintfA( buf + lstrlenA( buf ), 4096 - lstrlenA( buf ), " HTTP/1.0\r\nHost: %s\r\n", url_host );
|
||||
|
||||
StringCchPrintfA( buf + lstrlenA( buf ), 4096 - lstrlenA( buf ),
|
||||
"User-Agent: Winamp/%s%s\r\n"
|
||||
"%s%s"
|
||||
"Accept: */*\r\n\r\n",
|
||||
app_version,
|
||||
( redirect == 2 ? " (Mozilla)" : "" ),
|
||||
proxy_lp, authstr );
|
||||
|
||||
//MessageBox(NULL,buf,"SENDING:",0);
|
||||
{
|
||||
unsigned long arg = 0;
|
||||
ioctlsocket( sock, FIONBIO, &arg );
|
||||
}
|
||||
|
||||
send(sock,buf,lstrlenA(buf),0);
|
||||
|
||||
{
|
||||
unsigned long arg = 1;
|
||||
ioctlsocket( sock, FIONBIO, &arg );
|
||||
}
|
||||
}
|
||||
|
||||
sets( getString( IDS_HTTP_READ_REQUEST, errorStr, 1024 ) );
|
||||
|
||||
{ // get the standard HTTP 1.0 200 OK
|
||||
char buf[1024] = {0};
|
||||
int x = recv_string(sock,buf,sizeof(buf));
|
||||
//MessageBox(0, buf, "RECEIVING:", 0);
|
||||
if (x < 0 || rf_abort)
|
||||
{
|
||||
closesocket(sock);
|
||||
WSACleanup();
|
||||
FreeLibrary(hws);
|
||||
rfta(getString(IDS_HTTP_CONNECTION_LOST,errorStr,1024));
|
||||
}
|
||||
|
||||
if (strstr(buf," 302") || strstr(buf,"301"))
|
||||
{
|
||||
redirect=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is a very specific handling to allow for /listen.m3u with v1.x DNAS to work correctly
|
||||
// as we need alter the user-agent so it will provide us with the needed response (a DNAS bug)
|
||||
if ((redirect != 2) && strstr(buf,"ICY 404 Resource Not Found") && strstr(url_url,"listen.m3u")) {
|
||||
redirect=2;
|
||||
closesocket(sock);
|
||||
goto _redirect_goto;
|
||||
}
|
||||
else
|
||||
{
|
||||
redirect=0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strstr(buf,"OK") && !redirect)
|
||||
{
|
||||
StringCchCatA(buf,1024,getString(IDS_HTTP_CONNECTION_CLOSED,errorStr,1024));
|
||||
closesocket(sock);
|
||||
WSACleanup();
|
||||
FreeLibrary(hws);
|
||||
rfta(buf);
|
||||
}
|
||||
|
||||
sets(buf);
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
char buf[1024] = {0}, *p;
|
||||
int x = recv_string(sock,buf,sizeof(buf));
|
||||
if (x < 0 || rf_abort)
|
||||
{
|
||||
closesocket(sock);
|
||||
WSACleanup();
|
||||
FreeLibrary(hws);
|
||||
rfta(getString(IDS_HTTP_CONNECTION_LOST,errorStr,1024));
|
||||
}
|
||||
|
||||
if (buf[0] == '\r' || !buf[0])
|
||||
break;
|
||||
|
||||
{
|
||||
p=buf;
|
||||
while (p && *p && *p != ':') p++;
|
||||
if (p && *p == ':')
|
||||
{
|
||||
*p++=0;
|
||||
while (p && (*p == ' ' || *p == '\t'))
|
||||
p++;
|
||||
}
|
||||
else
|
||||
p=NULL;
|
||||
}
|
||||
|
||||
if (!lstrcmpiA(buf,"Content-Length") && (*p >= '0' && *p <= '9'))
|
||||
{
|
||||
content_length=0;
|
||||
while (p && *p >= '0' && *p <= '9')
|
||||
{
|
||||
content_length *= 10;
|
||||
content_length += *p++-'0';
|
||||
}
|
||||
}
|
||||
|
||||
if (!lstrcmpiA(buf,"Location") && redirect)
|
||||
{
|
||||
StringCchCopyA(locbuf,1024,p);
|
||||
rf_url=locbuf;
|
||||
closesocket(sock);
|
||||
|
||||
//blah
|
||||
goto _redirect_goto;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
createDirForFileW((wchar_t *)rf_file);
|
||||
HANDLE h = CreateFileW(rf_file,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,0,NULL);
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
closesocket(sock);
|
||||
WSACleanup();
|
||||
FreeLibrary(hws);
|
||||
rfta(getString(IDS_HTTP_ERROR_OPEN_FILE,errorStr,1024));
|
||||
}
|
||||
|
||||
{
|
||||
unsigned int start_time=GetTickCount();
|
||||
char buf[4096] = {0};
|
||||
while (1)
|
||||
{
|
||||
int x=p_recv(sock,buf,sizeof(buf),0);
|
||||
if (x == 0 || rf_abort)
|
||||
break;
|
||||
else if (x < 0)
|
||||
{
|
||||
if (WSAGetLastError()!=WSAEWOULDBLOCK) break;
|
||||
Sleep(50);
|
||||
}
|
||||
else // x > 0
|
||||
{
|
||||
DWORD t = 0;
|
||||
int lb=total_bytes;
|
||||
WriteFile(h,buf,x,&t,NULL);
|
||||
|
||||
total_bytes += x;
|
||||
if ( lb / 16384 != total_bytes / 16384 )
|
||||
{
|
||||
int bps;
|
||||
int t = ( GetTickCount() - start_time );
|
||||
if ( t < 1000 ) t = 1000;
|
||||
bps = total_bytes / ( ( t + 999 ) / 1000 );
|
||||
|
||||
if ( content_length )
|
||||
StringCchPrintfA( buf, 4096, getString( IDS_HTTP_RETRIEVE_FILE_LENGTH, errorStr, 1024 ), ( total_bytes * 100 ) / content_length, total_bytes, content_length, bps / 1000, ( bps / 10 ) % 100 );
|
||||
else
|
||||
StringCchPrintfA( buf, 4096, getString( IDS_HTTP_RETRIEVE_FILE, errorStr, 1024 ), total_bytes, bps / 1000, ( bps / 10 ) % 100 );
|
||||
|
||||
sets( buf );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CloseHandle(h);
|
||||
}
|
||||
|
||||
if (!content_length || total_bytes == content_length)
|
||||
success=1;
|
||||
else
|
||||
sets(getString(IDS_HTTP_FILE_INCOMPLETE,errorStr,1024));
|
||||
|
||||
closesocket(sock);
|
||||
WSACleanup();
|
||||
FreeLibrary(hws);
|
||||
rfta(success?getString(IDS_HTTP_SUCCESS,errorStr,1024):NULL);
|
||||
}
|
||||
|
||||
#undef rfta
|
||||
#undef sets
|
||||
|
||||
static BOOL CALLBACK rf_DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
|
||||
{
|
||||
static HANDLE hThread;
|
||||
static int r;
|
||||
|
||||
if (WADlg_initted())
|
||||
{
|
||||
INT_PTR a = WADlg_handleDialogMsgs(hwndDlg, uMsg, wParam, lParam);
|
||||
if (a)
|
||||
return a;
|
||||
}
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_USER+1:
|
||||
if (hThread != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(hThread);
|
||||
hThread=INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (!wParam)
|
||||
{
|
||||
g_rv=0;
|
||||
PostMessageW(hwndDlg,WM_USER,0,0); // make it go quick
|
||||
}
|
||||
else
|
||||
{
|
||||
SetDlgItemTextA(hwndDlg,IDCANCEL,getString(IDS_HTTP_CLOSE,NULL,0));
|
||||
r=5;
|
||||
SetTimer(hwndDlg,123,1000,NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
case WM_TIMER:
|
||||
if (wParam == 123)
|
||||
{
|
||||
if ( r == 0 )
|
||||
{
|
||||
KillTimer( hwndDlg, wParam );
|
||||
g_rv = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
char s[ 32 ] = { 0 };
|
||||
StringCchPrintfA( s, 32, getString( IDS_CLOSE_COUNTDOWN, NULL, 0 ), r-- );
|
||||
SetDlgItemTextA( hwndDlg, IDCANCEL, s );
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
case WM_ERASEBKGND:
|
||||
if (WADlg_initted())
|
||||
return 1; //handled by WADlg_DrawChildWindowBorders in WM_PAINT
|
||||
break;
|
||||
case WM_PAINT:
|
||||
{
|
||||
if (WADlg_initted())
|
||||
{
|
||||
int tab[] = { IDC_STATUS | DCW_SUNKENBORDER};
|
||||
WADlg_DrawChildWindowBorders(hwndDlg, tab, sizeof(tab) / sizeof(tab[0]));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
DWORD id;
|
||||
char errorStr[ 1024 ] = { 0 };
|
||||
|
||||
if ( WADlg_initted() )
|
||||
SetWindowLong( GetDlgItem( hwndDlg, IDCANCEL ), GWL_STYLE, GetWindowLongW( GetDlgItem( hwndDlg, IDCANCEL ), GWL_STYLE ) | BS_OWNERDRAW );
|
||||
|
||||
rf_dlgWnd = hwndDlg;
|
||||
rf_statusWnd = GetDlgItem( hwndDlg, IDC_STATUS );
|
||||
SetWindowTextW( hwndDlg, rf_dlgtitle );
|
||||
|
||||
if ( strstr( rf_url, "client.winamp.com/update" ) )
|
||||
SetDlgItemTextA( hwndDlg, IDC_URL, getString( IDS_HTTP_WINAMP_UPDATE_SITE, errorStr, 1024 ) );
|
||||
else
|
||||
SetDlgItemTextA( hwndDlg, IDC_URL, rf_url );
|
||||
|
||||
SetDlgItemTextA( hwndDlg, IDC_STATUS, getString( IDS_HTTP_INIT, errorStr, 1024 ) );
|
||||
rf_abort = 0;
|
||||
hThread = CreateThread( NULL, 0, rf_ThreadProc, 0, 0, &id );
|
||||
}
|
||||
return FALSE;
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case IDCANCEL:
|
||||
if (hThread!=INVALID_HANDLE_VALUE)
|
||||
{
|
||||
char errorStr[1024] = {0};
|
||||
rf_abort=1;
|
||||
#if 0
|
||||
if (g_in_resolve) g_in_resolve++;
|
||||
if (0 && g_in_resolve==3) // lame terminatethread shouldnt be used
|
||||
{
|
||||
TerminateThread(hThread,0);
|
||||
CloseHandle(hThread);
|
||||
hThread=INVALID_HANDLE_VALUE;
|
||||
g_rv=1;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
SetDlgItemTextA(hwndDlg,IDCANCEL,getString(IDS_HTTP_ABORT,errorStr,1024));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_rv=1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int httpRetrieveFileW(HWND hwnd, const char *url, const wchar_t *file, const wchar_t *dlgtitle)
|
||||
{
|
||||
int i;
|
||||
int activated=0;
|
||||
RECT r;
|
||||
HWND dlgWnd;
|
||||
if (rf_in) return 1;
|
||||
rf_in=1;
|
||||
g_rv=-1;
|
||||
rf_url=url;
|
||||
rf_file=file;
|
||||
rf_dlgtitle=dlgtitle;
|
||||
g_in_resolve=0;
|
||||
if (!hwnd) hwnd=hMainWindow;
|
||||
|
||||
if (hwnd == hMainWindow && g_dialog_box_parent)
|
||||
hwnd=g_dialog_box_parent;
|
||||
|
||||
{
|
||||
if (_strnicmp(url,"http://",7))
|
||||
{
|
||||
// MessageBox(hwnd,getString(IDS_ONLYHTTP,NULL,0),"Winamp",MB_OK|MB_ICONSTOP);
|
||||
rf_in=0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
GetWindowRect(hwnd,&r);
|
||||
dlgWnd=LPCreateDialogW(IDD_HTTPGET, hwnd, (WNDPROC)rf_DlgProc);
|
||||
if (r.bottom > GetSystemMetrics(SM_CXSCREEN)/2 && r.bottom-r.top < 100)
|
||||
{
|
||||
RECT r2;
|
||||
GetWindowRect(dlgWnd,&r2);
|
||||
r.top=r.bottom-(r2.bottom-r2.top);
|
||||
}
|
||||
|
||||
SetWindowPos(dlgWnd,NULL,r.left,r.top,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
|
||||
|
||||
if (GetForegroundWindow()==hwnd)
|
||||
{
|
||||
activated=1;
|
||||
ShowWindow(dlgWnd,SW_SHOW);
|
||||
}
|
||||
else
|
||||
ShowWindow(dlgWnd,SW_SHOWNA);
|
||||
|
||||
if (hwnd == hMainWindow)
|
||||
{
|
||||
if (hMainWindow) EnableWindow(hMainWindow,0);
|
||||
if (hPLWindow) EnableWindow(hPLWindow,0);
|
||||
if (hEQWindow) EnableWindow(hEQWindow,0);
|
||||
//if (hMBWindow) EnableWindow(hMBWindow,0);
|
||||
}
|
||||
else
|
||||
EnableWindow(hwnd,0);
|
||||
|
||||
while (1)
|
||||
{
|
||||
MSG msg;
|
||||
if (g_rv != -1) break;
|
||||
GetMessage(&msg,NULL,0,0);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
if ( activated && GetForegroundWindow() == dlgWnd )
|
||||
{
|
||||
}
|
||||
else
|
||||
activated = 0;
|
||||
|
||||
if ( hwnd == hMainWindow )
|
||||
{
|
||||
if ( hMainWindow )
|
||||
EnableWindow( hMainWindow, 1 );
|
||||
|
||||
if ( hPLWindow )
|
||||
EnableWindow( hPLWindow, 1 );
|
||||
|
||||
if ( hEQWindow )
|
||||
EnableWindow( hEQWindow, 1 );
|
||||
//if (hMBWindow) EnableWindow(hMBWindow,1);
|
||||
}
|
||||
else
|
||||
EnableWindow( hwnd, 1 );
|
||||
|
||||
DestroyWindow(dlgWnd);
|
||||
if (activated)
|
||||
SetForegroundWindow(hwnd);
|
||||
|
||||
i = g_rv;
|
||||
rf_in=0;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int httpRetrieveFile(HWND hwnd, const char *url, char *file, char *dlgtitle)
|
||||
{
|
||||
return httpRetrieveFileW(hwnd, url, AutoWide(file), AutoWide(dlgtitle));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,191 @@
|
||||
#ifndef NULLSOFT_WINAMP_IN2H
|
||||
#define NULLSOFT_WINAMP_IN2H
|
||||
// Input plugin interface
|
||||
|
||||
#include "out.h"
|
||||
#ifdef __cplusplus
|
||||
class api_service;
|
||||
#endif
|
||||
|
||||
// If you want your input plugin to support unicode then define the following which will then
|
||||
// adjust required functions to their unicode variants. This is supported from Winamp 5.3+.
|
||||
#define IN_UNICODE 0x0F000000
|
||||
#define IN_INIT_RET 0xF0000000
|
||||
|
||||
#ifdef UNICODE_INPUT_PLUGIN
|
||||
#define in_char wchar_t
|
||||
#define IN_VER_OLD (IN_UNICODE | 0x100)
|
||||
#define IN_VER (IN_UNICODE | 0x101)
|
||||
#define IN_VER_RET (IN_INIT_RET | IN_VER)
|
||||
#else
|
||||
#define in_char char
|
||||
#define IN_VER_OLD 0x100
|
||||
#define IN_VER 0x101
|
||||
#define IN_VER_RET (IN_INIT_RET | IN_VER)
|
||||
#endif
|
||||
|
||||
// added 5.64+ & updated 5.66+
|
||||
//
|
||||
// specify IN_VER if you want to provide a unicode (wchar_t*) description and only work on 5.64+
|
||||
// specify IN_VER_OLD to use the original (char*) description as before
|
||||
// note: we are using the fact that sizeof(char*) == sizeof(wchar_t*) to be able to allow this
|
||||
// so now when using IN_VER you will need to cast description to (wchar_t*) to set this.
|
||||
|
||||
// added 5.66+
|
||||
// specify IN_VER_RET to allow for the init(..) member to return an int status value as either
|
||||
// IN_INIT_SUCCESS or IN_INIT_FAILURE to allow for better support with loading failures or if
|
||||
// needing to specifically prevent loading if required e.g. OS incompatibility or access issues.
|
||||
//
|
||||
// Also added is the 'service' member which saves sending a IPC_GET_API_SERVICE call on loading
|
||||
// which will be filled in if IN_VER_RET is specified in the 'version' member of the plug-in.
|
||||
|
||||
#define IN_MODULE_FLAG_USES_OUTPUT_PLUGIN 1
|
||||
|
||||
// By default Winamp assumes your input plugin wants to use Winamp's EQ, and doesn't do replay gain
|
||||
// if you handle any of these yourself (EQ, Replay Gain adjustments), then set these flags accordingly
|
||||
|
||||
// Set this if you want to implement your own EQ inplace of using Winamp's native implementation.
|
||||
#define IN_MODULE_FLAG_EQ 2
|
||||
|
||||
// Set this if you adjusted volume for replay gain. For tracks with no replay gain metadata then you
|
||||
// should clear this flag UNLESS you handle "non_replaygain" gain adjustment yourself then keep it.
|
||||
#define IN_MODULE_FLAG_REPLAYGAIN 8
|
||||
|
||||
// Use this if you queried for the replay gain preamp parameter and used it. This is new to 5.54 clients.
|
||||
#define IN_MODULE_FLAG_REPLAYGAIN_PREAMP 16
|
||||
typedef struct
|
||||
{
|
||||
int version; // module type (IN_VER)
|
||||
char* description; // description of module, with version string
|
||||
|
||||
HWND hMainWindow; // Winamp's main window (filled in by Winamp - is a valid HWND on 5.1+ clients)
|
||||
HINSTANCE hDllInstance; // DLL instance handle (Also filled in by Winamp)
|
||||
|
||||
char* FileExtensions; // "mp3\0Layer 3 MPEG\0mp2\0Layer 2 MPEG\0mpg\0Layer 1 MPEG\0"
|
||||
// May be altered from Config, so the user can select what they want
|
||||
|
||||
int is_seekable; // is this stream seekable?
|
||||
int UsesOutputPlug; // does this plug-in use the output plug-ins? (musn't ever change, ever :)
|
||||
// note that this has turned into a "flags" field see IN_MODULE_FLAG_*
|
||||
|
||||
void(__cdecl* Config)(HWND hwndParent); // configuration dialog
|
||||
void(__cdecl* About)(HWND hwndParent); // about dialog
|
||||
|
||||
// 5.66 - changed from void (__cdecl *Init)(); if using IN_VER_RET or IN_VER_RET_OLD
|
||||
int(__cdecl* Init)(); // called at program init
|
||||
void(__cdecl* Quit)(); // called at program quit
|
||||
|
||||
#define GETFILEINFO_TITLE_LENGTH 2048
|
||||
// If file == NULL then the currently playing file is used (assumes you've cached it as required)
|
||||
void (*GetFileInfo)(const in_char* file, in_char* title, int* length_in_ms);
|
||||
|
||||
#define INFOBOX_EDITED 0
|
||||
#define INFOBOX_UNCHANGED 1
|
||||
int(__cdecl* InfoBox)(const in_char* file, HWND hwndParent);
|
||||
|
||||
int(__cdecl* IsOurFile)(const in_char* fn); // called before extension checks, to allow detection of mms://, etc
|
||||
|
||||
// playback stuff
|
||||
int(__cdecl* Play)(const in_char* fn); // return zero on success, -1 on file-not-found, some other value on other (stopping Winamp) error
|
||||
void(__cdecl* Pause)(); // pause stream
|
||||
void(__cdecl* UnPause)(); // unpause stream
|
||||
int(__cdecl* IsPaused)(); // ispaused? return 1 if paused, 0 if not
|
||||
void(__cdecl* Stop)(); // stop (unload) stream
|
||||
|
||||
// time stuff
|
||||
int(__cdecl* GetLength)(); // get length in ms
|
||||
int(__cdecl* GetOutputTime)(); // returns current output time in ms. (usually returns outMod->GetOutputTime()
|
||||
void(__cdecl* SetOutputTime)(int time_in_ms); // seeks to point in stream (in ms). Usually you signal your thread to seek, which seeks and calls outMod->Flush()..
|
||||
|
||||
// volume stuff
|
||||
void(__cdecl* SetVolume)(int volume); // from 0 to 255.. usually just call outMod->SetVolume
|
||||
void(__cdecl* SetPan)(int pan); // from -127 to 127.. usually just call outMod->SetPan
|
||||
|
||||
// in-window builtin vis stuff
|
||||
void(__cdecl* SAVSAInit)(int maxlatency_in_ms, int srate); // call once in Play(). maxlatency_in_ms should be the value returned from outMod->Open()
|
||||
// call after opening audio device with max latency in ms and samplerate
|
||||
void(__cdecl* SAVSADeInit)(); // call in Stop()
|
||||
|
||||
// simple vis supplying mode
|
||||
void(__cdecl* SAAddPCMData)(void* PCMData, int nch, int bps, int timestamp); // sets the spec data directly from PCM data quick and easy way
|
||||
// to get vis working :) needs at least 576 samples :)
|
||||
|
||||
// advanced vis supplying mode, only use if you're cool. Use SAAddPCMData for most stuff.
|
||||
int(__cdecl* SAGetMode)(); // gets csa (the current type (4=ws,2=osc,1=spec)) use when calling SAAdd()
|
||||
int(__cdecl* SAAdd)(void* data, int timestamp, int csa); // sets the spec data, filled in by Winamp
|
||||
|
||||
// vis stuff (plug-in)
|
||||
// simple vis supplying mode
|
||||
void(__cdecl* VSAAddPCMData)(void* PCMData, int nch, int bps, int timestamp); // sets the vis data directly from PCM data quick and easy way
|
||||
// to get vis working :) needs at least 576 samples :)
|
||||
|
||||
// advanced vis supplying mode, only use if you're cool. Use VSAAddPCMData for most stuff.
|
||||
int(__cdecl* VSAGetMode)(int* specNch, int* waveNch); // use to figure out what to give to VSAAdd
|
||||
int(__cdecl* VSAAdd)(void* data, int timestamp); // filled in by Winamp, called by plug-in
|
||||
|
||||
// call this in Play() to tell the vis plug-ins the current output params.
|
||||
void(__cdecl* VSASetInfo)(int srate, int nch); // <-- Correct (benski, dec 2005).. old declaration had the params backwards
|
||||
|
||||
// dsp plug-in processing:
|
||||
// (filled in by Winamp, calld by input plug)
|
||||
|
||||
// returns 1 if active (which means that the number of samples returned by dsp_dosamples could be
|
||||
// greater than went in.. Use it to estimate if you'll have enough room in the output buffer
|
||||
int(__cdecl* dsp_isactive)();
|
||||
|
||||
// returns number of samples to output. This can be as much as twice numsamples.
|
||||
// be sure to allocate enough buffer for samples, then.
|
||||
int(__cdecl* dsp_dosamples)(short int* samples, int numsamples, int bps, int nch, int srate);
|
||||
|
||||
// eq stuff
|
||||
void(__cdecl* EQSet)(int on, char data[10], int preamp); // 0-64 each, 31 is +0, 0 is +12, 63 is -12. Do nothing to ignore.
|
||||
|
||||
// info setting (filled in by Winamp)
|
||||
void(__cdecl* SetInfo)(int bitrate, int srate, int stereo, int synched); // if -1, changes ignored? :)
|
||||
|
||||
Out_Module* outMod; // filled in by Winamp, optionally used :)
|
||||
|
||||
// filled in by Winamp (added 5.66+ to replace need to call IPC_GET_API_SERVICE on loading)
|
||||
#ifdef __cplusplus
|
||||
api_service* service;
|
||||
#else
|
||||
void* service;
|
||||
#endif
|
||||
} In_Module;
|
||||
|
||||
// added 5.66+
|
||||
// return values from the init(..) which determines if Winamp will continue loading
|
||||
// and handling the plugin or if it will disregard the load attempt. If GEN_INIT_FAILURE
|
||||
// is returned then the plugin will be listed as [NOT LOADED] on the plug-in prefs page.
|
||||
#define IN_INIT_SUCCESS 0
|
||||
#define IN_INIT_FAILURE 1
|
||||
|
||||
|
||||
// These are the return values to be used with the uninstall plugin export function:
|
||||
// __declspec(dllexport) int __cdecl winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param)
|
||||
// which determines if Winamp can uninstall the plugin immediately or on Winamp restart.
|
||||
// If this is not exported then Winamp will assume an uninstall with reboot is the only way.
|
||||
//
|
||||
#define IN_PLUGIN_UNINSTALL_NOW 0x1
|
||||
#define IN_PLUGIN_UNINSTALL_REBOOT 0x0
|
||||
//
|
||||
// Uninstall support was added from 5.0+ and uninstall now support from 5.5+ though note
|
||||
// that it is down to you to ensure that if uninstall now is returned that it will not
|
||||
// cause a crash i.e. don't use if you've been subclassing the main window.
|
||||
//
|
||||
// The HWND passed in the calling of winampUninstallPlugin(..) is the preference page HWND.
|
||||
//
|
||||
|
||||
// For a input plugin to be correctly detected by Winamp you need to ensure that
|
||||
// the exported winampGetInModule2(..) is exported as an undecorated function
|
||||
// e.g.
|
||||
// #ifdef __cplusplus
|
||||
// extern "C" {
|
||||
// #endif
|
||||
// __declspec(dllexport) In_Module * __cdecl winampGetInModule2(){ return &plugin; }
|
||||
// #ifdef __cplusplus
|
||||
// }
|
||||
// #endif
|
||||
//
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,966 @@
|
||||
#include "main.h"
|
||||
#include "IVideoD3DOSD.h"
|
||||
#include "resource.h"
|
||||
|
||||
extern wchar_t FileTitle[];
|
||||
static HMODULE d3dx_lib = 0;
|
||||
|
||||
// For non-debug builds, comment out DXTraceW debug statements to
|
||||
// remove them completely
|
||||
//#ifndef _DEBUG
|
||||
#define DXTraceW //
|
||||
//#endif
|
||||
|
||||
typedef HRESULT (WINAPI *D3DXCREATESPRITE)(LPDIRECT3DDEVICE9, LPD3DXSPRITE *);
|
||||
typedef HRESULT (WINAPI *D3DXCREATEFONTW)(LPDIRECT3DDEVICE9, INT, UINT, UINT, UINT, BOOL, DWORD, DWORD, DWORD, DWORD, LPCWSTR, LPD3DXFONT *);
|
||||
typedef HRESULT (WINAPI *D3DXCREATETEXTUREFROMRESOURCEEXW)(LPDIRECT3DDEVICE9, HMODULE, LPCWSTR, UINT, UINT, UINT, DWORD, D3DFORMAT, D3DPOOL, DWORD, DWORD, D3DCOLOR, D3DXIMAGE_INFO *, PALETTEENTRY *, LPDIRECT3DTEXTURE9 *);
|
||||
D3DXCREATESPRITE pCreateSprite = NULL;
|
||||
D3DXCREATEFONTW pCreateFontW = NULL;
|
||||
D3DXCREATETEXTUREFROMRESOURCEEXW pCreateTextureFromResourceExW = NULL;
|
||||
|
||||
HMODULE FindD3DX9()
|
||||
{
|
||||
if (d3dx_lib)
|
||||
return d3dx_lib;
|
||||
|
||||
HMODULE d3dx9 = NULL;
|
||||
HANDLE hFind;
|
||||
WIN32_FIND_DATAW pfiledata;
|
||||
wchar_t systemDir[MAX_PATH] = {0};
|
||||
wchar_t libPath[MAX_PATH] = {0};
|
||||
GetSystemDirectoryW(systemDir, MAX_PATH);
|
||||
StringCchCatW(systemDir, MAX_PATH,L"\\d3dx9_");
|
||||
StringCchCopyW(libPath, MAX_PATH, systemDir);
|
||||
StringCchCatW(systemDir, MAX_PATH,L"*.dll");
|
||||
|
||||
hFind = FindFirstFileW(systemDir,&pfiledata);
|
||||
if (hFind != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
BOOL more = true;
|
||||
int iHighVersion = 0;
|
||||
while (more)
|
||||
{
|
||||
wchar_t *start = wcsrchr(pfiledata.cFileName,L'_') + 1;
|
||||
int version = _wtoi(start);
|
||||
if (version <= 42 && version > iHighVersion)
|
||||
iHighVersion = version;
|
||||
more = FindNextFileW(hFind,&pfiledata);
|
||||
}
|
||||
|
||||
FindClose(hFind);
|
||||
if (iHighVersion >= 24)
|
||||
{
|
||||
wchar_t finalD3DX9LibPath[MAX_PATH] = {0};
|
||||
StringCchPrintfW(finalD3DX9LibPath,MAX_PATH,L"%s%d%s",libPath,iHighVersion,L".dll");
|
||||
|
||||
d3dx9 = LoadLibraryW(finalD3DX9LibPath);
|
||||
}
|
||||
}
|
||||
|
||||
return d3dx9;
|
||||
}
|
||||
|
||||
IVideoD3DOSD::IVideoD3DOSD(void)
|
||||
{
|
||||
osdSprite = NULL;
|
||||
osdAtlasTexture = NULL;
|
||||
osdTimeFont = NULL;
|
||||
osdTitleFont = NULL;
|
||||
streaming = 0;
|
||||
titleFits = false;
|
||||
|
||||
// Texture Src Coordinates for sprite images
|
||||
// Right and Bottom (last two) excluded from image
|
||||
SetRect(&osdBkgrndTextSrcCoords, 38, 534, 647, 635);
|
||||
|
||||
SetRect(&osdPrevButtonNormalSrcCoords, 41, 17, 63, 31);
|
||||
SetRect(&osdPlayButtonNormalSrcCoords, 145, 14, 161, 35);
|
||||
SetRect(&osdPauseButtonNormalSrcCoords, 95, 16, 110, 33);
|
||||
SetRect(&osdStopButtonNormalSrcCoords, 195, 16, 210, 33);
|
||||
SetRect(&osdNextButtonNormalSrcCoords, 242, 17, 264, 31);
|
||||
SetRect(&osdProgressFrameNormalSrcCoords, 41, 226, 606, 235);
|
||||
SetRect(&osdVolumeFrameNormalSrcCoords, 41, 294, 111, 302);
|
||||
SetRect(&osdEndFSButtonNormalSrcCoords, 41, 140, 59, 158);
|
||||
SetRect(&osdMuteButtonNormalSrcCoords, 41, 416, 51, 428);
|
||||
SetRect(&osdProgressSliderNormalSrcCoords, 41, 343, 57, 361);
|
||||
SetRect(&osdVolumeSliderNormalSrcCoords, 41, 343, 57, 361);
|
||||
SetRect(&osdProgressProgressSrcCoords, 41, 274, 606, 282); //hilited progress indicator
|
||||
SetRect(&osdVolumeProgressSrcCoords, 41, 314, 111, 322); //hilited volume indicator
|
||||
|
||||
SetRect(&osdPrevButtonClickSrcCoords, 41, 76, 63, 90);
|
||||
SetRect(&osdPlayButtonClickSrcCoords, 145, 73, 161, 94);
|
||||
SetRect(&osdPauseButtonClickSrcCoords, 95, 75, 110, 92);
|
||||
SetRect(&osdStopButtonClickSrcCoords, 195, 75, 210, 92);
|
||||
SetRect(&osdNextButtonClickSrcCoords, 242, 76, 264, 90);
|
||||
SetRect(&osdEndFSButtonClickSrcCoords, 41, 192, 59, 210);
|
||||
SetRect(&osdProgressSliderClickSrcCoords, 41, 385, 57, 403);
|
||||
SetRect(&osdVolumeSliderClickSrcCoords, 41, 385, 57, 403);
|
||||
|
||||
SetRect(&osdPrevButtonDisabledSrcCoords, 41, 106, 63, 120);
|
||||
SetRect(&osdNextButtonDisabledSrcCoords, 242, 106, 264, 120);
|
||||
|
||||
SetRect(&osdPrevButtonHiliteSrcCoords, 41, 46, 63, 60);
|
||||
SetRect(&osdPlayButtonHiliteSrcCoords, 145, 43, 161, 64);
|
||||
SetRect(&osdPauseButtonHiliteSrcCoords, 95, 45, 110, 62);
|
||||
SetRect(&osdStopButtonHiliteSrcCoords, 195, 45, 210, 62);
|
||||
SetRect(&osdNextButtonHiliteSrcCoords, 242, 46, 264, 60);
|
||||
SetRect(&osdEndFSButtonHiliteSrcCoords, 41, 166, 59, 184);
|
||||
SetRect(&osdProgressSliderHiliteSrcCoords, 41, 363, 57, 381);
|
||||
SetRect(&osdVolumeSliderHiliteSrcCoords, 41, 363, 57, 381);
|
||||
|
||||
xScalingFactor = 1.0f;
|
||||
yScalingFactor = 1.0f;
|
||||
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
bState[i] = NORMAL;
|
||||
}
|
||||
|
||||
mouseOver = NO_BUTTON;
|
||||
mouseLastOver = NO_BUTTON;
|
||||
mousePressed = NO_BUTTON;
|
||||
mouseLastPressed = NO_BUTTON;
|
||||
mouseDragging = false;
|
||||
|
||||
displayTitle = NULL;
|
||||
marqueeTitleSrc = NULL;
|
||||
titleRestart = 0;
|
||||
dtFormat = 0;
|
||||
|
||||
isInited = false;
|
||||
isReadyToDraw = false;
|
||||
}
|
||||
|
||||
RECT IVideoD3DOSD::BuildHitRect(D3DXVECTOR3 position, RECT size)
|
||||
{
|
||||
RECT hitRect;
|
||||
// casting float to long since I know the position vector will not be too big.
|
||||
hitRect.left = (long)position.x;
|
||||
hitRect.top = (long)position.y;
|
||||
hitRect.right = (long)position.x + size.right - size.left;
|
||||
hitRect.bottom = (long)position.y + size.bottom - size.top;
|
||||
return hitRect;
|
||||
}
|
||||
|
||||
IVideoD3DOSD::~IVideoD3DOSD(void)
|
||||
{
|
||||
if (osdSprite)
|
||||
{
|
||||
osdSprite->Release();
|
||||
osdSprite = NULL;
|
||||
}
|
||||
if (osdAtlasTexture)
|
||||
{
|
||||
osdAtlasTexture->Release();
|
||||
osdAtlasTexture = NULL;
|
||||
}
|
||||
if (marqueeTitleSrc)
|
||||
{
|
||||
delete [] marqueeTitleSrc;
|
||||
marqueeTitleSrc = NULL;
|
||||
}
|
||||
|
||||
if (displayTitle)
|
||||
{
|
||||
delete [] displayTitle;
|
||||
displayTitle = NULL;
|
||||
}
|
||||
|
||||
//if (d3dx_lib)
|
||||
//{
|
||||
// FreeLibrary(d3dx_lib);
|
||||
// d3dx_lib = NULL;
|
||||
//}
|
||||
}
|
||||
|
||||
void IVideoD3DOSD::SetScalingFactor(float fx, float fy)
|
||||
{
|
||||
xScalingFactor = fx;
|
||||
yScalingFactor = fy;
|
||||
}
|
||||
|
||||
void IVideoD3DOSD::CreateOSD(IDirect3DDevice9 * device)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
d3dx_lib = FindD3DX9();
|
||||
if (!d3dx_lib)
|
||||
return;
|
||||
|
||||
pCreateFontW = (D3DXCREATEFONTW) GetProcAddress(d3dx_lib,"D3DXCreateFontW");
|
||||
pCreateSprite = (D3DXCREATESPRITE) GetProcAddress(d3dx_lib,"D3DXCreateSprite");
|
||||
pCreateTextureFromResourceExW = (D3DXCREATETEXTUREFROMRESOURCEEXW) GetProcAddress(d3dx_lib,"D3DXCreateTextureFromResourceExW");
|
||||
|
||||
if (!pCreateFontW || !pCreateSprite || !pCreateTextureFromResourceExW)
|
||||
return;
|
||||
|
||||
hr = pCreateSprite(device,&osdSprite);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DXTraceW(__FILE__, __LINE__, hr, L"CreateSprite Error", TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
int font_size = -12 ;
|
||||
hr = pCreateFontW(
|
||||
device,
|
||||
font_size,
|
||||
0,
|
||||
FW_NORMAL,
|
||||
1,
|
||||
0,
|
||||
DEFAULT_CHARSET,
|
||||
OUT_DEFAULT_PRECIS,
|
||||
ANTIALIASED_QUALITY, //DEFAULT_QUALITY,
|
||||
DEFAULT_PITCH,
|
||||
L"Arial",
|
||||
&osdTimeFont);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DXTraceW(__FILE__, __LINE__, hr, L"CreateFont (Time) Error", TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
font_size = -16 ;
|
||||
hr = pCreateFontW(
|
||||
device,
|
||||
font_size,
|
||||
0,
|
||||
FW_NORMAL,
|
||||
1,
|
||||
0,
|
||||
DEFAULT_CHARSET,
|
||||
OUT_DEFAULT_PRECIS,
|
||||
ANTIALIASED_QUALITY,//DEFAULT_QUALITY,
|
||||
DEFAULT_PITCH,
|
||||
L"Trebuchet MS",
|
||||
&osdTitleFont);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DXTraceW(__FILE__, __LINE__, hr, L"CreateFont (Title) Error", TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
ResetOSD(device);
|
||||
|
||||
isInited = true;
|
||||
}
|
||||
|
||||
void IVideoD3DOSD::UpdateOSD(HWND hWnd, VideoOutput *adjuster)
|
||||
{
|
||||
// Position of sprites in screen coordinates
|
||||
// Center of sprite (where the position is mapped) is left to default to upper left corner
|
||||
// Note the Bkgrnd is positioned and then all other sprites are relative to that
|
||||
RECT clientRect;
|
||||
GetClientRect(hWnd,&clientRect);
|
||||
// Need to adjust the client rect to match the video aspect ration to fit the osd on the video.
|
||||
// adjuster->adjustAspect(clientRect);
|
||||
// width of the client area - width of the bkgrnd / 2 gives the space on each side
|
||||
// add that space to the offset of the left side of the client area.
|
||||
float xPosBkg = clientRect.left +
|
||||
(((clientRect.right - clientRect.left) - (osdBkgrndTextSrcCoords.right - osdBkgrndTextSrcCoords.left))/2.0f);
|
||||
// width of the client area * .95 give the location of the bottom of the osd (i.e. 5% from bottom)
|
||||
// that minus the height of the bkgrnd gives the location of the upper left of background
|
||||
// add that space to the offset of the top of the client area.
|
||||
float yPosBkg = clientRect.top +
|
||||
(((clientRect.bottom - clientRect.top) * 1.0f) - (osdBkgrndTextSrcCoords.bottom - osdBkgrndTextSrcCoords.top));
|
||||
osdBkgrndPosition = D3DXVECTOR3(floor(xPosBkg), floor(yPosBkg), 0.0f);
|
||||
|
||||
osdPrevButtonPosition = osdBkgrndPosition + D3DXVECTOR3(191.0f, 75.0f, 0.0f);
|
||||
osdPlayButtonPosition = osdBkgrndPosition + D3DXVECTOR3(246.0f, 72.0f, 0.0f);
|
||||
osdPauseButtonPosition = osdBkgrndPosition + D3DXVECTOR3(296.0f, 74.0f, 0.0f);
|
||||
osdStopButtonPosition = osdBkgrndPosition + D3DXVECTOR3(345.5f, 74.0f, 0.0f);
|
||||
osdNextButtonPosition = osdBkgrndPosition + D3DXVECTOR3(392.5f, 75.0f, 0.0f);
|
||||
osdProgressFramePosition = osdBkgrndPosition + D3DXVECTOR3(22.0f, 49.0f, 0.0f);
|
||||
osdVolumeFramePosition = osdBkgrndPosition + D3DXVECTOR3(518.0f, 76.0f, 0.0f);
|
||||
osdEndFSButtonPosition = osdBkgrndPosition + D3DXVECTOR3(583.0f, 19.0f, 0.0f);
|
||||
osdMuteButtonPosition = osdVolumeFramePosition + D3DXVECTOR3(-15.0f, -1.0f, 0.0f);
|
||||
osdProgressSliderPosition = osdProgressFramePosition + D3DXVECTOR3(0.0f, 0.0f, 0.0f);
|
||||
osdVolumeSliderPosition = osdVolumeFramePosition + D3DXVECTOR3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
SetRect(&osdTimeRect,
|
||||
(long)osdBkgrndPosition.x + 26,
|
||||
(long)osdBkgrndPosition.y + 76,
|
||||
(long)osdBkgrndPosition.x + 98,
|
||||
(long)osdBkgrndPosition.y + 85);
|
||||
|
||||
SetRect(&osdTitleRect,
|
||||
(long)osdBkgrndPosition.x + 26,
|
||||
(long)osdBkgrndPosition.y + 17,
|
||||
(long)osdBkgrndPosition.x + 503,
|
||||
(long)osdBkgrndPosition.y + 37);
|
||||
|
||||
// Create Hit Test Rects for ui elements that don't move
|
||||
osdPrevButtonHit = BuildHitRect(osdPrevButtonPosition, osdPrevButtonNormalSrcCoords );
|
||||
osdPlayButtonHit = BuildHitRect(osdPlayButtonPosition, osdPlayButtonNormalSrcCoords );
|
||||
osdPauseButtonHit = BuildHitRect(osdPauseButtonPosition, osdPauseButtonNormalSrcCoords );
|
||||
osdStopButtonHit = BuildHitRect(osdStopButtonPosition, osdStopButtonNormalSrcCoords );
|
||||
osdNextButtonHit = BuildHitRect(osdNextButtonPosition, osdNextButtonNormalSrcCoords );
|
||||
osdEndFSButtonHit = BuildHitRect(osdEndFSButtonPosition, osdEndFSButtonNormalSrcCoords);
|
||||
osdProgressFrameHit = BuildHitRect(osdProgressFramePosition, osdProgressFrameNormalSrcCoords);
|
||||
osdVolumeFrameHit = BuildHitRect(osdVolumeFramePosition, osdVolumeFrameNormalSrcCoords);
|
||||
|
||||
streaming = (in_getlength() < 0) || !in_mod || !in_mod->is_seekable;
|
||||
if (streaming)
|
||||
{
|
||||
bState[PREV_BUTTON] = DISABLED;
|
||||
bState[NEXT_BUTTON] = DISABLED;
|
||||
bState[PROGRESS_FRAME] = DISABLED;
|
||||
bState[PROGRESS_SLIDER] = DISABLED;
|
||||
}
|
||||
|
||||
// Find out if the title will fit in the UI space for it
|
||||
RECT tempTitleRect = osdTitleRect;
|
||||
osdTitleFont->DrawTextW(NULL, FileTitle, -1, &tempTitleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOCLIP | DT_CALCRECT, D3DCOLOR_XRGB(255,255,255));
|
||||
if (tempTitleRect.right <= osdTitleRect.right)
|
||||
{
|
||||
// The title fits, just use it
|
||||
titleFits = true;
|
||||
displayTitle = FileTitle;
|
||||
dtFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOCLIP;
|
||||
} else
|
||||
{
|
||||
// title will not fit, we need to set up a marquee.
|
||||
//
|
||||
// a string with two copies of the title makes it easier to process
|
||||
// sizeNeeded, in chars, includes one space, five dots,
|
||||
// one space and 1 extra for null.
|
||||
size_t sizeNeeded = (lstrlenW(FileTitle)*2) + 8;
|
||||
marqueeTitleSrc = new wchar_t[sizeNeeded];
|
||||
displayTitle = new wchar_t[sizeNeeded];
|
||||
titleRestart = lstrlenW(FileTitle);
|
||||
StringCchPrintfW(marqueeTitleSrc, sizeNeeded, L"%s ..... %s", FileTitle, FileTitle);
|
||||
titleFits = false;
|
||||
dtFormat = DT_RIGHT | DT_TOP | DT_SINGLELINE;
|
||||
}
|
||||
|
||||
isReadyToDraw = true;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
#define DRAW_OSD_SET_ERROR(x) draw_osd_error=x
|
||||
#else
|
||||
#define DRAW_OSD_SET_ERROR(x)
|
||||
#endif
|
||||
|
||||
void IVideoD3DOSD::DrawOSD(IDirect3DDevice9 * device)
|
||||
{
|
||||
HRESULT hr;
|
||||
D3DXVECTOR3 sliderCenter(8.0f, 8.0f, 0.0f);
|
||||
|
||||
const wchar_t *draw_osd_error;
|
||||
hr = osdSprite->Begin(D3DXSPRITE_ALPHABLEND);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
|
||||
DXTraceW(__FILE__, __LINE__, hr, L"Sprite Begin Error", TRUE);
|
||||
return ;
|
||||
}
|
||||
|
||||
// Doing Scaling of sprites here
|
||||
// If we do translations and/or rotations we'll have to do a more
|
||||
// robust hit test (picking) since the current one assumes a rectangular
|
||||
// shape based on screen coordinates. Only scaling is currently handled
|
||||
// in the hit test.
|
||||
//D3DXMATRIX scalingMatrix;
|
||||
//osdSprite->SetTransform(D3DXMatrixScaling(&scalingMatrix, 1.0f /*xScalingFactor*/, 1.0f /*yScalingFactor*/, 0.0f));
|
||||
|
||||
hr = osdSprite->Draw(osdAtlasTexture, &osdBkgrndTextSrcCoords, NULL, &osdBkgrndPosition, D3DCOLOR_XRGB(255,255,255));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DRAW_OSD_SET_ERROR(L"Background Sprite Draw Error");
|
||||
goto DrawOSD_Error;
|
||||
}
|
||||
hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(PREV_BUTTON), NULL, &osdPrevButtonPosition, D3DCOLOR_XRGB(255,255,255));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DRAW_OSD_SET_ERROR(L"Prev Button Sprite Draw Error");
|
||||
goto DrawOSD_Error;
|
||||
}
|
||||
hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(PLAY_BUTTON), NULL, &osdPlayButtonPosition, D3DCOLOR_XRGB(255,255,255));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DRAW_OSD_SET_ERROR(L"Play Button Sprite Draw Error");
|
||||
goto DrawOSD_Error;
|
||||
}
|
||||
hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(PAUSE_BUTTON), NULL, &osdPauseButtonPosition, D3DCOLOR_XRGB(255,255,255));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DRAW_OSD_SET_ERROR(L"Pause Button Sprite Draw Error");
|
||||
goto DrawOSD_Error;
|
||||
}
|
||||
hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(STOP_BUTTON), NULL, &osdStopButtonPosition, D3DCOLOR_XRGB(255,255,255));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DRAW_OSD_SET_ERROR(L"Stop Button Sprite Draw Error");
|
||||
goto DrawOSD_Error;
|
||||
}
|
||||
hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(NEXT_BUTTON), NULL, &osdNextButtonPosition, D3DCOLOR_XRGB(255,255,255));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DRAW_OSD_SET_ERROR(L"Next Button Sprite Draw Error");
|
||||
goto DrawOSD_Error;
|
||||
}
|
||||
hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(PROGRESS_FRAME), NULL, &osdProgressFramePosition, D3DCOLOR_XRGB(255,255,255));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DRAW_OSD_SET_ERROR(L"Progress Frame Sprite Draw Error");
|
||||
goto DrawOSD_Error;
|
||||
}
|
||||
hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(VOLUME_FRAME), NULL, &osdVolumeFramePosition, D3DCOLOR_XRGB(255,255,255));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DRAW_OSD_SET_ERROR(L"Volume Frame Sprite Draw Error");
|
||||
goto DrawOSD_Error;
|
||||
}
|
||||
hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(ENDFS_BUTTON), NULL, &osdEndFSButtonPosition, D3DCOLOR_XRGB(255,255,255));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DRAW_OSD_SET_ERROR(L"EndFS Button Sprite Draw Error");
|
||||
goto DrawOSD_Error;
|
||||
}
|
||||
hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(MUTE_BUTTON), NULL, &osdMuteButtonPosition, D3DCOLOR_XRGB(255,255,255));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DRAW_OSD_SET_ERROR(L"Mute Button Sprite Draw Error");
|
||||
goto DrawOSD_Error;
|
||||
}
|
||||
|
||||
if (playing && !streaming && !mouseDragging) // if mouseDragging we may be repositioning the slider, don't set it back till Lmouseup
|
||||
{
|
||||
// calculate the relative position of the slider
|
||||
float ppercent = (in_getouttime() / 1000.0f) / in_getlength();
|
||||
float sizeOfProgFrame = (float)osdProgressFrameHit.right - osdProgressFrameHit.left - 0;
|
||||
// position the progress slider
|
||||
osdProgressSliderPosition.x = osdProgressFramePosition.x + (sizeOfProgFrame * ppercent);
|
||||
// Now build the hit rect based on the new position.
|
||||
osdProgressSliderHit = BuildHitRect(osdProgressSliderPosition + D3DXVECTOR3(0.0f,0.0f,0.0f), osdProgressSliderNormalSrcCoords);
|
||||
}
|
||||
|
||||
|
||||
hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(PROGRESS_SLIDER), &sliderCenter, &osdProgressSliderPosition, D3DCOLOR_XRGB(255,255,255));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DRAW_OSD_SET_ERROR(L"Progress Slider Sprite Draw Error");
|
||||
goto DrawOSD_Error;
|
||||
}
|
||||
|
||||
// Build the progress hilite line by drawing only a certain amount (width) of the texture.
|
||||
RECT seekProgress;
|
||||
// The progress hilite line goes on top of progress frame
|
||||
seekProgress = osdProgressProgressSrcCoords;
|
||||
// The width of the progress hilite line is determined by the location of the slider
|
||||
seekProgress.right = seekProgress.left + (osdProgressSliderHit.left - osdProgressFrameHit.left + 0);
|
||||
|
||||
hr = osdSprite->Draw(osdAtlasTexture,
|
||||
&seekProgress,
|
||||
NULL,
|
||||
&osdProgressFramePosition,
|
||||
D3DCOLOR_XRGB(255,255,255));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DRAW_OSD_SET_ERROR(L"Seek Progress Sprite Draw Error");
|
||||
goto DrawOSD_Error;
|
||||
}
|
||||
|
||||
if (!mouseDragging) // if mouseDragging we may be repositioning the slider, don't set it back till Lmouseup
|
||||
{
|
||||
// calculate the relative position of the slider
|
||||
float vpercent = config_volume / 255.0f;
|
||||
float sizeOfVolFrame = (float)osdVolumeFrameHit.right - osdVolumeFrameHit.left - 0;
|
||||
// position the volume slider
|
||||
osdVolumeSliderPosition.x = (osdVolumeFramePosition.x) + (sizeOfVolFrame * vpercent);
|
||||
// Now build the hit rect based on the new position.
|
||||
osdVolumeSliderHit = BuildHitRect(osdVolumeSliderPosition + D3DXVECTOR3(0.0f,0.0f,0.0f), osdVolumeSliderNormalSrcCoords);
|
||||
}
|
||||
hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(VOLUME_SLIDER), &sliderCenter, &osdVolumeSliderPosition, D3DCOLOR_XRGB(255,255,255));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DRAW_OSD_SET_ERROR(L"Volume SLider Sprite Draw Error");
|
||||
goto DrawOSD_Error;
|
||||
}
|
||||
|
||||
// Build the volume hilite line by drawing only a certain amount (width) of the texture.
|
||||
RECT volProgress;
|
||||
// The volume hilite line goes on top of volume frame
|
||||
volProgress = osdVolumeProgressSrcCoords;
|
||||
// The width of the volume hilite line is determined by the location of the slider
|
||||
volProgress.right = volProgress.left + (osdVolumeSliderHit.left - osdVolumeFrameHit.left + 0);
|
||||
|
||||
hr = osdSprite->Draw(osdAtlasTexture,
|
||||
&volProgress,
|
||||
NULL,
|
||||
&osdVolumeFramePosition,
|
||||
D3DCOLOR_XRGB(255,255,255));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DRAW_OSD_SET_ERROR(L"Volume Progress Sprite Draw Error");
|
||||
goto DrawOSD_Error;
|
||||
}
|
||||
|
||||
|
||||
if (osdTimeFont)
|
||||
{
|
||||
int seconds_in = in_getouttime() / 1000;
|
||||
int time_to_go = in_getlength();
|
||||
|
||||
wchar_t timerText[256] = {0};
|
||||
if (streaming)
|
||||
StringCbPrintfW(timerText,sizeof(timerText),L"%.2u:%.2u",seconds_in /60,seconds_in % 60);
|
||||
else
|
||||
StringCbPrintfW(timerText,sizeof(timerText),L"%.2u:%.2u / %.2u:%.2u",seconds_in /60,seconds_in % 60,time_to_go / 60, time_to_go % 60);
|
||||
osdTimeFont->DrawTextW(osdSprite, timerText, -1, &osdTimeRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOCLIP, D3DCOLOR_XRGB(163,164,167)); // #A3A4A7
|
||||
}
|
||||
|
||||
if (osdTitleFont)
|
||||
{
|
||||
// found possibility that user can pause in full screen and remove items from playlist
|
||||
// This prevents a crash by not trying to display a title.
|
||||
if (lstrlenW(FileTitle) > 0)
|
||||
{
|
||||
if (!titleFits)
|
||||
{
|
||||
// title does not fit, build marquee
|
||||
DWORD now = GetTickCount();
|
||||
static DWORD then;
|
||||
if (now - then > 250) // slow it down so people can read it.
|
||||
{
|
||||
static int charCount = 2; // start with the first char + 1 for null
|
||||
lstrcpynW(displayTitle,marqueeTitleSrc,charCount);
|
||||
charCount++;
|
||||
if (charCount > lstrlenW(marqueeTitleSrc))
|
||||
charCount = lstrlenW(FileTitle);
|
||||
then = now;
|
||||
}
|
||||
}
|
||||
|
||||
osdTitleFont->DrawTextW(osdSprite, displayTitle, -1, &osdTitleRect, dtFormat, D3DCOLOR_XRGB(204,204,204)); // #cccccc
|
||||
}
|
||||
}
|
||||
|
||||
hr = osdSprite->End();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DXTraceW(__FILE__, __LINE__, hr, L"Sprite End Error", TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
DrawOSD_Error:
|
||||
DXTraceW(__FILE__, __LINE__, hr, draw_osd_error, TRUE);
|
||||
osdSprite->End();
|
||||
}
|
||||
|
||||
RECT *IVideoD3DOSD::GetTextCoords(UI_ELEM item)
|
||||
{
|
||||
switch (item)
|
||||
{
|
||||
case PREV_BUTTON :
|
||||
switch (bState[item])
|
||||
{
|
||||
case NORMAL :
|
||||
return &osdPrevButtonNormalSrcCoords;
|
||||
break;
|
||||
case CLICKED :
|
||||
return &osdPrevButtonClickSrcCoords;
|
||||
break;
|
||||
case HILITE :
|
||||
return &osdPrevButtonHiliteSrcCoords;
|
||||
break;
|
||||
case DISABLED :
|
||||
return &osdPrevButtonDisabledSrcCoords;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case PLAY_BUTTON :
|
||||
switch (bState[item])
|
||||
{
|
||||
case NORMAL :
|
||||
case DISABLED :
|
||||
return &osdPlayButtonNormalSrcCoords;
|
||||
break;
|
||||
case CLICKED :
|
||||
return &osdPlayButtonClickSrcCoords;
|
||||
break;
|
||||
case HILITE :
|
||||
return &osdPlayButtonHiliteSrcCoords;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case PAUSE_BUTTON :
|
||||
switch (bState[item])
|
||||
{
|
||||
case NORMAL :
|
||||
case DISABLED :
|
||||
return &osdPauseButtonNormalSrcCoords;
|
||||
break;
|
||||
case CLICKED :
|
||||
return &osdPauseButtonClickSrcCoords;
|
||||
break;
|
||||
case HILITE :
|
||||
return &osdPauseButtonHiliteSrcCoords;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case STOP_BUTTON :
|
||||
switch (bState[item])
|
||||
{
|
||||
case NORMAL :
|
||||
case DISABLED :
|
||||
return &osdStopButtonNormalSrcCoords;
|
||||
break;
|
||||
case CLICKED :
|
||||
return &osdStopButtonClickSrcCoords;
|
||||
break;
|
||||
case HILITE :
|
||||
return &osdStopButtonHiliteSrcCoords;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case NEXT_BUTTON :
|
||||
switch (bState[item])
|
||||
{
|
||||
case NORMAL :
|
||||
return &osdNextButtonNormalSrcCoords;
|
||||
break;
|
||||
case CLICKED :
|
||||
return &osdNextButtonClickSrcCoords;
|
||||
break;
|
||||
case HILITE :
|
||||
return &osdNextButtonHiliteSrcCoords;
|
||||
break;
|
||||
case DISABLED :
|
||||
return &osdNextButtonDisabledSrcCoords;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case ENDFS_BUTTON :
|
||||
switch (bState[item])
|
||||
{
|
||||
case NORMAL :
|
||||
case DISABLED :
|
||||
return &osdEndFSButtonNormalSrcCoords;
|
||||
break;
|
||||
case CLICKED :
|
||||
return &osdEndFSButtonClickSrcCoords;
|
||||
break;
|
||||
case HILITE :
|
||||
return &osdEndFSButtonHiliteSrcCoords;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case MUTE_BUTTON :
|
||||
return &osdMuteButtonNormalSrcCoords;
|
||||
//switch (bState[item])
|
||||
//{
|
||||
//case NORMAL :
|
||||
//case DISABLED :
|
||||
// return &osdMuteButtonNormalSrcCoords;
|
||||
// break;
|
||||
//case CLICKED :
|
||||
// return &osdMuteButtonClickSrcCoords;
|
||||
// break;
|
||||
//case HILITE :
|
||||
// return &osdMuteButtonHiliteSrcCoords;
|
||||
// break;
|
||||
//}
|
||||
|
||||
break;
|
||||
case PROGRESS_FRAME :
|
||||
return &osdProgressFrameNormalSrcCoords;
|
||||
|
||||
break;
|
||||
case VOLUME_FRAME :
|
||||
return &osdVolumeFrameNormalSrcCoords;
|
||||
|
||||
break;
|
||||
case PROGRESS_SLIDER :
|
||||
switch (bState[item])
|
||||
{
|
||||
case NORMAL :
|
||||
case DISABLED :
|
||||
return &osdProgressSliderNormalSrcCoords;
|
||||
break;
|
||||
case CLICKED :
|
||||
return &osdProgressSliderClickSrcCoords;
|
||||
break;
|
||||
case HILITE :
|
||||
return &osdProgressSliderHiliteSrcCoords;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case VOLUME_SLIDER :
|
||||
switch (bState[item])
|
||||
{
|
||||
case NORMAL :
|
||||
case DISABLED :
|
||||
return &osdVolumeSliderNormalSrcCoords;
|
||||
break;
|
||||
case CLICKED :
|
||||
return &osdVolumeSliderClickSrcCoords;
|
||||
break;
|
||||
case HILITE :
|
||||
return &osdVolumeSliderHiliteSrcCoords;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void IVideoD3DOSD::LostOSD()
|
||||
{
|
||||
if (osdSprite)
|
||||
osdSprite->OnLostDevice();
|
||||
if (osdTimeFont)
|
||||
osdTimeFont->OnLostDevice();
|
||||
if (osdTitleFont)
|
||||
osdTitleFont->OnLostDevice();
|
||||
if (osdAtlasTexture)
|
||||
{
|
||||
osdAtlasTexture->Release();
|
||||
osdAtlasTexture = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void IVideoD3DOSD::ResetOSD(IDirect3DDevice9 * device)
|
||||
{
|
||||
if (osdSprite)
|
||||
osdSprite->OnResetDevice();
|
||||
if (osdTimeFont)
|
||||
osdTimeFont->OnResetDevice();
|
||||
if (osdTitleFont)
|
||||
osdTitleFont->OnResetDevice();
|
||||
|
||||
if (device)
|
||||
{
|
||||
HRESULT hr;
|
||||
hr = pCreateTextureFromResourceExW(
|
||||
device,
|
||||
NULL, // HMODULE
|
||||
MAKEINTRESOURCEW(IDB_OSD), // Our texture image atlas
|
||||
D3DX_DEFAULT, // width
|
||||
D3DX_DEFAULT, // height
|
||||
1, // MIP levels
|
||||
0, // usage
|
||||
D3DFMT_UNKNOWN, // get format from file
|
||||
D3DPOOL_DEFAULT, // mem pool
|
||||
D3DX_DEFAULT, // filter
|
||||
D3DX_DEFAULT, // MIP filter
|
||||
0, // transparent color key
|
||||
NULL, // image info struct
|
||||
NULL, // palette
|
||||
&osdAtlasTexture); // the returned texture, if success
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DXTraceW(__FILE__, __LINE__, hr, L"CreateTextureFromFileEx Error", TRUE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool IVideoD3DOSD::MouseDown(int xpt, int ypt, WPARAM wParam)
|
||||
{
|
||||
Show();
|
||||
// mouseLastPressed is used during mouse up to verify that the up is on the
|
||||
// same UI element as the mouse down.
|
||||
mouseLastPressed = HitTest((float)xpt, (float)ypt);
|
||||
bState[mouseLastPressed] = CLICKED;
|
||||
return false;
|
||||
}
|
||||
bool IVideoD3DOSD::MouseMove(int ixpt, int iypt, WPARAM wParam)
|
||||
{
|
||||
static int saved_ixpt;
|
||||
static int saved_iypt;
|
||||
|
||||
// Need to check whether the mouse cursor is still in the same place.
|
||||
// Evidently, WM_MOUSEMOVE can get triggered for other reasons than
|
||||
// actually moving the mouse, per Microsoft blogs
|
||||
// This code was triggering with IM and EMAIL notifications without
|
||||
// moving the mouse.
|
||||
if (ixpt == saved_ixpt && iypt == saved_iypt)
|
||||
return false;
|
||||
|
||||
saved_ixpt = ixpt;
|
||||
saved_iypt = iypt;
|
||||
|
||||
Show();
|
||||
|
||||
// Change input ints to floats so later calculations are more precise.
|
||||
float xpt = (float)ixpt;
|
||||
float ypt = (float)iypt;
|
||||
|
||||
mouseOver = HitTest((float)xpt, (float)ypt);
|
||||
if (wParam & MK_LBUTTON) //dragging
|
||||
{
|
||||
mouseDragging = true;
|
||||
if (mouseLastPressed == VOLUME_SLIDER)
|
||||
{
|
||||
if (xpt < (osdVolumeFrameHit.left)) xpt = (float) osdVolumeFrameHit.left;
|
||||
else if (xpt > (osdVolumeFrameHit.right) - 0) xpt = (float) osdVolumeFrameHit.right - 0;
|
||||
|
||||
//move the volume slider
|
||||
osdVolumeSliderPosition.x = xpt;
|
||||
// slider uses center as center
|
||||
osdVolumeSliderHit = BuildHitRect(osdVolumeSliderPosition + D3DXVECTOR3(0.0f,0.0f,0.0f),osdVolumeSliderNormalSrcCoords);
|
||||
}
|
||||
else if (mouseLastPressed == PROGRESS_SLIDER)
|
||||
{
|
||||
if (xpt < osdProgressFrameHit.left) xpt = (float)osdProgressFrameHit.left;
|
||||
else if (xpt > (osdProgressFrameHit.right)) xpt = (float)osdProgressFrameHit.right;
|
||||
|
||||
//move the progress slider
|
||||
osdProgressSliderPosition.x = xpt;
|
||||
osdProgressSliderHit = BuildHitRect(osdProgressSliderPosition + D3DXVECTOR3(0.0f,0.0f,0.0f),osdProgressSliderNormalSrcCoords);
|
||||
}
|
||||
} else // no click, just mousemove
|
||||
{
|
||||
mouseDragging = false;
|
||||
if (mouseLastOver != mouseOver)
|
||||
{
|
||||
if (bState[mouseLastOver] == HILITE)
|
||||
bState[mouseLastOver] = NORMAL;
|
||||
if (bState[mouseOver] == NORMAL)
|
||||
bState[mouseOver] = HILITE;
|
||||
mouseLastOver = mouseOver;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IVideoD3DOSD::MouseUp(int xpt, int ypt, WPARAM wParam)
|
||||
{
|
||||
mousePressed = HitTest((float)xpt, (float)ypt);
|
||||
|
||||
bState[mouseLastPressed] = NORMAL;
|
||||
|
||||
if (bState[mousePressed] == HILITE)
|
||||
bState[mousePressed] = NORMAL;
|
||||
|
||||
mouseDragging = false;
|
||||
|
||||
switch (mousePressed)
|
||||
{
|
||||
case ENDFS_BUTTON :
|
||||
if (mouseLastPressed == ENDFS_BUTTON)
|
||||
return true; // end full screen
|
||||
break;
|
||||
case PREV_BUTTON :
|
||||
if (mouseLastPressed == PREV_BUTTON)
|
||||
PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON1, 0);
|
||||
break;
|
||||
case PLAY_BUTTON :
|
||||
if (mouseLastPressed == PLAY_BUTTON)
|
||||
PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON2, 0);
|
||||
break;
|
||||
case PAUSE_BUTTON :
|
||||
if (mouseLastPressed == PAUSE_BUTTON)
|
||||
PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON3, 0);
|
||||
break;
|
||||
case STOP_BUTTON :
|
||||
if (mouseLastPressed == STOP_BUTTON)
|
||||
PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON4, 0);
|
||||
break;
|
||||
case NEXT_BUTTON :
|
||||
if (mouseLastPressed == NEXT_BUTTON)
|
||||
PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON5, 0);
|
||||
break;
|
||||
default :
|
||||
{
|
||||
// If not a button, check the sliders
|
||||
// The successful use of the sliders should not depend on
|
||||
// releasing the mouse inside the frame, which may be very small.
|
||||
switch (mouseLastPressed)
|
||||
{
|
||||
case PROGRESS_SLIDER :
|
||||
case PROGRESS_FRAME :
|
||||
{
|
||||
float xIntoFrame = (float)xpt - osdProgressFrameHit.left;
|
||||
// -8 is half the width of the slider
|
||||
float rightMaxOfFrame = (float)osdProgressFrameHit.right - 0;
|
||||
float leftMinOfFrame = (float)osdProgressFrameHit.left;
|
||||
float sizeOfFrame = rightMaxOfFrame - leftMinOfFrame;
|
||||
float t = xIntoFrame / sizeOfFrame;
|
||||
if (t < 0)
|
||||
t = 0;
|
||||
if (t > 1)
|
||||
t = 1;
|
||||
|
||||
int len = in_getlength();
|
||||
in_seek((int)(t*len*1000));
|
||||
}
|
||||
break;
|
||||
case VOLUME_SLIDER :
|
||||
case VOLUME_FRAME :
|
||||
{
|
||||
float xIntoFrame = (float)xpt - (osdVolumeFrameHit.left);
|
||||
// -8 is half the width of the slider
|
||||
float rightMaxOfFrame = (float)osdVolumeFrameHit.right - 0;
|
||||
float leftMinOfFrame = (float)osdVolumeFrameHit.left;
|
||||
float sizeOfFrame = rightMaxOfFrame - leftMinOfFrame;
|
||||
float t = xIntoFrame / sizeOfFrame;
|
||||
|
||||
if (t < 0)
|
||||
t = 0;
|
||||
if (t > 1)
|
||||
t = 1;
|
||||
|
||||
unsigned char v = (unsigned char)(t * 255);
|
||||
|
||||
config_volume = v;
|
||||
|
||||
in_setvol(v);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
mouseLastPressed = NO_BUTTON;
|
||||
return false;
|
||||
}
|
||||
|
||||
IVideoD3DOSD::UI_ELEM IVideoD3DOSD::HitTest(float xpt, float ypt)
|
||||
{
|
||||
if (PointInRect(xpt, ypt, osdPrevButtonHit))
|
||||
return PREV_BUTTON;
|
||||
else if (PointInRect(xpt, ypt, osdPlayButtonHit))
|
||||
return PLAY_BUTTON;
|
||||
else if (PointInRect(xpt, ypt, osdPauseButtonHit))
|
||||
return PAUSE_BUTTON;
|
||||
else if (PointInRect(xpt, ypt, osdStopButtonHit))
|
||||
return STOP_BUTTON;
|
||||
else if (PointInRect(xpt, ypt, osdNextButtonHit))
|
||||
return NEXT_BUTTON;
|
||||
else if (PointInRect(xpt, ypt, osdEndFSButtonHit))
|
||||
return ENDFS_BUTTON;
|
||||
else if (PointInRect(xpt, ypt, osdVolumeSliderHit))
|
||||
return VOLUME_SLIDER;
|
||||
else if (PointInRect(xpt, ypt, osdProgressSliderHit))
|
||||
return PROGRESS_SLIDER;
|
||||
else if (PointInRect(xpt, ypt, osdProgressFrameHit))
|
||||
return PROGRESS_FRAME;
|
||||
else if (PointInRect(xpt, ypt, osdVolumeFrameHit))
|
||||
return VOLUME_FRAME;
|
||||
else
|
||||
return NO_BUTTON;
|
||||
}
|
||||
|
||||
bool IVideoD3DOSD::PointInRect(float x, float y, RECT testRect)
|
||||
{
|
||||
if ((x >= testRect.left) && (x <= testRect.right) &&
|
||||
(y >= testRect.top) && (y <= testRect.bottom))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
#pragma once
|
||||
#include <d3d9.h>
|
||||
#include <d3dx9.h>
|
||||
#include <dxerr.h>
|
||||
#include "videoosd.h"
|
||||
#include "videooutput.h"
|
||||
#include "resource.h"
|
||||
|
||||
extern HWND hMainWindow;
|
||||
|
||||
|
||||
class IVideoD3DOSD :
|
||||
public IVideoOSD
|
||||
{
|
||||
public:
|
||||
IVideoD3DOSD(void);
|
||||
~IVideoD3DOSD(void);
|
||||
|
||||
enum UI_ELEM
|
||||
{
|
||||
NO_BUTTON,
|
||||
PREV_BUTTON,
|
||||
PLAY_BUTTON,
|
||||
PAUSE_BUTTON,
|
||||
STOP_BUTTON,
|
||||
NEXT_BUTTON,
|
||||
ENDFS_BUTTON,
|
||||
MUTE_BUTTON,
|
||||
PROGRESS_FRAME,
|
||||
VOLUME_FRAME,
|
||||
PROGRESS_SLIDER,
|
||||
VOLUME_SLIDER
|
||||
};
|
||||
|
||||
enum BUTTON_STATE
|
||||
{
|
||||
NORMAL,
|
||||
CLICKED,
|
||||
HILITE,
|
||||
DISABLED
|
||||
};
|
||||
|
||||
void CreateOSD(IDirect3DDevice9 * device);
|
||||
void UpdateOSD(HWND hWnd, VideoOutput *adjuster);
|
||||
void DrawOSD(IDirect3DDevice9 * device);
|
||||
void LostOSD();
|
||||
void ResetOSD(IDirect3DDevice9 *device);
|
||||
UI_ELEM HitTest(float x, float y);
|
||||
bool MouseDown(int xpt, int ypt, WPARAM wParam);
|
||||
bool MouseMove(int xpt, int ypt, WPARAM wParam);
|
||||
bool MouseUp(int xpt, int ypt, WPARAM wParam);
|
||||
void SetScalingFactor(float x, float y);
|
||||
bool isOSDInited(){return isInited;}
|
||||
bool isOSDReadyToDraw(){return isReadyToDraw;};
|
||||
|
||||
protected:
|
||||
ID3DXSprite *osdSprite;
|
||||
IDirect3DTexture9 *osdAtlasTexture;
|
||||
ID3DXFont *osdTimeFont;
|
||||
ID3DXFont *osdTitleFont;
|
||||
|
||||
// Texture Src Coordinates for sprite images
|
||||
// Right and Bottom (last two) excluded from image
|
||||
RECT osdPrevButtonNormalSrcCoords;
|
||||
RECT osdPlayButtonNormalSrcCoords;
|
||||
RECT osdPauseButtonNormalSrcCoords;
|
||||
RECT osdStopButtonNormalSrcCoords;
|
||||
RECT osdNextButtonNormalSrcCoords;
|
||||
RECT osdProgressFrameNormalSrcCoords;
|
||||
RECT osdVolumeFrameNormalSrcCoords;
|
||||
RECT osdEndFSButtonNormalSrcCoords;
|
||||
RECT osdMuteButtonNormalSrcCoords;
|
||||
RECT osdProgressSliderNormalSrcCoords;
|
||||
RECT osdVolumeSliderNormalSrcCoords;
|
||||
RECT osdProgressProgressSrcCoords;
|
||||
RECT osdVolumeProgressSrcCoords;
|
||||
|
||||
RECT osdPrevButtonClickSrcCoords;
|
||||
RECT osdPlayButtonClickSrcCoords;
|
||||
RECT osdPauseButtonClickSrcCoords;
|
||||
RECT osdStopButtonClickSrcCoords;
|
||||
RECT osdNextButtonClickSrcCoords;
|
||||
RECT osdEndFSButtonClickSrcCoords;
|
||||
RECT osdProgressSliderClickSrcCoords;
|
||||
RECT osdVolumeSliderClickSrcCoords;
|
||||
|
||||
RECT osdPrevButtonDisabledSrcCoords;
|
||||
RECT osdNextButtonDisabledSrcCoords;
|
||||
// RECT osdProgressFrameDisabledSrcCoords;
|
||||
// RECT osdProgressSliderDisabledSrcCoords;
|
||||
|
||||
RECT osdPrevButtonHiliteSrcCoords;
|
||||
RECT osdPlayButtonHiliteSrcCoords;
|
||||
RECT osdPauseButtonHiliteSrcCoords;
|
||||
RECT osdStopButtonHiliteSrcCoords;
|
||||
RECT osdNextButtonHiliteSrcCoords;
|
||||
// RECT osdProgressFrameHiliteSrcCoords;
|
||||
// RECT osdVolumeFrameHiliteSrcCoords;
|
||||
RECT osdEndFSButtonHiliteSrcCoords;
|
||||
RECT osdProgressSliderHiliteSrcCoords;
|
||||
RECT osdVolumeSliderHiliteSrcCoords;
|
||||
|
||||
RECT osdBkgrndTextSrcCoords;
|
||||
RECT osdTimeRect;
|
||||
RECT osdTitleRect;
|
||||
|
||||
// Position of sprites in screen coordinates
|
||||
// Center of sprite (where the position is mapped) is left to default to upper left corner
|
||||
// except for progress and volume sliders, which are mapped to their center
|
||||
// Note the Bkgrnd is positioned and then all other sprites are relative to that
|
||||
D3DXVECTOR3 osdBkgrndPosition;
|
||||
D3DXVECTOR3 osdPrevButtonPosition;
|
||||
D3DXVECTOR3 osdPlayButtonPosition;
|
||||
D3DXVECTOR3 osdPauseButtonPosition;
|
||||
D3DXVECTOR3 osdStopButtonPosition;
|
||||
D3DXVECTOR3 osdNextButtonPosition;
|
||||
D3DXVECTOR3 osdProgressFramePosition;
|
||||
D3DXVECTOR3 osdVolumeFramePosition;
|
||||
D3DXVECTOR3 osdEndFSButtonPosition;
|
||||
D3DXVECTOR3 osdMuteButtonPosition;
|
||||
D3DXVECTOR3 osdProgressSliderPosition;
|
||||
D3DXVECTOR3 osdVolumeSliderPosition;
|
||||
|
||||
// Hit test rects for buttons
|
||||
RECT osdPrevButtonHit;
|
||||
RECT osdPlayButtonHit;
|
||||
RECT osdPauseButtonHit;
|
||||
RECT osdStopButtonHit;
|
||||
RECT osdNextButtonHit;
|
||||
RECT osdEndFSButtonHit;
|
||||
RECT osdProgressFrameHit;
|
||||
RECT osdVolumeFrameHit;
|
||||
RECT osdProgressSliderHit;
|
||||
RECT osdVolumeSliderHit;
|
||||
|
||||
float xScalingFactor;
|
||||
float yScalingFactor;
|
||||
BUTTON_STATE bState[12]; // bState[0] is for NO_BUTTON
|
||||
bool streaming;
|
||||
wchar_t *displayTitle; // title displayed in osd UI
|
||||
wchar_t *marqueeTitleSrc; // temp string used to create displayTitle if title does not fit.
|
||||
size_t titleRestart; // location in title to loop back to for marquee effect
|
||||
bool titleFits; // indicates whether the title will fit in the UI title field
|
||||
DWORD dtFormat; // format of title text rect based on title size, i.e., center or left justified
|
||||
|
||||
UI_ELEM mouseOver;
|
||||
UI_ELEM mouseLastOver;
|
||||
UI_ELEM mousePressed;
|
||||
UI_ELEM mouseLastPressed; // used to verify that the LMouse up event matches the LMouse down
|
||||
bool mouseDragging; // whether dragging is in progress to decide to update from winamp info
|
||||
|
||||
bool isInited; // has run CreateOSD to create all the d3d objects
|
||||
bool isReadyToDraw; // has run UpdateOSD to init OSD for drawing, i.e., positioning the UI elements
|
||||
|
||||
bool PointInRect(float x, float y, RECT testRect);
|
||||
RECT BuildHitRect(D3DXVECTOR3 position, RECT size);
|
||||
RECT * GetTextCoords(UI_ELEM item);
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include <unknwn.h>
|
||||
#include <bfc/dispatch.h>
|
||||
// {6BB64D00-F2E1-4c43-B9AA-A762506B8BB6}
|
||||
static const GUID IID_IWasabiDispatchable =
|
||||
{ 0x6bb64d00, 0xf2e1, 0x4c43, { 0xb9, 0xaa, 0xa7, 0x62, 0x50, 0x6b, 0x8b, 0xb6 } };
|
||||
|
||||
|
||||
class IWasabiDispatchable : public IUnknown
|
||||
{
|
||||
public:
|
||||
virtual HRESULT STDMETHODCALLTYPE QueryDispatchable(REFIID riid, Dispatchable **ppDispatchable) = 0;
|
||||
};
|
||||
+1293
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,52 @@
|
||||
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
|
||||
** Filename:
|
||||
** Project:
|
||||
** Description: Unicode<->ANSI conversion layer for input plugins
|
||||
** Author: Ben Allison benski@nullsoft.com
|
||||
** Created:
|
||||
**/
|
||||
|
||||
#include "main.h"
|
||||
#include "../nu/AutoCharFn.h"
|
||||
#include "../nu/ns_wc.h"
|
||||
|
||||
|
||||
int InW_IsOurFile(In_Module *mod, const wchar_t *filename)
|
||||
{
|
||||
if(mod)
|
||||
{
|
||||
if (mod->version & IN_UNICODE)
|
||||
return mod->IsOurFile((in_char *)filename);
|
||||
else
|
||||
return mod->IsOurFile((in_char *)(char *)AutoCharFn(filename));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int InW_Play(In_Module *mod, const wchar_t *filename)
|
||||
{
|
||||
if (mod->version & IN_UNICODE)
|
||||
return mod->Play((in_char *)filename);
|
||||
else
|
||||
return mod->Play((in_char *)(char *)AutoCharFn(filename));
|
||||
}
|
||||
|
||||
int InW_InfoBox(In_Module *mod, const wchar_t *filename, HWND parent)
|
||||
{
|
||||
if (mod->version & IN_UNICODE)
|
||||
return mod->InfoBox((in_char *)filename, parent);
|
||||
else
|
||||
return mod->InfoBox((in_char *)(char *)AutoCharFn(filename), parent);
|
||||
}
|
||||
|
||||
void InW_GetFileInfo(In_Module *mod, const wchar_t *filename, wchar_t *title, int *length)
|
||||
{
|
||||
if (mod->version & IN_UNICODE)
|
||||
mod->GetFileInfo((in_char *)filename, (in_char *)title, length);
|
||||
else
|
||||
{
|
||||
char tempTitle[GETFILEINFO_TITLE_LENGTH]="";
|
||||
mod->GetFileInfo((in_char *)(char *)AutoCharFn(filename), tempTitle, length);
|
||||
MultiByteToWideCharSZ(CP_ACP, 0, tempTitle, -1, title, GETFILEINFO_TITLE_LENGTH);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
#include "main.h"
|
||||
#include "InflateObject.h"
|
||||
#include "zlib/unzip.h"
|
||||
|
||||
int ZLIBInflate::Reset(void *strm)
|
||||
{
|
||||
return ::inflateReset((z_streamp)strm);
|
||||
}
|
||||
|
||||
int ZLIBInflate::Init(void *strm,const char *version, int stream_size)
|
||||
{
|
||||
return ::inflateInit_((z_streamp)strm, version, stream_size);
|
||||
}
|
||||
|
||||
int ZLIBInflate::Init2(void *strm,int windowBits,const char *version, int stream_size)
|
||||
{
|
||||
return ::inflateInit2_((z_streamp)strm, windowBits,version, stream_size);
|
||||
}
|
||||
|
||||
int ZLIBInflate::Inflate(void *strm, int flush)
|
||||
{
|
||||
return ::inflate((z_streamp)strm, flush);
|
||||
}
|
||||
|
||||
int ZLIBInflate::End(void *strm)
|
||||
{
|
||||
return ::inflateEnd((z_streamp)strm);
|
||||
}
|
||||
|
||||
unsigned long ZLIBInflate::CRC32(unsigned long crc, const unsigned char *buf, unsigned int len)
|
||||
{
|
||||
return ::crc32(crc, buf, len);
|
||||
}
|
||||
|
||||
int ZLIBInflate::deflateReset(void *strm)
|
||||
{
|
||||
return ::deflateReset((z_streamp)strm);
|
||||
}
|
||||
|
||||
int ZLIBInflate::deflateInit2_(void *strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size)
|
||||
{
|
||||
return ::deflateInit2_((z_streamp)strm, level, method, windowBits, memLevel, strategy, version, stream_size);
|
||||
}
|
||||
|
||||
int ZLIBInflate::deflateEnd(void *strm)
|
||||
{
|
||||
return ::deflateEnd((z_streamp)strm);
|
||||
}
|
||||
|
||||
int ZLIBInflate::deflate(void *strm, int flush)
|
||||
{
|
||||
return ::deflate((z_streamp)strm, flush);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CBCLASS
|
||||
#undef CBCLASS
|
||||
#endif
|
||||
|
||||
#define CBCLASS ZLIBInflate
|
||||
START_DISPATCH;
|
||||
CB(API_INFLATE_INFLATERESET, Reset);
|
||||
CB(API_INFLATE_INFLATEINIT, Init);
|
||||
CB(API_INFLATE_INFLATEINIT2, Init2);
|
||||
CB(API_INFLATE_INFLATE, Inflate);
|
||||
CB(API_INFLATE_INFLATEEND, End);
|
||||
CB(API_INFLATE_CRC32, CRC32);
|
||||
CB(API_INFLATE_DEFLATERESET, deflateReset);
|
||||
CB(API_INFLATE_DEFLATEINIT2, deflateInit2_);
|
||||
CB(API_INFLATE_DEFLATEEND, deflateEnd);
|
||||
CB(API_INFLATE_DEFLATE, deflate);
|
||||
END_DISPATCH;
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef NULLSOFT_WINAMP_INFLATEOBJECT_H
|
||||
#define NULLSOFT_WINAMP_INFLATEOBJECT_H
|
||||
|
||||
#include "api_inflate.h"
|
||||
|
||||
class ZLIBInflate : public api_inflate
|
||||
{
|
||||
public:
|
||||
static const char *getServiceName() { return "zlib inflate"; }
|
||||
static const GUID getServiceGuid() { return inflateGUID; }
|
||||
public:
|
||||
int Reset(void *strm);
|
||||
int Init(void *strm, const char *version, int stream_size);
|
||||
int Init2(void *strm, int windowBits, const char *version, int stream_size);
|
||||
int Inflate(void *strm, int flush);
|
||||
int End(void *strm);
|
||||
unsigned long CRC32(unsigned long crc, const unsigned char *buf, unsigned int len);
|
||||
|
||||
int deflateReset(void *strm);
|
||||
int deflateInit2_(void *strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size);
|
||||
int deflate(void *strm, int flush);
|
||||
int deflateEnd(void *strm);
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
||||
|
||||
extern ZLIBInflate *zlibInflate;
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "main.h"
|
||||
#include "attributes.h"
|
||||
|
||||
_int::_int()
|
||||
{
|
||||
value = 0;
|
||||
}
|
||||
|
||||
_int::_int(intptr_t defaultValue)
|
||||
{
|
||||
value = defaultValue;
|
||||
}
|
||||
|
||||
intptr_t _int::operator =(intptr_t uintValue)
|
||||
{
|
||||
value = uintValue;
|
||||
return value;
|
||||
}
|
||||
|
||||
#define CBCLASS _int
|
||||
START_DISPATCH;
|
||||
CB(IFC_CONFIGITEM_GETINT, GetInt)
|
||||
CB(IFC_CONFIGITEM_GETFLOAT, GetFloat)
|
||||
END_DISPATCH;
|
||||
@@ -0,0 +1,56 @@
|
||||
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
|
||||
** Filename:
|
||||
** Project:
|
||||
** Description:
|
||||
** Author: Ben Allison benski@nullsoft.com
|
||||
** Created:
|
||||
**/
|
||||
#include "main.h"
|
||||
#include "InternetConfigGroup.h"
|
||||
|
||||
#include "../Agave/Config/ifc_configitem.h"
|
||||
#include "WinampAttributes.h"
|
||||
#include "../nu/ns_wc.h"
|
||||
|
||||
class ProxyConfigItem : public ifc_configitem
|
||||
{
|
||||
public:
|
||||
const wchar_t *GetString()
|
||||
{
|
||||
static wchar_t blah[256];
|
||||
if (config_proxy[0])
|
||||
MultiByteToWideCharSZ(CP_ACP, 0, config_proxy, -1, blah, 256);
|
||||
else
|
||||
return 0;
|
||||
return blah;
|
||||
}
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
||||
|
||||
#define CBCLASS ProxyConfigItem
|
||||
START_DISPATCH;
|
||||
CB(IFC_CONFIGITEM_GETSTRING, GetString)
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
|
||||
static ProxyConfigItem proxyConfigItem;
|
||||
|
||||
ifc_configitem *InternetConfigGroup::GetItem(const wchar_t *name)
|
||||
{
|
||||
if (!wcscmp(name, L"proxy"))
|
||||
return &proxyConfigItem;
|
||||
else if (!wcscmp(name, L"proxy80"))
|
||||
return &config_proxy80;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define CBCLASS InternetConfigGroup
|
||||
START_DISPATCH;
|
||||
CB(IFC_CONFIGGROUP_GETITEM, GetItem)
|
||||
CB(IFC_CONFIGGROUP_GETGUID, GetGUID)
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef NULLSOFT_WINAMP_INTERNETCONFIGGROUP_H
|
||||
#define NULLSOFT_WINAMP_INTERNETCONFIGGROUP_H
|
||||
|
||||
#include "main.h"
|
||||
#include "../Agave/Config/ifc_configgroup.h"
|
||||
|
||||
// {C0A565DC-0CFE-405a-A27C-468B0C8A3A5C}
|
||||
static const GUID internetConfigGroupGUID =
|
||||
{ 0xc0a565dc, 0xcfe, 0x405a, { 0xa2, 0x7c, 0x46, 0x8b, 0xc, 0x8a, 0x3a, 0x5c } };
|
||||
|
||||
class InternetConfigGroup : public ifc_configgroup
|
||||
{
|
||||
public:
|
||||
ifc_configitem *GetItem(const wchar_t *name);
|
||||
GUID GetGUID() { return internetConfigGroupGUID; }
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
||||
|
||||
extern InternetConfigGroup internetConfigGroup;
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
// helper functions for IDispatch
|
||||
#define JSAPI_PARAM_INDEX(paramInfo, paramNumber) (paramInfo->cArgs - paramNumber)
|
||||
#define JSAPI_PARAM_EXISTS(paramInfo, paramNumber) (paramInfo->cArgs >= paramNumber)
|
||||
#define JSAPI_NUM_PARAMS(paramInfo) (paramInfo->cArgs)
|
||||
#define JSAPI_VERIFY_PARAMCOUNT(paramInfo, count) if (paramInfo->cArgs != count) return DISP_E_BADPARAMCOUNT
|
||||
#define JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(paramInfo, minParams, maxParams) if (paramInfo->cArgs < minParams || paramInfo->cArgs > maxParams) return DISP_E_BADPARAMCOUNT
|
||||
#define JSAPI_VERIFY_PARAMTYPE(paramInfo, paramNumber, paramType, argErr) if (paramInfo->rgvarg[paramInfo->cArgs - paramNumber].vt != paramType) { *argErr = paramInfo->cArgs - paramNumber; return DISP_E_TYPEMISMATCH; }
|
||||
#define JSAPI_VERIFY_PARAMTYPE_OPTIONAL(paramInfo, paramNumber, paramType, argErr) if (JSAPI_PARAM_EXISTS(paramInfo, paramNumber) && paramInfo->rgvarg[paramInfo->cArgs - paramNumber].vt != paramType) { *argErr = paramInfo->cArgs - paramNumber; return DISP_E_TYPEMISMATCH; }
|
||||
#define JSAPI_GETSTRING(str, paramInfo, paramNumber, argErr) switch(paramInfo->rgvarg[paramInfo->cArgs - paramNumber].vt) { case VT_BSTR: str = paramInfo->rgvarg[paramInfo->cArgs - paramNumber].bstrVal; break; default: *argErr = paramInfo->cArgs - paramNumber; return DISP_E_TYPEMISMATCH; }
|
||||
#define JSAPI_GETNUMBER_AS_STRING(str, buffer, paramInfo, paramNumber, argErr) \
|
||||
if (JSAPI_PARAM(paramInfo, paramNumber).vt == VT_I4) {\
|
||||
int val_int = JSAPI_PARAM(paramInfo, paramNumber).lVal;\
|
||||
StringCbPrintfW(buffer, sizeof(buffer), L"%d", val_int);\
|
||||
str = buffer;\
|
||||
} else if (JSAPI_PARAM(paramInfo, paramNumber).vt == VT_BSTR)\
|
||||
str = JSAPI_PARAM(paramInfo, paramNumber).bstrVal;\
|
||||
else {\
|
||||
if (argErr) *argErr = paramInfo->cArgs - paramNumber;\
|
||||
return DISP_E_TYPEMISMATCH;\
|
||||
}
|
||||
#define JSAPI_GETUNSIGNED_AS_NUMBER(num, paramInfo, paramNumber, argErr) \
|
||||
if (JSAPI_PARAM(paramInfo, paramNumber).vt == VT_I4) num = (UINT)JSAPI_PARAM(paramInfo, paramNumber).lVal;\
|
||||
else if (JSAPI_PARAM(paramInfo, paramNumber).vt == VT_BSTR) num = wcstoul(JSAPI_PARAM(paramInfo, paramNumber).bstrVal,0, 10); \
|
||||
else return DISP_E_TYPEMISMATCH;
|
||||
|
||||
|
||||
#define JSAPI_PARAM(paramInfo, paramNumber) (paramInfo->rgvarg[paramInfo->cArgs - paramNumber])
|
||||
#define JSAPI_PARAM_OPTIONAL(paramInfo, paramNumber, dispID, opt) (JSAPI_PARAM_EXISTS(paramInfo, paramNumber)?paramInfo->rgvarg[paramInfo->cArgs - paramNumber].##dispID:(opt))
|
||||
#define JSAPI_VERIFY_METHOD(flags) if (!(wFlags & DISPATCH_METHOD)) return DISP_E_MEMBERNOTFOUND
|
||||
#define JSAPI_INIT_RESULT(result, type) if (result) { VariantInit(result); V_VT(result) = type; }
|
||||
#define JSAPI_SET_RESULT(result, field, value) if (result) { (result)->field = value; }
|
||||
#define JSAPI_EMPTY_RESULT(result) if (result) { V_VT(result) = VT_EMPTY; }
|
||||
#define JSAPI_SET_VARIANT(result, macro, value) if (result) { macro(result) = value; }
|
||||
#define JSAPI_DISP_ENUMIFY(x) __jsapi__enum__ ## x
|
||||
@@ -0,0 +1,197 @@
|
||||
#include "JSAPI2_Application.h"
|
||||
#include "main.h"
|
||||
#include "api.h"
|
||||
#include "language.h"
|
||||
#include "JSAPI.h"
|
||||
#include "JSAPI2_Security.h"
|
||||
|
||||
JSAPI2::ApplicationAPI::ApplicationAPI(const wchar_t *_key, JSAPI::ifc_info *_info)
|
||||
{
|
||||
info = _info;
|
||||
key = _key;
|
||||
refCount = 1;
|
||||
}
|
||||
|
||||
#define DISP_TABLE \
|
||||
CHECK_ID(LaunchURL)\
|
||||
CHECK_ID(version)\
|
||||
CHECK_ID(versionstring)\
|
||||
CHECK_ID(language)\
|
||||
CHECK_ID(languagepack)\
|
||||
CHECK_ID(settingspath)\
|
||||
|
||||
#define CHECK_ID(str) JSAPI_DISP_ENUMIFY(str),
|
||||
enum {
|
||||
DISP_TABLE
|
||||
};
|
||||
|
||||
#undef CHECK_ID
|
||||
#define CHECK_ID(str)\
|
||||
if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L## #str, -1))\
|
||||
{ rgdispid[i] = JSAPI_DISP_ENUMIFY(str); continue; }
|
||||
|
||||
HRESULT JSAPI2::ApplicationAPI::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::ApplicationAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::ApplicationAPI::GetTypeInfoCount(unsigned int FAR * pctinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
void CALLBACK OpenURLAPC(ULONG_PTR param);
|
||||
HRESULT JSAPI2::ApplicationAPI::LaunchURL(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 1, 2);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 2, VT_BOOL, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
|
||||
|
||||
if (security.GetActionAuthorization(L"application", L"launchurl", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
const wchar_t *url = JSAPI_PARAM(pdispparams, 1).bstrVal;
|
||||
wchar_t scheme[16]=L"";
|
||||
DWORD size = 16;
|
||||
// make sure it's an HTTP url
|
||||
if (PathIsURLW(url) && !UrlIsFileUrlW(url) && UrlGetPartW(url, scheme, &size, URL_PART_SCHEME, 0) == S_OK
|
||||
&& (!_wcsicmp(scheme, L"http") || !_wcsicmp(scheme, L"https")))
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
if (JSAPI_PARAM_OPTIONAL(pdispparams, 2, boolVal, VARIANT_FALSE) == VARIANT_TRUE)
|
||||
ShellExecuteW(NULL, L"open", url, NULL, L".", 0);
|
||||
else
|
||||
QueueUserAPC(OpenURLAPC, hMainThread, (ULONG_PTR)_wcsdup(url));
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::ApplicationAPI::version(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
if (wFlags & DISPATCH_PROPERTYGET)
|
||||
{
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_I4);
|
||||
JSAPI_SET_RESULT(pvarResult, lVal, ((APP_VERSION_NUM&0xf000)>>12) * 100 + ((APP_VERSION_NUM&0xf0)>>4) * 10 + (APP_VERSION_NUM&0xf));
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
#define WIDEN2(x) L ## x
|
||||
#define WIDEN(x) WIDEN2(x)
|
||||
HRESULT JSAPI2::ApplicationAPI::versionstring(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
if (wFlags & DISPATCH_PROPERTYGET)
|
||||
{
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BSTR;
|
||||
V_BSTR(pvarResult) = SysAllocString(WIDEN(APP_VERSION));
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::ApplicationAPI::language(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
if (wFlags & DISPATCH_PROPERTYGET)
|
||||
{
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BSTR;
|
||||
V_BSTR(pvarResult) = SysAllocString(WASABI_API_LNG->GetLanguageIdentifier(LANG_LANG_CODE));
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::ApplicationAPI::languagepack(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
if (wFlags & DISPATCH_PROPERTYGET)
|
||||
{
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BSTR;
|
||||
V_BSTR(pvarResult) = SysAllocString(WASABI_API_LNG->GetLanguageIdentifier(LANG_IDENT_STR));
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::ApplicationAPI::settingspath(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
if (wFlags & DISPATCH_PROPERTYGET)
|
||||
{
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BSTR;
|
||||
V_BSTR(pvarResult) = SysAllocString(WASABI_API_APP->path_getUserSettingsPath());
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
#undef CHECK_ID
|
||||
#define CHECK_ID(str) case JSAPI_DISP_ENUMIFY(str): return str(wFlags, pdispparams, pvarResult, puArgErr);
|
||||
HRESULT JSAPI2::ApplicationAPI::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::ApplicationAPI::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::ApplicationAPI::AddRef(void)
|
||||
{
|
||||
return InterlockedIncrement(&refCount);
|
||||
}
|
||||
|
||||
|
||||
ULONG JSAPI2::ApplicationAPI::Release(void)
|
||||
{
|
||||
LONG lRef = InterlockedDecrement(&refCount);
|
||||
if (lRef == 0) delete this;
|
||||
return lRef;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <ocidl.h>
|
||||
#include "JSAPI_Info.h"
|
||||
|
||||
namespace JSAPI2
|
||||
{
|
||||
class ApplicationAPI : public IDispatch
|
||||
{
|
||||
public:
|
||||
ApplicationAPI(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;
|
||||
JSAPI::ifc_info *info;
|
||||
volatile LONG refCount;
|
||||
|
||||
STDMETHOD (LaunchURL)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (version)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (versionstring)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (language)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (languagepack)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (settingspath)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,732 @@
|
||||
#include "JSAPI2_AsyncDownloader.h"
|
||||
#include "JSAPI2_Security.h"
|
||||
#include "main.h"
|
||||
#include "../Agave/Language/api_language.h"
|
||||
#include "JSAPI.h"
|
||||
#include "../nu/AutoChar.h"
|
||||
#include "../nu/AutoLock.h"
|
||||
#include "api.h"
|
||||
#include "..\Components\wac_network\wac_network_http_receiver_api.h"
|
||||
#include "resource.h"
|
||||
#include "../Plugins/General/gen_ml/ml.h"
|
||||
#include <api/service/svcs/svc_imgload.h>
|
||||
#include "JSAPI2_CallbackManager.h"
|
||||
|
||||
#define SCRIPT_E_REPORTED 0x80020101
|
||||
|
||||
#define SIMULTANEOUS_ASYNCDOWNLOADS 2
|
||||
std::vector<DownloadToken> asyncDownloads;
|
||||
Nullsoft::Utility::LockGuard asyncDownloadsLock;
|
||||
|
||||
|
||||
bool IsImage(const wchar_t *filename)
|
||||
{
|
||||
FOURCC imgload = svc_imageLoader::getServiceType();
|
||||
int n = (int) WASABI_API_SVC->service_getNumServices(imgload);
|
||||
for (int i=0; i<n; i++)
|
||||
{
|
||||
waServiceFactory *sf = WASABI_API_SVC->service_enumService(imgload,i);
|
||||
if (sf)
|
||||
{
|
||||
svc_imageLoader * l = (svc_imageLoader*)sf->getInterface();
|
||||
if (l)
|
||||
{
|
||||
if (l->isMine(filename))
|
||||
{
|
||||
sf->releaseInterface(l);
|
||||
return true;
|
||||
}
|
||||
sf->releaseInterface(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsPlaylist(const wchar_t *filename)
|
||||
{
|
||||
if (!AGAVE_API_PLAYLISTMANAGER || !AGAVE_API_PLAYLISTMANAGER->CanLoad(filename))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsMedia( const wchar_t *filename )
|
||||
{
|
||||
int a = 0;
|
||||
if ( !in_setmod_noplay( filename, &a ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace JSAPI2
|
||||
{
|
||||
class AsyncDownloaderAPICallback : public ifc_downloadManagerCallback
|
||||
{
|
||||
public:
|
||||
AsyncDownloaderAPICallback( const wchar_t *url, const wchar_t *destination_filepath, const wchar_t *onlineServiceId, const wchar_t *onlineServiceName )
|
||||
{
|
||||
this->hFile = INVALID_HANDLE_VALUE;
|
||||
this->url = _wcsdup( url );
|
||||
this->destination_filepath = _wcsdup( destination_filepath );
|
||||
this->onlineServiceId = _wcsdup( onlineServiceId );
|
||||
if ( onlineServiceName )
|
||||
this->onlineServiceName = _wcsdup( onlineServiceName );
|
||||
else
|
||||
this->onlineServiceName = NULL;
|
||||
this->totalSize = 0;
|
||||
this->downloaded = 0;
|
||||
ref_count = 1;
|
||||
}
|
||||
|
||||
void OnInit(DownloadToken token)
|
||||
{
|
||||
callbackManager.OnInit(this->url, this->onlineServiceId);
|
||||
}
|
||||
|
||||
void OnConnect(DownloadToken token)
|
||||
{
|
||||
// ---- retrieve total size
|
||||
api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
|
||||
if (http)
|
||||
{
|
||||
this->totalSize = http->content_length();
|
||||
}
|
||||
|
||||
// ---- create file handle
|
||||
hFile = CreateFileW(destination_filepath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if ( hFile == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
WAC_API_DOWNLOADMANAGER->CancelDownload(token);
|
||||
}
|
||||
|
||||
callbackManager.OnConnect(this->url, this->onlineServiceId);
|
||||
}
|
||||
|
||||
void OnData(DownloadToken token, void *data, size_t datalen)
|
||||
{
|
||||
// ---- OnConnect copied here due to dlmgr OnData called first
|
||||
// ---- retrieve total size
|
||||
api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
|
||||
if ( !this->totalSize && http )
|
||||
{
|
||||
this->totalSize = http->content_length();
|
||||
}
|
||||
|
||||
if ( hFile == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
// ---- create file handle
|
||||
hFile = CreateFileW(destination_filepath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if ( hFile == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
WAC_API_DOWNLOADMANAGER->CancelDownload(token);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// ---- OnConnect to be removed once dlmgr is fixed
|
||||
|
||||
// ---- OnData
|
||||
// ---- if file handle is invalid, then cancel download
|
||||
if ( hFile == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
WAC_API_DOWNLOADMANAGER->CancelDownload(token);
|
||||
return;
|
||||
}
|
||||
|
||||
this->downloaded = (size_t)WAC_API_DOWNLOADMANAGER->GetBytesDownloaded(token);
|
||||
|
||||
if ( datalen > 0 )
|
||||
{
|
||||
// ---- hFile is valid handle, and write to disk
|
||||
DWORD numWritten = 0;
|
||||
WriteFile(hFile, data, (DWORD)datalen, &numWritten, FALSE);
|
||||
|
||||
// ---- failed writing the number of datalen characters, cancel download
|
||||
if (numWritten != datalen)
|
||||
{
|
||||
WAC_API_DOWNLOADMANAGER->CancelDownload(token);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: if killswitch is turned on, then cancel download
|
||||
//if ( downloadStatus.UpdateStatus(p_token, this->downloaded, this->totalSize) )
|
||||
//{
|
||||
// WAC_API_DOWNLOADMANAGER->CancelDownload(p_token);
|
||||
//}
|
||||
|
||||
callbackManager.OnData(url, this->downloaded, this->totalSize, this->onlineServiceId);
|
||||
}
|
||||
|
||||
void OnCancel( DownloadToken p_token )
|
||||
{
|
||||
if ( hFile != INVALID_HANDLE_VALUE )
|
||||
{
|
||||
CloseHandle( hFile );
|
||||
DeleteFileW( destination_filepath );
|
||||
}
|
||||
|
||||
this->resumeNextPendingDownload( p_token );
|
||||
|
||||
callbackManager.OnCancel( url, this->onlineServiceId );
|
||||
|
||||
this->Release();
|
||||
}
|
||||
|
||||
void OnError(DownloadToken p_token, int error)
|
||||
{
|
||||
if ( hFile != INVALID_HANDLE_VALUE )
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
DeleteFileW(destination_filepath);
|
||||
}
|
||||
|
||||
this->resumeNextPendingDownload( p_token );
|
||||
|
||||
callbackManager.OnError(url, error, this->onlineServiceId);
|
||||
|
||||
this->Release();
|
||||
}
|
||||
|
||||
void OnFinish( DownloadToken p_token )
|
||||
{
|
||||
if ( hFile != INVALID_HANDLE_VALUE )
|
||||
{
|
||||
CloseHandle( hFile );
|
||||
|
||||
if ( IsMedia( PathFindFileNameW( destination_filepath ) ) )
|
||||
{
|
||||
LMDB_FILE_ADD_INFOW fi = { const_cast<wchar_t *>( destination_filepath ), -1, -1 };
|
||||
sendMlIpc( ML_IPC_DB_ADDORUPDATEFILEW, (WPARAM)&fi );
|
||||
sendMlIpc( ML_IPC_DB_SYNCDB, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
this->resumeNextPendingDownload( p_token );
|
||||
|
||||
|
||||
callbackManager.OnFinish( url, destination_filepath, this->onlineServiceId );
|
||||
|
||||
this->Release();
|
||||
}
|
||||
|
||||
|
||||
int GetSource( wchar_t *source, size_t source_cch )
|
||||
{
|
||||
if ( this->onlineServiceName )
|
||||
return wcscpy_s( source, source_cch, this->onlineServiceName );
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GetTitle( wchar_t *title, size_t title_cch )
|
||||
{
|
||||
return wcscpy_s( title, title_cch, PathFindFileNameW( this->destination_filepath ) );
|
||||
}
|
||||
|
||||
int GetLocation( wchar_t *location, size_t location_cch )
|
||||
{
|
||||
return wcscpy_s( location, location_cch, this->destination_filepath );
|
||||
}
|
||||
|
||||
|
||||
size_t AddRef()
|
||||
{
|
||||
return InterlockedIncrement( (LONG *)&ref_count );
|
||||
}
|
||||
|
||||
size_t Release()
|
||||
{
|
||||
if ( ref_count == 0 )
|
||||
return ref_count;
|
||||
|
||||
LONG r = InterlockedDecrement( (LONG *)&ref_count );
|
||||
if ( r == 0 )
|
||||
delete( this );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
private: // private destructor so no one accidentally calls delete directly on this reference counted object
|
||||
~AsyncDownloaderAPICallback()
|
||||
{
|
||||
if ( url )
|
||||
free( url );
|
||||
|
||||
if ( destination_filepath )
|
||||
free( destination_filepath );
|
||||
|
||||
if ( onlineServiceId )
|
||||
free( onlineServiceId );
|
||||
|
||||
if ( onlineServiceName )
|
||||
free( onlineServiceName );
|
||||
}
|
||||
|
||||
inline void resumeNextPendingDownload( DownloadToken p_token )
|
||||
{
|
||||
{
|
||||
Nullsoft::Utility::AutoLock lock( asyncDownloadsLock );
|
||||
|
||||
size_t l_index = 0;
|
||||
for ( DownloadToken &l_download_token : asyncDownloads )
|
||||
{
|
||||
if ( l_download_token == p_token )
|
||||
{
|
||||
asyncDownloads.erase( asyncDownloads.begin() + l_index );
|
||||
break;
|
||||
}
|
||||
|
||||
++l_index;
|
||||
}
|
||||
}
|
||||
|
||||
for ( DownloadToken &l_download_token : asyncDownloads )
|
||||
{
|
||||
if ( WAC_API_DOWNLOADMANAGER->IsPending( l_download_token ) )
|
||||
{
|
||||
WAC_API_DOWNLOADMANAGER->ResumePendingDownload( l_download_token );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
|
||||
private:
|
||||
HANDLE hFile;
|
||||
wchar_t *url;
|
||||
wchar_t *destination_filepath;
|
||||
wchar_t *onlineServiceId;
|
||||
wchar_t *onlineServiceName;
|
||||
size_t totalSize;
|
||||
size_t downloaded;
|
||||
LONG ref_count;
|
||||
};
|
||||
}
|
||||
|
||||
#define CBCLASS JSAPI2::AsyncDownloaderAPICallback
|
||||
START_DISPATCH;
|
||||
VCB( IFC_DOWNLOADMANAGERCALLBACK_ONFINISH, OnFinish )
|
||||
VCB( IFC_DOWNLOADMANAGERCALLBACK_ONCANCEL, OnCancel )
|
||||
VCB( IFC_DOWNLOADMANAGERCALLBACK_ONERROR, OnError )
|
||||
VCB( IFC_DOWNLOADMANAGERCALLBACK_ONDATA, OnData )
|
||||
VCB( IFC_DOWNLOADMANAGERCALLBACK_ONCONNECT, OnConnect )
|
||||
VCB( IFC_DOWNLOADMANAGERCALLBACK_ONINIT, OnInit )
|
||||
CB( IFC_DOWNLOADMANAGERCALLBACK_GETSOURCE, GetSource )
|
||||
CB( IFC_DOWNLOADMANAGERCALLBACK_GETTITLE, GetTitle )
|
||||
CB( IFC_DOWNLOADMANAGERCALLBACK_GETLOCATION, GetLocation )
|
||||
CB( ADDREF, AddRef )
|
||||
CB( RELEASE, Release )
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
|
||||
JSAPI2::AsyncDownloaderAPI::AsyncDownloaderAPI(const wchar_t *_key, JSAPI::ifc_info *_info)
|
||||
{
|
||||
info = _info;
|
||||
key = _key;
|
||||
refCount = 1;
|
||||
}
|
||||
|
||||
JSAPI2::AsyncDownloaderAPI::~AsyncDownloaderAPI()
|
||||
{
|
||||
// just in case someone forgot
|
||||
JSAPI2::callbackManager.Deregister(this);
|
||||
|
||||
size_t index = events.size();
|
||||
while(index--)
|
||||
{
|
||||
IDispatch *pEvent = events[index];
|
||||
if (NULL != pEvent)
|
||||
pEvent->Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define DISP_TABLE \
|
||||
CHECK_ID(DownloadMedia)\
|
||||
CHECK_ID(RegisterForEvents)\
|
||||
CHECK_ID(UnregisterFromEvents)\
|
||||
|
||||
#define CHECK_ID(str) JSAPI_DISP_ENUMIFY(str),
|
||||
enum {
|
||||
DISP_TABLE
|
||||
};
|
||||
|
||||
#undef CHECK_ID
|
||||
#define CHECK_ID(str)\
|
||||
if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L## #str, -1))\
|
||||
{ rgdispid[i] = JSAPI_DISP_ENUMIFY(str); continue; }
|
||||
|
||||
HRESULT JSAPI2::AsyncDownloaderAPI::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::AsyncDownloaderAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::AsyncDownloaderAPI::GetTypeInfoCount(unsigned int FAR * pctinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
int CALLBACK WINAPI BrowseCallbackProc_Download(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
|
||||
{
|
||||
if (uMsg == BFFM_INITIALIZED)
|
||||
{
|
||||
SendMessageW(hwnd, BFFM_SETSELECTIONW, 1, (LPARAM)lpData);
|
||||
|
||||
// this is not nice but it fixes the selection not working correctly on all OSes
|
||||
EnumChildWindows(hwnd, browseEnumProc, 0);
|
||||
}
|
||||
if (uMsg == WM_CREATE) SetWindowTextW(hwnd,getStringW(IDS_SELDOWNLOADDIR,NULL,0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GetPathToStore(wchar_t path_to_store[MAX_PATH]);
|
||||
bool GetOnlineDownloadPath(const wchar_t *key, const wchar_t *svcname, wchar_t path_to_store[MAX_PATH])
|
||||
{
|
||||
//retrieve online service specific download path
|
||||
GetPrivateProfileStringW(key,L"downloadpath",NULL,path_to_store,MAX_PATH,JSAPI2_INIFILE);
|
||||
|
||||
//if found then return, otherwise allow user to specify
|
||||
if (path_to_store && path_to_store[0]) return true;
|
||||
|
||||
//default music folder
|
||||
GetPathToStore(path_to_store);
|
||||
|
||||
//popup dialog to allow user select and specify online service download path
|
||||
BROWSEINFOW bi={0};
|
||||
wchar_t name[MAX_PATH] = {0};
|
||||
wchar_t title[256] = {0};
|
||||
bi.hwndOwner = g_dialog_box_parent?g_dialog_box_parent:hMainWindow;
|
||||
bi.pszDisplayName = name;
|
||||
StringCchPrintfW(title,256,getStringW(IDS_ONLINESERVICE_SELDOWNLOADDIR, 0, 0),svcname);
|
||||
bi.lpszTitle = title;
|
||||
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
|
||||
bi.lpfn = BrowseCallbackProc_Download;
|
||||
bi.lParam = (LPARAM)path_to_store;
|
||||
ITEMIDLIST *idlist = SHBrowseForFolderW(&bi);
|
||||
if (idlist)
|
||||
{
|
||||
SHGetPathFromIDListW(idlist, path_to_store);
|
||||
Shell_Free(idlist);
|
||||
WritePrivateProfileStringW(key,L"downloadpath",path_to_store,JSAPI2_INIFILE);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CleanNameForPath(wchar_t *name)
|
||||
{
|
||||
|
||||
while (name && *name)
|
||||
{
|
||||
switch(*name)
|
||||
{
|
||||
case L'?':
|
||||
case L'*':
|
||||
case L'|':
|
||||
*name = L'_';
|
||||
break;
|
||||
case '/':
|
||||
case L'\\':
|
||||
case L':':
|
||||
*name = L'-';
|
||||
break;
|
||||
case L'\"':
|
||||
*name = L'\'';
|
||||
break;
|
||||
case L'<':
|
||||
*name = L'(';
|
||||
break;
|
||||
case L'>': *name = L')';
|
||||
break;
|
||||
}
|
||||
name++;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::AsyncDownloaderAPI::DownloadMedia(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 1, 3);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr); //url
|
||||
JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 2, VT_BSTR, puArgErr); //destination file
|
||||
JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 3, VT_BOOL, puArgErr); //add to media library or not
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
|
||||
if (security.GetActionAuthorization(L"downloader", L"downloadmedia", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
|
||||
const wchar_t *url = JSAPI_PARAM(pdispparams, 1).bstrVal;
|
||||
wchar_t *destFileSpec=JSAPI_PARAM_OPTIONAL(pdispparams, 2, bstrVal, PathFindFileNameW(url));
|
||||
//filter reserved characters in file name
|
||||
CleanNameForPath(destFileSpec);
|
||||
|
||||
// verify that passed-in URL is a valid media type
|
||||
if (!url || !destFileSpec || (!IsImage(destFileSpec) && !IsPlaylist(destFileSpec) && !IsMedia(destFileSpec)))
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
wchar_t path_to_store[MAX_PATH] = {0};
|
||||
if (GetOnlineDownloadPath(this->key, this->info->GetName(), path_to_store))
|
||||
{
|
||||
CreateDirectoryW(path_to_store, NULL);
|
||||
|
||||
wchar_t destfile[MAX_PATH] = {0};
|
||||
PathCombineW(destfile, path_to_store, destFileSpec);
|
||||
|
||||
JSAPI2::AsyncDownloaderAPICallback *callback = new JSAPI2::AsyncDownloaderAPICallback(url, destfile, key, this->info->GetName());
|
||||
{
|
||||
Nullsoft::Utility::AutoLock lock(asyncDownloadsLock);
|
||||
if (asyncDownloads.size() < SIMULTANEOUS_ASYNCDOWNLOADS)
|
||||
{
|
||||
DownloadToken dt = WAC_API_DOWNLOADMANAGER->DownloadEx(AutoChar(url), callback, api_downloadManager::DOWNLOADEX_CALLBACK | api_downloadManager::DOWNLOADEX_UI);
|
||||
asyncDownloads.push_back(dt);
|
||||
}
|
||||
else
|
||||
{
|
||||
DownloadToken dt = WAC_API_DOWNLOADMANAGER->DownloadEx(AutoChar(url), callback, api_downloadManager::DOWNLOADEX_CALLBACK | api_downloadManager::DOWNLOADEX_PENDING | api_downloadManager::DOWNLOADEX_UI);
|
||||
asyncDownloads.push_back(dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::AsyncDownloaderAPI::RegisterForEvents(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_DISPATCH, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
|
||||
switch (security.GetActionAuthorization(L"downloader", L"events", key, info, JSAPI2::api_security::ACTION_PROMPT))
|
||||
{
|
||||
case JSAPI2::api_security::ACTION_DISALLOWED:
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
|
||||
break;
|
||||
case JSAPI2::api_security::ACTION_ALLOWED:
|
||||
{
|
||||
/** if this is the first time someone is registering an event
|
||||
** add ourselves to the callback manager
|
||||
*/
|
||||
if (events.empty())
|
||||
JSAPI2::callbackManager.Register(this);
|
||||
|
||||
IDispatch *event = JSAPI_PARAM(pdispparams, 1).pdispVal;
|
||||
event->AddRef();
|
||||
// TODO: benski> not sure, but we might need to: event->AddRef();
|
||||
events.push_back(event);
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::AsyncDownloaderAPI::UnregisterFromEvents(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_DISPATCH, puArgErr);
|
||||
|
||||
IDispatch *event = JSAPI_PARAM(pdispparams, 1).pdispVal;
|
||||
// TODO: benski> not sure, but we might need to: event->Release();
|
||||
|
||||
size_t index = events.size();
|
||||
while(index--)
|
||||
{
|
||||
if (events[index] == event)
|
||||
{
|
||||
events.erase(events.begin() + index);
|
||||
event->Release();
|
||||
}
|
||||
}
|
||||
|
||||
/** if we don't have any more event listeners
|
||||
** remove ourselves from the callback manager
|
||||
*/
|
||||
if (events.empty())
|
||||
JSAPI2::callbackManager.Deregister(this);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#undef CHECK_ID
|
||||
#define CHECK_ID(str) case JSAPI_DISP_ENUMIFY(str): return str(wFlags, pdispparams, pvarResult, puArgErr);
|
||||
HRESULT JSAPI2::AsyncDownloaderAPI::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::AsyncDownloaderAPI::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::AsyncDownloaderAPI::AddRef(void)
|
||||
{
|
||||
return InterlockedIncrement(&refCount);
|
||||
}
|
||||
|
||||
|
||||
ULONG JSAPI2::AsyncDownloaderAPI::Release(void)
|
||||
{
|
||||
LONG lRef = InterlockedDecrement(&refCount);
|
||||
if (lRef == 0) delete this;
|
||||
return lRef;
|
||||
}
|
||||
|
||||
|
||||
void JSAPI2::AsyncDownloaderAPI::InvokeEvent(const wchar_t *eventName, JSAPI::CallbackParameters::PropertyTemplate *parameters, size_t parametersCount)
|
||||
{
|
||||
size_t index = events.size();
|
||||
if (0 == index)
|
||||
{
|
||||
JSAPI2::callbackManager.Deregister(this);
|
||||
return;
|
||||
}
|
||||
|
||||
JSAPI::CallbackParameters *eventData= new JSAPI::CallbackParameters;
|
||||
if (NULL == eventData) return;
|
||||
|
||||
eventData->AddString(L"event", eventName);
|
||||
|
||||
if (NULL != parameters && 0 != parametersCount)
|
||||
eventData->AddPropertyIndirect(parameters, parametersCount);
|
||||
|
||||
HRESULT hr;
|
||||
while (index--)
|
||||
{
|
||||
IDispatch *pEvent = events[index];
|
||||
if (NULL != pEvent)
|
||||
{
|
||||
hr = JSAPI::InvokeEvent(eventData, pEvent);
|
||||
if (FAILED(hr) && SCRIPT_E_REPORTED != hr)
|
||||
{
|
||||
events.erase(events.begin() + index);
|
||||
pEvent->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (events.empty())
|
||||
JSAPI2::callbackManager.Deregister(this);
|
||||
|
||||
eventData->Release();
|
||||
}
|
||||
|
||||
|
||||
void JSAPI2::AsyncDownloaderAPI::OnInit(const wchar_t *url)
|
||||
{
|
||||
JSAPI::CallbackParameters::PropertyTemplate parameter =
|
||||
{JSAPI::CallbackParameters::typeString, L"url", (ULONG_PTR)url};
|
||||
|
||||
InvokeEvent(L"OnInit", ¶meter, 1);
|
||||
}
|
||||
|
||||
|
||||
void JSAPI2::AsyncDownloaderAPI::OnConnect(const wchar_t *url)
|
||||
{
|
||||
JSAPI::CallbackParameters::PropertyTemplate parameter =
|
||||
{JSAPI::CallbackParameters::typeString, L"url", (ULONG_PTR)url};
|
||||
|
||||
InvokeEvent(L"OnConnect", ¶meter, 1);
|
||||
}
|
||||
|
||||
|
||||
void JSAPI2::AsyncDownloaderAPI::OnData(const wchar_t *url, size_t downloadedlen, size_t totallen)
|
||||
{
|
||||
JSAPI::CallbackParameters::PropertyTemplate parameter[3] =
|
||||
{{JSAPI::CallbackParameters::typeString, L"url", (ULONG_PTR)url},
|
||||
{JSAPI::CallbackParameters::typeLong, L"downloadedlen", (ULONG_PTR)downloadedlen},
|
||||
{JSAPI::CallbackParameters::typeLong, L"totallen", (ULONG_PTR)totallen}};
|
||||
|
||||
InvokeEvent(L"OnData", ¶meter[0], 3);
|
||||
}
|
||||
|
||||
|
||||
void JSAPI2::AsyncDownloaderAPI::OnCancel(const wchar_t *url)
|
||||
{
|
||||
JSAPI::CallbackParameters::PropertyTemplate parameter =
|
||||
{JSAPI::CallbackParameters::typeString, L"url", (ULONG_PTR)url};
|
||||
|
||||
InvokeEvent(L"OnCancel", ¶meter, 1);
|
||||
}
|
||||
|
||||
|
||||
void JSAPI2::AsyncDownloaderAPI::OnError(const wchar_t *url, int error)
|
||||
{
|
||||
JSAPI::CallbackParameters::PropertyTemplate parameter[2] =
|
||||
{{JSAPI::CallbackParameters::typeString, L"url", (ULONG_PTR)url},
|
||||
{JSAPI::CallbackParameters::typeLong, L"error", (ULONG_PTR)error}};
|
||||
|
||||
InvokeEvent(L"OnError", ¶meter[0], 2);
|
||||
}
|
||||
|
||||
|
||||
void JSAPI2::AsyncDownloaderAPI::OnFinish(const wchar_t *url, const wchar_t *destfilename)
|
||||
{
|
||||
JSAPI::CallbackParameters::PropertyTemplate parameter[2] =
|
||||
{{JSAPI::CallbackParameters::typeString, L"url", (ULONG_PTR)url},
|
||||
{JSAPI::CallbackParameters::typeString, L"destfilename", (ULONG_PTR)destfilename}};
|
||||
|
||||
InvokeEvent(L"OnFinish", ¶meter[0], 2);
|
||||
}
|
||||
|
||||
const wchar_t *JSAPI2::AsyncDownloaderAPI::GetKey()
|
||||
{
|
||||
return this->key;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
#include <ocidl.h>
|
||||
#include "JSAPI_Info.h"
|
||||
#include <vector>
|
||||
#include "JSAPI_CallbackParameters.h"
|
||||
|
||||
namespace JSAPI2
|
||||
{
|
||||
class AsyncDownloaderAPI : public IDispatch
|
||||
{
|
||||
public:
|
||||
AsyncDownloaderAPI(const wchar_t *_key, JSAPI::ifc_info *info);
|
||||
~AsyncDownloaderAPI();
|
||||
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);
|
||||
public:
|
||||
/** Callbacks
|
||||
** JSAPI2::CallbackManager will have been nice enough to marshall onto our thread
|
||||
** so we don't have to worry about that
|
||||
*/
|
||||
void OnInit(const wchar_t *url);
|
||||
void OnConnect(const wchar_t *url);
|
||||
void OnData(const wchar_t *url, size_t downloadedlen, size_t totallen);
|
||||
void OnCancel(const wchar_t *url);
|
||||
void OnError(const wchar_t *url, int error);
|
||||
void OnFinish(const wchar_t *url, const wchar_t *destfilename);
|
||||
void InvokeEvent(const wchar_t *eventName, JSAPI::CallbackParameters::PropertyTemplate *parameters, size_t parametersCount);
|
||||
//Getter for key
|
||||
const wchar_t *GetKey();
|
||||
private:
|
||||
const wchar_t *key;
|
||||
volatile LONG refCount;
|
||||
JSAPI::ifc_info *info;
|
||||
typedef std::vector<IDispatch*> EventsList;
|
||||
EventsList events;
|
||||
|
||||
STDMETHOD (DownloadMedia)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (RegisterForEvents)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (UnregisterFromEvents)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
#include "JSAPI2_Bookmarks.h"
|
||||
#include "JSAPI2_Security.h"
|
||||
#include "main.h"
|
||||
#include "JSAPI.h"
|
||||
#include "../nu/AutoChar.h"
|
||||
|
||||
JSAPI2::BookmarksAPI::BookmarksAPI(const wchar_t *_key, JSAPI::ifc_info *_info)
|
||||
{
|
||||
info = _info;
|
||||
key = _key;
|
||||
refCount = 1;
|
||||
}
|
||||
|
||||
#define DISP_TABLE \
|
||||
CHECK_ID(Add)\
|
||||
|
||||
#define CHECK_ID(str) JSAPI_DISP_ENUMIFY(str),
|
||||
enum {
|
||||
DISP_TABLE
|
||||
};
|
||||
#undef CHECK_ID
|
||||
#define CHECK_ID(str)\
|
||||
if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L## #str, -1))\
|
||||
{ rgdispid[i] = JSAPI_DISP_ENUMIFY(str); continue; }
|
||||
|
||||
HRESULT JSAPI2::BookmarksAPI::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::BookmarksAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::BookmarksAPI::GetTypeInfoCount(unsigned int FAR * pctinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::BookmarksAPI::Add(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 1, 2);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 2, VT_BSTR, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
|
||||
if (security.GetActionAuthorization(L"bookmarks", L"add", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
JSAPI_SET_VARIANT(pvarResult, V_BOOL, VARIANT_TRUE);
|
||||
wchar_t *filename = JSAPI_PARAM(pdispparams, 1).bstrVal;
|
||||
wchar_t *title = JSAPI_PARAM_OPTIONAL(pdispparams, 2, bstrVal, 0);
|
||||
if (title)
|
||||
Bookmark_additem(filename, title);
|
||||
else if (filename)
|
||||
Bookmark_additem(filename, filename);
|
||||
else
|
||||
JSAPI_SET_VARIANT(pvarResult, V_BOOL, VARIANT_FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_SET_VARIANT(pvarResult, V_BOOL, VARIANT_FALSE);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#undef CHECK_ID
|
||||
#define CHECK_ID(str) case JSAPI_DISP_ENUMIFY(str): return str(wFlags, pdispparams, pvarResult, puArgErr);
|
||||
HRESULT JSAPI2::BookmarksAPI::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::BookmarksAPI::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::BookmarksAPI::AddRef(void)
|
||||
{
|
||||
return InterlockedIncrement(&refCount);
|
||||
}
|
||||
|
||||
|
||||
ULONG JSAPI2::BookmarksAPI::Release(void)
|
||||
{
|
||||
LONG lRef = InterlockedDecrement(&refCount);
|
||||
if (lRef == 0) delete this;
|
||||
return lRef;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <ocidl.h>
|
||||
#include "JSAPI_Info.h"
|
||||
|
||||
namespace JSAPI2
|
||||
{
|
||||
class BookmarksAPI : public IDispatch
|
||||
{
|
||||
public:
|
||||
BookmarksAPI(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 (Add)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,567 @@
|
||||
#include "JSAPI2_CallbackManager.h"
|
||||
#include "JSAPI2_TransportAPI.h"
|
||||
#include "JSAPI2_AsyncDownloader.h"
|
||||
#include "JSAPI2_MediaCore.h"
|
||||
#include "api.h"
|
||||
|
||||
JSAPI2::CallbackManager JSAPI2::callbackManager;
|
||||
|
||||
JSAPI2::CallbackManager::CallbackManager() : callbackGuard("JSAPI2::CallbackManager::callbackGuard")
|
||||
{}
|
||||
|
||||
void JSAPI2::CallbackManager::Register( JSAPI2::TransportAPI *me )
|
||||
{
|
||||
/* benski> important note:
|
||||
even thought JSAPI2::Transport inherits from IUnknown,
|
||||
we don't call AddRef here!
|
||||
because this would introduce a circular reference.
|
||||
JSAPI2::TransportAPI will call Deregister during it's
|
||||
destructor.
|
||||
*/
|
||||
Nullsoft::Utility::AutoLock lock( callbackGuard );
|
||||
transports.push_back( new TransportCallback( me ) );
|
||||
}
|
||||
|
||||
void JSAPI2::CallbackManager::Deregister( JSAPI2::TransportAPI *me )
|
||||
{
|
||||
/* benski> important note:
|
||||
even thought JSAPI2::Transport inherits from IUnknown,
|
||||
we don't call Release here!
|
||||
because this would introduce a circular reference.
|
||||
JSAPI2::TransportAPI will call Deregister during it's
|
||||
destructor.
|
||||
*/
|
||||
Nullsoft::Utility::AutoLock lock( callbackGuard );
|
||||
for ( size_t i = 0; i != transports.size(); i++ )
|
||||
{
|
||||
TransportCallback *callback = transports[ i ];
|
||||
if ( callback->api == me )
|
||||
{
|
||||
delete callback;
|
||||
transports.erase( transports.begin() + i );
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void JSAPI2::CallbackManager::Register( JSAPI2::MediaCoreAPI *me )
|
||||
{
|
||||
Nullsoft::Utility::AutoLock lock( callbackGuard );
|
||||
|
||||
//if (!mediaCores.contains(me))
|
||||
if ( mediaCores.end() == std::find( mediaCores.begin(), mediaCores.end(), me ) )
|
||||
{
|
||||
mediaCores.push_back( me );
|
||||
}
|
||||
}
|
||||
|
||||
void JSAPI2::CallbackManager::Deregister( JSAPI2::MediaCoreAPI *me )
|
||||
{
|
||||
Nullsoft::Utility::AutoLock lock( callbackGuard );
|
||||
|
||||
auto it = mediaCores.begin();
|
||||
while ( it != mediaCores.end() )
|
||||
{
|
||||
if ( *it != me )
|
||||
{
|
||||
it++;
|
||||
continue;
|
||||
}
|
||||
|
||||
it = mediaCores.erase( it );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void JSAPI2::CallbackManager::Register( JSAPI2::AsyncDownloaderAPI *me )
|
||||
{
|
||||
Nullsoft::Utility::AutoLock lock( callbackGuard );
|
||||
asyncDownloaders.push_back( new AsyncDownloaderCallback( me ) );
|
||||
}
|
||||
|
||||
void JSAPI2::CallbackManager::Deregister( JSAPI2::AsyncDownloaderAPI *me )
|
||||
{
|
||||
Nullsoft::Utility::AutoLock lock( callbackGuard );
|
||||
for ( size_t i = 0; i != asyncDownloaders.size(); i++ )
|
||||
{
|
||||
AsyncDownloaderCallback *callback = asyncDownloaders[ i ];
|
||||
if ( callback->api == me )
|
||||
{
|
||||
delete callback;
|
||||
asyncDownloaders.erase( asyncDownloaders.begin() + i );
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --- OnStop --- */
|
||||
struct OnStopAPCData
|
||||
{
|
||||
JSAPI2::TransportAPI *transport;
|
||||
int position;
|
||||
int is_full_stop;
|
||||
};
|
||||
|
||||
static void CALLBACK CMGR_OnStopAPC(ULONG_PTR param)
|
||||
{
|
||||
OnStopAPCData *data = (OnStopAPCData *)param;
|
||||
data->transport->OnStop(data->position, data->is_full_stop);
|
||||
data->transport->Release();
|
||||
delete data;
|
||||
}
|
||||
|
||||
void JSAPI2::CallbackManager::OnStop(int position, int is_full_stop)
|
||||
{
|
||||
DWORD threadId = GetCurrentThreadId();
|
||||
Nullsoft::Utility::AutoLock lock(callbackGuard);
|
||||
|
||||
for ( TransportCallback *l_transport : transports )
|
||||
{
|
||||
OnStopAPCData *data = new OnStopAPCData;
|
||||
data->transport = l_transport->api;
|
||||
data->position = position;
|
||||
data->is_full_stop = is_full_stop;
|
||||
|
||||
data->transport->AddRef(); // so it doesn't disappear while we're switching threads
|
||||
|
||||
if ( threadId == l_transport->threadId )
|
||||
{
|
||||
// same thread! huzzah but I wonder how that happened :)
|
||||
CMGR_OnStopAPC( (ULONG_PTR)data );
|
||||
}
|
||||
else
|
||||
{
|
||||
// different thread, do an APC
|
||||
if ( QueueUserAPC( CMGR_OnStopAPC, l_transport->threadHandle, (ULONG_PTR)data ) == 0 )
|
||||
{
|
||||
data->transport->Release();
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* --- --- */
|
||||
|
||||
/* --- OnPlay --- */
|
||||
struct OnPlayAPC
|
||||
{
|
||||
JSAPI2::TransportAPI *transport;
|
||||
wchar_t *filename;
|
||||
};
|
||||
|
||||
static void CALLBACK CMGR_OnPlayAPC(ULONG_PTR param)
|
||||
{
|
||||
OnPlayAPC *data = (OnPlayAPC *)param;
|
||||
data->transport->OnPlay(data->filename);
|
||||
|
||||
free(data->filename);
|
||||
|
||||
data->transport->Release();
|
||||
delete data;
|
||||
}
|
||||
|
||||
void JSAPI2::CallbackManager::OnPlay(const wchar_t *filename)
|
||||
{
|
||||
DWORD threadId = GetCurrentThreadId();
|
||||
Nullsoft::Utility::AutoLock lock(callbackGuard);
|
||||
|
||||
for ( TransportCallback *l_transport : transports )
|
||||
{
|
||||
OnPlayAPC *data = new OnPlayAPC;
|
||||
data->transport = l_transport->api;
|
||||
data->filename = _wcsdup(filename);
|
||||
|
||||
data->transport->AddRef(); // so it doesn't disappear while we're switching threads
|
||||
|
||||
if ( threadId == l_transport->threadId )
|
||||
{
|
||||
// same thread! huzzah but I wonder how that happened :)
|
||||
CMGR_OnPlayAPC( (ULONG_PTR)data );
|
||||
}
|
||||
else
|
||||
{
|
||||
// different thread, do an APC
|
||||
if ( QueueUserAPC( CMGR_OnPlayAPC, l_transport->threadHandle, (ULONG_PTR)data ) == 0 )
|
||||
{
|
||||
data->transport->Release();
|
||||
free( data->filename );
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --- --- */
|
||||
|
||||
|
||||
struct OnPauseAPC
|
||||
{
|
||||
JSAPI2::TransportAPI *transport;
|
||||
bool pause_state;
|
||||
};
|
||||
|
||||
static void CALLBACK CMGR_OnPauseAPC(ULONG_PTR param)
|
||||
{
|
||||
OnPauseAPC *data = (OnPauseAPC *)param;
|
||||
data->transport->OnPause(data->pause_state);
|
||||
data->transport->Release();
|
||||
delete data;
|
||||
}
|
||||
|
||||
void JSAPI2::CallbackManager::OnPause(bool pause_state)
|
||||
{
|
||||
DWORD threadId = GetCurrentThreadId();
|
||||
Nullsoft::Utility::AutoLock lock( callbackGuard );
|
||||
|
||||
for ( TransportCallback *l_transport : transports )
|
||||
{
|
||||
OnPauseAPC *data = new OnPauseAPC;
|
||||
data->transport = l_transport->api;
|
||||
data->pause_state = pause_state;
|
||||
|
||||
data->transport->AddRef(); // so it doesn't disappear while we're switching threads
|
||||
|
||||
if (threadId == l_transport->threadId)
|
||||
{
|
||||
// same thread! huzzah but I wonder how that happened :)
|
||||
CMGR_OnPauseAPC((ULONG_PTR)data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// different thread, do an APC
|
||||
if (QueueUserAPC(CMGR_OnPauseAPC, l_transport->threadHandle, (ULONG_PTR)data) == 0)
|
||||
{
|
||||
data->transport->Release();
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --- --- */
|
||||
bool JSAPI2::CallbackManager::OverrideMetadata( const wchar_t *filename, const wchar_t *tag, wchar_t *out, size_t outCch )
|
||||
{
|
||||
if ( NULL != filename && NULL != tag && NULL != out )
|
||||
{
|
||||
Nullsoft::Utility::AutoLock lock( callbackGuard );
|
||||
for ( MediaCoreAPI *l_mediaCore : mediaCores )
|
||||
{
|
||||
if ( l_mediaCore->OverrideMetadata( filename, tag, out, outCch ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* --- OnInit --- */
|
||||
struct OnInitAPC
|
||||
{
|
||||
JSAPI2::AsyncDownloaderAPI *asyncDownloader;
|
||||
wchar_t *url;
|
||||
};
|
||||
|
||||
static void CALLBACK CMGR_OnInitAPC(ULONG_PTR param)
|
||||
{
|
||||
OnInitAPC *data = (OnInitAPC *)param;
|
||||
data->asyncDownloader->OnInit(data->url);
|
||||
free(data->url);
|
||||
data->asyncDownloader->Release();
|
||||
delete data;
|
||||
}
|
||||
|
||||
void JSAPI2::CallbackManager::OnInit( const wchar_t *url, const wchar_t *onlinesvcId )
|
||||
{
|
||||
DWORD threadId = GetCurrentThreadId();
|
||||
Nullsoft::Utility::AutoLock lock( callbackGuard );
|
||||
|
||||
for ( AsyncDownloaderCallback *l_downloader : asyncDownloaders )
|
||||
{
|
||||
if ( wcscmp( onlinesvcId, l_downloader->api->GetKey() ) )
|
||||
continue; //only call back to the same online service that issued the download reqeust
|
||||
|
||||
OnInitAPC *data = new OnInitAPC;
|
||||
data->asyncDownloader = l_downloader->api;
|
||||
data->url = _wcsdup( url );
|
||||
|
||||
data->asyncDownloader->AddRef(); // so it doesn't disappear while we're switching threads
|
||||
|
||||
if ( threadId == l_downloader->threadId )
|
||||
{
|
||||
// same thread! huzzah but I wonder how that happened :)
|
||||
CMGR_OnInitAPC( (ULONG_PTR)data );
|
||||
}
|
||||
else
|
||||
{
|
||||
// different thread, do an APC
|
||||
if ( QueueUserAPC( CMGR_OnInitAPC, l_downloader->threadHandle, (ULONG_PTR)data ) == 0 )
|
||||
{
|
||||
data->asyncDownloader->Release();
|
||||
free( data->url );
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* --- OnConnect --- */
|
||||
struct OnConnectAPC
|
||||
{
|
||||
JSAPI2::AsyncDownloaderAPI *asyncDownloader;
|
||||
wchar_t *url;
|
||||
};
|
||||
|
||||
static void CALLBACK CMGR_OnConnectAPC(ULONG_PTR param)
|
||||
{
|
||||
OnConnectAPC *data = (OnConnectAPC *)param;
|
||||
data->asyncDownloader->OnConnect(data->url);
|
||||
free(data->url);
|
||||
data->asyncDownloader->Release();
|
||||
delete data;
|
||||
}
|
||||
|
||||
void JSAPI2::CallbackManager::OnConnect( const wchar_t *url, const wchar_t *onlinesvcId )
|
||||
{
|
||||
DWORD threadId = GetCurrentThreadId();
|
||||
Nullsoft::Utility::AutoLock lock( callbackGuard );
|
||||
|
||||
for ( AsyncDownloaderCallback *l_downloader : asyncDownloaders )
|
||||
{
|
||||
if ( wcscmp( onlinesvcId, l_downloader->api->GetKey() ) )
|
||||
continue; //only call back to the same online service that issued the download reqeust
|
||||
|
||||
OnConnectAPC *data = new OnConnectAPC;
|
||||
data->asyncDownloader = l_downloader->api;
|
||||
data->url = _wcsdup( url );
|
||||
|
||||
data->asyncDownloader->AddRef(); // so it doesn't disappear while we're switching threads
|
||||
|
||||
if ( threadId == l_downloader->threadId )
|
||||
{
|
||||
// same thread! huzzah but I wonder how that happened :)
|
||||
CMGR_OnConnectAPC( (ULONG_PTR)data );
|
||||
}
|
||||
else
|
||||
{
|
||||
// different thread, do an APC
|
||||
if ( QueueUserAPC( CMGR_OnConnectAPC, l_downloader->threadHandle, (ULONG_PTR)data ) == 0 )
|
||||
{
|
||||
data->asyncDownloader->Release();
|
||||
free( data->url );
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* --- OnCancel --- */
|
||||
struct OnCancelAPC
|
||||
{
|
||||
JSAPI2::AsyncDownloaderAPI *asyncDownloader;
|
||||
wchar_t *url;
|
||||
};
|
||||
|
||||
static void CALLBACK CMGR_OnCancelAPC(ULONG_PTR param)
|
||||
{
|
||||
OnCancelAPC *data = (OnCancelAPC *)param;
|
||||
data->asyncDownloader->OnCancel(data->url);
|
||||
free(data->url);
|
||||
data->asyncDownloader->Release();
|
||||
delete data;
|
||||
}
|
||||
|
||||
void JSAPI2::CallbackManager::OnCancel( const wchar_t *url, const wchar_t *onlinesvcId )
|
||||
{
|
||||
DWORD threadId = GetCurrentThreadId();
|
||||
Nullsoft::Utility::AutoLock lock( callbackGuard );
|
||||
|
||||
for ( AsyncDownloaderCallback *l_downloader : asyncDownloaders )
|
||||
{
|
||||
if ( wcscmp( onlinesvcId, l_downloader->api->GetKey() ) )
|
||||
continue; //only call back to the same online service that issued the download reqeust
|
||||
|
||||
OnCancelAPC *data = new OnCancelAPC;
|
||||
data->asyncDownloader = l_downloader->api;
|
||||
data->url = _wcsdup( url );
|
||||
|
||||
data->asyncDownloader->AddRef(); // so it doesn't disappear while we're switching threads
|
||||
|
||||
if ( threadId == l_downloader->threadId )
|
||||
{
|
||||
// same thread! huzzah but I wonder how that happened :)
|
||||
CMGR_OnCancelAPC( (ULONG_PTR)data );
|
||||
}
|
||||
else
|
||||
{
|
||||
// different thread, do an APC
|
||||
if ( QueueUserAPC( CMGR_OnCancelAPC, l_downloader->threadHandle, (ULONG_PTR)data ) == 0 )
|
||||
{
|
||||
data->asyncDownloader->Release();
|
||||
free( data->url );
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* --- OnData --- */
|
||||
struct OnDataAPC
|
||||
{
|
||||
JSAPI2::AsyncDownloaderAPI *asyncDownloader;
|
||||
wchar_t *url;
|
||||
size_t downloadedlen;
|
||||
size_t totallen;
|
||||
};
|
||||
|
||||
static void CALLBACK CMGR_OnDataAPC(ULONG_PTR param)
|
||||
{
|
||||
OnDataAPC *data = (OnDataAPC *)param;
|
||||
data->asyncDownloader->OnData(data->url, data->downloadedlen, data->totallen);
|
||||
free(data->url);
|
||||
data->asyncDownloader->Release();
|
||||
delete data;
|
||||
}
|
||||
|
||||
void JSAPI2::CallbackManager::OnData(const wchar_t *url, size_t downloadedlen, size_t totallen, const wchar_t *onlinesvcId)
|
||||
{
|
||||
DWORD threadId = GetCurrentThreadId();
|
||||
Nullsoft::Utility::AutoLock lock(callbackGuard);
|
||||
|
||||
for ( AsyncDownloaderCallback *downloader : asyncDownloaders )
|
||||
{
|
||||
if ( wcscmp(onlinesvcId, downloader->api->GetKey()) )
|
||||
continue; //only call back to the same online service that issued the download reqeust
|
||||
|
||||
OnDataAPC *data = new OnDataAPC;
|
||||
data->asyncDownloader = downloader->api;
|
||||
data->url = _wcsdup(url);
|
||||
data->downloadedlen = downloadedlen;
|
||||
data->totallen = totallen;
|
||||
data->asyncDownloader->AddRef(); // so it doesn't disappear while we're switching threads
|
||||
if (threadId == downloader->threadId)
|
||||
{
|
||||
// same thread! huzzah but I wonder how that happened :)
|
||||
CMGR_OnDataAPC((ULONG_PTR)data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// different thread, do an APC
|
||||
if (QueueUserAPC(CMGR_OnDataAPC, downloader->threadHandle, (ULONG_PTR)data) == 0)
|
||||
{
|
||||
data->asyncDownloader->Release();
|
||||
free(data->url);
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* --- OnError --- */
|
||||
struct OnErrorAPC
|
||||
{
|
||||
JSAPI2::AsyncDownloaderAPI *asyncDownloader;
|
||||
wchar_t *url;
|
||||
int error;
|
||||
};
|
||||
|
||||
static void CALLBACK CMGR_OnErrorAPC(ULONG_PTR param)
|
||||
{
|
||||
OnErrorAPC *data = (OnErrorAPC *)param;
|
||||
data->asyncDownloader->OnError(data->url, data->error);
|
||||
free(data->url);
|
||||
data->asyncDownloader->Release();
|
||||
delete data;
|
||||
}
|
||||
|
||||
void JSAPI2::CallbackManager::OnError(const wchar_t *url, int error, const wchar_t *onlinesvcId)
|
||||
{
|
||||
DWORD threadId = GetCurrentThreadId();
|
||||
Nullsoft::Utility::AutoLock lock(callbackGuard);
|
||||
|
||||
for ( AsyncDownloaderCallback *downloader : asyncDownloaders )
|
||||
{
|
||||
if ( wcscmp(onlinesvcId, downloader->api->GetKey()) )
|
||||
continue; //only call back to the same online service that issued the download reqeust
|
||||
|
||||
OnErrorAPC *data = new OnErrorAPC;
|
||||
data->asyncDownloader = downloader->api;
|
||||
data->url = _wcsdup(url);
|
||||
data->error = error;
|
||||
data->asyncDownloader->AddRef(); // so it doesn't disappear while we're switching threads
|
||||
if (threadId == downloader->threadId)
|
||||
{
|
||||
// same thread! huzzah but I wonder how that happened :)
|
||||
CMGR_OnErrorAPC((ULONG_PTR)data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// different thread, do an APC
|
||||
if (QueueUserAPC(CMGR_OnErrorAPC, downloader->threadHandle, (ULONG_PTR)data) == 0)
|
||||
{
|
||||
data->asyncDownloader->Release();
|
||||
free(data->url);
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* --- OnFinish --- */
|
||||
struct OnFinishAPC
|
||||
{
|
||||
JSAPI2::AsyncDownloaderAPI *asyncDownloader;
|
||||
wchar_t *url;
|
||||
wchar_t *destfilename;
|
||||
};
|
||||
|
||||
static void CALLBACK CMGR_OnFinishAPC(ULONG_PTR param)
|
||||
{
|
||||
OnFinishAPC *data = (OnFinishAPC *)param;
|
||||
data->asyncDownloader->OnFinish(data->url, data->destfilename);
|
||||
free(data->url);
|
||||
free(data->destfilename);
|
||||
data->asyncDownloader->Release();
|
||||
delete data;
|
||||
}
|
||||
|
||||
void JSAPI2::CallbackManager::OnFinish(const wchar_t *url, const wchar_t *destfilename, const wchar_t *onlinesvcId)
|
||||
{
|
||||
DWORD threadId = GetCurrentThreadId();
|
||||
Nullsoft::Utility::AutoLock lock(callbackGuard);
|
||||
|
||||
for ( AsyncDownloaderCallback *downloader : asyncDownloaders )
|
||||
{
|
||||
if ( wcscmp(onlinesvcId, downloader->api->GetKey()) )
|
||||
continue; //only call back to the same online service that issued the download reqeust
|
||||
|
||||
OnFinishAPC *data = new OnFinishAPC;
|
||||
data->asyncDownloader = downloader->api;
|
||||
data->url = _wcsdup(url);
|
||||
data->destfilename = _wcsdup(destfilename);
|
||||
data->asyncDownloader->AddRef(); // so it doesn't disappear while we're switching threads
|
||||
if (threadId == downloader->threadId)
|
||||
{
|
||||
// same thread! huzzah but I wonder how that happened :)
|
||||
CMGR_OnFinishAPC((ULONG_PTR)data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// different thread, do an APC
|
||||
if (QueueUserAPC(CMGR_OnFinishAPC, downloader->threadHandle, (ULONG_PTR)data) == 0)
|
||||
{
|
||||
data->asyncDownloader->Release();
|
||||
free(data->url);
|
||||
free(data->destfilename);
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
#pragma once
|
||||
#include "../nu/AutoLock.h"
|
||||
#include <vector>
|
||||
#include "../Components/wac_downloadManager/wac_downloadManager_api.h"
|
||||
|
||||
extern "C" HANDLE DuplicateCurrentThread();
|
||||
namespace JSAPI2
|
||||
{
|
||||
template <class API> struct CallbackInfo
|
||||
{
|
||||
CallbackInfo()
|
||||
{
|
||||
api = 0;
|
||||
threadId = 0;
|
||||
threadHandle = 0;
|
||||
}
|
||||
|
||||
CallbackInfo(API *me)
|
||||
{
|
||||
api = me;
|
||||
threadId = GetCurrentThreadId();
|
||||
threadHandle = DuplicateCurrentThread();
|
||||
}
|
||||
|
||||
~CallbackInfo()
|
||||
{
|
||||
CloseHandle(threadHandle);
|
||||
threadHandle = 0;
|
||||
}
|
||||
API *api;
|
||||
DWORD threadId;
|
||||
HANDLE threadHandle;
|
||||
};
|
||||
|
||||
class TransportAPI;
|
||||
class MediaCoreAPI;
|
||||
class AsyncDownloaderAPI;
|
||||
class CallbackManager
|
||||
{
|
||||
public:
|
||||
CallbackManager();
|
||||
|
||||
public:
|
||||
/** stuff for Winamp to call to trigger callbacks
|
||||
** these are primarily responsible for getting over to the correct thread
|
||||
** to keep that particular logic out of the various functions
|
||||
*/
|
||||
void OnStop(int position, int is_full_stop);
|
||||
void OnPlay(const wchar_t *filename);
|
||||
void OnPause(bool pause_state);
|
||||
|
||||
/** Stuff that's OK to call on any thread
|
||||
*/
|
||||
bool OverrideMetadata(const wchar_t *filename, const wchar_t *tag, wchar_t *out, size_t outCch);
|
||||
|
||||
/** stuff for Winamp to call to trigger callbacks
|
||||
** these are primarily responsible for getting over to the correct thread
|
||||
** to keep that particular logic out of the various functions
|
||||
*/
|
||||
void OnInit(const wchar_t *url, const wchar_t *onlinesvcId);
|
||||
void OnConnect(const wchar_t *url, const wchar_t *onlinesvcId);
|
||||
void OnData(const wchar_t *url, size_t downloadedlen, size_t totallen, const wchar_t *onlinesvcId);
|
||||
void OnCancel(const wchar_t *url, const wchar_t *onlinesvcId);
|
||||
void OnError(const wchar_t *url, int error, const wchar_t *onlinesvcId);
|
||||
void OnFinish(const wchar_t *url, const wchar_t *destfilename, const wchar_t *onlinesvcId);
|
||||
public:
|
||||
/* stuff for other JSAPI2 classes to call */
|
||||
void Register(JSAPI2::TransportAPI *me);
|
||||
void Deregister(JSAPI2::TransportAPI *me);
|
||||
|
||||
void Register(JSAPI2::MediaCoreAPI *me);
|
||||
void Deregister(JSAPI2::MediaCoreAPI *me);
|
||||
|
||||
void Register(JSAPI2::AsyncDownloaderAPI *me);
|
||||
void Deregister(JSAPI2::AsyncDownloaderAPI *me);
|
||||
private:
|
||||
/* Transport API callbacks */
|
||||
typedef CallbackInfo<JSAPI2::TransportAPI> TransportCallback;
|
||||
typedef std::vector<TransportCallback*> TransportsList;
|
||||
TransportsList transports;
|
||||
|
||||
typedef std::vector<MediaCoreAPI*> MediaCoreList;
|
||||
MediaCoreList mediaCores;
|
||||
|
||||
typedef CallbackInfo<JSAPI2::AsyncDownloaderAPI> AsyncDownloaderCallback;
|
||||
typedef std::vector<AsyncDownloaderCallback*> AsyncDownloadersList;
|
||||
AsyncDownloadersList asyncDownloaders;
|
||||
|
||||
Nullsoft::Utility::LockGuard callbackGuard;
|
||||
};
|
||||
|
||||
extern CallbackManager callbackManager;
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
#include "main.h"
|
||||
#include "resource.h"
|
||||
#include "JSAPI2_Creator.h"
|
||||
#include "JSAPI2_TransportAPI.h"
|
||||
#include "JSAPI2_PlayerAPI.h"
|
||||
#include "JSAPI2_Downloader.h"
|
||||
#include "JSAPI2_SecurityAPI.h"
|
||||
#include "JSAPI2_Security.h"
|
||||
#include "JSAPI2_Bookmarks.h"
|
||||
#include "JSAPI2_Application.h"
|
||||
#include "JSAPI2_SkinAPI.h"
|
||||
#include "JSAPI2_MediaCore.h"
|
||||
#include "JSAPI2_AsyncDownloader.h"
|
||||
#include "api.h"
|
||||
#include "language.h"
|
||||
|
||||
IDispatch *JSAPI2_Creator::CreateAPI(const wchar_t *name, const wchar_t *key, JSAPI::ifc_info *info)
|
||||
{
|
||||
if (!wcscmp(name, L"Transport"))
|
||||
return new JSAPI2::TransportAPI(key, info);
|
||||
else if (!wcscmp(name, L"PlayQueue"))
|
||||
return new JSAPI2::PlayerAPI(key, info);
|
||||
else if (!wcscmp(name, L"Downloader"))
|
||||
return new JSAPI2::DownloaderAPI(key, info);
|
||||
else if (!wcscmp(name, L"AsyncDownloader"))
|
||||
return new JSAPI2::AsyncDownloaderAPI(key, info);
|
||||
else if (!wcscmp(name, L"Security"))
|
||||
return new JSAPI2::SecurityAPI(key, info);
|
||||
else if (!wcscmp(name, L"Bookmarks"))
|
||||
return new JSAPI2::BookmarksAPI(key, info);
|
||||
else if (!wcscmp(name, L"Application"))
|
||||
return new JSAPI2::ApplicationAPI(key, info);
|
||||
else if (!wcscmp(name, L"Skin"))
|
||||
return new JSAPI2::SkinAPI(key, info);
|
||||
else if (!wcscmp(name, L"MediaCore"))
|
||||
return new JSAPI2::MediaCoreAPI(key, info);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int GetDescription(const wchar_t *group, const wchar_t *action, wchar_t *str, size_t str_len, int *flags)
|
||||
{
|
||||
if (!wcscmp(group, L"application"))
|
||||
{
|
||||
if (action && !wcscmp(action, L"launchurl"))
|
||||
{
|
||||
*flags = 0;
|
||||
StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_APPLICATION_LAUNCHURL, NULL, 0));
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
}
|
||||
else if (!wcscmp(group, L"transport"))
|
||||
{
|
||||
if (action && !wcscmp(action, L"events"))
|
||||
{
|
||||
*flags = 0;
|
||||
StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_TRANSPORT_EVENTS, NULL, 0));
|
||||
}
|
||||
else if (action && !wcscmp(action, L"metadata"))
|
||||
{
|
||||
*flags = 0;
|
||||
StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_TRANSPORT_METADATA, NULL, 0));
|
||||
}
|
||||
else if (action && !wcscmp(action, L"controls"))
|
||||
{
|
||||
*flags = 0;
|
||||
StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_TRANSPORT_CONTROLS, NULL, 0));
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
else if(!wcscmp(group, L"player"))
|
||||
{
|
||||
if (action && !wcscmp(action, L"playlist"))
|
||||
{
|
||||
*flags = 0;
|
||||
StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_PLAYER_PLAYLIST, NULL, 0));
|
||||
}
|
||||
else if (action && !wcscmp(action, L"metadata"))
|
||||
{
|
||||
*flags = 0;
|
||||
StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_PLAYER_METADATA, NULL, 0));
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
else if (!wcscmp(group, L"downloader"))
|
||||
{
|
||||
if (action && !wcscmp(action, L"events"))
|
||||
{
|
||||
*flags = 0;
|
||||
StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_DOWNLOADER_EVENTS, NULL, 0));
|
||||
}
|
||||
else if (action && !wcscmp(action, L"downloadmedia"))
|
||||
{
|
||||
*flags = 0;
|
||||
StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_DOWNLOADER_DOWNLOADMEDIA, NULL, 0));
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
else if (!wcscmp(group, L"security"))
|
||||
{
|
||||
*flags = JSAPI2::svc_apicreator::AUTHORIZATION_FLAG_GROUP_ONLY;
|
||||
StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_SECURITY_AUTH, NULL, 0));
|
||||
return 0;
|
||||
}
|
||||
else if (!wcscmp(group, L"bookmarks"))
|
||||
{
|
||||
*flags = JSAPI2::svc_apicreator::AUTHORIZATION_FLAG_GROUP_ONLY;
|
||||
StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_BOOKMARKS_AUTH, NULL, 0));
|
||||
return 0;
|
||||
}
|
||||
else if (!wcscmp(group, L"skin"))
|
||||
{
|
||||
*flags = JSAPI2::svc_apicreator::AUTHORIZATION_FLAG_GROUP_ONLY;
|
||||
StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_SKIN_AUTH, NULL, 0));
|
||||
return 0;
|
||||
}
|
||||
else if (!wcscmp(group, L"mediacore"))
|
||||
{
|
||||
if (action && !wcscmp(action, L"metadatahook"))
|
||||
{
|
||||
*flags = 0;
|
||||
StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_MEDIACORE_METADATAHOOK, NULL, 0));
|
||||
}
|
||||
else if (action && !wcscmp(action, L"metadata"))
|
||||
{
|
||||
*flags = 0;
|
||||
StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_MEDIACORE_METADATA, NULL, 0));
|
||||
}
|
||||
else if (action && !wcscmp(action, L"extensions"))
|
||||
{
|
||||
*flags = 0;
|
||||
StringCchCopyW(str, str_len, getStringW(IDS_SECURITY_MEDIACORE_EXTENSIONS, NULL, 0));
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int JSAPI2_Creator::PromptForAuthorization(HWND parent, const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, JSAPI2::api_security::AuthorizationData *data)
|
||||
{
|
||||
int flags = 0;
|
||||
wchar_t display_str[1024] = {0};
|
||||
if (GetDescription(group, action, display_str, 1024, &flags) == 0)
|
||||
{
|
||||
const wchar_t *title_str = JSAPI2::security.GetAssociatedName(authorization_key);
|
||||
return JSAPI2::security.SecurityPrompt(parent, title_str, display_str, flags);
|
||||
}
|
||||
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[] = "Winamp Javascript Objects";
|
||||
|
||||
// {53CCACEF-1EFE-4060-8D09-329AD0D4F9C4}
|
||||
static const GUID jsapi2_factory_guid =
|
||||
{ 0x53ccacef, 0x1efe, 0x4060, { 0x8d, 0x9, 0x32, 0x9a, 0xd0, 0xd4, 0xf9, 0xc4 } };
|
||||
|
||||
|
||||
|
||||
FOURCC JSAPI2CreatorFactory::GetServiceType()
|
||||
{
|
||||
return jsapi2_svc.getServiceType();
|
||||
}
|
||||
|
||||
const char *JSAPI2CreatorFactory::GetServiceName()
|
||||
{
|
||||
return serviceName;
|
||||
}
|
||||
|
||||
GUID JSAPI2CreatorFactory::GetGUID()
|
||||
{
|
||||
return jsapi2_factory_guid;
|
||||
}
|
||||
|
||||
void *JSAPI2CreatorFactory::GetInterface(int global_lock)
|
||||
{
|
||||
// if (global_lock)
|
||||
// WASABI_API_SVC->service_lock(this, (void *)ifc);
|
||||
return &jsapi2_svc;
|
||||
}
|
||||
|
||||
int JSAPI2CreatorFactory::SupportNonLockingInterface()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int JSAPI2CreatorFactory::ReleaseInterface(void *ifc)
|
||||
{
|
||||
//WASABI_API_SVC->service_unlock(ifc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *JSAPI2CreatorFactory::GetTestString()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int JSAPI2CreatorFactory::ServiceNotify(int msg, int param1, int param2)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define CBCLASS JSAPI2CreatorFactory
|
||||
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
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include "../Winamp/JSAPI2_svc_apicreator.h"
|
||||
|
||||
#include <api/service/waservicefactory.h>
|
||||
#include <api/service/services.h>
|
||||
|
||||
|
||||
class JSAPI2CreatorFactory : 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;
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include <ocidl.h>
|
||||
#include "JSAPI_Info.h"
|
||||
|
||||
namespace JSAPI2
|
||||
{
|
||||
class DownloaderAPI : public IDispatch
|
||||
{
|
||||
public:
|
||||
DownloaderAPI(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 (DownloadMedia)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
#include "JSAPI2_Downloader.h"
|
||||
#include "JSAPI2_Security.h"
|
||||
#include "main.h"
|
||||
#include "../Agave/Language/api_language.h"
|
||||
#include "JSAPI.h"
|
||||
#include "../nu/AutoChar.h"
|
||||
#include "api.h"
|
||||
#include "resource.h"
|
||||
#include "../Plugins/General/gen_ml/ml.h"
|
||||
#include <api/service/svcs/svc_imgload.h>
|
||||
|
||||
JSAPI2::DownloaderAPI::DownloaderAPI(const wchar_t *_key, JSAPI::ifc_info *_info)
|
||||
{
|
||||
info = _info;
|
||||
key = _key;
|
||||
refCount = 1;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
DISP_DOWNLOADERAPI_DOWNLOADMEDIA,
|
||||
};
|
||||
|
||||
#define DISP_TABLE \
|
||||
CHECK_ID(DownloadMedia, DISP_DOWNLOADERAPI_DOWNLOADMEDIA)\
|
||||
|
||||
#define CHECK_ID(str, id)\
|
||||
if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L## #str, -1))\
|
||||
{ rgdispid[i] = id; continue; }
|
||||
|
||||
HRESULT JSAPI2::DownloaderAPI::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::DownloaderAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::DownloaderAPI::GetTypeInfoCount(unsigned int FAR * pctinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
bool IsImage(const wchar_t *filename);
|
||||
bool IsPlaylist(const wchar_t *filename);
|
||||
bool IsMedia(const wchar_t *filename);
|
||||
bool GetOnlineDownloadPath(const wchar_t *key, const wchar_t *svcname, wchar_t path_to_store[MAX_PATH]);
|
||||
HRESULT JSAPI2::DownloaderAPI::DownloadMedia(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 1, 3);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 2, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 3, VT_BOOL, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
|
||||
if (security.GetActionAuthorization(L"downloader", L"downloadmedia", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
|
||||
const wchar_t *url = JSAPI_PARAM(pdispparams, 1).bstrVal;
|
||||
wchar_t *destFileSpec=JSAPI_PARAM_OPTIONAL(pdispparams, 2, bstrVal, PathFindFileNameW(url));
|
||||
|
||||
//filter reserved characters in file name
|
||||
CleanNameForPath(destFileSpec);
|
||||
|
||||
// verify that passed-in URL is a valid media type
|
||||
if (!IsImage(destFileSpec) && !IsPlaylist(destFileSpec) && !IsMedia(destFileSpec))
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
wchar_t path_to_store[MAX_PATH] = {0};
|
||||
if (GetOnlineDownloadPath(this->key, this->info->GetName(), path_to_store))
|
||||
{
|
||||
wchar_t dlgtitle[256] = {0};
|
||||
CreateDirectoryW(path_to_store, NULL);
|
||||
|
||||
wchar_t destfile[MAX_PATH] = {0};
|
||||
PathCombineW(destfile, path_to_store, destFileSpec);
|
||||
|
||||
httpRetrieveFileW(hMainWindow, AutoChar(url), destfile, getStringW(IDS_DOWNLOADING,dlgtitle,256));
|
||||
|
||||
// TODO: optional adding to media library or not (param 3)
|
||||
LMDB_FILE_ADD_INFOW fi = {const_cast<wchar_t *>(destfile), -1, -1};
|
||||
sendMlIpc(ML_IPC_DB_ADDORUPDATEFILEW, (WPARAM)&fi);
|
||||
sendMlIpc(ML_IPC_DB_SYNCDB, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#undef CHECK_ID
|
||||
#define CHECK_ID(str, id) case id: return str(wFlags, pdispparams, pvarResult, puArgErr);
|
||||
HRESULT JSAPI2::DownloaderAPI::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::DownloaderAPI::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::DownloaderAPI::AddRef(void)
|
||||
{
|
||||
return InterlockedIncrement(&refCount);
|
||||
}
|
||||
|
||||
|
||||
ULONG JSAPI2::DownloaderAPI::Release(void)
|
||||
{
|
||||
LONG lRef = InterlockedDecrement(&refCount);
|
||||
if (lRef == 0) delete this;
|
||||
return lRef;
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
#include "JSAPI2_ExternalObject.h"
|
||||
#include "JSAPI2_svc_apicreator.h"
|
||||
#include "JSAPI2_TransportAPI.h"
|
||||
#include "JSAPI2_PlayerAPI.h"
|
||||
#include "JSAPI2_Downloader.h"
|
||||
#include "JSAPI2_SecurityAPI.h"
|
||||
#include "JSAPI2_Security.h"
|
||||
#include "JSAPI2_Bookmarks.h"
|
||||
#include "JSAPI2_Application.h"
|
||||
#include "JSAPI2_SkinAPI.h"
|
||||
#include "JSAPI2_MediaCore.h"
|
||||
#include "JSAPI2_AsyncDownloader.h"
|
||||
#include "JSAPI.h"
|
||||
#include "api.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "../nu/AutoChar.h"
|
||||
#include "../nu/AutoCharFn.h"
|
||||
#include <api/service/waservicefactory.h>
|
||||
#include <shlwapi.h>
|
||||
/* benski: basic thoughts
|
||||
|
||||
ExternalObject will be created "on demand" when ml_online loads a page
|
||||
so ExternalObjects will have a lifetime (unlike ExternalCOM which is a singleton)
|
||||
|
||||
create wasabi services for creating window.external.* objects
|
||||
when a window.external.* function is requested, services are enumerated
|
||||
the key is passed to the object creator. The returned object will be treated
|
||||
as a singleton from ExternalObject's perspective. It will be Release()'d when
|
||||
the ExternalObject is destroyed.
|
||||
|
||||
the basic layout will be
|
||||
window.external.API.method
|
||||
|
||||
e.g.
|
||||
window.external.Transport.Play();
|
||||
|
||||
any time that non-singleton objects need to be created (Config object,
|
||||
playlist object, etc) they will be created from a method within the API object
|
||||
e.g.
|
||||
var new_playlist = window.external.Playlist.Create();
|
||||
*/
|
||||
|
||||
JSAPI2::ExternalObject::ExternalObject(const wchar_t *_key)
|
||||
{
|
||||
hwnd=0;
|
||||
|
||||
if (_key)
|
||||
key = _wcsdup(_key);
|
||||
else
|
||||
key = 0;
|
||||
|
||||
refCount = 1;
|
||||
// create Config API now.
|
||||
|
||||
ConfigCOM *configCOM;
|
||||
wchar_t szPath[MAX_PATH] = {0};
|
||||
PathCombineW(szPath, CONFIGDIR, L"jscfg.ini");
|
||||
if (SUCCEEDED(ConfigCOM::CreateInstanceW(key, AutoCharFn(szPath), &configCOM)))
|
||||
{
|
||||
AddDispatch(L"Config", configCOM);
|
||||
configCOM->Release();
|
||||
}
|
||||
}
|
||||
|
||||
JSAPI2::ExternalObject::~ExternalObject()
|
||||
{
|
||||
for (JSAPI::DispatchTable::iterator itr = dispatchTable.begin(); itr != dispatchTable.end(); itr++)
|
||||
{
|
||||
//JSAPI::Dispatcher *entry = *itr;
|
||||
delete (*itr);
|
||||
}
|
||||
dispatchTable.clear();
|
||||
if (key) free(key);
|
||||
}
|
||||
|
||||
DWORD JSAPI2::ExternalObject::AddDispatch(const wchar_t *name, IDispatch *object)
|
||||
{
|
||||
int id = (int) dispatchTable.size();
|
||||
dispatchTable.push_back(new JSAPI::Dispatcher(name, id, object));
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
#define CHECK_ID(str, id)\
|
||||
if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L##str, -1))\
|
||||
{ rgdispid[i] = id; continue; }
|
||||
|
||||
HRESULT JSAPI2::ExternalObject::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 (GetDispID(rgszNames[i], fdexNameCaseSensitive, &rgdispid[i]) == DISPID_UNKNOWN)
|
||||
unknowns=true;
|
||||
}
|
||||
if (unknowns)
|
||||
return DISP_E_UNKNOWNNAME;
|
||||
else
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::ExternalObject::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::ExternalObject::GetTypeInfoCount(unsigned int FAR * pctinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::ExternalObject::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
|
||||
{
|
||||
return InvokeEx(dispid, lcid, wFlags, pdispparams, pvarResult, pexecinfo, 0);
|
||||
}
|
||||
|
||||
STDMETHODIMP JSAPI2::ExternalObject::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 if (IsEqualIID(riid, IID_IWasabiDispatchable))
|
||||
*ppvObject = (IWasabiDispatchable *)this;
|
||||
else
|
||||
{
|
||||
*ppvObject = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
ULONG JSAPI2::ExternalObject::AddRef(void)
|
||||
{
|
||||
return InterlockedIncrement(&refCount);
|
||||
}
|
||||
|
||||
ULONG JSAPI2::ExternalObject::Release(void)
|
||||
{
|
||||
LONG lRef = InterlockedDecrement(&refCount);
|
||||
if (lRef == 0) delete this;
|
||||
return lRef;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::ExternalObject::GetDispID(BSTR bstrName, DWORD grfdex, DISPID *pid)
|
||||
{
|
||||
*pid = DISP_E_UNKNOWNNAME;
|
||||
|
||||
for (size_t entry=0;entry!=dispatchTable.size();entry++)
|
||||
{
|
||||
if (!wcscmp(bstrName, dispatchTable[entry]->name))
|
||||
{
|
||||
if (dispatchTable[entry]->object)
|
||||
{
|
||||
*pid = (DISPID)entry;
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return DISPID_UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
// look it up in wasabi
|
||||
IDispatch *disp = 0;
|
||||
waServiceFactory *sf = 0;
|
||||
int n = 0;
|
||||
do
|
||||
{
|
||||
sf = WASABI_API_SVC->service_enumService(JSAPI2::svc_apicreator::getServiceType(), n++);
|
||||
if (!sf)
|
||||
break;
|
||||
|
||||
if (sf)
|
||||
{
|
||||
JSAPI2::svc_apicreator *creator = (JSAPI2::svc_apicreator *)sf->getInterface();
|
||||
if (creator)
|
||||
{
|
||||
disp = creator->CreateAPI(bstrName, key, static_cast<JSAPI::ifc_info *>(this));
|
||||
}
|
||||
sf->releaseInterface(creator);
|
||||
}
|
||||
} while (sf && !disp);
|
||||
*pid = AddDispatch(bstrName, disp);
|
||||
if (!disp)
|
||||
{
|
||||
*pid = DISP_E_UNKNOWNNAME;
|
||||
return DISPID_UNKNOWN;
|
||||
}
|
||||
else
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::ExternalObject::InvokeEx(DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
|
||||
{
|
||||
if (id >= 0 && (size_t)id < dispatchTable.size())
|
||||
{
|
||||
IDispatch *disp = dispatchTable[id]->object;
|
||||
if (disp)
|
||||
disp->AddRef(); // I assume we're supposed to do this, but I'm not 100% sure
|
||||
JSAPI_INIT_RESULT(pvarRes, VT_DISPATCH);
|
||||
JSAPI_SET_RESULT(pvarRes, pdispVal, disp);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::ExternalObject::DeleteMemberByName(BSTR bstrName, DWORD grfdex)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::ExternalObject::DeleteMemberByDispID(DISPID id)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::ExternalObject::GetMemberProperties(DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::ExternalObject::GetMemberName(DISPID id, BSTR *pbstrName)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::ExternalObject::GetNextDispID(DWORD grfdex, DISPID id, DISPID *pid)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::ExternalObject::GetNameSpaceParent(IUnknown **ppunk)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::ExternalObject::QueryDispatchable(REFIID riid, Dispatchable **ppDispatchable)
|
||||
{
|
||||
if (IsEqualIID(riid, JSAPI::IID_JSAPI_ifc_info))
|
||||
{
|
||||
*ppDispatchable = (JSAPI::ifc_info *)this;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppDispatchable = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
(*ppDispatchable)->AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
const wchar_t *JSAPI2::ExternalObject::GetUserAgent()
|
||||
{
|
||||
return L"JSAPI2";
|
||||
}
|
||||
|
||||
void JSAPI2::ExternalObject::SetHWND(HWND hwnd)
|
||||
{
|
||||
this->hwnd = hwnd;
|
||||
}
|
||||
|
||||
HWND JSAPI2::ExternalObject::GetHWND()
|
||||
{
|
||||
return hwnd;
|
||||
}
|
||||
|
||||
void JSAPI2::ExternalObject::SetName(const wchar_t *name)
|
||||
{
|
||||
JSAPI2::security.AssociateName(key, name);
|
||||
}
|
||||
|
||||
const wchar_t *JSAPI2::ExternalObject::GetName()
|
||||
{
|
||||
return JSAPI2::security.GetAssociatedName(key);
|
||||
}
|
||||
|
||||
int JSAPI2::ExternalObject::AddAPI(const wchar_t *name, IDispatch *dispatch)
|
||||
{
|
||||
if (dispatch)
|
||||
{
|
||||
dispatch->AddRef();
|
||||
AddDispatch(name, dispatch);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#define CBCLASS JSAPI2::ExternalObject
|
||||
START_DISPATCH;
|
||||
CB(JSAPI_IFC_INFO_GETUSERAGENT, GetUserAgent)
|
||||
VCB(JSAPI_IFC_INFO_SETHWND, SetHWND)
|
||||
CB(JSAPI_IFC_INFO_GETHWND, GetHWND)
|
||||
VCB(JSAPI_IFC_INFO_SETNAME, SetName)
|
||||
CB(JSAPI_IFC_INFO_GETNAME, GetName)
|
||||
CB(JSAPI_IFC_INFO_ADDAPI, AddAPI)
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <ocidl.h>
|
||||
#include "JSAPI_DispatchTable.h"
|
||||
#include "../nu/ConfigCOM.h"
|
||||
#include "IWasabiDispatchable.h"
|
||||
#include "JSAPI_Info.h"
|
||||
#include <dispex.h>
|
||||
|
||||
namespace JSAPI2
|
||||
{
|
||||
class ExternalObject : public IDispatchEx,
|
||||
public IWasabiDispatchable,
|
||||
public JSAPI::ifc_info
|
||||
{
|
||||
public:
|
||||
ExternalObject(const wchar_t *_key);
|
||||
~ExternalObject();
|
||||
// *** IUnknown Methods ***
|
||||
STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
|
||||
STDMETHOD_(ULONG, AddRef)(void);
|
||||
STDMETHOD_(ULONG, Release)(void);
|
||||
|
||||
private:
|
||||
// *** 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);
|
||||
|
||||
// *** IDispatchEx Methods ***
|
||||
STDMETHOD (GetDispID)(BSTR bstrName, DWORD grfdex, DISPID *pid);
|
||||
STDMETHOD (InvokeEx)(DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller);
|
||||
STDMETHOD (DeleteMemberByName)(BSTR bstrName, DWORD grfdex) ;
|
||||
STDMETHOD (DeleteMemberByDispID)(DISPID id);
|
||||
STDMETHOD (GetMemberProperties)(DISPID id, DWORD grfdexFetch, DWORD *pgrfdex);
|
||||
STDMETHOD (GetMemberName)(DISPID id, BSTR *pbstrName);
|
||||
STDMETHOD (GetNextDispID)(DWORD grfdex, DISPID id, DISPID *pid);
|
||||
STDMETHOD (GetNameSpaceParent)(IUnknown **ppunk);
|
||||
|
||||
// *** IWasabiDispatchable Methods ***
|
||||
STDMETHOD(QueryDispatchable)(REFIID riid, Dispatchable **ppDispatchable);
|
||||
|
||||
// *** JSAPI::ifc_info Methods ***
|
||||
const wchar_t *GetUserAgent();
|
||||
void SetHWND(HWND hwnd);
|
||||
HWND GetHWND();
|
||||
void SetName(const wchar_t *name);
|
||||
const wchar_t *GetName();
|
||||
int AddAPI(const wchar_t *name, IDispatch *dispatch);
|
||||
private:
|
||||
// private helper methods
|
||||
DWORD AddDispatch(const wchar_t *name, IDispatch *object);
|
||||
|
||||
// members
|
||||
JSAPI::DispatchTable dispatchTable;
|
||||
volatile LONG refCount;
|
||||
wchar_t *key;
|
||||
HWND hwnd;
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
#include "JSAPI2_MediaCore.h"
|
||||
#include "main.h"
|
||||
#include "api.h"
|
||||
#include "JSAPI.h"
|
||||
#include "JSAPI2_Security.h"
|
||||
#include "JSAPI2_CallbackManager.h"
|
||||
|
||||
JSAPI2::MediaCoreAPI::MediaCoreAPI(const wchar_t *_key, JSAPI::ifc_info *_info) : metadataGuard("MediaCoreAPI metadata Guard")
|
||||
{
|
||||
info = _info;
|
||||
key = _key;
|
||||
refCount = 1;
|
||||
}
|
||||
|
||||
JSAPI2::MediaCoreAPI::~MediaCoreAPI()
|
||||
{
|
||||
JSAPI2::callbackManager.Deregister(this);
|
||||
}
|
||||
|
||||
#define DISP_TABLE \
|
||||
CHECK_ID(IsRegisteredExtension)\
|
||||
CHECK_ID(GetMetadata)\
|
||||
CHECK_ID(AddMetadataHook)\
|
||||
CHECK_ID(RemoveMetadataHook)\
|
||||
|
||||
|
||||
#define CHECK_ID(str) JSAPI_DISP_ENUMIFY(str),
|
||||
enum {
|
||||
DISP_TABLE
|
||||
};
|
||||
|
||||
#undef CHECK_ID
|
||||
#define CHECK_ID(str)\
|
||||
if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L## #str, -1))\
|
||||
{ rgdispid[i] = JSAPI_DISP_ENUMIFY(str); continue; }
|
||||
|
||||
HRESULT JSAPI2::MediaCoreAPI::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::MediaCoreAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::MediaCoreAPI::GetTypeInfoCount(unsigned int FAR * pctinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::MediaCoreAPI::IsRegisteredExtension(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);
|
||||
|
||||
const wchar_t *extension = JSAPI_PARAM(pdispparams, 1).bstrVal;
|
||||
int start_offs=0;
|
||||
wchar_t filename[MAX_PATH] = {0};
|
||||
StringCbPrintfW(filename, sizeof(filename), L"test.%s", extension);
|
||||
In_Module *i = in_setmod_noplay(filename, &start_offs);
|
||||
if (i)
|
||||
V_BOOL(pvarResult) = VARIANT_TRUE;
|
||||
else
|
||||
V_BOOL(pvarResult) = VARIANT_FALSE;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::MediaCoreAPI::GetMetadata(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 2);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 2, VT_BSTR, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
|
||||
|
||||
if (security.GetActionAuthorization(L"mediacore", L"metadata", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
wchar_t buffer[4096] = {0};
|
||||
extendedFileInfoStructW info;
|
||||
|
||||
info.filename = JSAPI_PARAM(pdispparams, 1).bstrVal;
|
||||
info.metadata = JSAPI_PARAM(pdispparams, 2).bstrVal;
|
||||
info.ret = buffer;
|
||||
info.retlen = sizeof(buffer)/sizeof(*buffer);
|
||||
|
||||
if (NULL != info.filename &&
|
||||
NULL != info.metadata)
|
||||
{
|
||||
if (0 == SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&info, IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE))
|
||||
info.ret = NULL;
|
||||
|
||||
JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(info.ret));
|
||||
}
|
||||
else
|
||||
JSAPI_EMPTY_RESULT(pvarResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_EMPTY_RESULT(pvarResult);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
void JSAPI2::MediaCoreAPI::RemoveMetadataHook(const wchar_t *filename)
|
||||
{
|
||||
Nullsoft::Utility::AutoLock metadataLock(metadataGuard);
|
||||
RemoveMetadataHook_again:
|
||||
MetadataMap::iterator itr;
|
||||
for (itr=metadataMap.begin();itr!=metadataMap.end();itr++)
|
||||
{
|
||||
if (!_wcsicmp(filename, itr->url.c_str()))
|
||||
{
|
||||
metadataMap.erase(itr);
|
||||
goto RemoveMetadataHook_again;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JSAPI2::MediaCoreAPI::RemoveMetadataHook(const wchar_t *filename, const wchar_t *tag)
|
||||
{
|
||||
Nullsoft::Utility::AutoLock metadataLock(metadataGuard);
|
||||
RemoveMetadataHook_again2:
|
||||
MetadataMap::iterator itr;
|
||||
for (itr=metadataMap.begin();itr!=metadataMap.end();itr++)
|
||||
{
|
||||
if (!_wcsicmp(filename, itr->url.c_str())
|
||||
&& !_wcsicmp(tag, itr->tag.c_str()))
|
||||
{
|
||||
metadataMap.erase(itr);
|
||||
goto RemoveMetadataHook_again2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::MediaCoreAPI::AddMetadataHook(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 3);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 2, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 3, VT_BSTR, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
|
||||
if (security.GetActionAuthorization(L"mediacore", L"metadatahook", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
const wchar_t *filename = JSAPI_PARAM(pdispparams, 1).bstrVal;
|
||||
const wchar_t *tag = JSAPI_PARAM(pdispparams, 2).bstrVal;
|
||||
const wchar_t *value = JSAPI_PARAM(pdispparams, 3).bstrVal;
|
||||
|
||||
if (NULL == filename || L'\0' == *filename ||
|
||||
NULL == tag || L'\0' == *tag)
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
JSAPI2::callbackManager.Register(this);
|
||||
metadata_info info;
|
||||
info.url = filename;
|
||||
info.tag = tag;
|
||||
info.metadata= value;
|
||||
|
||||
Nullsoft::Utility::AutoLock metadataLock(metadataGuard);
|
||||
|
||||
RemoveMetadataHook(filename, tag);
|
||||
|
||||
metadataMap.push_back(info);
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::MediaCoreAPI::RemoveMetadataHook(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 1, 2);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 2, VT_BSTR, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
|
||||
const wchar_t *filename = JSAPI_PARAM(pdispparams, 1).bstrVal;
|
||||
const wchar_t *tag = JSAPI_PARAM_OPTIONAL(pdispparams, 2, bstrVal, 0);
|
||||
|
||||
if (NULL == filename || L'\0' == *filename)
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (NULL != tag && L'\0' == *tag)
|
||||
tag = NULL;
|
||||
|
||||
if (NULL != tag)
|
||||
RemoveMetadataHook(filename, tag);
|
||||
else
|
||||
RemoveMetadataHook(filename);
|
||||
|
||||
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
bool JSAPI2::MediaCoreAPI::OverrideMetadata(const wchar_t *filename, const wchar_t *tag, wchar_t *out, size_t outCch)
|
||||
{
|
||||
Nullsoft::Utility::AutoLock metadataLock(metadataGuard);
|
||||
MetadataMap::iterator itr;
|
||||
for (itr=metadataMap.begin();itr!=metadataMap.end();itr++)
|
||||
{
|
||||
if (!_wcsicmp(filename, itr->url.c_str()) && !_wcsicmp(tag, itr->tag.c_str()))
|
||||
{
|
||||
StringCchCopyW(out, outCch, itr->metadata.c_str());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#undef CHECK_ID
|
||||
#define CHECK_ID(str) case JSAPI_DISP_ENUMIFY(str): return str(wFlags, pdispparams, pvarResult, puArgErr);
|
||||
HRESULT JSAPI2::MediaCoreAPI::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::MediaCoreAPI::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::MediaCoreAPI::AddRef(void)
|
||||
{
|
||||
return InterlockedIncrement(&refCount);
|
||||
}
|
||||
|
||||
|
||||
ULONG JSAPI2::MediaCoreAPI::Release(void)
|
||||
{
|
||||
LONG lRef = InterlockedDecrement(&refCount);
|
||||
if (lRef == 0) delete this;
|
||||
return lRef;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
#include <ocidl.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "../nu/AutoLock.h"
|
||||
#include "JSAPI_Info.h"
|
||||
|
||||
namespace JSAPI2
|
||||
{
|
||||
class MediaCoreAPI : public IDispatch
|
||||
{
|
||||
public:
|
||||
MediaCoreAPI(const wchar_t *_key, JSAPI::ifc_info *info);
|
||||
~MediaCoreAPI();
|
||||
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);
|
||||
|
||||
/* For CallbackManager */
|
||||
bool OverrideMetadata(const wchar_t *filename, const wchar_t *tag, wchar_t *out, size_t outCch);
|
||||
private:
|
||||
const wchar_t *key;
|
||||
volatile LONG refCount;
|
||||
JSAPI::ifc_info *info;
|
||||
|
||||
struct metadata_info
|
||||
{
|
||||
std::wstring url;
|
||||
std::wstring tag;
|
||||
std::wstring metadata;
|
||||
};
|
||||
typedef std::vector<metadata_info> MetadataMap;
|
||||
MetadataMap metadataMap;
|
||||
Nullsoft::Utility::LockGuard metadataGuard;
|
||||
|
||||
STDMETHOD (IsRegisteredExtension)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (GetMetadata)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (AddMetadataHook)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (RemoveMetadataHook)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
void RemoveMetadataHook(const wchar_t *filename);
|
||||
void RemoveMetadataHook(const wchar_t *filename, const wchar_t *tag);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
#include "JSAPI2_PlayerAPI.h"
|
||||
#include "JSAPI2_Security.h"
|
||||
#include "main.h"
|
||||
#include "JSAPI.h"
|
||||
#include "ipc_pe.h"
|
||||
#include <strsafe.h>
|
||||
|
||||
JSAPI2::PlayerAPI::PlayerAPI(const wchar_t *_key, JSAPI::ifc_info *_info)
|
||||
{
|
||||
info = _info;
|
||||
key = _key;
|
||||
refCount = 1;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
DISPID_PLAYERAPI_PLAY, // start playing a file immediately (and clear the old playlist)
|
||||
DISPID_PLAYERAPI_ENQUEUE, // insert a URL at the end of the playlist
|
||||
DISPID_PLAYERAPI_INSERT, // insert a URL at a particular position in the playlist
|
||||
DISPID_PLAYERAPI_CLEARQUEUE, // clear the playlist
|
||||
DISPID_PLAYERAPI_GETURL, // get the URL (or filename) for an item in the playlist
|
||||
DISPID_PLAYERAPI_GETTITLE, // get title for an item in the playlist
|
||||
DISPID_PLAYERAPI_GETMETADATA, // get a metadata string for an item in the playlist
|
||||
|
||||
// properties
|
||||
DISPID_PLAYERAPI_LENGTH, // length of the playlist
|
||||
DISPID_PLAYERAPI_POSITION, // position in the playlist
|
||||
};
|
||||
|
||||
#define DISP_TABLE \
|
||||
CHECK_ID(Play, DISPID_PLAYERAPI_PLAY)\
|
||||
CHECK_ID(Enqueue, DISPID_PLAYERAPI_ENQUEUE)\
|
||||
CHECK_ID(Insert, DISPID_PLAYERAPI_INSERT)\
|
||||
CHECK_ID(ClearQueue, DISPID_PLAYERAPI_CLEARQUEUE)\
|
||||
CHECK_ID(GetURL, DISPID_PLAYERAPI_GETURL)\
|
||||
CHECK_ID(GetTitle, DISPID_PLAYERAPI_GETTITLE)\
|
||||
CHECK_ID(GetMetadata, DISPID_PLAYERAPI_GETMETADATA)\
|
||||
CHECK_ID(length, DISPID_PLAYERAPI_LENGTH)\
|
||||
CHECK_ID(cursor, DISPID_PLAYERAPI_POSITION)\
|
||||
|
||||
#define CHECK_ID(str, id)\
|
||||
if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L## #str, -1))\
|
||||
{ rgdispid[i] = id; continue; }
|
||||
|
||||
HRESULT JSAPI2::PlayerAPI::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::PlayerAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlayerAPI::GetTypeInfoCount(unsigned int FAR * pctinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlayerAPI::Play(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 1, 3);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 2, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 3, VT_I4, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
|
||||
if (security.GetActionAuthorization(L"player", L"playlist", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
enqueueFileWithMetaStructW s = {0,0,0,0};
|
||||
SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_DELETE);
|
||||
|
||||
//PlayList_delete();
|
||||
s.filename = JSAPI_PARAM(pdispparams, 1).bstrVal;
|
||||
s.title = JSAPI_PARAM_OPTIONAL(pdispparams, 2, bstrVal, 0);
|
||||
s.ext = NULL;
|
||||
s.length = JSAPI_PARAM_OPTIONAL(pdispparams, 3, lVal, 0);
|
||||
|
||||
/*if (title)
|
||||
PlayList_append_withinfo(filename, title, length);
|
||||
else
|
||||
PlayList_appendthing(filename, 0);
|
||||
plEditRefresh();
|
||||
*/
|
||||
SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&s, IPC_PLAYFILEW);
|
||||
SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_STARTPLAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlayerAPI::Enqueue(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 1, 3);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 2, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 3, VT_I4, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
|
||||
if (security.GetActionAuthorization(L"player", L"playlist", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
enqueueFileWithMetaStructW s = {0,0,0,0};
|
||||
|
||||
//PlayList_delete();
|
||||
s.filename = JSAPI_PARAM(pdispparams, 1).bstrVal;
|
||||
s.title = JSAPI_PARAM_OPTIONAL(pdispparams, 2, bstrVal, 0);
|
||||
s.ext = NULL;
|
||||
s.length = JSAPI_PARAM_OPTIONAL(pdispparams, 3, lVal, 0);
|
||||
|
||||
/*if (title)
|
||||
PlayList_append_withinfo(filename, title, length);
|
||||
else
|
||||
PlayList_appendthing(filename, 0);
|
||||
plEditRefresh();
|
||||
*/
|
||||
SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&s, IPC_PLAYFILEW);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT JSAPI2::PlayerAPI::Insert(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 2, 4);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 2, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 3, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 4, VT_I4, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
|
||||
if (security.GetActionAuthorization(L"player", L"playlist", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
fileinfoW info;
|
||||
COPYDATASTRUCT cds;
|
||||
cds.dwData = IPC_PE_INSERTFILENAMEW;
|
||||
cds.lpData = &info;
|
||||
cds.cbData = sizeof(info);
|
||||
StringCbCopyW(info.file, sizeof(info.file), JSAPI_PARAM(pdispparams, 2).bstrVal);
|
||||
info.index = JSAPI_PARAM(pdispparams, 1).lVal;
|
||||
// benski> TODO const wchar_t *title = JSAPI_PARAM_OPTIONAL(pdispparams, 3, bstrVal, 0);
|
||||
// benski> TODO int length = JSAPI_PARAM_OPTIONAL(pdispparams, 4, lVal, 0);
|
||||
|
||||
SendMessageW(hPLWindow, WM_COPYDATA, 0, (LPARAM)&cds);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlayerAPI::ClearQueue(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
|
||||
if (security.GetActionAuthorization(L"player", L"playlist", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_DELETE);
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlayerAPI::GetURL(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_I4, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
|
||||
|
||||
if (security.GetActionAuthorization(L"player", L"metadata", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
int position = JSAPI_PARAM(pdispparams, 1).lVal;
|
||||
wchar_t filename[FILENAME_SIZE] = {0};
|
||||
if (PlayList_getitem2W(position, filename, 0) == 0)
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(filename));
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_EMPTY_RESULT(pvarResult);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_EMPTY_RESULT(pvarResult);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlayerAPI::GetTitle(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_I4, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
|
||||
|
||||
if (security.GetActionAuthorization(L"player", L"metadata", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
int position = JSAPI_PARAM(pdispparams, 1).lVal;
|
||||
wchar_t filetitle[FILETITLE_SIZE] = {0};
|
||||
if (PlayList_getitem2W(position, 0, filetitle) == 0)
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(filetitle));
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_EMPTY_RESULT(pvarResult);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_EMPTY_RESULT(pvarResult);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlayerAPI::GetMetadata(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 2);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 2, VT_BSTR, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
|
||||
|
||||
if (security.GetActionAuthorization(L"player", L"metadata", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
int position = JSAPI_PARAM(pdispparams, 1).lVal;
|
||||
wchar_t filename[FILENAME_SIZE] = {0};
|
||||
if (PlayList_getitem2W(position, filename, 0) == 0)
|
||||
{
|
||||
wchar_t buffer[4096] = {0};
|
||||
extendedFileInfoStructW info;
|
||||
|
||||
info.filename = filename;
|
||||
info.metadata = JSAPI_PARAM(pdispparams, 2).bstrVal;
|
||||
info.ret = buffer;
|
||||
info.retlen = sizeof(buffer)/sizeof(*buffer);
|
||||
|
||||
if (NULL != info.filename &&
|
||||
NULL != info.metadata)
|
||||
{
|
||||
if (0 == SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&info, IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE))
|
||||
info.ret = NULL;
|
||||
|
||||
JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(info.ret));
|
||||
}
|
||||
else
|
||||
JSAPI_EMPTY_RESULT(pvarResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_EMPTY_RESULT(pvarResult);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_EMPTY_RESULT(pvarResult);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlayerAPI::length(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
if (wFlags & DISPATCH_PROPERTYGET)
|
||||
{
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_I4;
|
||||
V_I4(pvarResult) = PlayList_getlength();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlayerAPI::cursor(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
if (wFlags & DISPATCH_PROPERTYPUT)
|
||||
{
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
|
||||
if (security.GetActionAuthorization(L"player", L"playlist", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
PlayList_setposition(JSAPI_PARAM(pdispparams, 1).lVal);
|
||||
plEditRefresh();
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
else if (wFlags & DISPATCH_PROPERTYGET)
|
||||
{
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_I4;
|
||||
V_I4(pvarResult) = PlayList_getPosition();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
|
||||
#undef CHECK_ID
|
||||
#define CHECK_ID(str, id) case id: return str(wFlags, pdispparams, pvarResult, puArgErr);
|
||||
HRESULT JSAPI2::PlayerAPI::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::PlayerAPI::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::PlayerAPI::AddRef(void)
|
||||
{
|
||||
return InterlockedIncrement(&refCount);
|
||||
}
|
||||
|
||||
|
||||
ULONG JSAPI2::PlayerAPI::Release(void)
|
||||
{
|
||||
LONG lRef = InterlockedDecrement(&refCount);
|
||||
if (lRef == 0) delete this;
|
||||
return lRef;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <ocidl.h>
|
||||
#include "JSAPI_Info.h"
|
||||
|
||||
namespace JSAPI2
|
||||
{
|
||||
class PlayerAPI : public IDispatch
|
||||
{
|
||||
public:
|
||||
PlayerAPI(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 (Play)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (Enqueue)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (Insert)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (ClearQueue)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (GetURL)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (GetTitle)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (GetMetadata)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
|
||||
STDMETHOD (length)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (cursor)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
#include "api.h"
|
||||
#include "JSAPI2_Security.h"
|
||||
#include "JSAPI2_svc_apicreator.h"
|
||||
#include <bfc/platform/types.h>
|
||||
#include "main.h"
|
||||
#include "resource.h"
|
||||
#include "language.h"
|
||||
#include <api/service/waservicefactory.h>
|
||||
#include <shlwapi.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
JSAPI2::Security::~Security()
|
||||
{
|
||||
for(NameMap::iterator iter = names.begin(); iter != names.end(); iter++)
|
||||
{
|
||||
if (NULL != iter->second)
|
||||
free(iter->second);
|
||||
}
|
||||
}
|
||||
|
||||
int JSAPI2::Security::GetActionAuthorization( const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, JSAPI::ifc_info *info, int default_authorization, AuthorizationData *data )
|
||||
{
|
||||
// TODO: benski> we should build a cache table, as we may hit this function repeatedly and it incurs a file lock
|
||||
// but for now it will get the ball rolling
|
||||
if ( action )
|
||||
{
|
||||
wchar_t group_action[ 256 ] = { 0 };
|
||||
StringCbPrintfW( group_action, sizeof( group_action ), L"%s@%s", action, group );
|
||||
int authorization = GetPrivateProfileIntW( authorization_key, group_action, api_security::ACTION_UNDEFINED, JSAPI2_INIFILE );
|
||||
if ( authorization != api_security::ACTION_UNDEFINED )
|
||||
return authorization;
|
||||
}
|
||||
if ( group )
|
||||
{
|
||||
int authorization = GetPrivateProfileIntW( authorization_key, group, api_security::ACTION_UNDEFINED, JSAPI2_INIFILE );
|
||||
if ( authorization != api_security::ACTION_UNDEFINED )
|
||||
return authorization;
|
||||
}
|
||||
|
||||
int authorization = GetPrivateProfileIntW( authorization_key, authorization_key, default_authorization, JSAPI2_INIFILE );
|
||||
|
||||
if ( ( ACTION_UNDEFINED == authorization || ACTION_PROMPT == authorization ) &&
|
||||
false != IsAuthorizationBypassed( authorization_key ) )
|
||||
{
|
||||
authorization = ACTION_ALLOWED;
|
||||
}
|
||||
|
||||
if ( ( authorization == ACTION_UNDEFINED || authorization == ACTION_PROMPT )/* if we have to prompt */
|
||||
&& default_authorization != ACTION_UNDEFINED /* clients pass ACTION_UNDEFINED, API's don't */
|
||||
&& group )
|
||||
{
|
||||
waServiceFactory *sf = 0;
|
||||
int n = 0;
|
||||
do
|
||||
{
|
||||
sf = WASABI_API_SVC->service_enumService( JSAPI2::svc_apicreator::getServiceType(), n++ );
|
||||
if ( !sf )
|
||||
break;
|
||||
|
||||
if ( sf )
|
||||
{
|
||||
JSAPI2::svc_apicreator *creator = (JSAPI2::svc_apicreator *)sf->getInterface();
|
||||
if ( creator )
|
||||
{
|
||||
HWND parent = 0;
|
||||
if ( info )
|
||||
parent = info->GetHWND();
|
||||
if ( !parent )
|
||||
parent = this->GetAssociation( authorization_key );
|
||||
|
||||
int prompt = creator->PromptForAuthorization( parent, group, action, authorization_key, data );
|
||||
if ( ( prompt & JSAPI2::svc_apicreator::AUTHORIZATION_MASK ) != JSAPI2::svc_apicreator::AUTHORIZATION_UNDEFINED )
|
||||
{
|
||||
sf->releaseInterface( creator );
|
||||
int new_authorization = 0;
|
||||
switch ( prompt & JSAPI2::svc_apicreator::AUTHORIZATION_MASK )
|
||||
{
|
||||
case JSAPI2::svc_apicreator::AUTHORIZATION_ALLOW:
|
||||
new_authorization = ACTION_ALLOWED;
|
||||
break;
|
||||
case JSAPI2::svc_apicreator::AUTHORIZATION_DENY:
|
||||
new_authorization = ACTION_DISALLOWED;
|
||||
break;
|
||||
default:
|
||||
return default_authorization;
|
||||
}
|
||||
if ( prompt & JSAPI2::svc_apicreator::AUTHORIZATION_FLAG_GROUP_ONLY )
|
||||
action = 0;
|
||||
if ( prompt & JSAPI2::svc_apicreator::AUTHORIZATION_FLAG_ALWAYS )
|
||||
SetActionAuthorization( group, action, authorization_key, new_authorization );
|
||||
if ( prompt & JSAPI2::svc_apicreator::AUTHORIZATION_FLAG_ALWAYS_FOR_SERVICE )
|
||||
SetActionAuthorization( 0, 0, authorization_key, new_authorization );
|
||||
|
||||
return new_authorization;
|
||||
}
|
||||
}
|
||||
|
||||
sf->releaseInterface( creator );
|
||||
}
|
||||
} while ( sf );
|
||||
}
|
||||
|
||||
return authorization;
|
||||
}
|
||||
|
||||
int JSAPI2::Security::SetActionAuthorization(const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, int authorization)
|
||||
{
|
||||
// TODO: benski> we should build a cache table, as we may hit this function repeatedly and it incurs a file lock
|
||||
// but for now it will get the ball rolling
|
||||
wchar_t intval[64] = {0};
|
||||
_itow(authorization, intval, 10);
|
||||
if (action)
|
||||
{
|
||||
wchar_t group_action[256] = {0};
|
||||
StringCbPrintfW(group_action, sizeof(group_action), L"%s@%s", action, group);
|
||||
WritePrivateProfileStringW(authorization_key, group_action, intval, JSAPI2_INIFILE);
|
||||
}
|
||||
else if (group)
|
||||
WritePrivateProfileStringW(authorization_key, group, intval, JSAPI2_INIFILE);
|
||||
else
|
||||
WritePrivateProfileStringW(authorization_key, authorization_key, intval, JSAPI2_INIFILE);
|
||||
|
||||
return JSAPI2::api_security::SUCCESS;
|
||||
}
|
||||
|
||||
void JSAPI2::Security::Associate(const wchar_t *authorization_key, HWND hwnd)
|
||||
{
|
||||
unsigned long key;
|
||||
if (FALSE == StrToIntExW(authorization_key, STIF_DEFAULT, (int*)&key))
|
||||
return;
|
||||
|
||||
associations[key] = (void *)hwnd;
|
||||
}
|
||||
|
||||
HWND JSAPI2::Security::GetAssociation(const wchar_t *authorization_key)
|
||||
{
|
||||
unsigned long key;
|
||||
if (FALSE == StrToIntExW(authorization_key, STIF_DEFAULT, (int*)&key))
|
||||
return NULL;
|
||||
|
||||
AssociationMap::iterator iter = associations.find(key);
|
||||
return (HWND)((iter != associations.end()) ? iter->second : NULL);
|
||||
}
|
||||
|
||||
|
||||
INT_PTR JSAPI2_SecurityPrompt(HWND hParent, LPCWSTR pszCaption, LPCWSTR pszTitle, LPCWSTR pszMessage, UINT flags);
|
||||
|
||||
int JSAPI2::Security::SecurityPrompt(HWND parent, const wchar_t *title_string, const wchar_t *display_string, int flags)
|
||||
{
|
||||
return (INT_PTR)JSAPI2_SecurityPrompt(parent, NULL, title_string, display_string, flags);
|
||||
}
|
||||
|
||||
void JSAPI2::Security::AssociateName(const wchar_t *authorization_key, const wchar_t *name)
|
||||
{
|
||||
unsigned long key;
|
||||
if (FALSE == StrToIntExW(authorization_key, STIF_DEFAULT, (int*)&key))
|
||||
return;
|
||||
|
||||
NameMap::iterator iter = names.find(key);
|
||||
if (NULL != name)
|
||||
{
|
||||
if (iter != names.end())
|
||||
{
|
||||
if (NULL != iter->second) free(iter->second);
|
||||
iter->second = _wcsdup(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
names.insert({key, _wcsdup(name)});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (iter != names.end())
|
||||
{
|
||||
if (NULL != iter->second)
|
||||
{
|
||||
free(iter->second);
|
||||
iter->second = NULL;
|
||||
}
|
||||
names.erase(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const wchar_t *JSAPI2::Security::GetAssociatedName(const wchar_t *authorization_key)
|
||||
{
|
||||
unsigned long key;
|
||||
if (FALSE == StrToIntExW(authorization_key, STIF_DEFAULT, (int*)&key))
|
||||
return NULL;
|
||||
|
||||
NameMap::iterator iter = names.find(key);
|
||||
return (iter != names.end()) ? iter->second : NULL;
|
||||
}
|
||||
|
||||
void JSAPI2::Security::ResetAuthorization(const wchar_t *authorization_key)
|
||||
{
|
||||
const wchar_t empty[2] = {0, 0};
|
||||
WritePrivateProfileSectionW(authorization_key, empty, JSAPI2_INIFILE);
|
||||
}
|
||||
|
||||
void JSAPI2::Security::SetBypass(const wchar_t *authorization_key, bool enable_bypass)
|
||||
{
|
||||
size_t index = bypassList.size();
|
||||
|
||||
unsigned long key;
|
||||
if (FALSE == StrToIntExW(authorization_key, STIF_DEFAULT, (int*)&key))
|
||||
return;
|
||||
|
||||
while(index--)
|
||||
{
|
||||
if (bypassList[index] == key)
|
||||
{
|
||||
if (false == enable_bypass)
|
||||
bypassList.erase(bypassList.begin() + index);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (false != enable_bypass)
|
||||
bypassList.push_back(key);
|
||||
}
|
||||
|
||||
bool JSAPI2::Security::IsAuthorizationBypassed(const wchar_t *authorization_key)
|
||||
{
|
||||
size_t index = bypassList.size();
|
||||
if (0 == index) return false;
|
||||
|
||||
unsigned long key;
|
||||
if (FALSE == StrToIntExW(authorization_key, STIF_DEFAULT, (int*)&key))
|
||||
return false;
|
||||
|
||||
while(index--)
|
||||
{
|
||||
if (bypassList[index] == key)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
JSAPI2::Security JSAPI2::security;
|
||||
|
||||
#define CBCLASS JSAPI2::Security
|
||||
START_DISPATCH;
|
||||
CB(JSAPI2_API_SECURITY_GETACTIONAUTHORIZATION, GetActionAuthorization);
|
||||
CB(JSAPI2_API_SECURITY_SETACTIONAUTHORIZATION, SetActionAuthorization);
|
||||
VCB(JSAPI2_API_SECURITY_ASSOCIATE, Associate);
|
||||
CB(JSAPI2_API_SECURITY_GETASSOCIATION, GetAssociation);
|
||||
CB(JSAPI2_API_SECURITY_SECURITYPROMPT, SecurityPrompt);
|
||||
VCB(JSAPI2_API_SECURITY_ASSOCIATENAME, AssociateName);
|
||||
CB(JSAPI2_API_SECURITY_GETASSOCIATEDNAME, GetAssociatedName);
|
||||
VCB(JSAPI2_API_SECURITY_RESETAUTHORIZATION, ResetAuthorization);
|
||||
VCB(JSAPI2_API_SECURITY_SETBYPASS, SetBypass);
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include "JSAPI2_api_security.h"
|
||||
#include <bfc/platform/types.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "JSAPI_Info.h"
|
||||
|
||||
namespace JSAPI2
|
||||
{
|
||||
class Security : public JSAPI2::api_security
|
||||
{
|
||||
public:
|
||||
~Security();
|
||||
static const char *getServiceName() { return "JSAPI2 Security API"; }
|
||||
static const GUID getServiceGuid() { return api_securityGUID; }
|
||||
int GetActionAuthorization(const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, JSAPI::ifc_info *info, int default_authorization = ACTION_UNDEFINED, AuthorizationData *data = 0);
|
||||
int SetActionAuthorization(const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, int authorization);
|
||||
void Associate(const wchar_t *authorization_key, HWND hwnd);
|
||||
HWND GetAssociation(const wchar_t *authorization_key);
|
||||
int SecurityPrompt(HWND hwnd, const wchar_t *title_string, const wchar_t *display_string, int flags);
|
||||
void AssociateName(const wchar_t *authorization_key, const wchar_t *name);
|
||||
const wchar_t *GetAssociatedName(const wchar_t *authorization_key);
|
||||
void ResetAuthorization(const wchar_t *authorization_key);
|
||||
void SetBypass(const wchar_t *authorization_key, bool enable_bypass);
|
||||
|
||||
protected:
|
||||
bool IsAuthorizationBypassed(const wchar_t *authorization_key);
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
|
||||
|
||||
private:
|
||||
typedef std::map<uint32_t, wchar_t*> NameMap;
|
||||
typedef std::map<uint32_t, void*> AssociationMap;
|
||||
typedef std::vector<uint32_t> BypassList;
|
||||
AssociationMap associations;
|
||||
NameMap names;
|
||||
BypassList bypassList;
|
||||
};
|
||||
|
||||
extern Security security;
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
#include "JSAPI2_SecurityAPI.h"
|
||||
#include "JSAPI2_Security.h"
|
||||
#include "main.h"
|
||||
#include "JSAPI.h"
|
||||
|
||||
JSAPI2::SecurityAPI::SecurityAPI(const wchar_t *_key, JSAPI::ifc_info *_info)
|
||||
{
|
||||
info = _info;
|
||||
key = _key;
|
||||
refCount = 1;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
DISPID_SECURITYAPI_SETACTIONAUTHORIZATION,
|
||||
DISPID_SECURITYAPI_GETACTIONAUTHORIZATION,
|
||||
};
|
||||
|
||||
#define DISP_TABLE \
|
||||
CHECK_ID(SetActionAuthorization, DISPID_SECURITYAPI_SETACTIONAUTHORIZATION)\
|
||||
CHECK_ID(GetActionAuthorization, DISPID_SECURITYAPI_GETACTIONAUTHORIZATION)\
|
||||
|
||||
#define CHECK_ID(str, id)\
|
||||
if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L## #str, -1))\
|
||||
{ rgdispid[i] = id; continue; }
|
||||
|
||||
HRESULT JSAPI2::SecurityAPI::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::SecurityAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::SecurityAPI::GetTypeInfoCount(unsigned int FAR * pctinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::SecurityAPI::GetActionAuthorization(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 1, 2);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 2, VT_BSTR, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_I4);
|
||||
JSAPI_SET_RESULT(pvarResult, lVal, security.GetActionAuthorization(JSAPI_PARAM(pdispparams, 1).bstrVal, JSAPI_PARAM_OPTIONAL(pdispparams, 2, bstrVal, 0), key, info, JSAPI2::api_security::ACTION_UNDEFINED));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::SecurityAPI::SetActionAuthorization(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 3);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 2, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 3, VT_I4, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
|
||||
if (security.GetActionAuthorization(L"security", L"set", key, info, JSAPI2::api_security::ACTION_DISALLOWED) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
const wchar_t *group = JSAPI_PARAM(pdispparams, 1).bstrVal;
|
||||
const wchar_t *action = JSAPI_PARAM(pdispparams, 2).bstrVal;
|
||||
int authorization = JSAPI_PARAM(pdispparams, 2).lVal;
|
||||
security.SetActionAuthorization(group, action, key, authorization);
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#undef CHECK_ID
|
||||
#define CHECK_ID(str, id) case id: return str(wFlags, pdispparams, pvarResult, puArgErr);
|
||||
HRESULT JSAPI2::SecurityAPI::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::SecurityAPI::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::SecurityAPI::AddRef(void)
|
||||
{
|
||||
return InterlockedIncrement(&refCount);
|
||||
}
|
||||
|
||||
|
||||
ULONG JSAPI2::SecurityAPI::Release(void)
|
||||
{
|
||||
LONG lRef = InterlockedDecrement(&refCount);
|
||||
if (lRef == 0) delete this;
|
||||
return lRef;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <ocidl.h>
|
||||
#include "JSAPI_Info.h"
|
||||
|
||||
namespace JSAPI2
|
||||
{
|
||||
class SecurityAPI : public IDispatch
|
||||
{
|
||||
public:
|
||||
SecurityAPI(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;
|
||||
JSAPI::ifc_info *info;
|
||||
volatile LONG refCount;
|
||||
|
||||
STDMETHOD (GetActionAuthorization)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (SetActionAuthorization)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,718 @@
|
||||
#include "main.h"
|
||||
#include "./resource.h"
|
||||
#include "./api.h"
|
||||
#include "./language.h"
|
||||
#include "./jsapi2_svc_apicreator.h"
|
||||
#include "./commandLink.h"
|
||||
|
||||
|
||||
#include <strsafe.h>
|
||||
|
||||
|
||||
#ifndef LONGX86
|
||||
#ifdef _WIN64
|
||||
#define LONGX86 LONG_PTR
|
||||
#else /*_WIN64*/
|
||||
#define LONGX86 LONG
|
||||
#endif /*_WIN64*/
|
||||
#endif // LONGX86
|
||||
|
||||
#ifdef WIN64
|
||||
#define MSGRESULT(__hwnd, __result) { SetWindowLongPtrW((__hwnd), DWLP_MSGRESULT, ((LONGX86)(LONG_PTR)(__result))); return TRUE; }
|
||||
#else
|
||||
#define MSGRESULT(__hwnd, __result) { SetWindowLongPtrW((__hwnd), DWL_MSGRESULT, ((LONGX86)(LONG_PTR)(__result))); return TRUE; }
|
||||
#endif
|
||||
|
||||
#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 SENDWAIPC(__ipcMsgId, __param) SENDMSG(hMainWindow, WM_WA_IPC, (WPARAM)(__param), (LPARAM)(__ipcMsgId))
|
||||
|
||||
|
||||
#ifndef OIC_WARNING
|
||||
#define OIC_WARNING 32515
|
||||
#endif
|
||||
|
||||
#define SECDLG_PROP L"SecurityPromptProp"
|
||||
|
||||
#ifndef IDC_HELPLINK
|
||||
#define IDC_HELPLINK 10000
|
||||
#endif
|
||||
|
||||
typedef struct __SECDLGCREATEPARAM
|
||||
{
|
||||
HWND hCenter;
|
||||
LPCWSTR pszCaption;
|
||||
LPCWSTR pszTitle;
|
||||
LPCWSTR pszMessage;
|
||||
UINT flags;
|
||||
} SECDLGCREATEPARAM;
|
||||
|
||||
typedef struct __SECDLG
|
||||
{
|
||||
HFONT titleFont;
|
||||
SIZE minSize;
|
||||
SIZE maxSize;
|
||||
} SECDLG;
|
||||
|
||||
#define GetDialog(__hwnd) ((SECDLG*)GetPropW((__hwnd), SECDLG_PROP))
|
||||
|
||||
static INT_PTR CALLBACK SecurityPrompt_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
|
||||
static HWND SecurityPrompt_GetPlayerWindow()
|
||||
{
|
||||
return (NULL != g_dialog_box_parent) ? g_dialog_box_parent : hMainWindow;
|
||||
}
|
||||
|
||||
INT_PTR JSAPI2_SecurityPrompt(HWND hParent, LPCWSTR pszCaption, LPCWSTR pszTitle, LPCWSTR pszMessage, UINT flags)
|
||||
{
|
||||
SECDLGCREATEPARAM param;
|
||||
ZeroMemory(¶m, sizeof(SECDLGCREATEPARAM));
|
||||
param.hCenter = hParent;
|
||||
param.flags = flags;
|
||||
param.pszCaption = pszCaption;
|
||||
param.pszTitle = pszTitle;
|
||||
param.pszMessage = pszMessage;
|
||||
|
||||
|
||||
if (NULL == hParent)
|
||||
hParent = SecurityPrompt_GetPlayerWindow();
|
||||
|
||||
return LPDialogBoxParamW(IDD_JSAPI2_AUTHORIZATION2, hParent, SecurityPrompt_DialogProc, (LPARAM)¶m);
|
||||
}
|
||||
|
||||
static BOOL SecurityPrompt_GetCenterRect(HWND hCenter, RECT *centerRect, BOOL fUseMonitor)
|
||||
{
|
||||
if (NULL == centerRect)
|
||||
return FALSE;
|
||||
|
||||
HWND hDesktop = GetDesktopWindow();
|
||||
HWND hTest = hCenter;
|
||||
while(NULL != hTest)
|
||||
{
|
||||
DWORD windowStyle = GetWindowLongPtrW(hTest, GWL_STYLE);
|
||||
if (WS_VISIBLE != ((WS_VISIBLE | WS_MINIMIZE) & windowStyle))
|
||||
{
|
||||
hTest = NULL;
|
||||
hCenter = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
hTest = GetParent(hTest);
|
||||
}
|
||||
}
|
||||
|
||||
if (FALSE != fUseMonitor || NULL == hCenter || !GetWindowRect(hCenter, centerRect))
|
||||
{
|
||||
MONITORINFO mi;
|
||||
mi.cbSize = sizeof(MONITORINFO);
|
||||
if (NULL == hCenter)
|
||||
{
|
||||
hCenter = SecurityPrompt_GetPlayerWindow();
|
||||
if (NULL != hCenter)
|
||||
{
|
||||
DWORD windowStyle = GetWindowLongPtrW(hCenter, GWL_STYLE);
|
||||
if (WS_VISIBLE != ((WS_VISIBLE | WS_MINIMIZE) & windowStyle))
|
||||
hCenter = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HMONITOR hMonitor = MonitorFromWindow(hCenter,
|
||||
(NULL != hCenter) ? MONITOR_DEFAULTTONEAREST : MONITOR_DEFAULTTOPRIMARY);
|
||||
|
||||
|
||||
if (NULL != hMonitor && GetMonitorInfo(hMonitor, &mi))
|
||||
{
|
||||
CopyRect(centerRect, &mi.rcWork);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NULL == hDesktop || !GetWindowRect(hDesktop, centerRect))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void SecurityPrompt_CenterDialog(HWND hwnd, HWND hCenter)
|
||||
{
|
||||
if (NULL == hwnd)
|
||||
return;
|
||||
|
||||
RECT centerRect, windowRect;
|
||||
if (!GetWindowRect(hwnd, &windowRect) ||
|
||||
!SecurityPrompt_GetCenterRect(hCenter, ¢erRect, FALSE))
|
||||
{
|
||||
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 void SecurityPrompt_CalculateMinMax(HWND hwnd, HWND hCenter)
|
||||
{
|
||||
SECDLG *psd = GetDialog(hwnd);
|
||||
if (NULL == hwnd || NULL == psd) return;
|
||||
|
||||
RECT centerRect, windowRect;
|
||||
if (GetWindowRect(hwnd, &windowRect))
|
||||
{
|
||||
psd->minSize.cx = windowRect.right - windowRect.left;
|
||||
psd->minSize.cy = windowRect.bottom - windowRect.top;
|
||||
}
|
||||
if (SecurityPrompt_GetCenterRect(hCenter, ¢erRect, TRUE))
|
||||
{
|
||||
InflateRect(¢erRect, -16, -16);
|
||||
psd->maxSize.cx = centerRect.right - centerRect.left;
|
||||
psd->maxSize.cy = centerRect.bottom - centerRect.top;
|
||||
|
||||
if (psd->maxSize.cx > 360)
|
||||
psd->maxSize.cx = 360;
|
||||
}
|
||||
}
|
||||
|
||||
static void SecurityPrompt_LoadIcon(HWND hwnd, HINSTANCE hInstance, LPCWSTR pszIcon)
|
||||
{
|
||||
HWND hControl = GetDlgItem(hwnd, IDC_MESSAGEICON);
|
||||
if (NULL == hControl) return;
|
||||
|
||||
SendMessageW(hControl, WM_SETREDRAW, FALSE, 0L);
|
||||
|
||||
HICON hIcon = (HICON)LoadImageW(hInstance, pszIcon, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR | LR_SHARED | LR_DEFAULTSIZE);
|
||||
|
||||
HICON hPrevious = (HICON)SendMessageW(hControl, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);
|
||||
if (NULL != hPrevious)
|
||||
DeleteObject(hPrevious);
|
||||
|
||||
if (NULL != hIcon)
|
||||
{
|
||||
hPrevious = (HICON)SendMessageW(hControl, STM_GETIMAGE, IMAGE_ICON, 0L);
|
||||
if (hPrevious != hIcon)
|
||||
DeleteObject(hIcon);
|
||||
}
|
||||
|
||||
SendMessageW(hControl, WM_SETREDRAW, TRUE, 0L);
|
||||
|
||||
if (0 != ShowWindow(hControl, (NULL != hIcon) ? SW_SHOWNA : SW_HIDE))
|
||||
InvalidateRect(hControl, NULL, TRUE);
|
||||
|
||||
}
|
||||
static BOOL SecurityPrompt_GetWindowTextSize(HWND hwnd, SIZE *pSize, BOOL fMultiline, LONG lineWidth)
|
||||
{
|
||||
if (NULL == pSize) return FALSE;
|
||||
|
||||
INT cchLen = GetWindowTextLengthW(hwnd);
|
||||
if (0 == cchLen)
|
||||
{
|
||||
ZeroMemory(pSize, sizeof(SIZE));
|
||||
return TRUE;
|
||||
}
|
||||
cchLen++;
|
||||
LPWSTR pszText = NULL;
|
||||
WCHAR szBuffer[1024] = {0};
|
||||
if (cchLen > ARRAYSIZE(szBuffer))
|
||||
{
|
||||
pszText = (LPWSTR)calloc(cchLen, sizeof(WCHAR));
|
||||
if (NULL == pszText) return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
pszText = szBuffer;
|
||||
cchLen = ARRAYSIZE(szBuffer);
|
||||
}
|
||||
|
||||
BOOL resultOk = FALSE;
|
||||
cchLen = GetWindowTextW(hwnd, pszText, cchLen);
|
||||
if (0 != cchLen)
|
||||
{
|
||||
HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
|
||||
if (NULL != hdc)
|
||||
{
|
||||
HFONT hf = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0L);
|
||||
HFONT originalFont = (HFONT)SelectObject(hdc, hf);
|
||||
|
||||
if (FALSE == fMultiline)
|
||||
{
|
||||
resultOk = GetTextExtentPoint32W(hdc, pszText, cchLen, pSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
RECT textRect;
|
||||
SetRect(&textRect, 0, 0, lineWidth, 0);
|
||||
INT h = DrawTextW(hdc, pszText, cchLen, &textRect, DT_CALCRECT | DT_NOPREFIX | DT_NOCLIP | DT_WORDBREAK);
|
||||
resultOk = (0 != h);
|
||||
if (resultOk)
|
||||
{
|
||||
pSize->cx = textRect.right - textRect.left;
|
||||
pSize->cy = textRect.bottom - textRect.top;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SelectObject(hdc, originalFont);
|
||||
ReleaseDC(hwnd, hdc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (pszText != szBuffer)
|
||||
free(pszText);
|
||||
|
||||
return resultOk;
|
||||
}
|
||||
|
||||
static LONG SecurityPrompt_CalculateFooterHeight(HWND hwnd, LONG marginCY)
|
||||
{
|
||||
RECT rect;
|
||||
HWND hControl;
|
||||
|
||||
|
||||
LONG height = 0;
|
||||
|
||||
if (NULL != (hControl = GetDlgItem(hwnd, IDC_BUTTON_ALLOW)) &&
|
||||
0 != (WS_VISIBLE & GetWindowLongPtrW(hControl, GWL_STYLE)) &&
|
||||
GetWindowRect(hControl, &rect))
|
||||
{
|
||||
height += (rect.bottom - rect.top);
|
||||
}
|
||||
|
||||
|
||||
if (0 == height &&
|
||||
NULL != (hControl = GetDlgItem(hwnd, IDC_BUTTON_DENY)) &&
|
||||
0 != (WS_VISIBLE & GetWindowLongPtrW(hControl, GWL_STYLE)) &&
|
||||
GetWindowRect(hControl, &rect))
|
||||
{
|
||||
height += (rect.bottom - rect.top);
|
||||
}
|
||||
|
||||
INT szCtrl[] = {IDC_APPLYTOALL, IDC_SEPARATOR, IDC_HELPTEXT, };
|
||||
for (INT i = 0; i < ARRAYSIZE(szCtrl); i++)
|
||||
{
|
||||
if (NULL != (hControl = GetDlgItem(hwnd, szCtrl[i])) &&
|
||||
0 != (WS_VISIBLE & GetWindowLongPtrW(hControl, GWL_STYLE)) &&
|
||||
GetWindowRect(hControl, &rect))
|
||||
{
|
||||
LONG h = (rect.bottom - rect.top);
|
||||
if (h > 0)
|
||||
{
|
||||
if (height > 0) height += marginCY;
|
||||
height += h;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != height)
|
||||
height += 2*marginCY;
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
static void SecurityPrompt_UpdateLayout(HWND hwnd, BOOL fRedraw)
|
||||
{
|
||||
SECDLG *psd = GetDialog(hwnd);
|
||||
if (NULL == hwnd || NULL == psd) return;
|
||||
|
||||
HWND hControl;
|
||||
RECT rect;
|
||||
LONG marginCX, marginCY;
|
||||
SIZE clientSize, iconSize, titleSize, messageSize;
|
||||
ZeroMemory(&clientSize, sizeof(SIZE));
|
||||
|
||||
SetRect(&rect, 6, 6, 6, 6);
|
||||
if (MapDialogRect(hwnd, &rect))
|
||||
{
|
||||
marginCX = rect.left;
|
||||
marginCY = rect.top;
|
||||
}
|
||||
else
|
||||
{
|
||||
marginCX = 12;
|
||||
marginCY = 12;
|
||||
}
|
||||
|
||||
if (NULL != (hControl = GetDlgItem(hwnd, IDC_MESSAGEICON)) &&
|
||||
0 != (WS_VISIBLE & GetWindowLongPtrW(hControl, GWL_STYLE)) &&
|
||||
GetWindowRect(hControl, &rect))
|
||||
{
|
||||
MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rect, 2);
|
||||
iconSize.cx = rect.right - rect.left;
|
||||
iconSize.cy = rect.bottom - rect.top;
|
||||
}
|
||||
else
|
||||
{
|
||||
ZeroMemory(&iconSize, sizeof(SIZE));
|
||||
}
|
||||
|
||||
if (NULL == (hControl = GetDlgItem(hwnd, IDC_TITLE)) ||
|
||||
0 == (WS_VISIBLE & GetWindowLongPtrW(hControl, GWL_STYLE)) ||
|
||||
FALSE == SecurityPrompt_GetWindowTextSize(hControl, &titleSize, FALSE, 0))
|
||||
{
|
||||
ZeroMemory(&titleSize, sizeof(SIZE));
|
||||
}
|
||||
|
||||
if (NULL == (hControl = GetDlgItem(hwnd, IDC_MESSAGE)) ||
|
||||
0 == (WS_VISIBLE & GetWindowLongPtrW(hControl, GWL_STYLE)) ||
|
||||
FALSE == SecurityPrompt_GetWindowTextSize(hControl, &messageSize, TRUE, psd->maxSize.cx - (iconSize.cx + marginCX * 3)))
|
||||
{
|
||||
ZeroMemory(&messageSize, sizeof(SIZE));
|
||||
}
|
||||
|
||||
clientSize.cx = iconSize.cx;
|
||||
if (messageSize.cx > 0)
|
||||
{
|
||||
clientSize.cx += messageSize.cx;
|
||||
if (iconSize.cx > 0) clientSize.cx += marginCX;
|
||||
}
|
||||
if (titleSize.cx > clientSize.cx)
|
||||
titleSize.cx = clientSize.cx;
|
||||
clientSize.cx += 2*marginCX;
|
||||
|
||||
clientSize.cy = titleSize.cy;
|
||||
|
||||
LONG h1 = messageSize.cy;
|
||||
if (h1 > 0) h1 += 2 * marginCY;
|
||||
|
||||
LONG h2 = iconSize.cy;
|
||||
if (h2 > 0) h2 += marginCY;
|
||||
|
||||
clientSize.cy += (h1 > h2) ? h1 : h2;
|
||||
if (clientSize.cy > 0)
|
||||
{
|
||||
if (clientSize.cy != titleSize.cy && 0 != titleSize.cy)
|
||||
clientSize.cy += marginCY;
|
||||
}
|
||||
clientSize.cy += SecurityPrompt_CalculateFooterHeight(hwnd, marginCY);
|
||||
|
||||
|
||||
DWORD windowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE);
|
||||
DWORD windowExStyle = GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
|
||||
|
||||
SetRect(&rect, 0, 0, clientSize.cx, clientSize.cy);
|
||||
if (AdjustWindowRectEx(&rect, windowStyle, FALSE, windowExStyle))
|
||||
{
|
||||
clientSize.cx = rect.right - rect.left;
|
||||
clientSize.cy = rect.bottom - rect.top;
|
||||
}
|
||||
if (clientSize.cx < psd->minSize.cx) clientSize.cx = psd->minSize.cx;
|
||||
if (clientSize.cy < psd->minSize.cy) clientSize.cy = psd->minSize.cy;
|
||||
|
||||
|
||||
SetWindowPos(hwnd, NULL, 0, 0, clientSize.cx, clientSize.cy, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
|
||||
|
||||
RECT clientRect;
|
||||
if (!GetClientRect(hwnd, &clientRect))
|
||||
SetRectEmpty(&clientRect);
|
||||
else
|
||||
InflateRect(&clientRect, -marginCX, -marginCY);
|
||||
|
||||
|
||||
if (NULL != (hControl = GetDlgItem(hwnd, IDC_TITLE)))
|
||||
{
|
||||
SetWindowPos(hControl, NULL, clientRect.left, clientRect.top, clientRect.right - clientRect.left, titleSize.cy, SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
if (NULL != (hControl = GetDlgItem(hwnd, IDC_MESSAGEICON)))
|
||||
{
|
||||
LONG y = clientRect.top;
|
||||
if (titleSize.cy > 0) y += (titleSize.cy + marginCY);
|
||||
SetWindowPos(hControl, NULL, clientRect.left, y, iconSize.cx, iconSize.cy, SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
if (NULL != (hControl = GetDlgItem(hwnd, IDC_MESSAGE)))
|
||||
{
|
||||
LONG x = clientRect.left;
|
||||
if (iconSize.cx > 0) x += (iconSize.cx + marginCX);
|
||||
LONG y = clientRect.top;
|
||||
if (titleSize.cy > 0) y += (titleSize.cy + marginCY);
|
||||
SetWindowPos(hControl, NULL, x, y, clientRect.right - x, messageSize.cy, SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
|
||||
HWND hHelp;
|
||||
hHelp = GetDlgItem(hwnd, IDC_HELPTEXT);
|
||||
if (NULL == hHelp || !GetWindowRect(hHelp, &rect))
|
||||
SetRectEmpty(&rect);
|
||||
else
|
||||
MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rect, 2);
|
||||
|
||||
SIZE linkSize;
|
||||
LONG bottomLine = clientRect.bottom;
|
||||
if (NULL != (hControl = GetDlgItem(hwnd, IDC_HELPLINK)) &&
|
||||
CommandLink_GetIdealSize(hControl, &linkSize))
|
||||
{
|
||||
RECT margins;
|
||||
|
||||
if (!CommandLink_GetMargins(hControl, &margins))
|
||||
SetRectEmpty(&margins);
|
||||
|
||||
if (linkSize.cy > 0)
|
||||
{
|
||||
bottomLine -= (linkSize.cy - margins.bottom);
|
||||
}
|
||||
|
||||
SetWindowPos(hControl, NULL, clientRect.left - margins.left, bottomLine, linkSize.cx, linkSize.cy, SWP_NOACTIVATE | SWP_NOZORDER);
|
||||
if (NULL != hHelp)
|
||||
{
|
||||
LONG x = clientRect.left + linkSize.cx - margins.right;
|
||||
LONG cy = rect.bottom - rect.top;
|
||||
SetWindowPos(hHelp, NULL, x, clientRect.bottom - cy, clientRect.right - x, cy, SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != (hControl = GetDlgItem(hwnd, IDC_SEPARATOR)) &&
|
||||
0 != (WS_VISIBLE & GetWindowLongPtrW(hControl, GWL_STYLE)) &&
|
||||
GetWindowRect(hControl, &rect))
|
||||
{
|
||||
bottomLine -= (marginCY + (rect.bottom - rect.top));
|
||||
SetWindowPos(hControl, NULL, 0, bottomLine, clientRect.right - clientRect.left + 2*marginCX + 2, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
if (NULL != (hControl = GetDlgItem(hwnd, IDC_APPLYTOALL)) &&
|
||||
0 != (WS_VISIBLE & GetWindowLongPtrW(hControl, GWL_STYLE)) &&
|
||||
GetWindowRect(hControl, &rect))
|
||||
{
|
||||
bottomLine -= (marginCY + (rect.bottom - rect.top));
|
||||
SetWindowPos(hControl, NULL, clientRect.left, bottomLine, clientRect.right - clientRect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
LONG buttonRight = clientRect.right;
|
||||
if (NULL != (hControl = GetDlgItem(hwnd, IDC_BUTTON_DENY)) &&
|
||||
0 != (WS_VISIBLE & GetWindowLongPtrW(hControl, GWL_STYLE)) &&
|
||||
GetWindowRect(hControl, &rect))
|
||||
{
|
||||
|
||||
SetWindowPos(hControl, NULL, buttonRight - (rect.right - rect.left), bottomLine - (marginCY + (rect.bottom - rect.top)),
|
||||
rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
if (rect.right > rect.left)
|
||||
{
|
||||
buttonRight -= ((rect.right - rect.left) + marginCX);
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != (hControl = GetDlgItem(hwnd, IDC_BUTTON_ALLOW)) &&
|
||||
0 != (WS_VISIBLE & GetWindowLongPtrW(hControl, GWL_STYLE)) &&
|
||||
GetWindowRect(hControl, &rect))
|
||||
{
|
||||
SetWindowPos(hControl, NULL, buttonRight - (rect.right - rect.left), bottomLine - (marginCY + (rect.bottom - rect.top)),
|
||||
rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
static HFONT SecurityPrompt_GetTitleFont(HWND hwnd)
|
||||
{
|
||||
SECDLG *psd = GetDialog(hwnd);
|
||||
if (NULL == psd)
|
||||
return (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0L);
|
||||
|
||||
if (NULL != psd->titleFont)
|
||||
return psd->titleFont;
|
||||
|
||||
|
||||
LOGFONTW lf;
|
||||
ZeroMemory(&lf, sizeof(LOGFONTW));
|
||||
|
||||
HFONT hf = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0L);
|
||||
|
||||
if (NULL != hf)
|
||||
GetObjectW(hf, sizeof(LOGFONTW), &lf);
|
||||
|
||||
if (L'\0' == lf.lfFaceName[0])
|
||||
{
|
||||
if (!SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(LOGFONTW), &lf, 0) ||
|
||||
FAILED(StringCchCopyW(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), L"MS Shell Dlg 2")))
|
||||
{
|
||||
lf.lfFaceName[0] = L'\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (L'\0' != lf.lfFaceName[0])
|
||||
{
|
||||
lf.lfWeight = FW_SEMIBOLD;
|
||||
psd->titleFont = CreateFontIndirectW(&lf);
|
||||
}
|
||||
|
||||
return psd->titleFont;
|
||||
}
|
||||
|
||||
static BOOL SecurityPrompt_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 INT_PTR SecurityPrompt_OnInitDialog(HWND hwnd, HWND hFocus, LPARAM param)
|
||||
{
|
||||
SECDLGCREATEPARAM *createParam = (SECDLGCREATEPARAM*)param;
|
||||
if (NULL == createParam) return 0;
|
||||
|
||||
SECDLG *psd = (SECDLG*)calloc(1, sizeof(SECDLG));
|
||||
if (NULL != psd)
|
||||
{
|
||||
if (!SetPropW(hwnd, SECDLG_PROP, psd))
|
||||
{
|
||||
free(psd);
|
||||
psd = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HMENU hMenu = GetSystemMenu(hwnd, FALSE);
|
||||
if (NULL != hMenu)
|
||||
{
|
||||
EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND|MF_DISABLED);
|
||||
DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
|
||||
DeleteMenu(hMenu, SC_SIZE, MF_BYCOMMAND);
|
||||
}
|
||||
|
||||
|
||||
SecurityPrompt_LoadIcon(hwnd, NULL, MAKEINTRESOURCEW(OIC_WARNING));
|
||||
|
||||
WCHAR szBuffer[4096] = {0};
|
||||
LPCWSTR pszText;
|
||||
HWND hControl;
|
||||
|
||||
SecurityPrompt_CalculateMinMax(hwnd, createParam->hCenter);
|
||||
|
||||
if (NULL != (pszText = createParam->pszCaption) && IS_INTRESOURCE(pszText))
|
||||
pszText = getStringW((INT)(INT_PTR)pszText, szBuffer, ARRAYSIZE(szBuffer));
|
||||
|
||||
if (NULL != pszText && L'\0' != *pszText)
|
||||
SetWindowTextW(hwnd, pszText);
|
||||
|
||||
if (NULL != (hControl = GetDlgItem(hwnd, IDC_TITLE)))
|
||||
{
|
||||
if (NULL != (pszText = createParam->pszTitle) && IS_INTRESOURCE(pszText))
|
||||
pszText = getStringW((INT)(INT_PTR)pszText, szBuffer, ARRAYSIZE(szBuffer));
|
||||
|
||||
HFONT hf = SecurityPrompt_GetTitleFont(hwnd);
|
||||
if (NULL != hf) SendMessageW(hControl, WM_SETFONT, (WPARAM)hf, 0L);
|
||||
|
||||
SetWindowTextW(hControl, pszText);
|
||||
ShowWindow(hControl, (NULL != pszText && L'\0' != *pszText) ? SW_SHOWNA : SW_HIDE);
|
||||
}
|
||||
|
||||
if (NULL != (hControl = GetDlgItem(hwnd, IDC_MESSAGE)))
|
||||
{
|
||||
if (NULL != (pszText = createParam->pszMessage) && IS_INTRESOURCE(pszText))
|
||||
pszText = getStringW((INT)(INT_PTR)pszText, szBuffer, ARRAYSIZE(szBuffer));
|
||||
SetWindowTextW(hControl, pszText);
|
||||
ShowWindow(hControl, (NULL != pszText && L'\0' != *pszText) ? SW_SHOWNA : SW_HIDE);
|
||||
}
|
||||
|
||||
getStringW(IDS_CLICKHERE, szBuffer, ARRAYSIZE(szBuffer));
|
||||
|
||||
HWND hLink = CreateWindowExW(WS_EX_NOPARENTNOTIFY, NWC_COMMANDLINKW, szBuffer,
|
||||
WS_VISIBLE | WS_CHILD | WS_TABSTOP | /*CLS_HOTTRACK | */CLS_DEFAULTCOLORS | CLS_ALWAYSUNDERLINE,
|
||||
0, 0, 0, 0, hwnd, (HMENU)IDC_HELPLINK, hMainInstance, NULL);
|
||||
|
||||
if (NULL != hLink)
|
||||
{
|
||||
if (NULL != (hControl = GetDlgItem(hwnd, IDC_APPLYTOALL)))
|
||||
SetWindowPos(hLink, hControl, 0, 0, 0, 0, SWP_NOACTIVATE |SWP_NOSIZE | SWP_NOMOVE);
|
||||
|
||||
SendMessageW(hLink, WM_SETFONT, (WPARAM)SendMessageW(hwnd, WM_GETFONT, 0, 0L), 0L);
|
||||
}
|
||||
|
||||
CheckDlgButton(hwnd, IDC_APPLYTOALL,
|
||||
(0 != (JSAPI2::svc_apicreator::AUTHORIZATION_FLAG_ALWAYS_FOR_SERVICE &createParam->flags)) ?
|
||||
BST_CHECKED : BST_UNCHECKED);
|
||||
|
||||
SecurityPrompt_UpdateLayout(hwnd, FALSE);
|
||||
|
||||
SecurityPrompt_CenterDialog(hwnd, createParam->hCenter);
|
||||
SendMessageW(hwnd, DM_REPOSITION, 0, 0L);
|
||||
|
||||
DWORD dialogThread = GetWindowThreadProcessId(hwnd, NULL);
|
||||
DWORD parentThread = GetWindowThreadProcessId(GetParent(hwnd), NULL);
|
||||
if (dialogThread != parentThread)
|
||||
{
|
||||
AttachThreadInput(parentThread, dialogThread, TRUE);
|
||||
SetForegroundWindow(hwnd);
|
||||
}
|
||||
|
||||
if (NULL != (hControl = GetDlgItem(hwnd, IDC_BUTTON_DENY)) &&
|
||||
WS_VISIBLE == ((WS_VISIBLE | WS_DISABLED) & GetWindowLongPtrW(hControl, GWL_STYLE)) &&
|
||||
PostMessageW(hwnd, WM_NEXTDLGCTL, (WPARAM)hControl, TRUE))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void SecurityPrompt_OnDestroy(HWND hwnd)
|
||||
{
|
||||
SECDLG *psd = GetDialog(hwnd);
|
||||
RemovePropW(hwnd, SECDLG_PROP);
|
||||
|
||||
DWORD dialogThread = GetWindowThreadProcessId(hwnd, NULL);
|
||||
DWORD parentThread = GetWindowThreadProcessId(GetParent(hwnd), NULL);
|
||||
if (dialogThread != parentThread)
|
||||
{
|
||||
AttachThreadInput(parentThread, dialogThread, FALSE);
|
||||
}
|
||||
|
||||
if (NULL == psd) return;
|
||||
|
||||
if (NULL != psd->titleFont)
|
||||
DeleteObject(psd->titleFont);
|
||||
|
||||
free(psd);
|
||||
}
|
||||
|
||||
static void SecurityPrompt_OnCommand(HWND hwnd, INT commandId, INT eventId, HWND hControl)
|
||||
{
|
||||
switch(commandId)
|
||||
{
|
||||
case IDC_BUTTON_ALLOW:
|
||||
case IDC_BUTTON_DENY:
|
||||
if(BN_CLICKED == eventId)
|
||||
{
|
||||
INT_PTR result = (IDC_BUTTON_ALLOW == commandId) ?
|
||||
JSAPI2::svc_apicreator::AUTHORIZATION_ALLOW :
|
||||
JSAPI2::svc_apicreator::AUTHORIZATION_DENY;
|
||||
|
||||
result |= (BST_CHECKED == IsDlgButtonChecked(hwnd, IDC_APPLYTOALL)) ?
|
||||
JSAPI2::svc_apicreator::AUTHORIZATION_FLAG_ALWAYS_FOR_SERVICE :
|
||||
JSAPI2::svc_apicreator::AUTHORIZATION_FLAG_ALWAYS;
|
||||
|
||||
EndDialog(hwnd, result);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static LRESULT SecurityPrompt_OnNotify(HWND hwnd, INT controlId, NMHDR *pnmh)
|
||||
{
|
||||
switch(controlId)
|
||||
{
|
||||
case IDC_HELPLINK:
|
||||
if (NM_CLICK == pnmh->code)
|
||||
SecurityPrompt_ShowHelp(hwnd);
|
||||
return TRUE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static INT_PTR CALLBACK SecurityPrompt_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch(uMsg)
|
||||
{
|
||||
case WM_INITDIALOG: return SecurityPrompt_OnInitDialog(hwnd, (HWND)wParam, lParam);
|
||||
case WM_DESTROY: SecurityPrompt_OnDestroy(hwnd); break;
|
||||
case WM_COMMAND: SecurityPrompt_OnCommand(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break;
|
||||
case WM_NOTIFY: MSGRESULT(hwnd, SecurityPrompt_OnNotify(hwnd, (INT)wParam, (NMHDR*)lParam));
|
||||
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
#include "JSAPI2_SkinAPI.h"
|
||||
#include "JSAPI2_Security.h"
|
||||
#include "main.h"
|
||||
#include "JSAPI.h"
|
||||
#include "wa_dlg.h"
|
||||
#include "api.h"
|
||||
#include "../nu/AutoWide.h"
|
||||
#include <tataki/color/skinclr.h>
|
||||
#include <api/service/waservicefactory.h>
|
||||
|
||||
JSAPI2::SkinAPI::SkinAPI(const wchar_t *_key, JSAPI::ifc_info *_info)
|
||||
{
|
||||
Tataki::Init(serviceManager); // we might need it, go ahead and init here
|
||||
info = _info;
|
||||
key = _key;
|
||||
refCount = 1;
|
||||
}
|
||||
|
||||
JSAPI2::SkinAPI::~SkinAPI()
|
||||
{
|
||||
Tataki::Quit();
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
DISPID_SKINAPI_GETCLASSICCOLOR,
|
||||
DISPID_SKINAPI_GETPLAYLISTCOLOR,
|
||||
DISPID_SKINAPI_GETSKINCOLOR,
|
||||
DISPID_SKINAPI_NAME,
|
||||
DISPID_SKINAPI_FONT,
|
||||
DISPID_SKINAPI_FONTSIZE,
|
||||
|
||||
};
|
||||
|
||||
#define DISP_TABLE \
|
||||
CHECK_ID(GetClassicColor, DISPID_SKINAPI_GETCLASSICCOLOR)\
|
||||
CHECK_ID(GetPlaylistColor, DISPID_SKINAPI_GETPLAYLISTCOLOR)\
|
||||
CHECK_ID(GetSkinColor, DISPID_SKINAPI_GETSKINCOLOR)\
|
||||
CHECK_ID(name, DISPID_SKINAPI_NAME)\
|
||||
CHECK_ID(font, DISPID_SKINAPI_FONT)\
|
||||
CHECK_ID(fontsize, DISPID_SKINAPI_FONTSIZE)\
|
||||
|
||||
#define CHECK_ID(str, id)\
|
||||
if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L## #str, -1))\
|
||||
{ rgdispid[i] = id; continue; }
|
||||
|
||||
HRESULT JSAPI2::SkinAPI::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::SkinAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::SkinAPI::GetTypeInfoCount(unsigned int FAR * pctinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::SkinAPI::GetClassicColor(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_I4, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
|
||||
|
||||
COLORREF color = WADlg_getColor(JSAPI_PARAM(pdispparams, 1).lVal);
|
||||
color = ((color >> 16) & 0xff | (color & 0xff00) | ((color << 16) & 0xff0000));
|
||||
wchar_t colorString[8] = {0};
|
||||
StringCchPrintfW(colorString, 8, L"#%06X", color);
|
||||
JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(colorString));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::SkinAPI::GetPlaylistColor(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_I4, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
|
||||
|
||||
COLORREF color = Skin_PLColors[JSAPI_PARAM(pdispparams, 1).lVal];
|
||||
color = ((color >> 16) & 0xff | (color & 0xff00) | ((color << 16) & 0xff0000));
|
||||
wchar_t colorString[8] = {0};
|
||||
StringCchPrintfW(colorString, 8, L"#%06X", color);
|
||||
JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(colorString));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::SkinAPI::GetSkinColor(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_BSTR);
|
||||
|
||||
ARGB32 color;
|
||||
if (SkinColor::TryGetColor(&color, JSAPI_PARAM(pdispparams, 1).bstrVal))
|
||||
{
|
||||
color = ((color >> 16) & 0xff | (color & 0xff00) | ((color << 16) & 0xff0000));
|
||||
wchar_t colorString[8] = {0};
|
||||
StringCchPrintfW(colorString, 8, L"#%06X", color);
|
||||
JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(colorString));
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_EMPTY_RESULT(pvarResult);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::SkinAPI::name(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
if (wFlags & DISPATCH_PROPERTYGET)
|
||||
{
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BSTR;
|
||||
V_BSTR(pvarResult) = SysAllocString(config_skin);
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::SkinAPI::font(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
if (wFlags & DISPATCH_PROPERTYGET)
|
||||
{
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BSTR;
|
||||
V_BSTR(pvarResult) = SysAllocString(GetFontNameW());
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::SkinAPI::fontsize(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
if (wFlags & DISPATCH_PROPERTYGET)
|
||||
{
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_I4;
|
||||
V_I4(pvarResult) = GetFontSize();
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
#undef CHECK_ID
|
||||
#define CHECK_ID(str, id) case id: return str(wFlags, pdispparams, pvarResult, puArgErr);
|
||||
HRESULT JSAPI2::SkinAPI::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::SkinAPI::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::SkinAPI::AddRef(void)
|
||||
{
|
||||
return InterlockedIncrement(&refCount);
|
||||
}
|
||||
|
||||
|
||||
ULONG JSAPI2::SkinAPI::Release(void)
|
||||
{
|
||||
LONG lRef = InterlockedDecrement(&refCount);
|
||||
if (lRef == 0) delete this;
|
||||
return lRef;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <ocidl.h>
|
||||
#include "JSAPI_Info.h"
|
||||
|
||||
namespace JSAPI2
|
||||
{
|
||||
class SkinAPI : public IDispatch
|
||||
{
|
||||
public:
|
||||
SkinAPI(const wchar_t *_key, JSAPI::ifc_info *info);
|
||||
~SkinAPI();
|
||||
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;
|
||||
JSAPI::ifc_info *info;
|
||||
volatile LONG refCount;
|
||||
|
||||
STDMETHOD (GetClassicColor)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (GetPlaylistColor)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (GetSkinColor)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
|
||||
STDMETHOD (name)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (font)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (fontsize)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,532 @@
|
||||
#include "JSAPI2_TransportAPI.h"
|
||||
#include "JSAPI2_Security.h"
|
||||
#include "JSAPI2_CallbackManager.h"
|
||||
#include "main.h"
|
||||
#include "JSAPI.h"
|
||||
#include "JSAPI_CallbackParameters.h"
|
||||
|
||||
#define SCRIPT_E_REPORTED 0x80020101
|
||||
|
||||
JSAPI2::TransportAPI::TransportAPI(const wchar_t *_key, JSAPI::ifc_info *info)
|
||||
{
|
||||
this->info = info;
|
||||
key = _key;
|
||||
refCount = 1;
|
||||
}
|
||||
|
||||
JSAPI2::TransportAPI::~TransportAPI()
|
||||
{
|
||||
// just in case someone forgot
|
||||
JSAPI2::callbackManager.Deregister(this);
|
||||
|
||||
size_t index = events.size();
|
||||
while(index--)
|
||||
{
|
||||
IDispatch *pEvent = events[index];
|
||||
if (NULL != pEvent)
|
||||
pEvent->Release();
|
||||
}
|
||||
}
|
||||
|
||||
#define DISP_TABLE \
|
||||
CHECK_ID(Prev)\
|
||||
CHECK_ID(Play)\
|
||||
CHECK_ID(Pause)\
|
||||
CHECK_ID(Stop)\
|
||||
CHECK_ID(Next)\
|
||||
CHECK_ID(shuffle)\
|
||||
CHECK_ID(repeat)\
|
||||
CHECK_ID(position)\
|
||||
CHECK_ID(length)\
|
||||
CHECK_ID(url)\
|
||||
CHECK_ID(title)\
|
||||
CHECK_ID(playing)\
|
||||
CHECK_ID(paused)\
|
||||
CHECK_ID(GetMetadata)\
|
||||
CHECK_ID(RegisterForEvents)\
|
||||
CHECK_ID(UnregisterFromEvents)\
|
||||
|
||||
|
||||
#define CHECK_ID(str) JSAPI_DISP_ENUMIFY(str),
|
||||
enum {
|
||||
DISP_TABLE
|
||||
};
|
||||
|
||||
#undef CHECK_ID
|
||||
#define CHECK_ID(str)\
|
||||
if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, rgszNames[i], -1, L## #str, -1))\
|
||||
{ rgdispid[i] = JSAPI_DISP_ENUMIFY(str); continue; }
|
||||
|
||||
HRESULT JSAPI2::TransportAPI::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::TransportAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::TransportAPI::GetTypeInfoCount(unsigned int FAR * pctinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::TransportAPI::ButtonPress(WPARAM button, const wchar_t *action, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
|
||||
switch (security.GetActionAuthorization(L"transport", action, key, info, JSAPI2::api_security::ACTION_PROMPT))
|
||||
{
|
||||
case JSAPI2::api_security::ACTION_DISALLOWED:
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
|
||||
break;
|
||||
case JSAPI2::api_security::ACTION_ALLOWED:
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
SendMessageW(hMainWindow, WM_COMMAND, button, 0);
|
||||
break;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::TransportAPI::Prev(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
return ButtonPress(WINAMP_BUTTON1, L"controls", wFlags, pdispparams, pvarResult, puArgErr);
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::TransportAPI::Play(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
return ButtonPress(WINAMP_BUTTON2, L"controls", wFlags, pdispparams, pvarResult, puArgErr);
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::TransportAPI::Pause(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
return ButtonPress(WINAMP_BUTTON3, L"controls", wFlags, pdispparams, pvarResult, puArgErr);
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::TransportAPI::Stop(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
return ButtonPress(WINAMP_BUTTON4, L"controls", wFlags, pdispparams, pvarResult, puArgErr);
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::TransportAPI::Next(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
return ButtonPress(WINAMP_BUTTON5, L"controls", wFlags, pdispparams, pvarResult, puArgErr);
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::TransportAPI::shuffle(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
if (wFlags & DISPATCH_PROPERTYPUT)
|
||||
{
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BOOL, puArgErr);
|
||||
switch (security.GetActionAuthorization(L"transport", L"controls", key, info, JSAPI2::api_security::ACTION_PROMPT))
|
||||
{
|
||||
case JSAPI2::api_security::ACTION_DISALLOWED:
|
||||
return S_OK;
|
||||
case JSAPI2::api_security::ACTION_ALLOWED:
|
||||
if (!!config_shuffle != JSAPI_PARAM(pdispparams, 1).lVal)
|
||||
SendMessageW(hMainWindow, WM_COMMAND, WINAMP_FILE_SHUFFLE, 0);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
else if (wFlags & DISPATCH_PROPERTYGET)
|
||||
{
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BOOL;
|
||||
V_BOOL(pvarResult) = (0 != config_shuffle) ? VARIANT_TRUE : VARIANT_FALSE;//(LONG)SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_GET_SHUFFLE);
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
|
||||
HRESULT JSAPI2::TransportAPI::repeat(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
if (wFlags & DISPATCH_PROPERTYPUT)
|
||||
{
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BOOL, puArgErr);
|
||||
switch (security.GetActionAuthorization(L"transport", L"controls", key, info, JSAPI2::api_security::ACTION_PROMPT))
|
||||
{
|
||||
case JSAPI2::api_security::ACTION_DISALLOWED:
|
||||
return S_OK;
|
||||
case JSAPI2::api_security::ACTION_ALLOWED:
|
||||
if (!!config_repeat != !!JSAPI_PARAM(pdispparams, 1).boolVal)
|
||||
SendMessageW(hMainWindow, WM_COMMAND, WINAMP_FILE_REPEAT, 0);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
else if (wFlags & DISPATCH_PROPERTYGET)
|
||||
{
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BOOL;
|
||||
V_BOOL(pvarResult) = (0 != config_repeat) ? VARIANT_TRUE : VARIANT_FALSE;
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::TransportAPI::position(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
if (wFlags & DISPATCH_PROPERTYPUT)
|
||||
{
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
|
||||
if (security.GetActionAuthorization(L"transport", L"controls", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
SendMessageW(hMainWindow, WM_WA_IPC, JSAPI_PARAM(pdispparams, 1).lVal, IPC_JUMPTOTIME);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
else if (wFlags & DISPATCH_PROPERTYGET)
|
||||
{
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_I4;
|
||||
V_I4(pvarResult) = (LONG)SendMessageW(hMainWindow, WM_WA_IPC, 0, IPC_GETOUTPUTTIME);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::TransportAPI::length(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
if (wFlags & DISPATCH_PROPERTYGET)
|
||||
{
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_I4;
|
||||
V_I4(pvarResult) = (LONG)SendMessageW(hMainWindow, WM_WA_IPC, 2, IPC_GETOUTPUTTIME);
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::TransportAPI::url(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
if (wFlags & DISPATCH_PROPERTYGET)
|
||||
{
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
|
||||
if (security.GetActionAuthorization(L"transport", L"metadata", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(FileName));
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_EMPTY_RESULT(pvarResult);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::TransportAPI::title(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
if (wFlags & DISPATCH_PROPERTYGET)
|
||||
{
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
|
||||
|
||||
if (security.GetActionAuthorization(L"transport", L"metadata", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(FileTitle));
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_EMPTY_RESULT(pvarResult);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::TransportAPI::playing(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
if (wFlags & DISPATCH_PROPERTYGET)
|
||||
{
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BOOL;
|
||||
switch (security.GetActionAuthorization(L"transport", L"controls", key, info, JSAPI2::api_security::ACTION_PROMPT))
|
||||
{
|
||||
case JSAPI2::api_security::ACTION_DISALLOWED:
|
||||
V_BOOL(pvarResult) = VARIANT_FALSE;
|
||||
break;
|
||||
case JSAPI2::api_security::ACTION_ALLOWED:
|
||||
V_BOOL(pvarResult) = ::playing?VARIANT_TRUE:VARIANT_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::TransportAPI::paused(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
if (wFlags & DISPATCH_PROPERTYGET)
|
||||
{
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BOOL;
|
||||
switch (security.GetActionAuthorization(L"transport", L"controls", key, info, JSAPI2::api_security::ACTION_PROMPT))
|
||||
{
|
||||
case JSAPI2::api_security::ACTION_DISALLOWED:
|
||||
V_BOOL(pvarResult) = VARIANT_FALSE;
|
||||
break;
|
||||
case JSAPI2::api_security::ACTION_ALLOWED:
|
||||
V_BOOL(pvarResult) = ::paused?VARIANT_TRUE:VARIANT_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::TransportAPI::GetMetadata(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_BSTR);
|
||||
|
||||
if (security.GetActionAuthorization(L"transport", L"metadata", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
wchar_t buffer[4096] = {0};
|
||||
extendedFileInfoStructW info;
|
||||
|
||||
info.filename = FileName;
|
||||
info.metadata = JSAPI_PARAM(pdispparams, 1).bstrVal;
|
||||
info.ret = buffer;
|
||||
info.retlen = sizeof(buffer)/sizeof(*buffer);
|
||||
|
||||
if (NULL != info.filename &&
|
||||
NULL != info.metadata)
|
||||
{
|
||||
if (0 == SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&info, IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE))
|
||||
info.ret = NULL;
|
||||
|
||||
JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(info.ret));
|
||||
}
|
||||
else
|
||||
JSAPI_EMPTY_RESULT(pvarResult);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_EMPTY_RESULT(pvarResult);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::TransportAPI::RegisterForEvents(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_DISPATCH, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
|
||||
switch (security.GetActionAuthorization(L"transport", L"events", key, info, JSAPI2::api_security::ACTION_PROMPT))
|
||||
{
|
||||
case JSAPI2::api_security::ACTION_DISALLOWED:
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
|
||||
break;
|
||||
case JSAPI2::api_security::ACTION_ALLOWED:
|
||||
{
|
||||
/** if this is the first time someone is registering an event
|
||||
** add ourselves to the callback manager
|
||||
*/
|
||||
if (events.empty())
|
||||
JSAPI2::callbackManager.Register(this);
|
||||
|
||||
IDispatch *event = JSAPI_PARAM(pdispparams, 1).pdispVal;
|
||||
event->AddRef();
|
||||
// TODO: benski> not sure, but we might need to: event->AddRef();
|
||||
events.push_back(event);
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::TransportAPI::UnregisterFromEvents(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_DISPATCH, puArgErr);
|
||||
|
||||
IDispatch *event = JSAPI_PARAM(pdispparams, 1).pdispVal;
|
||||
// TODO: benski> not sure, but we might need to: event->Release();
|
||||
|
||||
size_t index = events.size();
|
||||
while(index--)
|
||||
{
|
||||
if (events[index] == event)
|
||||
{
|
||||
events.erase(events.begin() + index);
|
||||
event->Release();
|
||||
}
|
||||
}
|
||||
|
||||
/** if we don't have any more event listeners
|
||||
** remove ourselves from the callback manager
|
||||
*/
|
||||
if (events.empty())
|
||||
JSAPI2::callbackManager.Deregister(this);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#undef CHECK_ID
|
||||
#define CHECK_ID(str) case JSAPI_DISP_ENUMIFY(str): return str(wFlags, pdispparams, pvarResult, puArgErr);
|
||||
HRESULT JSAPI2::TransportAPI::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::TransportAPI::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::TransportAPI::AddRef(void)
|
||||
{
|
||||
return InterlockedIncrement(&refCount);
|
||||
}
|
||||
|
||||
|
||||
ULONG JSAPI2::TransportAPI::Release(void)
|
||||
{
|
||||
LONG lRef = InterlockedDecrement(&refCount);
|
||||
if (lRef == 0) delete this;
|
||||
return lRef;
|
||||
}
|
||||
|
||||
void JSAPI2::TransportAPI::InvokeEvent(const wchar_t *eventName, JSAPI::CallbackParameters::PropertyTemplate *parameters, size_t parametersCount)
|
||||
{
|
||||
size_t index = events.size();
|
||||
if (0 == index)
|
||||
{
|
||||
JSAPI2::callbackManager.Deregister(this);
|
||||
return;
|
||||
}
|
||||
|
||||
JSAPI::CallbackParameters *eventData= new JSAPI::CallbackParameters;
|
||||
if (NULL == eventData) return;
|
||||
|
||||
eventData->AddString(L"event", eventName);
|
||||
|
||||
if (NULL != parameters && 0 != parametersCount)
|
||||
eventData->AddPropertyIndirect(parameters, parametersCount);
|
||||
|
||||
HRESULT hr;
|
||||
while (index--)
|
||||
{
|
||||
IDispatch *pEvent = events[index];
|
||||
if (NULL != pEvent)
|
||||
{
|
||||
hr = JSAPI::InvokeEvent(eventData, pEvent);
|
||||
if (FAILED(hr) && SCRIPT_E_REPORTED != hr)
|
||||
{
|
||||
events.erase(events.begin() + index);
|
||||
pEvent->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (events.empty())
|
||||
JSAPI2::callbackManager.Deregister(this);
|
||||
|
||||
eventData->Release();
|
||||
}
|
||||
|
||||
void JSAPI2::TransportAPI::OnStop(int position, int is_full_stop)
|
||||
{
|
||||
if (!is_full_stop)
|
||||
{
|
||||
JSAPI::CallbackParameters::PropertyTemplate parameter =
|
||||
{JSAPI::CallbackParameters::typeLong, L"position", (ULONG_PTR)position};
|
||||
|
||||
InvokeEvent(L"OnStop", ¶meter, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
InvokeEvent(L"OnEndOfFile", NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void JSAPI2::TransportAPI::OnPlay(const wchar_t *filename)
|
||||
{
|
||||
JSAPI::CallbackParameters::PropertyTemplate parameter =
|
||||
{JSAPI::CallbackParameters::typeString, L"filename", (ULONG_PTR)filename};
|
||||
|
||||
InvokeEvent(L"OnPlay", ¶meter, 1);
|
||||
}
|
||||
|
||||
|
||||
void JSAPI2::TransportAPI::OnPause(bool pause_state)
|
||||
{
|
||||
JSAPI::CallbackParameters::PropertyTemplate parameter =
|
||||
{JSAPI::CallbackParameters::typeBool, L"paused", (ULONG_PTR)pause_state};
|
||||
|
||||
InvokeEvent(L"OnPause", ¶meter, 1);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <ocidl.h>
|
||||
#include <vector>
|
||||
#include "JSAPI_Info.h"
|
||||
#include "JSAPI_CallbackParameters.h"
|
||||
|
||||
namespace JSAPI2
|
||||
{
|
||||
class TransportAPI : public IDispatch
|
||||
{
|
||||
public:
|
||||
TransportAPI(const wchar_t *_key, JSAPI::ifc_info *info);
|
||||
~TransportAPI();
|
||||
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);
|
||||
public:
|
||||
/** Callbacks
|
||||
** JSAPI2::CallbackManager will have been nice enough to marshall onto our thread
|
||||
** so we don't have to worry about that
|
||||
*/
|
||||
void OnStop(int position, int is_full_stop);
|
||||
void OnPlay(const wchar_t *filename);
|
||||
void OnPause(bool pause_state);
|
||||
void InvokeEvent(const wchar_t *eventName, JSAPI::CallbackParameters::PropertyTemplate *parameters, size_t parametersCount);
|
||||
private:
|
||||
const wchar_t *key;
|
||||
volatile LONG refCount;
|
||||
JSAPI::ifc_info *info;
|
||||
typedef std::vector<IDispatch*> EventsList;
|
||||
EventsList events;
|
||||
|
||||
STDMETHOD (ButtonPress)(WPARAM button, const wchar_t *action, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (Prev)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (Play)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (Pause)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (Stop)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (Next)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (shuffle)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (repeat)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (position)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (length)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (url)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (title)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (playing)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (paused)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (GetMetadata)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (RegisterForEvents)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (UnregisterFromEvents)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
#pragma once
|
||||
#include <bfc/dispatch.h>
|
||||
#include "JSAPI_Info.h"
|
||||
|
||||
namespace JSAPI2
|
||||
{
|
||||
class api_security : public Dispatchable
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
ACTION_UNDEFINED = -1,
|
||||
ACTION_DISALLOWED = 0,
|
||||
ACTION_ALLOWED = 1,
|
||||
ACTION_PROMPT = 2,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SUCCESS = 0,
|
||||
FAILURE = 1,
|
||||
};
|
||||
|
||||
|
||||
struct AuthorizationData
|
||||
{
|
||||
GUID data_id;
|
||||
void *data;
|
||||
size_t data_len;
|
||||
};
|
||||
|
||||
// returns one of JSAPI2::api_security::ACTION_DISALLOWED, etc.
|
||||
int GetActionAuthorization(const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, JSAPI::ifc_info *info, int default_authorization = ACTION_ALLOWED, AuthorizationData *data = 0);
|
||||
|
||||
// returns JSAPI2_SUCCESS, etc.
|
||||
int SetActionAuthorization(const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, int authorization);
|
||||
|
||||
// associates an HWND with a key.. used for prompting
|
||||
void Associate(const wchar_t *authorization_key, HWND hwnd);
|
||||
HWND GetAssociation(const wchar_t *authorization_key);
|
||||
|
||||
// if you just want a simple security prompt, you can call this in your svc_apicreator::PromptForAuthorization implementation
|
||||
int SecurityPrompt(HWND hwnd, const wchar_t *title_string, const wchar_t *display_string, int flags=0);
|
||||
|
||||
// associates a name (e.g. an online service name) with a key.. used for prompting
|
||||
void AssociateName(const wchar_t *authorization_key, const wchar_t *name);
|
||||
const wchar_t *GetAssociatedName(const wchar_t *authorization_key);
|
||||
|
||||
// clears out all settings for a given key
|
||||
void ResetAuthorization(const wchar_t *authorization_key);
|
||||
|
||||
void SetBypass(const wchar_t *authorization_key, bool enable_bypass);
|
||||
|
||||
enum
|
||||
{
|
||||
JSAPI2_API_SECURITY_GETACTIONAUTHORIZATION = 0,
|
||||
JSAPI2_API_SECURITY_SETACTIONAUTHORIZATION = 1,
|
||||
JSAPI2_API_SECURITY_ASSOCIATE = 2,
|
||||
JSAPI2_API_SECURITY_GETASSOCIATION = 3,
|
||||
JSAPI2_API_SECURITY_SECURITYPROMPT = 4,
|
||||
JSAPI2_API_SECURITY_ASSOCIATENAME = 5,
|
||||
JSAPI2_API_SECURITY_GETASSOCIATEDNAME = 6,
|
||||
JSAPI2_API_SECURITY_RESETAUTHORIZATION = 7,
|
||||
JSAPI2_API_SECURITY_SETBYPASS = 8,
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
inline int api_security::GetActionAuthorization(const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, JSAPI::ifc_info *info, int default_authorization, AuthorizationData *data)
|
||||
{
|
||||
return _call(JSAPI2_API_SECURITY_GETACTIONAUTHORIZATION, (int)default_authorization, group, action, authorization_key, info, default_authorization, data);
|
||||
}
|
||||
|
||||
inline int api_security::SetActionAuthorization(const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, int authorization)
|
||||
{
|
||||
return _call(JSAPI2_API_SECURITY_SETACTIONAUTHORIZATION, (int)FAILURE, group, action, authorization_key, authorization);
|
||||
}
|
||||
|
||||
inline void api_security::Associate(const wchar_t *authorization_key, HWND hwnd)
|
||||
{
|
||||
_voidcall(JSAPI2_API_SECURITY_ASSOCIATE, authorization_key, hwnd);
|
||||
}
|
||||
|
||||
inline HWND api_security::GetAssociation(const wchar_t *authorization_key)
|
||||
{
|
||||
return _call(JSAPI2_API_SECURITY_GETASSOCIATION, (HWND)0, authorization_key);
|
||||
}
|
||||
|
||||
inline int api_security::SecurityPrompt(HWND hwnd, const wchar_t *title_string, const wchar_t *display_string, int flags)
|
||||
{
|
||||
return _call(JSAPI2_API_SECURITY_SECURITYPROMPT, (int)0, hwnd, title_string, display_string, flags);
|
||||
}
|
||||
|
||||
inline void api_security::AssociateName(const wchar_t *authorization_key, const wchar_t *name)
|
||||
{
|
||||
_voidcall(JSAPI2_API_SECURITY_ASSOCIATENAME, authorization_key, name);
|
||||
}
|
||||
|
||||
inline const wchar_t *api_security::GetAssociatedName(const wchar_t *authorization_key)
|
||||
{
|
||||
return _call(JSAPI2_API_SECURITY_GETASSOCIATEDNAME, (const wchar_t *)0, authorization_key);
|
||||
}
|
||||
|
||||
inline void api_security::ResetAuthorization(const wchar_t *authorization_key)
|
||||
{
|
||||
_voidcall(JSAPI2_API_SECURITY_RESETAUTHORIZATION, authorization_key);
|
||||
}
|
||||
inline void api_security::SetBypass(const wchar_t *authorization_key, bool enable_bypass)
|
||||
{
|
||||
_voidcall(JSAPI2_API_SECURITY_SETBYPASS, authorization_key, enable_bypass);
|
||||
}
|
||||
|
||||
// {D8BA8766-E489-4cfc-8527-9F3206257FFC}
|
||||
static const GUID api_securityGUID =
|
||||
{ 0xd8ba8766, 0xe489, 0x4cfc, { 0x85, 0x27, 0x9f, 0x32, 0x6, 0x25, 0x7f, 0xfc } };
|
||||
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user