我们的应用程序执行一些游标操作以在WinForms上启用“相对”漂亮的拖放动画(当时WPF不是一个选项)。但是,当在RDP会话中使用应用程序时,它会抛出一个通用的GDI +异常。
抛出这个的方法是:
[DllImport("user32")]
private static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO pIconInfo);
[DllImport("user32.dll")]
private static extern IntPtr LoadCursorFromFile(string lpFileName);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool DestroyIcon(IntPtr hIcon);
[DllImport("gdi32.dll", SetLastError = true)]
private static extern bool DeleteObject(IntPtr hObject);
public static Bitmap BitmapFromCursor(Cursor cur)
{
ICONINFO iInfo;
GetIconInfo(cur.Handle, out iInfo);
Bitmap bmp = Bitmap.FromHbitmap(iInfo.hbmColor);
DeleteObject(iInfo.hbmColor);
DeleteObject(iInfo.hbmMask);
BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
Bitmap dstBitmap = new Bitmap(bmData.Width, bmData.Height, bmData.Stride, PixelFormat.Format32bppArgb, bmData.Scan0);
bmp.UnlockBits(bmData);
return new Bitmap(dstBitmap);
}
特别是这一行:
Bitmap bmp = Bitmap.FromHbitmap(iInfo.hbmColor);
当调试hbmColor
为0
时,这意味着在通过RDP运行时,对GetIconInfo
的调用不会返回所需信息。
我可以查看0
并处理特殊情况,但是我能做些什么来使其在RDP上工作正常吗?
修改
这是ICONINFO
结构:
[StructLayout(LayoutKind.Sequential)]
struct ICONINFO
{
public bool fIcon; // Specifies whether this structure defines an icon or a cursor. A value of TRUE specifies
// an icon; FALSE specifies a cursor.
public Int32 xHotspot; // Specifies the x-coordinate of a cursor's hot spot. If this structure defines an icon, the hot
// spot is always in the center of the icon, and this member is ignored.
public Int32 yHotspot; // Specifies the y-coordinate of the cursor's hot spot. If this structure defines an icon, the hot
// spot is always in the center of the icon, and this member is ignored.
public IntPtr hbmMask; // (HBITMAP) Specifies the icon bitmask bitmap. If this structure defines a black and white icon,
// this bitmask is formatted so that the upper half is the icon AND bitmask and the lower half is
// the icon XOR bitmask. Under this condition, the height should be an even multiple of two. If
// this structure defines a color icon, this mask only defines the AND bitmask of the icon.
public IntPtr hbmColor; // (HBITMAP) Handle to the icon color bitmap. This member can be optional if this
// structure defines a black and white icon. The AND bitmask of hbmMask is applied with the SRCAND
// flag to the destination; subsequently, the color bitmap is applied (using XOR) to the
// destination by using the SRCINVERT flag.
}
从HABJAN的回答我已经将p / Invoke中的注释添加到上面的结构中。看起来hbmMask
包含我之后的位图参考,但我担心我的位操作技能相当生疏。当p / Invoke表示上半部分/下半部分时 - 它推断出什么?
是否可以从中获取黑白位图?
答案 0 :(得分:1)
我认为这是由于你的RDP颜色深度。如果光标仅为黑白(通过RDP),则不会获得hbmColor
值,因为此参数是可选的。
MSDN说:
hbmColor
Type: HBITMAP
描述:图标颜色位图的句柄。如果此结构定义了黑白图标,则此成员可以是可选的。 hbmMask的AND位掩码与SRCAND标志一起应用于目标;随后,使用SRCINVERT标志将颜色位图(使用XOR)应用于目标。
修改强>
public static Bitmap BitmapFromCursor(Cursor cur)
{
ICONINFO iInfo;
GetIconInfo(cur.Handle, out iInfo);
Bitmap bmpColor = null;
if (iInfo.hbmColor != IntPtr.Zero) {
bmpColor = Bitmap.FromHbitmap(iInfo.hbmColor);
}
else {
bmpColor = new Bitmap(w,h);
// fill bmpColor with white colour
}
Bitmap bmpMask = Bitmap.FromHbitmap(iInfo.hbmMask);
DeleteObject(iInfo.hbmColor);
DeleteObject(iInfo.hbmMask);
// apply mask bitmap to color bitmap:
// http://stackoverflow.com/questions/3654220/alpha-masking-in-c-sharp-system-drawing
BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
Bitmap dstBitmap = new Bitmap(bmData.Width, bmData.Height, bmData.Stride, PixelFormat.Format32bppArgb, bmData.Scan0);
bmp.UnlockBits(bmData);
return new Bitmap(dstBitmap);
}
...我没有测试这段代码,只是为了简要介绍一下该怎么做...
答案 1 :(得分:1)
在HABJAN的帮助下,我能够找到一种方法来完成这项工作。我在这里写答案的原因是因为从句柄获得的位图掩码包含两个掩码,因此您必须选择所需的版本(根据文档)。
public static Bitmap GetBitmapFromMask(IntPtr maskH)
{
using (var bothMasks = Bitmap.FromHbitmap(maskH))
{
int midY = bothMasks.Height / 2;
using (var mask = bothMasks.Clone(new Rectangle(0, midY, bothMasks.Width, midY), bothMasks.PixelFormat))
{
using (var input = new Bitmap(mask.Width, mask.Height))
{
using (var g = Graphics.FromImage(input))
{
using (var b = new SolidBrush(Color.FromArgb(255, 255, 255, 255)))
g.FillRectangle(b, 0, 0, input.Width, input.Height);
}
var output = new Bitmap(mask.Width, mask.Height, PixelFormat.Format32bppArgb);
var rect = new Rectangle(0, 0, input.Width, input.Height);
var bitsMask = mask.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
var bitsInput = input.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
var bitsOutput = output.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
{
for (int y = 0; y < input.Height; y++)
{
byte* ptrMask = (byte*)bitsMask.Scan0 + y * bitsMask.Stride;
byte* ptrInput = (byte*)bitsInput.Scan0 + y * bitsInput.Stride;
byte* ptrOutput = (byte*)bitsOutput.Scan0 + y * bitsOutput.Stride;
for (int x = 0; x < input.Width; x++)
{
ptrOutput[4 * x] = ptrInput[4 * x]; // blue
ptrOutput[4 * x + 1] = ptrInput[4 * x + 1]; // green
ptrOutput[4 * x + 2] = ptrInput[4 * x + 2]; // red
ptrOutput[4 * x + 3] = ptrMask[4 * x]; // alpha
}
}
}
mask.UnlockBits(bitsMask);
input.UnlockBits(bitsInput);
output.UnlockBits(bitsOutput);
return output;
}
}
}
}
这是由HABJAN链接的答案的基本副本 - 它似乎不会对结果字节执行逻辑AND或逻辑XOR - 但似乎没有做必要的工作。