Converting ImageMoniker to WPF BitmapSource in VS2022 - visual-studio-extensions

I'm developing an extension for Visual Studio that includes a XAML view inside a VS window. I want the extension to look and feel like the native UI. The extension is currently running and working fine in VS2017 and VS2019 using the following code to transform a moniker to a WPF BitmapSource that can be used directly from XAML:
public static BitmapSource GetIconForImageMoniker(ImageMoniker? imageMoniker, int sizeX, int sizeY)
{
if (imageMoniker == null)
{
return null;
}
IVsImageService2 vsIconService = ServiceProvider.GlobalProvider.GetService(typeof(SVsImageService)) as IVsImageService2;
if (vsIconService == null)
{
return null;
}
ImageAttributes imageAttributes = new ImageAttributes
{
Flags = (uint)_ImageAttributesFlags.IAF_RequiredFlags,
ImageType = (uint)_UIImageType.IT_Bitmap,
Format = (uint)_UIDataFormat.DF_WPF,
LogicalHeight = sizeY,
LogicalWidth = sizeX,
StructSize = Marshal.SizeOf(typeof(ImageAttributes))
};
IVsUIObject result = vsIconService.GetImage(imageMoniker.Value, imageAttributes);
object data;
result.get_Data(out data);
BitmapSource glyph = data as BitmapSource;
if (glyph != null)
{
glyph.Freeze();
}
return glyph;
}
This method is a direct copy-paste from the WpfUtil class available in multiple of Mads Kristensen's extensions.
As already mentioned, this works fine in VS2017 and VS2019. Now I want this running in VS2022 as well. The extension shows up inside VS2022 but the icons are no longer shown. The problem is that this returns null in VS2022 but not in the previous versions:
ServiceProvider.GlobalProvider.GetService(typeof(SVsImageService)) as IVsImageService2;
Does anyone know how to make this work in VS2022 as well?

This is caused by changes to the interop libraries in VS2022. Namely, they've all been consolidated to a single library (you can see the details here).
This does break compatibility with targeting prior versions of Visual Studio. There is a guide for migrating extensions to VS2022, but to summarize, the guidance is to:
Refactor the source code into a Shared Project.
Create a new VSIX projects targeting VS2022 and the VSIX project you have now would remain for targeting prior versions.

Related

How to share Preferences in a Xamarin.Forms project between an iOS and iOS extensions?

