Can't run a managed custom action on uninstall - dll

I have a custom action which should be run on uninstall. But for unknown reason the msiexec says "There is a problem with this Windows Installer package. A DLL required for this install to complete could not be run. Contact your support personnel or package vendor.". The code goes below:
<Binary SourceFile="SetupWiX.CA.dll" Id="Binary1" />
<CustomAction Id="DropDatabase" BinaryKey="Binary1" DllEntry="DropDatabase" Execute="deferred" Return="check"/>
<Custom Action='DropDatabase' After="SetCustomActionDataValue_DropDatabase">Installed</Custom>
I have few other custom actions that run on install and they run fine. Everything is same there except the conditions.
So how can I make my custom action run on uninstall correctly?
I've created a blank wix setup project, and a simple custom action that shows message box on uninstall, and it works fine. I don't know what is the problem with my first custom action.
I use the same DLL on install and uninstall.
The error log goes below:
Action start 16:07:34: INSTALL.
Action start 16:07:34: ValidateProductID.
Action ended 16:07:34: ValidateProductID. Return value 1.
Action start 16:07:34: CostInitialize.
Action ended 16:07:34: CostInitialize. Return value 1.
Action start 16:07:34: FileCost.
Action ended 16:07:34: FileCost. Return value 1.
Action start 16:07:34: CostFinalize.
Action ended 16:07:34: CostFinalize. Return value 1.
Action start 16:07:34: InstallValidate.
Action ended 16:07:34: InstallValidate. Return value 1.
Action start 16:07:34: InstallInitialize.
Action ended 16:07:37: InstallInitialize. Return value 1.
Action start 16:07:37: ProcessComponents.
Action ended 16:07:37: ProcessComponents. Return value 1.
Action start 16:07:37: UnpublishFeatures.
Action ended 16:07:37: UnpublishFeatures. Return value 1.
Action start 16:07:37: RemoveFiles.
Action ended 16:07:37: RemoveFiles. Return value 0.
Action start 16:07:37: InstallFiles.
Action ended 16:07:37: InstallFiles. Return value 1.
Action start 16:07:37: DropDatabase.
Action ended 16:07:37: DropDatabase. Return value 1.
Action start 16:07:37: RegisterUser.
Action ended 16:07:37: RegisterUser. Return value 0.
Action start 16:07:37: RegisterProduct.
Action ended 16:07:37: RegisterProduct. Return value 1.
Action start 16:07:37: PublishFeatures.
Action ended 16:07:37: PublishFeatures. Return value 1.
Action start 16:07:37: PublishProduct.
Action ended 16:07:37: PublishProduct. Return value 1.
Action start 16:07:37: InstallFinalize.
CustomAction DropDatabase returned actual error code 1154 (note this may not be 100% accurate if translation happened inside sandbox)
MSI (s) (D4:DC) [16:07:41:650]: Product: MyProduct -- Error 1723. There is a problem with this Windows Installer package. A DLL required for this install to complete could not be run. Contact your support personnel or package vendor. Action DropDatabase, entry: DropDatabase, library: C:\Windows\Installer\MSI4DEF.tmp
Error 1723. There is a problem with this Windows Installer package. A DLL required for this install to complete could not be run. Contact your support personnel or package vendor. Action DropDatabase, entry: DropDatabase, library: C:\Windows\Installer\MSI4DEF.tmp
Action ended 16:07:41: InstallFinalize. Return value 3.
Action ended 16:07:42: INSTALL. Return value 3.

The problem was in my custom action method being private, not public.

Related

What happens if a rollback custom action fails?

What happens if a rollback custom action fails? Do I need to specify a Return attribute in Wix CustomAction element for a rollback custom action?
I did a quick test. I created a binary custom action:
This is a C++ code:
UINT __stdcall ForceInstallFailure(MSIHANDLE hModule)
{
return ERROR_INSTALL_FAILURE;
}
A Wix code:
<CustomAction Id="CA_ForceInstallFailure" BinaryKey="Bin_CAInst"
DllEntry="ForceInstallFailure"
Execute="rollback" Return="check" Impersonate="no" />
Wix translated it into type 3329:
Type 1 (DLL generated from a binary stream called through an entry point) +
3328 (msidbCustomActionTypeInScript + msidbCustomActionTypeNoImpersonate + msidbCustomActionTypeRollback)
I simulated a rollback with https://wixtoolset.org/docs/v3/customactions/wixfailwhendeferred/
This is what I get in MSI log:
Rollback: CA_ForceInstallFailure
MSI (s) (90:B4) [02:18:54:053]: Executing op: ActionStart(Name=CA_ForceInstallFailure,,)
MSI (s) (90:B4) [02:18:54:053]: Executing op: CustomActionRollback(Action=CA_ForceInstallFailure,ActionType=3329,Source=BinaryData,Target=ForceInstallFailure,)
MSI (s) (90:14) [02:18:54:053]: Invoking remote custom action. DLL: C:\Windows\Installer\MSIC523.tmp, Entrypoint: ForceInstallFailure
CustomAction CA_ForceInstallFailure returned actual error code 1603 but will be translated to success due to continue marking
It looks like Windows Installer doesn't check a custom action return value during a rollback, even though I didn't mark it specifically as Return="ignore" which would translate to msidbCustomActionTypeContinue addition.
Although it logically seems the correct behavior, I could not find any official documentation that describes this.
The Windows Installer does not have rollback for rollback, so it ignores custom action failures during rollback.

Trigger Odoo's Scheduled Action During Specific Hours (e.g. everyday every 1AM to 6AM)

I want to have Scheduled Action that executes one after another from 1AM to 6AM everyday.
How can I achieve this?
Since the only menus I have are "Execute Every" and "Next Execution Date" I do not know how can I mention the specific hours range. I am using Odoo 11.
You can use a wrapper action which is scheduled to run more frequently.
def action_function():
# you will need to store a value (is_running: True|False) in the database, maybe in ir.config_parameter
if current_hour not in (1, 2, 3, 4, 5):
return None
elif is_running:
return None
else:
# Mark that the action is in process, have to commit to the database
is_running = True
self.env.cr.commit()
# Then call your actual action function
do_some_real_thing()
# Mark that the action is done
is_running = False
Basically, the wrapper action of below steps repeats frequently like every 10 minutes.
Check the time, if not between 1am and 6am, do nothing;
Check if the action is already running, if yes, do nothing;
Else, mark that the action as in process, and do the actual thing,
once done, mark the action as finished.

Why is CostFinalize modifying my custom property in one install and not the other?

I have two installs with virtually identical code. I set a custom property like this:
<SetProperty Id="MYCONFIGPATH" Value="[CONFIGPATH]" Before="CostInitialize"/>
And then reference that property in a component:
<Component Id="CopyConfigFromConfigPath" Guid="{XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}" MultiInstance="yes">
<Condition>CONFIGPATH</Condition>
<CopyFile SourceProperty="MYCONFIGPATH" DestinationDirectory="ConfigBOR" DestinationName="ConfigBOR.xml" Id="CopyConfigBOR" />
</Component>
I'm not certain this is what's causing the failure to copy this file but I suspect it is:
MSI (s) (64:6C) [14:03:42:383]: PROPERTY CHANGE: Modifying MYCONFIGPATH property. Its current value is 'C:\Installs\ConfigBOR.xml'. Its new value: 'C:\Installs\ConfigBOR.xml\'.
Notice the trailing backslash. This happens shortly after starting CostFinalize. Just above that log entry are some suspicious looking entries but I can't figure out what they mean so I'm not sure they're relevant:
MSI (s) (64:6C) [14:03:42:380]: Doing action: CostFinalize
MSI (s) (64:6C) [14:03:42:380]: Note: 1: 2205 2: 3: ActionText
and
MSI (s) (64:6C) [14:03:42:382]: Note: 1: 2205 2: 3: Patch
MSI (s) (64:6C) [14:03:42:383]: Note: 1: 2205 2: 3: Condition
I have identical code in another installer (BOR is replaced with the product name in that one) but it doesn't modify this property and does correctly copy this file. Why doesn't it work here?
I don't think your question provides enough information to answer this for certain, but my psychic powers tell me that MYCONFIGPATH is in the Directory table in one package but not in the other. Thus the directory resolution phase of CostFinalize affects the two packages differently.
C:\Installs\ConfigBOR.xml did not exist. I guess WIX picked up on that and, instead of throwing an error, decided to check if a directory with that name were present.

