/***************************************************************************** * * 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 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 && *NoNo = 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 && *NoNo = 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