本文介绍了.NET互操作的IntPtr与裁判的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

可能是一个noob问题,但互操作是不是我的强项之一呢。



除了限制过载的数量没有任何理由,我应该声明我DllImports这样的:

 函数[DllImport(user32.dll中)] 
公共静态外部INT SendMessage函数(IntPtr的的HWND,INT味精,诠释的wParam,lParam的的IntPtr);

和使用它们像这样:

 的IntPtr的lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(formatrange)); 
Marshal.StructureToPtr(formatrange,lParam的,虚假的);

INT的returnValue = User32.SendMessage(_RichTextBox.Handle,ApiConstants.EM_FORMATRANGE话,wParam,lParam的);

Marshal.FreeCoTaskMem(lParam的);



<$:



而不是创建一个有针对性的超载p $ p> 函数[DllImport(user32.dll中)]
公共静态外部INT SendMessage函数(IntPtr的的HWND,INT味精,诠释的wParam,楼盘FORMATRANGE lParam的);

和使用它,如:

  FORMATRANGE的lParam =新FORMATRANGE(); 
INT的returnValue = User32.SendMessage(_RichTextBox.Handle,ApiConstants.EM_FORMATRANGE来讲,wParam,lParam的参考);



由裁判超载最终被更容易使用,但我不知道是否有一个缺点,即。我不知道的。



编辑:



伟大的大量信息到目前为止家伙



@P爸爸:你有基础的结构类关闭一个抽象(或任何)类的例子吗?我改变了我的签名:

 函数[DllImport(user32.dll中,SetLastError = TRUE)] 
