PRINTERの「利用可能な用紙」などにつきまして
投稿者 るきお  (社会人)
投稿日時
2021/6/25 19:38:52
ここにプリンターがサポートする用紙の一覧を取得するVBのサンプルプログラムがあります。
https://docs.microsoft.com/ja-jp/office/vba/access/concepts/printing/programmatically-retrieve-printer-capabilities
Office VBA リファレンスの一部なので、Excel VBAでも動作するのではないかと思いますがどうでしょうか?
https://docs.microsoft.com/ja-jp/office/vba/access/concepts/printing/programmatically-retrieve-printer-capabilities
Office VBA リファレンスの一部なので、Excel VBAでも動作するのではないかと思いますがどうでしょうか?
投稿者 snowmansnow  (社会人)
投稿日時
2021/6/25 20:22:36
るきお様こんばんは、
お返事ありがとうございます。
やっぱりダメで、
「エラー438
オブジェクトは、このプロパティまたはメソッドをサポートしていません。」になってしまいます。
「利用可能な用紙:」一覧は、複合機のトレイ内容と一致してる複合機もありますし、
複合機のトレイ内容の一部のものもありますし、複合機のトレイ内容より多いものもあります。
「利用可能な用紙:」一覧の意味が知りたいですし、複合機本来の各トレイ用紙一覧が取得できて、
その中の用紙を設定したいです。(無人で、用紙変更・補給などせず印刷したいです。)
各メーカーの独自?ドライバーの中の、トレイ一覧も、ただトレイ番号一覧のものや、
用紙も表示してるもの、用紙の大きさや向きも表示してるものなど様々でした。
各メーカーのドライバーの中の表示項目の全部又は一部は、何かしらの規格に基づいていて、
それを、独自の表示方法で表示してるだけ、ではないのでしょうか?
それぞれ、完全に各メーカー独自の世界なのでしょうか?
規格があるのなら、表示してるものを、それを通信したり取り出す事ができるのでは?と思いました。
規格~の考えが間違っていて、取り出す事や設定する事は出来ない世界なのでしょうか?
VBNETやPOWERSHELLの用紙設定は、遠隔で設定できても、その紙があるかわからず、
パソコンで設定してから、プリンタに行って、紙を確認したり、変更・補充しないと、
印刷は完了せずに、エラーのままなのでしょうか?そのエラーはわかりますか?
お手数かけますが、よろしくお願いします。
お返事ありがとうございます。
やっぱりダメで、
「エラー438
オブジェクトは、このプロパティまたはメソッドをサポートしていません。」になってしまいます。
「利用可能な用紙:」一覧は、複合機のトレイ内容と一致してる複合機もありますし、
複合機のトレイ内容の一部のものもありますし、複合機のトレイ内容より多いものもあります。
「利用可能な用紙:」一覧の意味が知りたいですし、複合機本来の各トレイ用紙一覧が取得できて、
その中の用紙を設定したいです。(無人で、用紙変更・補給などせず印刷したいです。)
各メーカーの独自?ドライバーの中の、トレイ一覧も、ただトレイ番号一覧のものや、
用紙も表示してるもの、用紙の大きさや向きも表示してるものなど様々でした。
各メーカーのドライバーの中の表示項目の全部又は一部は、何かしらの規格に基づいていて、
それを、独自の表示方法で表示してるだけ、ではないのでしょうか?
それぞれ、完全に各メーカー独自の世界なのでしょうか?
規格があるのなら、表示してるものを、それを通信したり取り出す事ができるのでは?と思いました。
規格~の考えが間違っていて、取り出す事や設定する事は出来ない世界なのでしょうか?
VBNETやPOWERSHELLの用紙設定は、遠隔で設定できても、その紙があるかわからず、
パソコンで設定してから、プリンタに行って、紙を確認したり、変更・補充しないと、
印刷は完了せずに、エラーのままなのでしょうか?そのエラーはわかりますか?
お手数かけますが、よろしくお願いします。
投稿者 るきお  (社会人)
投稿日時
2021/6/25 20:44:47
とりあえず、Excelで動くようにしたプログラムを共有します。
久しぶりにExcel VBAをいじりました。
Application.Printer というものはExcelにはないのですね。そこをいじって動くようにしました。私の環境では動作しましたが、付け焼刃なので動かない環境もあるかもしれません。
久しぶりにExcel VBAをいじりました。
Application.Printer というものはExcelにはないのですね。そこをいじって動くようにしました。私の環境では動作しましたが、付け焼刃なので動かない環境もあるかもしれません。
' Declaration for the DeviceCapabilities function API call.
Private Declare PtrSafe Function DeviceCapabilities Lib "winspool.drv" _
Alias "DeviceCapabilitiesA" (ByVal lpsDeviceName As String, _
ByVal lpPort As String, ByVal iIndex As Long, lpOutput As Any, _
ByVal lpDevMode As Long) As Long
' DeviceCapabilities function constants.
Private Const DC_PAPERNAMES = 16
Private Const DC_PAPERS = 2
Private Const DC_BINNAMES = 12
Private Const DC_BINS = 6
Private Const DEFAULT_VALUES = 0
Sub GetPaperList()
Dim lngPaperCount As Long
Dim lngCounter As Long
Dim hPrinter As Long
Dim strDeviceName As String
Dim strDevicePort As String
Dim strPaperNamesList As String
Dim strPaperName As String
Dim intLength As Integer
Dim strMsg As String
Dim aintNumPaper() As Integer
On Error GoTo GetPaperList_Err
' Get the name and port of the default printer.
Dim printer As String
printer = Application.ActivePrinter
strDeviceName = Split(printer, " on ")(0)
strDevicePort = Split(printer, " on ")(1)
'strDeviceName = Application.ActivePrinter.DeviceName
'strDevicePort = Application.ActivePrinter.Port
' Get the count of paper names supported by the printer.
lngPaperCount = DeviceCapabilities(lpsDeviceName:=strDeviceName, _
lpPort:=strDevicePort, _
iIndex:=DC_PAPERNAMES, _
lpOutput:=ByVal vbNullString, _
lpDevMode:=DEFAULT_VALUES)
' Re-dimension the array to the count of paper names.
ReDim aintNumPaper(1 To lngPaperCount)
' Pad the variable to accept 64 bytes for each paper name.
strPaperNamesList = String(64 * lngPaperCount, 0)
' Get the string buffer of all paper names supported by the printer.
lngPaperCount = DeviceCapabilities(lpsDeviceName:=strDeviceName, _
lpPort:=strDevicePort, _
iIndex:=DC_PAPERNAMES, _
lpOutput:=ByVal strPaperNamesList, _
lpDevMode:=DEFAULT_VALUES)
' Get the array of all paper numbers supported by the printer.
lngPaperCount = DeviceCapabilities(lpsDeviceName:=strDeviceName, _
lpPort:=strDevicePort, _
iIndex:=DC_PAPERS, _
lpOutput:=aintNumPaper(1), _
lpDevMode:=DEFAULT_VALUES)
' List the available paper names.
strMsg = "Papers available for " & strDeviceName & vbCrLf
For lngCounter = 1 To lngPaperCount
' Parse a paper name from the string buffer.
strPaperName = Mid(String:=strPaperNamesList, _
Start:=64 * (lngCounter - 1) + 1, Length:=64)
intLength = VBA.InStr(Start:=1, String1:=strPaperName, String2:=Chr(0)) - 1
strPaperName = Left(String:=strPaperName, Length:=intLength)
' Add a paper number and name to text string for the message box.
strMsg = strMsg & vbCrLf & aintNumPaper(lngCounter) _
& vbTab & strPaperName
Next lngCounter
' Show the paper names in a message box.
MsgBox Prompt:=strMsg
GetPaperList_End:
Exit Sub
GetPaperList_Err:
MsgBox Prompt:=Err.Description, Buttons:=vbCritical & vbOKOnly, _
Title:="Error Number " & Err.Number & " Occurred"
Resume GetPaperList_End
End Sub
投稿者 るきお  (社会人)
投稿日時
2021/6/25 20:57:48
snowmansnowさんが、取得したいのは、紙が実際にセットされていて、印刷指示をすれば実際に印刷可能な用紙の一覧を取得したいということでしょうか?
Windowsではプリンタードライバーに最低限必要なインターフェースが定義されており、各プリンタードライバーは定義された情報を返します。
また、それとは別にプリンター独自の拡張機能や情報を保持している場合もあります。
実際に印刷可能な用紙の一覧や、セットされている紙はWindowsでは定義されていない情報だと思いますので、プリンタードライバーが独自に定義している場合のみ取得可能です。
標準化されている情報のリファレンスはたとえば、このあたりにあります。
https://docs.microsoft.com/ja-jp/windows/win32/api/wingdi/ns-wingdi-devmodea
https://docs.microsoft.com/ja-jp/windows/win32/printdocs/printer-info-1
DEVMODEA構造体のリファレンスにはこの構造体におけるPaperSizeの定数と意味も掲載されています。
プリンタードライバーが実際にこの情報として何を返すかは、このリファレンスでは「selects the size of the paper to print on」としか記載されておらず、詳細はメーカーに委ねられているかもしれません。
私はあまりこのあたりのことは詳しくありません。
ドライバー開発者用のリファレンスにはもっと情報が記載されているかもしれません。
Windowsではプリンタードライバーに最低限必要なインターフェースが定義されており、各プリンタードライバーは定義された情報を返します。
また、それとは別にプリンター独自の拡張機能や情報を保持している場合もあります。
実際に印刷可能な用紙の一覧や、セットされている紙はWindowsでは定義されていない情報だと思いますので、プリンタードライバーが独自に定義している場合のみ取得可能です。
標準化されている情報のリファレンスはたとえば、このあたりにあります。
https://docs.microsoft.com/ja-jp/windows/win32/api/wingdi/ns-wingdi-devmodea
https://docs.microsoft.com/ja-jp/windows/win32/printdocs/printer-info-1
DEVMODEA構造体のリファレンスにはこの構造体におけるPaperSizeの定数と意味も掲載されています。
プリンタードライバーが実際にこの情報として何を返すかは、このリファレンスでは「selects the size of the paper to print on」としか記載されておらず、詳細はメーカーに委ねられているかもしれません。
私はあまりこのあたりのことは詳しくありません。
ドライバー開発者用のリファレンスにはもっと情報が記載されているかもしれません。
投稿者 snowmansnow  (社会人)
投稿日時
2021/6/25 22:43:31
るきお様お返事ありがとうございます。
APIの例、ありがとうございます。
自分では動かなかったので、どんな値がでるか期待していました。
でも、VBNETのPAPERSIZEと同じ数でした(用紙の種類は表示がされたりされなかったりで、確実には確認できませんでいたが)
APIで気になっているのが
DC_BINSとDC_BINNAMESで、先に教えて頂いたwebにGETBINNAME()があり、
るきお様の修正してくれたコード
を使ったところ、トレイ?トレイ名?の出力を確認できました。
今日は複合機群の各出力を確認できず、プリンターダイアログのどれと対応してるのか確認できませんが、
月曜以降確認させて頂きたいと思います。
教えて頂いたC++のサイトは、用紙の例と、出力エラーのスプール残の確認用でしょうか?
スプールが残っていたら、紙が違うという事でしょうか?
複合機側もエラーになっていると思われ、共同作業場(遠隔)では、迷惑かもしれないと思います・・・
また、「実際に印刷可能な用紙の一覧や、セットされている紙はWindowsでは定義されていない情報だと思いますので、プリンタードライバーが独自に定義している場合のみ取得可能です。」
は、残念で、可能な場合の取得も敷居が高そうな話で悲しいです。
「selects the size of the paper to print on」の記載も、教えて頂いたwebのpdfで確認できず、
メーカー次第で悲しいですが、私の希望はかなわないのかもしれません。
月曜以降に少し期待しています。
その際は、また報告します。
大変ありがとうございます。
APIの例、ありがとうございます。
自分では動かなかったので、どんな値がでるか期待していました。
でも、VBNETのPAPERSIZEと同じ数でした(用紙の種類は表示がされたりされなかったりで、確実には確認できませんでいたが)
APIで気になっているのが
DC_BINSとDC_BINNAMESで、先に教えて頂いたwebにGETBINNAME()があり、
るきお様の修正してくれたコード
Dim printer As String
printer = Application.ActivePrinter
strDeviceName = Split(printer, " on ")(0)
strDevicePort = Split(printer, " on ")(1)
を使ったところ、トレイ?トレイ名?の出力を確認できました。
今日は複合機群の各出力を確認できず、プリンターダイアログのどれと対応してるのか確認できませんが、
月曜以降確認させて頂きたいと思います。
教えて頂いたC++のサイトは、用紙の例と、出力エラーのスプール残の確認用でしょうか?
スプールが残っていたら、紙が違うという事でしょうか?
複合機側もエラーになっていると思われ、共同作業場(遠隔)では、迷惑かもしれないと思います・・・
また、「実際に印刷可能な用紙の一覧や、セットされている紙はWindowsでは定義されていない情報だと思いますので、プリンタードライバーが独自に定義している場合のみ取得可能です。」
は、残念で、可能な場合の取得も敷居が高そうな話で悲しいです。
「selects the size of the paper to print on」の記載も、教えて頂いたwebのpdfで確認できず、
メーカー次第で悲しいですが、私の希望はかなわないのかもしれません。
月曜以降に少し期待しています。
その際は、また報告します。
大変ありがとうございます。
投稿者 snowmansnow  (社会人)
投稿日時
2021/7/3 12:14:46
こんにちは、るきお様
月曜から体調不良で、昨日やっと確認できました。
WMIでプリンタの一覧とポートNOを取得してから、
GetBinListで、値を取得してみました。
複合機のA社の標準複合機ドライバのものは、エラーになり、BinListを取得できませんでしたが、
他の会社は、BinListを取得できました。
トレイ数と、BinList数は一致しておりました。
トレイ種類と、BinListを比較したかったのですが、
GetBinListでは、数字のみで紙サイズがわからず、一致を確認できませんでした。
VBNETでPaperSizeを取得した時も、APIは数字だけのものが多く、VBNETではサイズ表示をしていたので、
VBNETでBinListを取得できたら、サイズも確認できるのでは?と思っております。
複合機のA社の一部の標準複合機のプリンタドライバのものは、BinListを取得できてるようでした。
複合機のA社の標準複合機ドライバのものも、VBNETでは、エラーにならないのかな?と思っております。
APIのトレイ数字の一覧と、PaperSizeの一覧のようなものは、あるのでしょうか?
もしあったら見てみたいです。
月曜から体調不良で、昨日やっと確認できました。
WMIでプリンタの一覧とポートNOを取得してから、
GetBinListで、値を取得してみました。
複合機のA社の標準複合機ドライバのものは、エラーになり、BinListを取得できませんでしたが、
他の会社は、BinListを取得できました。
トレイ数と、BinList数は一致しておりました。
トレイ種類と、BinListを比較したかったのですが、
GetBinListでは、数字のみで紙サイズがわからず、一致を確認できませんでした。
VBNETでPaperSizeを取得した時も、APIは数字だけのものが多く、VBNETではサイズ表示をしていたので、
VBNETでBinListを取得できたら、サイズも確認できるのでは?と思っております。
複合機のA社の一部の標準複合機のプリンタドライバのものは、BinListを取得できてるようでした。
複合機のA社の標準複合機ドライバのものも、VBNETでは、エラーにならないのかな?と思っております。
APIのトレイ数字の一覧と、PaperSizeの一覧のようなものは、あるのでしょうか?
もしあったら見てみたいです。
投稿者 snowmansnow  (社会人)
投稿日時
2021/7/3 22:10:28
こんばんは、るきお様、魔界の仮面弁士様
勘違いしてまして
PAPERSOURCEのROWKINDと
PAPERSIZEのROWKINDは、対応しておらず、
トレイのサイズはCUSTOM設定のWIDTHやHEIGHTから分からないと思われました。
仕方が無いのでプリンタ設定のダイアログの用紙トレイから取得しようと思いました。
でも、COMBOBOXのhWndと個数までは取得できたのですが、
用紙テキストを取得しようとすると、エクセルが落ちます。
以前に魔界の仮面弁士様が別のサイトで、
http://hanatyan.sakura.ne.jp/vb60bbs/wforum.cgi?mode=allread&no=15777
メモリの確保が大事とおっしゃってましたが、まだよく分かりません。
COLLECTIONの例で
http://nonsoft.la.coocan.jp/Win32Api/Win32ApiEnumWin.htmlや
るきお様のページも見たのですが、フォームでない別アプリが良くわかりませんでした。
何か対策やヒントございましたらお願いしたいです。
宜しくお願いします。
勘違いしてまして
PAPERSOURCEのROWKINDと
PAPERSIZEのROWKINDは、対応しておらず、
トレイのサイズはCUSTOM設定のWIDTHやHEIGHTから分からないと思われました。
仕方が無いのでプリンタ設定のダイアログの用紙トレイから取得しようと思いました。
でも、COMBOBOXのhWndと個数までは取得できたのですが、
用紙テキストを取得しようとすると、エクセルが落ちます。
Private Function MyGetComboBoxItem(hWnd As Long) As String
'
' コンボボックス文字列取得
'http://mt-soft.sakura.ne.jp/web_dl/vb-parts/get_combobox/
Dim strItemData As String * 4096 '取得文字列格納用バッファ
Dim lngRc As Long
Dim Cnt As Long
Dim i As Long
Dim Dt As String
Dim p As Long
Cnt = SendMessage(hWnd, CB_GETCOUNT, 0, CLng(0)) '個数取得
Dt = ""
For i = 0 To Cnt - 1
MsgBox "ここ1"
lngRc = SendMessage(hWnd, CB_GETLBTEXT, i, strItemData) '文字列取得
MsgBox "ここ2"
p = InStr(strItemData, vbNullChar) - 1 '文字列長
If p >= 0 Then Dt = Dt & Left(strItemData, p)
Dt = Dt & vbCrLf
Next i
MyGetComboBoxItem = Dt
End Function
以前に魔界の仮面弁士様が別のサイトで、
http://hanatyan.sakura.ne.jp/vb60bbs/wforum.cgi?mode=allread&no=15777
メモリの確保が大事とおっしゃってましたが、まだよく分かりません。
COLLECTIONの例で
http://nonsoft.la.coocan.jp/Win32Api/Win32ApiEnumWin.htmlや
るきお様のページも見たのですが、フォームでない別アプリが良くわかりませんでした。
何か対策やヒントございましたらお願いしたいです。
宜しくお願いします。
投稿者 snowmansnow  (社会人)
投稿日時
2021/7/4 07:51:13
おはようございます るきお様、魔界の仮面弁士様
http://nonsoft.la.coocan.jp/Win32Api/Win32ApiEnumWin.html様の
function GetStatusBarTextの例を
コンボボックスに変えたつもりですが、
'共有メモリ初期化の lngRet = WriteProcessMemory(~)の戻り値が0になっています。
その後のsendmessage以前にダメなようでした。
それ以前は動いているようでした。
メモリ関係が良くわかりません・・・
何か良い対策は、ございますでしょうか?
よろしくお願いします。
http://nonsoft.la.coocan.jp/Win32Api/Win32ApiEnumWin.html様の
function GetStatusBarTextの例を
コンボボックスに変えたつもりですが、
'共有メモリ初期化の lngRet = WriteProcessMemory(~)の戻り値が0になっています。
その後のsendmessage以前にダメなようでした。
それ以前は動いているようでした。
メモリ関係が良くわかりません・・・
何か良い対策は、ございますでしょうか?
よろしくお願いします。
投稿者 snowmansnow  (社会人)
投稿日時
2021/7/4 10:40:39
こんにちは、るきお様、魔界の仮面弁士様
VBAで解決できなくて、C#のフォームアプリケーション、クラスライブラリで取得してみました。
お騒がせしましたが、また宜しくお願いします。
(過去webとかも、もう少し調べてから御質問します)
もし、別途VBAで教えていただければ、とても有難いです。
VBAで解決できなくて、C#のフォームアプリケーション、クラスライブラリで取得してみました。
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing.Printing;
namespace WindowsFormsAppPrinterCLCS
{
[Guid(GetPrinter.ClassId)]
public class GetPrinter
{
// COM用のGUID値
public const string ClassId = "F0C14F0A-20B3-4716-AF7E-21458B1219D4";
//SendMessage(データ転送)
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(int hWnd, int Msg, int wParam, StringBuilder lParam);
//SendMessage(データ転送)
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(int hWnd, int Msg, int wParam, int lParam);
const int CB_GETLBTEXT = 0x0148;
const int CB_GETCOUNT = 0x0146;
const int CB_GETLBTEXTLEN = 0x0149;
public string GetSource(string pn)
{
string lineAll = "";
PrintDocument printDoc = new PrintDocument();
PaperSource pkSource = new PaperSource();
printDoc.PrinterSettings.PrinterName = pn;
for (int i = 0; i <= printDoc.PrinterSettings.PaperSources.Count - 1; i++)
{
pkSource = printDoc.PrinterSettings.PaperSources[i];
lineAll += "," + i + ":" + pkSource.Kind + ":"+ pkSource.RawKind + ":" + pkSource.SourceName + Environment.NewLine;
}
return lineAll;
}
public string GetPaperHeightWidth(string printername,string customname)
{
string lineAll = "";
PrinterSettings settings = new PrinterSettings();
foreach (PaperSize size in settings.PaperSizes)
{
lineAll += "," + size.Kind + ":" + size.RawKind + ":" + size.PaperName + ":" + size.Height + ":" + size.Width + Environment.NewLine;
}
return lineAll;
}
public string GetComboText(int cbHandle, int i)
{
//https://bytes.com/topic/c-sharp/answers/831658-getting-setting-edititem-combobox-using-sendmessage
StringBuilder ssb = new StringBuilder(256, 256);
SendMessage(cbHandle, CB_GETLBTEXT, i, ssb);
return ssb.ToString();
}
public int GetComboCount(int cbHandle)
{
int CBcount = SendMessage(cbHandle, CB_GETCOUNT, 0, 0);
return CBcount;
}
}
}
お騒がせしましたが、また宜しくお願いします。
(過去webとかも、もう少し調べてから御質問します)
もし、別途VBAで教えていただければ、とても有難いです。
PRINTERの用紙についてお聞きしたいです。
普段は、複数種類の複合機や、
PDFプリンターをプリンターとして利用する事が多いです。
Windowsの設定の、プリンターのキューを開いてプロパティを開くと
全般タブの、機能の中に「利用可能な用紙:」というボックスがあります。
ここに表示される用紙の一覧(1種類から4種類くらい)をVBAなどで取得する事は可能でしょうか?
POWERSHELLのTRAY一覧や(用紙サイズがわからない)
VBNETのPaperSize一覧(ものすごい種類の用紙が取得される)
とも違うのでは?と思っています。
複合機のトレイ設定数・内容と合致する事や、相違する事(トレイの一部のみ表示)
があるみたいでした。
①この「利用可能な用紙:」一覧の用紙の意味が知りたいのと、
②この一覧の取得や、
③できれば、複合機での、手差しトレイでない、
標準的なトレイ一覧が取得できるといいなぁと思っています。
④「利用可能な用紙:」の下の「基本設定」ボタンを押した後で出てくる
ダイアログの、「用紙サイズ」との違いがあれば知りたいです。
⑤VBNETのPaperSize一覧の用紙の意味も知りたいです。
⑥POWERSHELLの、set可能なPaperSizeの意味と、①や④との対応も知りたいです。
POWERSHELLでPaperSizeをsetしても、①や④のダイアログには影響しないようですし、
でも、プリンタによってはsetを受け付けないPaperSizeもあるようでした。
windows10 64bit powershell7
https://www.koskila.net/how-to-change-printer-paper-size-using-powershell/
⑦意味がわかり、一覧の取得ができましたら、VBAなどで、それぞれに影響する用紙設定も教えて欲しいです。
APIの例もエラーになってしまい、何の用紙を取得できてるのか、実行結果を確認できませんでした。
https://docs.microsoft.com/ja-jp/office/vba/access/concepts/printing/programmatically-retrieve-printer-capabilities
できればVBAで、またはVBNETやPOWERSHELLでもよろしいので、教えて頂ける方お願いします。
Excel2016の32bitでも64bitでもよろしいです。
APIやVBNETやPOWERSHELLの説明を見たり、少し実行してみてもわからず、よろしくお願いします