Procedure.a Test_LockMutex(Mutex, TimeOut_ms.u) ; Попытка захватить Mutex за определенный промежуток времени. Protected x.a, i TimeOut_ms = TimeOut_ms/16 x = #False For i=0 To TimeOut_ms If TryLockMutex(Mutex) x=#True Break EndIf Delay(16) Next i ProcedureReturn x EndProcedure Procedure Load_WinPref() Protected x, i x = OpenPreferences(G_ProgramMiscInfo\Dir_SysFiles+"MainWin.dat") PreferenceGroup("") G_ProgramMiscInfo\Setting\TorrentDirPath = ReadPreferenceString("TorrentDirPath", G_ProgramMiscInfo\ProgFilePath) G_ProgramMiscInfo\Setting\TorrentFilePath = ReadPreferenceString("TorrentFilePath", G_ProgramMiscInfo\ProgFilePath+#DirTorrentFiles) G_ProgramMiscInfo\Setting\TorrentSavePath = ReadPreferenceString("TorrentSavePath", G_ProgramMiscInfo\ProgFilePath+#DirTorrentFiles) If G_ProgramMiscInfo\Setting\TorrentDirPath<>"" And Right(G_ProgramMiscInfo\Setting\TorrentDirPath, 1)<>"\" : G_ProgramMiscInfo\Setting\TorrentDirPath+"\" : EndIf If G_ProgramMiscInfo\Setting\TorrentFilePath<>"" And Right(G_ProgramMiscInfo\Setting\TorrentFilePath, 1)<>"\" : G_ProgramMiscInfo\Setting\TorrentFilePath+"\" : EndIf If G_ProgramMiscInfo\Setting\TorrentSavePath<>"" And Right(G_ProgramMiscInfo\Setting\TorrentSavePath, 1)<>"\" : G_ProgramMiscInfo\Setting\TorrentSavePath+"\" : EndIf If FileSize(G_ProgramMiscInfo\ProgFilePath+G_ProgramMiscInfo\Setting\TorrentDirPath)= -2 G_ProgramMiscInfo\Setting\TorrentDirPath = G_ProgramMiscInfo\ProgFilePath + G_ProgramMiscInfo\Setting\TorrentDirPath EndIf If FileSize(G_ProgramMiscInfo\ProgFilePath+G_ProgramMiscInfo\Setting\TorrentFilePath)= -2 G_ProgramMiscInfo\Setting\TorrentFilePath = G_ProgramMiscInfo\ProgFilePath + G_ProgramMiscInfo\Setting\TorrentFilePath EndIf If FileSize(G_ProgramMiscInfo\ProgFilePath+G_ProgramMiscInfo\Setting\TorrentSavePath)= -2 G_ProgramMiscInfo\Setting\TorrentSavePath = G_ProgramMiscInfo\ProgFilePath + G_ProgramMiscInfo\Setting\TorrentSavePath EndIf PreferenceGroup("MainWin") G_ProgramMiscInfo\Setting\MainWinState = ReadPreferenceLong("State", 0) G_ProgramMiscInfo\Setting\MainWinVisible = ReadPreferenceLong("MainWinVisible", #True) G_ProgramMiscInfo\Setting\MainWinX = ReadPreferenceLong("WinX", 100) G_ProgramMiscInfo\Setting\MainWinY = ReadPreferenceLong("WinY", 100) G_ProgramMiscInfo\Setting\MainWinW = ReadPreferenceLong("WinW", 700) G_ProgramMiscInfo\Setting\MainWinH = ReadPreferenceLong("WinH", 400) G_ProgramMiscInfo\Setting\SplitterPos = ReadPreferenceLong("SplitterPos", 120) G_ProgramMiscInfo\Setting\TabPos = ReadPreferenceLong("TabPos", 0) & 7 G_ProgramMiscInfo\Setting\Speed_CoboBoxState = 0;ReadPreferenceLong("Speed_CoboBox", 0) & 3 G_ProgramMiscInfo\Setting\ShowDomainsName = ReadPreferenceLong("DomainsName", 1) & 1 PreferenceGroup("TorrentList") For i=1 To 14 G_ProgramMiscInfo\Setting\TorrentListIcon_Width[i-1] = ReadPreferenceLong("Column"+Str(i), 0) Next i For i=1 To 14 G_ProgramMiscInfo\Setting\TorrentListIcon_ORDERARRAY[i-1] = ReadPreferenceLong("Orderrary"+Str(i), i-1) Next i PreferenceGroup("TrackerList") For i=1 To 5 G_ProgramMiscInfo\Setting\ListIcon_Tracker_Width[i-1] = ReadPreferenceLong("Column"+Str(i), 0) Next i For i=1 To 5 G_ProgramMiscInfo\Setting\ListIcon_Tracker_ORDERARRAY[i-1] = ReadPreferenceLong("Orderrary"+Str(i), i-1) Next i PreferenceGroup("PeerList") For i=1 To 11 G_ProgramMiscInfo\Setting\ListIcon_Peer_Width[i-1] = ReadPreferenceLong("Column"+Str(i), 0) Next i For i=1 To 11 G_ProgramMiscInfo\Setting\ListIcon_Peer_ORDERARRAY[i-1] = ReadPreferenceLong("Orderrary"+Str(i), i-1) Next i PreferenceGroup("FilesList") For i=1 To 8 G_ProgramMiscInfo\Setting\ListIcon_Files_Width[i-1] = ReadPreferenceLong("Column"+Str(i), 0) Next i For i=1 To 8 G_ProgramMiscInfo\Setting\ListIcon_Files_ORDERARRAY[i-1] = ReadPreferenceLong("Orderrary"+Str(i), i-1) Next i PreferenceGroup("PieceList") For i=1 To 6;7 G_ProgramMiscInfo\Setting\ListIcon_Piece_Width[i-1] = ReadPreferenceLong("Column"+Str(i), 0) Next i For i=1 To 6;7 G_ProgramMiscInfo\Setting\ListIcon_Piece_ORDERARRAY[i-1] = ReadPreferenceLong("Orderrary"+Str(i), i-1) Next i If x ClosePreferences() EndIf EndProcedure Procedure Load_Setting() ; Настройки программы. Protected x, i x = OpenPreferences(G_ProgramMiscInfo\Dir_SysFiles+"Setting.dat") PreferenceGroup("") G_ProgramSetting\TreePos = ReadPreferenceLong("Pos", 0) PreferenceGroup("Misc") G_ProgramSetting\Misc\MinimazeTray = ReadPreferenceLong("MinimazeTray", 1)&1 G_ProgramSetting\Misc\CloseTray = ReadPreferenceLong("CloseTray", 0)&1 G_ProgramSetting\Misc\BalloonTray = ReadPreferenceLong("BalloonTray", 1)&1 G_ProgramSetting\Misc\HideShowTray = ReadPreferenceLong("HideShowTray", 1)&1 PreferenceGroup("Lan") G_ProgramSetting\Lan\Port = ReadPreferenceLong("Port", 0) G_ProgramSetting\Lan\RandomPort = ReadPreferenceLong("RandomPort", 0)&1 G_ProgramSetting\Lan\MaxConnect = ReadPreferenceLong("MaxConnect", 100) G_ProgramSetting\Lan\MaxPeer = ReadPreferenceLong("MaxPeer", 20) G_ProgramSetting\Lan\SlotTorrent = ReadPreferenceLong("SlotTorrent", 4) If G_ProgramSetting\Lan\Port=0 Or G_ProgramSetting\Lan\RandomPort = 1 i=0 Repeat G_ProgramSetting\Lan\Port = Random(20000)+40000 If CreateNetworkServer(0, G_ProgramSetting\Lan\Port) CloseNetworkServer(0) Break EndIf i+1 Until i>=8 EndIf PreferenceGroup("Torrent") G_ProgramSetting\Torrent\MaxActiveTorrent = ReadPreferenceLong("MaxActiveTorrent", 100) G_ProgramSetting\Torrent\MaxLoad = ReadPreferenceLong("MaxLoad", 4) G_ProgramSetting\Torrent\Serial_LoadPiece = ReadPreferenceLong("SerialLoadPiece", 0)&1 If x ClosePreferences() EndIf EndProcedure Procedure LoadTorrentData() ; Загрузка описания файлов торрента из файла TorrentInfo.dat. Protected FileID, i, x, TempS.s Protected Size.q, RealReadBytes.l, MemPos.l, *FileData Protected CountTorrent.l, CountTorrent_Bytes.l, StartPosTorrent.l, TempL.l Protected TempW.w x = 0 MemPos = 0 For i=1 To 2 If i=1 TempS = "TorrentInfo.dat" Else TempS = "TorrentInfo.datbk" EndIf FileID = ReadFile(#PB_Any, G_ProgramMiscInfo\Dir_SysFiles+TempS) If FileID Size = Lof(FileID) If Size>0 And Size<10000000 *FileData = AllocateMemory(Size+10000) If *FileData RealReadBytes = ReadData(FileID, *FileData, Size) If RealReadBytes>0 RealReadBytes-4 If CRC32Fingerprint(*FileData, RealReadBytes) = PeekL(*FileData+RealReadBytes) x = 1 CloseFile(FileID) Break EndIf EndIf FreeMemory(*FileData) *FileData = 0 EndIf EndIf CloseFile(FileID) EndIf Next i If x = 1 And *FileData MemPos + 32 ; Зарезирвировано. LockMutex(G_TorrentList\Mutex) ; Блокируем обращения к списку торрентов. LockMutex(G_TorrentList\Mutex_Table) ClearList(G_TorrentList\TorrentList()) ; Очистка списка, хранящего полную информация о торрентах. ClearList(G_TorrentList\Table()) G_TorrentList\Info\Speed\All_InBytes=PeekQ(*FileData+MemPos) : MemPos + 8 ; Сколько скачано байт за все время работы клиента. G_TorrentList\Info\Speed\All_OutBytes=PeekQ(*FileData+MemPos) : MemPos + 8 ; Сколько отданно байт за все время работы клиента. CountTorrent = PeekL(*FileData+MemPos) : MemPos + 4 ; Число торрентов. If CountTorrent<10000 For i=1 To CountTorrent CountTorrent_Bytes = PeekL(*FileData+MemPos) ; Число байт, занимаемых данными торрента в этом файле. If CountTorrent_Bytes>0 And CountTorrent_Bytes+MemPos <= RealReadBytes MemPos + 4 StartPosTorrent = MemPos If CRC32Fingerprint(*FileData+MemPos+4, CountTorrent_Bytes-8) = PeekL(*FileData+MemPos) ; Правильная контрольная сумма. MemPos + 4 TempL = PeekL(*FileData+MemPos) ; Количество байт, хранящих имя торрент-файла (UTF-8). If TempL>0 And TempL+(MemPos-StartPosTorrent) < CountTorrent_Bytes MemPos + 4 TempS = PeekS(*FileData+MemPos, TempL, #PB_UTF8) MemPos + TempL If TempS<>"" If FileSize(G_ProgramMiscInfo\Dir_SysFiles+TempS) > 0 ; В системной папке есть торрент файл. If AddElement(G_TorrentList\TorrentList()) G_TorrentList\TorrentList()\Torrent\SysFileName = TempS ; Имя торрент файла, находящегося в системной папке торрента. TempL = PeekL(*FileData+MemPos) ; Количество байт, хранящих INFO Hash. If TempL>0 And TempL+(MemPos-StartPosTorrent) < CountTorrent_Bytes MemPos + 4 TempS = PeekS(*FileData+MemPos, TempL, #PB_Ascii) MemPos + TempL If TempS<>"" G_TorrentList\TorrentList()\TorrentFile\INFO_Hash = TempS EndIf Else MemPos = StartPosTorrent+CountTorrent_Bytes : DeleteElement(G_TorrentList\TorrentList()) : Continue EndIf TempL = PeekL(*FileData+MemPos) ; Имя торрента, отображаемое в таблице. If TempL>0 And TempL+(MemPos-StartPosTorrent) < CountTorrent_Bytes MemPos + 4 TempS = PeekS(*FileData+MemPos, TempL, #PB_UTF8) MemPos + TempL If TempS<>"" G_TorrentList\TorrentList()\TorrentName = TempS EndIf Else MemPos = StartPosTorrent+CountTorrent_Bytes : DeleteElement(G_TorrentList\TorrentList()) : Continue EndIf TempL = PeekL(*FileData+MemPos) ; Метка торрента. If TempL>=0 And TempL+(MemPos-StartPosTorrent) < CountTorrent_Bytes MemPos + 4 If TempL>0 TempS = PeekS(*FileData+MemPos, TempL, #PB_UTF8) Else TempS = "" EndIf MemPos + TempL G_TorrentList\TorrentList()\Label = TempS Else MemPos = StartPosTorrent+CountTorrent_Bytes : DeleteElement(G_TorrentList\TorrentList()) : Continue EndIf TempL = PeekL(*FileData+MemPos) ; Путь к файлам с торрентом. Если в торренте папка, то включено также содержимое "CurrentDir_Name", т. е. полный абсолютный путь к папке. If TempL>0 And TempL+(MemPos-StartPosTorrent) < CountTorrent_Bytes MemPos + 4 TempS = PeekS(*FileData+MemPos, TempL, #PB_UTF8) MemPos + TempL If TempS<>"" If Len(TempS)>10 And Left(TempS, 10)="?Portable\" ; Выявляем этом портабле путь или нет. TempS=Right(TempS, Len(TempS)-10) TempS=G_ProgramMiscInfo\ProgFilePath+TempS EndIf G_TorrentList\TorrentList()\Torrent\Path = TempS EndIf Else MemPos = StartPosTorrent+CountTorrent_Bytes : DeleteElement(G_TorrentList\TorrentList()) : Continue EndIf ; Количество загруженных байт. ; Количество отправленных байт. ; Лимит приёма. ; Лимит отдачи. ; Лишние данные. ; Сколько времени (в секундах) осталось до конца загрузки. TempL = PeekL(*FileData+MemPos) If TempL <> OffsetOf( Sub_TorrentInfo_TorrentList_Network_IO\InSpeed) Or TempL+(MemPos-StartPosTorrent) > CountTorrent_Bytes ;Or TempL<=0 MemPos = StartPosTorrent+CountTorrent_Bytes : DeleteElement(G_TorrentList\TorrentList()) : Continue EndIf MemPos + 4 CopyMemory(*FileData+MemPos, @G_TorrentList\TorrentList()\Network_IO, TempL) : MemPos + TempL ; В массиве каждый бит обозначает присутсвие или отсутствие части (куска) на диске. 0 - части нет; 1 - часть есть. TempL = PeekL(*FileData+MemPos) If TempL+(MemPos-StartPosTorrent) > CountTorrent_Bytes Or TempL < -1 MemPos = StartPosTorrent+CountTorrent_Bytes : DeleteElement(G_TorrentList\TorrentList()) : Continue EndIf MemPos + 4 If TempL>=0 ReDim G_TorrentList\TorrentList()\Torrent\MapFile\MapPiece(TempL) ;If TempL>0 CopyMemory(*FileData+MemPos, @G_TorrentList\TorrentList()\Torrent\MapFile\MapPiece(), TempL+1) : MemPos + TempL+1 ;EndIf Else ReDim G_TorrentList\TorrentList()\Torrent\MapFile\MapPiece(0) EndIf ; Число частей. G_TorrentList\TorrentList()\Torrent\CountPiece = PeekL(*FileData+MemPos) : MemPos + 4 If MemPos-StartPosTorrent > CountTorrent_Bytes MemPos = StartPosTorrent+CountTorrent_Bytes : DeleteElement(G_TorrentList\TorrentList()) : Continue EndIf ; Текущий размер всех файлов торрента (сколько есть на диске). G_TorrentList\TorrentList()\Torrent\CurrentFileSize = PeekQ(*FileData+MemPos) : MemPos + 8 If MemPos-StartPosTorrent > CountTorrent_Bytes MemPos = StartPosTorrent+CountTorrent_Bytes : DeleteElement(G_TorrentList\TorrentList()) : Continue EndIf ; Состояние торрента. G_TorrentList\TorrentList()\TorrentStatus = PeekB(*FileData+MemPos) : MemPos + 1 If MemPos-StartPosTorrent > CountTorrent_Bytes MemPos = StartPosTorrent+CountTorrent_Bytes : DeleteElement(G_TorrentList\TorrentList()) : Continue EndIf ; Дата добавления торрента. G_TorrentList\TorrentList()\AddDate = PeekL(*FileData+MemPos) : MemPos + 4 If MemPos-StartPosTorrent > CountTorrent_Bytes MemPos = StartPosTorrent+CountTorrent_Bytes : DeleteElement(G_TorrentList\TorrentList()) : Continue EndIf ; Время активности торреена (в секундах). G_TorrentList\TorrentList()\ActiveTimeSec = PeekL(*FileData+MemPos) : MemPos + 4 If MemPos-StartPosTorrent > CountTorrent_Bytes MemPos = StartPosTorrent+CountTorrent_Bytes : DeleteElement(G_TorrentList\TorrentList()) : Continue EndIf TempW = PeekW(*FileData+MemPos) : MemPos + 2 If MemPos-StartPosTorrent > CountTorrent_Bytes MemPos = StartPosTorrent+CountTorrent_Bytes : DeleteElement(G_TorrentList\TorrentList()) : Continue EndIf If TempW>=0 If AddElement(G_TorrentList\Table()) G_TorrentList\Table()\INFO_Hash = G_TorrentList\TorrentList()\TorrentFile\INFO_Hash G_TorrentList\Table()\Percent = TempW EndIf EndIf ; Размер торрента G_TorrentList\TorrentList()\Torrent\Torrent_FileSize = PeekQ(*FileData+MemPos) : MemPos + 8 If MemPos-StartPosTorrent > CountTorrent_Bytes MemPos = StartPosTorrent+CountTorrent_Bytes : DeleteElement(G_TorrentList\TorrentList()) : Continue EndIf G_TorrentList\TorrentList()\TorrentFile\All_Size = PeekQ(*FileData+MemPos) : MemPos + 8 ;MemPos + 32 ; Зарезирвировано. If MemPos-StartPosTorrent > CountTorrent_Bytes MemPos = StartPosTorrent+CountTorrent_Bytes : DeleteElement(G_TorrentList\TorrentList()) : Continue EndIf EndIf Else ; На диске нет торрент-файла. MemPos + CountTorrent_Bytes EndIf EndIf EndIf Else ; Ошибка в контрольной сумме. MemPos + CountTorrent_Bytes EndIf EndIf Next i EndIf UnlockMutex(G_TorrentList\Mutex_Table) UnlockMutex(G_TorrentList\Mutex) FreeMemory(*FileData) EndIf EndProcedure CompilerIf #PB_Compiler_Version>=510 Procedure UnPak(*pak, PakLen, *PacSize.Integer) Protected *Unpak_mem, RealSize *Unpak_mem = 0 *PacSize\i = 0 RealSize = PeekL(*pak) *pak+4 : PakLen-4 If RealSize>0 And RealSize<1000000 *mem = AllocateMemory(RealSize) If *mem CompilerIf #PB_Compiler_Version>=520 If UncompressMemory(*pak, PakLen, *mem, RealSize, #PB_PackerPlugin_BriefLZ) = RealSize CompilerElse If UncompressMemory(*pak, PakLen, *mem, RealSize, #PB_Packer_BriefLZ) = RealSize CompilerEndIf *Unpak_mem = *mem *PacSize\i = RealSize Else FreeMemory(*mem) EndIf EndIf EndIf ProcedureReturn *Unpak_mem EndProcedure CompilerElse Procedure UnPak(*pak, *PacSize.Integer) Protected *Unpak_mem, RealSize *Unpak_mem = 0 *PacSize\i = 0 CompilerIf #PB_Compiler_Processor=#PB_Processor_x86 RealSize = PeekL(*pak+2) CompilerElse RealSize = PeekL(*pak+4) CompilerEndIf If RealSize>0 And RealSize<1000000 *mem = AllocateMemory(RealSize) If *mem If UnpackMemory(*pak, *mem) = RealSize *Unpak_mem = *mem *PacSize\i = RealSize Else FreeMemory(*mem) EndIf EndIf EndIf ProcedureReturn *Unpak_mem EndProcedure CompilerEndIf Procedure Start_Server(Pref.a) Protected String.s, Port.u, Temp, Test.a Port=G_ProgramSetting\Lan\Port Test=#False Repeat If CreateNetworkServer(#TorrentServer, Port) Test=#True G_ProgramSetting\Lan\Port = Port Break Else Test=#False Repeat String = InputRequester(#MessageName, "К сожалению порт "+Str(G_ProgramSetting\Lan\Port)+" занят. Выберите другой.",Str(Random(30000)+30000)) Temp = Val(String) If String="" ;And Pref=0 Break 2 ;End ElseIf TestNumber(String)=#False Or Temp<1000 Or Temp>65535 MessageRequester(#MessageName, "Допустимый диапазон от 1000 до 65535!", #MB_OK|#MB_ICONWARNING) Else Port = Temp Break EndIf ForEver EndIf ForEver If Test=#False; Не удалось создать сервер. G_TorrentList\Info\PortIconState = #PortIconState_ErrCreateServer EndIf EndProcedure Procedure Init_Program() Protected *Point, Temp, i Protected Temp_1.l, Temp_2 Protected uxtheme_Module, ws2_32_Module Protected WSA.WSADATA G_ProgramMiscInfo\CurrentDate = Date() ws2_32_Module=OpenLibrary(#PB_Any, "ws2_32.dll") If ws2_32_Module=0 MessageRequester(#MessageName+" - инициализация программы", "Ошибка загрузки библиотеки 'ws2_32.dll'.", #MB_OK|#MB_ICONERROR) End EndIf G_ProgramMiscInfo\Network\WSA\LibID = ws2_32_Module G_ProgramMiscInfo\Network\WSA\WSACreateEvent = GetFunction(ws2_32_Module, "WSACreateEvent") G_ProgramMiscInfo\Network\WSA\WSACloseEvent = GetFunction(ws2_32_Module, "WSACloseEvent") G_ProgramMiscInfo\Network\WSA\WSAEventSelect = GetFunction(ws2_32_Module, "WSAEventSelect") G_ProgramMiscInfo\Network\WSA\WSAWaitForMultipleEvents = GetFunction(ws2_32_Module, "WSAWaitForMultipleEvents") G_ProgramMiscInfo\Network\WSA\WSAEnumNetworkEvents = GetFunction(ws2_32_Module, "WSAEnumNetworkEvents") Temp=0 CallFunction(ws2_32_Module, "WSAStartup", $202, @WSA) Temp=0 ;G_ProgramMiscInfo\DirIconID = ExtractIcon_(0, "shell32.dll", 3) ; Иконка папки. G_ProgramMiscInfo\LoadTorrent\Mutex = CreateMutex() ; Для процедуры Open_LoadTorrent_Win, обрабатыващей торрент-файлы. G_ProgramMiscInfo\Panel_Info_Mutex = CreateMutex() ; Вывод данных на панель информации. G_ProgramMiscInfo\SaveTorrentData_Mutex = CreateMutex() ; Запись в файл с описанием торрентов. G_ProgramMiscInfo\Panel_Info_Semaphore = CreateSemaphore(2) G_ProgramMiscInfo\FontDefault =GetStockObject_(#DEFAULT_GUI_FONT) G_ProgramMiscInfo\Network\TrackerTask_Mutex = CreateMutex() G_ProgramMiscInfo\Network\TrackerTask_Semaphore = CreateSemaphore() G_ProgramMiscInfo\Network\DomainsPeer_Mutex = CreateMutex() G_ProgramMiscInfo\Network\DomainsPeer_Semaphore = CreateSemaphore() G_ProgramMiscInfo\Network\ConnectPeer_Mutex = CreateMutex() G_ProgramMiscInfo\Network\ConnectPeer_Semaphore = CreateSemaphore() G_ProgramMiscInfo\ProgEndSate = 0 G_ProgramMiscInfo\Network\TrackerTask_EndThread = 0 G_TorrentList\Mutex = CreateMutex() ; Для управления доступом к структуре G_TorrentList. G_TorrentList\Mutex_Table = CreateMutex() ; Контроль доступа к списку "Table". G_ProgramMiscInfo\TorrentListIcon_Mutex = CreateMutex() ; Доступ к таблице. Создание пунктов, модификация, стирание. G_ProgramMiscInfo\ListIcon_Files_Mutex = CreateMutex() ; Для доступа к таблице на вкладце "Файлы". Ипользуется чтобы не возникло конфликтов при совместном доступе к массиву из потока и CallBack процедуры таблицы. G_ProgramMiscInfo\ListIcon_Piece_Mutex = CreateMutex() ; Для доступа к таблице на вкладце "Части". Ипользуется чтобы не возникло конфликтов при совместном доступе к массиву из потока и CallBack процедуры таблицы. G_ProgramMiscInfo\TrayInfo\Balloon_Mutex = CreateMutex() ; Для разграничевания доступа к BalloonList() из нескольких потоков. G_ProgramMiscInfo\TrayInfo\Balloon_Visible = #False G_ProgramMiscInfo\List_Torrent_Pos = -1 ; Ни один торрент не выбран в списке. G_ProgramMiscInfo\OS_Version = OSVersion() G_ProgramMiscInfo\Draw\DrawThemeParentBackground=0 If G_ProgramMiscInfo\OS_Version>#PB_OS_Windows_2000 uxtheme_Module = OpenLibrary(#PB_Any,"uxtheme.dll") If uxtheme_Module G_ProgramMiscInfo\Draw\DrawThemeParentBackground = GetFunction(uxtheme_Module, "DrawThemeParentBackground") EndIf EndIf If G_ProgramMiscInfo\LoadTorrent\Mutex=0 Or G_ProgramMiscInfo\Panel_Info_Mutex=0 Or G_ProgramMiscInfo\SaveTorrentData_Mutex=0 Or G_ProgramMiscInfo\Panel_Info_Semaphore=0 Or G_ProgramMiscInfo\Network\TrackerTask_Mutex=0 Or G_ProgramMiscInfo\Network\TrackerTask_Semaphore=0 Or G_TorrentList\Mutex=0 Or G_TorrentList\Mutex_Table=0 Or G_ProgramMiscInfo\TorrentListIcon_Mutex=0 Or G_ProgramMiscInfo\ListIcon_Files_Mutex=0 Or G_ProgramMiscInfo\ListIcon_Piece_Mutex=0 Or G_ProgramMiscInfo\TrayInfo\Balloon_Mutex=0 Or G_ProgramMiscInfo\Network\ConnectPeer_Mutex=0 Or G_ProgramMiscInfo\Network\ConnectPeer_Semaphore=0 MessageRequester(#MessageName+" - инициализация программы", "Ошибка создания мьютекса или семафора.", #MB_OK|#MB_ICONERROR) End EndIf G_ProgramMiscInfo\Draw\HOLLOW_BRUSH=GetStockObject_(#HOLLOW_BRUSH) G_ProgramMiscInfo\Draw\Gray_BRUSH = CreateSolidBrush_($E0E0E0) G_ProgramMiscInfo\Draw\Brush_ProgressBar_TableTorrent = CreateSolidBrush_($48864D) G_ProgramMiscInfo\Draw\Brush_MapPiece = G_ProgramMiscInfo\Draw\Brush_ProgressBar_TableTorrent G_ProgramMiscInfo\Draw\Pen_MapPiece = CreatePen_(#PS_SOLID,1,$48864D) G_ProgramMiscInfo\Draw\Brush_Full_Piece = G_ProgramMiscInfo\Draw\Brush_ProgressBar_TableTorrent G_ProgramMiscInfo\Draw\Brush_Piece = CreateSolidBrush_(RGB(205, 238, 217)) FillMemory(@G_ProgramMiscInfo\Torrent_ImageList, SizeOf(G_ProgramMiscInfo\Torrent_ImageList), -1, #PB_Long) FillMemory(@G_ProgramMiscInfo\Torrent_Flags_ImageList, SizeOf(G_ProgramMiscInfo\Torrent_Flags_ImageList), -1, #PB_Long) Temp = 0 : Temp_2 = 0 CompilerIf #PB_Compiler_Version>=510 *Point = UnPak(?IconPac, ?IconPac_End-?IconPac, @Temp) CompilerElse *Point = UnPak(?IconPac, @Temp) CompilerEndIf If *Point<>0 And Temp>0 For i=#MainWin_ToolBar_Icon_AddTorrent To #MainWin_Panel_Info_Icon_Log_Warning ;Speed Temp_1=PeekL(*Point+Temp_2) ; Сколько байт занимает файл. If Temp_1<=0 Or Temp_1+Temp_2>Temp Or CatchImage(i, *Point+Temp_2+4, Temp_1) = 0 MessageRequester(#MessageName+" - инициализация программы", "Ошибка при распаковке ресурсов программы!", #MB_OK|#MB_ICONERROR) Break EndIf Temp_2+Temp_1+4 Next i FreeMemory(*Point) Else MessageRequester(#MessageName+" - инициализация программы", "Ошибка при распаковке ресурсов программы!", #MB_OK|#MB_ICONERROR) EndIf G_ProgramMiscInfo\DirIconID=ImageID(#MainWin_IconDir) LoadFont(#MainWin_Panel_Info_Font_Scroll,"MS Sans Serif",10, #PB_Font_Bold) LoadFont(#MainWin_Panel_Info_Font_Scroll_Text,"Tahoma",8) G_ProgramMiscInfo\Font_SpeedGraph = FontID(#MainWin_Panel_Info_Font_Scroll_Text) ;LoadFont(#MainWin_Panel_Info_Font_SpeedGraph,"Tahoma",8) CreateImage(#MainWin_Panel_Info_Image_Temp, 100, 24) ; Временный (буферный) рисунок, для отображения данных "Доступно" и "Загружено". CreateImage(#MainWin_Panel_Info_Image_Accessibly_1, 100, 24) ; Рисунок "Доступно" на вкладке "Общая информация" панели информации о торрентах. CreateImage(#MainWin_Panel_Info_Image_Accessibly_2, 100, 24) CreateImage(#MainWin_Panel_Info_Image_Load_1, 100, 24) ; Рисунок "Загружено" на вкладке "Общая информация" панели информации о торрентах. CreateImage(#MainWin_Panel_Info_Image_Load_2, 100, 24) If FileSize(G_ProgramMiscInfo\ProgFilePath+#DirProgFiles)<> - 2 If CreateDirectory(G_ProgramMiscInfo\ProgFilePath+#DirProgFiles) If CreateDirectory(G_ProgramMiscInfo\ProgFilePath+#DirSysFiles) SetFileAttributes(G_ProgramMiscInfo\ProgFilePath+#DirSysFiles, #PB_FileSystem_Hidden) Else MessageRequester(#MessageName+" - инициализация программы", "Не удалось создать системную папку"+Chr(10)+G_ProgramMiscInfo\ProgFilePath+#DirSysFiles, #MB_OK|#MB_ICONWARNING) EndIf CreateDirectory(G_ProgramMiscInfo\ProgFilePath+#DirTorrentFiles) Else MessageRequester(#MessageName+" - инициализация программы", "Не удалось создать системную папку"+Chr(10)+G_ProgramMiscInfo\ProgFilePath+#DirProgFiles, #MB_OK|#MB_ICONWARNING) EndIf Else If FileSize(G_ProgramMiscInfo\ProgFilePath+#DirSysFiles)<> -2 If CreateDirectory(G_ProgramMiscInfo\ProgFilePath+#DirSysFiles) SetFileAttributes(G_ProgramMiscInfo\ProgFilePath+#DirSysFiles, #PB_FileSystem_Hidden) Else MessageRequester(#MessageName+" - инициализация программы", "Не удалось создать системную папку"+Chr(10)+G_ProgramMiscInfo\ProgFilePath+#DirSysFiles, #MB_OK|#MB_ICONWARNING) EndIf EndIf If FileSize(G_ProgramMiscInfo\ProgFilePath+#DirTorrentFiles)<>-2 CreateDirectory(G_ProgramMiscInfo\ProgFilePath+#DirTorrentFiles) EndIf EndIf ; Идентификатор клиента в сети. G_ProgramMiscInfo\Network\peer_id=#PeerID ;#ProgName For i=Len(#PeerID)+1 To 20 ;#ProgName Repeat Temp = Random(74)+48 If (Temp>='0' And Temp<='9') Or (Temp>='A' And Temp<='Z') Or (Temp>='a' And Temp<='z') Break EndIf ForEver G_ProgramMiscInfo\Network\peer_id+Chr(Temp) Next i For i=0 To 19 G_ProgramMiscInfo\Network\peer_id_bin[i] = Asc(Mid(G_ProgramMiscInfo\Network\peer_id, i+1, 1)) Next i G_ProgramMiscInfo\Network\Key = Random($7FFFFFFF) G_ProgramMiscInfo\Network\Key_Hex = RSet(Hex(G_ProgramMiscInfo\Network\Key, #PB_Long), 8, "0") Load_WinPref() Load_Setting() LoadTorrentData() ; Загрузка описания файлов торрента из файла TorrentInfo.dat. Start_Server(0) EndProcedure Procedure Save_WinPref() Protected Win.WINDOWPLACEMENT If CreatePreferences(G_ProgramMiscInfo\Dir_SysFiles+"MainWin.dat") PreferenceGroup("") If FindString(G_ProgramMiscInfo\Setting\TorrentDirPath, G_ProgramMiscInfo\ProgFilePath, 1)=1 G_ProgramMiscInfo\Setting\TorrentDirPath = Mid(G_ProgramMiscInfo\Setting\TorrentDirPath, Len(G_ProgramMiscInfo\ProgFilePath)+1) EndIf If FindString(G_ProgramMiscInfo\Setting\TorrentFilePath, G_ProgramMiscInfo\ProgFilePath, 1)=1 G_ProgramMiscInfo\Setting\TorrentFilePath = Mid(G_ProgramMiscInfo\Setting\TorrentFilePath, Len(G_ProgramMiscInfo\ProgFilePath)+1) EndIf If FindString(G_ProgramMiscInfo\Setting\TorrentSavePath, G_ProgramMiscInfo\ProgFilePath, 1)=1 G_ProgramMiscInfo\Setting\TorrentSavePath = Mid(G_ProgramMiscInfo\Setting\TorrentSavePath, Len(G_ProgramMiscInfo\ProgFilePath)+1) EndIf WritePreferenceString("TorrentDirPath", G_ProgramMiscInfo\Setting\TorrentDirPath) WritePreferenceString("TorrentFilePath", G_ProgramMiscInfo\Setting\TorrentFilePath) WritePreferenceString("TorrentSavePath", G_ProgramMiscInfo\Setting\TorrentSavePath) PreferenceGroup("MainWin") Win\Length = SizeOf(WINDOWPLACEMENT) GetWindowPlacement_(WindowID(#MainWin), @Win) WritePreferenceLong("State", Win\flags) WritePreferenceLong("MainWinVisible", G_ProgramMiscInfo\Setting\MainWinVisible) WritePreferenceLong("WinX", Win\rcNormalPosition\left) WritePreferenceLong("WinY", Win\rcNormalPosition\top) WritePreferenceLong("WinW", Win\rcNormalPosition\right - Win\rcNormalPosition\left) WritePreferenceLong("WinH", Win\rcNormalPosition\bottom - Win\rcNormalPosition\top) WritePreferenceLong("SplitterPos", GetGadgetState(#MainWin_Splitter_Vertikal)) WritePreferenceLong("TabPos", SendMessage_(G_ProgramMiscInfo\PanelInfo\hPanel, #TCM_GETCURSEL, 0, 0)) WritePreferenceLong("Speed_CoboBox", G_ProgramMiscInfo\Setting\Speed_CoboBoxState) WritePreferenceLong("DomainsName", G_ProgramMiscInfo\Setting\ShowDomainsName) PreferenceGroup("TorrentList") For i=1 To 14 WritePreferenceLong("Column"+Str(i), GetGadgetItemAttribute(#MainWin_ListIcon_Torrent, 0, #PB_ListIcon_ColumnWidth, i-1)) Next i SendMessage_(GadgetID(#MainWin_ListIcon_Torrent),#LVM_GETCOLUMNORDERARRAY,14,@G_ProgramMiscInfo\Setting\TorrentListIcon_ORDERARRAY[0]) For i=1 To 14 WritePreferenceLong("Orderrary"+Str(i), G_ProgramMiscInfo\Setting\TorrentListIcon_ORDERARRAY[i-1]) Next i PreferenceGroup("TrackerList") For i=1 To 5 WritePreferenceLong("Column"+Str(i), GetGadgetItemAttribute(#MainWin_Panel_Info_ListIcon_Tracker, 0, #PB_ListIcon_ColumnWidth, i-1)) Next i SendMessage_(GadgetID(#MainWin_Panel_Info_ListIcon_Tracker),#LVM_GETCOLUMNORDERARRAY,5,@G_ProgramMiscInfo\Setting\ListIcon_Tracker_ORDERARRAY[0]) For i=1 To 5 WritePreferenceLong("Orderrary"+Str(i), G_ProgramMiscInfo\Setting\ListIcon_Tracker_ORDERARRAY[i-1]) Next i PreferenceGroup("PeerList") For i=1 To 11 WritePreferenceLong("Column"+Str(i), GetGadgetItemAttribute(#MainWin_Panel_Info_ListIcon_Peer, 0, #PB_ListIcon_ColumnWidth, i-1)) Next i SendMessage_(GadgetID(#MainWin_Panel_Info_ListIcon_Peer),#LVM_GETCOLUMNORDERARRAY,11,@G_ProgramMiscInfo\Setting\ListIcon_Peer_ORDERARRAY[0]) For i=1 To 11 WritePreferenceLong("Orderrary"+Str(i), G_ProgramMiscInfo\Setting\ListIcon_Peer_ORDERARRAY[i-1]) Next i PreferenceGroup("FilesList") For i=1 To 8 WritePreferenceLong("Column"+Str(i), GetGadgetItemAttribute(#MainWin_Panel_Info_ListIcon_Files, 0, #PB_ListIcon_ColumnWidth, i-1)) Next i SendMessage_(GadgetID(#MainWin_Panel_Info_ListIcon_Files),#LVM_GETCOLUMNORDERARRAY,8,@G_ProgramMiscInfo\Setting\ListIcon_Files_ORDERARRAY[0]) For i=1 To 8 WritePreferenceLong("Orderrary"+Str(i), G_ProgramMiscInfo\Setting\ListIcon_Files_ORDERARRAY[i-1]) Next i PreferenceGroup("PieceList") For i=1 To 6;7 WritePreferenceLong("Column"+Str(i), GetGadgetItemAttribute(#MainWin_Panel_Info_ListIcon_Piece, 0, #PB_ListIcon_ColumnWidth, i-1)) Next i SendMessage_(GadgetID(#MainWin_Panel_Info_ListIcon_Piece),#LVM_GETCOLUMNORDERARRAY,6,@G_ProgramMiscInfo\Setting\ListIcon_Piece_ORDERARRAY[0]) For i=1 To 6;7 WritePreferenceLong("Orderrary"+Str(i), G_ProgramMiscInfo\Setting\ListIcon_Piece_ORDERARRAY[i-1]) Next i ClosePreferences() Else MessageRequester(#MessageName, "Ошибка при сохранении настроек программы!", #MB_OK|#MB_ICONWARNING) EndIf EndProcedure Procedure Save_Setting() ; Настройки программы. Protected x;, i If CreatePreferences(G_ProgramMiscInfo\Dir_SysFiles+"Setting.dat") PreferenceGroup("") WritePreferenceLong("Pos", G_ProgramSetting\TreePos) PreferenceGroup("Misc") WritePreferenceLong("MinimazeTray", G_ProgramSetting\Misc\MinimazeTray) WritePreferenceLong("CloseTray", G_ProgramSetting\Misc\CloseTray) WritePreferenceLong("BalloonTray", G_ProgramSetting\Misc\BalloonTray) WritePreferenceLong("HideShowTray", G_ProgramSetting\Misc\HideShowTray) PreferenceGroup("Lan") WritePreferenceLong("Port", G_ProgramSetting\Lan\Port) WritePreferenceLong("RandomPort", G_ProgramSetting\Lan\RandomPort) WritePreferenceLong("MaxConnect", G_ProgramSetting\Lan\MaxConnect) WritePreferenceLong("MaxPeer", G_ProgramSetting\Lan\MaxPeer) WritePreferenceLong("SlotTorrent", G_ProgramSetting\Lan\SlotTorrent) PreferenceGroup("Torrent") WritePreferenceLong("MaxActiveTorrent", G_ProgramSetting\Torrent\MaxActiveTorrent) WritePreferenceLong("MaxLoad", G_ProgramSetting\Torrent\MaxLoad) WritePreferenceLong("SerialLoadPiece", G_ProgramSetting\Torrent\Serial_LoadPiece) ClosePreferences() EndIf EndProcedure Procedure.b SaveTorrentData() ; Сохранение описания файлов торрента в файле TorrentInfo.dat. Protected FileID, i, x, TempS.s Protected Size.q, RealReadBytes.l, MemPos.l, *FileData Protected CountTorrent.l, CountTorrent_Bytes.l, StartPosTorrent.l, TempL.l Protected TorrentList_Size.l, CRC32.l, Result.b Result = #False x = 0 For i=1 To 80 If TryLockMutex(G_ProgramMiscInfo\SaveTorrentData_Mutex) x=1 Break EndIf Delay(10) Next i If x=0 : ProcedureReturn 0 : EndIf If FileSize(G_ProgramMiscInfo\Dir_SysFiles+"TorrentInfo.dat")>0 x = 0 FileID = ReadFile(#PB_Any, G_ProgramMiscInfo\Dir_SysFiles+"TorrentInfo.dat") ; Проверяем целостность данных файла. If FileID Size = Lof(FileID) If Size>0 And Size<10000000 *FileData = AllocateMemory(Size) If *FileData RealReadBytes = ReadData(FileID, *FileData, Size) If RealReadBytes>0 RealReadBytes-4 If CRC32Fingerprint(*FileData, RealReadBytes) = PeekL(*FileData+RealReadBytes) x = 1 EndIf EndIf FreeMemory(*FileData) EndIf EndIf CloseFile(FileID) EndIf *FileData = 0 : FileID = 0 If x = 1 If FileSize(G_ProgramMiscInfo\Dir_SysFiles+"TorrentInfo.datbk")>=0 If DeleteFile(G_ProgramMiscInfo\Dir_SysFiles+"TorrentInfo.datbk") CopyFile(G_ProgramMiscInfo\Dir_SysFiles+"TorrentInfo.dat", G_ProgramMiscInfo\Dir_SysFiles+"TorrentInfo.datbk") EndIf Else CopyFile(G_ProgramMiscInfo\Dir_SysFiles+"TorrentInfo.dat", G_ProgramMiscInfo\Dir_SysFiles+"TorrentInfo.datbk") EndIf EndIf EndIf MemPos = 0 x = 0 For i=1 To 80 If TryLockMutex(G_TorrentList\Mutex) x=1 Break EndIf Delay(10) Next i If x=0 UnlockMutex(G_ProgramMiscInfo\SaveTorrentData_Mutex) ProcedureReturn 0 EndIf *FileData = AllocateMemory(1000000) If *FileData FileID = CreateFile(#PB_Any, G_ProgramMiscInfo\Dir_SysFiles+"TorrentInfo.dat") If FileID TorrentList_Size = ListSize(G_TorrentList\TorrentList()) WriteQuad(FileID, 0) ; Зарезирвировано. WriteQuad(FileID, 0) ; Зарезирвировано. WriteQuad(FileID, 0) ; Зарезирвировано. WriteQuad(FileID, 0) ; Зарезирвировано. WriteQuad(FileID, G_TorrentList\Info\Speed\All_InBytes) ; Сколько скачано байт за все время работы клиента. WriteQuad(FileID, G_TorrentList\Info\Speed\All_OutBytes); Сколько отданно байт за все время работы клиента. WriteLong(FileID, TorrentList_Size) ; Число торрентов. ForEach G_TorrentList\TorrentList() MemPos = 8 ; Пропускаем размер данных торрента (4 байта) и CRC32 (4) байта, которые будут заполены в конце. TempS = G_TorrentList\TorrentList()\Torrent\SysFileName ; Имя торрент файла, находящегося в системной папке торрента. TempL = StringByteLength(TempS, #PB_UTF8) PokeL(*FileData+MemPos, TempL) : MemPos + 4 PokeS(*FileData+MemPos, TempS, TempL, #PB_UTF8) MemPos + TempL If MemPos<900000 TempS = G_TorrentList\TorrentList()\TorrentFile\INFO_Hash ; INFO Hash. TempL = StringByteLength(TempS, #PB_Ascii) PokeL(*FileData+MemPos, TempL) : MemPos + 4 PokeS(*FileData+MemPos, TempS, TempL, #PB_Ascii) MemPos + TempL EndIf If MemPos<900000 TempS = G_TorrentList\TorrentList()\TorrentName ; Имя торрента, отображаемое в таблице. TempL = StringByteLength(TempS, #PB_UTF8) PokeL(*FileData+MemPos, TempL) : MemPos + 4 PokeS(*FileData+MemPos, TempS, TempL, #PB_UTF8) MemPos + TempL EndIf If MemPos<900000 TempS = G_TorrentList\TorrentList()\Label ; Метка торрента. TempL = StringByteLength(TempS, #PB_UTF8) PokeL(*FileData+MemPos, TempL) : MemPos + 4 If TempL>0 PokeS(*FileData+MemPos, TempS, TempL, #PB_UTF8) EndIf MemPos + TempL EndIf If MemPos<900000 TempS = G_TorrentList\TorrentList()\Torrent\Path ; Путь к файлам с торрентом. Если в торренте папка, то включено также содержимое "CurrentDir_Name", т. е. полный абсолютный путь к папке. If FindString(TempS, G_ProgramMiscInfo\ProgFilePath, 1)=1 TempS=Right(TempS, Len(TempS)-Len(G_ProgramMiscInfo\ProgFilePath)) TempS="?Portable\"+TempS EndIf TempL = StringByteLength(TempS, #PB_UTF8) PokeL(*FileData+MemPos, TempL) : MemPos + 4 PokeS(*FileData+MemPos, TempS, TempL, #PB_UTF8) MemPos + TempL EndIf ; Количество загруженных байт. ; Количество отправленных байт. ; Лимит приёма. ; Лимит отдачи. ; Лишние данные. ; Сколько времени (в секундах) осталось до конца загрузки. If MemPos<900000 TempL = OffsetOf(Sub_TorrentInfo_TorrentList_Network_IO\InSpeed) PokeL(*FileData+MemPos, TempL) : MemPos + 4 CopyMemory(@G_TorrentList\TorrentList()\Network_IO, *FileData+MemPos, TempL) MemPos + TempL EndIf If MemPos<900000 TempL = ArraySize(G_TorrentList\TorrentList()\Torrent\MapFile\MapPiece()) PokeL(*FileData+MemPos, TempL) : MemPos + 4 If TempL>=0 CopyMemory(@G_TorrentList\TorrentList()\Torrent\MapFile\MapPiece(), *FileData+MemPos, TempL+1) MemPos + TempL+1 EndIf EndIf If MemPos<999000 ; Число частей. PokeL(*FileData+MemPos, G_TorrentList\TorrentList()\Torrent\CountPiece) : MemPos + 4 ; Текущий размер всех файлов торрента (сколько есть на диске). PokeQ(*FileData+MemPos, G_TorrentList\TorrentList()\Torrent\CurrentFileSize) : MemPos + 8 ; Состояние торрента. PokeB(*FileData+MemPos, G_TorrentList\TorrentList()\TorrentStatus) : MemPos + 1 ; Дата добавления торрента. PokeL(*FileData+MemPos, G_TorrentList\TorrentList()\AddDate) : MemPos + 4 ; Время активности торреена (в секундах). PokeL(*FileData+MemPos, G_TorrentList\TorrentList()\ActiveTimeSec) : MemPos + 4 x = 0 ForEach G_TorrentList\Table() If G_TorrentList\Table()\INFO_Hash = G_TorrentList\TorrentList()\TorrentFile\INFO_Hash x = 1 Break EndIf Next If x = 1 ;NextElement(G_TorrentList\Table()) PokeW(*FileData+MemPos, G_TorrentList\Table()\Percent) Else PokeW(*FileData+MemPos, 0) EndIf MemPos + 2 PokeQ(*FileData+MemPos, G_TorrentList\TorrentList()\Torrent\Torrent_FileSize) : MemPos + 8 PokeQ(*FileData+MemPos, G_TorrentList\TorrentList()\TorrentFile\All_Size) : MemPos + 8 ;MemPos + 32 ; Зарезирвировано. PokeL(*FileData, MemPos) ; Размер данных торрента. PokeL(*FileData+4, CRC32Fingerprint(*FileData+8, MemPos-8)) ; CRC32 EndIf WriteData(FileID, *FileData, MemPos) FillMemory(*FileData, MemPos, 0) Next CloseFile(FileID) CRC32 = CRC32FileFingerprint(G_ProgramMiscInfo\Dir_SysFiles+"TorrentInfo.dat") FileID = OpenFile(#PB_Any, G_ProgramMiscInfo\Dir_SysFiles+"TorrentInfo.dat") If FileID FileSeek(FileID, Lof(FileID)) WriteLong(FileID, CRC32) CloseFile(FileID) EndIf Result = #True EndIf FreeMemory(*FileData) EndIf UnlockMutex(G_TorrentList\Mutex) UnlockMutex(G_ProgramMiscInfo\SaveTorrentData_Mutex) ProcedureReturn Result EndProcedure Procedure End_Program() Protected WSACloseEvent.WSACloseEvent=G_ProgramMiscInfo\Network\WSA\WSACloseEvent If G_ProgramMiscInfo\ProgEndSate = 0 G_ProgramMiscInfo\ProgEndSate = 1 For x=0 To 4000 Delay(2) WindowEvent() If IsThread(G_ProgramMiscInfo\Thread\Network_ThreadID)=0 And IsThread(G_ProgramMiscInfo\Thread\OutText_ThreadID)=0 Break EndIf Next x ; Очистка списка заданий подключения к пирам. LockMutex(G_ProgramMiscInfo\Network\ConnectPeer_Mutex) ForEach G_ProgramMiscInfo\Network\ConnectPeer_List() DeleteElement(G_ProgramMiscInfo\Network\ConnectPeer_List()) Next ForEach G_ProgramMiscInfo\Network\ConnectPeer_ResiltID_List() If G_ProgramMiscInfo\Network\ConnectPeer_ResiltID_List()\ConnectID CloseNetworkConnection(G_ProgramMiscInfo\Network\ConnectPeer_ResiltID_List()\ConnectID) G_ProgramMiscInfo\Network\ConnectPeer_ResiltID_List()\ConnectID=0 EndIf DeleteElement(G_ProgramMiscInfo\Network\ConnectPeer_ResiltID_List()) Next ForEach G_ProgramMiscInfo\Network\TestConnect() If G_ProgramMiscInfo\Network\TestConnect()\ConnectID CloseNetworkConnection(G_ProgramMiscInfo\Network\TestConnect()\ConnectID) G_ProgramMiscInfo\Network\TestConnect()\ConnectID=0 EndIf If G_ProgramMiscInfo\Network\TestConnect()\hEvent WSACloseEvent(G_ProgramMiscInfo\Network\TestConnect()\hEvent) G_ProgramMiscInfo\Network\TestConnect()\hEvent=0 EndIf DeleteElement(G_ProgramMiscInfo\Network\TestConnect()) Next UnlockMutex(G_ProgramMiscInfo\Network\ConnectPeer_Mutex) SignalSemaphore(G_ProgramMiscInfo\Network\DomainsPeer_Semaphore) ; Чтобы поток завершился. If FileSize(G_ProgramMiscInfo\ProgFilePath+#DirProgFiles)<> - 2 If CreateDirectory(G_ProgramMiscInfo\ProgFilePath+#DirProgFiles) If CreateDirectory(G_ProgramMiscInfo\ProgFilePath+#DirSysFiles) SetFileAttributes(G_ProgramMiscInfo\ProgFilePath+#DirSysFiles, #PB_FileSystem_Hidden) EndIf CreateDirectory(G_ProgramMiscInfo\ProgFilePath+#DirTorrentFiles) EndIf Else If FileSize(G_ProgramMiscInfo\ProgFilePath+#DirSysFiles)<> -2 If CreateDirectory(G_ProgramMiscInfo\ProgFilePath+#DirSysFiles) SetFileAttributes(G_ProgramMiscInfo\ProgFilePath+#DirSysFiles, #PB_FileSystem_Hidden) EndIf EndIf If FileSize(G_ProgramMiscInfo\ProgFilePath+#DirTorrentFiles)<>-2 CreateDirectory(G_ProgramMiscInfo\ProgFilePath+#DirTorrentFiles) EndIf EndIf Save_WinPref() If SaveTorrentData()=#False ; Сохранение описания файлов торрента в файле TorrentInfo.dat. MessageRequester(#MessageName, "Ошибка при сохранении в файл, данных о торрентах!", #MB_OK|#MB_ICONERROR) EndIf Tracker_Stopped_All_Tracker() ; Информирование трекеров об том, что торрент-клиент завершает свою работу. For i=0 To 6 hListView = G_ProgramMiscInfo\PanelInfo\Page_hWnd[i] If hListView *Proc = GetWindowLongPtr_(hListView,#GWL_USERDATA) If *Proc SetWindowLongPtr_(hListView, #GWL_WNDPROC, *Proc) SetWindowLongPtr_(hListView,#GWL_USERDATA, 0) EndIf EndIf Next i hListView=G_ProgramMiscInfo\hTorrentListIcon *Proc = GetWindowLongPtr_(hListView,#GWL_USERDATA) If *Proc SetWindowLongPtr_(hListView, #GWL_WNDPROC, *Proc) SetWindowLongPtr_(hListView,#GWL_USERDATA, 0) EndIf hWnd=GadgetID(#MainWin_Panel_Info_MiscInfo_Scroll_Back) *Proc = GetWindowLongPtr_(hWnd,#GWL_USERDATA) If *Proc SetWindowLongPtr_(hWnd, #GWL_WNDPROC, *Proc) SetWindowLongPtr_(hWnd,#GWL_USERDATA, 0) EndIf DestroyWindow_(G_ProgramMiscInfo\PanelInfo\hPanel) EndIf EndProcedure Procedure RegGadget_Callback(hwnd, msg, wparam, lparam) Protected *Gadget_Info.My_Gadget_Info = GetProp_(hwnd, "GadgetInfo") Protected OldProc = *Gadget_Info\OldCallback If msg = #WM_NCDESTROY If *Gadget_Info If *Gadget_Info\DestroyProc CallFunctionFast(*Gadget_Info\DestroyProc, *Gadget_Info\pbid) EndIf EndIf RemoveProp_(hwnd, "GadgetInfo") FreeMemory(*Gadget_Info) EndIf ProcedureReturn CallWindowProc_(OldProc, hwnd, msg, wparam, lparam) EndProcedure Procedure RegisterGadget(hwnd.i, ID.i, DestroyProc.i , *vttemp.My_PB_Gadget_VT) Protected *Gadget_Info.My_Gadget_Info Protected OldCallback.i Protected *vt.My_PB_Gadget_VT Protected *Gadget, result If ((hwnd = 0) Or (id < #PB_Any)) ProcedureReturn 0 EndIf *vt = AllocateMemory(SizeOf(My_PB_Gadget_VT)) If *vttemp <> 0 CopyMemory(*vttemp,*vt,SizeOf(My_PB_Gadget_VT)) EndIf *Gadget = PB_Object_GetOrAllocateID(PB_GADGET_OBJECTS, ID) result = PB_Gadget_RegisterGadget(ID, *Gadget, hwnd, *vt) If DestroyProc *Gadget_Info = AllocateMemory(SizeOf(My_Gadget_Info)) If id = #PB_Any *Gadget_Info\PBID = hwnd Else *Gadget_Info\PBID = ID EndIf *Gadget_Info\DestroyProc = DestroyProc *Gadget_Info\OldCallback = SetWindowLongPtr_(GadgetID(*Gadget_Info\PBID), #GWL_WNDPROC, @RegGadget_Callback()) SetProp_(GadgetID(*Gadget_Info\PBID), "GadgetInfo", *Gadget_Info) EndIf ProcedureReturn hwnd EndProcedure Procedure Create_Gadget(Id.i, ClassName.s, Text.s, Style.i, X.l, Y.l, CX.l, CY.l, ExStyle.i=0, DestroyProc.i=0, *vt.My_PB_Gadget_VT=0) Protected hwnd.i Protected Parent.i = PeekI(PB_Object_GetThreadMemory(PB_GADGET_GLOBALS)) Protected hInstance.i = GetModuleHandle_(0) hwnd = CreateWindowEx_(ExStyle, ClassName, Text, Style, X, Y, CX, CY, Parent, 0, hInstance, 0) SendMessage_(hWnd, #WM_SETFONT, GetGadgetFont(#PB_Default), 1); If hwnd = #False : ProcedureReturn #False : EndIf ProcedureReturn RegisterGadget(hwnd, ID, DestroyProc, *vt) EndProcedure Procedure CreateRebar(hwndOwner, hwndTB) Protected rbi.REBARINFO Protected rbBand.REBARBANDINFO Protected icex.INITCOMMONCONTROLSEX icex\dwSize = SizeOf(INITCOMMONCONTROLSEX) icex\dwICC = #ICC_COOL_CLASSES | #ICC_BAR_CLASSES InitCommonControlsEx_(@icex) ;| #WS_CLIPSIBLINGS hwndRB = CreateWindowEx_(#WS_EX_TOOLWINDOW, "ReBarWindow32", #Null, #WS_CHILD | #WS_VISIBLE | #WS_CLIPCHILDREN | #RBS_VARHEIGHT | #CCS_NODIVIDER, 0, 0, 0, 0, hwndOwner, #Null, GetModuleHandle_(0), #Null) rbi\cbSize = SizeOf(REBARINFO) rbi\fMask = 0 rbi\himl = #Null SendMessage_(hwndRB, #RB_SETBARINFO, 0, @rbi) rbBand\cbSize = SizeOf(REBARBANDINFO) rbBand\fMask = #RBBIM_COLORS | #RBBIM_TEXT | #RBBIM_STYLE | #RBBIM_CHILD | #RBBIM_CHILDSIZE | #RBBIM_SIZE rbBand\fStyle = #RBBS_CHILDEDGE rbBand\clrBack = GetSysColor_(#COLOR_3DFACE) rbBand\clrFore = GetSysColor_(#COLOR_3DFACE) ; ; ;/ Get the height of the ToolBar we created earlier dwBtnSize = SendMessage_(hwndTB, #TB_GETBUTTONSIZE, 0,0) ;/ Set values for band with the ToolBar tbtext$ = "" rbBand\lpText = @tbtext$ ; text to display for ToolBar rbBand\hwndChild = hwndTB ; handle to our ToolBar ;rbBand\cxMinChild = 30 ; min width of band (0 hides ToolBar) rbBand\cyMinChild = (dwBtnSize>>16) ; min height of band set to button height rbBand\cx = 700 ; width of band SendMessage_(hwndRB, #RB_INSERTBAND, -1, @rbBand) ProcedureReturn hwndRB; EndProcedure Procedure.s ConvertByte_ToString(Number.q, NbDecimal.a) Protected Result.s, i, Char.s NbDecimal = NbDecimal & %11 If Number>=0 If Number < 1000 Result = Str(Number)+" б"; Байты Else For i=1 To 4 If Number/1024 < 1000 Result = StrF(Number/1024, NbDecimal) Break EndIf Number/1024 Next i Result = RTrim(Result, "0") Char = Right(Result, 1) If Char<"0" Or Char>"9" Result = Left(Result, Len(Result)-1) EndIf Select i Case 1 Result + " Кб" Case 2 Result + " Мб" Case 3 Result + " Гб" Case 4 Result + " Тб" EndSelect EndIf Else Result = Chr($221E) EndIf ProcedureReturn Result EndProcedure Procedure GetIcon_Extension(Part.s) ; Идентификатор иконки (16x16), связанной с расширением в переменной Part Static NewList Part_IconID.GetIcon_Extension() Protected Info.SHFILEINFO, IconID Part=LCase(Part) ForEach Part_IconID() If Part=Part_IconID()\Part ; Данные о расширенни найдены ProcedureReturn Part_IconID()\IconID EndIf Next ; Данных о расширении нет, поэтому загружаем иконку IconID = 0 If SHGetFileInfo_("." + Part, #FILE_ATTRIBUTE_NORMAL, @Info.SHFILEINFO, SizeOf(SHFILEINFO), #SHGFI_USEFILEATTRIBUTES | #SHGFI_ICON | #SHGFI_SMALLICON) IconID = Info\hIcon Else ExtractIconEx_("shell32.dll", 0, 0, @IconID , 1) EndIf If IconID If AddElement(Part_IconID()) Part_IconID()\Part=Part Part_IconID()\IconID=IconID EndIf EndIf ProcedureReturn IconID EndProcedure ;Узнать имя компа в сети по IP адресу. Procedure.s GetHostNameByIP(ip$) Protected wsa.WSAData, *host.hostent Protected Count, *Mem *host = 0 If ip$<>"" Count = StringByteLength(ip$, #PB_Ascii) If Count>0 *Mem = AllocateMemory(Count+4) If *Mem FillMemory(*Mem, Count+4, 0, #PB_Byte) PokeS(*Mem, ip$, -1, #PB_Ascii) ipaddr=inet_addr_(*Mem) If ipaddr<>#INADDR_NONE And ipaddr<>#INADDR_ANY And ipaddr<>0 *host=gethostbyaddr_(@ipaddr,4,#AF_INET) EndIf FreeMemory(*Mem) EndIf EndIf EndIf If *host ProcedureReturn PeekS(*host\h_name, -1, #PB_Ascii) Else ProcedureReturn "" ;ip$ EndIf EndProcedure Procedure.l ip2int(ip.s) ; Преобразование IP-строки в IP-число. intIp.l=0 For k=4 To 1 Step -1 intIp=intIp+Val(StringField(ip, k, ".")) If k>1 intIp<<8 EndIf Next ProcedureReturn intIp EndProcedure Procedure SysTray_IconBalloon(Tray, WindowID, Title.s, Message.s, TimeOut, TypeIcon) ; Tray - идентификатор значка в трее ; WindowID - Системный идентификатор окна ; Title - текст в заголовке баллона ; Message - текст в баллоне ; TimeOut - Время (в миллисекундах) отображения баллона ; TypeIcon - тип значка #NIIF_NONE #NIIF_INFO #NIIF_WARNING #NIIF_ERROR #NIIF_USER Protected nid.NOTIFYICONDATA_2K nid\cbSize = SizeOf(NOTIFYICONDATA_2K) nid\uVersion = #NOTIFYICON_VERSION Shell_NotifyIcon_(#NIM_SETVERSION, @nid) nid\uCallbackMessage=#PB_Event_SysTray nid\uID = Tray nid\hwnd = WindowID nid\dwInfoFlags = TypeIcon;#NIIF_INFO nid\uFlags = #NIF_INFO nid\uTimeout = TimeOut nid\dwState = #NIS_SHAREDICON PokeS(@nid\szInfo, message, 256) PokeS(@nid\szInfoTitle, title, 64) ProcedureReturn Shell_NotifyIcon_(#NIM_MODIFY, @nid) EndProcedure Procedure Test_TrayIcon(Tray, WindowID) ; Tray - идентификатор значка в трее ; WindowID - системный идентификатор окна, к которому привязан значок ; Результат - 1 - значок есть; 0 - значка нет Protected nid.NOTIFYICONDATA_2K , x nid\cbSize = SizeOf(NOTIFYICONDATA_2K) nid\uID = Tray nid\hwnd = WindowID nid\uFlags = #NIF_STATE nid\dwStateMask = #NIS_HIDDEN x = Shell_NotifyIcon_(#NIM_MODIFY, @nid) ProcedureReturn x EndProcedure Procedure.b Test_Memory(*Pointer, Size) ; Провка доступности указаного участка памяти. Protected mbi.MEMORY_BASIC_INFORMATION Protected Result.b = #False, dwWrote If Size dwWrote = VirtualQuery_(*Pointer, @mbi, SizeOf(MEMORY_BASIC_INFORMATION)) If dwWrote If mbi\BaseAddress+mbi\RegionSize >= *Pointer+Size If mbi\Protect & (#PAGE_READONLY | #PAGE_READWRITE | #PAGE_EXECUTE_READ | #PAGE_EXECUTE_READWRITE) Result = #True EndIf EndIf EndIf EndIf ProcedureReturn Result EndProcedure Procedure.b TestNumber(String.s) ; Проверяет чтобы в строке были только цифры. Protected Result.b, Len, Char.s, i Result = #True Len = Len(String) For i=1 To Len Char = Mid(String, i, 1) If Char<"0" Or Char>"9" Result = #False Break EndIf Next i ProcedureReturn Result EndProcedure Procedure.b TestNumber_Hex(String.s) ; Проверяет чтобы в строке были только цифры. Protected Result.b, Len, Char.s, i Result = #True Len = Len(String) For i=1 To Len Char = Mid(String, i, 1) If (Char<"0" Or Char>"9") And (Char<"A" Or Char>"F")And (Char<"a" Or Char>"f") Result = #False Break EndIf Next i ProcedureReturn Result EndProcedure Procedure.s DelNull(String.s) Protected Result.s Result=String Pos=FindString(String, ".", 1) If Pos>0 Len=Len(String) For i=Len To Pos Step -1 Char.s=Mid(String, i, 1) If Char="." i-1 Break ElseIf Char<>"0" Break EndIf Next i If i0 And *dest And *destLen g_zip\next_in = *source g_zip\avail_in = sourceLen g_zip\next_out = *dest g_zip\avail_out = *destLen g_zip\zalloc = #Null g_zip\zfree = #Null g_zip\opaque = #Null g_zip\data_type = 1 If inflateInit2(@g_zip,15+32,?G_ZIP_UnPack_V,SizeOf(g_zip)) = #Z_OK If inflate(@g_zip, #Z_FINISH) = #Z_STREAM_END If g_zip\total_out>0 And PeekI(*destLen)>=g_zip\total_out Result = g_zip\total_out ; Сколько байт в буфере. EndIf EndIf inflateEnd(@g_zip) EndIf EndIf ProcedureReturn Result DataSection G_ZIP_UnPack_V: CompilerIf #PB_Compiler_Version<520 Data.a $31, $2E, $32, $2E, $33, 0, 0, 0, 0 ;@"1.2.3" CompilerElse Data.a $31, $2E, $32, $2E, $38, 0, 0, 0, 0 ;@"1.2.8" CompilerEndIf EndDataSection EndProcedure Procedure.s URLEncode_Binary(*Mem, Size) Protected Encoded.s, Char.a, i Encoded = "" Size-1 For i=0 To Size Char=PeekA(*Mem+i) ; If (Char>='0' And Char<='9') Or (Char>='A' And Char<='Z') Or (Char>='a' And Char<='z') ; Encoded+Chr(Char) ; ElseIf Char='$' Or Char='-' Or Char='_' Or Char='.' Or Char='+' Or Char='!' Or Char='*' Or Char=Asc("'") Or Char='(' Or Char=')' Or Char=',' ; Encoded+Chr(Char) ; Else Encoded+"%"+RSet(Hex(Char, #PB_Ascii),2,"0") ; EndIf Next i ProcedureReturn Encoded EndProcedure Procedure.s URLEncode_String(String.s) Protected Result.s, *Mem, Size Result = "" Size=StringByteLength(String, #PB_Ascii) If Size>0 *Mem = AllocateMemory(Size+2) If *Mem PokeS(*Mem, String, Size, #PB_Ascii) Result = URLEncode_Binary(*Mem, Size) FreeMemory(*Mem) EndIf EndIf ProcedureReturn Result EndProcedure Procedure.q ReverseQuad(Var.q) Protected Result.q Protected *Source, *Destination *Source = @Var *Destination = @Result PokeB(*Destination ,PeekB(*Source+7)) PokeB(*Destination+1,PeekB(*Source+6)) PokeB(*Destination+2,PeekB(*Source+5)) PokeB(*Destination+3,PeekB(*Source+4)) PokeB(*Destination+4,PeekB(*Source+3)) PokeB(*Destination+5,PeekB(*Source+2)) PokeB(*Destination+6,PeekB(*Source+1)) PokeB(*Destination+7,PeekB(*Source)) ProcedureReturn Result EndProcedure Procedure.l ReverseLong(Var.l) Protected Result.l Protected *Source, *Destination *Source = @Var *Destination = @Result PokeB(*Destination ,PeekB(*Source+3)) PokeB(*Destination+1,PeekB(*Source+2)) PokeB(*Destination+2,PeekB(*Source+1)) PokeB(*Destination+3,PeekB(*Source)) ProcedureReturn Result EndProcedure Procedure.w ReverseWord(Var.w) Protected Result.w Protected *Source, *Destination *Source = @Var *Destination = @Result PokeB(*Destination ,PeekB(*Source+1)) PokeB(*Destination+1,PeekB(*Source)) ProcedureReturn Result EndProcedure Procedure.a ReverseBits_Byte(Byte.a) Protected Result.a, i Result=0 For i=1 To 8 If Byte&1 Result | %00000001 Else Result & %11111110 EndIf If i<8 : Byte>>1 : Result<<1 : EndIf Next i ProcedureReturn Result EndProcedure Procedure.s TestBadConnect(Connect, *ErrP, TestConnect) ; Выявление ошибок связи с инетом. Protected Result.s, Test.l, Err, socketHandle Test=0 : Result="" ;DisableDebugger ; Кривой велосипед, но вроде работающий. If TestConnect=#True ;SendNetworkData(Connect, @Test, 0) ; Проверка на закрытие коннекта трекером. socketHandle = ConnectionID(Connect) Err = ioctlsocket_(socketHandle, #FIONREAD, @Test) EndIf Err = WSAGetLastError_() ;EnableDebugger If Err *Mem = AllocateMemory(1024) If *Mem FillMemory(*Mem, 1024, 0) Test=FormatMessage_(#FORMAT_MESSAGE_FROM_SYSTEM, 0, Err, 0, *Mem, 1024, 0) If Err>0 Result = PeekS(*Mem, Test) EndIf FreeMemory(*Mem) If *ErrP PokeI(*ErrP, Err) EndIf EndIf EndIf ProcedureReturn Result EndProcedure Procedure.s TimeLog() ProcedureReturn FormatDate(" [%dd/%mm/%yyyy %hh:%ii:%ss] — ", G_ProgramMiscInfo\CurrentDate) EndProcedure Procedure.a CreateFile_Size(FileName.s, Size.q) ; Создание файла требуемого размера, заполненого нулевыми байтами. Protected Result.a, *Mem, FileID, i Protected Count, BlockSize, Temp Result = #False FileID = CreateFile(#PB_Any, FileName) If FileID If Size>0 If Size<100*1024*1024 ; Меньше 100 мегабайт. If Size<1024*1024 ; Меньше мегабайта. BlockSize = Size Count=1 Else BlockSize = 1024*1024 Count = Round(Size/BlockSize, #PB_Round_Up) EndIf Else BlockSize = 10*1024*1024 Count = Round(Size/BlockSize, #PB_Round_Up) EndIf *Mem = AllocateMemory(BlockSize) If *Mem FileSeek(FileID, 0) FillMemory(*Mem, BlockSize, 0) For i=1 To Count If i=Count Temp=Size-Loc(FileID) If Temp<=0 Or Temp>BlockSize: Break : EndIf BlockSize = Temp EndIf WriteData(FileID, *Mem, BlockSize) FlushFileBuffers(FileID) Next i If Loc(FileID) = Size Result = #True EndIf FreeMemory(*Mem) EndIf Else Result = #True EndIf CloseFile(FileID) EndIf ProcedureReturn Result EndProcedure Procedure CreateMoreDirectory(Path.s) ; Создание множества папок по абсолютному пути. Protected Result, CurrentPath.s Protected Count, i, Dir.s;, Temp.s Result=#True CurrentPath="" If Path<>"" Dir=GetPathPart(Path) If FileSize(Dir)<>-2 ReplaceString(Path, "/", "\", #PB_String_InPlace) Count=CountString(Path, "\") If Count>=2 CurrentPath=StringField(Path, 1, "\")+"\" For i=2 To Count Dir = StringField(Path, i, "\") If Dir<>"" CurrentPath+Dir+"\" If FileSize(CurrentPath)<>-2 If CreateDirectory(CurrentPath)=0 Result=#False Break EndIf EndIf EndIf Next i EndIf EndIf EndIf ProcedureReturn Result EndProcedure Procedure.l Add_AverageList_Long(List MyList.l(), Add.l, MaxList.l) ; Добавляет новый элемент в список, укадяем последний элемента, если число элементов превысило MaxList и вычисняет средне арехметическое всех элементов. Protected Result.l, x.l, i, Size FirstElement(MyList()) If InsertElement(MyList()) MyList() = Add EndIf Size = ListSize(MyList()) If Size>MaxList LastElement(MyList()) For i=Size-1 To MaxList Step -1 DeleteElement(MyList()) Next i EndIf Result=0 : x=0 ForEach MyList() Result + MyList() x + 1 Next Result / x ProcedureReturn Result EndProcedure Procedure.u Add_AverageList_Uncode(List MyList.u(), Add.u, MaxList.l) ; Добавляет новый элемент в список, укадяем последний элемента, если число элементов превысило MaxList и вычисняет средне арехметическое всех элементов. Protected Result, x, i, Size FirstElement(MyList()) If InsertElement(MyList()) MyList() = Add EndIf Size = ListSize(MyList()) If Size>MaxList LastElement(MyList()) For i=Size-1 To MaxList Step -1 DeleteElement(MyList()) Next i EndIf Result=0 : x=0 ForEach MyList() Result + MyList() x + 1 Next Result / x ProcedureReturn Result EndProcedure Procedure IsMouseOver(wnd) Protected re.RECT, pt.POINT GetWindowRect_(wnd,@re) GetCursorPos_(@pt) ProcedureReturn PtInRect_(@re, pt\x | (pt\y<<32) ) EndProcedure Procedure CreateToolTip(WindowID, GadgetID, Text.s, Title.s, Icon) Protected ToolTip.TOOLINFO, hWnd Protected hinst hinst = GetModuleHandle_(0) hWnd=CreateWindowEx_(#WS_EX_TOPMOST,"ToolTips_Class32","",#WS_POPUP|#TTS_NOPREFIX|#TTS_ALWAYSTIP,0,0,0,0,WindowID,0,hinst,0) If hWnd ToolTip\cbSize = SizeOf(TOOLINFO) ToolTip\uFlags = #TTF_IDISHWND | #TTF_SUBCLASS ToolTip\hWnd = WindowID ToolTip\uId = GadgetID ToolTip\hInst = hinst ToolTip\lpszText = @Text SendMessage_(hWnd, #TTM_ADDTOOL, 0, @ToolTip) If Title <> "" SendMessage_(hWnd, #TTM_SETTITLE, Icon, @Title) EndIf EndIf ProcedureReturn hWnd EndProcedure Procedure ToolTip_Change(hToolTip, hWnd, GadgetID, Text.s, Title.s, Icon) Protected ttChange.TOOLINFO ttChange\cbSize = SizeOf(TOOLINFO) ttChange\hWnd = hWnd ttChange\uId = GadgetID ttChange\lpszText = @Text SendMessage_(hToolTip, #TTM_SETTITLE, Icon, @Title) SendMessage_(hToolTip, #TTM_UPDATETIPTEXT, 0, @ttChange) EndProcedure ; IDE Options = PureBasic 5.20 beta 15 LTS (Windows - x86) ; Folding = -------- ; EnableXP ; CompileSourceDirectory