Jump to content
Sign in to follow this  
Lupo73

Receive files from context menu

Recommended Posts

Lupo73

In one of my apps (DropIt, available on SourceForge) I have added a system context menu integration to send files to the software by right-click on them and selecting "Send to DropIt".

The feature works fine with one file, but if I select several files and than right-click and try to send them to DropIt, the software starts one time per file and system crash if too many files are sent.

There is a way to fix it and allow to send many files at once? Thanks! :mellow:


SFTPEx, AutoCompleteInput_DateTimeStandard(), _ImageWriteResize()_GUIGraduallyHide(): some AutoIt functions.

Lupo PenSuite: all-in-one and completely free selection of portable programs and games.

DropIt: a personal assistant to automatically manage your files.

ArcThemALL!: application to multi-archive your files and folders.

Share this post


Link to post
Share on other sites
KaFu
Lupo73

Thanks for the report.. I'll check this solution soon..


SFTPEx, AutoCompleteInput_DateTimeStandard(), _ImageWriteResize()_GUIGraduallyHide(): some AutoIt functions.

Lupo PenSuite: all-in-one and completely free selection of portable programs and games.

DropIt: a personal assistant to automatically manage your files.

ArcThemALL!: application to multi-archive your files and folders.

Share this post


Link to post
Share on other sites
Lupo73

It could be the solution, but is a little obscure for me.. how can I implement it in a script that receive parameters normally from $CmdLine?

I have attached my software code to show you how it is designed, not to have the solution (this is the hard/good aspect of programming), but to have some tips to proceed. thanks!

DropIt.au3

Edited by Lupo73

SFTPEx, AutoCompleteInput_DateTimeStandard(), _ImageWriteResize()_GUIGraduallyHide(): some AutoIt functions.

Lupo PenSuite: all-in-one and completely free selection of portable programs and games.

DropIt: a personal assistant to automatically manage your files.

ArcThemALL!: application to multi-archive your files and folders.

Share this post


Link to post
Share on other sites
KaFu

Share this post


Link to post
Share on other sites
KaFu

So, what behavior do you expect? I think two scenarios can occur. DropIt is not running and is started by the "Send to DropIt" command, or DropIt is already running and the "Send to DropIt" command needs to be routed to the running instance. Are both scenarios valid?

Edit: So where's the regwrite part for the "Send to DropIt" command? Need that one to test too :blink:

Edited by KaFu

Share this post


Link to post
Share on other sites
Lupo73

The software is designed to work fine as portable program. So the registration in Context menu and in SendTo menu are made in the installer version only, during installation (so from the installer itself, not by the software). I could consider to add them also as options (as I made in my other app ArcThemALL!), if you think it is needed.

