Custom icon for ClickOnce application in 'Add or Remove Programs' - wix

A ClickOnce application created using Mage is not showing the icon that was specified in for the Mage command-line parameter in control panel Add or Remove Programs.
I read some blogs, like:
Application icon is not displayed in Add/Remove Programs dialog
Missing Icon in Add/Remove Programs for ClickOnce Application
How can I achieve this without editing registry keys? Is it possible?

There's no way to do this without editing the registry, but you can do it programmatically. You have to be sure the icon is included in the deployment. We set our assembly description to the same string as our Product Name, so we can look through the uninstall strings for the right application by searching for the assembly description. This way, we don't have to hardcode the product name in this code.
private static void SetAddRemoveProgramsIcon()
{
//only run if deployed
if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed
&& ApplicationDeployment.CurrentDeployment.IsFirstRun)
{
try
{
Assembly code = Assembly.GetExecutingAssembly();
AssemblyDescriptionAttribute asdescription =
(AssemblyDescriptionAttribute)Attribute.GetCustomAttribute(code, typeof(AssemblyDescriptionAttribute));
string assemblyDescription = asdescription.Description;
//the icon is included in this program
string iconSourcePath = Path.Combine(System.Windows.Forms.Application.StartupPath, "youriconfile.ico");
if (!File.Exists(iconSourcePath))
return;
RegistryKey myUninstallKey = Registry.CurrentUser.OpenSubKey(#"Software\Microsoft\Windows\CurrentVersion\Uninstall");
string[] mySubKeyNames = myUninstallKey.GetSubKeyNames();
for (int i = 0; i < mySubKeyNames.Length; i++)
{
RegistryKey myKey = myUninstallKey.OpenSubKey(mySubKeyNames[i], true);
object myValue = myKey.GetValue("DisplayName");
if (myValue != null && myValue.ToString() == assemblyDescription)
{
myKey.SetValue("DisplayIcon", iconSourcePath);
break;
}
}
}
catch (Exception ex)
{
//log an error
}
}
}

Related

JavaFX - set programmatically the destination path to print directly a node to pdf file

I want to print a node to a pdf file using "Microsoft Print to PDF" printer. Supposing that the Printer object is already extracted I have the next function which is working perfectly.
public static void printToPDF(Printer printer, Node node) {
PrinterJob job = PrinterJob.createPrinterJob(printer);
if (job != null) {
job.getJobSettings().setPrintQuality(PrintQuality.HIGH);
PageLayout pageLayout = job.getPrinter().createPageLayout(Paper.A4, PageOrientation.PORTRAIT,
Printer.MarginType.HARDWARE_MINIMUM);
boolean printed = job.printPage(pageLayout, node);
if (printed) {
job.endJob();
} else {
System.out.println("Printing failed.");
}
} else {
System.out.println("Could not create a printer job.");
}
}
The only issue that I have here, is that a dialog box is popping up and asking for a destination path to save the pdf. I was struggling to find a solution to set the path programmatically, but with no success. Any suggestions? Thank you in advance.
After some more research I came with an ugly hack. I accessed jobImpl private field from PrinterJob, and I took attributes out of it. Therefore I inserted the destination attribute, and apparently it is working as requested. I know it is not nice, but ... is kind of workable. If you have any nicer suggestion, please do not hesitate to post them.
try {
java.lang.reflect.Field field = job.getClass().getDeclaredField("jobImpl");
field.setAccessible(true);
PrinterJobImpl jobImpl = (PrinterJobImpl) field.get(job);
field.setAccessible(false);
field = jobImpl.getClass().getDeclaredField("printReqAttrSet");
field.setAccessible(true);
PrintRequestAttributeSet printReqAttrSet = (PrintRequestAttributeSet) field.get(jobImpl);
field.setAccessible(false);
printReqAttrSet.add(new Destination(new java.net.URI("file:/C:/deleteMe/wtv.pdf")));
} catch (Exception e) {
System.err.println(e);
}

Loading Xaml via XamlReader only for Preview

just got some Problems with Loading Xaml Files by Runtime.
For your Information my Code-Snippet to Load the File as Content of a Usercontrol:
public UserControl LoadXaml(FileInfo paramFile)
{
FileInfo _XamlFile = paramFile;
UIElement rootElement;
FileStream s = new FileStream(_XamlFile.FullName, FileMode.Open);
rootElement = (UIElement)XamlReader.Load(s);
s.Close();
UserControl uc = new UserControl();
if (rootElement.GetType() == typeof(Window))
{
uc.Content = (rootElement as Window).Content;
}
else
{
uc = rootElement as UserControl;
}
return uc;
}
private void lstPDFDokumente_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var _XamlFile = ((System.Windows.Controls.ListBox)sender).SelectedItem as FileInfo;
if (_XamlFile != null)
{
layoutGrid.Children.Clear();
System.Windows.Controls.UserControl rootElement;
rootElement = XamlController.LoadXaml(_XamlFile);
layoutGrid.Children.Add(rootElement);
}
}
This works fine while Events and x:Class="..." are deleted by hand.
The Problems I try to solve are:
If there is a x:Class="..." at the root element the XamlReader throws the first exception.
When the XamlReader reaches a Control which contains an event, for Example Click or TextChanged, it throws another Exception.
What i try to figure out is how to load a XamlFile, show it inside of a Control in the main Window and to show some of the attributes like Name,Height,Width and so on.
Just read dozens of Websites but never found a topic about to make a preview or things like that.
One of the solutions i tried is to read the Xaml File as XML and delete that code.
The Problem was to get a list of all possible Events in C#.
If there are some Questions to that Code, feel free to ask :)
Greetings
Daniel

