2014-06-10 3 views
1

우리의 응용 프로그램은 WinForms에서 "상대적으로"멋진 드래그 드롭 애니메이션을 사용할 수 있도록 커서 조작을합니다 (WPF는 옵션이 아닐 때). 그러나 RDP 세션을 통해 응용 프로그램을 사용하면 일반 GDI + 예외가 throw됩니다.Bitmap.FromHbitmap에서 RDP를 통해 호출 할 때 오류가 발생합니다.

는이 인 슬로우있어서

[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를 통해이 작업을 수행 할 수있는 방법이 있습니까? 나는 위의 구조에 호출/P의 의견을 추가 한 아래

[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의 대답에서 :

편집

다음은 ICONINFO 구조입니다. hbmMask에 비트 맵 참조가 포함 된 것 같습니다.하지만 비트 조작 기술이 다소 녹슬 까봐 두렵습니다. p/Invoke가 상반부/하반부를 말할 때 - 그것은 무엇을 추론합니까?

여기에서 흑백 비트 맵을 얻을 수 있습니까?

+0

'ICONINFO'구조 정의를 표시 할 수 있습니까? – HABJAN

+0

winapi 함수의 반환 값을 무시하는 것은 일반적인 실수입니다. 그것은 선택 사항이 아니며 친숙한 .NET 예외가 없으므로 문제가 발생하지 않습니다. GetIconInfo()가 * false *를 반환하면 Win32Exception을 던져 실패 이유를 알 수 있습니다. 그리고 선언을 수정하여 SetLastError = true를 추가하십시오. –

+0

건배 한스, p/Invoke에서 복사하여 붙여 넣기보다는 좀 더 익숙해지기 위해 필요한 것입니다. 나는 그 다음에 염두에 두었다. – Marlon

답변

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); 
} 

... 내가했다 HABJAN의 도움으로 ... 그것은 당신에게 무엇을 할 수있는 간단한 정보를 제공하기 위해 단지,

+0

안녕하세요, 네 말이 맞습니다 - p/Invoke의 추가 정보로 내 질문을 수정했습니다 - hbmMask가 필요한 것을 포함하고있는 것처럼 보입니다. 이걸로 비트 맵을 얻을 수 있을지 모르겠군요? – Marlon

+0

@Marlon : 'iInfo.hbmColor'와 동일하게 'iInfo.hbmMask'를 수행해야합니다. 이렇게하면 2 비트 맵, 하나의 컬러 비트 맵 및 두 번째 마스크 비트 맵을 얻을 수 있습니다. 그래서 hbmColor == 0인지 확인해야합니다. 흰색 배경으로 간단한 비트 맵을 만들고 마스크 위에 마스크를 적용해야합니다. 마스크를 적용하려면이 질문을 확인하십시오. http://stackoverflow.com/questions/3654220/alpha-masking-in-c-sharp-system-drawing – HABJAN

+0

@Marlon : 간단한 샘플로 내 대답을 편집했습니다. 처럼. – HABJAN

1

를이 코드를 테스트하지 않았다 직업을 구할 수있는 방법을 찾아 낼 수 있습니다. 여기에 답을 쓰는 이유는 핸들에서 가져온 비트 맵 마스크에 두 개의 마스크가 포함되어 있기 때문에 원하는 버전을 선택해야하기 때문입니다 (문서마다).

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 하나를 수행하지 않는 것 같습니다.

+0

GetBitmapFromMask 메서드뿐만 아니라 전체 솔루션을 붙여 넣을 수 있습니까? 감사! – Tsury

관련 문제