简体   繁体   English

如何在 WIX 中使用来自 MSI 安装程序的 OrignalDatabase 并将其传递给 C++ 自定义操作代码

[英]How do I use the OrignalDatabase from MSI Installer in WIX and pass it to the C++ custom action code

Introduction: I have a codebase being used for the updation of the MSI and that I am doing using the MD5 hash and every-time an update arrives at server, the code has functionalities that check the MD5 from DB and if it doesn't match then update it but for the first time when a new user installs it I need to find the current hash of the MSI at runtime, since user can change it's location and name and it can result in hash changes.简介:我有一个用于更新 MSI 的代码库,并且我正在使用 MD5 hash 并且每次更新到达服务器时,该代码都具有检查 DB 中的 MD5 以及是否不匹配的功能然后更新它,但是当新用户第一次安装它时,我需要在运行时找到 MSI 的当前 hash,因为用户可以更改它的位置和名称,它可能导致 hash 更改。

Problem Statement: I have the WIX Installer for my MSI and I want to get to get the [Original Database] property from the WIX and send it to the C++ Custom Action DLL for generating MD5 at runtime, I am looking to do it post installation because the Database will be setup after the installation and the app starts running. Problem Statement: I have the WIX Installer for my MSI and I want to get to get the [Original Database] property from the WIX and send it to the C++ Custom Action DLL for generating MD5 at runtime, I am looking to do it post installation因为数据库将在安装后设置并且应用程序开始运行。 So I can store the MD5 in a temporary file or do it post installation.所以我可以将 MD5 存储在一个临时文件中或在安装后进行。 I know other people also have questions already posted on StackOverflow regarding OriginalDatabase but I couldn't find them quite satisfactory and addressing the problem that I am facing and there was no proper code example for this and so I am writing this question.我知道其他人也已经在 StackOverflow 上发布了关于OriginalDatabase的问题,但我找不到它们非常令人满意并解决了我面临的问题,并且没有合适的代码示例,所以我正在写这个问题。

The problem I am facing are these我面临的问题是这些

  1. How to get the path in WIX and send it to the C++ Custom Action如何获取 WIX 中的路径并将其发送到 C++ 自定义操作
  2. How to store the MD5 in the DB through WIX, though this is not too important but if I can get a solution for this, it would be great.如何通过 WIX 将 MD5 存储在数据库中,虽然这不是太重要,但如果我能找到解决方案,那就太好了。

WIX Code: WIX 代码:

<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
    xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">

<Product Id="{}" UpgradeCode="{}" 
        Name="Secureone Agent" Version="1.0.0" Manufacturer="MJ Inc." Language="1033">

    <Package InstallerVersion="200" Compressed="yes" Comments="MJ Client Installer Package" Platform="x64"/>
    <Media Id="1" Cabinet="product.cab" EmbedCab="yes"/>

    <!-- Pre-Install checks -->

    <Condition Message="This application is only supported on Windows Vista, Windows Server 2008, or higher.">
        <![CDATA[Installed OR (VersionNT >= 600)]]>
    </Condition>

    <Condition Message="Setup can not be installed on x32 machine.">
      <![CDATA[Not VersionNT32]]>
    </Condition>

    
    <?define Platform=x64 ?>
    <?define BIN_PATH='.\bin' ?>
    <?if $(var.Platform) = x64 ?>
    <?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
    <?else ?>
    <?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?>
    <?endif ?>

    
    <!-- License agreement -->
    <WixVariable Id="WixUILicenseRtf" Value=".\eula\eula-en.rtf" />

    <!--Application logo-->
    <Icon Id="Logo.ico" SourceFile=".\resources\logo.ico" />

    <!--Application logo for Control Panel-->
    <Property Id="ARPPRODUCTICON" Value="Logo.ico" />

    <!--Top Banner UI Logo-->
    <WixVariable Id="WixUIBannerBmp" Overridable="yes" Value=".\resources\TopBanner.jpg" />
    <!--Verticle Banner UI Logo-->
    <WixVariable Id="WixUIDialogBmp" Overridable="yes" Value=".\resources\BackgroundLogo.jpg" />
    
    <Directory Id="TARGETDIR" Name="SourceDir">
        <Directory Id="$(var.PlatformProgramFilesFolder)">
            <Directory Id="INSTALLDIR" Name="Secureone">
               <Component Id="ServiceConfigFile" Guid="{}">
                  <File Id="ServiceConfigFile" Source="$(var.BIN_PATH)\core.db"/>
               </Component>
               <Component Id="ServiceFile" Guid="{}">
                  <File Id="ServiceFile" Source="$(var.BIN_PATH)\lzsvc.exe"/>
<!-- Install service -->
                  <ServiceInstall Id="ServiceInstaller"
                                    Type="ownProcess"
                                    Name="LZAgentService"
                                    DisplayName="LZ Agent Service"
                                    Description="Service for LZ Agent"
                                    Start="auto"
                                    ErrorControl="normal"
                                    Account="LocalSystem">
                        <util:ServiceConfig 
                                            FirstFailureActionType="restart"
                                            SecondFailureActionType="restart"
                                            ThirdFailureActionType="none"
                                            ResetPeriodInDays="1"
                                            RestartServiceDelayInSeconds="0" />
                    </ServiceInstall>
                    <ServiceControl Id="Service_start" Start="install" Stop="both" Name="LZAgentService" Wait="no" />
                    <ServiceControl Id="Service_stop" Stop="both" Remove="uninstall" Name="LZAgentService" Wait="no" />
