Jump to content

Passing argument to a running AutoIT EXE - (Moved)


Recommended Posts

Hi,

 

I am trying to do a program that will be able to receive a number of filename and populate a list but i am having some issues.

 

Here's how i need it to work :

1) Select a number of PDF files then do a right click on them

2) Select the Merge PDF Option

3) This should open the autoIT app then show the list of file to merge

-> Unfortunately Windows can't send multiple filenames to an EXE file and this is by design..

Currently, windows open 10X the autoIT program with 1 file argument...

 

The only way for this to work at the moment it to use Send To then this will work... ( but i want it the the main context menu )

 

From what i saw online, you need a listener that will get this list then pass it to the main program but i don't know to much where to start.

Anyone here had that kind of issue ?

Link to post
Share on other sites
  • Moderators

Moved to the appropriate forum, as the Developer General Discussion forum very clearly states:

Quote

General development and scripting discussions.


Do not create AutoIt-related topics here, use the AutoIt General Help and Support or AutoIt Technical Discussion forums.

Moderation Team

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to post
Share on other sites
5 hours ago, OhBobSaget said:

From what i saw online, you need a listener that will get this list then pass it to the main program but i don't know to much where to start.

Send To is ultimately the way to go, if possible.

If not, then a down and dirty way of doing it would just be to have your context menu .exe create a file, based on the argument passed to it, in a temp directory with a different extension and the full path contained in the contents.  The. have it call the “real” exe only if it isn’t running yet, and then exit.

Then have the “real” .exe sleep a second or so when it starts to let all the temp files be created.  Then have it scoop them up and process them, then delete them and exit.

It’s not pretty, but I think you’ll end up doing something like this no matter what.

 

Code hard, but don’t hard code...

Link to post
Share on other sites

Here my contribution to your project.  I felt it could be fun to make a POC using a RDBMS.  Seems it is working quite well :

#include <SQLite.au3>
#include <Constants.au3>
#include <Misc.au3>

Local Const $SQLITE_DLL = "sqlite3.dll"
Local Const $SQLITE_Database_Name = "Merge.DB"

If $CmdLine[0] <> 1 Then Exit MsgBox ($MB_SYSTEMMODAL, "", "You need to provide full path file")
If Not FileExists($CmdLine[1]) Then Exit MsgBox ($MB_SYSTEMMODAL, "", "File does not exist")

Local $hProc
While True
  $hProc = _Singleton("MergeListener", 1)
  If $hProc Then ExitLoop
  Sleep(Random(10, 15))
WEnd

_SQLite_Startup($SQLITE_DLL, False, 1)
If @error Then Exit MsgBox($MB_SYSTEMMODAL, "SQLite Startup Error", "Unable to start SQLite. Check existence of DLL")
Local $hDB = _SQLite_Open($SQLITE_Database_Name)
If $hDB = 0 Then Exit MsgBox($MB_SYSTEMMODAL, "SQLite Open Error", "Unable to open database")

Local $aRow
_SQLite_QuerySingleRow (-1, "select count(*) from Merge;", $aRow)
If Not $aRow[0] Then ConsoleWrite ("Start Merge Process here" & @CRLF)

_SQLite_Exec(-1, "insert into merge values('" & $CmdLine[1] & "');")

_SQLite_Close()
_SQLite_Shutdown()

You need to create a "Merge.DB" file with a single table called "Merge" with a single column called "Path" (unique not null).  And you are good to go.  The actual Merge script is the one you start on the fist creation of a row.  The actual Merge script can peek (select) at the table until there is no more rows added.  At the end of the process, it needs to delete all rows.  I think you should also have a mutex on the overall Merge process, so there is no 2 processes competing.

Link to post
Share on other sites
11 hours ago, JockoDundee said:

Send To is ultimately the way to go, if possible.

If not, then a down and dirty way of doing it would just be to have your context menu .exe create a file, based on the argument passed to it, in a temp directory with a different extension and the full path contained in the contents.  The. have it call the “real” exe only if it isn’t running yet, and then exit.

Then have the “real” .exe sleep a second or so when it starts to let all the temp files be created.  Then have it scoop them up and process them, then delete them and exit.

It’s not pretty, but I think you’ll end up doing something like this no matter what.

 

Yes, it was my first thought on how to do it, but too dirty for me ;)  I would prefer to end up with Send To than using this method hehe

 

Thank you JockoDundee

Link to post
Share on other sites
17 minutes ago, Nine said:

Here my contribution to your project.  I felt it could be fun to make a POC using a RDBMS.  Seems it is working quite well :

#include <SQLite.au3>
#include <Constants.au3>
#include <Misc.au3>

Local Const $SQLITE_DLL = "sqlite3.dll"
Local Const $SQLITE_Database_Name = "Merge.DB"

If $CmdLine[0] <> 1 Then Exit MsgBox ($MB_SYSTEMMODAL, "", "You need to provide full path file")
If Not FileExists($CmdLine[1]) Then Exit MsgBox ($MB_SYSTEMMODAL, "", "File does not exist")

Local $hProc
While True
  $hProc = _Singleton("MergeListener", 1)
  If $hProc Then ExitLoop
  Sleep(Random(10, 15))
WEnd

_SQLite_Startup($SQLITE_DLL, False, 1)
If @error Then Exit MsgBox($MB_SYSTEMMODAL, "SQLite Startup Error", "Unable to start SQLite. Check existence of DLL")
Local $hDB = _SQLite_Open($SQLITE_Database_Name)
If $hDB = 0 Then Exit MsgBox($MB_SYSTEMMODAL, "SQLite Open Error", "Unable to open database")

Local $aRow
_SQLite_QuerySingleRow (-1, "select count(*) from Merge;", $aRow)
If Not $aRow[0] Then ConsoleWrite ("Start Merge Process here" & @CRLF)

_SQLite_Exec(-1, "insert into merge values('" & $CmdLine[1] & "');")

_SQLite_Close()
_SQLite_Shutdown()

You need to create a "Merge.DB" file with a single table called "Merge" with a single column called "Path" (unique not null).  And you are good to go.  The actual Merge script is the one you start on the fist creation of a row.  The actual Merge script can peek (select) at the table until there is no more rows added.  At the end of the process, it needs to delete all rows.  I think you should also have a mutex on the overall Merge process, so there is no 2 processes competing.

So this code snippet would work if :

 

I select 10 PDF files, and from the context menu i select the option to launch the PDF merge ?

Because this action will launch 10x this code snippet in a short period of time.

From my understanding, you are creating a DB that will hold all the filepaths... but how does it know that it is now time to launch the main AutoIT App that will do the PDF Merge ?

Also.... will it be able to write in that DB with 10 apps are trying at the same time to interact with Merge.DB ?

 

Thank you Nine

 

Link to post
Share on other sites

Yes.  This is why I have use a mutex to ensure that only one process runs at a given time.  Like I already said the merge process can peek at the table.  Please read carefully my comments at the end of the snippet.

ps. do not quote everything we tell you, it makes the thread cumbersome for nothing.  Use reply box at the end of the thread instead.

pps.  In my test I have started 12 listeners at a time in a close loop and all the 12 paths were written correctly in th DB...

 

Edited by Nine
Link to post
Share on other sites

I downloaded the SQL3Lite, managed to create the table, column etc. then use your code sample.

Just one thing that i am not too sure...

When does the outside APP to merge will be called?  From what i can see in the code provided this is what will do it :

If Not $aRow[0] Then ConsoleWrite ("Start Merge Process here" & @CRLF)

I tried replacing this ConsoleWrite command by a msgbox to see the behavior and it seems that it is never called.

 

What i would like here is that when all the files have been processed, they are added to a list in a GUI then the user can choose various options before merging them

Sorry if i am unclear.

 

 

Link to post
Share on other sites

@Nine, should the insert really be after the select count(*)?  How does the Merge process get called if there is only one file?

_SQLite_QuerySingleRow (-1, "select count(*) from Merge;", $aRow)
If Not $aRow[0] Then ConsoleWrite ("Start Merge Process here" & @CRLF)

_SQLite_Exec(-1, "insert into merge values('" & $CmdLine[1] & "');")

 

Code hard, but don’t hard code...

Link to post
Share on other sites
3 hours ago, OhBobSaget said:

Yes, it was my first thought on how to do it,

Did you have a second thought on how to do it, because I can’t really think of a way besides some variation of what I said, aside from using different IPCs?

Code hard, but don’t hard code...

Link to post
Share on other sites
1 hour ago, OhBobSaget said:

I tried replacing this ConsoleWrite command by a msgbox to see the behavior and it seems that it is never called.

Yes there was a small bug, select count(*) is still returning a string even if the result is 0.  So try this now :

#include <SQLite.au3>
#include <Constants.au3>
#include <Misc.au3>

Local Const $SQLITE_DLL = "sqlite3.dll"
Local Const $SQLITE_Database_Name = "Merge.DB"

While True
  If _Singleton("MergeListener", 1) Then ExitLoop
  Sleep(Random(10, 15))
WEnd

If $CmdLine[0] <> 1 Then Exit MsgBox ($MB_SYSTEMMODAL, "", "You need to provide full path file")
If Not FileExists($CmdLine[1]) Then Exit MsgBox ($MB_SYSTEMMODAL, "", "File does not exist")

