2012-05-12 59 views
0

我嘗試使用WinAPI而不是(System.Drawing.Printing.PrintDocument)來準備打印文檔,因爲Graphic.DrawString不能正確渲染高棉Unicode。只有TextRendering.DrawText正確呈現它。我相信Graphic是GDI +包裝器,TextRendering.DrawText是使用GDI。此外,PrintDocument不適用於TextRendering.DrawText。從hDC創建圖形導致算術運算溢出

Private Declare Function CreateDC Lib "gdi32" Alias "CreateDCA" _ 
(ByVal lpDriverName As String, ByVal lpDeviceName As String, _ 
ByVal lpOutput As String, ByVal lpInitData As DEVMODE) As Long 
Private Declare Function EndDoc Lib "gdi32" (ByVal hdc As Long) As Long 
Private Declare Function StartDoc Lib "gdi32" Alias "StartDocA" (ByVal hdc As Long, ByVal lpdi As DOCINFO) As Long 
Private Declare Function StartPage Lib "gdi32" (ByVal hdc As Long) As Long 
Private Declare Function EndPage Lib "gdi32" (ByVal hdc As Long) As Long 

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 
    '' Getting Printer hDC 
    Dim printHandler As Long = CreateDC(Nothing, "Send To OneNote 2010", Nothing, Nothing) 
    Dim docInfo As New DOCINFO 
    docInfo.cbSize = Len(docInfo) 
    docInfo.lpszDatatype = Nothing 
    docInfo.lpszOutput = Nothing 
    docInfo.lpszDocName = "Testing" 

    StartDoc(printHandler, docInfo) 
    StartPage(printHandler) 

    Dim g As Graphics = Graphics.FromHdc(printHandler) 
    TextRenderer.DrawText(g, "Hello World", Me.Font, New Point(10, 10), Color.Black) 

    EndPage(printHandler) 
    EndDoc(printHandler) 
End Sub 

這是我的嘗試。它在這行代碼上失敗:Dim g As Graphics = Graphics.FromHdc(printHandler)。看起來Long是64位,IntPtr是32位。

有沒有解決方法?

+2

爲什麼要聲明'CreateDC'來返回一個'Long'? API使用'IntPtr'返回'HDC'。 – arx

+0

我在問這個問題之前已經試過IntPtr了。當我使用Long時,它將OneNote 2010作爲打印機打開。當我使用IntPtr時,它什麼都不做。 – invisal

回答

2

您的所有P/Invoke定義在VB.NET中都是錯誤的。你顯然已經從一個專門針對VB 6的項目或網站複製了它們,但很多事情都隨着.NET而改變。

正確的定義是這樣的:

<DllImport("gdi32.dll", SetLastError:=False, CharSet:=CharSet.Auto)> _ 
Private Shared Function CreateDC(lpszDriver As String, _ 
           lpszDevice As String, _ 
           lpszOutput As IntPtr, _ 
           ByRef lpInitData As DEVMODE) As IntPtr 
End Function 

<DllImport("gdi32.dll", SetLastError:=False)> _ 
Private Shared Function EndDoc(hdc As IntPtr) As Integer 
End Function 

<DllImport("gdi32.dll", SetLastError:=False)> _ 
Private Shared Function StartDoc(hdc As IntPtr, ByRef lpdi As DOCINFO) As Integer 
End Function 

<DllImport("gdi32.dll", SetLastError:=False)> _ 
Private Shared Function StartPage(hdc As IntPtr) As Integer 
End Function 

<DllImport("gdi32.dll", SetLastError:=False)> _ 
Private Shared Function EndPage(hdc As IntPtr) As Integer 
End Function 

而且有很好的機會你對DEVMODEDOCINFO結構的定義是錯誤的,也是如此。對於指針類型,您可能使用的是Long而不是IntPtr,對於數值類型,可以使用LongInteger,因爲這些類型的含義已從VB 6更改爲VB.NET。

你可能不需要DEVMODE結構可言,如果是的話,你可以用替換CreateDC函數定義:

<DllImport("gdi32.dll", SetLastError:=False, CharSet:=CharSet.Auto)> _ 
Private Shared Function CreateDC(lpszDriver As String, _ 
           lpszDevice As String, _ 
           lpszOutput As IntPtr, _ 
           lpInitData As IntPtr) As IntPtr _ 
End Function 

,並通過IntPtr.ZerolpInitData,就像你會爲lpszOutput,如指令the documentation - IntPtr.Zero對於指針類型實際上等效於NULL

DOCINFO結構將被聲明爲:

<StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)> _ 
Private Structure DOCINFO 
    Dim cbSize As Integer 
    Dim lpszDocName As String 
    Dim lpszOutput As String 
    Dim lpszDatatype As String 
    Dim fwType As Integer 
End Structure 

作爲每the documentation,所述fwType構件可以是任何以下常量:

  • Private Const DI_APPBANDING As Integer = &H1
  • Private Const DI_ROPS_READ_DESTINATION As Integer = &H2

所有這一切......你知道在.NET世界中有更簡單的打印方式,對吧?

+0

我知道更容易。使用PrintDocument及其PrintPage事件。重點在於PrintDocument不適用於TextRendering。我改變了你所建議的一切。 CreateDC返回null。我會盡力解決它。 (如果我不能自己解決,我會再來這裏)歡呼。 – invisal

+0

@invisal我不能告訴你在不知道你傳遞給函數的參數的情況下,你對'CreateDC'的調用有什麼問題。當它返回NULL時,這表示函數失敗。確保你檢查了[文檔](http://msdn.microsoft.com/en-us/library/dd183490.aspx),並確保你傳遞了有效的參數。 (另外我忘了在我的答案中包含**,您必須調用['DeleteDC'函數](http://msdn.microsoft.com/zh-cn/library/dd183533.aspx)來銷燬您創建的設備上下文在完成之後使用'CreateDC',否則會泄漏內存**。) –

相關問題