Queue-таймер вылетает...

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Re: Queue-таймер вылетает...

Сообщение Адская_Капча » 05.12.2015 (Сб) 13:46

То, что создание потока происходит медленно - мне пришла идея посмотреть CreateThread изнутри...
Оказывается, это обертка над CreateRemoteThread, а в последней содержатся следующие функции:
RtlImageNtHeader
NtCreateThread (видимо, основная)
NtQueryInformationThread
RtlQueryInformationActivationContext
CsrClientCallServer
NtResumeThread
RtlActivateActivationContextEx
GetModuleHandleA
GetProcAddress

Очень много всякой всячины, которая, видимо, и тормозит...
RtlImageNtHeader, GetModuleHandleA и QueryInformation всякие - не понимаю, зачем нужны.

Чистый вызов через NtCreateThread - это хорошая или плохая затея? Наверное, плохая (RtlActivateActivationContextEx - думаю, нужно зачем-то)?

А вот еще, оказывается, есть какая-то функция RtlCreateUserThread...
И в ней содержатся такие:
NtQuerySystemInformation
RtlImageNtHeader
NtAllocateVirtualMemory
RtlInitializeContext
NtCreateThread

Вроде, поменьше внутренних функций. Ну RtlInitializeContext в ней, наверное нужная вещь...
Создание потока через RtlCreateUserThread - хорошая идея или нет? Или нестабильно будет работать?

Главная затея - чтобы быстродействие повысить. Скорость, скорость, скорость...

The Trick писал(а):При чем вообще Interlocked-функции?

Про них Хакер сказал...

The Trick писал(а):просто пиши обработчик окна в модуле

То есть, это нужно сабклассить созданное (через CreateWindowEx) окно, правильно понимаю?
Это будет быстрее, чем механизм RaiseEvent?

The Trick писал(а):замапить массив на RWE память

Не знаю, зачем делать именно через замапивание... Хакер считает, что для вставок лучше всего память из хипа выделять, и я именно так делаю.

The Trick писал(а):Ассемблерную вставку править.

Просто ее зациклить от начала до конца, а также убрать подпроцедуру CLEAR, правильно думаю?

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Queue-таймер вылетает...

Сообщение The trick » 05.12.2015 (Сб) 19:01

Адская_Капча писал(а):Чистый вызов через NtCreateThread - это хорошая или плохая затея?

Адская_Капча писал(а):Создание потока через RtlCreateUserThread - хорошая идея или нет? Или нестабильно будет работать?

Это недокументированные функции и ими не следует пользоваться без крайней необходимости. Они требуют дополнительный "обвес".
Адская_Капча писал(а):Про них Хакер сказал...

Я прочитал это, но я уже сказал с таким успехом можно использовать высокочастотный таймер без всяких потоков.
Адская_Капча писал(а):То есть, это нужно сабклассить созданное (через CreateWindowEx) окно, правильно понимаю?Это будет быстрее, чем механизм RaiseEvent?

Сабклассить не нужно, обработчик регистрируется с классом окна. Практически тоже самое по времени.
Адская_Капча писал(а):Не знаю, зачем делать именно через замапивание... Хакер считает, что для вставок лучше всего память из хипа выделять, и я именно так делаю.

Не важно откуда выделять память. А замапивание делается для ускорения. Я бы мог конечно для записи каждой асм инструкции использовать Get/PutMem или записать все в массив, а потом скопировать через CopyMemory в память с RWE доступом, но я пишу сразу туда без лишних действий замапивая массив на этот участок.
Адская_Капча писал(а):Просто ее зациклить от начала до конца, а также убрать подпроцедуру CLEAR, правильно думаю?

Да, для ожидающих таймеров есть такой парметр как bManualReset, его нужно высавлять в False.
UA6527P

Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Re: Queue-таймер вылетает...

Сообщение Адская_Капча » 06.12.2015 (Вс) 17:57

