#include #include "util.h" #ifndef ASSERT #if defined(_DEBUG) || defined(DEBUG) #define ASSERT(b) if(!b) MessageBox(NULL, "FAILED: #b", "ASSERT", MB_OK ); #else #define ASSERT(b) #endif #endif #define MAX_STRING_RESOURCE_LEN 1024 LPCSTR g_pszMsgBoxTitle = "HTML Help Dumper Tool"; int MsgBox(int idString, UINT nType) { char szMsg[MAX_STRING_RESOURCE_LEN + 1]; if (LoadString(GetModuleHandle(NULL), idString, szMsg, sizeof(szMsg)) == 0) { return 0; } return MessageBox(GetActiveWindow(), szMsg, g_pszMsgBoxTitle, nType); } int MsgBox(PCSTR pszMsg, UINT nType) { return MessageBox(GetActiveWindow(), pszMsg, g_pszMsgBoxTitle, nType); } PCSTR FindFilePortion( PCSTR pszFile ) { PCSTR psz = strrchr(pszFile, '\\'); if (psz) pszFile = psz + 1; psz = strrchr(pszFile, '/'); if (psz) return psz + 1; psz = strrchr(pszFile, ':'); return (psz ? psz + 1 : pszFile); } typedef enum { JAN=1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC } MONTHS; int DaysInMonth(int nMonth, int nYear) { switch( nMonth ) { case SEP: case APR: case JUN: case NOV: return 30; case FEB: return (nYear % 4) == 0 ? 29 : 28; // handle leap year default: return 31; } } int JulianDate(int nDay, int nMonth, int nYear) { int nDayOfYear = 0; int iMonth; for( iMonth = JAN ; iMonth < nMonth ; iMonth++ ) nDayOfYear += DaysInMonth(iMonth, nYear); return( (nYear % 10) * 1000 + nDayOfYear + nDay ); } #define YRMASK 0xFE00 #define YRSHIFT 9 #define MONMASK 0x01E0 #define MONSHIFT 5 #define DAYMASK 0x001F #define DAYSHIFT 0 #define HRMASK 0xF800 #define HRSHIFT 11 #define MINMASK 0x07E0 #define MINSHIFT 5 #define SECMASK 0x001F #define SECSHIFT 0 HRESULT FileTimeToDateTimeString( FILETIME FileTime, LPTSTR pszDateTime ) { HRESULT hr = S_FALSE; WORD wDosDate = 0; WORD wDosTime = 0; if( FileTimeToDosDateTime( &FileTime, &wDosDate, &wDosTime ) ) { DWORD dwDay = (wDosDate & DAYMASK) >> DAYSHIFT; DWORD dwMonth = (wDosDate & MONMASK) >> MONSHIFT; DWORD dwYear = (((wDosDate & YRMASK) >> YRSHIFT) + 80) % 100; DWORD dwHour = (wDosTime & HRMASK) >> HRSHIFT; DWORD dwMinute = (wDosTime & MINMASK) >> MINSHIFT; DWORD dwSecond = ((wDosTime & SECMASK) >> SECSHIFT) * 2; LPCSTR pszAMPM = NULL; if( dwHour >= 12 ) pszAMPM = "PM"; else pszAMPM = "AM"; if( dwHour > 12 ) dwHour -= 12; if( dwHour == 0 ) dwHour = 12; wsprintf( pszDateTime, "%02d/%02d/%02d %02d:%02d %s", dwMonth, dwDay, dwYear, dwHour, dwMinute, pszAMPM ); hr = S_OK; } return hr; } int FileTimeToJulianDate( FILETIME FileTime ) { int iReturn = 0; WORD wDosDate = 0; WORD wDosTime = 0; if( FileTimeToDosDateTime( &FileTime, &wDosDate, &wDosTime ) ) { DWORD dwDay = (wDosDate & DAYMASK) >> DAYSHIFT; DWORD dwMonth = (wDosDate & MONMASK) >> MONSHIFT; DWORD dwYear = ((wDosDate & YRMASK) >> YRSHIFT) + 1980; iReturn = JulianDate( dwDay, dwMonth, dwYear ); } return iReturn; } /////////////////////////////////////////////////////////// // // Get the windows directory for the system or the user // // Note, Windows NT Terminal Server has changed the system API // of GetWindowsDirectory to return a per-user system directory. // Inorder to determine this condtion we need to check kernel32 // for the GetSystemWindowsDirectory API and if it exists use // this one instead. // UINT HHGetWindowsDirectory( LPSTR lpBuffer, UINT uSize, UINT uiType ) { UINT uiReturn = 0; PFN_GETWINDOWSDIRECTORY pfnGetUsersWindowsDirectory = NULL; PFN_GETWINDOWSDIRECTORY pfnGetSystemWindowsDirectory = NULL; // determine which system API to call for each case HINSTANCE hInst = LoadLibrary( "Kernel32" ); if( !hInst ) return uiReturn; pfnGetSystemWindowsDirectory = (PFN_GETWINDOWSDIRECTORY) GetProcAddress( hInst, "GetSystemWindowsDirectoryA" ); pfnGetUsersWindowsDirectory = (PFN_GETWINDOWSDIRECTORY) GetProcAddress( hInst, "GetWindowsDirectoryA" ); ASSERT( pfnGetUsersWindowsDirectory ); // if NULL then we have a bug! if( !pfnGetSystemWindowsDirectory ) { pfnGetSystemWindowsDirectory = pfnGetUsersWindowsDirectory; } if( uiType == HH_SYSTEM_WINDOWS_DIRECTORY ) uiReturn = pfnGetSystemWindowsDirectory( lpBuffer, uSize ); else if( uiType == HH_USERS_WINDOWS_DIRECTORY ) uiReturn = pfnGetUsersWindowsDirectory( lpBuffer, uSize ); else uiReturn = 0; FreeLibrary( hInst ); return uiReturn; } LPSTR CatPath(LPSTR lpTop, LPCSTR lpTail) { // // make sure we have a slash at the end of the first element // LPSTR p; p = lpTop + strlen(lpTop); p = CharPrev(lpTop,p); if (*p != '\\' && *p != '/') { strcat(lpTop,"\\"); } // // strip any leading slash from the second element // while (*lpTail == '\\') lpTail = CharNext(lpTail); // // add them together // strcat(lpTop, lpTail); return lpTop; } #pragma data_seg(".text", "CODE") static const char txtGlobal[] = "global.col"; static const char txtColReg[] = "hhcolreg.dat"; static const char txtHelp[] = "help"; static const char txtHHDat[] = "hh.dat"; #pragma data_seg() /////////////////////////////////////////////////////////// // // Get the help directory // // Note, this is always relative to the system's windows // directory and not the user's windows directory. // See HHGetWindowsDirectory for details on this. // UINT HHGetHelpDirectory( LPTSTR lpBuffer, UINT uSize ) { UINT uiReturn = 0; uiReturn = HHGetWindowsDirectory( lpBuffer, uSize ); CatPath( lpBuffer, txtHelp ); return uiReturn; } DWORD CreatePath(char *szPath) { char szTmp[MAX_PATH],*p,*q,szTmp2[MAX_PATH]; DWORD dwErr; strcpy(szTmp2,szPath); memset(szTmp,0,sizeof(szTmp)); q = szTmp2; p = szTmp; while (*q) { if (*q == '/' || *q == '\\') { if (szTmp[1] == ':' && strlen(szTmp) <= 3) { if(IsDBCSLeadByte(*q)) { *p++ = *q++; if(*q) *p++ = *q++; } else *p++ = *q++; continue; } if (!::CreateDirectory(szTmp,0)) { if ( (dwErr = GetLastError()) != ERROR_ALREADY_EXISTS) return(dwErr); } } if(IsDBCSLeadByte(*q)) { *p++ = *q++; if(*q) *p++ = *q++; } else *p++ = *q++; } if (!::CreateDirectory(szTmp,0)) { if ((dwErr = GetLastError()) != ERROR_ALREADY_EXISTS) return(dwErr); } return(FALSE); } /////////////////////////////////////////////////////////// // // Get the full pathname to the global collections file // // Note, this is in always in the system's help directory. // UINT HHGetGlobalCollectionPathname( LPTSTR lpBuffer, UINT uSize, BOOL *pbNewPath ) { UINT uiReturn = 0; *pbNewPath = TRUE; uiReturn = HHGetHelpDataPath( lpBuffer ); if (uiReturn != S_OK) { *pbNewPath = FALSE; uiReturn = HHGetHelpDirectory( lpBuffer, uSize ); if( !IsDirectory(lpBuffer) ) CreatePath( lpBuffer ); } CatPath( lpBuffer, txtColReg ); return uiReturn; } BOOL IsDirectory( LPCSTR lpszPathname ) { DWORD dwAttribs = GetFileAttributes( lpszPathname ); if( dwAttribs != (DWORD) -1 ) if( dwAttribs & FILE_ATTRIBUTE_DIRECTORY ) return TRUE; return FALSE; } static const char txtProfiles[] = "Profiles"; static const char txtUser[] = "Default User"; static const char txtAllUsers[] = "All Users"; static const char txtApplicationData[] = "Application Data"; static const char txtMicrosoft[] = "Microsoft"; static const char txtHTMLHelp[] = "HTML Help"; typedef HRESULT (WINAPI *PFN_SHGETFOLDERPATH)( HWND hWnd, int nFolder, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath ); #ifndef CSIDL_FLAG_CREATE #define CSIDL_COMMON_APPDATA 0x0023 #define CSIDL_FLAG_CREATE 0x8000 #endif /////////////////////////////////////////////////////////// // // Get the full path to where the common help data files lives // hhcolreg.dat, *.chw and *.chs // // Note, if the subdirectories of the path does not exist // we will create them // HRESULT HHGetHelpDataPath( LPSTR pszPath ) { HRESULT hResult = S_OK; PFN_SHGETFOLDERPATH pfnSHGetFolderPath = NULL; HINSTANCE hInst = LoadLibrary( "Shell32" ); if( !hInst ) return S_FALSE; pfnSHGetFolderPath = (PFN_SHGETFOLDERPATH) GetProcAddress( hInst, "SHGetFolderPathA" ); // if this function does not exist then we need to similate the return path of // "%windir%\Profiles\All Users\Application Data" if( pfnSHGetFolderPath ) { // now call it hResult = pfnSHGetFolderPath( NULL, CSIDL_FLAG_CREATE | CSIDL_COMMON_APPDATA, NULL, 0, pszPath); if (pszPath[0] == NULL) { FreeLibrary( hInst ); // since we already have a copy of Shell32 loaded, free it return S_FALSE; } } else { FreeLibrary( hInst ); // since we already have a copy of Shell32 loaded, free it return S_FALSE; } FreeLibrary( hInst ); // since we already have a copy of Shell32 loaded, free it // append "Microsoft" CatPath( pszPath, txtMicrosoft ); if( !IsDirectory(pszPath) ) if( !CreateDirectory( pszPath, NULL ) ) return S_FALSE; // append "HTML Help" CatPath( pszPath, txtHTMLHelp ); if( !IsDirectory(pszPath) ) if( !CreateDirectory( pszPath, NULL ) ) return S_FALSE; return hResult; } /////////////////////////////////////////////////////////// // // Get the full pathname to the user's data file // // Note, this is always relative to the users's windows // directory and not the system's windows directory. // See HHGetWindowsDirectory for details on this. // UINT HHGetUsersDataPathname( LPTSTR lpBuffer, UINT uSize ) { UINT uiReturn = 0; uiReturn = HHGetWindowsDirectory( lpBuffer, uSize, HH_USERS_WINDOWS_DIRECTORY ); CatPath( lpBuffer, txtHHDat ); return uiReturn; }