Search code examples
c#windows-installerinterop

MsiSourceListEnumSources interop c#


I am trying to get the source locations from an installed msi products using the MsiSourceListEnumSources api call.

I always get an invalid_parameter return and cannot figure this out.

[DllImport(MSI_LIB, CharSet = CharSet.Auto)]
    [return: MarshalAs(UnmanagedType.U4)]
    internal static extern MsiError MsiSourceListEnumSources(
        string szProductOrPatchCode,
        string szUserSid,
        MsiInstallContext dwContext,
        MsiCode dwOptions,
        int dwIndex,
        [Out] StringBuilder szSource,
        ref int pcchSource);


[Flags]
public enum MsiInstallContext :int
{
    MsiinstallcontextNone = 0,
    MsiinstallcontextUsermanaged = 1,
    MsiinstallcontextUserunmanaged = 2,
    MsiinstallcontextMachine = 4,

    MsiinstallcontextAll =
        (MsiinstallcontextUsermanaged | MsiinstallcontextUserunmanaged | MsiinstallcontextMachine),

    MsiInstallContext_AlluserManaged = 8
}


[Flags]
public enum MsiCode : int
{
    MSICODE_PRODUCT = 0,
    MSISOURCETYPE_NETWORK = 1,
    MSISOURCETYPE_URL = 2
}

 var productCode = "{E636F802-3504-4DE0-92AD-2A47138974FA}";
 var counter = 0;
 int MAX_PATH = 260;
 var strOutPut = new StringBuilder(MAX_PATH);
 int sizeOf = MAX_PATH;
 string EveryOne = "s-1-1-0";
 string sid = UserPrincipal.Current.Sid.ToString();

 var success = MsiInterop.MsiSourceListEnumSources(
            productCode, null, MsiInstallContext.MsiinstallcontextMachine , MsiCode.MSICODE_PRODUCT , counter,  strOutPut, ref sizeOf );

I cannot figure out what I am doing wrong, I have tried like a hundred and one different combinations.


Solution

  • This works for me:

    [DllImport("msi", CharSet = CharSet.Unicode)]
        public static extern int MsiSourceListEnumSourcesW(string pc,string sid, MsiInstallContext ctx, MsiCode opts, int index,  [Out] StringBuilder szResult, ref int len);
    }
    

    together with your enumerations and this call:

    int len = 16384;
    StringBuilder thing = new StringBuilder(null, len); 
    int rf = MsiInvoke.MsiSourceListEnumSourcesW(ProdCode, null, 
                    MsiInvoke.MsiInstallContext.MsiinstallcontextMachine,
                    MsiInvoke.MsiCode.MsiProdN,
                    0, 
                    thing,
                    ref len);
    

    The error in your code appears to be that you can't just set the MSICODE_PRODUCT flag, you must set a sourcetype flag, and the network flavor works.