既定のプリンターと用紙サイズの変更
投稿者 るきお  (社会人)
投稿日時
2022/2/19 16:58:46
Windows API の SetDefaultPrinterを使用すると既定のプリンターを設定できます。
この例はWindowsフォームアプリケーションで作成しています。
WMIを使う方法もあると思います。
用紙サイズの方は話が込み入っています。
>確認は[設定] > [デバイス] > [プリンターとスキャナー] で該当プリンタの「印刷設定」で確認しました。
この設定はプリンターごとに違う部分になるかもしれないので、使用されているプリンターのデバイスドライバーの仕様を確認する必要があるかもしれません。
プリンターにこだわらず用紙サイズを指定して印刷できれば良いのであれば、WindowsフォームアプリケーションでPrintDocumentコントロールのDefaultPageSettings.PaperSizeで指定することは可能です。
https://docs.microsoft.com/ja-jp/dotnet/api/system.drawing.printing.pagesettings.papersize?view=netframework-2.0
この例はWindowsフォームアプリケーションで作成しています。
Public Class Form1
<Runtime.InteropServices.DllImport("winspool.drv")>
Public Shared Function SetDefaultPrinter(Name As String) As Boolean
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'参考:インストールされているプリンターの名前を確認する方法
For Each printerName As String In Printing.PrinterSettings.InstalledPrinters
Debug.WriteLine(printerName)
Next
'既定のプリンターのセット
SetDefaultPrinter("DocuWorks Printer")
End Sub
End Class
WMIを使う方法もあると思います。
用紙サイズの方は話が込み入っています。
>確認は[設定] > [デバイス] > [プリンターとスキャナー] で該当プリンタの「印刷設定」で確認しました。
この設定はプリンターごとに違う部分になるかもしれないので、使用されているプリンターのデバイスドライバーの仕様を確認する必要があるかもしれません。
プリンターにこだわらず用紙サイズを指定して印刷できれば良いのであれば、WindowsフォームアプリケーションでPrintDocumentコントロールのDefaultPageSettings.PaperSizeで指定することは可能です。
PrintDocument1.DefaultPageSettings.PaperSize = New Printing.PaperSize("カスタムサイズ", 400, 400)
https://docs.microsoft.com/ja-jp/dotnet/api/system.drawing.printing.pagesettings.papersize?view=netframework-2.0
投稿者 まこ  (社会人)
投稿日時
2022/2/19 21:27:14
るきお 様、ありがとうございます。
SetDefaultPrinter APIを使った方法で「既定のプリンタの変更」はできました。
参考にしたページでは、PowerShellを使って「用紙サイズ」や「向き」の変更もできているようなので
何か方法はあるのかな、と思いましたが、OSバージョンやプリンタ機種による相違かもしれません。
当然、プリンタドライバの違いで設定できる項目に相違があることは承知しております。
自分の環境にインストールされているプリンタはPowerShellでも軒並みNGでした。
こちらの方は、半分、あきらめています。
只、「既定のプリンタの変更」の方は折角、APIによる方法を教えてもらったのですが、
PowerShellでも変更できているので、コードでのSystem.Management.Automationによる方法で
実現可能と考えています。
後学のために今、「PSObject Class」について調べていて、もう少し粘ってみます。
SetDefaultPrinter APIを使った方法で「既定のプリンタの変更」はできました。
参考にしたページでは、PowerShellを使って「用紙サイズ」や「向き」の変更もできているようなので
何か方法はあるのかな、と思いましたが、OSバージョンやプリンタ機種による相違かもしれません。
当然、プリンタドライバの違いで設定できる項目に相違があることは承知しております。
自分の環境にインストールされているプリンタはPowerShellでも軒並みNGでした。
こちらの方は、半分、あきらめています。
只、「既定のプリンタの変更」の方は折角、APIによる方法を教えてもらったのですが、
PowerShellでも変更できているので、コードでのSystem.Management.Automationによる方法で
実現可能と考えています。
後学のために今、「PSObject Class」について調べていて、もう少し粘ってみます。
投稿者 るきお  (社会人)
投稿日時
2022/2/19 22:28:51
>参考にしたページでは、PowerShellを使って「用紙サイズ」や「向き」の変更もできているようなので
何か方法はあるのかな、と思いました
言われてみればそうですね。
WMIでやってみました。このプログラムを実行しても用紙サイズは変わりませんでした。
ただ、私の場合、まこさんが提示されたサイトのPowerShellでも用紙サイズは変わらなかったです。エラーにもなりません。
だから、ひょっとするとまこさんの環境ではうまくいくのかもしれませんね。
なお、上述のプログラムもPowerShellも実行するには「管理者として実行」する必要がありました。
参考:別バージョン
こちらも結果は変わらずです。
何か方法はあるのかな、と思いました
言われてみればそうですね。
WMIでやってみました。このプログラムを実行しても用紙サイズは変わりませんでした。
'要 Option Strict Off
Using printer As New Management.ManagementObject("Win32_Printer.DeviceID=""Microsoft Print to PDF""")
printer.Get() '一応Getしてみても特に変わらず
Debug.WriteLine("参考:このプリンターで使用できるプロパティの一覧")
For Each prop In printer.Properties
Debug.WriteLine($"{prop.Name} = {prop.Value}")
Next
printer("DefaultPaperType") = "A5"
printer.Put()
End Using
ただ、私の場合、まこさんが提示されたサイトのPowerShellでも用紙サイズは変わらなかったです。エラーにもなりません。
だから、ひょっとするとまこさんの環境ではうまくいくのかもしれませんね。
なお、上述のプログラムもPowerShellも実行するには「管理者として実行」する必要がありました。
参考:別バージョン
こちらも結果は変わらずです。
'要 Option Strict Off
Using mc As New Management.ManagementClass("Win32_Printer")
Using printers As System.Management.ManagementObjectCollection = mc.GetInstances()
Dim printer As Management.ManagementObject = Nothing
For Each p In printers
If p("Name") = "Microsoft Print to PDF" Then
printer = p
Exit For
End If
Next
Debug.WriteLine("参考:このプリンターで使用できるプロパティの一覧")
For Each prop In printer.Properties
Debug.WriteLine($"{prop.Name} = {prop.Value}")
Next
printer("DefaultPaperType") = "A5"
printer.Put()
printer.Dispose()
End Using
End Using
投稿者 るきお  (社会人)
投稿日時
2022/2/19 22:35:24
まこさんも、用紙の変更の方はPowerShellでもできていないと書かれていましたね。
投稿者 まこ  (社会人)
投稿日時
2022/2/19 22:50:22
System.Management.Automationによる方法で、「既定プリンタの変更」は実現できました。
変数の名前がダメダメですが....
変数の名前がダメダメですが....
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim runspaceInvoke As RunspaceInvoke = New RunspaceInvoke()
Dim printer As Object = runspaceInvoke.Invoke("Get-WmiObject Win32_Printer | Where-Object Name -eq ""CubePDF""")
Dim v As PSObject = printer(0)
Dim vv As Management.ManagementObject = v.ImmediateBaseObject
vv.InvokeMethod("SetDefaultPrinter", Nothing)
End Sub
投稿者 るきお  (社会人)
投稿日時
2022/2/19 22:51:40
どうしてもプリンターの設定を変更しようと思うと、DEVMODE構造体まわりの話になってくると思うのですよね。
https://docs.microsoft.com/ja-jp/dotnet/api/system.drawing.printing.printersettings.gethdevmode?view=dotnet-plat-ext-6.0
この構造体は本当に意地悪で多くのプログラマーを苦しめているんです。
そして、引用したサイトに書いてある
>DEVMODE 構造体はデバイス固有です。
の部分が、私が最初に書いた
>この設定はプリンターごとに違う部分になるかもしれないので、使用されているプリンターのデバイスドライバーの仕様を確認する必要があるかもしれません。
の部分です。
過去にチャレンジした人の名残がネット上に見つかりました。
http://bbs.wankuma.com/index.cgi?mode=al2&namber=2377&KLOG=2
https://atmarkit.itmedia.co.jp/bbs/phpBB/viewtopic.php?topic=42909&forum=7
https://dobon.net/vb/bbs/log3-47/28144.html
デバイスごとに仕様が違うとすると、あるプリンターで成功しても別のプリンターでは通用しないということがありえます。
だから、既定の用紙サイズを変更する方法はこれだという決定的な情報が古していないのだと思います。
VB6版ですがサンプルを公開している人はいました。
この方はカスタムサイズを設定する方法を公開しているようです。
https://binaryworld.net/main/CodeDetail.aspx?CodeId=3093
プログラムが複雑なので中身は見ていないのですが、どのプリンターでも通用するものなのかどうかは疑問です。
https://docs.microsoft.com/ja-jp/dotnet/api/system.drawing.printing.printersettings.gethdevmode?view=dotnet-plat-ext-6.0
この構造体は本当に意地悪で多くのプログラマーを苦しめているんです。
そして、引用したサイトに書いてある
>DEVMODE 構造体はデバイス固有です。
の部分が、私が最初に書いた
>この設定はプリンターごとに違う部分になるかもしれないので、使用されているプリンターのデバイスドライバーの仕様を確認する必要があるかもしれません。
の部分です。
過去にチャレンジした人の名残がネット上に見つかりました。
http://bbs.wankuma.com/index.cgi?mode=al2&namber=2377&KLOG=2
https://atmarkit.itmedia.co.jp/bbs/phpBB/viewtopic.php?topic=42909&forum=7
https://dobon.net/vb/bbs/log3-47/28144.html
デバイスごとに仕様が違うとすると、あるプリンターで成功しても別のプリンターでは通用しないということがありえます。
だから、既定の用紙サイズを変更する方法はこれだという決定的な情報が古していないのだと思います。
VB6版ですがサンプルを公開している人はいました。
この方はカスタムサイズを設定する方法を公開しているようです。
https://binaryworld.net/main/CodeDetail.aspx?CodeId=3093
プログラムが複雑なので中身は見ていないのですが、どのプリンターでも通用するものなのかどうかは疑問です。
投稿者 るきお  (社会人)
投稿日時
2022/2/19 22:53:46
>System.Management.Automationによる方法で、「既定プリンタの変更」は実現できました。
既定のプリンターの変更は、デバイスごとの違いもなく、私が提示したWindows APIのプログラムでもできています。
問題は既定の用紙のサイズの変更の方です。
こちらは、PowerShell版で私もまこさんもできておらず、私の.NET版のプログラムでもできていません。
私が思っていることは前述のとおりです。
既定のプリンターの変更は、デバイスごとの違いもなく、私が提示したWindows APIのプログラムでもできています。
問題は既定の用紙のサイズの変更の方です。
こちらは、PowerShell版で私もまこさんもできておらず、私の.NET版のプログラムでもできていません。
私が思っていることは前述のとおりです。
投稿者 まこ  (社会人)
投稿日時
2022/2/19 23:15:37
るきお様、了解です。
色々、検証していただき、ありがとうございます。
自分もそこまで、こだわるわけではないので......
興味があったのは、PowerShellの文字列を使って、コードに移植する事だったので。
これで、終わりにしたいと思います。
どうも、ありがとうございました。
PS. RunspaceInvokeはIDisposableを実装しているので、Usingした方がいいかも。
色々、検証していただき、ありがとうございます。
自分もそこまで、こだわるわけではないので......
興味があったのは、PowerShellの文字列を使って、コードに移植する事だったので。
これで、終わりにしたいと思います。
どうも、ありがとうございました。
PS. RunspaceInvokeはIDisposableを実装しているので、Usingした方がいいかも。
投稿者 KOZ  (社会人)
投稿日時
2022/2/20 20:58:50
デフォルトプリンタの用紙設定を変更するサンプルです。
これで設定変更できないでしょうか?
# 長いので API 宣言は後述
これで設定変更できないでしょうか?
# 長いので API 宣言は後述
Option Strict On
Imports System.ComponentModel
Imports System.Drawing.Printing
Imports System.Runtime.InteropServices
Module Module1
Sub Main()
'デフォルトプリンタの用紙設定を行う
Dim ps As New PrinterSettings
For Each paperSize As PaperSize In ps.PaperSizes
If paperSize.Kind = PaperKind.A3 Then
ps.DefaultPageSettings.PaperSize = paperSize
Exit For
End If
Next
Dim pd As New PRINTER_DEFAULTS()
Dim hPrinter As IntPtr
pd.DesiredAccess = PRINTER_ALL_ACCESS
If Not OpenPrinter(ps.PrinterName, hPrinter, pd) Then
Throw New Win32Exception()
End If
Try
Dim pi2 As PRINTER_INFO_2 = GetPrinterInfo2(hPrinter)
Dim hMem As IntPtr = ps.GetHdevmode()
Try
pi2.pDevMode = GlobalLock(hMem)
SetPrinter(hPrinter, 2, pi2, 0)
Finally
GlobalUnlock(hMem)
GlobalFree(hMem)
End Try
Finally
ClosePrinter(hPrinter)
End Try
End Sub
Private Function GetPrinterInfo2(hPrinter As IntPtr) As PRINTER_INFO_2
Dim needed As Integer
GetPrinter(hPrinter, 2, IntPtr.Zero, 0, needed)
If needed <= 0 Then
Throw New Win32Exception()
End If
Dim pPrinterInfo As IntPtr = Marshal.AllocHGlobal(needed)
Try
Dim temp As Integer
If Not GetPrinter(hPrinter, 2, pPrinterInfo, needed, temp) Then
Throw New Win32Exception()
End If
Return Marshal.PtrToStructure(Of PRINTER_INFO_2)(pPrinterInfo)
Finally
Marshal.FreeHGlobal(pPrinterInfo)
End Try
End Function
End Module
投稿者 KOZ  (社会人)
投稿日時
2022/2/20 21:00:08
Module NativeMethods
Public Const STANDARD_RIGHTS_REQUIRED As Integer = &HF0000
Public Const PRINTER_ACCESS_ADMINISTER As Integer = &H4
Public Const PRINTER_ACCESS_USE As Integer = &H8
Public Const PRINTER_ALL_ACCESS As Integer = STANDARD_RIGHTS_REQUIRED Or
PRINTER_ACCESS_ADMINISTER Or
PRINTER_ACCESS_USE
Public Structure PRINTER_DEFAULTS
Public pDatatype As IntPtr
Public pDevMode As IntPtr
Public DesiredAccess As Integer
End Structure
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>
Public Structure PRINTER_INFO_2
Public pServerName As String
Public pPrinterName As String
Public pShareName As String
Public pPortName As String
Public pDriverName As String
Public pComment As String
Public pLocation As String
Public pDevMode As IntPtr
Public pSepFile As String
Public pPrintProcessor As String
Public pDatatype As String
Public pParameters As String
Public pSecurityDescriptor As IntPtr
Public Attributes As Integer
Public Priority As Integer
Public DefaultPriority As Integer
Public StartTime As Integer
Public UntilTime As Integer
Public Status As Integer
Public cJobs As Integer
Public AveragePPM As Integer
End Structure
<DllImport("winspool.drv", CharSet:=CharSet.Auto)>
Public Function OpenPrinter(pPrinterName As String,
ByRef phPrinter As IntPtr,
ByRef pDefault As PRINTER_DEFAULTS) As Boolean
End Function
<DllImport("winspool.drv", CharSet:=CharSet.Auto)>
Public Function SetPrinter(hPrinter As IntPtr,
Level As Integer,
ByRef pi2 As PRINTER_INFO_2,
command As Integer) As Boolean
End Function
<DllImport("winspool.drv", SetLastError:=True, CharSet:=CharSet.Auto)>
Public Function GetPrinter(hPrinter As IntPtr,
dwLevel As Integer,
pPrinter As IntPtr,
cbBuf As Integer,
ByRef pcbNeeded As Integer) As Boolean
End Function
<DllImport("winspool.drv", SetLastError:=True)>
Public Function ClosePrinter(hPrinter As IntPtr) As Boolean
End Function
<DllImport("kernel32.dll")>
Public Function GlobalFree(hMem As IntPtr) As IntPtr
End Function
<DllImport("kernel32.dll")>
Public Function GlobalLock(hMem As IntPtr) As IntPtr
End Function
<DllImport("kernel32.dll")>
Public Function GlobalUnlock(hMem As IntPtr) As Boolean
End Function
End Module
投稿者 KOZ  (社会人)
投稿日時
2022/2/20 21:32:41
DEVMODEW 構造体
https://docs.microsoft.com/ja-jp/windows-hardware/drivers/display/the-devmodew-structure
DEVMODEW structure (wingdi.h)
https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-devmodew
DEVMODE構造体にはパブリックメンバーとプライベートメンバーがあり、用紙サイズは dmPaperSize という定義済みメンバなので設定できると思いますよ。
https://docs.microsoft.com/ja-jp/windows-hardware/drivers/display/the-devmodew-structure
DEVMODEW structure (wingdi.h)
https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-devmodew
DEVMODE構造体にはパブリックメンバーとプライベートメンバーがあり、用紙サイズは dmPaperSize という定義済みメンバなので設定できると思いますよ。
投稿者 るきお  (社会人)
投稿日時
2022/2/20 21:34:48
おお。用紙サイズ変わりました。いいですね。
Windows 10の「Windows で通常使うプリンターを管理する」をオフにして、「管理者として実行」する必要はありました。
Windows 10の「Windows で通常使うプリンターを管理する」をオフにして、「管理者として実行」する必要はありました。
投稿者 まこ  (社会人)
投稿日時
2022/2/20 22:28:58
おお、すごい!!
こちらでも用紙サイズ変更できました。同じ要領で向きも変更できました。
KOZ様、ありがとうございます。
こちらでも用紙サイズ変更できました。同じ要領で向きも変更できました。
KOZ様、ありがとうございます。
Windows既定のプリンターの変更と用紙サイズの変更をVB.NETから行いたいです。
調査したら↓のPowerShellを使った方法が見つかったのですが、PowerShellも
使ったことがないので、コードから利用するのに苦戦しています。
https://qiita.com/arachan@github/items/438f4cd806d445aa8ce5
試行錯誤して以下のような所まで自分でやってみたのですが、
ここから先に進めません。お助けください。
System.Management.Automationの参照はできています。
【既定のプリンターの変更】
PowerShellからは↓で変更できました。プリンタはとりあえず「DocuWorks Printer」という仮想プリンタにしています。
ここはインストールされているプリンタからComboBox等で選べるようにするつもりです。
デバッガで確認すると、変数printerはコレクションで1つだけ要素が格納されていました。
【用紙サイズの変更】
こちらはPowerShellからは↓でもNG。
確認は[設定] > [デバイス] > [プリンターとスキャナー] で該当プリンタの「印刷設定」で確認しました。
できればA3からA4に縮小印刷する場合の設定方法があれば、それも教えて欲しいです。