<!-- Install service end -->    
                </Component>
            </Directory>
        </Directory>
    </Directory>
    
    <UIRef Id="WixUI_Minimal"/>

    <Feature Id="DefaultFeature" Level="1">
        <ComponentRef Id="ServiceFile"/>
        <ComponentRef Id="ServiceConfigFile"/>
        <ComponentRef Id="ProductComponent" />
    </Feature>
    <InstallExecuteSequence>
        <Custom Action="RollbackCA" After="InstallFiles" />
        <Custom Action='UserAuth' After='InstallFiles'/>
    </InstallExecuteSequence>
</Product>

<Fragment>
    <ComponentGroup Id="ProductComponents" Directory="INSTALLDIR">
        <Component Id="ProductComponent" Guid="{B2C908AF-C09A-41D0-92D1-AC7BEAC8F68D}">
            <RemoveFile Id='lzsvc_log' On='uninstall' Name='lzsvc.log' />
            <RemoveFile Id='lzsvc.log.bak' On='uninstall' Name='lzsvc.log.bak' />
            <RemoveFile Id='lzcore_log' On='uninstall' Name='lzcore.log' />
         </Component>
    </ComponentGroup>
</Fragment>
   
<Fragment>
    <CustomAction Id='UserAuth'
                  BinaryKey='AuthBinary'
                  DllEntry='AuthenticateUser'
                  Execute='deferred'
                  Return='check'
                  Impersonate="yes"
                />
                
    <CustomAction Id='RollbackCA'
                      BinaryKey='AuthBinary'
                      DllEntry='RollbackInstall'
                      Execute='rollback'
                      Return='check'
                      Impersonate="yes"
                />

    <Binary Id='AuthBinary' SourceFile='$(var.BIN_PATH)\CustomAction.dll'/>
</Fragment>   
   
</Wix>

So the answer was actually a bit tricky at first but then I found it as my senior helped in it, so here it is.所以答案一开始实际上有点棘手,但后来我发现它是我的前辈帮助的,所以就在这里。 Currently this code finds the current path of the MSI on runtime and writes the MD5 of it in the C:\Windows\Temp\Path.txt but don't forget to include the md5 and md5wrapper header files and cpp files in the project.目前,此代码在运行时查找 MSI 的当前路径,并将其 MD5 写入C:\Windows\Temp\Path.txt但不要忘记在项目中包含md5md5wrapper header 文件和 cpp 文件。

C++ Custom Action: C++ 自定义操作:

void MD5ToDB(MSIHANDLE hInstall)
{
    TCHAR* szValueBuf=NULL;
    DWORD cchValueBuf = 0;
    UINT uiStat = MsiGetProperty(hInstall, TEXT("OriginalDatabase"), TEXT(""), &cchValueBuf);
    //cchValueBuf now contains the size of the property's string, without null termination
    if (ERROR_MORE_DATA == uiStat)
    {
        ++cchValueBuf; // add 1 for null termination
        szValueBuf = new TCHAR[cchValueBuf];
        if (szValueBuf)
        {
            uiStat = MsiGetProperty(hInstall, TEXT("OriginalDatabase"), szValueBuf, &cchValueBuf);
        }
        
    }
    if (ERROR_SUCCESS != uiStat)
    {
        if (szValueBuf != NULL)
            delete[] szValueBuf;
        return;
    }

    //Convert tcahr to char
    
    char* charWindowsPropertyValue = NULL;
    charWindowsPropertyValue = new CHAR[cchValueBuf];
    wcstombs(charWindowsPropertyValue, szValueBuf, wcslen(szValueBuf) + 1);//Converting tchar to char
    std::string filePath(charWindowsPropertyValue);//converting char array to string
    md5wrapper md5;
    std::string hash = md5.getHashFromFile(filePath);//claculating md5 of the file path as string.
    FILE* fp=NULL;
    fopen_s(&fp,"C:\\Windows\\Temp\\Path.txt", "w+");//creating and writing to Path.txt
    if (NULL != fp) {
        fwrite(hash.c_str(), hash.length(), 1, fp);
        fclose(fp);
    }
    
}



UINT __stdcall ExtractingProperty(
    MSIHANDLE hInstall
)
{
    HRESULT hr = S_OK;
    UINT er = ERROR_SUCCESS;

    hr = WcaInitialize(hInstall, "ExtractingProperty");
    ExitOnFailure(hr, "Failed to initialize");

    WcaLog(LOGMSG_STANDARD, "Initialized.");
    MD5ToDB(hInstall);


LExit:
    er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
    return WcaFinalize(er);
}
//Code was mostly taken from MSDN and the main attempt was to get the MD5 of the path after obtaining the path.

WIX File WIX文件

<Custom Action="MD5ToDB" After"<Some Action>"/>

<CustomAction Id="MD5ToDB" 
                    BinaryKey="AuthBinary" 
                    DllEntry="ExtractingProperty" 
                    Execute="immediate" 
                    Return="check" />
    

Don't forget to add the function name in WIX .def file.不要忘记在 WIX .def文件中添加 function 名称。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM