Что нового

Возможно ли динамическое изменение #include ?

Suppir

Продвинутый
Сообщения
967
Репутация
62
Добрый день!

Есть основная программа, скомпилированная в .exe (у пользователей не стоит AutoIt). Я хочу дать возможность продвинутым пользователям дописывать свои функции к этой программе (в формате .au3). При этом не хочу раскрывать код основной программы.

Возможно ли сделать так, чтобы основная программа (которая в .exe) автоматически определяла в своей директории все файлы с расширением .au3 и при запуске подключала бы их в качестве своих модулей с помощью #include "имя файла.au3"?

В описании сказано, что #include не может использовать переменные (только строки).

Сначала я думал создать пользовательский файл, скажем user_func.au3, который прописать в include основной программы. Но дело в том, что пользовательские функции получаются довольно длинные (и при этом очень похожие). Поэтому, когда они все в одном файле, можно легко запутаться :wacko:. Гораздо удобней их держать в разных файлах.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
#Include<> обрабатывается на стадии компиляции, поэтому твоя затея в чистом виде не реализуема. Но ты можешь использовать Execute()...

Или другим способом:

Код:
Global Const $AutoIt3 = @TempDir & '\AutoIt3.exe'
Global Const $MyScript = @TempDir & '\MyScript.tmp'

FileInstall(@AutoItExe, $AutoIt3, 1)

$Pid = Run($AutoIt3 & ' /ErrorStdOut ' & $MyScript, '', @SW_HIDE, $STDOUT_CHILD)
If @error Then
	MsgBox(0, '', 'Error!')
Else
	Sleep(100)
	Do
		$Data = StdoutRead($Pid)
		If $Data > '' Then
			MsgBox(0, '', 'Error!')
			ExitLoop
		EndIf
	Until @error
	MsgBox(0, '', 'OK')
EndIf

FileDelete($AutoIt3)
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
В хелпе написано, что для FileInstall ( "source", "dest" [, flag] )
source обязательно должен быть строкой (не переменной).

execute() не подойдет, потому что каждая функция примерно на 2 - 3 страницы.

Что-то я не очень понял код. А именно, что мы запускаем с помощью Run?
 

snoitaleR

AutoIT Гуру
Сообщения
855
Репутация
223
Suppir
А что, если в основной программе подключить постоянный .au3 и держать этот постоянный .au3 в открытом виде для возможности изменять в нем #include "xxx"?
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
snoitaleR, я написал про этот вариант в первом посте. Но, просто, это очень неудобно.
По сути, пользователи пишут функции по одному шаблону с небольшими различиями, со своей спецификой. И если 5 - 6 функций запихнуть в один файл, то он уже становится нечитабельным. А предполагается, что пользователь может прописать 15 - 20 функций. Поэтому хочу эти пользовательские функции держать в разных файлах .au3
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
snoitaleR сказал(а):
А что, если в основной программе подключить постоянный .au3 и держать этот постоянный .au3 в открытом виде для возможности изменять в нем #include "xxx"?

Не получится, т.к. речь идет о скомпилированном файле.

Suppir сказал(а):
А именно, что мы запускаем с помощью Run?

Мы присоединяем файл AutoIt3.exe к нашему скомпилированному EXE-шнику. И далее запускаем любой код, в данном примере из файла MyScript.tmp на выполнение. Ну а внутри этого файла можешь написать сколько угодно #Include<> с соответствующими путями, это обычный AU3-файл.


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

Suppir [?]
В хелпе написано, что для FileInstall ( "source", "dest" [, flag] )source обязательно должен быть строкой (не переменной).

:smile:

Ну значит нужно явно указать путь для AutoIt3.exe.
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
Yashied, т.е. в этом случае размер exe-шника будет большой?
*Но нужно попробовать*


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

Дело в том, что у пользователей нет AutoIt (не установлен)
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Suppir [?]
Дело в том, что у пользователей нет AutoIt (не установлен)

Именно поэтому я его и включаю в EXE-файл. Далее распаковываю во временную папку и от туда запускаю на выполнение нужный код.
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
Хорошо, я попробую этот вариант, спасибо.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
У меня на этом принципе работает 3D Axis.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
Yashied [?]
Именно по этому я его и включаю в EXE-файл
После компиляций сам скрипт содержит уже в себе интерпритатор, т.е @AutoItExe включать не нужно, а просто указать на сам exe-шник скрипта (с теми же параметрами).