How to get a deep link of my application from the Windows Phone Marketplace using .NET code?

How do I get a deep link of my application programmatically from the Windows Phone Marketplace, so that I can use it in my code?
Getting the AppDeeplink is quite useful for example in ShareStatusTask and ShareLinkTask.
It is possible, however you have to use some non-trivial code for getting the real AppID from within your app Manifest file. Here's what I do:
First save somewhere in resources the string for Windows Phone app deeplinks, this is simple:
"http://windowsphone.com/s?appId={0}"
Then you have to find the real AppId by opening the App Manifest file and finding the proper tag, I use this code inside my MarketplaceHelper for doing so:
static MarketplaceHelper()
{
try
{
// load product details from WMAppManifest.xml
XElement app = XElement.Load("WMAppManifest.xml").Descendants("App").Single();
Title = GetValue(app, "Title");
Version = new Version(GetValue(app, "Version"));
Author = GetValue(app, "Author");
Publisher = GetValue(app, "Publisher");
Description = GetValue(app, "Description");
// remove the surrounding braces
string productID = GetValue(app, "ProductID");
ProductID = Regex.Match(productID, "(?<={).*(?=})").Value;
}
catch (Exception e)
{
// should not happen, every application has this field and should containt the ProductID and Version
}
}
private static string GetValue(XElement app, string attrName)
{
XAttribute at = app.Attribute(attrName);
return at != null ? at.Value : null;
}
If the Manifest is there and is properly formatted, and it should be, otherwise the app won't work, you can get this way any data you want.
Now you can construct the deeplink like this:
string deeplink = string.Format(AppResources.DeepLinkFormat, MarketplaceHelper.ProductID);

How do I use Sitecore.Data.Serialization.Manager.LoadItem(path,LoadOptions) to restore a item to Sitecore?

I am trying to use the sitecore API to serialize and restore sitecore items. I have created a WCF app to retrieve an Item name given a ID or sitecore path (/sitecore/content/home), retrieve a list of the names of the items children give an id or path. I can also Serialize the content tree.
public void BackupItemTree(string id)
{
Database db = Sitecore.Configuration.Factory.GetDatabase("master");
Item itm = db.GetItem(id);
Sitecore.Data.Serialization.Manager.DumpTree(itm);
}
The above code works great. After running it can see that the content tree has been serialized.
However when I try to restore the serialized items useing the following:
public void RestoreItemTree(string path)
{
try
{
using (new Sitecore.SecurityModel.SecurityDisabler())
{
Database db = Sitecore.Configuration.Factory.GetDatabase("master");
Data.Serialization.LoadOptions opt = new Data.Serialization.LoadOptions(db);
opt.ForceUpdate = true;
Sitecore.Data.Serialization.Manager.LoadItem(path, opt);
//Sitecore.Data.Serialization.Manager.LoadTree(path, opt);
}
}
catch (Exception ex)
{
throw ex;
}
}
With this code I get no errors. It runs, but if I check SiteCore it didn't do anything. I have tested using the Office Core example. The path I sent in, which might be the issue is:
C:\inetpub\wwwroot\sitecoretest\Data\serialization\master\sitecore\content\Home\Standard-Items\Teasers\Our-Clients.item
and
C:\inetpub\wwwroot\sitecorebfahnestockinet\Data\serialization\master\sitecore\content\Home\Standard-Items\Teasers\Our-Clients
Neither seems to do anything. I changed the teaser title of the item and am trying to restore to before the but every time the change is still present.
Any help would be appreciated as the SiteCore documentation is very limited.
You can always check how the Sitecore code works using Reflector, the following method is called when you click "Revert Item" in back-end:
protected virtual Item LoadItem(Item item, LoadOptions options)
{
Assert.ArgumentNotNull(item, "item");
return Manager.LoadItem(PathUtils.GetFilePath(new ItemReference(item).ToString()), options);
}
In LoadOptions you can specify whether you want to overwrite ("Revert Item") or just update ("Update Item") it.
See Sitecore.Shell.Framework.Commands.Serialization.LoadItemCommand for more info.
You have the correct LoadOptions for forcing an overwrite (aka Revert).
I suspect that the path you are using for the .item file wrong. I would suggest modifying your method to take a path to a Sitecore item. Using that path, you should leverage other serialization APIs to determine where the file should be.
public void RestoreItemTree(string itemPath)
{
Sitecore.Data.Database db = Sitecore.Configuration.Factory.GetDatabase("master");
Sitecore.Data.Serialization.ItemReference itemReference = new Sitecore.Data.Serialization.ItemReference(db.Name, itemPath);
string path = Sitecore.Data.Serialization.PathUtils.GetFilePath(itemReference.ToString());
Sitecore.Data.Serialization.LoadOptions opt = new Sitecore.Data.Serialization.LoadOptions(db);
opt.ForceUpdate = true;
using (new Sitecore.SecurityModel.SecurityDisabler())
{
Sitecore.Data.Serialization.Manager.LoadItem(path, opt);
}
}
Took me a while to work out, but you have to remove .item when restoring the tree
try this
public void RestoreItemTree(string itemPath)
{
var db = Factory.GetDatabase("master");
var itemReference = new ItemReference(db.Name, itemPath);
var path = PathUtils.GetFilePath(itemReference.ToString());
if (!System.IO.File.Exists(path))
{
throw new Exception("File not found " + path);
}
var opt = new LoadOptions(db);
opt.ForceUpdate = true;
using (new SecurityDisabler())
{
Manager.LoadItem(path, opt);
Manager.LoadTree(path.Replace(".item", ""), opt);
}
}

