Автор Тема: Помогите разобраться с функцией DllCall  (Прочитано 1023 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Vovsla [?]

  • Осваивающий
  • **
  • Сообщений: 494
  • Репутация: 25
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.14.0
Хочу сделать au3 библиотеку для работы с DISM'ом через API (DismAPI.dll)
Только не понимаю как пользоваться функцией DllCall.
Например, откуда узнать return type? В документации он не указан
https://msdn.microsoft.com/ru-ru/library/windows/desktop/hh824800(v=vs.85).aspx

Русское сообщество AutoIt

Помогите разобраться с функцией DllCall
« Отправлен: Июнь 19, 2017, 21:28:21 »

Оффлайн inververs [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 2135
  • Репутация: 459
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
Re: Помогите разобраться с функцией DllCall
« Ответ #1, Отправлен: Июнь 19, 2017, 21:33:00 »
HRESULT это и есть return type, в autoit можно просто LONG

Оффлайн Vovsla [?]

  • Осваивающий
  • **
  • Сообщений: 494

  • Автор темы
  • Репутация: 25
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.14.0
Re: Помогите разобраться с функцией DllCall
« Ответ #2, Отправлен: Июнь 19, 2017, 22:54:29 »
Спасибо.
Попробовал получить информацию об образе, как написано здесь
https://msdn.microsoft.com/ru-ru/library/windows/desktop/hh824767(v=vs.85).aspx
Код: AutoIt [Выделить]
$ImageInfo=DllCall('c:\Windows\System32\DismApi.dll', 'LONG', 'DismGetImageInfo')
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $ImageInfo = ' & $ImageInfo & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
 


получил
---------------------------
AutoIt v3: AutoIt3.exe - Ошибка приложения
---------------------------
Инструкция по адресу 0x0000000000000002 обратилась к памяти по адресу 0x0000000000000002. Память не может быть read.


"ОК" -- завершение приложения
---------------------------
ОК   
---------------------------

Пробовал так, результат такой же
Код: AutoIt [Выделить]
DllCall('c:\Windows\System32\DismApi.dll', 'LONG', 'DismDelete', 'WSTR', 'ImageInfo')
$ImageInfo=DllCall('c:\Windows\System32\DismApi.dll', 'LONG', 'DismGetImageInfo')
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $ImageInfo = ' & $ImageInfo & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
 


Что не так?

Оффлайн Prog [?]

  • Осваивающий
  • **
  • Сообщений: 265
  • Репутация: 28
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
Re: Помогите разобраться с функцией DllCall
« Ответ #3, Отправлен: Июнь 20, 2017, 00:00:23 »
Vovsla  [?]
Цитировать
Попробовал получить информацию об образе, как написано здесь
У функции три параметра, а в вашем коде их нет.

Русское сообщество AutoIt

Re: Помогите разобраться с функцией DllCall
« Ответ #3 Отправлен: Июнь 20, 2017, 00:00:23 »

Оффлайн Skif_off [?]

  • Новичок
  • *
  • Сообщений: 173
  • Репутация: 12
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.x.x
Re: Помогите разобраться с функцией DllCall
« Ответ #4, Отправлен: Июнь 20, 2017, 00:51:20 »
И, к слову, если вызов был удачен, то $ImageInfo будет массивом.

Оффлайн inververs [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 2135
  • Репутация: 459
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
Re: Помогите разобраться с функцией DllCall
« Ответ #5, Отправлен: Июнь 20, 2017, 19:08:45 »
Код: AutoIt [Выделить]
#RequireAdmin
#include <WinAPIDiag.au3>

Local Const $DISM_ONLINE_IMAGE = "DISM_{53BFAE52-B167-4E2F-A258-0A37B57FF845}"
Local Const $DISM_SESSION_DEFAULT = 0

Local $sPath = $DISM_ONLINE_IMAGE

If $sPath = $DISM_ONLINE_IMAGE And Not @AutoItX64 Then
    Exit MsgBox(16, 0, 'Running the DISM API online under WoW64 is not supported')
EndIf

Local $sLogFile = 'dismlog.txt' ;NULL for default log %windir%\Logs\DISM\dism.log
If $sLogFile And FileExists($sLogFile) Then FileDelete($sLogFile)

;~ HRESULT WINAPI DismInitialize(
;~   _In_     DismLogLevel LogLevel,
;~   _In_opt_ PCWSTR       LogFilePath,
;~   _In_opt_ PCWSTR       ScratchDirectory
;~ );
Local $aData = DllCall('DismAPI.dll', 'long', 'DismInitialize', _
    'int', 2, _
    'wstr', $sLogFile, _
    'wstr', Null)
If @error Then
    Exit _WinAPI_ShowLastError('DllCall @error = ' & @error)
EndIf
If $aData[0] < 0 Then
    Exit MsgBox(16, 'DismInitialize 0x' & Hex($aData[0]), _WinAPI_GetErrorMessage($aData[0]))
EndIf

;~ HRESULT WINAPI DismOpenSession(
;~   _In_     PCWSTR      ImagePath,
;~   _In_opt_ PCWSTR      WindowsDirectory,
;~   _In_opt_ PCWSTR      SystemDrive,
;~   _Out_    DismSession *Session
;~ );
Local $aData = DllCall('DismAPI.dll', 'long', 'DismOpenSession', _
    'wstr', $sPath, _
    'wstr', Null, _
    'wstr', Null, _
    'uint*', 0)
If @error Then
    Exit _WinAPI_ShowLastError('DllCall @error = ' & @error)
EndIf
If $aData[0] < 0 Then
    Exit MsgBox(16, 'DismOpenSession 0x' & Hex($aData[0]), _WinAPI_GetErrorMessage($aData[0]))
EndIf
Local $iDismSession = $aData[4]
MsgBox(64, 'Session = ',  $iDismSession)


;~ HRESULT WINAPI DismShutdown(void);
DllCall('DismAPI.dll', 'long', 'DismShutdown')

ShellExecute($sLogFile)
 


Оффлайн Vovsla [?]

  • Осваивающий
  • **
  • Сообщений: 494

  • Автор темы
  • Репутация: 25
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.14.0
Re: Помогите разобраться с функцией DllCall
« Ответ #6, Отправлен: Июнь 20, 2017, 23:03:14 »
DismInitialize может возвращать значения:
Returns S_OK on success.
Returns DISMAPI_E_DISMAPI_ALREADY_INITIALIZED if DismInitialize has already been called by the process without a matching call to DismShutdown.
Returns HRESULT_FROM_WIN32(ERROR_ELEVATION_REQUIRED) if the process is not elevated.

Размерность массива $aData = 4
$aData[0] = 0 или 1, я правильно понимаю что это и есть S_OK или DISMAPI_E_DISMAPI_ALREADY_INITIALIZED ?
$aData[0] будет меньше чем 0 если функция вообще не отработает?
$aData[1] всегда = 2, что это значит?
Почему $aData[2] и $aData[3] всегда пустые?

Оффлайн Prog [?]

  • Осваивающий
  • **
  • Сообщений: 265
  • Репутация: 28
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
Re: Помогите разобраться с функцией DllCall
« Ответ #7, Отправлен: Июнь 21, 2017, 00:06:59 »
Vovsla  [?]
Цитировать
$aData[1] всегда = 2, что это значит?
Почему $aData[2] и $aData[3] всегда пустые?
http://autoit-script.ru/autoit3_docs/functions/DllCall.htm
Цитировать
Если вызов функции вызвал сбой, то @error устанавливается в 1. Иначе возвращается массив, который содержит возвращаемое функцией значение и копирует все параметры (включая параметры, которые функция может изменить при передаче ссылок).
$return[0] = возвращаемое значение функции
$return[1] = параметр_1
$return[2] = параметр_2
 ...
$return[n] = параметр_n

Русское сообщество AutoIt

Re: Помогите разобраться с функцией DllCall
« Ответ #7 Отправлен: Июнь 21, 2017, 00:06:59 »

Оффлайн inververs [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 2135
  • Репутация: 459
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
Re: Помогите разобраться с функцией DllCall
« Ответ #8, Отправлен: Июнь 21, 2017, 08:17:38 »
Vovsla  [?]
Цитировать
DismInitialize может возвращать значения:
Да, может, а может другие WINAPI ошибки, но это не точно, в общем случае всегда нужно смотреть на тип возвращаемого значения, а это нулевой параметр.
Все эти DISMAPI_E_DISMAPI_ALREADY_INITIALIZED или ERROR_ELEVATION_REQUIRED это цифровые константы, но в документации microsoft никогда, (очень редко) не пишет их значения. Нужно скачивать SDK или пользоваться гуглом для поиска. Вот, например, парочка констант:
DISMAPI_E_DISMAPI_ALREADY_INITIALIZED = 1, ERROR_ELEVATION_REQUIRED = 0x800702E4, S_OK = 0
Если функция выполнилась как задумано - она должна возвращать S_OK. НО! Это все актуально если тип возвращаемого = HRESULT
Если бы функция возвращала BOOL, то в случае успеха она бы возвращала 1, а в случае ошибки 0.

Цитировать
Размерность массива $aData = 4
Да, DLLCall всегда возвращает массив! Но, только в том случае, если @error равен 0, в документации так и написано:
Успех: @error = 0.
Ошибка: Устанавливает @error
@error: 1 - невозможно использовать файл DLL,
2 неизвестный возвращаемый тип (return type).
3 функция не найдена в файле DLL.
4 неверное количество параметров.
5 неверный параметр.
Если вы ошибаетесь в количестве параметров, или имени функции, то сломаетесь еще до момента проверки результата, поэтому всегда сперва проверяется флаг @error и только затем сам результат. Как только функция отлажена, и вы уверены что правильно вызываете, то можно проверку на @error убирать. Но обычно оставляют.

Цитировать
$aData[1] всегда = 2, что это значит?
Смотрите, DLLCall вызывает функцию, которая может возвращать значения. Она может возвратить ноль, одно, два, три и так далее. Как быть и как их все получить? В других языках такие возвращаемые значения передаются в переменных по ссылкам, но не в AutoIT (с 1 исключением, struct* заполняются сами). В AutoIT подумали и решили, все, что попадает в функцию и все то, что она возвращает - возвращать в виде массива! Так и получается, сколько у функции параметров - такой и размер массива. Результат - нулевой параметр - он всегда в [ 0], в [1] - первый параметр, В [2] и [3] второй и третий параметр функции.

Почему в [1] стоит 2 - я сам туда ее передал.  ;)

С этой функцией все просто,  все параметры - входящие, не очень интересно, посмотри на
HRESULT WINAPI DismOpenSession(
  _In_     PCWSTR      ImagePath,
  _In_opt_ PCWSTR      WindowsDirectory,
  _In_opt_ PCWSTR      SystemDrive,
  _Out_    DismSession *Session
);
4 параметр(_Out_    DismSession *Session) записан как _Out_ - именно в него функция запишет результат, его можно получить как $aData[4], и т.к он параметр OUT или то, что он в документации *Session, то записывается со звездочкой в конце ('uint*', 0).
Там записан 0, т.к синтаксис требует передачу чего то. Чего - то у нас обычно либо NULL либо 0, а еще потому - что это параметр ТОЛЬКО выходной, функция вообще его не читает, ты можешь туда передавать 123124123 например, но это не разумно, поэтому 0.

Бывает, что параметр одновременно и входящий и выходящий _Inout_ тогда то, что туда передано имеет значение - нужно читать документацию.
Бывают еще _In_opt_ - входящий не обязательный, _Out_opt_ выходящий  не обязательный итп.
« Последнее редактирование: Июнь 21, 2017, 08:48:57 от inververs »

Оффлайн sngr [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 838
  • Репутация: 347
    • Награды
  • Версия AutoIt: 3.3.8.1
Re: Помогите разобраться с функцией DllCall
« Ответ #9, Отправлен: Июнь 21, 2017, 09:40:58 »
Vovsla
Чтоб разобраться с dllcall тебе нужно открыть папку include и смотреть как там умелые люди им пользуются:
Код: AutoIt [Выделить]
    $tICONINFO = DllStructCreate($tagICONINFO)
    $Ret = DllCall('user32.dll', 'int', 'GetIconInfo', 'ptr', $hIcon, 'ptr', DllStructGetPtr($tICONINFO))
    If (@error) Or (Not $Ret[0]) Then
        Return SetError(1, 0, 0)
    EndIf

вот тебе передача в функцию структуры, вот тебе проверка ошибок.

Оффлайн Vovsla [?]

  • Осваивающий
  • **
  • Сообщений: 494

  • Автор темы
  • Репутация: 25
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.14.0
Re: Помогите разобраться с функцией DllCall
« Ответ #10, Отправлен: Июнь 21, 2017, 22:59:40 »
Большое спасибо за подробное разъяснение.
На странице DismInitialize написано, что данную функцию нужно вызывать перед любой другой. Но почему-то в примерах данная функция не используется https://msdn.microsoft.com/ru-ru/library/windows/desktop/hh824747(v=vs.85).aspx
Все же нужна эта функция или нет? И как Вы про нее узнали? Я не нашел упоминаний про данную функцию в других функциях.

Оффлайн Alofa [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 1108
  • Репутация: 155
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
Re: Помогите разобраться с функцией DllCall
« Ответ #11, Отправлен: Июнь 21, 2017, 23:42:48 »
... в примерах данная функция не используется https://msdn.microsoft.com/ru-ru/library/windows/desktop/hh824747(v=vs.85).aspx
Вы уверены?

... Все же нужна эта функция или нет?
Прислушайтесь к совету sngr:
... открыть папку include и смотреть...

К примеру:
Код: AutoIt [Выделить]

Оффлайн inververs [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 2135
  • Репутация: 459
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
Re: Помогите разобраться с функцией DllCall
« Ответ #12, Отправлен: Июнь 22, 2017, 11:13:21 »
Vovsla  [?]
Цитировать
Но почему-то в примерах данная функция не используется https://msdn.microsoft.com/ru-ru/library/windows/desktop/hh824747(v=vs.85).aspx
Вот ты странный:
Не поленился, захожу по первой же ссылке в Basic DISM API Sample и эта функция вызывается  в самом начале, одной из первых.. даже не пришлось листать страницу..


Внимание: Для просмотра прикреплённых файлов необходимо Войти или Зарегистрироваться

Оффлайн Vovsla [?]

  • Осваивающий
  • **
  • Сообщений: 494

  • Автор темы
  • Репутация: 25
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.14.0
Re: Помогите разобраться с функцией DllCall
« Ответ #13, Отправлен: Июнь 23, 2017, 17:18:08 »
Да, извиняюсь, не заметил


Добавлено: Июнь 23, 2017, 18:54:57
Я правильно понимаю, что в DismGetImageInfo нужно создавать структуру?
https://msdn.microsoft.com/ru-ru/library/windows/desktop/hh824767(v=vs.85).aspx

Но почему-то когда я указываю тип данных struct, то появляется ошибка
Я правильно создаю структуру? Или ее нужно создать полностью, иначе не будет работать?
Код: AutoIt [Выделить]
Global Const $tagDismImageInfo='struct; UINT ImageIndex; wstr ImageIndex; (и т.д.)  endstruct' ;
$DismImageInfo=DllStructCreate($tagDismImageInfo)

Func DismGetImageInfo($ImageFilePath) ; в разработке
    $DismImageInfo=DllStructCreate($tagDismImageInfo)
    $Result=DllCall('DismAPI.dll', 'long', 'DismGetImageInfo', _
                    'wstr', $ImageFilePath, _
                    'struct*', $DismImageInfo, _
                    'uint*', 0)

    If @error Then Return DISMErrorMessage('ShowLastError', 'DismGetImageInfo', @error)
    If $Result[0]<0 Then Return DISMErrorMessage('GetErrorMessage', 'DismGetImageInfo', $Result[0])
EndFunc
 


Если вместо struct указать int или uint, то ошибки нет, но возвращается просто число



Добавлено: Июнь 23, 2017, 19:40:40
Кстати, DismLanguage тоже структура. Не понятно, как использовать структуру в структуре?
« Последнее редактирование: Июнь 23, 2017, 19:40:40 от Vovsla, Причина: Объединение сообщений »

Оффлайн Garrett [?]

  • Глобальный модератор
  • *
  • Сообщений: 3862
  • Репутация: 955
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.14.0
Re: Помогите разобраться с функцией DllCall
« Ответ #14, Отправлен: Июнь 23, 2017, 20:49:01 »
Vovsla
Не проверял, написал навскидку.
(нажмите для показа/скрытия)

Скорблю и помню.




Русское сообщество AutoIt

Re: Помогите разобраться с функцией DllCall
« Ответ #14 Отправлен: Июнь 23, 2017, 20:49:01 »

 

Похожие темы

  Тема / Автор Ответов Последний ответ
2 Ответов
3268 Просмотров
Последний ответ Март 28, 2011, 12:13:18
от Sergey2210
15 Ответов
4137 Просмотров
Последний ответ Июнь 30, 2013, 21:02:12
от mef-t
4 Ответов
1858 Просмотров
Последний ответ Август 14, 2013, 06:19:11
от mef-t
9 Ответов
3250 Просмотров
Последний ответ Декабрь 16, 2013, 01:38:58
от Garrett
0 Ответов
994 Просмотров
Последний ответ Декабрь 14, 2013, 08:49:11
от madmasles
3 Ответов
1726 Просмотров
Последний ответ Февраль 23, 2014, 14:13:50
от Trans
1 Ответов
725 Просмотров
Последний ответ Август 05, 2014, 13:00:08
от madmasles
1 Ответов
1241 Просмотров
Последний ответ Октябрь 05, 2014, 17:11:47
от Dm666
1 Ответов
538 Просмотров
Последний ответ Август 05, 2015, 00:57:26
от firex
0 Ответов
854 Просмотров
Последний ответ Сентябрь 12, 2016, 06:09:48
от DezmontDeXa