Suppir
На данный момент твоя задумка не реализуема, я в своё время использовал некий самодельный модуль плагинов. Работает это так:

Основной скрипт:
Код:
Global $aUDF_Modules[100]

_UDFsModuleInclude(@ScriptDir & "\External_UDFs.fnc")
_UDFsModuleInclude(@ScriptDir & "\Other_UDFs.fnc")

$vRet = _UDFsModuleExecuteFunction("Some_UDF", "Are you sure?")
MsgBox(64, "", "Returned Message from Some_UDF: " & $vRet)

$vRet = _UDFsModuleExecuteFunction("Other_UDF", "Notepad.exe") ;Run the notepad
MsgBox(64, "", "Returned Message from Other_UDF: " & $vRet)

Func _UDFsModuleExecuteFunction($sFuncName, $sParams="")
	Local $sUDFs_Module = "", $sRead_UDFs_Module = "", $sCmdLine_Parser
	
	For $i = 1 To $aUDF_Modules[0]
		$sRead_UDFs_Module = FileRead($aUDF_Modules[$i])
		
		If StringRegExp($sRead_UDFs_Module, "(?im)^Func " & $sFuncName) Then
			$sUDFs_Module = $aUDF_Modules[$i]
			ExitLoop
		EndIf
	Next
	
	If Not FileExists($sUDFs_Module) Or $sRead_UDFs_Module = "" Then Return SetError(1, 0, "")
	
	$sCmdLine_Parser &= '#NoTrayIcon' & @CRLF
	$sCmdLine_Parser &= @CRLF
	$sCmdLine_Parser &= 'If $CmdLine[0] = 0 Then Exit ;We need at least 1 command line' & @CRLF
	$sCmdLine_Parser &= @CRLF
	$sCmdLine_Parser &= ';Collecting parameters' & @CRLF
	$sCmdLine_Parser &= '$sParams = ""' & @CRLF
	$sCmdLine_Parser &= @CRLF
	$sCmdLine_Parser &= 'For $i = 2 To $CmdLine[0]' & @CRLF
	$sCmdLine_Parser &= '	$sParams &= $CmdLine[$i] & "|"' & @CRLF
	$sCmdLine_Parser &= 'Next' & @CRLF
	$sCmdLine_Parser &= @CRLF
	$sCmdLine_Parser &= '$sParams = StringTrimRight($sParams, 1)' & @CRLF
	$sCmdLine_Parser &= 'Call($CmdLine[1], $sParams)' & @CRLF
	
	If Not StringInStr($sRead_UDFs_Module, $sCmdLine_Parser) Then
		$sRead_UDFs_Module = $sCmdLine_Parser & @CRLF & $sRead_UDFs_Module
		$hFile = FileOpen($sUDFs_Module, 2)
		FileWrite($hFile, $sRead_UDFs_Module)
		FileClose($hFile)
	EndIf
	
	Local $sStdOutRead = ""
	Local $iPID = Run(@AutoItExe & ' /AutoIt3ExecuteScript "' & _
		$sUDFs_Module & '" ' & $sFuncName & ' "' & $sParams & '"', '', '', 2 + 4)
	
	If @error Then Return SetError(2, 0, "")
	
	While 1
		$sStdOutRead &= StdoutRead($iPID)
		If @error Then ExitLoop
		
		Sleep(10)
	WEnd
	
	Return $sStdOutRead
EndFunc

Func _UDFsModuleInclude($sModule)
	If Not FileExists($sModule) Then Return SetError(1, 0, 0)
	
	$aUDF_Modules[0] += 1
	$aUDF_Modules[$aUDF_Modules[0]] = $sModule
EndFunc


файл-модуль (a.k.a плагин) - External_UDFs.fnc:
Код:
#NoTrayIcon

If $CmdLine[0] = 0 Then Exit ;We need at least 1 command line

;Collecting parameters
$sParams = ""

For $i = 2 To $CmdLine[0]
	$sParams &= $CmdLine[$i] & "|"
Next

$sParams = StringTrimRight($sParams, 1)
Call($CmdLine[1], $sParams)

;==== UDFs Part ====

Func Some_UDF($sParams)
	Local $iRet = MsgBox(36, "Question", $sParams)
	
	ConsoleWrite($iRet)
EndFunc

файл-модуль - Other_UDFs.fnc:
Код:
Func Other_UDF($sParams)
	Local $iRet = Run($sParams)
	ConsoleWrite($iRet)
EndFunc
 
Верх