The Trick писал(а):с таким успехом можно использовать высокочастотный таймер без всяких потоков

Да, но он же будет блокирующий (в одном потоке)...

The Trick писал(а):А замапивание делается для ускорения

Ускорение Изображение
Вот это уже интересный момент...
SafeArrayAllocDescriptor, видимо, не использует HeapAlloc нигде (по крайней мере, найти не удалось). Но он вызывает CoGetMalloc из OLE32.DLL. Не совсем понятно, что эта за функция.
Но из OLE32 есть CoTaskMemAlloc и она очень маленькая и, видимо, быстрая. А функции выделения через хип достаточно объемные и в них много всего.
Только непонятно, есть ли право на выполнение у памяти, выделенной через CoTaskMemAlloc? Флажков-то нету никаких...

Не совсем понятен термин "замапивание". Это отображение в память подкачки (не оперативную)?

The Trick писал(а):для записи каждой асм инструкции использовать Get/PutMem или записать все в массив, а потом скопировать через CopyMemory в память с RWE доступом

А смысл делать именно так: сначала в массив, а потом его копировать?
Можно ведь выделить память через хип и сразу туда писать PutMem-мами, используя указатель на выделенный хип. Или это хуже будет?

Какой способ выделения памяти под ассемблерные вставки (с правом на выполнение) самый быстрый и годится ли для этого CoTaskMemAlloc?



Второй момент: QueueTimer, похоже, сразу использует создание потока из ntdll и видимо здесь накладные расходы будут ниже, чем при использовании WaitForSingleObject и CreateThread.
Вопрос: почему в режиме IDE при закрытии формы само IDE никак не останавливается, а продолжает работать в нижеприведенном коде? Что в нем не так?

Форма с двумя кнопками:
Код: Выделить всё
Option Explicit

Private Declare Function CreateTimerQueue Lib "kernel32" () As Long
Private Declare Function CreateTimerQueueTimer Lib "kernel32" (ByRef phNewTimer As Long, ByVal TimerQueue As Long, ByVal Callback As Long, ByVal Parameter As Long, ByVal DueTime As Long, ByVal Period As Long, ByVal Flags As Long) As Long
Private Declare Function DeleteTimerQueue Lib "kernel32" (ByVal TimerQueue As Long) As Long
Private Declare Function DeleteTimerQueueTimer Lib "kernel32" (ByVal TimerQueue As Long, ByVal Timer As Long, ByVal CompletionEvent As Long) As Long

Private Const WT_EXECUTEONLYONCE = &H8&
Private Const WT_EXECUTELONGFUNCTION = &H10&
Private Const WT_EXECUTEINTIMERTHREAD = &H20&

Private Type WNDCLASSEX
    cbSize          As Long
    style           As Long
    lpfnwndproc     As Long
    cbClsextra      As Long
    cbWndExtra2     As Long
    hInstance       As Long
    hIcon           As Long
    hCursor         As Long
    hbrBackground   As Long
    lpszMenuName    As Long
    lpszClassName   As Long
    hIconSm         As Long
End Type

Private Declare Function UnregisterClassW Lib "user32" (ByVal lpClassName As Long, ByVal hInstance As Long) As Long
Private Declare Function RegisterClassExW Lib "user32" (pcWndClassEx As WNDCLASSEX) As Integer
Private Declare Function CreateWindowExW Lib "user32" (ByVal dwExStyle As Long, ByVal lpClassName As Long, ByVal lpWindowName As Long, ByVal dwStyle As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hWndParent As Long, ByVal hMenu As Long, ByVal hInstance As Long, lpParam As Any) As Long

Private Const HWND_MESSAGE As Long = -3

' Global Variables
Private m_hQueue As Long
Private m_hTimer As Long

Private Const m_sMsgClass As String = "TrickWaitClass"
Private m_hwnd As Long



Private Sub Form_Load()
    Command1.Caption = "Start"
    Command2.Caption = "Stop"
   
    m_hQueue = CreateTimerQueue()
