Below is how I would have implemented the solution. In short, I'd use constants instead of magical values, and I'd hide C-ish bits in a sub that provides an interface better suited to Perl.

use v5.10.0; use strict; use warnings; use Win32::API qw( ); use constant MAX_PATH => 260; use constant MAX_FEATURE_CHARS => 38; use constant { INSTALLSTATE_NOTUSED => -7, # component disabled INSTALLSTATE_BADCONFIG => -6, # configuration data corrupt INSTALLSTATE_INCOMPLETE => -5, # installation suspended or in p +rogress INSTALLSTATE_SOURCEABSENT => -4, # run from source, source is una +vailable INSTALLSTATE_MOREDATA => -3, # return buffer overflow INSTALLSTATE_INVALIDARG => -2, # invalid function argument INSTALLSTATE_UNKNOWN => -1, # unrecognized product or featur +e INSTALLSTATE_BROKEN => 0, # broken INSTALLSTATE_ADVERTISED => 1, # advertised feature INSTALLSTATE_REMOVED => 1, # component being removed (actio +n state, not settable) INSTALLSTATE_ABSENT => 2, # uninstalled (or action state a +bsent but clients remain) INSTALLSTATE_LOCAL => 3, # installed on local drive INSTALLSTATE_SOURCE => 4, # run from source, CD or net INSTALLSTATE_DEFAULT => 5, # use default, local or source }; my %INSTALLSTATE_DESC = ( INSTALLSTATE_NOTUSED() => 'The component being requested is d +isabled on the computer', INSTALLSTATE_BADCONFIG() => '[configuration data corrupt]', INSTALLSTATE_INCOMPLETE() => '[installation suspended or in prog +ress]', INSTALLSTATE_SOURCEABSENT() => 'The component source is inaccessib +le', INSTALLSTATE_MOREDATA() => '[return buffer overflow]', INSTALLSTATE_INVALIDARG() => 'One of the function parameters is +invalid', INSTALLSTATE_UNKNOWN() => 'The product code or component ID i +s unknown', INSTALLSTATE_BROKEN() => '[broken]', INSTALLSTATE_ADVERTISED() => '[advertised feature]', INSTALLSTATE_REMOVED() => '[component being removed (action s +tate, not settable)]', INSTALLSTATE_ABSENT() => 'The component is not installed', INSTALLSTATE_LOCAL() => 'The component is installed locally +', INSTALLSTATE_SOURCE() => 'The component is installed to run +from source', INSTALLSTATE_DEFAULT() => '[use default, local or source]', ); { # UINT MsiGetShortcutTarget( # __in LPCTSTR szShortcutTarget, # __out LPTSTR szProductCode, # __out LPTSTR szFeatureId, # __out LPTSTR szComponentCode # ); my $MsiGetShortcutTarget = Win32::API->new( 'msi.dll', 'MsiGetShortcutTarget', 'PPPP', 'N'); sub MsiGetShortcutTarget { my ($szShortcutTarget) = @_; $szShortcutTarget .= "\0"; my $szProductCode = "\0" x 39; my $szFeatureId = "\0" x (MAX_FEATURE_CHARS+1); my $szComponentCode = "\0" x 39; return () if $^E = $MsiGetShortcutTarget->Call( $szShortcutTarget, $szProductCode, $szFeatureId, $szComponentCode, ); s/\0.*//s for $szProductCode, $szFeatureId, $szComponentCode; return ( $szProductCode, $szFeatureId, $szComponentCode ); } } { # INSTALLSTATE MsiGetComponentPath( # __in LPCTSTR szProduct, # __in LPCTSTR szComponent, # __out LPTSTR lpPathBuf, # __inout DWORD *pcchBuf # ); my $MsiGetComponentPath = Win32::API->new( 'msi.dll', 'MsiGetComponentPath', 'PPPP', 'I'); sub MsiGetComponentPath { my ($szProduct, $szComponent) = @_; $szProduct .= "\0"; $szComponent .= "\0"; my $lpPathBuf = "\0" x MAX_PATH; my $pcchBuf = pack('L', MAX_PATH); my $rv = $MsiGetComponentPath->Call( $szProduct, $szComponent, $lpPathBuf, $pcchBuf, ); return ( $rv, substr($lpPathBuf, 0, unpack('L', $pcchBuf)) ); } } { my $shortcut = 'Microsoft Office Word 2007.lnk'; my ($product, $feature, $component) = MsiGetShortcutTarget($shortc +ut) or die("MsiGetShortcutTarget: $^E\n"); say "product: $product"; say "feature: $feature"; say "component: $component"; my ($install_state, $path) = MsiGetComponentPath($product, $component); say "install state: $INSTALLSTATE_DESC{$install_state}"; say "install path: $path"; }

Untested (since I don't know of what advertised shortcuts exist on my machine).

Update: Changed +CONSTANT to CONSTANT() for hash keys.


In reply to Re: A little help with Win32::API? (cleanup) by ikegami
in thread A little help with Win32::API? by flamey

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.