Too Many Events Using DTF InstallLogModes

I'm currently logging "everything" using the following flags:
const DTF.InstallLogModes logEverything = DTF.InstallLogModes.FatalExit |
DTF.InstallLogModes.Error |
DTF.InstallLogModes.Warning |
DTF.InstallLogModes.User |
DTF.InstallLogModes.Info |
DTF.InstallLogModes.ResolveSource |
DTF.InstallLogModes.OutOfDiskSpace |
DTF.InstallLogModes.ActionStart |
DTF.InstallLogModes.ActionData |
DTF.InstallLogModes.CommonData |
DTF.InstallLogModes.Progress |
DTF.InstallLogModes.Initialize |
DTF.InstallLogModes.Terminate |
DTF.InstallLogModes.ShowDialog;
DTF.Installer.SetInternalUI(DTF.InstallUIOptions.Silent);
var handler = new DTF.ExternalUIRecordHandler(ProcessMessage);
DTF.Installer.SetExternalUI(handler, logEverything);
DTF.Installer.EnableLog(logEverything, logPath, true, true);
DTF.Installer.InstallProduct(installerPath, commandLine);
This has the effect of writing an enormous number of events to the log file.
For example, I'm seeing thousands of these:
MSI (s) (14:A0) [11:33:50:764]: Component: comp_27E5179987044690962CE98B3F95FD72; Installed: Local; Request: Null; Action: Null; Client State: Local
MSI (c) (4C:8C) [11:34:17:869]: Creating MSIHANDLE (592) of type 790531 for thread 8076
MSI (c) (4C:8C) [11:34:17:893]: Closing MSIHANDLE (592) of type 790531 for thread 8076
How do I disable those extremely verbose messages in the log? I need to keep the Progress events.
If you don't want them, don't set the bts in the API call. Just set progress. However, you do need to get hold of the error messages and warnings to display them.
However....what's your goal here? You don't need to re-invent the logging that you can get in other ways. The purpose of using that external UI call API is that you are now in charge of all the UI for the install. This isn't really about logging, it's about you being responsible for the UI, and a standard install will typically show all those messages in one form or another. For example, along with progress messages you get action messages that says what's going on (file name being copied, etc). If that is an actual product that you are installing, then you really need to show error messages, files in use dialogs, warnings, or you're simply hiding everything that goes on.
Link to underlying AP docs: https://msdn.microsoft.com/en-us/library/aa370573(v=vs.85).aspx

spring batch| Graceful job termination within the job

After launching a job, in the before job - there are certain occasions where we want to gracefully terminate the job (i.e. dont run the job at all but neither complain i.e .no exception). The current way of doing this looks like invoking jobExecution.stop - However, this results in JobInteruptedException which further results in logger.error invocation.
Is there any other better programmatic alternative (without manual intervention)?
You may read :
Section 5.3.3 Configuring for Stop and
section 5.3.4. Programmatic Flow Decisions.
Just introduce an end element for your first step based on condition:
The 'end' element instructs a Job to stop with a BatchStatus of
COMPLETED.
I solved the problem adding a flag boolean executeTheJob in my "before job" listener that I set to false when I don't want to execute the job.
Then I handle that in my firstStep with this configuration:
<step id="firstStep" >
<tasklet ref="myFirstTasklet"/>
<stop on="STOPPED" restart="firstStep" />
<next on="COMPLETED" to="nextStep"/>
</step>
And at the beginning of my first tasklet I have this:
if (executeTheJob == false) {
contribution.setExitStatus(ExitStatus.STOPPED);
}
stop() instruction will be active only if transaction commit successfully.
If all you chunks rollback your job doesn't stop.
I have make this workaround:
Create a ChunkListener and in the method afterChunkError(ChunkContext chunkCtx) put:
StepExecution stepExecution = chunkCtx.getStepContext().getStepExecution();
JobExecution jobExecution = jobExplorer.getJobExecution(stepExecution.getJobExecutionId());
if (jobExecution.getStatus().equals(BatchStatus.STOPPING)) {
stepExecution.setTerminateOnly();
}
This will force a "controlled" stop.
Instead of invoking stop() on the job execution, try signalling it via the JobOperator as shown in Stopping a Job