简体   繁体   中英

wix 3.7 set property based on script/logic/code

We have developed a pretty comprehensive wix installer msi package, which includes some 10+ c# custom actions.

My problem is that I have yet to figure out how to programmatically "set" a property.

Basically what I want to do is to parse an existing property into a new property.

This parsing would be nice to do in c#, but could also be done in RegEx, JavaScript or w/e.

However I am unable to do this from my c# custom actions ("Cannot access session details from a non-immediate custom action") and as far as I can read I can only change a property from a type 51 custom action. However a type 51 cannot use my c# custom actions. So its catch 22.

Can anyone give give me an example on how to perform the following in wix: Perform a regular expression/string manipulation using the value of one property and setting another with the result.

It seems obvious to me that this should be possible, but after a lot of searching I am still in the dark.

Any help would be appreciated.


Edit #1: After 3 years of working with wix, I still feel like an amateur, but here goes: I thought the only way to send properties and work with them in a custom action was this pattern:

 <CustomAction Id="CA.SetCreateMessageQueueProperty"
                  Property="CA.CreateMessageQueue"
                  Value="MsmqData=.\Private$\[MYAPPLICATIONNAME]/ObservationReportingService.svc,Observation delivery queue"
                  Return="check"/>
    <CustomAction Id="CA.CreateMessageQueue" 
                  BinaryKey="BI.CA" 
                  DllEntry="CreateMessageQueue" 
                  Execute="deferred" 
                  Return="check"
                  Impersonate="no"/>
    <InstallExecuteSequence>
      <Custom Action="CA.SetCreateMessageQueueProperty"
              After="InstallFiles"/>
      <Custom Action="CA.CreateMessageQueue" After="CA.SetCreateMessageQueueProperty">
        <![CDATA[((&FE.Afs=3) AND NOT (!FE.Afs=3))]]>
      </Custom>
    </InstallExecuteSequence>

In the custom action c# assembly:

[CustomAction]
        public static ActionResult CreateMessageQueue(Session session)
        {
            return session.DoCustomAction("CreateMessageQueue",
                () =>
                    {
                        string msmqData = session.ExtractString("MsmqData");

                        //create actual message queue
                            }
                        }
                    });
        }

internal static ActionResult DoCustomAction(this Session session, string name, Action action)
        {
            session.Log("Begin " + name);
            session.Log("session.CustomActionData.Count:" + session.CustomActionData.Count);
            try
            {
                action.Invoke();
            }
            catch (Exception ex)
            {
                session.Log(string.Format("Exception: {0}\nInner Exception: {1}", ex, ex.InnerException));
                return ActionResult.Failure;
            }
            return ActionResult.Success;
        }

I am thinking you are trying to retrieve an existing property and assign it to a new one during a deferred custom action.

<CustomAction Id="SetProperty" Return="check" Property="NameOfCustomActionYouAreUsingToRetrieveProperty" Value="[PROPERTY]"></CustomAction>

As deferred custom actions in the InstallExecuteSequence cannot access the installer properties we have to add the property to CustomActionData .

I wrote my custom actions in C++ but I will post the code and you will get an idea to change it to C# code.

extern "C" UINT __stdcall NameOfCustomActionYouAreUsingToRetrieveProperty(MSIHANDLE hInstall)
{
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
LPWSTR szValueBuf = NULL;

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

WcaLog(LOGMSG_STANDARD, "Initialized.");

hr = WcaGetProperty(L"CustomActionData",&szValueBuf);
ExitOnFailure(hr, "failed to get CustomActionData");

hr = MsiSetProperty(hInstall, "NEWPROPERTY",  szValueBuf);
ExitOnFailure(hr, "failed to set the new property");

LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);     
}

In C#, your code would look something like this:

[CustomAction]
public static ActionResult MyCustomAction(Session session)
{
  string property = session["PROPERTYNAME"];
  session["PROPERTYNAME"] = "Look at me!";
  return ActionResult.Success;
}

The session object has access to the install database and all its tables. And using its indexer, you can get and set any property in the property table.

You also need a small .config file describing the .NET runtime:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v2.0.50727"/>
  </startup>
</configuration>

A lot cleaner than the C++ alternative using MsiGetProperty and MsiSetProperty .

Hopefully, this helps. You can find everything I just wrote in this WiX tutorial , most notably this page .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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