jjohn has asked for the wisdom of the Perl Monks concerning the following question:

Greetings,

I'm having some difficulty calling the Win32 API function CoInitializeSecurity() from Perl. I'm using ActiveState Perl 5.8.3 and the Win32::API module. The COM objects I need to talk to require impersonation and, according to the docs, I can do this with the aforementioned function. However, translating the C/VB docs into a Win32::API call has proven a bit beyond my humble powers. Has anyone successfully called this OLE32.DLL function successfully from Perl? My target platform is Server 2003, but this function is available on earlier platforms.

Here's my sloppy test harness:

use strict; use Data::Dumper; use Win32::API; print "Setting COM security\n"; # CoInitilizeSecurity defined : # http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com +/htm/cmf_a2c_8ayh.asp my $CoInit = Win32::API->new( "OLE32.DLL", "CoInitializeSecurity" # input prototypes # 1 P, # Access perms # 2 N, # num of els in asAuthSvr # 3 P, # array of auth services # 4 P, # reserved # 5 N, # default auth level # 6 N, # proxy impersonation level # 7 P, # sole auth list # 8 N, # add'l capabilities # 9 P, # reserved "PNPPNNPNP", "N", # return ) or warn "Can't get DLL"; my $NULL = 0; my $RPC_C_AUTHEN_NONE = 0; my $RPC_C_AUTHEN_LEVEL_NONE = 1; my $RPC_C_IMP_LEVEL_IMP = 3; my $EOAC_NONE = 0; my $result = $CoInit->Call( $NULL, 0, $RPC_C_AUTHEN_NONE, $NULL, $RPC_C_AUTHEN_LEVEL_NONE, $RPC_C_IMP_LEVEL_IMP, $NULL, $EOAC_NONE, $NULL, ); # $result = -2147221008 if ($result != 0){ warn "Oops: ", Dumper($result), "\n"; } print "done\n";

Also note that I have tried Win32::API::Prototype but it fails to translate the return argument and the first parameter. Any suggestions as to how I might crack this nut would be met with warm appreciation.

Thank you for your time.

Replies are listed 'Best First'.
Re: Calling CoInitializeSecurity() from Win32::API
by meetraz (Hermit) on Feb 21, 2004 at 00:25 UTC
    The key to your problem is finding out which HRESULT is meant by "-2147221008". You can use Win32::OLE::HRESULT() for that.

    To make a long story short....

    use strict; use Win32::OLE qw(HRESULT); use constant CO_E_NOTINITIALIZED => 0x800401F0; my $result = -2147221008; if (HRESULT(CO_E_NOTINITIALIZED) == $result) { print "Eureka! The problem is CO_E_NOTINITIALIZED\n"; }

    So the answer is, you must call CoInitialize() first before calling CoInitializeSecurity()...

    And yes, this appears to work fine:

    use strict; use Data::Dumper; use Win32::API; print "Setting COM security\n"; # CoInitilizeSecurity defined : # http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com +/htm/cmf_a2c_8ayh.asp my $CoInit = Win32::API->new( "OLE32.DLL", "CoInitialize", # input prototypes # 1 P, # reserved "P", "N", # return ) or warn "Can't get DLL"; my $CoInitSec = Win32::API->new( "OLE32.DLL", "CoInitializeSecurity", # input prototypes # 1 P, # Access perms # 2 N, # num of els in asAuthSvr # 3 P, # array of auth services # 4 P, # reserved # 5 N, # default auth level # 6 N, # proxy impersonation level # 7 P, # sole auth list # 8 N, # add'l capabilities # 9 P, # reserved "PNPPNNPNP", "N", # return ) or warn "Can't get DLL"; my $NULL = 0; my $RPC_C_AUTHEN_NONE = 0; my $RPC_C_AUTHEN_LEVEL_NONE = 1; my $RPC_C_IMP_LEVEL_IMP = 3; my $EOAC_NONE = 0; my $result1 = $CoInit->Call( $NULL ); if ($result1 != 0){ warn "Oops: ", Dumper($result1), "\n"; } my $result2 = $CoInitSec->Call( $NULL, 0, $RPC_C_AUTHEN_NONE, $NULL, $RPC_C_AUTHEN_LEVEL_NONE, $RPC_C_IMP_LEVEL_IMP, $NULL, $EOAC_NONE, $NULL, ); if ($result2 != 0){ warn "Oops: ", Dumper($result2), "\n"; } print "done\n";

    I should add, it's probably more correct to pass in "undef" for a null pointer instead of your $NULL, because otherwise Win32::API might be passing a real valid pointer to the perl SV containing an integer zero.

      Ah! Thanks. I did manage to look up the error code and to my surprise Win32::OLE->Initialize() does exactly what I need. Win32::API is strong, but mysterious ju-ju. As for the whether NULL pointers should be 0 or undef, I agree the undef ought to work, but then the numeric 0 ought to as well. Since I don't understand how clever Win32::API is about the type conversions, so I erred on the side of explicit values.

      Thanks again. My Win32-FU is mightily, er, stoppable. :-)