End Sub

Private Sub Form_Unload(Cancel As Integer)
    DeleteTimerQueue m_hQueue
    m_hQueue = 0
End Sub

' Запуск таймера
Private Sub Command1_Click()
    Dim cls As WNDCLASSEX
   
    cls.cbSize = Len(cls)
    cls.hInstance = App.hInstance
    cls.lpfnwndproc = GetAddress(AddressOf Module1.MyWndProc)
    cls.lpszClassName = StrPtr(m_sMsgClass)
    cls.cbClsextra = 8
   
    If RegisterClassExW(cls) = 0 Then Exit Sub
   
    m_hwnd = CreateWindowExW(0, StrPtr(m_sMsgClass), 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, App.hInstance, ByVal 0&)
    If m_hwnd = 0 Then Exit Sub
       
    If m_hTimer = 0 Then
        CreateTimerQueueTimer m_hTimer, m_hQueue, AddressOf TimerCallBack, _
        ByVal m_hwnd&, 0, 50, WT_EXECUTEINTIMERTHREAD
    End If
End Sub

' Останов таймера
Private Sub Command2_Click()
    If m_hTimer <> 0 Then
        DeleteTimerQueueTimer m_hQueue, m_hTimer, ByVal -1& '0& '-1&
        m_hTimer = 0
    End If
   
    DestroyWindow m_hwnd
   
    UnregisterClassW StrPtr(m_sMsgClass), App.hInstance
End Sub