SharePoint 2010 Rename Document on Upload Fails in Explorer View

I'm trying to implement a customization in SharePoint 2010 so that when a document is uploaded to a library, the file name is changed to include the Document ID in the name. (I know that people shouldn't worry about file names as much any more, but we have a lot of legacy files already named and users who like to have local copies).
I was able to implement a custom Event Receiver on the ItemAdded event that renames the file by adding the Document ID before the file name. This works correctly from the web Upload.
The problem is with the Explorer View. When I try to add the file using WebDAV in the Explorer View, I get two copies of the file. It seems that when a file is uploaded via the Web the events that fire are
ItemAdding
ItemAdded
But when I copy/paste a file into Explorer View I see the following events:
ItemAdding
ItemAdded
ItemAdding
ItemAdded
ItemUpdating
ItemUpdated
The result is I have two files with different names (since the Document IDs are different).
I've found a lot of people talking about this issue online (this is the best article I found). Anyone have any other ideas? Would it make more sense to do this in a workflow instead of an event receiver? I could use a scheduled job instead, but that might be confusing to the user if the document name changed a few minutes later.
This is my code that works great when using the Web upload but not when using Explorer View:
public override void ItemAdded(SPItemEventProperties properties)
{
try
{
SPListItem currentItem = properties.ListItem;
if (currentItem["_dlc_DocId"] != null)
{
string docId = currentItem["_dlc_DocId"].ToString();
if (!currentItem["BaseName"].ToString().StartsWith(docId))
{
EventFiringEnabled = false;
currentItem["BaseName"] = docId + currentItem["BaseName"];
currentItem.SystemUpdate();
EventFiringEnabled = true;
}
}
}
catch (Exception ex)
{
//Probably should log an error here
}
base.ItemAdded(properties);
}
I have found that using a Visual Studio workflow allows me the most flexibility to do this. A SharePoint Designer Workflow would be simpler, but would be harder to deploy to different sites and libraries.
After reading some good articles including this and this I have come up with this code which seems to work. It starts a workflow and waits until the document is not in a LockState and then processes the filename.
The workflow looks like this:
And here is the code behind:
namespace ControlledDocuments.RenameWorkflow
{
public sealed partial class RenameWorkflow : SequentialWorkflowActivity
{
public RenameWorkflow()
{
InitializeComponent();
}
public Guid workflowId = default(System.Guid);
public SPWorkflowActivationProperties workflowProperties = new SPWorkflowActivationProperties();
Boolean continueWaiting = true;
private void onWorkflowActivated1_Invoked(object sender, ExternalDataEventArgs e)
{
CheckFileStatus();
}
private void whileActivity(object sender, ConditionalEventArgs e)
{
e.Result = continueWaiting;
}
private void onWorkflowItemChanged(object sender, ExternalDataEventArgs e)
{
CheckFileStatus();
}
private void CheckFileStatus()
{
if (workflowProperties.Item.File.LockType == SPFile.SPLockType.None)
{
continueWaiting = false;
}
}
private void renameFile(object sender, EventArgs e)
{
try
{
SPListItem currentItem = workflowProperties.Item;
if (currentItem["_dlc_DocId"] != null)
{
string docId = currentItem["_dlc_DocId"].ToString();
if (!currentItem["BaseName"].ToString().StartsWith(docId))
{
currentItem["BaseName"] = docId + currentItem["BaseName"];
currentItem.SystemUpdate();
}
}
}
catch (Exception ex)
{
//Should do something useful here
}
}
}
}
Hope this helps someone else if they have the same problem.
Well i'd go for the workflow workaround... there are 2 options imo:
1) Create a boolean fied in your document library, then create a SPD workflow that fires when the item is added and set that field to "Changed" or something. In the EventReceiver you then check whether that field has been set..
2) Do everything with the SPD workflow - changing the title like in this example should be no problem.