Что нового

Работа с DLL: Как отправить в DLL-файл (фукцию) значение и вернуть обратно?

Автор
K

Kalisnik

Эволюция
Сообщения
295
Репутация
63
OffTopic:

А мне PureBasic понравился. После мозгового штурма и тотального перестроения нервных цепей головного мозга, кодить в нем мне стало довольно комфортно. С AutoIt я вообще обленился - это как роскошный, шикарный автомобиль, обшитый мехом и кожей. После которого действительно нет ни какого желания пересаживаться в неудобный и жесткий спортивный болид - но иногда потребность возникает. Я вот уже несколько месяцев смотрю на С, но так пока и не решился к нему подойти. Посмотрю-посмотрю, глазки друг другу построим, и снова сажусь в AutoIt. :D Так что здесь меня выручает PureBasic. Когда нужна скорость, пишешь на нем dll-библиотечку, вставляешь эту груду неотесанных лошадок под капот уже практически ставшего родным AutoIt, и "летаешь" с комфортом. :laugh:
 

xahik

Новичок
Сообщения
6
Репутация
1
asdf8 сказал(а):
судя по скудному набору функций для работы с массивами и практически все эти функции корректно работают только с одномерными массивами.
Почему вы так решили?
Размер массива можно узнать с помощью функции ArraySize и эта функция работает с многомерными массивами!
Код:
Dim MyArray(10, 20, 30, 40)
Debug ArraySize(MyArray(),1)
Debug ArraySize(MyArray(),2)
Debug ArraySize(MyArray(),3)
Debug ArraySize(MyArray(),4)

Вот передача массива в процедуру.
Обратите внимание что массив многомерный и явно не передается его размер.
Код:
Procedure fill(Array A.l(2))  ; the 1 stays for the number of dimensions in the array
  x1=ArraySize(A(),1)
  x2=ArraySize(A(),2)
  y=0
  For i = 0 To x1
    For z = 0 To x2
      A(i, z) = y
      y + 1
    Next z
  Next i
EndProcedure

Dim A.l(10, 20)
fill(A())  ; the array A() will be passed as parameter here

Debug A(5, 1)
Debug A(10, 2)


Yashied сказал(а):
Я, после того, как написал Copy UDF, забил на этот PureBasic.
Посмотрел исходник...
И честно не мог понять зачем WinAPI функции непосредственно вызывать из системных DLL?
Ведь это:
Код:
CallFunction(Kernel, "CopyFileExW", *Param\Source, *Param\Destination, *Param\Proc, *Param\Ptr, *Param\Cancel, *Param\Flags)
Можно было бы записать так:
Код:
CopyFileEx_(*Param\Source, *Param\Destination, *Param\Proc, *Param\Ptr, *Param\Cancel, *Param\Flags)

Зачем было самостоятельно выделять память под структуру
Код:
*Param.Parameters = AllocateMemory(SizeOf(Parameters))
если можно было бы без этого обойтись?

Еще там есть такие строки:
Код:
SourceLen.l = 2 * (CallFunction(Kernel, "lstrlenW", *Source) + 1)
	DestinationLen.l = 2 * (CallFunction(Kernel, "lstrlenW", *Destination) + 1)
Почему бы не сделать так?
Код:
SourceLen = MemoryStringLength(*Source, #PB_Unicode)
DestinationLen = MemoryStringLength(*Destination, #PB_Unicode)

В общем, не были использованы все возможности PureBasic и многое сделано через :-[
Возможно поэтому показалось что все так сложно!


Yashied сказал(а):
Постоянная каша с определением типов через "." просто убивает...
Переменные по умолчанию имеют тип Integer (4 байта для x86 и 8 байт для x64, знаковые положительные и отрицательные числа).
Тип переменной нужно указать только один раз при ее первом использовании.

Yashied сказал(а):
А о "гаджетах" я вообще лучше промолчу. А еще там очень бестолковая справка. Вроде, на первй взгляд, все, что необходимо, написано, красиво оформлена, а на деле от нее очень мало толку.
А что с гаджетами не так?
Они используются при создании оконного интерфейса в программах (в некоторых других средах из называют контролами).
По моему, справка оформлена нормально, все отсортировано по разделам, есть перекрестные ссылки при описании взаимосвязанных функций.

Yashied сказал(а):
Например, попробуйте написать на C# или том же PB функцию WinWait()...
:smile:

Если сделать так чтобы лишь работало, то код будет таким:
Код:
Procedure WinWait(Title.s, Timeout)
  Delay(Timeout)
  ProcedureReturn  FindWindow_(0, Title)
EndProcedure
 
Debug WinWait("Диспетчер задач Windows", 100)

А вот так по правилам, с точной выдержкой таймаута:
Код:
Procedure WinWait(Title.s, Timeout)
  result=0
  TimeStart = ElapsedMilliseconds()
  Repeat
    HWND=FindWindow_(0, Title)
    If HWND
      result=HWND : Break
    Else : Delay(2)
    EndIf
  Until ElapsedMilliseconds()-TimeStart > Timeout
  ProcedureReturn  result
 EndProcedure
 
 Debug WinWait("Диспетчер задач Windows", 100)
 

asdf8

Скриптер
Сообщения
564
Репутация
152
xahik
Вот передача массива в процедуру.
Обратите внимание что массив многомерный и явно не передается его размер.
зачем подменять понятия? Речь шла о передачи массива в dll.

судя по скудному набору функций для работы с массивами и практически все эти функции корректно работают только с одномерными массивами.
Почему вы так решили?

можно тогда поподробнее - почему SortArray работает с многомерным массивом, как с одномерным, а ReDim для многомерных массивов позволяет изменить только размерность массива, но не кол-во элементов в первом измерении?
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
xahik сказал(а):
Можно было бы записать так:
Код:
CopyFileEx_(*Param\Source, *Param\Destination, *Param\Proc, *Param\Ptr, *Param\Cancel, *Param\Flags)

Потому что в справке я этого не нашел.

xahik сказал(а):
в некоторых других средах из называют контролами

Самое главное, что они в MSDN называются "Controls".

xahik сказал(а):
По моему, справка оформлена нормально, все отсортировано по разделам, есть перекрестные ссылки при описании взаимосвязанных функций.

В справке к AutoIt есть примеры ко всем родным функциям и иногда даже с пояснениями (например Bit... функции). В PureBasic, да, справка аккуратная, с перекрестными ссылками, но после ее прочтения остается очень много вопросов. Примеров (тем более толковых) кот наплакал. К слову, когда я начинал изучать AutoIt, то в течение ~года, мне было достаточно только одной лишь справки. Я даже о существовании форума не знал. Еще пример хорошей справки - InnoSetup.

xahik сказал(а):
А что с гаджетами не так?

Идеологически неверный подход. Почему я должен сам задавать ID для гаджетов и помнить их, вместо того, чтобы их (ID) возвращала сама функция? Почему название функций для работы с гаджетами называются так по дурацки? Например, почему GadgetID(), а не GadgetHandle() или GadgetGetHandle()? То, что возвращает эта функция, везде называется "Handle", а не ID. ID, это совсем другое, это то, что возвращает API функция GetDlgCtrlID(). Все это и многое другое сильно "травмируют" начинающего пользователя, и если он решит перейти на другой ЯП (а это непременно случиться), то ему придется все понятия изучать заново.

xahik сказал(а):
Переменные по умолчанию имеют тип Integer (4 байта для x86 и 8 байт для x64, знаковые положительные и отрицательные числа).

IMHO, полная глупость. Должно быть "l", а не "плавающий" тип. Да и вообще, если уж используются типы, то они не должны отличаться от оных в MSDN. BYTE - это unsigned char, почему в PB он определеи как signed char? Тип INT всегда signed integer (4 байта), почему в PB он используется как PTR? Ну, и т.д.

xahik сказал(а):
А вот так по правилам, с точной выдержкой таймаута...

Параметр "Title" может содержать еще и класс, и т.д., или может быть хендлом. А еще есть параметр "Text" и опция "WinTitleMatchMode"...
 

asdf8

Скриптер
Сообщения
564
Репутация
152
если уж используются типы, то они не должны отличаться от оных в MSDN

Yashied

мне кажется это побочный эффект мультиплатформенности, аналогичный случай с проектом SciTE-Ru - хотят, чтобы работало у всех, ограничивают возможности для всех и все равно - больше всех достается тем, кто сидит на окнах.
 

xahik

Новичок
Сообщения
6
Репутация
1
Yashied сказал(а):
Примеров (тем более толковых) кот наплакал.
Вот почти 2000 примеров http://www.purearea.net/pb/download/CodeArchiv_v4-Beta.rar

Yashied сказал(а):
Почему я должен сам задавать ID для гаджетов и помнить их, вместо того, чтобы их (ID) возвращала сама функция?
В место идентификатора, используйте константу #PB_Any и тогда функция сама будет возвращать свой идентификатор.
Это касается, не только гаджетов, но и файлов, рисунков и т. д.

Yashied сказал(а):
Должно быть "l", а не "плавающий" тип.
Пожалуйста!
Добавьте строку
Код:
Define.l
в начало программы и по умолчанию будет тип LONG

Yashied сказал(а):
Параметр "Title" может содержать еще и класс
Тоже не проблема.
Код:
Procedure WinWait(Title.s, ClassName.s, Timeout)
  Delay(Timeout)
  ProcedureReturn  FindWindow_(ClassName, Title)
EndProcedure
 
Debug WinWait("Диспетчер задач Windows", "#32770", 100)
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
xahik сказал(а):
Вот почти 2000 примеров http://www.purearea.net/pb/download/CodeArchiv_v4-Beta.rar

Спасибо, но у меня его антивирус не пропускает. CAV.exe содержит вирус... Это только у меня?

:(

P.S

Да, похоже только у меня (Avast5). Хорошие примеры.

:smile:
 

Suppir

Продвинутый
Сообщения
967
Репутация
62
Забавный момент: я думал, что передаваемая с помощью DllCall переменная с типом Str ограничена 32 kb в размере. Оказалось, что и несколько мегабайт можно передать и получить обратно.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Suppir сказал(а):
Забавный момент: я думал, что передаваемая с помощью DllCall переменная с типом Str ограничена 32 kb в размере. Оказалось, что и несколько мегабайт можно передать и получить обратно.

Передается не тип STR, а тип PTR. При передаче в функцию строки с помощью DllCall(), автоматически создается структура "char" и копируется туда строка. А в функцию передается указатель - DllStructGetPtr(). Следующие два фрагмента эквивалентны.

Код:
DllCall('kernel32.dll', 'int', 'SetCurrentDirectoryW', 'wstr', @ScriptDir)


Код:
$tDir = DllStructCreate('wchar[' & (StringLen(@ScriptDir) + 1) & ']')
DllStructSetData($tDir, 1, @ScriptDir)
DllCall('kernel32.dll', 'bool', 'SetCurrentDirectoryW', 'ptr', DllStructGetPtr($tDir))


P.S

Строки ограничены 2147483647 символами (2 ГБ для Unicode).
 

xahik

Новичок
Сообщения
6
Репутация
1
CAV.exe это не вирус а проводник ко каталогу исходных текстов.
 

Suppir

Продвинутый
Сообщения
967
Репутация
62
Ребята, вопрос насчет dll и autoit.

Пишу в c#:

Код:
using System;
using System.Collections.Generic;

namespace summ
{
	public class MyClass
	{
	
		public static int Add(int a, int b)
		{
			return (a + b);
		
		}
	}
}



генерирую dll. Потом пишу в au3:

Код:
$res = DllCall("summ.dll", "int", "MyClass.Add", "int", "2", "int", "5")
ConsoleWrite($res[0])


Однако выдает ошибку (subscript used with non-array variable - в общем, не отработал dllCall). В чем здесь может быть проблема?
 

xahik

Новичок
Сообщения
6
Репутация
1
Suppir сказал(а):
Ребята, вопрос насчет dll и autoit.

Пишу в c#:


Однако выдает ошибку (subscript used with non-array variable - в общем, не отработал dllCall). В чем здесь может быть проблема?
Может быть потому что C# создает управляемый код?
Создал подобную DLL и нет этой ошибки.

Код:
ProcedureDLL Add(a, b)
  ProcedureReturn a + b
EndProcedure

Код:
$res = DllCall("summ.dll", "int", "Add", "int", "2", "int", "5")
ConsoleWrite($res[0])
 
Автор
K

Kalisnik

Эволюция
Сообщения
295
Репутация
63
Может так?
Код:
$res = DllCall("summ.dll", "int:cdecl", "MyClass.Add", "int", "2", "int", "5")
ConsoleWrite($res[0])
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Suppir сказал(а):
Однако выдает ошибку (subscript used with non-array variable - в общем, не отработал dllCall). В чем здесь может быть проблема?

Прежде, чем задавать вопрос, нужно было проверить, почему DllCall() не отрабатывает.

Код:
$res = DllCall("summ.dll", "int", "MyClass.Add", "int", 2, "int", 5)
If @error Then
	ConsoleWrite('ERROR: ' & @error)
Else
	ConsoleWrite('OK: ' & $res[0])
EndIf
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
xahik сказал(а):
Создал подобную DLL и нет этой ошибки.

Код:
ProcedureDLL Add(a, b)
  ProcedureReturn a + b
EndProcedure

Код:
$res = DllCall("summ.dll", "int", "Add", "int", "2", "int", "5")
ConsoleWrite($res[0])

Скажи пожалуйста, какой тип в этом случае будет у "a" и "b"? "i"? Если так, то по идее, это не должно работать в x64, и нужно писать так:

Код:
DllCall("summ.dll", "int_ptr", "Add", "int_ptr", "2", "int_ptr", "5")
 

Suppir

Продвинутый
Сообщения
967
Репутация
62
Yashied [?]
режде, чем задавать вопрос, нужно было проверить, почему DllCall() не отрабатывает.

Пишет error 3. ( "function" not found in the DLL file).


Похоже что да, c# создает управляемый код. Прежде чем использовать функции из dll, эту dll необходимо зарегистрировать в системе. Буду разбираться...


Добавлено:
Сообщение автоматически объединено:

xahik [?]
Может быть потому что C# создает управляемый код?Создал подобную DLL и нет этой ошибки.

Потому что вы создаете в PureBasic. Там dll-ки сразу работают.


Добавлено:
Сообщение автоматически объединено:

Kalisnik [?]
Может так?Код: AutoIt [Выделить]$res = DllCall("summ.dll", "int:cdecl", "MyClass.Add", "int", "2", "int", "5")ConsoleWrite($res[0])



Так тоже выдает error 3. Просто DllCall не может найти функцию в dll.


В общем, сейчас передо мной стоит задача:
написать на c# dll, которая складывала бы два числа. А потом вызвать эту функцию из AutoIt.





Добавлено:
Сообщение автоматически объединено:

Попробовал зарегистрировать dll:

Код:
ShellExecute("regsvr32.exe", @ScriptDir & "\summ.dll")

$res = DllCall("summ.dll", "int", "MyClass.Add", "int", 2, "int", 5)
If @error Then
    ConsoleWrite('ERROR: ' & @error)
Else
    ConsoleWrite('OK: ' & $res[0])
EndIf


Однако пишет: summ.dll была загружена, но найти точку входа для DllRegister не удалось :(
 

Suppir

Продвинутый
Сообщения
967
Репутация
62
xahik
не работает. Насколько я понял, чтобы работать с dll, написанными на .NET, их сначала нужно зарегистрировать в системе.
 

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
Прочитал тему и решил чуть-чуть поизучать pure basic,хочу написать dll для разшифрования пароля передоваемым в эту dll и если приложение которое вызывает эту dll = exe то отправляет расшифрованный пароль,если же нет то рэндомно не правильные значения,скажите,восможно ли узнать расширение того файла который вызывает эту dll? Чуть не забыл,где можно взять русскую справку по PB?

мда... на 2х форумах по PureBasic не отвечают,может все сговорились там?
 
Верх