Модуль:
Код: Выделить всё
Private Declare Function PostMessageW Lib "user32" (ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function DefWindowProcW Lib "user32" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Private Declare Function EbMode Lib "vba6" () As Long

Declare Function DestroyWindow Lib "user32" (ByVal hwnd As Long) As Long

Private Const WM_USER As Long = &H400

' Global Variables
Dim a As Long

' Callback of TimerProc
Sub TimerCallBack(ByVal lpParameter As Long, ByVal TimerOrWaitFired As Long)
    PostMessageW lpParameter, WM_USER, 0, ByVal 0&
End Sub

' CallBack созданного окна для обработки
Function MyWndProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    If uMsg = WM_USER Then
'        RaiseProc
'        Exit Function
       
        Select Case EbMode
        Case 0 'stop
            Debug.Print "destroy"
            DestroyWindow hwnd
        Case 1 'run
            RaiseProc
            Exit Function
        End Select
    End If
   
    MyWndProc = DefWindowProcW(hwnd, uMsg, wParam, lParam)
End Function

' Пользовательская процедура для таймера
Sub RaiseProc()
    Debug.Print "---" & a
    a = a + 1
End Sub

' Обертка для AddressOf
Function GetAddress(lPtr As Long) As Long
    GetAddress = lPtr
End Function

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Queue-таймер вылетает...

Сообщение ger_kar » 06.12.2015 (Вс) 18:34

Адская_Капча писал(а):Не совсем понятен термин "замапивание". Это отображение в память подкачки (не оперативную)?
Мапить или замапливать - это если перевести на нормальный русский значить отображать(отобразить). А слово "отображать" имеет очень широкий смысл, причем не только в программировании. В данном контексте замапить массив - это значит ассоциировать массив с определенным участком памяти и таким образом работать с ней (с памятью) как с массивом. Получается, что память будет отображаться в виде массива. В этом и состоит смысл отображения. Что касается ускорения о котором говорит The Trick, то здесь ускорение связано с тем, что исключаются промежуточные операции связанные с копированием данных в памяти. Для создания ассемблерной вставки так или иначе приходится использовать массив или массивы, поэтому используя замапленный массив, можно сразу напрямую формировать ассемблерную вставку в памяти без дополнительный операций копирования.
Бороться и искать, найти и перепрятать

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Queue-таймер вылетает...

Сообщение The trick » 06.12.2015 (Вс) 19:34

Адская_Капча писал(а):Да, но он же будет блокирующий (в одном потоке)...

Так и с Interlocked будет тоже самое. Тебе придется опрашивать флаг в основном потоке.
Адская_Капча писал(а):Ускорение Вот это уже интересный момент...SafeArrayAllocDescriptor, видимо, не использует HeapAlloc нигде (по крайней мере, найти не удалось). Но он вызывает CoGetMalloc из OLE32.DLL. Не совсем понятно, что эта за функция.Но из OLE32 есть CoTaskMemAlloc и она очень маленькая и, видимо, быстрая. А функции выделения через хип достаточно объемные и в них много всего.Только непонятно, есть ли право на выполнение у памяти, выделенной через CoTaskMemAlloc? Флажков-то нету никаких...Не совсем понятен термин "замапивание". Это отображение в память подкачки (не оперативную)?

ger_kar все уже объяснил. Я создаю массив который уже ссылается на память выделенную через VirtualAlloc (ранее по коду), т.е. обращаясь Arr(0) - я обращаюсь к первому байту выделенной памяти.
Адская_Капча писал(а):А смысл делать именно так: сначала в массив, а потом его копировать?Можно ведь выделить память через хип и сразу туда писать PutMem-мами, используя указатель на выделенный хип. Или это хуже будет?
.
Через PutMem будет медленней, т.к. тратится время на вызов функции и возврат, а также на внутренние операции. Это я сравниваю свой способ с твоим. А так это зависит от размера вставок.
Адская_Капча писал(а):Какой способ выделения памяти под ассемблерные вставки (с правом на выполнение) самый быстрый и годится ли для этого CoTaskMemAlloc?

Не годится. Если ты создаешь вставку впервые то быстрее будет VirtualAlloc.
UA6527P

Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Re: Queue-таймер вылетает...

Сообщение Адская_Капча » 06.12.2015 (Вс) 20:17

Спасибо, теперь понятно... видимо, буду переделывать существующие программы, ведь они через PutMem вставки формировали.

А по коду - всячески выписываю мыслимые и немыслимые загогулины формой - ничего не вылетает. А вот из IDE никак нельзя выйти никакими способами. Неужели в примере MyWndProc и TimerCallBack будут только как ассемблерная вставка работать, а простой вызов из кода не пойдет?
Хочу попробовать "добить" способ с QueueTimers...

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Queue-таймер вылетает...

Сообщение Хакер » 07.12.2015 (Пн) 4:48

Адская_Капча писал(а):Спасибо, теперь понятно... видимо, буду переделывать существующие программы, ведь они через PutMem вставки формировали.

Давай-давай. А когда законичшь — напиши сюда. Я тебе скажу причину, по которой ты пойдёшь переделывать все свои программы обратно.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Queue-таймер вылетает...

Сообщение ger_kar » 07.12.2015 (Пн) 6:13

Хакер писал(а):Давай-давай. А когда законичшь — напиши сюда. Я тебе скажу причину, по которой ты пойдёшь переделывать все свои программы обратно.
А если сразу сказать? Вот прямо сейчас? Пользы то гораздо больше будет :)
Бороться и искать, найти и перепрятать

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Queue-таймер вылетает...

Сообщение Хакер » 07.12.2015 (Пн) 6:51

ger_kar писал(а):ользы то гораздо больше будет :)

Нет, тогда теряется воспитательный эффект.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Re: Queue-таймер вылетает...

Сообщение Адская_Капча » 29.05.2016 (Вс) 10:57

Как переделывать? Изображение
Почемууу Изображение

Хотя оно и верно, что надо воспитывать... Так как Адская капча еще многого не знает, словно находясь в колыбельке программирования, и сладко-сладко баится в кроватке ИзображениеИзображение

Но ведь спится-то сладко-сладко!

Пред.

Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: Google-бот, Yandex-бот и гости: 28

    TopList