The problem is that users reported me that the program starts N times, if I try to send N files to it through context menu (I don't know if the problem occurs also using sendto, but I think so). So I'd like to fix it in both my apps. :blink:


SFTPEx, AutoCompleteInput_DateTimeStandard(), _ImageWriteResize()_GUIGraduallyHide(): some AutoIt functions.

Lupo PenSuite: all-in-one and completely free selection of portable programs and games.

DropIt: a personal assistant to automatically manage your files.

ArcThemALL!: application to multi-archive your files and folders.

Share this post


Link to post
Share on other sites
KaFu

First of all, multiple selection of files sended via contextmenu to commandline should result in a $CmdLineRaw something like shown below.

MsgBox(0,"",$CmdLineRaw)
ClipPut($CmdLineRaw)
; "C:\Program Files\WinRAR\Zip.SFX" "C:\Program Files\WinRAR\Zip64.SFX" "C:\Program Files\WinRAR\zipnew.dat"

You're reading the commandline input with this

$temp = $CmdLine[0]

thus only capturing the very first element.

You should relocate the working code using the commandline parameters to a function (line ~1073 - 1104, e.g. _func_CmdLine). Stringsplit the $CmdLineRaw into an $aProfilLocation array to process in a loop for multiple selections.

Insert a call to the _EnforceSingleInstance() function exactly where the _func_CmdLine() was located before.

Take a look at my example in post #2 above.

In the _EnforceSingleInstance() the part "If IsHWnd($hwnd) Then" checks, whether there is already an instance running.

You have to add a wm_copydata message queue and rename the default autoit gui with a unique UUID (use mentioned page to generate one). In the function WM_COPYDATA() add a second call to _func_CmdLine($msg). These are the parts you'll need to add to you script:

Global $sCmdLineRaw

Func _Main()
    ;.....

    ImTarget()
    GUIRegisterMsg($WM_DROPFILES, "WM_DROPFILES_UNICODE_FUNC")
    GUIRegisterMsg($WM_SYSCOMMAND, "WM_SYSCOMMAND")
    $prof = Refresh($sIniPr, $profiles)

    $hwnd_AutoIt = _EnforceSingleInstance('261f3b38-e935-4229-9afc-01933cc7392b') ; any 'unique' string; created with http://www.guidgen.com/Index.aspx
    ControlSetText($hwnd_AutoIt, '', ControlGetHandle($hwnd_AutoIt, '', 'Edit1'), $hGUI) ; to pass hWnd of main GUI to AutoIt default GUI, this is you main guis hwnd
    GUIRegisterMsg($WM_COPYDATA, "WM_COPYDATA")

    While 1 ; Your main working loop
        If $sCmdLineRaw Then ; received via WM_COPYDATA
            $sCmdLineRaw = ""
            _func_CmdLine($sCmdLineRaw)
        EndIf
    WEnd
    ;.....
    ;.....
EndFunc   ;==>_Main

Func _EnforceSingleInstance($GUID_Program = "")
    If $GUID_Program = "" Then Return
    $hwnd = WinGetHandle($GUID_Program)
    If IsHWnd($hwnd) Then ; second instance exists, forward data and exit
        $hwnd_Target = ControlGetText($hwnd, '', ControlGetHandle($hwnd, '', 'Edit1')) ; grab target hWnd from default AutoIt GUI Edit control
        WM_COPYDATA_SendData(HWnd($hwnd_Target), $CmdLineRaw)
        Exit
    EndIf
    _func_CmdLine($CmdLineRaw) ; this is first instance, process commandline immediatly
    AutoItWinSetTitle($GUID_Program)
    Return WinGetHandle($GUID_Program)
EndFunc   ;==>_EnforceSingleInstance

Func WM_COPYDATA($hwnd, $MsgID, $wParam, $lParam)
    ; http://www.autoitscript.com/forum/index.php?showtopic=105861&view=findpost&p=747887
    ; Melba23, based on code from Yashied
    Local $tCOPYDATA = DllStructCreate("dword;dword;ptr", $lParam)
    Local $tMsg = DllStructCreate("char[" & DllStructGetData($tCOPYDATA, 2) & "]", DllStructGetData($tCOPYDATA, 3))
    $msg = DllStructGetData($tMsg, 1)
    $sCmdLineRaw = $msg ; assign received data to global variable to process in the main loop
    Return 0
EndFunc   ;==>WM_COPYDATA

Func WM_COPYDATA_SendData($hwnd, $sData)
    If Not IsHWnd($hwnd) Then Return 0
    If $sData = "" Then $sData = " "
    Local $tCOPYDATA, $tMsg
    $tMsg = DllStructCreate("char[" & StringLen($sData) + 1 & "]")
    DllStructSetData($tMsg, 1, $sData)
    $tCOPYDATA = DllStructCreate("dword;dword;ptr")
    DllStructSetData($tCOPYDATA, 2, StringLen($sData) + 1)
    DllStructSetData($tCOPYDATA, 3, DllStructGetPtr($tMsg))
    $Ret = DllCall("user32.dll", "lparam", "SendMessage", "hwnd", $hwnd, "int", $WM_COPYDATA, "wparam", 0, "lparam", DllStructGetPtr($tCOPYDATA))
    If (@error) Or ($Ret[0] = -1) Then Return 0
    Return 1
EndFunc   ;==>WM_COPYDATA_SendData

Func _func_CmdLine($sCmdLineRaw)
    $aProfilLocation = StringSplit($sCmdLineRaw....
    ;....
    ; Add loop to process multiple inputs
EndFunc   ;==>_func_CmdLine

The first call to _func_CmdLine($CmdLineRaw) processes the input if you're program is closed and the first instance is called. If there is already an instance of your program running, the $CmdLineRaw parameter is transfered to that instance via wm_copydata and the new instance exits. The first instance receives the $CmdLineRaw via wm_copydata an processed it via _func_CmdLine($msg)...

Ahhhh, too easy, isn't it :blink:...

Edit: While I think about it, better assign the received data to a global variable in WM_COPYDATA and return from function as fast as possible. Process the received results in the main loop. Adjusted the code above a little. Best to place the _EnforceSingleInstance() call directly after your call to Refresh(), as $hGUI is already defined then.

Edited by KaFu

Share this post


Link to post
Share on other sites
Lupo73

I'm testing it... You can see that in my code is already present a "Checking of multiple instances" that, if the option is enabled, close the new instance if another one is open. So I may need to modify it to work with your code too.

To do a test I have firstly added a MsgBox to write the $CmdLineRaw received by the software and if I select N files and send them to DropIt with context menu:

- if my multiple instances blocker is enabled, only one instance is started and only one file is in $CmdLineRaw parameter

- if it is disabled, N instances are started and only one file per instance is in $CmdLineRaw parameter

So in both cases the $CmdLineRaw not contains N parameters, but only one parameter each instance started and I need to start a first instance and send other parameters to it. I can't understand if it is what your code does. :blink:

Note also that lines 1073-1104 are used to detect if the first parameter is a command to start the software with a specified profile and I need to keep this feature in the eventual recoding.

Thanks!


SFTPEx, AutoCompleteInput_DateTimeStandard(), _ImageWriteResize()_GUIGraduallyHide(): some AutoIt functions.

Lupo PenSuite: all-in-one and completely free selection of portable programs and games.

DropIt: a personal assistant to automatically manage your files.

ArcThemALL!: application to multi-archive your files and folders.

Share this post


Link to post
Share on other sites
KaFu

Lets see ;) ...

- So in both cases the $CmdLineRaw not contains N parameters

- if the first parameter is a command to

Okay, thought it was like I posted above with N parameters (has something to do with which switches you used to created the contextmenu I guess). Additionally it's a "command" / unqualified filename by default, not a full filename (as I assumed :blink: ). What does the contextmenu return? A full filename I guess.

First I would two Global arrays, containing possible profile filenames to process (org and buffer).

Because the Commandline switch (no full filename+path) and Contextmenu (full filename+path) switch's are different, you'll have to deal with how to add them to the array additionally. First thing to do, maybe check with something like FileExists() and if not, try if your own profile pattern matches, then add to processing array.

Best to create a separate function to deal with the addition to the processing array.

In the_EnforceSingleInstance() function, the first instance should add directly to the processing array, all subsequent pass the data via wm_copydata to the first instance and exit. The first instance appends the received data to the processing buffer array (to prevent interfering with the processing itself).

Relocate your processing function to the main loop. Loop through it, as long as 1 element exits in the array (maybe [0] should be a counter of elements).

If an element has been processed, delete it from the array.

Last thing to add to the main loop is a check if the buffer array contains an element, and if so copy it to processing array and delete it from buffer. This will start the processing function again.

Edit: Rewrote it a little, sry :P...

Edited by KaFu

Share this post


Link to post
Share on other sites
Lupo73

Sorry, but it is very complex for me..

The array that contains profile names is $profiles. Note also that from context menu are automatically sent parameters as full filename+path, but also with commandline the software can receive: full filename+path, filename+relative path, profile name (as "-profilename" as first parameter).

I can't create the mechanism you have in mind, but it seems well structured.. can you write me an example of it? thanks!

I know this forum is for this kind of requests, but here there are programmers like me that like to collaborate to their works.. so I try: I'd like to improve also other aspects of DropIt (for example adding support to PNG target images), but I'm not a so advanced programmer and I'm looking for someone interested in this project.. it is on SourceForge and fully open source.. now it's good, but could became better.. if it could interest you..


SFTPEx, AutoCompleteInput_DateTimeStandard(), _ImageWriteResize()_GUIGraduallyHide(): some AutoIt functions.

Lupo PenSuite: all-in-one and completely free selection of portable programs and games.

DropIt: a personal assistant to automatically manage your files.

ArcThemALL!: application to multi-archive your files and folders.

Share this post


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
Sign in to follow this  

×