IShellItemImageFactory.GetImage(): Transparency > Black with Windows11 - c#

I use the IShellItemImageFactory.GetImage API to produce thumnails from image files. After installing Windows 11 all thumbs for images with transpareny (PNGs) are drawn with black background. That looks terrible. Does anyone know, if this behaviour can be changed? Or know another method?
The code (shortened, without exception handling and releasing ressources):
public Bitmap ExtractThumbnail(string filePath, Size size)
{
SHCreateItemFromParsingName(filePath, IntPtr.Zero, typeof(IShellItemImageFactory).GUID, out IShellItemImageFactory factory);
factory.GetImage(size, SIIGBF.SIIGBF_RESIZETOFIT, out IntPtr bmp);
return Bitmap.FromHbitmap(bmp);
}
( Windows 11, VS 2022, .Net Framework 4.8 )

Related

Update input language of on screen keyboard

I have an Windows Forms application written in C# .NET 5 with a webview2 control which hosts a kiosk based application which will be run full screen on a touchscreen.
The application will use the on screen keyboard for user input. The application is hosted on our own machines, which will only be used for our application so changing the system input language is exactly what we want to achieve.
I need to allow the users to pick their own input language. In 4.7.2 I can achieve this by setting InputLanguage.CurrentInputLanguage, which dynamically updates the on screen keyboard input language, you also see the system input language update in the task bar (which in production will not be visible to users).
In .NET 5, setting the same value does not have the desired effect, the on screen keyboard does not reflect the changed input language, not does the input language update in the taskbar.
I notice the libraries behind the scenes have changed which is clearly why I am having this issue.
I have tried the following without success in a simple dummy app:
private void btnEnglish_Click(object sender, EventArgs e)
{
var language = InputLanguage.FromCulture(System.Globalization.CultureInfo.GetCultureInfo("en-GB"));
if (InputLanguage.InstalledInputLanguages.IndexOf(language) >= 0)
InputLanguage.CurrentInputLanguage = language;
ChangeSystemInputLanguage(language);
}
private static void ChangeSystemInputLanguage(InputLanguage language)
{
Application.OleRequired();
IntPtr handleOld = ActivateKeyboardLayout(new HandleRef(language, language.Handle), 0);
if (handleOld == IntPtr.Zero)
{
throw new ArgumentException("ErrorBadInputLanguage", nameof(language));
}
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr ActivateKeyboardLayout(HandleRef hkl, int uFlags);
Short of downgrading to 4.7.2 or re-writting in WPF (and such using the InputLanguageManager), can anyone make any recommendations how I might achieve the desired effect in .NET 5.0?
For anyone having this issue, the answer was incredibly simple...
before updating the CurrentInputLanguage, set focus on a control on in your form!

Setting wallpaper through Active Desktop in UWP app changes fit mode

I am using the Active Desktop interface in C# to change desktop wallpaper in Windows. I am only using the IActiveDesktop.SetWallpaper method and never use IActiveDesktop.SetWallpaperOptions, so I would expect only the wallpaper image to change and not its fit (tile, stretch, fill, etc.).
When I my compile my code as a .NET desktop app, this behaves as expected. However, when I use Desktop Bridge to compile my app as a UWP app for the Windows Store, the wallpaper fit changes and not just the image. I don't understand why running my code as a UWP app should make the Active Desktop interface behave any differently.
For example, if I select "Span" in the Windows 10 Settings app to make the wallpaper stretch across my two monitors, my UWP app does not respect this setting. When it changes the wallpaper image, the fit also changes to show the image separately on each monitor. But the .NET desktop version of my app respects the wallpaper fit setting and does not change it.
I have included the relevant part of my code below. The entire file can be found here.
[ComImport]
[Guid("F490EB00-1240-11D1-9888-006097DEACF9")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IActiveDesktop
{
[PreserveSig]
int ApplyChanges(AD_Apply dwFlags);
[PreserveSig]
int SetWallpaper([MarshalAs(UnmanagedType.LPWStr)] string pwszWallpaper, int dwReserved);
}
public class WallpaperChanger
{
public static readonly Guid CLSID_ActiveDesktop =
new Guid("{75048700-EF1F-11D0-9888-006097DEACF9}");
public static IActiveDesktop GetActiveDesktop()
{
Type typeActiveDesktop = Type.GetTypeFromCLSID(WallpaperChanger.CLSID_ActiveDesktop);
return (IActiveDesktop)Activator.CreateInstance(typeActiveDesktop);
}
public static void SetWallpaper(string imagePath)
{
IActiveDesktop iad = GetActiveDesktop();
iad.SetWallpaper(imagePath, 0);
iad.ApplyChanges(AD_Apply.ALL | AD_Apply.FORCE | AD_Apply.BUFFERED_REFRESH);
}
}
Note: I've tried using the SetWallpaperAsync function available in the Windows UWP library, and it has the same problem. Also this problem is not specific to multiple monitors, the same thing happens with just a single one.

Error showing Icon in picturebox

I've been using this code to show an icon in a picturebox.
Image FromIcon(Icon ico)
{
try
{
this.toolTip1.SetToolTip(pictureBox1, "The icon of the Executable");
return ico.ToBitmap();
}
catch (Exception e)
{
this.toolTip1.SetToolTip(pictureBox1, "Don't worry, it looks perfectly fine on the executable!");
MessageBox.Show(e.Message + "\r\n" + e.StackTrace);
Clipboard.SetText(e.Message + "\r\n" + e.StackTrace);
// Alternate method
return Bitmap.FromHicon(ico.Handle);
}
}
However it is showing this error.
Requested range extends past the end of the array.
at System.Runtime.InteropServices.Marshal.CopyToNative(Object source, Int32 startIndex, IntPtr destination, Int32 length)
at System.Runtime.InteropServices.Marshal.Copy(Byte[] source, Int32 startIndex, IntPtr destination, Int32 length)
at System.Drawing.Icon.ToBitmap()
Also the icon is shown in a nasty way,
That's the same icon I use for my application. What can go wrong?
That icon is 32 bit as well as the other.
If I use another icon, it works fine and no error pops up.
I know this is an old question but I recently came across the same issue so thought I would post the resolution for anyone else facing the same problem.
For me, the issue was that I was creating the ICO files from PNG image formats but the application that the files were used in targeted a .NET framework that was earlier than 4.6 (i.e. the version in which support was added for PNG frames in .ico files). See note from the Icon.ToBitmap() documentation below:
Beginning with framework version 4.6 support was added for PNG frames in .ico files. Applications that target earlier versions of the framework but are running on the 4.6 bits can opt in into the new behavior by adding the following line to the <runtime> section of the app.config file:<AppContextSwitchOverrides value="Switch.System.Drawing.DontSupportPngFramesInIcons=false" />
So once I added the above line to the app.config file it resolved the issue.

Extending caption bar without glass

I saw that Windows 7 Wizard has the title bar extended without requiring Aero Glass. Look at this:
I made my application to work with Aero Glass, but how about withiut it?
Thanks in advance!
I haven't test this yet, but I think it will work, mark it as answer if you agree:
[DllImport("uxtheme")]
static extern int DrawThemeBackground(IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, ref RECT pRect, ref RECT pClipRect);
This method works, loog at this
You shouldn't need to do anything. The DWM is still running when using the Basic theme, it's just not doing any accelerated rendering.

Avoiding duplicate icon resources in a .NET (C#) project

I'm using Visual C# 2008 Express. I'd like to use the same icon for the application (ie, the icon shown for the .exe), and for the main form. Unfortunately, VC# doesn't seem to be very smart about this, and insists on duplicating the icon data.
There doesn't seem to be a way of selecting an "already embedded" icon for use in the form or project icon (only selecting a file), and using the same file for both icons just embeds the file twice as far as I can see. It's not a big deal (hard drive space is cheap now, right?), but it bugs me.
Any idea how to avoid this? Is there a way to programatically load the executable's icon for use when the form is constructed, say? A couple of forum posts about similar things seem to suggest that .NET resources don't use the normal old Windows resource system -- is there a way from within the framework of getting at the old-style resources? Or do I have to bind the Win32 API functions to do it?
You're right, and it's rather annoying.
You have to load the icons yourself instead of relying on designer-generated code. Save the icon as a project resource, then load the resource into the form's Icon property in the form's constructor:
this.Icon = Properties.Resources.myIconResourceName;
You're looking for Icon.ExtractAssociatedIcon. Call passing your executable:
var icon = Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location);
Yeah, it's pretty annoying. But the problem with the proposed answer of Icon.ExtractAssociatedIcon is that it will retrieve the 32x32 icon, and then downsample to a 16x16 icon in your forms window or on the taskbar, which will look terrible unless your 32x32 icon is very cleverly constructed.
The way I'm doing it is with interop (put the first line in your form constructor):
this.Icon = ExtractSmallIconFromLibrary(Application.ExecutablePath);
...
public static Icon ExtractSmallIconFromLibrary(string file) {
IntPtr[] reficon = new IntPtr[1];
int nextracted = ExtractIconEx(file, 0, null, reficon, 1);
if (nextracted < 1)
return null;
Icon unmanaged_icon = Icon.FromHandle(reficon[0]);
Icon icon = (Icon)unmanaged_icon.Clone();
DestroyIcon(unmanaged_icon.Handle);
return icon;
}
[DllImport("Shell32", CharSet = CharSet.Auto)]
extern static int ExtractIconEx(
[MarshalAs(UnmanagedType.LPTStr)]
string lpszFile,
int nIconIndex,
IntPtr[] phIconLarge,
IntPtr[] phIconSmall,
int nIcons
);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
extern static bool DestroyIcon(IntPtr handle);
But this isn't great, either, since you do want the 32x32 icon for things like the Alt-Tab icon list. So you really need to extract the entire icon, which is a bigger job. Maybe there's a straightforward way to combine the two icons into one. Or you can do like this codeproject program, which extracts the whole icon in the first place with a huge pile of code.
I think in many cases including a duplicate icon is at the end of the day more efficient than trying to extract it from the unmanaged resource - considering you can't use Icon.ExtractAssociatedIcon for UNC paths.
I had a similar problem.
I have and exe icon I want to reuse for subforms without increasing file size.
//From MyApp
MySubForm msf = new MySubForm();
msf.Icon = this.Icon;
msf.Show();
I don't know if this is useful, but I want to share it in anyway.

Categories