From: eugene on
Hello everybody.
I'm trying to use Ffidl package and currently stuck with a problem.
Particularly, I need to call ShellExecuteEx function (its description
can be found here: http://msdn.microsoft.com/en-us/library/bb762154%28v=VS.85%29.aspx).
The problem is that it takes a pointer to SHELLEXECUTEINFO structure,
and I just can't grasp the ways to work with pointers and structures
in Ffidl.
Digging the internet I found the following working perl code snippet
here: http://code.activestate.com/lists/perl-win32-users/5702/

use strict;
use Win32::API;

my $ShellExecuteEx = new Win32::API('shell32.dll', 'ShellExecuteEx',
['P'], 'N') or die 'Get ShellExecuteEx: ' .
Win32::FormatMessage(Win32::GetLastError());

my $lpVerb = pack 'A*', 'open';
my $lpFile = pack 'A*', 'C:\\path\\readme.txt';
print $lpVerb, $lpFile;

my $args = pack 'LLLPPPPLLLPLLLL';
$args = pack 'LLLPPPPLLLPLLLL', length $args, 12, 0, $lpVerb, $lpFile,
0, 0, 5, 0, 0, 0, 0, 0, 0, 0;

my $ret = $ShellExecuteEx->Call($args) or die 'Call ShellExecuteEx:
' . Win32::FormatMessage(Win32::GetLastError());

I tried to "translate" from perl to Tcl and here's the result:

package require Ffidl
package require Ffidlrt

::ffidl::typedef SEI long long long pointer pointer pointer pointer
long long long pointer long long long
::ffidl::callout ShellExecuteEx pointer long [ ::ffidl::symbol
shell32.dll ShellExecuteEx ]

set verb [ binary format a* open ]
set file [ binary format a* {c:\\path\\readme.txt} ]

set args [ binary format [ ::ffidl::info format SEI ] [ ::ffidl::info
sizeof SEI ] 12 0 [ ::ffidl::get-string verb ] [ ::ffidl::get-string
file ] 0 0 5 0 0 0 0 0 0 0 ]
ShellExecuteEx $args

However, it spews the error on the last line: "expected integer but
got 8"
I suppose the variable $args is not formatted as expected by
ShellExecuteEx, but I'm out of ideas how to fix it.
Can anybody experienced in dealing with Ffidl and complex structures
give me a hint what's missing/wrong in my code?
From: Alexandre Ferrieux on
On Aug 6, 4:22 pm, eugene <eugene.mind...(a)gmail.com> wrote:
> Hello everybody.
> I'm trying to use Ffidl package and currently stuck with a problem.
> Particularly, I need to call ShellExecuteEx function (its description
> can be found here:http://msdn.microsoft.com/en-us/library/bb762154%28v=VS.85%29.aspx).
> The problem is that it takes a pointer to SHELLEXECUTEINFO structure,
> and I just can't grasp the ways to work with pointers and structures
> in Ffidl.
> Digging the internet I found the following working perl code snippet
> here:http://code.activestate.com/lists/perl-win32-users/5702/
>
> use strict;
> use Win32::API;
>
> my $ShellExecuteEx = new Win32::API('shell32.dll', 'ShellExecuteEx',
> ['P'], 'N') or die 'Get ShellExecuteEx: ' .
> Win32::FormatMessage(Win32::GetLastError());
>
> my $lpVerb = pack 'A*', 'open';
> my $lpFile = pack 'A*', 'C:\\path\\readme.txt';
> print $lpVerb, $lpFile;
>
> my $args = pack 'LLLPPPPLLLPLLLL';
> $args = pack 'LLLPPPPLLLPLLLL', length $args, 12, 0, $lpVerb, $lpFile,
> 0, 0, 5, 0, 0, 0, 0, 0, 0, 0;
>
> my $ret = $ShellExecuteEx->Call($args) or die 'Call ShellExecuteEx:
> ' .  Win32::FormatMessage(Win32::GetLastError());
>
> I tried to "translate" from perl to Tcl and here's the result:
>
> package require Ffidl
> package require Ffidlrt
>
> ::ffidl::typedef SEI long long long pointer pointer pointer pointer
> long long long pointer long long long
> ::ffidl::callout ShellExecuteEx pointer long [ ::ffidl::symbol
> shell32.dll ShellExecuteEx ]
>
> set verb [ binary format a* open ]
> set file [ binary format a* {c:\\path\\readme.txt} ]
>
> set args [ binary format [ ::ffidl::info format SEI ] [ ::ffidl::info
> sizeof SEI ] 12 0 [ ::ffidl::get-string verb ] [ ::ffidl::get-string
> file ] 0 0 5 0 0 0 0 0 0 0 ]
> ShellExecuteEx $args
>
> However, it spews the error on the last line: "expected integer but
> got 8"
> I suppose the variable $args is not formatted as expected by
> ShellExecuteEx, but I'm out of ideas how to fix it.
> Can anybody experienced in dealing with Ffidl and complex structures
> give me a hint what's missing/wrong in my code?

Random shot, maybe unrelated: since the SHELLEXECUTEINFO struct is
_inout, shouldn't you be using the pointer-var type ? You'd call
[ShellExecuteEx args] in this case, and the modified byte array would
be available in args afterwards. I admit the error message doesn't
hint at that at all though...

-Alex
From: David Gravereaux on
Aside from Ffidl, there's other ways to call ShellExecuteEx.

1) Twapi or

2) write a C extension. I'll even donate the code:

http://tomasoft.cvs.sourceforge.net/viewvc/tomasoft/winutils/Shell.c?revision=1.6&view=markup

--


From: eugene on
On Aug 6, 8:15 pm, Alexandre Ferrieux <alexandre.ferri...(a)gmail.com>
wrote:
>
> Random shot, maybe unrelated: since the SHELLEXECUTEINFO struct is
> _inout, shouldn't you be using the pointer-var type ? You'd call
> [ShellExecuteEx args] in this case, and the modified byte array would
> be available in args afterwards. I admit the error message doesn't
> hint at that at all though...
>
> -Alex

Alex, you're right, thanks. However, that wasn't the source of the
problem :)
Actually, in this case there's two ways to call ShellExecuteEx
(provided that args structure is filled correctly):
1. If the function is imported like you suggested:
::ffidl::callout ShellExecuteEx pointer-var long [ ::ffidl::symbol
shell32.dll ShellExecuteEx ]
Then it indeed can be called like this:
ShellExecuteEx args
2. But one can still use my original definition:
::ffidl::callout ShellExecuteEx pointer long [ ::ffidl::symbol
shell32.dll ShellExecuteEx ]
In this case the call looks like this:
ShellExecuteEx [ ::ffidl::get-bytearray $args ]

The actual problems with my original Tcl code snippet were:
1. I inadvertently missed one structure field in SEI type definition.
2. I should have passed variable value, not its name to ::ffidl::get-
string.

So, the working Tcl code:

package require Ffidl
package require Ffidlrt

::ffidl::typedef sei long long long pointer pointer pointer pointer
long long long pointer long long long long
::ffidl::callout ShellExecuteEx pointer-var long [ ::ffidl::symbol
shell32.dll ShellExecuteEx ]

set verb open
set file {C:\\path\\readme.txt}

set args [ binary format [ ::ffidl::info format sei ] [ ::ffidl::info
sizeof sei ] 12 0 [ ::ffidl::get-string $verb ] [ ::ffidl::get-string
$file ] 0 0 5 0 0 0 0 0 0 0 ]
ShellExecuteEx args
From: eugene on
On Aug 6, 10:05 pm, David Gravereaux <davyg...(a)pobox.com> wrote:
> Aside from Ffidl, there's other ways to call ShellExecuteEx.
>
> 1) Twapi  or
>
> 2) write a C extension.  I'll even donate the code:
>
> http://tomasoft.cvs.sourceforge.net/viewvc/tomasoft/winutils/Shell.c?...
>
> --
>
>  signature.asc
> < 1KViewDownload

Yes David, I'm aware of different ways to call Windows API functions
from Tcl, however, my application already uses Ffidl for other
purposes so I just decided to try using it to the maximum extent.
This ShellExecuteEx though became a major showstopper for me :)
First I tried to use your winutils package and its shell function
worked flawlessly with simple verbs like "open", but when I tried to
use other ones, like "properties" for example, it failed with error
"File association is not available". I suppose some verbs require
setting the correct fMask field in SHELLEXECUTEINFO structure and I
haven't found the way to do it in winutils.