#include "stdafx.h" CRomBrowser::CRomBrowser (HWND & MainWindow, HWND & StatusWindow ) : m_MainWindow(MainWindow), m_StatusWindow(StatusWindow), m_RefreshThread(NULL), m_RomIniFile(NULL), m_NotesIniFile(NULL), m_ExtIniFile(NULL), m_ZipIniFile(NULL), m_WatchThreadID(0), m_ShowingRomBrowser(false), m_AllowSelectionLastRom(true) { if (g_Settings) { m_RomIniFile = new CIniFile(g_Settings->LoadString(SupportFile_RomDatabase).c_str()); m_NotesIniFile = new CIniFile(g_Settings->LoadString(SupportFile_Notes).c_str()); m_ExtIniFile = new CIniFile(g_Settings->LoadString(SupportFile_ExtInfo).c_str()); m_ZipIniFile = new CIniFile(g_Settings->LoadString(SupportFile_7zipCache).c_str()); } m_hRomList = 0; m_Visible = false; m_WatchThread = NULL; m_WatchStopEvent = NULL; GetFieldInfo(m_Fields); m_FieldType.resize(m_Fields.size()); } CRomBrowser::~CRomBrowser (void) { m_StopRefresh = true; WatchThreadStop(); DeallocateBrushs(); if (m_RomIniFile) { delete m_RomIniFile; m_RomIniFile = NULL; } if (m_NotesIniFile) { delete m_NotesIniFile; m_NotesIniFile = NULL; } if (m_ExtIniFile) { delete m_ExtIniFile; m_ExtIniFile = NULL; } if (m_ZipIniFile) { delete m_ZipIniFile; m_ZipIniFile = NULL; } } void CRomBrowser::AddField (ROMBROWSER_FIELDS_LIST & Fields, LPCSTR Name, int Pos,int ID,int Width,LanguageStringID LangID, bool UseDefault) { Fields.push_back(ROMBROWSER_FIELDS(Name,Pos,ID,Width,LangID,UseDefault)); } void CRomBrowser::GetFieldInfo ( ROMBROWSER_FIELDS_LIST & Fields, bool UseDefault /* = false */) { Fields.clear(); AddField(Fields,"File Name", -1, RB_FileName, 218,RB_FILENAME, UseDefault); AddField(Fields,"Internal Name", -1, RB_InternalName, 200,RB_INTERNALNAME, UseDefault); AddField(Fields,"Good Name", 0, RB_GoodName, 218,RB_GOODNAME, UseDefault); AddField(Fields,"Status", 1, RB_Status, 92, RB_STATUS, UseDefault); AddField(Fields,"Rom Size", -1, RB_RomSize, 100,RB_ROMSIZE, UseDefault); AddField(Fields,"Notes (Core)", 2, RB_CoreNotes, 120,RB_NOTES_CORE, UseDefault); AddField(Fields,"Notes (default plugins)", 3, RB_PluginNotes, 188,RB_NOTES_PLUGIN, UseDefault); AddField(Fields,"Notes (User)", -1, RB_UserNotes, 100,RB_NOTES_USER, UseDefault); AddField(Fields,"Cartridge ID", -1, RB_CartridgeID, 100,RB_CART_ID, UseDefault); AddField(Fields,"Manufacturer", -1, RB_Manufacturer, 100,RB_MANUFACTUER, UseDefault); AddField(Fields,"Country", -1, RB_Country, 100,RB_COUNTRY, UseDefault); AddField(Fields,"Developer", -1, RB_Developer, 100,RB_DEVELOPER, UseDefault); AddField(Fields,"CRC1", -1, RB_Crc1, 100,RB_CRC1, UseDefault); AddField(Fields,"CRC2", -1, RB_Crc2, 100,RB_CRC2, UseDefault); AddField(Fields,"CIC Chip", -1, RB_CICChip, 100,RB_CICCHIP, UseDefault); AddField(Fields,"Release Date", -1, RB_ReleaseDate, 100,RB_RELEASE_DATE, UseDefault); AddField(Fields,"Genre", -1, RB_Genre, 100,RB_GENRE, UseDefault); AddField(Fields,"Players", -1, RB_Players, 100,RB_PLAYERS, UseDefault); AddField(Fields,"Force Feedback", -1, RB_ForceFeedback, 100,RB_FORCE_FEEDBACK, UseDefault); AddField(Fields,"File Format", -1, RB_FileFormat, 100,RB_FILE_FORMAT, UseDefault); } int CRomBrowser::CalcSortPosition (DWORD lParam) { int Start = 0; int End = ListView_GetItemCount((HWND)m_hRomList) - 1; if (End < 0) { return 0; } for (int SortIndex = NoOfSortKeys; SortIndex >= 0; SortIndex --) { stdstr SortFieldName = g_Settings->LoadStringIndex(RomBrowser_SortFieldIndex,SortIndex); if (SortFieldName.length() == 0) { continue; } if (End == Start) { break; } size_t index; for (index = 0; index < m_Fields.size(); index++) { if (_stricmp(m_Fields[index].Name(),SortFieldName.c_str()) == 0) { break; } } if (index >= m_Fields.size()) { continue; } SORT_FIELD SortFieldInfo; SortFieldInfo._this = this; SortFieldInfo.Key = index; SortFieldInfo.KeyAscend = g_Settings->LoadBoolIndex(RomBrowser_SortAscendingIndex,SortIndex); //calc new start and end int LastTestPos = -1; while (Start < End) { int TestPos = (int)floor((float)((Start + End) / 2)); if (LastTestPos == TestPos) { TestPos += 1; } LastTestPos = TestPos; LV_ITEM lvItem; memset(&lvItem, 0, sizeof(LV_ITEM)); lvItem.mask = LVIF_PARAM; lvItem.iItem = TestPos; if (!ListView_GetItem((HWND)m_hRomList, &lvItem)) { return End; } int Result = RomList_CompareItems(lParam,lvItem.lParam,(DWORD)&SortFieldInfo); if (Result < 0) { if (End == TestPos) { break; } End = TestPos; } else if (Result > 0) { if (Start == TestPos) { break; } Start = TestPos; } else { //Find new start float Left = (float)Start; float Right = (float)TestPos; while (Left < Right) { int NewTestPos = (int)floor((Left + Right) / 2); if (LastTestPos == NewTestPos) { NewTestPos += 1; } LastTestPos = NewTestPos; LV_ITEM lvItem; memset(&lvItem, 0, sizeof(LV_ITEM)); lvItem.mask = LVIF_PARAM; lvItem.iItem = NewTestPos; if (!ListView_GetItem((HWND)m_hRomList, &lvItem)) { return End; } int Result = RomList_CompareItems(lParam,lvItem.lParam,(DWORD)&SortFieldInfo); if (Result <= 0) { if (Right == NewTestPos) { break; } Right = (float)NewTestPos; } else if (Result > 0) { Left = Left != (float)NewTestPos ? (float)NewTestPos : Left + 1; } } Start = (int)((float)Right); //Find new end Left = (float)TestPos; Right = (float)End; while (Left < Right) { int NewTestPos = (int)ceil((Left + Right) / 2); if (LastTestPos == NewTestPos) { NewTestPos -= 1; } LastTestPos = NewTestPos; LV_ITEM lvItem; memset(&lvItem, 0, sizeof(LV_ITEM)); lvItem.mask = LVIF_PARAM; lvItem.iItem = NewTestPos; if (!ListView_GetItem((HWND)m_hRomList, &lvItem)) { return End; } int Result = RomList_CompareItems(lParam,lvItem.lParam,(DWORD)&SortFieldInfo); if (Result >= 0) { if (Left == NewTestPos) { break; } Left = (float)NewTestPos; } if (Result < 0) { Right = (float)NewTestPos; } } End = (int)Left; break; } } } //Compare end with item to see if we should do it after or before it for (int SortIndex = 0; SortIndex < NoOfSortKeys; SortIndex ++) { stdstr SortFieldName = g_Settings->LoadStringIndex(RomBrowser_SortFieldIndex,SortIndex); if (SortFieldName.length() == 0) { continue; } size_t index; for (index = 0; index < m_Fields.size(); index++) { if (_stricmp(m_Fields[index].Name(),SortFieldName.c_str()) == 0) { break; } } if (index >= m_Fields.size()) { continue; } SORT_FIELD SortFieldInfo; SortFieldInfo._this = this; SortFieldInfo.Key = index; SortFieldInfo.KeyAscend = g_Settings->LoadBoolIndex(RomBrowser_SortAscendingIndex,SortIndex) != 0; LV_ITEM lvItem; memset(&lvItem, 0, sizeof(LV_ITEM)); lvItem.mask = LVIF_PARAM; lvItem.iItem = End; if (!ListView_GetItem((HWND)m_hRomList, &lvItem)) { return End; } int Result = RomList_CompareItems(lParam, lvItem.lParam ,(DWORD)&SortFieldInfo); if (Result < 0) { return End; } if (Result > 0) { return End + 1; } } return End + 1; } void CRomBrowser::AddRomToList (const char * RomLocation, const char * lpLastRom) { ROM_INFO RomInfo; memset(&RomInfo, 0, sizeof(ROM_INFO)); strncpy(RomInfo.szFullFileName, RomLocation, sizeof(RomInfo.szFullFileName) - 1); if (!FillRomInfo(&RomInfo)) { return; } AddRomInfoToList(RomInfo,lpLastRom); } void CRomBrowser::AddRomInfoToList (ROM_INFO &RomInfo , const char * lpLastRom) { int ListPos = m_RomInfo.size(); m_RomInfo.push_back(RomInfo); LV_ITEM lvItem; memset(&lvItem, 0, sizeof(lvItem)); lvItem.mask = LVIF_TEXT | LVIF_PARAM; lvItem.iItem = CalcSortPosition(ListPos); lvItem.lParam = (LPARAM)ListPos; lvItem.pszText = LPSTR_TEXTCALLBACK; int index = ListView_InsertItem((HWND)m_hRomList, &lvItem); int iItem = ListView_GetNextItem((HWND)m_hRomList, -1, LVNI_SELECTED); //if (iItem == -1) { return; } //if the last rom then highlight the item if (iItem < 0 && _stricmp(RomInfo.szFullFileName,lpLastRom) == 0) { ListView_SetItemState((HWND)m_hRomList,index,LVIS_SELECTED | LVIS_FOCUSED,LVIS_SELECTED | LVIS_FOCUSED); } if (iItem >= 0) { ListView_EnsureVisible((HWND)m_hRomList,iItem,FALSE); } } void CRomBrowser::AllocateBrushs (void) { for (size_t count = 0; count < m_RomInfo.size(); count++) { if (m_RomInfo[count].SelColor == -1) { m_RomInfo[count].SelColorBrush = (DWORD)((HBRUSH)(COLOR_HIGHLIGHT + 1)); } else { m_RomInfo[count].SelColorBrush = (DWORD)CreateSolidBrush(m_RomInfo[count].SelColor); } } } DWORD CRomBrowser::AsciiToHex (char * HexValue) { DWORD Count, Finish, Value = 0; Finish = strlen(HexValue); if (Finish > 8 ) { Finish = 8; } for (Count = 0; Count < Finish; Count++) { Value = (Value << 4); switch( HexValue[Count] ) { case '0': break; case '1': Value += 1; break; case '2': Value += 2; break; case '3': Value += 3; break; case '4': Value += 4; break; case '5': Value += 5; break; case '6': Value += 6; break; case '7': Value += 7; break; case '8': Value += 8; break; case '9': Value += 9; break; case 'A': Value += 10; break; case 'a': Value += 10; break; case 'B': Value += 11; break; case 'b': Value += 11; break; case 'C': Value += 12; break; case 'c': Value += 12; break; case 'D': Value += 13; break; case 'd': Value += 13; break; case 'E': Value += 14; break; case 'e': Value += 14; break; case 'F': Value += 15; break; case 'f': Value += 15; break; default: Value = (Value >> 4); Count = Finish; } } return Value; } void CRomBrowser::CreateRomListControl (void) { m_hRomList = (HWND)CreateWindowEx( WS_EX_CLIENTEDGE,WC_LISTVIEW,NULL, WS_TABSTOP | WS_VISIBLE | WS_CHILD | LVS_OWNERDRAWFIXED | LVS_SINGLESEL | LVS_REPORT, 0,0,0,0,m_MainWindow,(HMENU)IDC_ROMLIST,GetModuleHandle(NULL),NULL); ResetRomBrowserColomuns(); LoadRomList(); } void CRomBrowser::DeallocateBrushs (void) { for (size_t count = 0; count < m_RomInfo.size(); count++) { if (m_RomInfo[count].SelColor == -1) { continue; } if (m_RomInfo[count].SelColorBrush) { DeleteObject((HBRUSH)m_RomInfo[count].SelColorBrush); m_RomInfo[count].SelColorBrush = NULL; } } } void CRomBrowser::FillRomExtensionInfo(ROM_INFO * pRomInfo) { //Initialize the structure pRomInfo->UserNotes[0] = 0; pRomInfo->Developer[0] = 0; pRomInfo->ReleaseDate[0] = 0; pRomInfo->Genre[0] = 0; pRomInfo->Players = 1; pRomInfo->CoreNotes[0] = 0; pRomInfo->PluginNotes[0] = 0; strcpy(pRomInfo->GoodName,"#340#"); strcpy(pRomInfo->Status,"Unknown"); //Get File Identifier char Identifier[100]; sprintf(Identifier,"%08X-%08X-C:%X",pRomInfo->CRC1,pRomInfo->CRC2,pRomInfo->Country); //Rom Notes if (m_Fields[RB_UserNotes].Pos() >= 0) { m_NotesIniFile->GetString(Identifier,"Note","",pRomInfo->UserNotes,sizeof(pRomInfo->UserNotes)); } //Rom Extension info if (m_Fields[RB_Developer].Pos() >= 0) { m_ExtIniFile->GetString(Identifier,"Developer","",pRomInfo->Developer,sizeof(pRomInfo->Developer)); } if (m_Fields[RB_ReleaseDate].Pos() >= 0) { m_ExtIniFile->GetString(Identifier,"ReleaseDate","",pRomInfo->ReleaseDate,sizeof(pRomInfo->ReleaseDate)); } if (m_Fields[RB_Genre].Pos() >= 0) { m_ExtIniFile->GetString(Identifier,"Genre","",pRomInfo->Genre,sizeof(pRomInfo->Genre)); } if (m_Fields[RB_Players].Pos() >= 0) { m_ExtIniFile->GetNumber(Identifier,"Players",1,(DWORD &)pRomInfo->Players); } if (m_Fields[RB_ForceFeedback].Pos() >= 0) { m_ExtIniFile->GetString(Identifier,"ForceFeedback","unknown",pRomInfo->ForceFeedback,sizeof(pRomInfo->ForceFeedback)); } //Rom Settings if (m_Fields[RB_GoodName].Pos() >= 0) { m_RomIniFile->GetString(Identifier,"Good Name",pRomInfo->GoodName,pRomInfo->GoodName,sizeof(pRomInfo->GoodName)); } m_RomIniFile->GetString(Identifier,"Status",pRomInfo->Status,pRomInfo->Status,sizeof(pRomInfo->Status)); if (m_Fields[RB_CoreNotes].Pos() >= 0) { m_RomIniFile->GetString(Identifier,"Core Note","",pRomInfo->CoreNotes,sizeof(pRomInfo->CoreNotes)); } if (m_Fields[RB_PluginNotes].Pos() >= 0) { m_RomIniFile->GetString(Identifier,"Plugin Note","",pRomInfo->PluginNotes,sizeof(pRomInfo->PluginNotes)); } //Get the text color char String[100]; m_RomIniFile->GetString("Rom Status",pRomInfo->Status,"000000",String,7); pRomInfo->TextColor = (AsciiToHex(String) & 0xFFFFFF); pRomInfo->TextColor = (pRomInfo->TextColor & 0x00FF00) | ((pRomInfo->TextColor >> 0x10) & 0xFF) | ((pRomInfo->TextColor & 0xFF) << 0x10); //Get the selected color sprintf(String,"%s.Sel",pRomInfo->Status); m_RomIniFile->GetString("Rom Status",String,"FFFFFFFF",String,9); int selcol = AsciiToHex(String); if (selcol < 0) { pRomInfo->SelColor = - 1; } else { selcol = (AsciiToHex(String) & 0xFFFFFF); selcol = (selcol & 0x00FF00) | ((selcol >> 0x10) & 0xFF) | ((selcol & 0xFF) << 0x10); pRomInfo->SelColor = selcol; } //Get the selected text color sprintf(String,"%s.Seltext",pRomInfo->Status); m_RomIniFile->GetString("Rom Status",String,"FFFFFF",String,7); pRomInfo->SelTextColor = (AsciiToHex(String) & 0xFFFFFF); pRomInfo->SelTextColor = (pRomInfo->SelTextColor & 0x00FF00) | ((pRomInfo->SelTextColor >> 0x10) & 0xFF) | ((pRomInfo->SelTextColor & 0xFF) << 0x10); } bool CRomBrowser::FillRomInfo(ROM_INFO * pRomInfo) { int count; BYTE RomData[0x1000]; if (!LoadDataFromRomFile(pRomInfo->szFullFileName,RomData,sizeof(RomData),&pRomInfo->RomSize,pRomInfo->FileFormat)) { return false; } else { if (strstr(pRomInfo->szFullFileName,"?") != NULL) { strcpy(pRomInfo->FileName,strstr(pRomInfo->szFullFileName,"?") + 1); } else { char drive[_MAX_DRIVE] ,dir[_MAX_DIR], ext[_MAX_EXT]; _splitpath( pRomInfo->szFullFileName, drive, dir, pRomInfo->FileName, ext ); } if (m_Fields[RB_InternalName].Pos() >= 0) { memcpy(pRomInfo->InternalName,(void *)(RomData + 0x20),20); for( count = 0 ; count < 20; count += 4 ) { pRomInfo->InternalName[count] ^= pRomInfo->InternalName[count+3]; pRomInfo->InternalName[count + 3] ^= pRomInfo->InternalName[count]; pRomInfo->InternalName[count] ^= pRomInfo->InternalName[count+3]; pRomInfo->InternalName[count + 1] ^= pRomInfo->InternalName[count + 2]; pRomInfo->InternalName[count + 2] ^= pRomInfo->InternalName[count + 1]; pRomInfo->InternalName[count + 1] ^= pRomInfo->InternalName[count + 2]; } pRomInfo->InternalName[21] = '\0'; } pRomInfo->CartID[0] = *(RomData + 0x3F); pRomInfo->CartID[1] = *(RomData + 0x3E); pRomInfo->CartID[2] = '\0'; pRomInfo->Manufacturer = *(RomData + 0x38); pRomInfo->Country = *(RomData + 0x3D); pRomInfo->CRC1 = *(DWORD *)(RomData + 0x10); pRomInfo->CRC2 = *(DWORD *)(RomData + 0x14); pRomInfo->CicChip = GetCicChipID(RomData); FillRomExtensionInfo(pRomInfo); if (pRomInfo->SelColor == -1) { pRomInfo->SelColorBrush = (DWORD)((HBRUSH)(COLOR_HIGHLIGHT + 1)); } else { pRomInfo->SelColorBrush = (DWORD)CreateSolidBrush(pRomInfo->SelColor); } return true; } } bool CRomBrowser::GetRomFileNames( strlist & FileList, const CPath & BaseDirectory, const stdstr & Directory, bool InWatchThread ) { if (!BaseDirectory.DirectoryExists()) { return false; } CPath SearchPath(BaseDirectory,"*.*"); SearchPath.AppendDirectory(Directory.c_str()); if (!SearchPath.FindFirst(CPath::_A_ALLFILES)) { return false; } do { if (InWatchThread && WaitForSingleObject(m_WatchStopEvent,0) != WAIT_TIMEOUT) { return false; } if (SearchPath.IsDirectory()) { if (g_Settings->LoadDword(RomBrowser_Recursive)) { stdstr CurrentDir = Directory + SearchPath.GetCurrentDirectory() + "\\"; GetRomFileNames(FileList,BaseDirectory,CurrentDir,InWatchThread); } } else { AddFileNameToList(FileList, Directory, SearchPath); } } while (SearchPath.FindNext()); return true; } void CRomBrowser::NotificationCB ( LPCWSTR Status, CRomBrowser * /*_this*/ ) { g_Notify->DisplayMessage(5,L"%s",Status); } void CRomBrowser::AddFileNameToList( strlist & FileList, const stdstr & Directory, CPath & File ) { if (FileList.size() > 3000) { return; } stdstr Drive, Dir, Name, Extension; File.GetComponents(NULL,&Dir,&Name,&Extension); Extension.ToLower(); if (Extension == "zip" || Extension == "7z" || Extension == "v64" || Extension == "z64" || Extension == "n64" || Extension == "rom" || Extension == "jap" || Extension == "pal" || Extension == "usa" || Extension == "eur" || Extension == "bin") { stdstr FileName = Directory+Name+Extension; FileName.ToLower(); FileList.push_back(FileName); } } void CRomBrowser::FillRomList ( strlist & FileList, const CPath & BaseDirectory, const stdstr & Directory, const char * lpLastRom ) { CPath SearchPath(BaseDirectory,"*.*"); SearchPath.AppendDirectory(Directory.c_str()); WriteTraceF(TraceDebug,__FUNCTION__ ": 1 %s",(LPCSTR)SearchPath); if (!SearchPath.FindFirst(CPath::_A_ALLFILES)) { return; } do { WriteTraceF(TraceDebug,__FUNCTION__ ": 2 %s m_StopRefresh = %d",(LPCSTR)SearchPath,m_StopRefresh); if (m_StopRefresh) { break; } if (SearchPath.IsDirectory()) { if (g_Settings->LoadDword(RomBrowser_Recursive)) { stdstr CurrentDir = Directory + SearchPath.GetCurrentDirectory() + "\\"; FillRomList(FileList,BaseDirectory,CurrentDir,lpLastRom); } continue; } AddFileNameToList(FileList, Directory, SearchPath); stdstr Extension = SearchPath.GetExtension(); Extension.ToLower(); if (Extension == "zip" || Extension == "v64" || Extension == "z64" || Extension == "n64" || Extension == "rom" || Extension == "jap" || Extension == "pal" || Extension == "usa" || Extension == "eur" || Extension == "bin") { AddRomToList(SearchPath,lpLastRom); continue; } if (Extension == "7z" ) { try { C7zip ZipFile(SearchPath); if (!ZipFile.OpenSuccess()) { continue; } char ZipFileName[260]; stdstr_f SectionName("%s-%d",ZipFile.FileName(ZipFileName,sizeof(ZipFileName)),ZipFile.FileSize()); SectionName.ToLower(); WriteTraceF(TraceDebug,__FUNCTION__ ": 4 %s",SectionName.c_str()); for (int i = 0; i < ZipFile.NumFiles(); i++) { CSzFileItem * f = ZipFile.FileItem(i); if (f->IsDir) { continue; } ROM_INFO RomInfo; std::wstring FileNameW = ZipFile.FileNameIndex(i); if (FileNameW.length() == 0) { continue; } stdstr FileName; FileName.FromUTF16(FileNameW.c_str()); WriteTrace(TraceDebug,__FUNCTION__ ": 5"); char drive2[_MAX_DRIVE] ,dir2[_MAX_DIR], FileName2[MAX_PATH], ext2[_MAX_EXT]; _splitpath( FileName.c_str(), drive2, dir2, FileName2, ext2 ); WriteTraceF(TraceDebug,__FUNCTION__ ": 6 %s",ext2); if (_stricmp(ext2, ".v64") != 0 && _stricmp(ext2, ".z64") != 0 && _stricmp(ext2, ".n64") != 0 && _stricmp(ext2, ".rom") != 0 && _stricmp(ext2, ".jap") != 0 && _stricmp(ext2, ".pal") != 0 && _stricmp(ext2, ".usa") != 0 && _stricmp(ext2, ".eur") != 0 && _stricmp(ext2, ".bin") == 0) { continue; } WriteTrace(TraceDebug,__FUNCTION__ ": 7"); memset(&RomInfo, 0, sizeof(ROM_INFO)); stdstr_f zipFileName("%s?%s",(LPCSTR)SearchPath,FileName.c_str()); ZipFile.SetNotificationCallback((C7zip::LP7ZNOTIFICATION)NotificationCB,this); strncpy(RomInfo.szFullFileName, zipFileName.c_str(), sizeof(RomInfo.szFullFileName) - 1); RomInfo.szFullFileName[sizeof(RomInfo.szFullFileName) - 1] = 0; strcpy(RomInfo.FileName,strstr(RomInfo.szFullFileName,"?") + 1); RomInfo.FileFormat = Format_7zip; WriteTrace(TraceDebug,__FUNCTION__ ": 8"); char szHeader[0x90]; if (m_ZipIniFile->GetString(SectionName.c_str(),FileName.c_str(),"",szHeader,sizeof(szHeader)) == 0) { BYTE RomData[0x1000]; if (!ZipFile.GetFile(i,RomData,sizeof(RomData))) { continue; } WriteTrace(TraceDebug,__FUNCTION__ ": 9"); if (!CN64Rom::IsValidRomImage(RomData)) { continue; } WriteTrace(TraceDebug,__FUNCTION__ ": 10"); ByteSwapRomData(RomData,sizeof(RomData)); WriteTrace(TraceDebug,__FUNCTION__ ": 11"); stdstr RomHeader; for (int x = 0; x < 0x40; x += 4) { RomHeader += stdstr_f("%08X",*((DWORD *)&RomData[x])); } WriteTraceF(TraceDebug,__FUNCTION__ ": 11a %s",RomHeader.c_str()); int CicChip = GetCicChipID(RomData); //save this info WriteTrace(TraceDebug,__FUNCTION__ ": 12"); m_ZipIniFile->SaveString(SectionName.c_str(),FileName.c_str(),RomHeader.c_str()); m_ZipIniFile->SaveNumber(SectionName.c_str(),stdstr_f("%s-Cic",FileName.c_str()).c_str(),CicChip); strcpy(szHeader,RomHeader.c_str()); } WriteTrace(TraceDebug,__FUNCTION__ ": 13"); BYTE RomData[0x40]; for (int x = 0; x < 0x40; x += 4) { *((DWORD *)&RomData[x]) = AsciiToHex(&szHeader[x*2]); } WriteTrace(TraceDebug,__FUNCTION__ ": 14"); memcpy(RomInfo.InternalName,(void *)(RomData + 0x20),20); for( int count = 0 ; count < 20; count += 4 ) { RomInfo.InternalName[count] ^= RomInfo.InternalName[count+3]; RomInfo.InternalName[count + 3] ^= RomInfo.InternalName[count]; RomInfo.InternalName[count] ^= RomInfo.InternalName[count+3]; RomInfo.InternalName[count + 1] ^= RomInfo.InternalName[count + 2]; RomInfo.InternalName[count + 2] ^= RomInfo.InternalName[count + 1]; RomInfo.InternalName[count + 1] ^= RomInfo.InternalName[count + 2]; } RomInfo.RomSize = (int)f->Size; WriteTrace(TraceDebug,__FUNCTION__ ": 15"); RomInfo.InternalName[21] = '\0'; RomInfo.CartID[0] = *(RomData + 0x3F); RomInfo.CartID[1] = *(RomData + 0x3E); RomInfo.CartID[2] = '\0'; RomInfo.Manufacturer = *(RomData + 0x38); RomInfo.Country = *(RomData + 0x3D); RomInfo.CRC1 = *(DWORD *)(RomData + 0x10); RomInfo.CRC2 = *(DWORD *)(RomData + 0x14); m_ZipIniFile->GetNumber(SectionName.c_str(),stdstr_f("%s-Cic",FileName.c_str()).c_str(), (ULONG)-1,(DWORD &)RomInfo.CicChip); WriteTrace(TraceDebug,__FUNCTION__ ": 16"); FillRomExtensionInfo(&RomInfo); if (RomInfo.SelColor == -1) { RomInfo.SelColorBrush = (DWORD)((HBRUSH)(COLOR_HIGHLIGHT + 1)); } else { RomInfo.SelColorBrush = (DWORD)CreateSolidBrush(RomInfo.SelColor); } WriteTrace(TraceDebug,__FUNCTION__ ": 17"); AddRomInfoToList(RomInfo,lpLastRom); } } catch (...) { WriteTraceF(TraceError,__FUNCTION__ "(): execpetion processing %s", (LPCSTR)SearchPath); } continue; } } while (SearchPath.FindNext()); m_ZipIniFile->FlushChanges(); } int CRomBrowser::GetCicChipID (BYTE * RomData) { __int64 CRC = 0; int count; for (count = 0x40; count < 0x1000; count += 4) { CRC += *(DWORD *)(RomData+count); } switch (CRC) { case 0x000000D0027FDF31: return CIC_NUS_6101; case 0x000000CFFB631223: return CIC_NUS_6101; case 0x000000D057C85244: return CIC_NUS_6102; case 0x000000D6497E414B: return CIC_NUS_6103; case 0x0000011A49F60E96: return CIC_NUS_6105; case 0x000000D6D5BE5580: return CIC_NUS_6106; default: return CIC_UNKNOWN; } } void CRomBrowser::HighLightLastRom(void) { if (!m_AllowSelectionLastRom) { return; } //Make sure Rom browser is visible if (!RomBrowserVisible()) { return; } //Get the string to the last rom stdstr LastRom = g_Settings->LoadStringIndex(File_RecentGameFileIndex,0); LPCSTR lpLastRom = LastRom.c_str(); LV_ITEM lvItem; lvItem.mask = LVIF_PARAM; int ItemCount = ListView_GetItemCount((HWND)m_hRomList); for (int index = 0; index < ItemCount; index++) { //Get The next item lvItem.iItem = index; if (!ListView_GetItem((HWND)m_hRomList, &lvItem)) { return; } //Get the rom info for that item if (lvItem.lParam < 0 || lvItem.lParam >= (LPARAM)m_RomInfo.size()) { return; } ROM_INFO * pRomInfo = &m_RomInfo[lvItem.lParam]; if (!m_AllowSelectionLastRom) { return; } //if the last rom then highlight the item if (_stricmp(pRomInfo->szFullFileName,lpLastRom) == 0) { ListView_SetItemState((HWND)m_hRomList,index,LVIS_SELECTED | LVIS_FOCUSED,LVIS_SELECTED | LVIS_FOCUSED); ListView_EnsureVisible((HWND)m_hRomList,index,FALSE); return; } } } bool CRomBrowser::LoadDataFromRomFile(char * FileName,BYTE * Data,int DataLen, int * RomSize, FILE_FORMAT & FileFormat) { BYTE Test[4]; if (_strnicmp(&FileName[strlen(FileName)-4], ".ZIP",4) == 0 ) { int len, port = 0, FoundRom; unz_file_info info; char zname[132]; unzFile file; file = unzOpen(FileName); if (file == NULL) { return false; } port = unzGoToFirstFile(file); FoundRom = FALSE; while(port == UNZ_OK && FoundRom == FALSE) { unzGetCurrentFileInfo(file, &info, zname, 128, NULL,0, NULL,0); if (unzLocateFile(file, zname, 1) != UNZ_OK ) { unzClose(file); return true; } if( unzOpenCurrentFile(file) != UNZ_OK ) { unzClose(file); return true; } unzReadCurrentFile(file,Test,4); if (CN64Rom::IsValidRomImage(Test)) { FoundRom = true; memcpy(Data,Test,4); len = unzReadCurrentFile(file,&Data[4],DataLen - 4) + 4; if ((int)DataLen != len) { unzCloseCurrentFile(file); unzClose(file); return false; } *RomSize = info.uncompressed_size; if(unzCloseCurrentFile(file) == UNZ_CRCERROR) { unzClose(file); return false; } unzClose(file); } if (FoundRom == false) { unzCloseCurrentFile(file); port = unzGoToNextFile(file); } } if (FoundRom == false) { return false; } FileFormat = Format_Zip; } else { DWORD dwRead; HANDLE hFile; hFile = CreateFile(FileName,GENERIC_READ,FILE_SHARE_READ,NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); if (hFile == INVALID_HANDLE_VALUE) { return false; } SetFilePointer(hFile,0,0,FILE_BEGIN); ReadFile(hFile,Test,4,&dwRead,NULL); if (!CN64Rom::IsValidRomImage(Test)) { CloseHandle( hFile ); return false; } SetFilePointer(hFile,0,0,FILE_BEGIN); if (!ReadFile(hFile,Data,DataLen,&dwRead,NULL)) { CloseHandle( hFile ); return false; } *RomSize = GetFileSize(hFile,NULL); CloseHandle( hFile ); FileFormat = Format_Uncompressed; } ByteSwapRomData(Data,DataLen); return true; } void CRomBrowser::ByteSwapRomData (BYTE * Data, int DataLen) { int count; switch (*((DWORD *)&Data[0])) { case 0x12408037: for( count = 0 ; count < DataLen; count += 4 ) { Data[count] ^= Data[count+2]; Data[count + 2] ^= Data[count]; Data[count] ^= Data[count+2]; Data[count + 1] ^= Data[count + 3]; Data[count + 3] ^= Data[count + 1]; Data[count + 1] ^= Data[count + 3]; } break; case 0x40123780: for( count = 0 ; count < DataLen; count += 4 ) { Data[count] ^= Data[count+3]; Data[count + 3] ^= Data[count]; Data[count] ^= Data[count+3]; Data[count + 1] ^= Data[count + 2]; Data[count + 2] ^= Data[count + 1]; Data[count + 1] ^= Data[count + 2]; } break; case 0x80371240: break; } } void CRomBrowser::LoadRomList (void) { stdstr FileName = g_Settings->LoadString(SupportFile_RomListCache); //Open the cache file HANDLE hFile = CreateFile(FileName.c_str(),GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); if (hFile == INVALID_HANDLE_VALUE) { //if file does not exist then refresh the data RefreshRomBrowser(); return; } DWORD dwRead; unsigned char md5[16]; ReadFile(hFile,&md5,sizeof(md5),&dwRead,NULL); //Read the size of ROM_INFO int RomInfoSize = 0; ReadFile(hFile,&RomInfoSize,sizeof(RomInfoSize),&dwRead,NULL); if (RomInfoSize != sizeof(ROM_INFO) || dwRead != sizeof(RomInfoSize)) { CloseHandle(hFile); RefreshRomBrowser(); return; } //Read the Number of entries int Entries = 0; ReadFile(hFile,&Entries,sizeof(Entries),&dwRead,NULL); //Read Every Entry DeallocateBrushs(); m_RomInfo.clear(); for (int count = 0; count < Entries; count++) { ROM_INFO RomInfo; ReadFile(hFile,&RomInfo,RomInfoSize,&dwRead,NULL); RomInfo.SelColorBrush = NULL; LV_ITEM lvItem; memset(&lvItem, 0, sizeof(lvItem)); lvItem.mask = LVIF_TEXT | LVIF_PARAM; lvItem.iItem = ListView_GetItemCount((HWND)m_hRomList); lvItem.lParam = (LPARAM)m_RomInfo.size(); lvItem.pszText = LPSTR_TEXTCALLBACK; ListView_InsertItem((HWND)m_hRomList, &lvItem); m_RomInfo.push_back(RomInfo); } CloseHandle(hFile); AllocateBrushs(); RomList_SortList(); } void CRomBrowser::MenuSetText ( HMENU hMenu, int MenuPos, const wchar_t * Title, char * ShortCut) { MENUITEMINFOW MenuInfo; wchar_t String[256]; if (Title == NULL || wcslen(Title) == 0) { return; } memset(&MenuInfo, 0, sizeof(MENUITEMINFO)); MenuInfo.cbSize = sizeof(MENUITEMINFO); MenuInfo.fMask = MIIM_TYPE; MenuInfo.fType = MFT_STRING; MenuInfo.fState = MFS_ENABLED; MenuInfo.dwTypeData = String; MenuInfo.cch = 256; GetMenuItemInfoW(hMenu,MenuPos,TRUE,&MenuInfo); wcscpy(String,Title); if (wcschr(String,'\t') != NULL) { *(wcschr(String,'\t')) = '\0'; } if (ShortCut) { swprintf(String,sizeof(String) / sizeof(String[0]),L"%s\t%s",String,ShortCut); } SetMenuItemInfoW(hMenu,MenuPos,TRUE,&MenuInfo); } void CRomBrowser::RefreshRomBrowser (void) { DWORD ThreadID; if (m_RefreshThread) { return; } WriteTrace(TraceDebug,__FUNCTION__ ": 1"); m_StopRefresh = false; m_RefreshThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RefreshRomBrowserStatic,(LPVOID)this,0,&ThreadID); WriteTrace(TraceDebug,__FUNCTION__ ": 2"); } void CRomBrowser::RefreshRomBrowserStatic (CRomBrowser * _this) { try { if (_this->m_hRomList == NULL) { return; } //delete cache stdstr CacheFileName = g_Settings->LoadString(SupportFile_RomListCache); DeleteFile(CacheFileName.c_str()); //clear all current items WriteTrace(TraceDebug,__FUNCTION__ " 1"); ListView_DeleteAllItems((HWND)_this->m_hRomList); _this->DeallocateBrushs(); _this->m_RomInfo.clear(); WriteTrace(TraceDebug,__FUNCTION__ " 2"); InvalidateRect((HWND)_this->m_hRomList,NULL,TRUE); Sleep(100); WriteTrace(TraceDebug,__FUNCTION__ " 3"); if (_this->m_WatchRomDir != g_Settings->LoadString(Directory_Game)) { WriteTrace(TraceDebug,__FUNCTION__ " 4"); _this->WatchThreadStop(); WriteTrace(TraceDebug,__FUNCTION__ " 5"); _this->WatchThreadStart(); WriteTrace(TraceDebug,__FUNCTION__ " 6"); } WriteTrace(TraceDebug,__FUNCTION__ " 7"); stdstr RomDir = g_Settings->LoadString(Directory_Game); stdstr LastRom = g_Settings->LoadStringIndex(File_RecentGameFileIndex,0); WriteTrace(TraceDebug,__FUNCTION__ " 8"); strlist FileNames; _this->FillRomList (FileNames, CPath(RomDir),stdstr(""), LastRom.c_str()); WriteTrace(TraceDebug,__FUNCTION__ " 9"); _this->SaveRomList(FileNames); WriteTrace(TraceDebug,__FUNCTION__ " 10"); CloseHandle(_this->m_RefreshThread); _this->m_RefreshThread = NULL; WriteTrace(TraceDebug,__FUNCTION__ " 11"); } catch (...) { WriteTrace(TraceError,__FUNCTION__ "(): Unhandled Exception "); } } void CRomBrowser::ResetRomBrowserColomuns (void) { size_t Coloumn, index; LV_COLUMNW lvColumn; wchar_t szString[300]; GetFieldInfo(m_Fields); //Remove all current coloumns memset(&lvColumn,0,sizeof(lvColumn)); lvColumn.mask = LVCF_FMT; while (ListView_GetColumn((HWND)m_hRomList,0,&lvColumn)) { ListView_DeleteColumn((HWND)m_hRomList,0); } //Add Colomuns lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvColumn.fmt = LVCFMT_LEFT; lvColumn.pszText = szString; for (Coloumn = 0; Coloumn < m_Fields.size(); Coloumn ++) { for (index = 0; index < m_Fields.size(); index ++) { if (m_Fields[index].Pos() == Coloumn) { break; } } if (index == m_Fields.size() || m_Fields[index].Pos() != Coloumn) { m_FieldType[Coloumn] = -1; break; } m_FieldType[Coloumn] = m_Fields[index].ID(); lvColumn.cx = m_Fields[index].ColWidth(); wcsncpy(szString, GS(m_Fields[index].LangID()), sizeof(szString) / sizeof(szString[0])); SendMessage(m_hRomList, LVM_INSERTCOLUMNW, (WPARAM)(int)(Coloumn), (LPARAM)(const LV_COLUMNW *)(&lvColumn)); } } void CRomBrowser::ResizeRomList (WORD nWidth, WORD nHeight) { if (RomBrowserVisible()) { if (g_Settings->LoadDword(RomBrowser_Maximized) == 0 && nHeight != 0) { if (g_Settings->LoadDword(RomBrowser_Width) != nWidth) { g_Settings->SaveDword(RomBrowser_Width,nWidth); } if (g_Settings->LoadDword(RomBrowser_Height) != nHeight) { g_Settings->SaveDword(RomBrowser_Height,nHeight); } } if (IsWindow((HWND)m_StatusWindow)) { RECT rc; GetWindowRect((HWND)m_StatusWindow, &rc); nHeight -= (WORD)(rc.bottom - rc.top); } MoveWindow((HWND)m_hRomList, 0, 0, nWidth, nHeight, TRUE); } } bool CRomBrowser::RomBrowserVisible (void) { if (!IsWindow((HWND)m_hRomList)) { return false; } if (!IsWindowVisible((HWND)m_hRomList)) { return false; } if (!m_Visible) { return false; } return true; } void CRomBrowser::RomBrowserToTop(void) { BringWindowToTop((HWND)m_hRomList); SetFocus((HWND)m_hRomList); } void CRomBrowser::RomBrowserMaximize(bool Mazimize) { g_Settings->SaveDword(RomBrowser_Maximized,(DWORD)Mazimize); } bool CRomBrowser::RomListDrawItem(int idCtrl, DWORD lParam) { if (idCtrl != IDC_ROMLIST) { return false; } LPDRAWITEMSTRUCT ditem = (LPDRAWITEMSTRUCT)lParam; RECT rcItem, rcDraw; char String[300]; LV_ITEM lvItem; HBRUSH hBrush; LV_COLUMN lvc; int nColumn; lvItem.mask = LVIF_PARAM; lvItem.iItem = ditem->itemID; if (!ListView_GetItem((HWND)m_hRomList, &lvItem)) { return false; } lvItem.state = ListView_GetItemState((HWND)m_hRomList, ditem->itemID, -1); bool bSelected = (lvItem.state & LVIS_SELECTED) != 0; if (lvItem.lParam < 0 || lvItem.lParam >= (LPARAM)m_RomInfo.size()) { return true; } ROM_INFO * pRomInfo = &m_RomInfo[lvItem.lParam]; if (pRomInfo == NULL) { return true; } if (bSelected) { hBrush = (HBRUSH)pRomInfo->SelColorBrush; SetTextColor(ditem->hDC,pRomInfo->SelTextColor); } else { hBrush = (HBRUSH)(COLOR_WINDOW + 1); SetTextColor(ditem->hDC,pRomInfo->TextColor); } FillRect( ditem->hDC, &ditem->rcItem,hBrush); SetBkMode( ditem->hDC, TRANSPARENT ); //Draw ListView_GetItemRect((HWND)m_hRomList,ditem->itemID,&rcItem,LVIR_LABEL); ListView_GetItemText((HWND)m_hRomList,ditem->itemID, 0, String, sizeof(String)); memcpy(&rcDraw,&rcItem,sizeof(RECT)); rcDraw.right -= 3; std::wstring text = stdstr(String).ToUTF16(); if (wcscmp(L"#340#", text.c_str()) == 0) { text = GS(RB_NOT_GOOD_FILE); } DrawTextW(ditem->hDC, text.c_str(), text.length(), &rcDraw, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER | DT_WORD_ELLIPSIS); memset(&lvc,0,sizeof(lvc)); lvc.mask = LVCF_FMT | LVCF_WIDTH; for(nColumn = 1; ListView_GetColumn((HWND)m_hRomList,nColumn,&lvc); nColumn += 1) { rcItem.left = rcItem.right; rcItem.right += lvc.cx; ListView_GetItemText((HWND)m_hRomList,ditem->itemID, nColumn, String, sizeof(String)); memcpy(&rcDraw,&rcItem,sizeof(RECT)); rcDraw.right -= 3; std::wstring text = stdstr(String).ToUTF16(); if (wcscmp(L"#340#", text.c_str()) == 0) { text = GS(RB_NOT_GOOD_FILE); } DrawTextW(ditem->hDC, text.c_str(), text.length(), &rcDraw, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER | DT_WORD_ELLIPSIS); } return true; } bool CRomBrowser::RomListNotify(int idCtrl, DWORD pnmh) { if (idCtrl != IDC_ROMLIST) { return false; } if (!RomBrowserVisible()) { return false; } switch (((LPNMHDR)pnmh)->code) { case LVN_COLUMNCLICK: RomList_ColoumnSortList(pnmh); break; case NM_RETURN: RomList_OpenRom(pnmh); break; case NM_DBLCLK: RomList_OpenRom(pnmh); break; case LVN_GETDISPINFO: RomList_GetDispInfo(pnmh); break; case NM_RCLICK: RomList_PopupMenu(pnmh); break; case NM_CLICK: { LONG iItem = ListView_GetNextItem((HWND)m_hRomList, -1, LVNI_SELECTED); if (iItem != -1) { m_AllowSelectionLastRom = false; } } break; default: return false; } return true; } void CRomBrowser::RomList_ColoumnSortList(DWORD pnmh) { LPNMLISTVIEW pnmv = (LPNMLISTVIEW)pnmh; size_t index; for (index = 0; index < m_Fields.size(); index++) { if (m_Fields[index].Pos() == (size_t)pnmv->iSubItem) { break; } } if (m_Fields.size() == index) { return; } if (_stricmp(g_Settings->LoadStringIndex(RomBrowser_SortFieldIndex,0).c_str(),m_Fields[index].Name()) == 0) { g_Settings->SaveBoolIndex(RomBrowser_SortAscendingIndex,0,!g_Settings->LoadBoolIndex(RomBrowser_SortAscendingIndex,0)); } else { int count; for (count = NoOfSortKeys; count > 0; count --) { g_Settings->SaveStringIndex(RomBrowser_SortFieldIndex,count,g_Settings->LoadStringIndex(RomBrowser_SortFieldIndex,count - 1).c_str()); g_Settings->SaveBoolIndex(RomBrowser_SortAscendingIndex,count,g_Settings->LoadBoolIndex(RomBrowser_SortAscendingIndex, count - 1)); } g_Settings->SaveStringIndex(RomBrowser_SortFieldIndex,0,m_Fields[index].Name()); g_Settings->SaveBoolIndex(RomBrowser_SortAscendingIndex,0,true); } RomList_SortList(); } int CALLBACK CRomBrowser::RomList_CompareItems(DWORD lParam1, DWORD lParam2, DWORD lParamSort) { SORT_FIELD * SortFieldInfo = (SORT_FIELD *)lParamSort; CRomBrowser * _this = SortFieldInfo->_this; if (lParam1 < 0 || lParam1 >= _this->m_RomInfo.size()) { return 0; } if (lParam2 < 0 || lParam2 >= _this->m_RomInfo.size()) { return 0; } ROM_INFO * pRomInfo1 = &_this->m_RomInfo[SortFieldInfo->KeyAscend?lParam1:lParam2]; ROM_INFO * pRomInfo2 = &_this->m_RomInfo[SortFieldInfo->KeyAscend?lParam2:lParam1]; int result; switch (SortFieldInfo->Key) { case RB_FileName: result = (int)lstrcmpi(pRomInfo1->FileName, pRomInfo2->FileName); break; case RB_InternalName: result = (int)lstrcmpi(pRomInfo1->InternalName, pRomInfo2->InternalName); break; case RB_GoodName: result = (int)lstrcmpi(pRomInfo1->GoodName, pRomInfo2->GoodName); break; case RB_Status: result = (int)lstrcmpi(pRomInfo1->Status, pRomInfo2->Status); break; case RB_RomSize: result = (int)pRomInfo1->RomSize - (int)pRomInfo2->RomSize; break; case RB_CoreNotes: result = (int)lstrcmpi(pRomInfo1->CoreNotes, pRomInfo2->CoreNotes); break; case RB_PluginNotes: result = (int)lstrcmpi(pRomInfo1->PluginNotes, pRomInfo2->PluginNotes); break; case RB_UserNotes: result = (int)lstrcmpi(pRomInfo1->UserNotes, pRomInfo2->UserNotes); break; case RB_CartridgeID: result = (int)lstrcmpi(pRomInfo1->CartID, pRomInfo2->CartID); break; case RB_Manufacturer: result = (int)pRomInfo1->Manufacturer - (int)pRomInfo2->Manufacturer; break; case RB_Country: result = (int)pRomInfo1->Country - (int)pRomInfo2->Country; break; case RB_Developer: result = (int)lstrcmpi(pRomInfo1->Developer, pRomInfo2->Developer); break; case RB_Crc1: result = (int)pRomInfo1->CRC1 - (int)pRomInfo2->CRC1; break; case RB_Crc2: result = (int)pRomInfo1->CRC2 - (int)pRomInfo2->CRC2; break; case RB_CICChip: result = (int)pRomInfo1->CicChip - (int)pRomInfo2->CicChip; break; case RB_ReleaseDate: result = (int)lstrcmpi(pRomInfo1->ReleaseDate, pRomInfo2->ReleaseDate); break; case RB_Players: result = (int)pRomInfo1->Players - (int)pRomInfo2->Players; break; case RB_ForceFeedback: result = (int)lstrcmpi(pRomInfo1->ForceFeedback, pRomInfo2->ForceFeedback); break; case RB_Genre: result = (int)lstrcmpi(pRomInfo1->Genre, pRomInfo2->Genre); break; case RB_FileFormat: result = (int)pRomInfo1->FileFormat - (int)pRomInfo2->FileFormat; break; default: result = 0; break; } return result; } void CRomBrowser::RomList_GetDispInfo(DWORD pnmh) { LV_DISPINFO * lpdi = (LV_DISPINFO *)pnmh; if (lpdi->item.lParam < 0 || lpdi->item.lParam >= (LPARAM)m_RomInfo.size()) { return; } ROM_INFO * pRomInfo = &m_RomInfo[lpdi->item.lParam]; if (pRomInfo == NULL) { strcpy(lpdi->item.pszText," "); return; } switch(m_FieldType[lpdi->item.iSubItem]) { case RB_FileName: strncpy(lpdi->item.pszText, pRomInfo->FileName, lpdi->item.cchTextMax); break; case RB_InternalName: strncpy(lpdi->item.pszText, pRomInfo->InternalName, lpdi->item.cchTextMax); break; case RB_GoodName: strncpy(lpdi->item.pszText, pRomInfo->GoodName, lpdi->item.cchTextMax); break; case RB_CoreNotes: strncpy(lpdi->item.pszText, pRomInfo->CoreNotes, lpdi->item.cchTextMax); break; case RB_PluginNotes: strncpy(lpdi->item.pszText, pRomInfo->PluginNotes, lpdi->item.cchTextMax); break; case RB_Status: strncpy(lpdi->item.pszText, pRomInfo->Status, lpdi->item.cchTextMax); break; case RB_RomSize: sprintf(lpdi->item.pszText,"%.1f MBit",(float)pRomInfo->RomSize/0x20000); break; case RB_CartridgeID: strncpy(lpdi->item.pszText, pRomInfo->CartID, lpdi->item.cchTextMax); break; case RB_Manufacturer: switch (pRomInfo->Manufacturer) { case 'N':strncpy(lpdi->item.pszText, "Nintendo", lpdi->item.cchTextMax); break; case 0: strncpy(lpdi->item.pszText, "None", lpdi->item.cchTextMax); break; default: sprintf(lpdi->item.pszText, "(Unknown %c (%X))", pRomInfo->Manufacturer,pRomInfo->Manufacturer); break; } break; case RB_Country: switch (pRomInfo->Country) { case '7': strncpy(lpdi->item.pszText, "Beta", lpdi->item.cchTextMax); break; case 'A': strncpy(lpdi->item.pszText, "NTSC", lpdi->item.cchTextMax); break; case 'D': strncpy(lpdi->item.pszText, "Germany", lpdi->item.cchTextMax); break; case 'E': strncpy(lpdi->item.pszText, "America", lpdi->item.cchTextMax); break; case 'F': strncpy(lpdi->item.pszText, "France", lpdi->item.cchTextMax); break; case 'J': strncpy(lpdi->item.pszText, "Japan", lpdi->item.cchTextMax); break; case 'I': strncpy(lpdi->item.pszText, "Italy", lpdi->item.cchTextMax); break; case 'P': strncpy(lpdi->item.pszText, "Europe", lpdi->item.cchTextMax); break; case 'S': strncpy(lpdi->item.pszText, "Spain", lpdi->item.cchTextMax); break; case 'U': strncpy(lpdi->item.pszText, "Australia", lpdi->item.cchTextMax); break; case 'X': strncpy(lpdi->item.pszText, "PAL", lpdi->item.cchTextMax); break; case 'Y': strncpy(lpdi->item.pszText, "PAL", lpdi->item.cchTextMax); break; case 0: strncpy(lpdi->item.pszText, "None", lpdi->item.cchTextMax); break; default: sprintf(lpdi->item.pszText, "Unknown %c (%02X)", pRomInfo->Country,pRomInfo->Country); break; } break; case RB_Crc1: sprintf(lpdi->item.pszText,"0x%08X",pRomInfo->CRC1); break; case RB_Crc2: sprintf(lpdi->item.pszText,"0x%08X",pRomInfo->CRC2); break; case RB_CICChip: if (pRomInfo->CicChip < 0) { sprintf(lpdi->item.pszText,"Unknown CIC Chip"); } else { sprintf(lpdi->item.pszText,"CIC-NUS-610%d",pRomInfo->CicChip); } break; case RB_UserNotes: strncpy(lpdi->item.pszText, pRomInfo->UserNotes, lpdi->item.cchTextMax); break; case RB_Developer: strncpy(lpdi->item.pszText, pRomInfo->Developer, lpdi->item.cchTextMax); break; case RB_ReleaseDate: strncpy(lpdi->item.pszText, pRomInfo->ReleaseDate, lpdi->item.cchTextMax); break; case RB_Genre: strncpy(lpdi->item.pszText, pRomInfo->Genre, lpdi->item.cchTextMax); break; case RB_Players: sprintf(lpdi->item.pszText,"%d",pRomInfo->Players); break; case RB_ForceFeedback: strncpy(lpdi->item.pszText, pRomInfo->ForceFeedback, lpdi->item.cchTextMax); break; case RB_FileFormat: switch (pRomInfo->FileFormat) { case Format_Uncompressed: strncpy(lpdi->item.pszText, "Uncompressed", lpdi->item.cchTextMax); break; case Format_Zip: strncpy(lpdi->item.pszText, "Zip", lpdi->item.cchTextMax); break; case Format_7zip: strncpy(lpdi->item.pszText, "7zip", lpdi->item.cchTextMax); break; default: sprintf(lpdi->item.pszText, "Unknown (%X)", pRomInfo->FileFormat); break; } break; default: strncpy(lpdi->item.pszText, " ", lpdi->item.cchTextMax); } if (lpdi->item.pszText == NULL || strlen(lpdi->item.pszText) == 0) { strcpy(lpdi->item.pszText, " "); } } void CRomBrowser::RomList_OpenRom(DWORD /*pnmh*/) { ROM_INFO * pRomInfo; LV_ITEM lvItem; LONG iItem; iItem = ListView_GetNextItem((HWND)m_hRomList, -1, LVNI_SELECTED); if (iItem == -1) { return; } memset(&lvItem, 0, sizeof(LV_ITEM)); lvItem.mask = LVIF_PARAM; lvItem.iItem = iItem; if (!ListView_GetItem((HWND)m_hRomList, &lvItem)) { return; } if (lvItem.lParam < 0 || lvItem.lParam >= (LPARAM)m_RomInfo.size()) { return; } pRomInfo = &m_RomInfo[lvItem.lParam]; if (!pRomInfo) { return; } m_StopRefresh = true; CN64System::RunFileImage(pRomInfo->szFullFileName); } void CRomBrowser::RomList_PopupMenu(DWORD /*pnmh*/) { LONG iItem = ListView_GetNextItem((HWND)m_hRomList, -1, LVNI_SELECTED); m_SelectedRom = ""; if (iItem != -1) { LV_ITEM lvItem; memset(&lvItem, 0, sizeof(LV_ITEM)); lvItem.mask = LVIF_PARAM; lvItem.iItem = iItem; if (!ListView_GetItem((HWND)m_hRomList, &lvItem)) { return; } if (lvItem.lParam < 0 || lvItem.lParam >= (LPARAM)m_RomInfo.size()) { return; } ROM_INFO * pRomInfo = &m_RomInfo[lvItem.lParam]; if (!pRomInfo) { return; } m_SelectedRom = pRomInfo->szFullFileName; } //Load the menu HMENU hMenu = LoadMenu(GetModuleHandle(NULL),MAKEINTRESOURCE(IDR_POPUP)); HMENU hPopupMenu = (HMENU)GetSubMenu(hMenu,0); //Fix up menu MenuSetText(hPopupMenu, 0, GS(POPUP_PLAY), NULL); MenuSetText(hPopupMenu, 2, GS(MENU_REFRESH), NULL); MenuSetText(hPopupMenu, 3, GS(MENU_CHOOSE_ROM), NULL); MenuSetText(hPopupMenu, 5, GS(POPUP_INFO), NULL); MenuSetText(hPopupMenu, 6, GS(POPUP_GFX_PLUGIN), NULL); MenuSetText(hPopupMenu, 8, GS(POPUP_SETTINGS), NULL); MenuSetText(hPopupMenu, 9, GS(POPUP_CHEATS), NULL); if (m_SelectedRom.size() == 0) { DeleteMenu(hPopupMenu,9,MF_BYPOSITION); DeleteMenu(hPopupMenu,8,MF_BYPOSITION); DeleteMenu(hPopupMenu,7,MF_BYPOSITION); DeleteMenu(hPopupMenu,6,MF_BYPOSITION); DeleteMenu(hPopupMenu,5,MF_BYPOSITION); DeleteMenu(hPopupMenu,4,MF_BYPOSITION); DeleteMenu(hPopupMenu,1,MF_BYPOSITION); DeleteMenu(hPopupMenu,0,MF_BYPOSITION); } else { bool inBasicMode = g_Settings->LoadDword(UserInterface_BasicMode) != 0; bool CheatsRemembered = g_Settings->LoadDword(Setting_RememberCheats) != 0; if (!CheatsRemembered) { DeleteMenu(hPopupMenu,9,MF_BYPOSITION); } if (inBasicMode) { DeleteMenu(hPopupMenu,8,MF_BYPOSITION); } if (inBasicMode && !CheatsRemembered) { DeleteMenu(hPopupMenu,7,MF_BYPOSITION); } DeleteMenu(hPopupMenu,6,MF_BYPOSITION); if (!inBasicMode && g_Plugins && g_Plugins->Gfx() && g_Plugins->Gfx()->GetRomBrowserMenu != NULL) { HMENU GfxMenu = (HMENU)g_Plugins->Gfx()->GetRomBrowserMenu(); if (GfxMenu) { MENUITEMINFO lpmii; InsertMenuW(hPopupMenu, 6, MF_POPUP|MF_BYPOSITION, (DWORD)GfxMenu, GS(POPUP_GFX_PLUGIN)); lpmii.cbSize = sizeof(MENUITEMINFO); lpmii.fMask = MIIM_STATE; lpmii.fState = 0; SetMenuItemInfo(hPopupMenu, (DWORD)GfxMenu, MF_BYCOMMAND,&lpmii); } } } //Get the current Mouse location POINT Mouse; GetCursorPos(&Mouse); //Show the menu TrackPopupMenu(hPopupMenu, 0, Mouse.x, Mouse.y, 0,m_MainWindow, NULL); DestroyMenu(hMenu); } void CRomBrowser::RomList_SortList(void) { SORT_FIELD SortFieldInfo; for (int count = NoOfSortKeys; count >= 0; count --) { stdstr SortFieldName = g_Settings->LoadStringIndex(RomBrowser_SortFieldIndex,count); size_t index; for (index = 0; index < m_Fields.size(); index++) { if (_stricmp(m_Fields[index].Name(),SortFieldName.c_str()) == 0) { break; } } if (index >= m_Fields.size()) { continue; } SortFieldInfo._this = this; SortFieldInfo.Key = index; SortFieldInfo.KeyAscend = g_Settings->LoadBoolIndex(RomBrowser_SortAscendingIndex,count) != 0; ListView_SortItems((HWND)m_hRomList, RomList_CompareItems, &SortFieldInfo ); } } /* * SaveRomList - save all the rom information about the current roms in the rom brower * to a cache file, so it is quick to reload the information */ void CRomBrowser::SaveRomList ( strlist & FileList ) { MD5 ListHash = RomListHash(FileList); stdstr FileName = g_Settings->LoadString(SupportFile_RomListCache); HANDLE hFile = CreateFile(FileName.c_str(),GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); DWORD dwWritten; WriteFile(hFile,ListHash.raw_digest(),16,&dwWritten,NULL); //Write the size of ROM_INFO int RomInfoSize = sizeof(ROM_INFO); WriteFile(hFile,&RomInfoSize,sizeof(RomInfoSize),&dwWritten,NULL); //Write the Number of entries int Entries = m_RomInfo.size(); WriteFile(hFile,&Entries,sizeof(Entries),&dwWritten,NULL); //Write Every Entry for (int count = 0; count < Entries; count++) { ROM_INFO * RomInfo = &m_RomInfo[count]; WriteFile(hFile,RomInfo,RomInfoSize,&dwWritten,NULL); } //Close the file handle CloseHandle(hFile); } void CRomBrowser::SaveRomListColoumnInfo(void) { WriteTrace(TraceDebug,__FUNCTION__ ": Start"); // if (!RomBrowserVisible()) { return; } if (g_Settings == NULL) { return; } LV_COLUMN lvColumn; memset(&lvColumn,0,sizeof(lvColumn)); lvColumn.mask = LVCF_WIDTH; for (size_t Coloumn = 0;ListView_GetColumn((HWND)m_hRomList,Coloumn,&lvColumn); Coloumn++) { size_t index; bool bFound = false; for (index = 0; index < m_Fields.size(); index++) { if (m_Fields[index].Pos() == Coloumn) { bFound = true; break; } } if (bFound) { if (m_Fields[index].ColWidth() != lvColumn.cx) { m_Fields[index].SetColWidth(lvColumn.cx); } } } WriteTrace(TraceDebug,__FUNCTION__ ": Done"); } int CALLBACK CRomBrowser::SelectRomDirCallBack(HWND hwnd,DWORD uMsg,DWORD /*lp*/, DWORD lpData) { switch(uMsg) { case BFFM_INITIALIZED: // WParam is TRUE since you are passing a path. // It would be FALSE if you were passing a pidl. if (lpData) { SendMessage(hwnd,BFFM_SETSELECTION,TRUE,lpData); SetWindowTextW(hwnd, GS(DIR_SELECT_ROM)); } break; } return 0; } void CRomBrowser::SelectRomDir(void) { wchar_t SelectedDir[MAX_PATH]; LPITEMIDLIST pidl; BROWSEINFOW bi; WriteTrace(TraceDebug,__FUNCTION__ " 1"); stdstr RomDir = g_Settings->LoadString(Directory_Game); bi.hwndOwner = m_MainWindow; bi.pidlRoot = NULL; bi.pszDisplayName = SelectedDir; bi.lpszTitle = GS(SELECT_ROM_DIR); bi.ulFlags = BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS; bi.lpfn = (BFFCALLBACK)SelectRomDirCallBack; bi.lParam = (DWORD)RomDir.c_str(); WriteTrace(TraceDebug,__FUNCTION__ " 2"); if ((pidl = SHBrowseForFolderW(&bi)) != NULL) { WriteTrace(TraceDebug,__FUNCTION__ " 3"); char Directory[_MAX_PATH]; if (SHGetPathFromIDList(pidl, Directory)) { int len = strlen(Directory); WriteTrace(TraceDebug,__FUNCTION__ " 4"); if (Directory[len - 1] != '\\') { strcat(Directory,"\\"); } WriteTrace(TraceDebug,__FUNCTION__ " 5"); WriteTrace(TraceDebug,__FUNCTION__ " 6"); g_Settings->SaveString(Directory_Game,Directory); WriteTrace(TraceDebug,__FUNCTION__ " 7"); g_Notify->AddRecentDir(Directory); WriteTrace(TraceDebug,__FUNCTION__ " 8"); RefreshRomBrowser(); WriteTrace(TraceDebug,__FUNCTION__ " 9"); } } } void CRomBrowser::FixRomListWindow (void) { //Change the window Style long Style = GetWindowLong(m_MainWindow,GWL_STYLE) | WS_SIZEBOX | WS_MAXIMIZEBOX; SetWindowLong(m_MainWindow,GWL_STYLE,Style); //Get the current window size RECT rect; GetWindowRect(m_MainWindow, &rect); //We find the middle position of the screen, we use this if theres no setting int X = (GetSystemMetrics(SM_CXSCREEN) - (rect.right - rect.left)) / 2; int Y = (GetSystemMetrics(SM_CYSCREEN) - (rect.bottom - rect.top)) / 2; //Load the value from settings, if none is available, default to above g_Settings->LoadDword(RomBrowser_Top, (DWORD &)Y); g_Settings->LoadDword(RomBrowser_Left,(DWORD &)X); SetWindowPos(m_MainWindow,NULL,X,Y,0,0,SWP_NOZORDER|SWP_NOSIZE); //Fix height and width int Width = g_Settings->LoadDword(RomBrowser_Width); int Height = g_Settings->LoadDword(RomBrowser_Height); if (Width < 200) { Width = 200; } if (Height < 200) { Height = 200; } RECT rcClient; rcClient.top = 0; rcClient.bottom = Height; rcClient.left = 0; rcClient.right = Width; AdjustWindowRect(&rcClient,GetWindowLong(m_MainWindow,GWL_STYLE),true); int WindowHeight = rcClient.bottom - rcClient.top; int WindowWidth = rcClient.right - rcClient.left; SetWindowPos(m_MainWindow,NULL,0,0,WindowWidth,WindowHeight,SWP_NOMOVE|SWP_NOZORDER); } void CRomBrowser::ShowRomList (void) { if (m_Visible || g_Settings->LoadBool(GameRunning_CPU_Running)) { return; } m_ShowingRomBrowser = true; WatchThreadStop(); if (m_hRomList == NULL) { CreateRomListControl(); } EnableWindow((HWND)m_hRomList,TRUE); ShowWindow((HWND)m_hRomList,SW_SHOW); FixRomListWindow(); m_AllowSelectionLastRom = true; //Make sure selected item is visible int iItem = ListView_GetNextItem((HWND)m_hRomList, -1, LVNI_SELECTED); ListView_EnsureVisible((HWND)m_hRomList,iItem,FALSE); //Mark the window as visible m_Visible = true; RECT rcWindow; if (GetClientRect(m_MainWindow,&rcWindow)) { ResizeRomList((WORD)rcWindow.right,(WORD)rcWindow.bottom); } InvalidateRect((HWND)m_hRomList,NULL,TRUE); //Start thread to watch for dir changed WatchThreadStart(); m_ShowingRomBrowser = false; } void CRomBrowser::HideRomList (void) { if (!RomBrowserVisible()) { return; } ShowWindow(m_MainWindow,SW_HIDE); SaveRomListColoumnInfo(); WatchThreadStop(); //Make sure the window does disappear Sleep(100); //Disable the rom list EnableWindow((HWND)m_hRomList,FALSE); ShowWindow((HWND)m_hRomList,SW_HIDE); if (g_Settings->LoadBool(RomBrowser_Maximized)) { ShowWindow(m_MainWindow,SW_RESTORE); } //Change the window style long Style = GetWindowLong(m_MainWindow,GWL_STYLE) & ~(WS_SIZEBOX | WS_MAXIMIZEBOX); SetWindowLong(m_MainWindow,GWL_STYLE,Style); //Move window to correct location RECT rect; GetWindowRect(m_MainWindow,&rect); int X = (GetSystemMetrics( SM_CXSCREEN ) - (rect.right - rect.left)) / 2; int Y = (GetSystemMetrics( SM_CYSCREEN ) - (rect.bottom - rect.top)) / 2; g_Settings->LoadDword(UserInterface_MainWindowTop,(DWORD &)Y); g_Settings->LoadDword(UserInterface_MainWindowLeft,(DWORD &)X); SetWindowPos(m_MainWindow,NULL,X,Y,0,0,SWP_NOZORDER|SWP_NOSIZE); //Mark the window as not visible m_Visible = false; //Make the main window visible again ShowWindow(m_MainWindow,SW_SHOW); BringWindowToTop(m_MainWindow); PostMessage(m_MainWindow, WM_MAKE_FOCUS, 0,0 ); } bool CRomBrowser::RomDirNeedsRefresh ( void ) { bool InWatchThread = (m_WatchThreadID == GetCurrentThreadId()); //Get Old MD5 of file names stdstr FileName = g_Settings->LoadString(SupportFile_RomListCache); HANDLE hFile = CreateFile(FileName.c_str(),GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); if (hFile == INVALID_HANDLE_VALUE) { //if file does not exist then refresh the data return true; } DWORD dwRead; unsigned char CurrentFileMD5[16]; ReadFile(hFile,&CurrentFileMD5,sizeof(CurrentFileMD5),&dwRead,NULL); CloseHandle(hFile); //Get Current MD5 of file names strlist FileNames; if (!GetRomFileNames(FileNames,CPath(g_Settings->LoadString(Directory_Game)),stdstr(""), InWatchThread )) { return false; } FileNames.sort(); MD5 NewMd5 = RomListHash(FileNames); if (memcmp(NewMd5.raw_digest(),CurrentFileMD5,sizeof(CurrentFileMD5)) != 0) { return true; } return false; } MD5 CRomBrowser::RomListHash ( strlist & FileList ) { stdstr NewFileNames; FileList.sort(); for (strlist::iterator iter = FileList.begin(); iter != FileList.end(); iter++) { NewFileNames += *iter; NewFileNames += ";"; } MD5 md5Hash((const unsigned char *)NewFileNames.c_str(), NewFileNames.length()); WriteTraceF(TraceDebug,__FUNCTION__ ": %s - %s",md5Hash.hex_digest(),NewFileNames.c_str()); return md5Hash; } void CRomBrowser::WatchRomDirChanged ( CRomBrowser * _this ) { try { WriteTrace(TraceDebug,__FUNCTION__ ": 1"); _this->m_WatchRomDir = g_Settings->LoadString(Directory_Game); WriteTrace(TraceDebug,__FUNCTION__ ": 2"); if (_this->RomDirNeedsRefresh()) { WriteTrace(TraceDebug,__FUNCTION__ ": 2a"); PostMessage((HWND)_this->m_MainWindow,WM_COMMAND,ID_FILE_REFRESHROMLIST,0); } WriteTrace(TraceDebug,__FUNCTION__ ": 3"); HANDLE hChange[] = { _this->m_WatchStopEvent, FindFirstChangeNotification(_this->m_WatchRomDir.c_str(),g_Settings->LoadDword(RomBrowser_Recursive),FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE), }; WriteTrace(TraceDebug,__FUNCTION__ ": 4"); for (;;) { WriteTrace(TraceDebug,__FUNCTION__ ": 5"); if (WaitForMultipleObjects(sizeof(hChange) / sizeof(hChange[0]),hChange,false,INFINITE) == WAIT_OBJECT_0) { WriteTrace(TraceDebug,__FUNCTION__ ": 5a"); FindCloseChangeNotification(hChange[1]); return; } WriteTrace(TraceDebug,__FUNCTION__ ": 5b"); if (_this->RomDirNeedsRefresh()) { PostMessage((HWND)_this->m_MainWindow,WM_COMMAND,ID_FILE_REFRESHROMLIST,0); } WriteTrace(TraceDebug,__FUNCTION__ ": 5c"); if (!FindNextChangeNotification(hChange[1])) { FindCloseChangeNotification(hChange[1]); return; } WriteTrace(TraceDebug,__FUNCTION__ ": 5d"); } } catch (...) { WriteTraceF(TraceError,__FUNCTION__ ": Unhandled Exception"); } } void CRomBrowser::WatchThreadStart (void) { WriteTrace(TraceDebug,__FUNCTION__ ": 1"); WatchThreadStop(); WriteTrace(TraceDebug,__FUNCTION__ ": 2"); m_WatchStopEvent = CreateEvent(NULL,true,false,NULL); WriteTrace(TraceDebug,__FUNCTION__ ": 3"); m_WatchThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WatchRomDirChanged,this,0,&m_WatchThreadID); WriteTrace(TraceDebug,__FUNCTION__ ": 4"); } void CRomBrowser::WatchThreadStop( void ) { if (m_WatchThread == NULL) { return; } WriteTrace(TraceDebug,__FUNCTION__ ": 1"); SetEvent(m_WatchStopEvent); DWORD ExitCode = 0; for (int count = 0; count < 20; count ++ ) { WriteTrace(TraceDebug,__FUNCTION__ ": 2"); GetExitCodeThread(m_WatchThread,&ExitCode); if (ExitCode != STILL_ACTIVE) { break; } Sleep(200); } WriteTrace(TraceDebug,__FUNCTION__ ": 3"); if (ExitCode == STILL_ACTIVE) { WriteTrace(TraceDebug,__FUNCTION__ ": 3a"); TerminateThread(m_WatchThread,0); } WriteTrace(TraceDebug,__FUNCTION__ ": 4"); CloseHandle(m_WatchThread); CloseHandle(m_WatchStopEvent); m_WatchStopEvent = NULL; m_WatchThread = NULL; m_WatchThreadID = 0; WriteTrace(TraceDebug,__FUNCTION__ ": 5"); }