找回密码
 立即注册

QQ登录

只需一步,快速开始

graper

高级会员

45

主题

63

帖子

1348

积分

高级会员

积分
1348

活字格认证

graper
高级会员   /  发表于:2009-12-11 16:08  /   查看:6619  /  回复:0
Post by "winking", 03-06-2007, 10:16
-----------------------------------------------------


Recently, I am working on fixing bugs which they are most related to PInvoke. well, the definition of PInvoke seems all right at all, but they not works, and more seriously, some of them caused application ending unexpected, I am puzzled, after all I read some books and articles, trace the code, then everything comes to him who waits, I found the answer to the riddle, and I share my experience here, to simplify the question, I show you case by case.
There is a API whcih can prompt the printing setting named DocumentProperties, it's in winspool.drv the Cpp version API define is following (if you want to get more information, please refere to MSDN, it's sub of GDI, [url=]ms-help://MS.MSDN.vAug06.en/gdi/prntspol_7k1f.htm[/url]):
                        LONG DocumentProperties(
                          HWND hWnd,                          // handle to parent window
                          HANDLE hPrinter,                    // handle to printer object
                          LPTSTR pDeviceName,             // device name
                          PDEVMODE pDevModeOutput, // modified device mode
                          PDEVMODE pDevModeInput,    // original device mode
                          DWORD fMode                        // mode options
                        );
well, in my application, I defined it like following:
                       [DllImport("winspool.drv", SetLastError = true)]
                       public extern static int DocumentProperties(
                               IntPtr hWnd,                      // handle to parent window
                               IntPtr hPrinter,                   // handle to printer object
                               string pDeviceName,           // device name
                               ref IntPtr pDevModeOutput, // modified device mode
                               ref IntPtr pDevModeInput,    // original device mode
                               int fMode                           // mode options
                       );
Then I used it to open printer setting dialog, and try to get the modifed result, strangely, the application end unexpected, why, I guess some where throw some seriouse exception which cause application end, but after I attatched VS2005 IDE to application, then do call API, application end unepected as well, and no exception was thrown. Then I read API definition, I found I have wrong definition for PInvoke, here the parameters pDevModeOutput and pDevModeInput is only a pointer, but I defined as ref IntPtr, it means a pointer to pointer, that's wrong.
Ok, I have corrected my definition of PInvoke, and refere to MSDN, it seems all right, it should can be working (list in following block), but the result is out of my expected, application still end unexpected in some use case. why?
                       [DllImport("winspool.drv", SetLastError = true)]
                       public extern static int DocumentProperties(
                               IntPtr hWnd,                      // handle to parent window
                               IntPtr hPrinter,                   // handle to printer object
                               string pDeviceName,           // device name
                               IntPtr pDevModeOutput,      // modified device mode
                               IntPtr pDevModeInput,        // original device mode
                               int fMode                           // mode options
                       );
I track the source code after convert the MSIL to local native application, and debug in windbg, the I found a strange call, the PInvoke jump to native ANSI mode API (DocumentPropertiesA, you can use cpp editor view the function, it defined at winspool.h), that's funny, my application is unicode version (gerneral, csharp application is UNICODE version), why it call ANSI version? the I check my definition of PInvoke, and explicitly define the CharSet to Unicode, all is ok, following is code changed:
                       [DllImport("winspool.drv", CharSet = CharSet.Unicode, SetLastError = true)]
                       public extern static int DocumentProperties(
                               IntPtr hWnd,                      // handle to parent window
                               IntPtr hPrinter,                   // handle to printer object
                               string pDeviceName,           // device name
                               IntPtr pDevModeOutput,      // modified device mode
                               IntPtr pDevModeInput,        // original device mode
                               int fMode                           // mode options
                       );
Then I read MSDN, and I found explicitly define the CharSet to Unicode is not recommanded, it should define to CharSet.Auto, so the lastest PInvoke version is following:
                       [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
                       public extern static int DocumentProperties(
                               IntPtr hWnd,                      // handle to parent window
                               IntPtr hPrinter,                   // handle to printer object
                               string pDeviceName,           // device name
                               IntPtr pDevModeOutput,      // modified device mode
                               IntPtr pDevModeInput,        // original device mode
                               int fMode                           // mode options
                       );



Reply by "Colin", 03-06-2007, 17:36
-----------------------------------------------------

我在PInvoke.net上找了一下,声明是下面的样子:

[DllImport("winspool.Drv", EntryPoint = "DocumentPropertiesW", SetLastError = true,
         ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter,
        [MarshalAs(UnmanagedType.LPWStr)] string pDeviceName,
        IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode);

呵呵,很多东西都没用过啊!

借道推荐个小工具:PINVOKE.NET Add-In for Visual Studio 2005 自动在PInvoke.net上搜索API声明,并添加到自己的代码中。

0 个回复

您需要登录后才可以回帖 登录 | 立即注册
返回顶部