/* Miranda IM Help Plugin Copyright (C) 2002 Richard Hughes, 2005-2007 H. Herkenrath 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 (Help-License.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #define __RPCASYNC_H__ /* header shows warnings in VS6 */ #include #include #define MIRANDA_VER 0x0600 #include #include #include #include #include #include "help.h" extern HWND hwndHelpDlg; struct DlgControlData { int id; int type; TCHAR *szTitle; char *szText; // ANSI or UTF-8 depending on _UNICODE defined (for RichEdit) }; struct DialogData { char *szId; char *szModule; struct DlgControlData *control; int controlCount; DWORD timeLoaded,timeLastUsed; int changes; LCID locale; UINT defaultCodePage; int isLocaleRTL; }; static struct DialogData *dialogCache=NULL; static int dialogCacheCount=0; static CRITICAL_SECTION csDialogCache; static HANDLE hServiceFileChange,hFileChange; #define DIALOGCACHEEXPIRY 10*60*1000 // delete from cache after those milliseconds static int ServiceFileChanged(WPARAM wParam,LPARAM lParam) { int i; UNREFERENCED_PARAMETER(lParam); EnterCriticalSection(&csDialogCache); for(i=0;icontrolCount;i++) { mir_free(entry->control[i].szText); // does NULL check mir_free(entry->control[i].szTitle); // does NULL check } mir_free(entry->control); // does NULL check mir_free(entry->szId); // does NULL check mir_free(entry->szModule); // does NULL check } void FreeDialogCache(void) { int i; if(hFileChange!=INVALID_HANDLE_VALUE) { CallService(MS_SYSTEM_REMOVEWAIT,(WPARAM)hFileChange,0); FindCloseChangeNotification(hFileChange); } DestroyServiceFunction(hServiceFileChange); DeleteCriticalSection(&csDialogCache); for(i=0;ihwndCtl); return; } fp=_tfopen(szSearch,_T("rt")); if(fp==NULL) { if(!Miranda_Terminated() && IsWindow(hwndHelpDlg)) PostMessage(hwndHelpDlg,M_HELPLOADFAILED,0,(LPARAM)dtsp->hwndCtl); return; } fgets(line,SIZEOF(line),fp); TrimString(line); if(lstrcmpA(line,"Miranda Help Pack Version 1")) { fclose(fp); if(!Miranda_Terminated() && IsWindow(hwndHelpDlg)) PostMessage(hwndHelpDlg,M_HELPLOADFAILED,0,(LPARAM)dtsp->hwndCtl); return; } // headers dialog.locale=LOCALE_USER_DEFAULT; dialog.defaultCodePage=CP_ACP; while(!feof(fp)) { startOfLine=ftell(fp); if(fgets(line,SIZEOF(line),fp)==NULL) break; TrimString(line); if(IsEmpty(line) || line[0]==';' || line[0]=='\0') continue; if(line[0]=='[') break; pszColon=strchr(line,':'); if(pszColon==NULL) { fclose(fp); if(!Miranda_Terminated() && IsWindow(hwndHelpDlg)) PostMessage(hwndHelpDlg,M_HELPLOADFAILED,0,(LPARAM)dtsp->hwndCtl); return; } *pszColon='\0'; // locale if(!lstrcmpA(line,"Locale")) { char szCP[6]; TrimString(pszColon+1); dialog.locale=MAKELCID((USHORT)strtol(pszColon+1,NULL,16),SORT_DEFAULT); // codepage if(GetLocaleInfoA(dialog.locale,LOCALE_IDEFAULTANSICODEPAGE,szCP,sizeof(szCP))) { szCP[5]='\0'; // codepages have 5 digits at max dialog.defaultCodePage=atoi(szCP); } } } // RTL flag // see also: http://blogs.msdn.com/michkap/archive/2006/03/03/542963.aspx { LOCALESIGNATURE sig; dialog.isLocaleRTL=0; if(GetLocaleInfo(dialog.locale,LOCALE_FONTSIGNATURE,(LPTSTR)&sig,sizeof(sig)/sizeof(TCHAR))) dialog.isLocaleRTL=(sig.lsUsb[3]&0x8000000); // Win2000+: testing for 'Layout progress: horizontal from right to left' bit switch(PRIMARYLANGID(LANGIDFROMLCID(dialog.locale))) { // prior to Win2000 case LANG_ARABIC: case LANG_HEBREW: case LANG_FARSI: dialog.isLocaleRTL=1; } } // body fseek(fp,startOfLine,SEEK_SET); success=1; control=NULL; while(!feof(fp)) { if(fgets(line,SIZEOF(line),fp)==NULL) break; if(IsEmpty(line) || line[0]==';' || line[0]=='\0') continue; TrimStringSimple(line); if(line[0]=='[' && line[lstrlenA(line)-1]==']') { pszLine=line+1; line[lstrlenA(line)-1]='\0'; // module pszColon=strrchr(pszLine,':'); if(pszColon==NULL) continue; *pszColon='\0'; pszColon++; TrimString(pszLine); if(lstrcmpiA(dtsp->szModule,pszLine)) continue; pszBuf=pszLine; // dlgid pszLine=pszColon; pszColon=strrchr(pszLine,'@'); if(pszColon==NULL) continue; *pszColon='\0'; pszColon++; TrimString(pszColon); if(lstrcmpA(dtsp->szDlgId,pszColon)) continue; if(dialog.szModule==NULL && dialog.szId==NULL) { dialog.szModule=mir_strdup(pszBuf); dialog.szId=mir_strdup(pszColon); if(dialog.szId==NULL || dialog.szModule==NULL) { success=0; break; } } buf=(struct DlgControlData*)mir_realloc(dialog.control,sizeof(struct DlgControlData)*(dialog.controlCount+1)); if(buf==NULL) { success=0; break; } dialog.controlCount++; dialog.control=(struct DlgControlData*)buf; control=&dialog.control[dialog.controlCount-1]; ZeroMemory(control,sizeof(*control)); // ctlid TrimString(pszLine); control->id=atoi(pszLine); } else if(control!=NULL) { pszLine=line; // ctltext pszColon=strchr(pszLine,'='); if(pszColon==NULL) continue; *pszColon='\0'; pszColon++; TrimString(pszColon); TrimString(pszLine); if(*pszColon=='\0' || *pszLine=='\0') continue; #if defined(_UNICODE) { int size=lstrlenA(pszLine)+1; control->szTitle=(WCHAR*)mir_alloc(size*sizeof(WCHAR)); if(control->szTitle!=NULL) { *control->szTitle=_T('\0'); MultiByteToWideChar(dialog.defaultCodePage,0,pszLine,-1,control->szTitle,size); } } #else control->szTitle=mir_strdup(pszLine); #endif // text #if defined(_UNICODE) control->szText=mir_utf8encodecp(pszColon,dialog.defaultCodePage); #else control->szText=mir_strdup(pszColon); #endif control=NULL; // control done } } fclose(fp); if(success) { int i,dialogInserted=0; dialog.timeLoaded=dialog.timeLastUsed=GetTickCount(); EnterCriticalSection(&csDialogCache); for(i=0;ihwndCtl); } if(!success) { mir_free(dialog.szId); // does NULL check mir_free(dialog.szModule); // does NULL check mir_free(dialog.control); // does NULL check if(!Miranda_Terminated() && IsWindow(hwndHelpDlg)) PostMessage(hwndHelpDlg,M_HELPLOADFAILED,0,(LPARAM)dtsp->hwndCtl); } mir_free(dtsp->szDlgId); mir_free(dtsp->szModule); mir_free(dtsp); } // mir_free() the return value char *CreateControlIdentifier(const char *pszDlgId,const char *pszModule,int ctrlId,HWND hwndCtl) { int size; char *szId; TCHAR szDefCtlText[128]; GetControlTitle(hwndCtl,szDefCtlText,SIZEOF(szDefCtlText)); size=lstrlenA(pszModule)+lstrlenA(pszDlgId)+SIZEOF(szDefCtlText)+22; szId=(char*)mir_alloc(size); mir_snprintf(szId,size,"[%s:%i@%s]\r\n"TCHAR_STR_PARAM"%s",pszModule,ctrlId,pszDlgId,szDefCtlText,szDefCtlText[0]?"=":""); return szId; } int GetControlHelp(HWND hwndCtl,const char *pszDlgId,const char *pszModule,int ctrlId,TCHAR **ppszTitle,char **ppszText,int *pType,LCID *pLocaleID,UINT *pCodePage,BOOL *pIsRTL,DWORD flags) { int i,j,useNext=0; struct LoaderThreadStartParams *dtsp; EnterCriticalSection(&csDialogCache); for(i=0;iszDlgId=mir_strdup(pszDlgId); dtsp->szModule=mir_strdup(pszModule); if(dtsp->szDlgId==NULL || dtsp->szModule==NULL) { mir_free(dtsp->szDlgId); // does NULL check mir_free(dtsp->szModule); // does NULL check mir_free(dtsp); LeaveCriticalSection(&csDialogCache); return 0; } dtsp->ctrlId=ctrlId; dtsp->hwndCtl=hwndCtl; mir_forkthread(LoaderThread,dtsp); } LeaveCriticalSection(&csDialogCache); return 1; } /**************************** SAVE HELP ***************************/ #ifdef EDITOR void SetControlHelp(const char *pszDlgId,const char *pszModule,int ctrlId,TCHAR *pszTitle,char *pszText,int type) { int i,j; int found=0; void *buf; EnterCriticalSection(&csDialogCache); j=0; for(i=0;i\r\n",dialogCache[i].szId,dialogCache[i].szModule); for(j=0;j\r\n",dialogCache[i].control[j].id,dialogCache[i].control[j].type); if(dialogCache[i].control[j].szTitle) AppendToCharBuffer(&data,"%s\r\n",dialogCache[i].control[j].szTitle); if(dialogCache[i].control[j].szText) AppendToCharBuffer(&data,"%s\r\n",dialogCache[i].control[j].szText); AppendToCharBuffer(&data,"\r\n"); } AppendToCharBuffer(&data,""); } if(success) { dialogCache[i].changes=0; dialogCache[i].timeLoaded=GetTickCount(); } */ MessageBoxEx(NULL,success?TranslateT("Help saving complete."):TranslateT("Help saving failed!"),TranslateT("Help Editor"),(success?MB_ICONINFORMATION:MB_ICONERROR)|MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL,LANGIDFROMLCID((LCID)CallService(MS_LANGPACK_GETLOCALE, 0, 0))); } void SaveDialogCache(void) { mir_forkthread(DialogCacheSaveThread,0,NULL); } #endif // defined EDITOR