PureBasic - форум

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » PureBasic - форум » Вопросы по PureBasic » Шаг за шагом


Шаг за шагом

Сообщений 1 страница 23 из 23

1

Это я.Завалил свою работу с прогой....Хочу разобратся.Где можно взять уроки/видео по PureBasic?????
Дана прога:

Код:
;- Window Constants
;
Enumeration
  #Window_0
  #Window_1
EndEnumeration

;- Gadget Constants
;
Enumeration
  #Text_0
  #Text_1
  #String_0
  #String_1
  #Button_0
  
  #ListIcon_Files
  #Text_Files
EndEnumeration

Procedure Direct(Directory.s, SearchFileName.s) 
  If Right(Directory.s,1)<>"\":Directory.s + "\":EndIf 
  z=ExamineDirectory(#PB_Any, Directory.s, "*.*")  
  If z 
    While NextDirectoryEntry(z) 
      EntryName.s=DirectoryEntryName(z) 
      ;------------------------------------------ 
      If EntryName = "." Or EntryName = ".." 
        Continue 
      EndIf 
      ;------------------------------------------ 
      Type=DirectoryEntryType(z) 
      If Type = #PB_DirectoryEntry_Directory 
        Direct(Directory.s+EntryName, SearchFileName)  
      ElseIf Type = #PB_DirectoryEntry_File 
        ;-------------------------------------------      
        FileName.s= Directory.s+EntryName  
        If LCase(EntryName) = SearchFileName
          AddGadgetItem(#ListIcon_Files, -1, FileName)
        EndIf
        SetGadgetText(#Text_Files, FileName)
      EndIf 
    Wend 
    FinishDirectory(z) 
  EndIf 
EndProcedure

Procedure StartSearchFile(*x)
  Direct("C:\", LCase(GetGadgetText(#String_0))) 
EndProcedure

Procedure Open_Window_0()
  If OpenWindow(#Window_0, 405, 361, 258, 67, "Поиск файлов",  #PB_Window_MinimizeGadget | #PB_Window_TitleBar | #PB_Window_ScreenCentered )
    If CreateGadgetList(WindowID(#Window_0))
      TextGadget(#Text_0, 5, 15, 85, 15, "Имя файла:")
      TextGadget(#Text_1, 5, 40, 85, 15, "Размер файла:")
      StringGadget(#String_0, 95, 10, 155, 20, "")
      StringGadget(#String_1, 95, 35, 50, 20, "", #PB_String_Numeric)
      ButtonGadget(#Button_0, 165, 35, 85, 24, "Искать")
    EndIf
  EndIf
EndProcedure



Open_Window_0()

Repeat
  Event = WaitWindowEvent()
  
  If Event = #PB_Event_Gadget
    If EventGadget() = #Button_0
      If GetGadgetText(#String_0)<>""
      OpenWindow(#Window_1, 0, 0, 500,400,"Найденные файлы", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
      ListIconGadget(#ListIcon_Files, 2, 2, 496, 350, "Файлы", 470, #PB_ListIcon_GridLines|#PB_ListIcon_FullRowSelect)
      TextGadget(#Text_Files, 2,360,496, 48, "")
      HideWindow(#Window_0, 1)
      CreateThread(@StartSearchFile(), 0)
    Else
      MessageRequester("", "Заполните поля")
      EndIf
    EndIf
  EndIf
  
Until Event = #PB_Event_CloseWindow

Хочу понять PureBasic. Поможите?
Расскажите как туда запихнеуть плеер и заставить её искать(она неработает).И поиск по размеру?Как???
Не прошу сделать за меня: научите делать))))

0

2

Давай по порядку.
Вот код поиска файлов:

Код:
Procedure Direct(Directory.s, SearchFileName.s) 
  If Right(Directory.s,1)<>"\":Directory.s + "\":EndIf ; Если в конце пути (в конце строки) нет символа '\', то добавлям его.
  z=ExamineDirectory(#PB_Any, Directory.s, "*.*")  ; Начало сканирования папки, путь к которой указан в строковой переменной Directory.
  If z                                             ; Идентификатор (число) сканируемой папки. Он нужен для других функций, например NextDirectoryEntry().
    While NextDirectoryEntry(z)                    ; Переходим к следующему объекту (файлу или папке). Если больше объектов нет - цикл прервется.
      EntryName.s=DirectoryEntryName(z)            ; Имя файла или папки.
      ;------------------------------------------ 
      If EntryName = "." Or EntryName = ".."       ; Если это текущая (".") или родительская ("..") папка,
        Continue                                   ; то досрочно переходим в начало цикла While-Wend.
      EndIf 
      ;------------------------------------------ 
      Type=DirectoryEntryType(z)                   ; Узнаем тип объекта (файл или папка).
      If Type = #PB_DirectoryEntry_Directory       ; Если это папка,
        Direct(Directory.s+EntryName, SearchFileName)  ; то процедура вызывает саму себя (рекурсия) для сканирования этой папки.
      ElseIf Type = #PB_DirectoryEntry_File        ; Если это файл,
        ;-------------------------------------------      
        FileName.s= Directory.s+EntryName          ; то получаем полный путь к файлу.
        If LCase(EntryName) = SearchFileName       ; Сравниваем имена файлов.
          ;AddGadgetItem(#ListIcon_Files, -1, FileName)
          Debug FileName
        EndIf
        ;SetGadgetText(#Text_Files, FileName)
      EndIf 
    Wend                                           ; Конец цкла While-Wend.
    FinishDirectory(z)                             ; Освобождение ресурсов, используемых при сканировании папки.
  EndIf 
EndProcedure

Direct("C:\", "boot.ini")

Прочитай справку на каждую функцию. Для этого, просто ставь текстовый курсор на имя функции и жми F1 на клавиатуре.
Еще будет полезно посмотреть как работает программа в пошаговом режиме. Это из разряда что лучше один раз увидеть, чем сто раз услышать.
Для просмотра работы программы в пошаговом режиме, нужно воспользоваться встроенным отладчиком, про работу с которым, можно прочитать здесь.

0

3

хороший пример поиска файла в предыдущем сообщении.
как можно вывести список найденных файлов по окончании поиска?

0

4

В примере, список выводится в отладочное окно. А куда вам его требуется вывести?

0

5

да, я это заметил. я хотел бы сделать из этого примера функцию для вызова (библиотеку)
после вызова и отработки функции получить список найденных файлов. я программирую на AutoIT. PB нужен для написания dll.
я примерно накидал функцию для вызова

открыть
Код:
Procedure Direct(Directory.s) 
  If Right(Directory.s,1)<>"\":Directory.s + "\":EndIf ; Если в конце пути (в конце строки) нет символа '\', то добавлям его.
  z=ExamineDirectory(#PB_Any, Directory.s, "*.*")  ; Начало сканирования папки, путь к которой указан в строковой переменной Directory.
  If z                                             ; Идентификатор (число) сканируемой папки. Он нужен для других функций, например NextDirectoryEntry().
    While NextDirectoryEntry(z)                    ; Переходим к следующему объекту (файлу или папке). Если больше объектов нет - цикл прервется.
      EntryName.s=DirectoryEntryName(z)            ; Имя файла или папки.
      ;------------------------------------------ 
      If EntryName = "." Or EntryName = ".."       ; Если это текущая (".") или родительская ("..") папка,
        Continue                                   ; то досрочно переходим в начало цикла While-Wend.
     EndIf 
     ;------------------------------------------ 
      Type=DirectoryEntryType(z)                   ; Узнаем тип объекта (файл или папка).
      If Type = #PB_DirectoryEntry_Directory   ; Если это папка,
        Direct(Directory.s+EntryName)   ; то процедура вызывает саму себя (рекурсия) для сканирования этой папки.
      ElseIf Type = #PB_DirectoryEntry_File        ; Если это файл,
        ;-------------------------------------------      
      FileName.s = Directory.s+EntryName ; то получаем полный путь к файлу.
      WriteStringN(0,FileName)
      EndIf 
    Wend     
    FinishDirectory(z)                             ; Освобождение ресурсов, используемых при сканировании папки. 
  EndIf 
EndProcedure

ProcedureDLL.s Search (PathF.s,FileW.s)
  CreateFile(0,FileW)
  OpenFile(0,FileW)
  Direct(PathF) 
  CloseFile(0)
EndProcedure

хотелось бы получить на выходе список файлов
прошу извинить за возможную корявость кода. я первый день читаю справку по PB. мой первый опыт )))

Отредактировано werbot (21.09.2014 16:23:44)

0

6

werbot написал(а):

хотелось бы получить на выходе список файлов

Это понятно, но ведь список нужно как-то передать из dll в вызывающую программу. Например поместить все пути к файлам в одну строку, разделив их каким-то символом, напрмиер, символом новой строки. И эту строку вернуть из dll.
Или это будет сделано через файл?

0

7

нет это нужно через строку. файл я сделал для примера..
в autoit сбор в одну строку - $var &= 'строка'
в PB такого нет. как создать список в функции, которая работает рекурсивно и выдать его в виде строки?

Отредактировано werbot (21.09.2014 23:46:41)

0

8

вобщем. сделал так

открыть
Код:
Procedure Direct(Directory.s, List Files.s()) 
  If Right(Directory.s,1)<>"\":Directory.s + "\":EndIf 
  z=ExamineDirectory(#PB_Any, Directory.s, "*.*") 
  If z                                            
    While NextDirectoryEntry(z)                   
      EntryName.s=DirectoryEntryName(z)            
      If EntryName = "." Or EntryName = ".."  
        Continue                           
     EndIf 
      Type=DirectoryEntryType(z)                 
      If Type = #PB_DirectoryEntry_Directory  
        Direct(Directory.s+EntryName, Files())  
      ElseIf Type = #PB_DirectoryEntry_File      
        FileName.s = Directory.s+EntryName 
        If AddElement(Files())
          Files()=FileName
        EndIf
      EndIf 
    Wend     
    FinishDirectory(z)                         
  EndIf 
EndProcedure

ProcedureDLL.s Search(PathF.s)
 Protected NewList Files.s() 
  Direct(PathF, Files())
  ForEach Files()
    String$=String$ + Files() + "|"
  Next
  ProcedureReturn String$
EndProcedure

все работает и передает строку при вызове функции. но!!!. это вообще плохо. времени на формирование строки уходит до минуты. а сам поиск 2-4 сек.каким образом можно передать список?

0

9

в итоге все решилось

открыть
Код:
Procedure Direct(Directory.s, List Files.s()) 
  If Right(Directory.s,1)<>"\":Directory.s + "\":EndIf 
  z=ExamineDirectory(#PB_Any, Directory.s, "*.*") 
  If z                                            
    While NextDirectoryEntry(z)                   
      EntryName.s=DirectoryEntryName(z)            
      If EntryName = "." Or EntryName = ".."  
        Continue                           
     EndIf 
      Type=DirectoryEntryType(z)                 
      If Type = #PB_DirectoryEntry_Directory  
        Direct(Directory.s+EntryName, Files())  
      ElseIf Type = #PB_DirectoryEntry_File      
        FileName.s = Directory.s+EntryName 
        If AddElement(Files())
          Files()=FileName
        EndIf
      EndIf 
    Wend     
    FinishDirectory(z)                         
  EndIf 
EndProcedure

ProcedureDLL Search(*proc, PathF.s)
  Protected NewList Files.s() 
  If *proc
    Direct(PathF, Files())
    ForEach Files()
      Define path.s = Files()
      CallFunctionFast(*proc, @path)
    Next
    ProcedureReturn 1
  EndIf
  ProcedureReturn 0
EndProcedure

0

10

werbot написал(а):

String$=String$ + Files() + "|"

Такая конструкция будет медленно работать из-за того что при каждом добавлении в строку, пересчитывается ее размер путем перебора всех байт строки и поиска нулевого.

0

11

как тогда вернуть строку без таких затрат? хотя я и решил вопрос, но другой вариант не будет лишним.
спасибо вам за ответы. я хотел бы освоить PB. начал , наверное , не с самого простого. но все же ))
PB скоростной язык

0

12

Слабым звеном в данном случае является пересчет длины строки при каждом действии с ней.
Но ничего не мешает складывать строки в памяти.

Код:
Structure MemString
  *String
  Pos.i
  Len.i
EndStructure

Procedure Add_MemString(*Str.MemString, String.s)
  If *Str
    
    Len = StringByteLength(String)
    If Len>0
      
      If *Str\Len-*Str\Pos < Len
        *Str\Len+Len+1000
        *Str\String = ReAllocateMemory(*Str\String, *Str\Len)
      EndIf
      
      *Str\Pos+PokeS(*Str\String+*Str\Pos, String, Len, #PB_String_NoZero)
      
    EndIf
    
  EndIf
EndProcedure

Procedure Free_MemString(*Str.MemString)
  If *Str
    If *Str\String
      FreeMemory(*Str\String)
      *Str\String=0
    EndIf
    *Str\Pos=0
    *Str\Len=0
  EndIf
EndProcedure

Procedure Direct(Directory.s, List Files.s()) 
  If Right(Directory.s,1)<>"\":Directory.s + "\":EndIf 
  z=ExamineDirectory(#PB_Any, Directory.s, "*.*") 
  If z                                            
    While NextDirectoryEntry(z)                   
      EntryName.s=DirectoryEntryName(z)            
      If EntryName = "." Or EntryName = ".."  
        Continue                           
     EndIf 
      Type=DirectoryEntryType(z)                 
      If Type = #PB_DirectoryEntry_Directory  
        Direct(Directory.s+EntryName, Files())  
      ElseIf Type = #PB_DirectoryEntry_File      
        FileName.s = Directory.s+EntryName 
        If AddElement(Files())
          Files()=FileName
        EndIf
      EndIf 
    Wend     
    FinishDirectory(z)                         
  EndIf 
EndProcedure

ProcedureDLL.i Search(PathF.s)
  Protected NewList Files.s() 
  Static String.MemString
  
  Free_MemString(@String)
  
  Direct(PathF, Files())
  ForEach Files()
    Add_MemString(@String, Files() + "|")
  Next
  
  ProcedureReturn String\String
EndProcedure

0

13

сравнил в работе ваш код и код , который я выложил в сообщении №9
видимо из за создания структуры ваш код  отстает на 5 сек.

Отредактировано werbot (23.09.2014 05:01:43)

0

14

Петр, извините за настойчивость и непонятливость. :)
в вашей функции строка

Код:
ProcedureReturn String\String

возвращает указатель(адрес) где находится список. я , при вызове функции из своей программы, создаю структуру по этому адресу, но мне не хватает размера..как в вашем коде вернуть и размер структуры(элемента)?
при тесте самой функции в редакторе PB я увидел, что общий размер строк находится в String\Len.
вот как это вернуть при ProcedureReturn

Отредактировано werbot (23.09.2014 11:38:37)

0

15

Если в процедуре Add_MemString, заменить строку

Код:
*Str\Len+Len+1000

на

Код:
*Str\Len+Len+1000000

то работает быстрее.

0

16

спасибо. но как вернуть и указатель на адрес строки и указатель на размер строки?

0

17

werbot написал(а):

, при вызове функции из своей программы, создаю структуру по этому адресу

Принимать в вызывающей программе нужно не как структуру, а как строку. Должно получится.

werbot написал(а):

как вернуть и указатель на адрес строки и указатель на размер строки?

Вернуть размер строки можно таким образом:

Код:
ProcedureDLL.i Search(PathF.s, *Size.Integer)
  Protected NewList Files.s() 
  Static String.MemString
  
  Free_MemString(@String)
  
  Direct(PathF, Files())
  ForEach Files()
    Add_MemString(@String, Files() + "|")
  Next
  
  If *Size
    *Size\i = String\Pos
  EndIf
  
  ProcedureReturn String\String
EndProcedure

В вызывающей программе нужно во втором аргументе передать адрес переменной в которую запишется размер строки.

+1

18

вобщем, в моем коде (не PB), который вызывает эту функцию все сложилось так

Код:
$hDLL = DllOpen("test.dll")
$Struct = DllStructCreate("UINT_PTR")
$Result = DllCall($hDLL, "UINT_PTR", "Search", "STR", "C:\",'UINT_PTR',DllStructGetPtr($Struct))
$resstruct = DllStructCreate('char[' & DllStructGetData($Struct, 1) & ']',$Result[0])
$stringdelr = StringTrimRight(DllStructGetData($resstruct,1),1)
DllClose($hDLL)
$res = StringSplit($stringdelr,'|',1) ;получил список путей

это код на AutoIT. так я получил все что надо (указатели) и получил массив найденных путей.
кстати, стало быстро работать когда увеличил значение с 1000 до 1000 000. быстрее в десять раз. я так понимаю, что это резерв места в памяти под возможный размер строки?

Отредактировано werbot (23.09.2014 12:40:24)

0

19

Так вроде тоже работает.

Код:
$hDLL = DllOpen("test.dll")
$x=0
$Result = DllCall($hDLL, "STR", "Search", "STR", "C:\",'UINT*',$x)
$stringdelr = StringTrimRight($Result[0],1)
DllClose($hDLL)
$res = StringSplit($stringdelr,'|',1) ;получил список путей

Знать длину строки при этом не обязательно, о чем писал выше.

Пётр написал(а):

Принимать в вызывающей программе нужно не как структуру, а как строку.

werbot написал(а):

кстати, стало быстро работать когда увеличил значение с 1000 до 1000 000. быстрее в десять раз. я так понимаю, что это резерв места в памяти под возможный размер строки?

Да, это выделение памяти под строку. Когда выделяется мало памяти, часто происходит повторное выделение и если в текущем участке памяти, ОС не может выделить запрошенный объем памяти, то он выделяется в другом участке, с копированием данных. Это копирование требует времени и чем чаще оно происходит и чем больше объем копируемых данных, тем больше времени на это затрачивается.

0

20

все хорошо работает.
память, правда, ест до 200мб.
в отличии от других способов.

0

21

Это зависит от числа файлов и длины их путей. У меня процесс использует 16 МБ. Под строку при этом выделено 4 МБ.

0

22

я поиск делал на диске С. полностью весь диск. понятно что там путей больше. конечно в реале не так часто нужно возвращать все пути. ищут файл . это при массовом копировании нужны все

0

23

я бы попробовал такой вариант

1. перебираем список, суммируем [длины строк+1(на каждую строку - разделитель)]+1(в конце на нуль-байт)
2.Заказываем блок памяти полученного выше размера.
3.Переписываем в него список с использованием PokeS() - получаем нуль-терминированную строку в блоке памяти

должно получиться быстро т.к. операция выделения/перевыделения памяти всего одна
остальные операции - перемещения внутри готовых блоков памяти

0


Вы здесь » PureBasic - форум » Вопросы по PureBasic » Шаг за шагом