公共静态EXTERN INT SendMessage函数(IntPtr的的HWND,INT味精,INT的wParam,[IN,OUT的MarshalAs(UnmanagedType.LPStruct)CHARFORMAT2 lParam的);



没有退出的MarshalAs 的SendMessage函数(在我的测试EM_GETCHARFORMAT)失败。上面的例子中工作得很好,但如果我将其更改为:

 函数[DllImport(user32.dll中,SetLastError = TRUE)] 
公共静态外部INT SendMessage函数(IntPtr的的HWND,INT味精,INT的wParam,[IN,OUT的MarshalAs(UnmanagedType.LPStruct)NativeStruct lParam的);



我得到一个System.TypeLoadException,说的CHARFORMAT2格式不正确(我会尝试和捕获。它在这里)



例外:



未能加载类型'CC.Utilities.WindowsApi.CHARFORMAT2 从程序集CC.Utilities,版本= 1.0.9.1212,文化=中性公钥= 111aac7a42f7965e,因为格式无效



NativeStruct类:

  {
}
p>

我试过摘要,添加 StructLayout 属性, 。等等,我也得到了同样的异常

  [StructLayout(LayoutKind.Sequential)] 
公共类CHARFORMAT2:NativeStruct
{

}

修改



我没有按照常见问题,我问可以讨论,但没有正面回答的问题。除此之外出现了有见地的信息大量的在这个线程。所以我会离开它的读者投票选出了一个答案。第一个10多了,票就可以解决。如果没有回答满足了这种在两天内(12/17 PST),我会加上我自己的答案是总结了线程的所有美味的知识: - )



再次编辑:



我撒了谎,接受P爸爸的答案,因为他是人,已经有很大的帮助(他有一个可爱的小猴子太: -P)


解决方案

如果该结构是没有加工定制marshalable,我非常喜欢后一种方式,在这里你声明p /调用函数取 REF (指针)的类型。或者,你可以宣布你的类型如类,而不是结构,然后你可以通过,以及



  [StructLayout(LayoutKind.Sequential)] 
结构本地类型{

}

函数[DllImport(。 ..)]
静态外部布尔NativeFunction(REF本地类型富);

//不能传递null NativeFunction
//除非您还包括重载需要的IntPtr

函数[DllImport(...)]
静态外部布尔NativeFunction(IntPtr的富);

//但在宣布本地类型的一类作品,也

[StructLayout(LayoutKind.Sequential)]
类NativeType2 {
$ ... b $ b}

函数[DllImport(...)
静态外部布尔NativeFunction(NativeType2富);

//现在你可以传递null




Edit

You mention you're getting a TypeLoadException when using a class instead of a struct, and ask for a sample. I did up a quick test using CHARFORMAT2, since it looks like that's what you're trying to use.

First the ABC:

[StructLayout(LayoutKind.Sequential)]
abstract class NativeStruct{} // simple enough

The StructLayout attribute is required, or you will get a TypeLoadException.

Now the CHARFORMAT2 class:

[StructLayout(LayoutKind.Sequential, Pack=4, CharSet=CharSet.Auto)]
class CHARFORMAT2 : NativeStruct{
    public DWORD    cbSize = (DWORD)Marshal.SizeOf(typeof(CHARFORMAT2));
    public CFM      dwMask;
    public CFE      dwEffects;
    public int      yHeight;
    public int      yOffset;
    public COLORREF crTextColor;
    public byte     bCharSet;
    public byte     bPitchAndFamily;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
    public string   szFaceName;
    public WORD     wWeight;
    public short    sSpacing;
    public COLORREF crBackColor;
    public LCID     lcid;
    public DWORD    dwReserved;
    public short    sStyle;
    public WORD     wKerning;
    public byte     bUnderlineType;
    public byte     bAnimation;
    public byte     bRevAuthor;
    public byte     bReserved1;
}

I've used using statements to alias System.UInt32 as DWORD, LCID, and COLORREF, and alias System.UInt16 as WORD. I try to keep my P/Invoke definitions as true to SDK spec as I can. CFM and CFE are enums that contain the flag values for these fields. I've left their definitions out for brevity, but can add them in if needed.

I've declared SendMessage as:

[DllImport("user32.dll", CharSet=CharSet.Auto)]
static extern IntPtr SendMessage(
    HWND hWnd, MSG msg, WPARAM wParam, [In, Out] NativeStruct lParam);

HWND is an alias for System.IntPtr, MSG is System.UInt32, and WPARAM is System.UIntPtr.

[In, Out] attribute on lParam is required for this to work, otherwise, it doesn't seem to get marshaled both directions (before and after call to native code).

I call it with:

CHARFORMAT2 cf = new CHARFORMAT2();
SendMessage(rtfControl.Handle, (MSG)EM.GETCHARFORMAT, (WPARAM)SCF.DEFAULT, cf);

EM and SCF are enums I've, again, left out for (relative) brevity.

I check success with:

Console.WriteLine(cf.szFaceName);

and I get:

Microsoft Sans Serif

Works like a charm!


Um, or not, depending on how much sleep you've had and how many things you're trying to do at once, I suppose.

This would work if CHARFORMAT2 were a blittable type. (A blittable type is a type that has the same representation in managed memory as in unmanaged memory.) For instance, the MINMAXINFO type does work as described.

[StructLayout(LayoutKind.Sequential)]
class MINMAXINFO : NativeStruct{
    public Point ptReserved;
    public Point ptMaxSize;
    public Point ptMaxPosition;
    public Point ptMinTrackSize;
    public Point ptMaxTrackSize;
}

This is because blittable types are not really marshaled. They're just pinned in memory—this keeps the GC from moving them—and the address of their location in managed memory is passed to the native function.

Non-blittable types have to be marshaled. The CLR allocates unmanaged memory and copies the data between the managed object and its unmanaged representation, making the necessary conversions between formats as it goes.

The CHARFORMAT2 structure is non-blittable because of the string member. The CLR can't just pass a pointer to a .NET string object where a fixed-length character array is expected to be. So the CHARFORMAT2 structure must be marshaled.

As it would appear, for correct marshaling to occur, the interop function must be declared with the type to be marshaled. In other words, given the above definition, the CLR must be making some sort of determination based on the static type of NativeStruct. I would guess that it's correctly detecting that the object needs to be marshaled, but then only "marshaling" a zero-byte object, the size of NativeStruct itself.

So in order to get your code working for CHARFORMAT2 (and any other non-blittable types you might use), you'll have to go back to declaring SendMessage as taking a CHARFORMAT2 object. Sorry I led you astray on this one.


Captcha for the previous edit:

Yeah, whip it good!


Cory,

This is off topic, but I notice a potential problem for you in the app it looks like you're making.

The rich textbox control uses standard GDI text-measuring and text-drawing functions. Why is this a problem? Because, despite claims that a TrueType font looks the same on screen as on paper, GDI does not accurately place characters. The problem is rounding.

GDI uses all-integer routines to measure text and place characters. The width of each character (and height of each line, for that matter) is rounded to the nearest whole number of pixels, with no error correction.

The error can easily be seen in your test app. Set the font to Courier New at 12 points. This fixed-width font should space characters exactly 10 per inch, or 0.1 inches per character. This should mean that, given your starting line width of 5.5 inches, you should be able to fit 55 characters on the first line before wrap occurs.

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123

But if you try, you'll see that wrap occurs after only 54 characters. What's more the 54 character and part of the 53 overhang the apparent margin shown on the ruler bar.

This assumes you have your settings at standard 96 DPI (normal fonts). If you use 120 DPI (large fonts), you won't see this problem, although it appears that you size your control incorrectly in this case. You also won't likely see this on the printed page.

What's going on here? The problem is that 0.1 inches (the width of one character) is 9.6 pixels (again, using 96 DPI). GDI doesn't space characters using floating point numbers, so it rounds this up to 10 pixels. So 55 characters takes up 55 * 10 = 550 pixels / 96 DPI = 5.7291666... inches, whereas what we were expecting was 5.5 inches.

While this will probably be less noticeable in the normal use case for a word processor program, there is a likelihood of instances where word wrap occurs at different places on screen versus on page, or that things don't line up the same once printed as they did on screen. This could turn out to be a problem for you if this is a commercial application you're working on.

Unfortunately, the fix for this problem is not easy. It means you'll have to dispense with the rich textbox control, which means a huge hassle of implementing yourself everything it does for you, which is quite a lot. It also means that the text drawing code you'll have to implement becomes fairly complicated. I've got code that does it, but it's too complex to post here. You might, however, find this example or this one helpful.

Good luck!


Abstract Base Class

这篇关于.NET互操作的IntPtr与裁判的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-29 00:09
查看更多