I'm trying to get a string (UserID) using Preferences.Get (Xamarin.Essentials) on a PushNotification.Extension project, but as the Preferences.Set happens in the Xamarin iOS project, I'm always getting an empty string in the extensions project.
Is there a way to share this preference between the iOS project and the iOS.extension?
public string UserID
{
get
{
return Preferences.Get(nameof(UserID), UserIDDefault);
}
set
{
Preferences.Set(nameof(UserID), value);
}
}
According to Apple docs , please follow the steps to enable data-sharinig .
Enable App Groups Capabilities , refer to App Group Capabilities in Xamarin.iOS.
Add the app to the App Group .
Use NSUserDefaults and init it with the name of the extension bundle identifier.
//Save
var defaults = new NSUserDefaults(#"com.example.domain.MyShareExtension");
defaults.SetString("value","Mykey");
defaults.Synchronize();
//Get
var defaults = new NSUserDefaults(#"com.example.domain.MyShareExtension");
var value = defaults.ValueForKey("Mykey");
"NSUserDefaults(string)" does not work for me.
In the Xamarin iOS documentation this constructor is marked as deprecated! see https://learn.microsoft.com/en-us/dotnet/api/foundation.nsuserdefaults?view=xamarin-ios-sdk-12
But when I use "NSUserDefaults(String, NSUserDefaultsType)" it runs perfect.

Xamarin Forms (VS2019) + iOS Intents UI: How to access Assets from Extension (IntentsUI)

I used the Xamarin version of SoupChef for Siri Intents. I was able to access the Container's Assets from the SoupChefIntentsUI.IntentViewController by requesting the bundle by identifier (using the BundleIdentifier of the main App) and then I just loaded the image by passing the bundle
CGSize DisplayOrderConfirmation(Order order, OrderSoupIntent intent, OrderSoupIntentResponse response){
/* unrelated code */
//this line work in the SoupChef example but
//On Xamarin.Forms this returns null
var containerBundle = NSBundle.FromIdentifier("com.something.SoupChef");
//always returns null because it seems it looks into the IntentsUI.Assets
var iconNull = UIImage.FromBundle("AppIcon");
//it returns the icon from the SoupChef.Assets
var iconNotNull = UIImage.FromBundle("AppIcon", containerBundle, configuration: null);
/* unrelated code */
}
I was also able to retrieve the AppIcon by creating the NSBundle doing something like this (in case you didn't want to assume that the bundle identifier names don't follow the Apple standard where the Container and the extensions have the same bundle identifier with the exception of the last segment)
CGSize DisplayOrderConfirmation(Order order, OrderSoupIntent intent, OrderSoupIntentResponse response){
/* unrelated code */
Class GetClassForType (Type type)
{
IntPtr myClassHandle = Class.GetHandle (typeToLookup);
if (myClassHandle != IntPtr.Zero)
return new Class (myClassHandle);
else
return null;
}
//this returns the bundle identifier of the SoupChef app
//(not the SoupChefIntentUI) on the SoupChef example
//on Xamarin.Forms (my project) it returns the IntentsUI identifier
var containerBundle = NSBundle.FromClass(GetClassForType(typeof(SoupChef.OrderIntent)));
//the icon is returned
var icon = UIImage.FromBundle("AppIcon", containerBundle, configuration: null);
/* unrelated code */
}
My problem is that I want to do the same thing on a different project that is using Xamarin.Forms, and the two previous ways that worked for me on the SoupChef project don't work here.
Is there a way to access the Assets set on the App.iOS.Assets or do I have to move them to the shared project where I have the models and other things that both the App.iOS and its Extensions are using?
I noticed that the Bindings (the project where the OrderIntent is) in the SoupChef example has the same namespace as the Container App ("SoupChef"), so I assigned the same namespace in my project with Xamarin.Forms and still nothing.

XSLT3 Options for .NET Core in 2019

Has anyone got XSLT3 transforms working in .NET Core 2.x+ in 2019?
Seems that the request to MS for XSLT2/3 support hasn't moved forwards, and the Saxon people have other priorities, especially given the IKVM closedown.
Are there any other alternatives for in-process XSLT transformation? At the moment, it seems my only choice is to wrap something up via an external service or some undesirable (for us) COM-style approach that would involve lots of marshalling of data, hurting performance.
Unfortunately IKVM has never supported .NET Core, so the .NET version of Saxon cannot be made to work in that environment. In Saxonica we've been exploring alternative avenues for .NET support, but we haven't found anything remotely promising. (Anyone fancy doing a Kotlin implementation for .NET?)
I don't know what's possible using XMLPrime or Exselt, both of which target .NET.
2021 Update
Saxonica now ships SaxonCS on .NET 5, this product is built by converting the Java code of SaxonJ to C# source code using a custom transpiler.
There is one way how to use Saxon on .NET Core: via Transform.exe running as a process.
You can use code similar to this:
/// <summary>Transform XML inputFile using xsltFile and parameters. Save the result to the outputFile.</summary>
public void Transform(string inputFile, string outputFile, string xsltFile, NameValueCollection parameters)
{
//Search for the instalation path on the system
string path = GetInstalPath(#"Software\Saxonica\SaxonHE-N\Settings", "InstallPath");
string exePath = Path.Combine(path, "bin", "Transform.exe");
string parametersCmd = null;
//Set indicidual parameters
foreach (string parameter in parameters)
{
parametersCmd += String.Format("{0}={1} ", parameter, parameters[parameter]);
}
//set arguments for Transform.exe
string arguments = string.Format("-s:\"{1}\" -xsl:\"{0}\" -o:\"{3}\" {2}", xsltFile, inputFile, parametersCmd, outputFile);
//https://stackoverflow.com/questions/5377423/hide-console-window-from-process-start-c-sharp
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = exePath;
startInfo.Arguments = arguments;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
int waitingTime = 5 * 60 * 1000; //5 minutes; time in milliseconds
Process processTemp = new Process();
processTemp.StartInfo = startInfo;
processTemp.EnableRaisingEvents = true;
try
{
processTemp.Start();
processTemp.WaitForExit(waitingTime);
}
catch (Exception e)
{
throw;
}
}
static string GetInstalPath(string comName, string key)
{
RegistryKey comKey = Registry.CurrentUser.OpenSubKey(comName);
if (comKey == null)
return null;
string clsid = (string)comKey.GetValue(key);
return clsid;
}
SaxonCS EE has been released and works with .NET 5 and .NET 6 (RC/preview) and that way allows using XSLT 3, XPath 3.1 and XQuery 3.1 with .NET Core. It is only available under a commercial license however, but you can test it with a trial license, download from Saxonica is at https://www.saxonica.com/download/dotnet.xml, also on NuGet as https://www.nuget.org/packages/SaxonCS/.
In the meantime IKVM has been updated (https://www.nuget.org/packages/IKVM.Maven.Sdk) and is capable of producing .NET 3.1, .NET 5 and .NET 6 (aka .NET core) compatible cross-compilations. Using that I have managed to cross-compile Saxon HE 11.4 Java to .NET 6 and have published two command line apps/dotnet tools on NuGet to run XSLT 3.0 or XQuery 3.1:
XSLT 3.0: https://www.nuget.org/packages/SaxonHE11NetXslt/
XQuery 3.0: https://www.nuget.org/packages/SaxonHE11NetXQuery/
I have furthermore created an extension library to ease the use of the Java s9api from .NET code, it is on NuGet at https://www.nuget.org/packages/SaxonHE11s9apiExtensions/, the GitHub repository is at https://github.com/martin-honnen/SaxonHE11s9apiExtensions.
A simple example to run some XSLT 3.0 code with .NET 6, using the IKVM cross compiled Saxon HE 11, would be:
using net.sf.saxon.s9api;
using net.liberty_development.SaxonHE11s9apiExtensions;
//using System.Reflection;
// force loading of updated xmlresolver (no longer necessary with Saxon HE 11.5)
//ikvm.runtime.Startup.addBootClassPathAssembly(Assembly.Load("org.xmlresolver.xmlresolver"));
//ikvm.runtime.Startup.addBootClassPathAssembly(Assembly.Load("org.xmlresolver.xmlresolver_data"));
var processor = new Processor(false);
Console.WriteLine($"{processor.getSaxonEdition()} {processor.getSaxonProductVersion()}");
var xslt30Transformer = processor.newXsltCompiler().Compile(new Uri("https://github.com/martin-honnen/martin-honnen.github.io/raw/master/xslt/processorTestHTML5Xslt3InitialTempl.xsl")).load30();
xslt30Transformer.callTemplate(null, processor.NewSerializer(Console.Out));
A samples project showing various examples of XPath 3.1, XQuery 3.1 and XSLT 3.0 usage is at https://github.com/martin-honnen/SaxonHE11IKVMNet6SaxonCSSamplesAdapted.

Auto Fill Web Forms in .net-Core

I am new to .net core.
How can I auto fill forms and submit in dotnet core ?
Please find following sample URLs I want to try
https://mparivahan.in/uyt/?pur_cd=102
Value - 1 = "MH1R"
Value - 2 = "5656"
https://www.filegstrstnow.com/searchGSTTaxpayer
sample Value = "24AADCS0852Q1Z2"
With Regards
I guess you want to automate operations in browser. For this purpose you need a browser automation framework which can be used in you .NET Core 2.0 code. Something like Selenium WebDriver. In this case you code will look like this:
[Test]
public void TestWithFirefoxDriver()
{
using (var driver = new FirefoxDriver())
{
driver.Navigate().GoToUrl(#"https://parivahan.gov.in/rcdlstatus/?pur_cd=102");
driver.FindElement(By.Id("form_rcdl:tf_reg_no1")).Send("GJ01RR");
driver.FindElement(By.Id("form_rcdl:tf_reg_no2")).Send("5656");
driver.FindElement(By.Id("form_rcdl:j_idt36")).Click();
var wait = new WebDriverWait(driver, TimeSpan.FromMinutes(1));
// Find element with the result to retrieve value, and so on..
}
}
Note: I didn't check the code above in runtime, it is just for demonstration purposes.
To run Selenium automation code without opening the browser you could use PhantomJS driver instead of drivers for real browsers like FirefoxDriver. Change this line:
using (var driver = new FirefoxDriver())
to:
using (var driver = new PhantomJSDriver())

Microsoft Speech Recognition in webservices is not returning the result

Well i'm using Microsoft Speech Platform SDK 10.2.
I made a asp.Net WebService application and most of the WebServices works fine (HelloWorld(), etc...), but I have one service that uses the SpeechRecognitionEngine and when I deploy the application and try to run this webservice I get no result, i.e, I can see through the debug mode that it reaches the return line, but when I call it trought the browser the page keeps loading for ever, without any response.
Here's a sample of the code:
[WebMethod]
public bool voiceRecognition() {
SpeechRecognitionEngine sre = new SpeechRecognitionEngine(new System.Globalization.CultureInfo("pt-PT"));
Choices c = new Choices();
c.Add("test");
GrammarBuilder gb = new GrammarBuilder();
gb.Append(c);
Grammar g = new Grammar(gb);
sre.LoadGrammar(g);
sre.InitialSilenceTimeout = TimeSpan.FromSeconds(5);
//// just for Testing
RecognitionResult result = null;
if (result != null) {
return true;
} else {
return false;
}
}
Note: I'm using IIS to deploy the WebService Application.
If someone have some thoughts please let me know.
I don't know if you've found your answer or not. When trying to solve this myself a couple of days ago, I stumbled across your question and it matched our circumstances to a "T".
In order to fix it all we had to do was put...
sre.RecognizeAsyncStop();
sre.Dispose();
where "sre" is your SpeechRecognitionEngine variable. If you don't stop it and dispose of it at the end of your web service then the web service won't return.
Hope this helps. :)

Resources