Что нового

Помогите разобраться с функцией DllCall

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
HRESULT это и есть return type, в autoit можно просто LONG
 
Автор
V

vovsla

Осваивающий
Сообщения
607
Репутация
36
Спасибо.
Попробовал получить информацию об образе, как написано здесь
https://msdn.microsoft.com/ru-ru/library/windows/desktop/hh824767(v=vs.85).aspx
Код:
$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.


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

Пробовал так, результат такой же
Код:
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


Что не так?
 

Skif_off

Знающий
Сообщения
173
Репутация
12
И, к слову, если вызов был удачен, то $ImageInfo будет массивом.
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Код:
#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)
 
Автор
V

vovsla

Осваивающий
Сообщения
607
Репутация
36
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

Продвинутый
Сообщения
537
Репутация
65
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
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
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_ выходящий не обязательный итп.
 

sngr

AutoIT Гуру
Сообщения
1,010
Репутация
408
Vovsla
Чтоб разобраться с dllcall тебе нужно открыть папку include и смотреть как там умелые люди им пользуются:
Код:
$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

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

vovsla

Осваивающий
Сообщения
607
Репутация
36
Большое спасибо за подробное разъяснение.
На странице DismInitialize написано, что данную функцию нужно вызывать перед любой другой. Но почему-то в примерах данная функция не используется https://msdn.microsoft.com/ru-ru/library/windows/desktop/hh824747(v=vs.85).aspx
Все же нужна эта функция или нет? И как Вы про нее узнали? Я не нашел упоминаний про данную функцию в других функциях.
 
A

Alofa

Гость
Vovsla сказал(а):
... в примерах данная функция не используется https://msdn.microsoft.com/ru-ru/library/windows/desktop/hh824747(v=vs.85).aspx
Вы уверены?

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

К примеру:
Код:
_Crypt_Startup()
_GDIPlus_Startup()
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Vovsla [?]
Но почему-то в примерах данная функция не используется https://msdn.microsoft.com/ru-ru/library/windows/desktop/hh824747(v=vs.85).aspx
Вот ты странный:
Не поленился, захожу по первой же ссылке в Basic DISM API Sample и эта функция вызывается в самом начале, одной из первых.. даже не пришлось листать страницу..
 

Вложения

  • Снимок.PNG
    Снимок.PNG
    53.3 КБ · Просмотры: 19
Автор
V

vovsla

Осваивающий
Сообщения
607
Репутация
36
Да, извиняюсь, не заметил


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

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

Но почему-то когда я указываю тип данных struct, то появляется ошибка
Я правильно создаю структуру? Или ее нужно создать полностью, иначе не будет работать?
Код:
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, то ошибки нет, но возвращается просто число



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

Кстати, DismLanguage тоже структура. Не понятно, как использовать структуру в структуре?
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
Vovsla
Не проверял, написал навскидку.
Код:
Global Const $tagDismImageInfo = _
    "int    ImageType;" _
   &"uint   ImageIndex;" _
   &"ptr    ImageName;" _
   &"ptr    ImageDescription;" _
   &"uint64 ImageSize;" _
   &"uint   Architecture;" _
   &"ptr    ProductName;" _
   &"ptr    EditionId;" _
   &"ptr    InstallationType;" _
   &"ptr    Hal;" _
   &"ptr    ProductType;" _
   &"ptr    ProductSuite;" _
   &"uint   MajorVersion;" _
   &"uint   MinorVersion;" _
   &"uint   Build;" _
   &"uint   SpBuild;" _
   &"uint   SpLevel;" _
   &"int    Bootable;" _
   &"ptr    SystemRoot;" _
   &"ptr    Language;" _
   &"uint   LanguageCount;" _
   &"uint   DefaultLanguageIndex;" _
   &"ptr    CustomizedInfo;"


; DismImageType
Global Const $DismImageTypeUnsupported = -1
Global Const $DismImageTypeWim = 0
Global Const $DismImageTypeVhd = 1

; DismImageBootable
Global Const $DismImageBootableYes = 0
Global Const $DismImageBootableNo = 1
Global Const $DismImageBootableUnknown = 2

$sImageFilePath = "filename.wim"

$hDismImageInfo = _DismGetImageInfo($sImageFilePath)
; @extended - Число возвращаемых структур DismImageInfo.
$iSize = @extended
$pArrayDismImageInfo = DllStructCreate('ptr['& $iSize &'];', $hDismImageInfo)

Local $aDismImageInfo[$iSize]

For $i = 0 To $iSize -1
   $aDismImageInfo[$i] = DllStructCreate($tagDismImageInfo, DllStructGetData($pArrayDismImageInfo, 1, $i+1))
Next

ConsoleWrite(StringFormat('> ImageType: %d\n', DllStructGetData($aDismImageInfo[0], 'ImageType')))
; ConsoleWrite(StringFormat('> ImageType: %d\n', DllStructGetData($aDismImageInfo[1], 'ImageType')))
; и т.д.
#Region

Func _DismGetImageInfo($sImageFilePath)

   $aRet = DllCall('dismapi.dll', 'int', 'DismGetImageInfo', _
				   'wstr', $sImageFilePath, _
				   'ptr*', 0, _
				   'uint*', 0)

   If @error Or $aRet[0] <> 0 Then
;~ 	  ConsoleWrite(StringFormat('! Error: function DismGetImageInfo return (%s)\n', (@error <> 0)? ('@error: '& @error) : ('$aRet: '& $aRet[0])))
	  Return SetError(1, 0, 0)
   EndIf

;~    ConsoleWrite(StringFormat('! Error: function DismGetImageInfo return (%s)\n', _
;~ 		   				    ('$aRet[0]: ' & $aRet[0] & '$aRet[2]: ' & $aRet[2] & '$aRet[3]: ' & $aRet[3])))
   Return SetError($aRet[0], $aRet[3], $aRet[2])
EndFunc ;==> _DismGetImageInfo

#EndRegion
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Vovsla [?]
Но почему-то когда я указываю тип данных struct, то появляется ошибка
Если struct то всегда struct* без исключений.

Но в этой функции нужно не struct* а ptr*

Я правильно создаю структуру?
Нет не правильно, wstr тип не поддерживается. Смотрите в справке в DllStructCreate
 
Верх