_SQLite_Startup($SQLITE_DLL, False, 1)
If @error Then Exit MsgBox($MB_SYSTEMMODAL, "SQLite Startup Error", "Unable to start SQLite. Check existence of DLL")
Local $hDB = _SQLite_Open($SQLITE_Database_Name)
If $hDB = 0 Then Exit MsgBox($MB_SYSTEMMODAL, "SQLite Open Error", "Unable to open database")

Local $aRow
_SQLite_QuerySingleRow (-1, "select count(*) from Merge;", $aRow)
If $aRow[0] = "0" Then MsgBox ($MB_SYSTEMMODAL, VarGetType($aRow[0]), "Start Merge Process here" & @CRLF)

_SQLite_Exec(-1, "insert into merge values('" & $CmdLine[1] & "');")

_SQLite_Close()
_SQLite_Shutdown()

ps. make sure you delete all rows from the table before starting your test again...

Edited by Nine
Link to post
Share on other sites
36 minutes ago, JockoDundee said:

should the insert really be after the select count(*)?

Not important, it has to be started sooner or later.

37 minutes ago, JockoDundee said:

How does the Merge process get called if there is only one file?

To be honest I don't care, it is the Merge responsibility to manage 1 or multiple files.  The POC was about the listener...

Link to post
Share on other sites
#NoTrayIcon
#include <Mailslot.au3> ; "http://www.autoitscript.com/forum/index.php?showtopic=106710"
Global Const $sMailSlotName = "\\.\mailslot\RandomNameForThisTest"

example() ;  Obviously you'll have to compile the script and associate a file type to it, in order to test this example.
Func example() ; "https://www.autoitscript.com/forum/index.php?showtopic=205483&view=findpost&p=1478490"
    Local $hTimer = TimerInit(), $hTimerTotal = $hTimer
    Local $hMailSlot = _MailSlotCreate($sMailSlotName)
    If @error Then
        If $CmdLine[0] Then _MailSlotWrite($sMailSlotName, $CmdLineRaw)
        Exit
    EndIf
    SplashTextOn(@ScriptName, "1 sec. please")
    Local $iWaitTime = Round(TimerDiff($hTimer)) * 10 ; more or less, think of a good delay scheme. This is what I thought of.
    Local $iCount = 0, $sTemp, $sFiles = ""
    If $CmdLine[0] Then
        For $n = 1 To $CmdLine[0]
            example_AddThisFileToTheList($hTimer, $iCount, $sFiles, $CmdLine[$n])
        Next
    Else
;~      If FileExists(@ScriptDir & "\*.TestAFile") Then
;~          FileDelete(@ScriptDir & "\*.TestAFile")
;~      Else
;~          For $n = 1 To 100 ; create 100 sample files with ext.  ".TestAFile"
;~              FileWriteLine(@ScriptDir & "\Test file number " & StringRight("000" & $n, 3) & ".TestAFile", "Test file. Do delete.")
;~          Next
;~      EndIf
    EndIf
    Do
        $sTemp = example_ReadMessage($hMailSlot)
        If @extended Then example_AddThisFileToTheList($hTimer, $iCount, $sFiles, $sTemp)
    Until TimerDiff($hTimer) > $iWaitTime
    _MailSlotClose($hMailSlot) ; ...to free the instance, if you want to do just this run on its own.
    SplashOff()
    MsgBox(0, @ScriptName, "Listing " & $iCount & " file(s) in " & Round(TimerDiff($hTimerTotal)) & " ms. :" & @CRLF & $sFiles, 120)
EndFunc   ;==>example

Func example_AddThisFileToTheList(ByRef $hTimer, ByRef $iCount, ByRef $sFiles, $sTemp)
    $hTimer = TimerInit()
    $iCount += 1
    $sFiles &= StringReplace($sTemp, '"', '') & @CRLF
EndFunc   ;==>example_AddThisFileToTheList

Func example_ReadMessage($hHandle)
    Local $iSize = _MailSlotCheckForNextMessage($hHandle)
    If $iSize Then Return SetError(0, $iSize, _MailSlotRead($hHandle, $iSize, 1))
    Return ""
EndFunc   ;==>example_ReadMessage

:)

Edited by argumentum
nicer code
Link to post
Share on other sites
3 hours ago, Nine said:

Not important, it has to be started sooner or later

Yes but in the case where only one file is selected (perhaps by accident, if merging one file is like the sound of one hand clapping), merge never gets called.  But the row still gets added to the DB.

