I'm changing our installer to support the possibility of having several versions of our software installed at the same time.
This leads to the scenario where several earlier versions of our product are installed and I need to let the user choose which of the current versions should be upgraded.
Currently I'm using a property called OLDERFOUND to detect if their are older versions at all:
<Upgrade Id='$(var.UpgradeCode)'>
<UpgradeVersion
OnlyDetect='yes'
Property='OLDERFOUND'
Minimum='0.0.0'
Maximum='$(var.Version)'
IncludeMaximum='no'
IncludeMinimum='yes' />
</Upgrade>
On OLDERFOUND a dialog whith a combobox is shown. I dynamically add items to the combobox using a c# CustomAction:
[CustomAction]
public static ActionResult FillVersionList(Session xiSession)
{
View view = xiSession.Database.OpenView("SELECT * FROM ComboBox");
view.Execute();
Record record = xiSession.Database.CreateRecord(4);
//CURRENTVERSIONS is the name of the combobox property
record.SetString(1, "CURRENTVERSIONS");
record.SetInteger(2, 1);
record.SetString(3, "foo");
record.SetString(4, "foo");
view.Modify(ViewModifyMode.InsertTemporary, record);
record = xiSession.Database.CreateRecord(4);
record.SetString(1, "CURRENTIVARVERSIONS");
record.SetInteger(2, 2);
record.SetString(3, "bar");
record.SetString(4, "bar");
view.Modify(ViewModifyMode.InsertTemporary, record);
view.Close();
return ActionResult.Success;
}
What I can't figure out how to do is
populate the combobox with all previous installed versions
and then update the one chosen by the user
I tried to figure out a way to read from the registry to get all versions (I have a registry key for each version installed), but haven't come up with anything. I have no idea how to specify which earlier version to update.
I dont understand why you want the user to select which version to upgrade. When your new product is distributed, it will have an upgrade code/product/package code combination which matches one of the previous installation and it can be used to upgrade ONLY that installation. You wont be able to change that behaviour based on user's decision.
Read more about the upgrade code/product code here:
UPGRADE CODE
Product vs package vs upgrade code
Related
I want to retrieve a list of the extensions excluded from search indexing. Tried this
using Microsoft.Search.Interop;
CSearchManager csm=new CSearchManager();
ISearchCatalogManager iscm = csm.GetCatalog("SystemIndex")
Microsoft.Search.Interop.IEnumString ies = iscm.EnumerateExcludedExtensions();
but it turns out EnumerateExcludedExtensions is not implemented.
Anyone one know of an alternate route?
Thanks
The following does work, retrieving the excluded extensions with the marked get/set-able bool IExtensions.IncludedExtensions at the apparently false-by-default value.
Curious to see that attempting to set that bool to true to get the included extensions instead gens an accessdenied error, and further running as admin, a notimplemented error. I could not find actual documentation.
This worked on Win 7 and Win 10 in my testing, but will have to ship in a try block regardless of course, and if it breaks down the line, not critical in my case, just becomes a missing feature.
using MSSCTLB; // C:\Windows\System32\mssrch.dll "Microsoft Search CoClasses Type Library"
CGatheringManager gm=new CGatheringManager();
IExtensions iexs = gm.GatherApplications["Windows"].GatherProjects["SystemIndex"].Gather.Extensions;
foreach (IExtension item in iexs) listBox1.Items.Add(item.Extension);
also, the extended interfaces can be seen in
MSSITLB, "Microsoft Search Interface Type Library"
"C:\Windows\System32\mssitlb.dll"
Since I switched to VS 2019 (from 2017) I am pretty sure I got a degraded IntelliSense experience. I looked for settings under Tools -> Options... but did not find anything helpful.
The matter is this: suppose I have a variable kvp that has a property Key, I could type "key.", scroll to the "Key" property (if this is not already selected) and then type ";" to complete the statement.
But this does not work anymore. Instead it now ignores what I selected and I get
key.;
The only way to get the selected property is to explicitly hit enter. Same when I type the first character(s) to select the desired option: when pressing ; it just leaves what I already typed and adds the ; immediately behind it, ignoring what I selected in the popup menu.
What happened and how do I get the proper behavior back?
I am using the Preview version but I already had a couple of updates and it does not improve so I guess it is by design or default behavior now.
Here's some of my code for Perry. It is just an example though, the problem (or what I regard to be a problem) occurs with any object variable.
private static void AddBlockNodes(TreeNode node, IDictionary<string, Block> blocks)
{
foreach (KeyValuePair<string, Block> kvp in blocks)
{
string name = kvp.Key;
Block block = kvp.Value;
TreeNode childNode = new TreeNode(name);
childNode.Tag = block;
node.Nodes.Add(childNode);
AddBlockNodes(childNode, block.Subblocks);
}
}
it just leaves what I already typed and adds the ; immediately behind
it, ignoring what I selected in the popup menu.What happened and how
do I get the proper behavior back?
It is quite an abnormal behavior and l have installed Visual Studio 16.6.0 Preview 2.1 and test your code in my side and it works well.
Type variable kvp. and then select property Key and it types as expected. I did not face missing property Key during the process.
You can try these steps to troubleshoot your issue:
Suggestion
1) reset all settings by Tools-->Import and Export Settings-->Reset all settings
2) close VS Instance, enter the project path and delete .vs hidden folder which stores some Intellisense settings, bin, obj folder and then restart your project again. I wonder if you migrate an old project into VS2019 preview version, I think you should complete this step.
3) disable any third party extensions if you have under Extensions-->Manage Extensions in case they cause this behavior.
4) delete all component caches under C:\Users\xxx\AppData\Local\Microsoft\VisualStudio\16.0_xxx(16.0 is VS2019)\ComponentModelCache
5) try to create a new project in VS2019 Preview version and test whether this issue persists in the new platform and if it works, I think it is an issue of your project itself. Or you can try to migrate your project into the new project.
Hope it could help you.
I've recently loaded documents into Drive in C#, but was not aware of the KeepRevisionForever property. Now that I'm trying to upload newer versions of the documents, I'm trying to set this property to true, but it looks like it will only keep this property for the latest update. I.e., I'll upload up to version 5, but the KeepRevisionForever property is only set for version 4, not versions 1 - 3. Can the API allow for keeping revisions for all updates?
Below is the code block where this is being done:
Google.Apis.Drive.v3.Data.File fileUpdate = new Google.Apis.Drive.v3.Data.File
{
Name = doc.Name + "." + doc.ApplicationExtension
, ModifiedTime = doc.DateModified.ToUniversalTime()
};
var update = aobjservice.Files.Update(fileUpdate, doc.GoogleObjectId, docUploadStream, doc.mimetype);
update.KeepRevisionForever = true;
update.Fields = "*";
var task = update.Upload();
UPDATE: I'm up to 34 previous versions of this file, plus the current version (35), and I'm noticing that the older ones get this property checked. And if I keep updating this file, it'll keep updating this property for the file that's 3 versions prior to the current. Below are the version numbers and whether the "Keep revision forever" is checked for that version:
Yes
No
No
No
Yes
According to Manage Revisions, just set the keepRevisionForever to true if you don't want Drive API to auto-purge old revisions:
Google Drive automatically purges (or "prunes") older revisions in
order to optimize disk usage. To prevent this from happening, you can
set the boolean flag keepRevisionForever to true to mark revisions
that you don't want Drive to purge.
I have been trying to build a sort of an update mechanism using the Microsoft Sync framework which would check for changes in one folder(A) and update the same on the other(B). I have a problem where my sync always overwrites the file on the other folder(B). This happens when I set the ConflictResolutionPolicy to source wins or merge. I want the user to have the ability to say Yes overwrite or No skip. Probably like the windows dialog box when we are copying files and when there is a conflict between files of the same name. I would really appreciate it if someone could help me or would give me a lead to some documentation on how to get this dialog box functionality when there is a conflict between files.
This is what I do right now but I can't get it to do anything. There are files that are of the same name but different time-stamps which has to trigger a conflict but doesn't unfortunately in my case.
private void OnItemConflicting(object sender, ItemConflictingEventArgs args)
{
args.SetResolutionAction(ConflictResolutionAction.SaveConflict);
Console.WriteLine(" Conflict detected for item " + args.DestinationChange.ItemId.ToString());
}
private void OnItemConstraint(object sender, ItemConstraintEventArgs args)
{
args.SetResolutionAction(ConstraintConflictResolutionAction.RenameDestination);
ConstraintConflictResolutionAction.RenameDestination.ToString();
Console.WriteLine(" Constraint conflict detected" + args.DestinationChange.ItemId.ToString());
}
if you set the conflict resolution to source wins, then of course it will overwrite the destination.
displaying the dialog box is outside of the framework's scope already.
you can handle an event when a conflict fires or you can preview the changes before you sync. you can display or prompt the user for the options to resolve the conflict
both scenarios are covered in the documentation that gets installed with the SDK
I'm writing an application which changes Crystal Reports database access parameters in report files. I open reports witin a .NET windows forms app and apply the SDK functionality to change driver type (ODBC/OLEDB), server name, database name, user, password, authentication type etc. I'm having a problem with the database name. My code DOES change the specific properties of the table ConnectionInfo (in subreports too) but fails to update the general SQL Query within the report. This results in the report still accessing the old database.
So if the original report was configured to access database_1 and I'm changing it to database_2, it will have all table properties properly changed to database_2 (verifiable in the Designer). It will still have database_1 in the query though. The database name remains unchanged in both the SDK RowsetController.GetSQLStatement() result and in the Crystal Reports Developer query view (Database->Show SQL Query...).
Also I have to have both databases (database_1 and database_2) online while the conversion takes place, otherwise I get exceptions on either GetSQLStatement(when database_1 is offline; becuase it still refers to it) or SetTableLocation (when database_2 is offline - this is expected and acceptable behavior though). If both db are online, there are no errors.
Here is exactly what I'm using:
1) CrystalDecisions.CrystalReports.Engine.ReportDocument.Load(filePath, OpenReportMethod.OpenReportByTempCopy)
(...)
2) Make and fill CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag
3) Iterate through CrystalDecisions.ReportAppServer.DataDefModel.Tables and apply all properties with SetTableLocaiton() for each one.
4) Repeat with each subreport
5) RowsetController.GetSQLStatement() to view the report's sql query.
Is there some way to update the query basing on the new table ConnectionInfos (which seem to be set properly)? I don't even see any possibility of manually updating the query (GET, search&replace, SET).
I'm using:
.NET 4.5,
Visual Studio 2012,
CR for VS 13.0.5,
Crystal Reports Developer 9.2.2.693 for results verification (source reports are also created with it)
Answer: set propper QualifiedName for each table. The QualifiedName is the full name of the table including the DbName. This later appears in the SQL Query of the report. By qualified name we understand:
myDatabase.mySchema.myTableName
Code example:
CrystalDecisions.ReportAppServer.DataDefModel.Table boTable = new CrystalDecisions.ReportAppServer.DataDefModel.Table();
CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag boMainPropertyBag = new CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag();
CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag boInnerPropertyBag = new CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag();
// Custom function to fill property bags with values which influence the table properties as seen in CR Developer
FillPropertyBags(boMainPropertyBag, boInnerPropertyBag);
CrystalDecisions.ReportAppServer.DataDefModel.ConnectionInfo boConnectionInfo = new CrystalDecisions.ReportAppServer.DataDefModel.ConnectionInfo();
boConnectionInfo.Attributes = boMainPropertyBag;
boConnectionInfo.Kind = CrystalDecisions.ReportAppServer.DataDefModel.CrConnectionInfoKindEnum.crConnectionInfoKindCRQE;
boTable.ConnectionInfo = boConnectionInfo;
CrystalDecisions.ReportAppServer.DataDefModel.Tables boTables = boReportDocument.ReportClientDocument.DatabaseController.Database.Tables;
for (int i = 0; i < boTables.Count; i++)
{
boTable.Name = boTables[i].Name;
// the QualifiedName is directly taken into the CR general query so this is a quick fix to change it
boTable.QualifiedName = boTables[i].QualifiedName.Replace("oldDbName", "newDbName");
boTable.Alias = boTables[i].Alias;
boReportDocument.ReportClientDocument.DatabaseController.SetTableLocation(boTables[i], boTable);
}
Uhh...Researching for whole day and found answer after publishing question on SO.