450 lines
11 KiB
C
Executable File
450 lines
11 KiB
C
Executable File
/*****************************************************************************
|
|
*
|
|
* This program is free software ; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* $Id: association_win32.c 603 2006-01-19 13:00:33Z picard $
|
|
*
|
|
* The Core Pocket Media Player
|
|
* Copyright (c) 2004-2005 Gabor Kovacs
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include "../common.h"
|
|
|
|
#if defined(TARGET_WIN32) || defined(TARGET_WINCE)
|
|
|
|
#define REG_ASSOCIATIONS 0x2C00
|
|
|
|
#ifndef STRICT
|
|
#define STRICT
|
|
#endif
|
|
#include <windows.h>
|
|
|
|
static void SetURLProtocol(const tchar_t* Base)
|
|
{
|
|
const tchar_t* Name = T("URL Protocol");
|
|
tchar_t Value[MAXPATH];
|
|
DWORD RegType;
|
|
DWORD RegSize;
|
|
DWORD Disp=0;
|
|
HKEY Key;
|
|
if (RegCreateKeyEx(HKEY_CLASSES_ROOT, Base, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &Key, &Disp) == ERROR_SUCCESS)
|
|
{
|
|
RegSize=sizeof(Value);
|
|
if (RegQueryValueEx(Key, NULL, 0, &RegType, (LPBYTE)Value, &RegSize) != ERROR_SUCCESS ||
|
|
tcsnicmp(Value,T("URL:"),4)!=0)
|
|
{
|
|
stprintf_s(Value,TSIZEOF(Value),T("URL:%s protocol"),Base);
|
|
RegSetValueEx(Key, NULL, 0, REG_SZ, (LPBYTE)Value, (DWORD)((tcslen(Value)+1)*sizeof(tchar_t)));
|
|
}
|
|
|
|
RegSize=sizeof(Value);
|
|
if (RegQueryValueEx(Key, Name, 0, &RegType, (LPBYTE)Value, &RegSize) != ERROR_SUCCESS)
|
|
RegSetValueEx(Key, Name, 0, REG_SZ, (LPBYTE)T(""), sizeof(tchar_t));
|
|
|
|
RegCloseKey(Key);
|
|
}
|
|
}
|
|
|
|
static void SetEditFlags(const tchar_t* Base,DWORD Value)
|
|
{
|
|
DWORD Disp=0;
|
|
HKEY Key;
|
|
if (RegCreateKeyEx(HKEY_CLASSES_ROOT, Base, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &Key, &Disp) == ERROR_SUCCESS)
|
|
{
|
|
RegSetValueEx(Key, T("EditFlags"), 0, REG_DWORD, (LPBYTE)&Value, sizeof(Value));
|
|
RegCloseKey(Key);
|
|
}
|
|
//BrowserFlags=8 (?)
|
|
}
|
|
|
|
static void SetReg(const tchar_t* Base,const tchar_t* New,bool_t State)
|
|
{
|
|
tchar_t Old[MAXPATH];
|
|
tchar_t Backup[MAXPATH];
|
|
DWORD Disp=0;
|
|
HKEY Key;
|
|
DWORD RegSize;
|
|
DWORD RegType;
|
|
|
|
stprintf_s(Backup,TSIZEOF(Backup),T("%s.bak"),Context()->ProgramName);
|
|
|
|
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, Base, 0, KEY_READ|KEY_WRITE, &Key) == ERROR_SUCCESS)
|
|
{
|
|
RegSize=sizeof(Old);
|
|
if (RegQueryValueEx(Key, NULL, 0, &RegType, (LPBYTE)Old, &RegSize) != ERROR_SUCCESS)
|
|
Old[0] = 0;
|
|
|
|
if (tcsicmp(Old,New)!=0)
|
|
{
|
|
if (State)
|
|
{
|
|
RegSetValueEx(Key, NULL, 0, REG_SZ, (LPBYTE)New, (DWORD)((tcslen(New)+1)*sizeof(tchar_t)));
|
|
RegSetValueEx(Key, Backup, 0, REG_SZ, (LPBYTE)Old, RegSize);
|
|
}
|
|
}
|
|
else
|
|
if (!State)
|
|
{
|
|
RegSize = sizeof(Old);
|
|
if (RegQueryValueEx(Key, Backup, 0, &RegType, (LPBYTE)Old, &RegSize) == ERROR_SUCCESS)
|
|
{
|
|
RegSetValueEx(Key, NULL, 0, REG_SZ, (LPBYTE)Old, RegSize);
|
|
RegDeleteValue(Key, Backup);
|
|
}
|
|
}
|
|
|
|
RegCloseKey(Key);
|
|
}
|
|
else
|
|
if (State)
|
|
{
|
|
if (RegCreateKeyEx(HKEY_CLASSES_ROOT, Base, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &Key, &Disp) == ERROR_SUCCESS)
|
|
{
|
|
RegSetValueEx(Key, NULL, 0, REG_SZ, (LPBYTE)New, (DWORD)((tcslen(New)+1)*sizeof(New)));
|
|
RegSetValueEx(Key, Backup, 0, REG_SZ, (LPBYTE)T(""), sizeof(tchar_t));
|
|
RegCloseKey(Key);
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool_t CmpReg(const tchar_t* Base, const tchar_t* Value)
|
|
{
|
|
bool_t Result = 0;
|
|
HKEY Key;
|
|
DWORD RegSize;
|
|
DWORD RegType;
|
|
tchar_t s[MAXPATH];
|
|
|
|
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, Base, 0, KEY_READ, &Key) == ERROR_SUCCESS)
|
|
{
|
|
RegSize = sizeof(s);
|
|
if (RegQueryValueEx(Key, NULL, 0, &RegType, (LPBYTE)s, &RegSize) == ERROR_SUCCESS && RegType == REG_SZ)
|
|
Result = tcsicmp(s,Value)==0;
|
|
|
|
RegCloseKey(Key);
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
static void SetFileAssociation(const tchar_t* Ext,bool_t State,bool_t MIME,bool_t PlayList)
|
|
{
|
|
tchar_t Base[64];
|
|
tchar_t Type[64];
|
|
tchar_t Path[MAXPATH];
|
|
tchar_t Open[MAXPATH];
|
|
tchar_t Icon[MAXPATH];
|
|
|
|
GetModuleFileName(NULL,Path,MAXPATH);
|
|
if (tcschr(Path,' '))
|
|
stprintf_s(Open,TSIZEOF(Open),T("\"%s\" \"%%1\""),Path);
|
|
else
|
|
stprintf_s(Open,TSIZEOF(Open),T("%s \"%%1\""),Path);
|
|
stprintf_s(Icon,TSIZEOF(Icon),T("%s, -%d"),Path,1000);
|
|
|
|
stprintf_s(Base,TSIZEOF(Base),T(".%s"),Ext);
|
|
stprintf_s(Type,TSIZEOF(Type),MIME?T("%s"):T("%sFile"),Ext);
|
|
tcsupr(Type);
|
|
|
|
if (!MIME)
|
|
{
|
|
SetReg(Base,Type,State);
|
|
if (State)
|
|
SetEditFlags(Type,PlayList?0x10010000:0x10000);
|
|
}
|
|
else
|
|
if (State)
|
|
SetURLProtocol(Type);
|
|
|
|
stprintf_s(Base,TSIZEOF(Base),T("%s\\DefaultIcon"),Type);
|
|
SetReg(Base,Icon,State);
|
|
|
|
stprintf_s(Base,TSIZEOF(Base),T("%s\\Shell\\Open\\Command"),Type);
|
|
SetReg(Base,Open,State);
|
|
}
|
|
|
|
#if defined(NDEBUG) && !defined(TARGET_WIN32)
|
|
static bool_t GetReg(const tchar_t* Base, tchar_t* Value,DWORD ValueSize)
|
|
{
|
|
bool_t Result = 0;
|
|
HKEY Key;
|
|
DWORD RegType;
|
|
|
|
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, Base, 0, KEY_READ, &Key) == ERROR_SUCCESS)
|
|
{
|
|
if (RegQueryValueEx(Key, NULL, 0, &RegType, (LPBYTE)Value, &ValueSize) == ERROR_SUCCESS && RegType == REG_SZ && Value[0])
|
|
Result = 1;
|
|
|
|
RegCloseKey(Key);
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
static bool_t EmptyFileAssociation(const tchar_t* Ext,bool_t MIME)
|
|
{
|
|
tchar_t Base[MAXPATH];
|
|
tchar_t Type[MAXPATH];
|
|
|
|
stprintf_s(Base,TSIZEOF(Base),T(".%s"),Ext);
|
|
if (MIME || GetReg(Base,Type,sizeof(Type)))
|
|
{
|
|
if (MIME)
|
|
tcscpy_s(Type,TSIZEOF(Type),Ext);
|
|
stprintf_s(Base,TSIZEOF(Base),T("%s\\Shell\\Open\\Command"),Type);
|
|
if (GetReg(Base,Type,sizeof(Type)))
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
static bool_t GetFileAssociation(const tchar_t* Ext,bool_t MIME)
|
|
{
|
|
tchar_t Base[64];
|
|
tchar_t Type[64];
|
|
|
|
stprintf_s(Base,TSIZEOF(Base),T(".%s"),Ext);
|
|
stprintf_s(Type,TSIZEOF(Type),MIME?T("%s"):T("%sFile"),Ext);
|
|
tcsupr(Type);
|
|
|
|
if (MIME || CmpReg(Base,Type))
|
|
{
|
|
tchar_t Path[MAXPATH];
|
|
tchar_t Open[MAXPATH];
|
|
|
|
GetModuleFileName(NULL,Path,MAXPATH);
|
|
if (tcschr(Path,' '))
|
|
stprintf_s(Open,TSIZEOF(Open),T("\"%s\" \"%%1\""),Path);
|
|
else
|
|
stprintf_s(Open,TSIZEOF(Open),T("%s \"%%1\""),Path);
|
|
|
|
stprintf_s(Base,TSIZEOF(Base),T("%s\\Shell\\Open\\Command"),Type);
|
|
if (CmpReg(Base,Open))
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int Enum( node* p, int* No, datadef* Param )
|
|
{
|
|
array List;
|
|
|
|
NodeEnumClass(&List,MEDIA_CLASS);
|
|
if (*No>=0 && *No<ARRAYCOUNT(List,int))
|
|
{
|
|
memset(Param,0,sizeof(datadef));
|
|
Param->No = ARRAYBEGIN(List,int)[*No];
|
|
Param->Name = LangStr(Param->No,NODE_NAME);
|
|
Param->Type = TYPE_BOOL;
|
|
Param->Size = sizeof(bool_t);
|
|
Param->Flags = DF_SETUP|DF_NOSAVE|DF_CHECKLIST;
|
|
Param->Class = ASSOCIATION_ID;
|
|
if (!UniqueExts(ARRAYBEGIN(List,int),ARRAYBEGIN(List,int)+*No))
|
|
Param->Flags = DF_HIDDEN;
|
|
ArrayClear(&List);
|
|
return ERR_NONE;
|
|
}
|
|
*No -= ARRAYCOUNT(List,int);
|
|
ArrayClear(&List);
|
|
|
|
NodeEnumClass(&List,STREAM_CLASS);
|
|
if (*No>=0 && *No<ARRAYCOUNT(List,int))
|
|
{
|
|
tchar_t Mime[MAXPATH];
|
|
bool_t HasHost;
|
|
|
|
memset(Param,0,sizeof(datadef));
|
|
Param->No = ARRAYBEGIN(List,int)[*No];
|
|
Param->Name = LangStr(Param->No,NODE_NAME);
|
|
Param->Type = TYPE_BOOL;
|
|
Param->Size = sizeof(bool_t);
|
|
Param->Flags = DF_SETUP|DF_NOSAVE|DF_CHECKLIST;
|
|
Param->Class = ASSOCIATION_ID;
|
|
|
|
stprintf_s(Mime,TSIZEOF(Mime),T("%s://"),LangStr(Param->No,NODE_CONTENTTYPE));
|
|
GetMime(Mime,NULL,0,&HasHost);
|
|
if (!HasHost || tcsicmp(Mime,T("://"))==0 || tcsicmp(Mime,T("http://"))==0)
|
|
Param->Flags = DF_HIDDEN;
|
|
ArrayClear(&List);
|
|
return ERR_NONE;
|
|
}
|
|
*No -= ARRAYCOUNT(List,int);
|
|
ArrayClear(&List);
|
|
|
|
return ERR_INVALID_PARAM;
|
|
}
|
|
|
|
static int Get(node* p, int No, void* Data, int Size)
|
|
{
|
|
if (NodeIsClass(No,STREAM_CLASS))
|
|
{
|
|
assert(Size==sizeof(bool_t));
|
|
*(bool_t*)Data = GetFileAssociation(LangStr(No,NODE_CONTENTTYPE),1);
|
|
return ERR_NONE;
|
|
}
|
|
else
|
|
if (NodeIsClass(No,MEDIA_CLASS))
|
|
{
|
|
const tchar_t* Exts = LangStr(No,NODE_EXTS);
|
|
if (Exts && Exts[0])
|
|
{
|
|
tchar_t s[16];
|
|
const tchar_t *r,*q;
|
|
|
|
assert(Size==sizeof(bool_t));
|
|
*(bool_t*)Data = 1;
|
|
for (r=Exts;r;)
|
|
{
|
|
q = tcschr(r,':');
|
|
if (q)
|
|
{
|
|
tcsncpy_s(s,TSIZEOF(s),r,q-r);
|
|
if (!GetFileAssociation(s,0))
|
|
{
|
|
*(bool_t*)Data = 0;
|
|
break;
|
|
}
|
|
}
|
|
r = tcschr(r,';');
|
|
if (r) ++r;
|
|
}
|
|
return ERR_NONE;
|
|
}
|
|
}
|
|
return ERR_INVALID_PARAM;
|
|
}
|
|
|
|
static int Set(node* p, int No, const void* Data, int Size)
|
|
{
|
|
if (NodeIsClass(No,STREAM_CLASS))
|
|
{
|
|
assert(Size==sizeof(bool_t));
|
|
SetFileAssociation(LangStr(No,NODE_CONTENTTYPE),*(bool_t*)Data,1,0);
|
|
return ERR_NONE;
|
|
}
|
|
else
|
|
if (NodeIsClass(No,MEDIA_CLASS))
|
|
{
|
|
const tchar_t* Exts = LangStr(No,NODE_EXTS);
|
|
if (Exts && Exts[0])
|
|
{
|
|
tchar_t s[16];
|
|
const tchar_t *r,*q;
|
|
bool_t State;
|
|
|
|
assert(Size==sizeof(bool_t));
|
|
State = *(bool_t*)Data;
|
|
|
|
for (r=Exts;r;)
|
|
{
|
|
q = tcschr(r,':');
|
|
if (q)
|
|
{
|
|
tcsncpy_s(s,TSIZEOF(s),r,q-r);
|
|
SetFileAssociation(s,State,0,q[1]==FTYPE_PLAYLIST);
|
|
}
|
|
r = tcschr(r,';');
|
|
if (r) ++r;
|
|
}
|
|
return ERR_NONE;
|
|
}
|
|
}
|
|
return ERR_INVALID_PARAM;
|
|
}
|
|
|
|
static void AssignEmpty(node* p)
|
|
{
|
|
#if defined(NDEBUG) && !defined(TARGET_WIN32)
|
|
int v;
|
|
if (!NodeRegLoadValue(0,REG_ASSOCIATIONS,&v,sizeof(v),TYPE_INT) || !v)
|
|
{
|
|
// set default associations for empty extensions
|
|
array List;
|
|
int* i;
|
|
|
|
NodeEnumClass(&List,MEDIA_CLASS);
|
|
|
|
for (i=ARRAYBEGIN(List,int);i!=ARRAYEND(List,int);++i)
|
|
{
|
|
const tchar_t* Exts = LangStr(*i,NODE_EXTS);
|
|
if (Exts && Exts[0])
|
|
{
|
|
bool_t Empty = 1;
|
|
tchar_t s[16];
|
|
const tchar_t *r,*q;
|
|
|
|
for (r=Exts;r;)
|
|
{
|
|
q = tcschr(r,':');
|
|
if (q)
|
|
{
|
|
tcsncpy_s(s,TSIZEOF(s),r,q-r);
|
|
if (!EmptyFileAssociation(s,0))
|
|
{
|
|
Empty = 0;
|
|
break;
|
|
}
|
|
}
|
|
r = tcschr(r,';');
|
|
if (r) ++r;
|
|
}
|
|
|
|
if (Empty)
|
|
{
|
|
bool_t True = 1;
|
|
Set(p,*i,&True,sizeof(True));
|
|
}
|
|
}
|
|
}
|
|
|
|
ArrayClear(&List);
|
|
|
|
v = 1;
|
|
NodeRegSaveValue(0,REG_ASSOCIATIONS,&v,sizeof(v),TYPE_INT);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static int Create(node* p)
|
|
{
|
|
p->Enum = (nodeenum)Enum;
|
|
p->Get = (nodeget)Get;
|
|
p->Set = (nodeset)Set;
|
|
AssignEmpty(p);
|
|
return ERR_NONE;
|
|
}
|
|
|
|
static const nodedef Association =
|
|
{
|
|
sizeof(node)|CF_GLOBAL|CF_SETTINGS,
|
|
ASSOCIATION_ID,
|
|
NODE_CLASS,
|
|
PRI_MAXIMUM+500,
|
|
(nodecreate)Create,
|
|
};
|
|
|
|
void Association_Init()
|
|
{
|
|
NodeRegisterClass(&Association);
|
|
}
|
|
|
|
void Association_Done()
|
|
{
|
|
NodeUnRegisterClass(ASSOCIATION_ID);
|
|
}
|
|
|
|
#endif
|