Next time, multiple files do get selected (seconds or days later), the single file will get merged in with the others unintentionally.

Code hard, but don’t hard code...

Link to post
Share on other sites

I think you are misunderstanding the way the script works.  Did you try it and find a bug that can be replicated or you just assume you are right based on a wrong assumption ?  Because the script works all the time for 1 or 12 or xyz files selected.  An easy way to prove this, use this code :

#include <Constants.au3>
#include <File.au3>
#include <Array.au3>

Local $aList = _FileListToArray(@ScriptDir, "*.au3", $FLTA_FILES, True)
For $i = 1 to 1; $aList[0]
  Run('merge.exe "' & $aList[$i] & '"')
  Sleep (50)
Next

Compile the latest POC into merge.exe.  Then run this caller.  You will see it works all the time...As I already said, ensure you delete all rows before starting a new test :guitar:

Link to post
Share on other sites
8 hours ago, JockoDundee said:

I am sorry.

No offense.

I have push further the POC by writing the Merge Procedure script, to make sure that all along it was working correctly.  If OP or anyone else would like to use this solution, I recommend that you put your DB into WAL mode, see this document.  That would make your scripts run faster.  But it will work with or without...

Listener :

#include <SQLite.au3>
#include <Constants.au3>
#include <Misc.au3>

Local Const $SQLITE_DLL = "sqlite3.dll"
Local Const $SQLITE_Database_Name = "Merge.DB"

While True
  If _Singleton("MergeListener", 1) Then ExitLoop
  Sleep(Random(10, 15))
WEnd

If $CmdLine[0] <> 1 Then Exit MsgBox ($MB_SYSTEMMODAL, "", "You need to provide full path file")
If Not FileExists($CmdLine[1]) Then Exit MsgBox ($MB_SYSTEMMODAL, "", "File does not exist")

_SQLite_Startup($SQLITE_DLL, False, 1)
If @error Then Exit MsgBox($MB_SYSTEMMODAL, "SQLite Startup Error", "Unable to start SQLite. Check existence of DLL")
Local $hDB = _SQLite_Open($SQLITE_Database_Name)
If $hDB = 0 Then Exit MsgBox($MB_SYSTEMMODAL, "SQLite Open Error", "Unable to open database")

Local $aRow
_SQLite_QuerySingleRow (-1, "select count(*) from Merge;", $aRow)
If $aRow[0] = "0" Then Run("MergeProc.exe")

Do
Until _SQLite_Exec(-1, "insert into merge values('" & $CmdLine[1] & "');") = $SQLITE_OK

_SQLite_Close()
_SQLite_Shutdown()

Proc :

#include <SQLite.au3>
#include <Constants.au3>
#include <Misc.au3>

Local Const $SQLITE_DLL = "sqlite3.dll"
Local Const $SQLITE_Database_Name = "Merge.DB"

_Singleton("MergeProc") ; make sure that only one proc is running at a time

_SQLite_Startup($SQLITE_DLL, False, 1)
If @error Then Exit MsgBox($MB_SYSTEMMODAL, "SQLite Startup Error (Proc)", "Unable to start SQLite. Check existence of DLL")
Local $hDB = _SQLite_Open($SQLITE_Database_Name)
If $hDB = 0 Then Exit MsgBox($MB_SYSTEMMODAL, "SQLite Open Error (Proc)", "Unable to open database")

Local $aRow, $iPrev = "-1", $iRes
While True
  $iRes = _SQLite_QuerySingleRow (-1, "select count(*) from Merge;", $aRow) ; peek to see if all rows have been written (change sleep time as needed)
  Sleep (200)
  If $iRes <> $SQLITE_OK Then ContinueLoop
  If $iPrev = $aRow[0] Then ExitLoop
  $iPrev = $aRow[0]
WEnd

Local $aResult, $iRows, $iColumns
_SQLite_GetTable(-1, "select * from Merge;", $aResult, $iRows, $iColumns)
_SQLite_Exec(-1, "delete from Merge;")

_SQLite_Close()
_SQLite_Shutdown()

_ArrayDisplay($aResult)

 

Link to post
Share on other sites

@argumentum 

For the moment i am trying the @Nine solution.

I am currently have some stability problem with  this solution, because the number of file that are passed as argument are not stable...

I often select like 10-12 files but only 8-9 files end up being pass to the main merging PDF program.

 

Also i had problem with the @Nine The statement to remove the entries in the DB "delete from Merge;"

I had to find another way.... so i copy a template DB every time the software is used instead of purging the DB.

 

As for your solution, i just took a quick look at the code and i was not sure if it was something that might work, isnt that UDF for mail stuff ?

 

Thank you both for your help ;)

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...