im an currently following this guide to add windows toast notifications to my app.
https://learn.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/send-local-toast-desktop
i need to create a shortcut that contains the System.AppUserModel.ID and System.AppUserModel.ToastActivatorCLSID.
now the website says to just have your installer create this and they recommend using WIX. which is fine but i would rather just create the shortcut from C# code.
so there is this example that creates the shortcut via C#.
https://code.msdn.microsoft.com/windowsdesktop/sending-toast-notifications-71e230a2
but it only shows adding the AppUserModel.ID and not the ToastActivatorCLSID...
here is some of that code...
private void InstallShortcut(String shortcutPath)
{
// Find the path to the current executable
String exePath = Process.GetCurrentProcess().MainModule.FileName;
IShellLinkW newShortcut = (IShellLinkW)new CShellLink();
// Create a shortcut to the exe
ShellHelpers.ErrorHelper.VerifySucceeded(newShortcut.SetPath(exePath));
ShellHelpers.ErrorHelper.VerifySucceeded(newShortcut.SetArguments(""));
// Open the shortcut property store, set the AppUserModelId property
IPropertyStore newShortcutProperties = (IPropertyStore)newShortcut;
using (PropVariant appId = new PropVariant(APP_ID))
{
ShellHelpers.ErrorHelper.VerifySucceeded(newShortcutProperties.SetValue(System Properties.System.AppUserModel.ID, appId));
ShellHelpers.ErrorHelper.VerifySucceeded(newShortcutProperties.Commit());
}
// Commit the shortcut to disk
IPersistFile newShortcutSave = (IPersistFile)newShortcut;
ShellHelpers.ErrorHelper.VerifySucceeded(newShortcutSave.Save(shortcutPath, true));
}
the thing is that the AppUserModel does not have a ToastActivatorCLSID property. seems strange.
i figured i could just add another using block to add the ToastActivatorCLSID property like this
using (PropVariant clsId = new PropVariant(CLSID))
{
ShellHelpers.ErrorHelper.VerifySucceeded(newShortcutProperties.SetValue(System Properties.System.AppUserModel.ToastActivatorCLSID, CLSID));
ShellHelpers.ErrorHelper.VerifySucceeded(newShortcutProperties.Commit());
}
but the SystemProperties.System.AppUserModel.ToastActivatorCLSID doesnt exist.
right now the appuser model is coming from Microsoft.WindowsAPICodePack.Shell.PropertySystem.
this page shows it should exist
https://learn.microsoft.com/en-us/windows/desktop/properties/props-system-appusermodel-toastactivatorclsid
i would if with that information i could make some kind of interface or something to add in that ToastActivatorCLSID.
there is very little on the internet on this topic. Don't know if there is a different reference or something.
any help would be great
I've been running into the same problem and I've found a work around.
Clone this github repo: https://github.com/aybe/Windows-API-Code-Pack-1.1
open the WindowsAPICodePack12.sln in visual studio.
open Shell > PropertySystem > SystemProperties.cs
find the AppUserModel class on line 2302
add this code to the class:
public static PropertyKey ToastActivatorCLSID
{
get
{
PropertyKey key = new PropertyKey(new Guid("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}"), 26);
return key;
}
}
Build the project. Open the bin folder (where the built projects go) and find Microsoft.WindowsAPICodePack.dll and Microsoft.WindowsAPICodePack.Shell.dll
Reference these dlls in your project instead of the original code pack.
Related
I created some add-in for excel in C#. In it is one public class for using in VBA. On my machine all works ok. When I install add-in on tester computer (I'm using InstallShield 2015 Limited Edition for Visual Studio to create setup file) I can't set object.
C# code
using System;
using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace PMTAddin
{
[Guid("B2350EC1-522E-4B75-BB02-86BB0FD1A60E")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class PublicClass
{
public void test()
{
System.Windows.Forms.MessageBox.Show(
"test."
, "test"
, System.Windows.Forms.MessageBoxButtons.OK
, System.Windows.Forms.MessageBoxIcon.Error
);
}
private int GetWorksheetID(Excel.Workbook wb, string worksheetName)
{
int result = 0;
foreach (Excel.Worksheet ws in wb.Worksheets)
{
if (ws.Name == worksheetName)
{
result = ws.Index;
break;
}
}
return result;
}
[ComRegisterFunctionAttribute]
public static void RegisterFunction(Type type)
{
Registry.ClassesRoot.CreateSubKey(GetSubKeyName(type, "Programmable"));
RegistryKey key = Registry.ClassesRoot.OpenSubKey(GetSubKeyName(type, "InprocServer32"), true);
key.SetValue("", System.Environment.SystemDirectory + #"\mscoree.dll", RegistryValueKind.String);
}
[ComUnregisterFunctionAttribute]
public static void UnregisterFunction(Type type)
{
Registry.ClassesRoot.DeleteSubKey(GetSubKeyName(type, "Programmable"), false);
}
private static string GetSubKeyName(Type type, string subKeyName)
{
System.Text.StringBuilder s = new System.Text.StringBuilder();
s.Append(#"CLSID\{");
s.Append(type.GUID.ToString().ToUpper());
s.Append(#"}\");
s.Append(subKeyName);
return s.ToString();
}
}
}
In VBA project I checked reference to it on the list. It calls PMT.
VBA
Sub dsf()
Dim o As PMT.PublicClass
Set o = New PMT.PublicClass 'at this lane on other computer I got error 429. On my computer all work smoothly and method test is running.
o.test
End Sub
I thought that maybe it was something .NET Framework, but it is installed. Any ideas?
EDIT:
I create two diffrent version for bittnes, but the same error.
But I found some new info. In registry on my computer it looks like this
and on tester machine it looks like this
There are no CodeBase value... Do you think this is the problem? If it is, how I need to modify RegisterFunction method to correct this?
After long seeking I found the solution. It's kind of partial, because for 64 bit Excel we need to register library manually (maybe someone knows, how to add bat file to installation file).
I found the answer on this site.
While creating Install Shield instalation file we need to do two things.
Add .tlb file to application files (this step was done by me, before posting on stackoverflow)
Click right on project.Primary output file and choose properities like in screenshot (for *.tlb file we need to check the same, but without "COM Interop")
Without this the installer will not properlly register add-in in registry.
Install file created like this would register add-in for 32-bit excel only. If you want to use it also in 64-bit Excel you need to register library manually. I created simple bat file like this:
c:
cd C:\Windows\Microsoft.NET\Framework64\v4.0.30319
regasm.exe "[pathToDLL]\AddInName.dll" /tlb:"[pathToDLL]\AddInName.tlb" /codebase
pause
Remember, that you need to run it with admin rights.
Is there anyway that a reference can be added to a solution programmatically?
I have an add-in button, when the user presses it, I want a reference to be added.
The reason is, I have created a piece of software that I want to be integrated into any given VS program (if the developer wants it), they would simply click the add-in button and the reference would be loaded in the current solution.
Is this possible?
Something like this I haven't tested it
get the environment
EnvDTE80.DTE2 pEnv = null;
Type myType = Type.GetTypeFromProgID("VisualStudio.DTE.8.0");
pEnv = (EnvDTE80.DTE2)Activator.CreateInstance(myType, true);
get the solution.
Solution2 pSolution = (Solution2)pEnv.VS.Solution;
get the project that you want
Project pProject = pSolution.Projects[0];
add the reference
pProject.References.Add(string referenceFilePath);
There is an example on CodeProject.
The functionality is contained within a single class elRefManager and the method to call is CheckReferences. The code can be looked at here by selecting the elRefManager.cs file on the left hand side.
As seen in the article you could do...
private void button1_Click(object sender, System.EventArgs e)
{
int ec;
ec=elRefManager.CheckReferences(null, new string[] {textBox1.Text});
if (ec<0)
MessageBox.Show("An error occurred adding this reference");
if (ec>0)
MessageBox.Show("Could not add " + textBox1.Text +
"\nCheck its spelling and try again");
}
System.Assembly.load Allows you to call functions in a library that were not built with your program.
If you want to add a reference to the project so that its in the solution you can use the following. Basically the same as #Scots answer.
I did it in a macro which is vb but I'm sure you can get the idea
DTE.Windows.Item(Constants.vsWindowKindSolutionExplorer).Activate()
Dim objProject As EnvDTE.Project
Dim i As Long
i = DTE.Solution.Projects.Count
For Each objProject In DTE.Solution.Projects
If (objProject.Name() = "csCA") Then
Dim vsproj As VSLangProj.VSProject
vsproj = objProject.Object
vsproj.References.Add("C:\Users\test.dll")
End If
Next
I've got some issues running Puma.Net. I've got all the functions looking fine in the code but when it comes this point:
Value = pumaPage.RecognizeToString();
It then gives an error saying the library dibapi.dll can't be found. But I just can't even add it as a reference it says something like
Can't add reference Make sure the file is accessible and that it is a assembly or Com-Component.
So I gave it all the rights it needs to be read, write & executed. I even gave it full controll on all the users but it just won't work.
Maybe I made a mistake somewhere so here is the full code of the programm.
static void Main()
{
string Image = "V:/Test_images/value.PNG";
Console.WriteLine("Running the Program!");
var pumaPage = new PumaPage(Image);
string Value;
using (pumaPage)
{
pumaPage.FileFormat = PumaFileFormat.RtfAnsi;
pumaPage.EnableSpeller = false;
pumaPage.Language = PumaLanguage.Digits;
Value = pumaPage.RecognizeToString();
}
Console.WriteLine("The Value is" + Value);
Console.ReadLine();
}
I've added the Puma.Net dll and "using Puma.Net;" so it should work. Does someone got any idea what could be wrong?
Here is also the errormessage that appears all the time.
The Error Message which appears
If you need a translation just tell me.
Btw it is a Console Application and I would love to keep it that way. If it is not possible then I can also try to use turn it into a Form Application but that's a whole new part for me so it could take a while to get into it.
You need to copy dibapi.dll to the output folder as described in the documentation:
Steps to add Puma.NET to your project:
1. Add reference to Puma.Net.dll;
2. Make sure that after project building the output folder (i.e. bin\Debug or bin\Release)
contains files Puma.Net.dll and puma.interop.dll. If the last is not present (IDE didn’t
copy it) copy it to the folder manually;
3. Copy dibapi.dll to the output folder;
I want to create simple toast notification to action center in windows 10 from this example. But I got problem on Step 2:
using Windows.UI.Notifications;
It`s missing. But I have spent a lot of time to find it and got no result. I really have no idea where I can find or at least download it.
What I tried:
After long search I found Windows.UI.dll in C:\Windows\System32 but when I try to add it as reference into project I got this error. Even after I tried to copy it and made this fully accessible nothing changed
I tried to reinstall .Net (I`m using 4.5.2)
Installed Windows 10 SDK
Tried to import with global
Added
<PropertyGroup>
<TargetPlatformVersion>10.0</TargetPlatformVersion>
</PropertyGroup>
Added System.Runtime.dll reference
Example code which probably is useless for you:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Toolkit.Uwp.Notifications;
using Microsoft.QueryStringDotNET;
using Windows.UI.Notifications;
namespace MessagerClient.Notifications {
class DefaultWindowsNotification {
public static void notificationTest() {
string title = "Andrew sent you a picture";
string content = "Check this out, Happy Canyon in Utah!";
string image = "http://blogs.msdn.com/something.jpg";
string logo = "ms-appdata:///local/Andrew.jpg";
ToastVisual visual = new ToastVisual() {
BindingGeneric = new ToastBindingGeneric() {
Children =
{
new AdaptiveText()
{
Text = title
},
new AdaptiveText()
{
Text = content
},
new AdaptiveImage()
{
Source = image
}
},
AppLogoOverride = new ToastGenericAppLogo() {
Source = logo,
HintCrop = ToastGenericAppLogoCrop.Circle
}
}
};
Console.WriteLine("NOTIFICATION");
//Can`t use because of Windows.UI library
ToastNotificationManager.CreateToastNotifier().Show(visual);
}
}
}
You have to fight Visual Studio pretty hard to use these UWP contracts in a Winforms app. You got off on the wrong foot right away with the wrong TargetPlatformVersion, pretty hard to recover from that. Full steps to take:
Edit the .csproj file with a text editor, Notepad will do. Insert this:
<PropertyGroup>
<TargetPlatformVersion>10.0.10586</TargetPlatformVersion>
</PropertyGroup>
Which assumes you have the 10586 SDK version installed on your machine. Current right now, these versions change quickly. Double-check by looking in the C:\Program Files (x86)\Windows Kits\10\Include with Explorer, you see the installed versions listed in that directory.
Open the Winforms project, use Project > Add Reference > Windows tab > tick the Windows.Data and the Windows.UI contract. Add Reference again and use the Browse tab to select System.Runtime. I picked the one in C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\ .NETFramework\v4.6.1\Facades. This reference displays with a warning icon, not sure what it is trying to say but it doesn't appear to have any side-effects.
Test it by dropping a button on the form, double-click to add the Click event handler. The most basic code:
using Windows.UI.Notifications;
...
private void button1_Click(object sender, EventArgs e) {
var xml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText01);
var text = xml.GetElementsByTagName("text");
text[0].AppendChild(xml.CreateTextNode("Hello world"));
var toast = new ToastNotification(xml);
ToastNotificationManager.CreateToastNotifier("anythinggoeshere").Show(toast);
}
Embellish by using a different ToastTemplateType to add an image or more lines of text. Do keep in mind that your program can only work on a Win10 machine.
If anyone should happen to stumble on this, see this similar but newer post -
Toast Notifications in Win Forms .NET 4.5
Read Stepan Hakobyan's comment at the bottom.
Essentially, I'm seeing the same thing. This code runs, I can step through it line by line with no exceptions but the toast notification is never shown within a Form app.
I assume this is a shared resource somewhere in Windows. Rather than making a copy for each app, is there a way to use this icon just like all Winforms apps use it?
How is this specified for Winforms apps by default? I don't see any reference of any icons in code or project settings. Just that it uses the "default icon".
It is stored as a resource in the System.Windows.Forms.dll assembly. You could get a copy with Reflector. Open the assembly, open the Resources node, all the way down to "wfc.ico". Right-click, Save As. Not sure why you'd want to use it, given that it is the default.
You set a custom icon for your application with Project + Properties, Application tab, Icon setting. Each form has its own Icon property.
If you have Visual Studio 2010 installed then there is a large collection of icons (potentially including the application icon/s), check out the following directory:
%ProgramFiles%\Microsoft Visual Studio 10.0\Common7\VS2010ImageLibrary\1033
There may be a similar directory for previous VS versions, take a look if needs be.
EDIT:
On doing a search in the folder of the unzipped file for app there are two notable results:
Application.ico and ApplicationGeneric.ico + its *.png counterpart.
If you have VS 2010 and any of the icons in here are suitable, I believe you don't need to copy a single one - you should be able to include the file indirectly (as a shared/linked file) when adding using the Existing Item... dialog; you do this by selecting the arrow next to Add button and selecting the Add As Link option.
What I can't see working as desired is simply overwriting these files in an attempt to apply a global change.
It is stored as a resource in the System.Windows.Forms.dll assembly. You could get a copy with reflection as folow:
public static class FormUtils
{
private static Icon _defaultFormIcon;
public static Icon DefaultFormIcon
{
get
{
if (_defaultFormIcon == null)
_defaultFormIcon = (Icon)typeof(Form).
GetProperty("DefaultIcon", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static).GetValue(null, null);
return _defaultFormIcon;
}
}
public static void SetDefaultIcon()
{
var icon = Icon.ExtractAssociatedIcon(EntryAssemblyInfo.ExecutablePath);
typeof(Form)
.GetField("defaultIcon", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)
.SetValue(null, icon);
}
}
public static class FormExtensions
{
internal static void GetIconIfDefault(this Form dest, Form source)
{
if (dest.Icon == FormUtils.DefaultFormIcon)
dest.Icon = source.Icon;
}
}
So as you can see in the code you have in this way the same Icon.Handle. The same reference.
Form.DefaultIcon is an internal lazy loaded static property in class Form.
You can also override the default Winforms icon for your application. In Program.cs i use:
FormUtils.SetDefaultIcon();
This function will then override the default icon with the icon specified in your Application properties, the icon of your executable.
You can just use the Save method:
C#:
string IcoFilename = "C:\\Junk\\Default.ico";
using (System.IO.FileStream fs = new System.IO.FileStream(IcoFilename, System.IO.FileMode.Create))
{
this.Icon.Save(fs);
}
Visual Basic:
Dim strFilename As String = "C:\Junk\Default.ico"
Using fs As New System.IO.FileStream(strFilename, IO.FileMode.Create)
Me.Icon.Save(fs)
End Using
I had a problem which was similar, but different. Rather than needing to get the default icon, I needed to check to see whether the icon on a form was set or if it was left as the default. While I could have used reflection to get it, I ended up using a simpler solution:
private static Icon defaultIcon = new Form().Icon;
// ...
if(this.Icon == defaultIcon)
{
// ...
}