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声明,并添加到自己的代码中。 |
|