WNDCLASS

WNDCLASSは、どういうウィンドウなのかという属性を決めるもの(他にも決めるものはあるんだけど)で、これを登録することで、ある程度の雛形が出来る。

WNDCLASSA (winuser.h) - Win32 apps | Microsoft Docs

今回は、クライアント領域に独自のウィンドウクラスの子ウィンドウをつくる。
色がライトグレーってだけなんだけど。

ウィンドウプロシージャも2つ作っておく。
1個でも出来ると思ったけど、同じウィンドウプロシージャのWM_CREATEを繰り返してしまうバグをつくってしまったので、分けた。

登録は2つともやっておく。
子のほうは背景を淡灰色ブラシに。
作成はここでは親だけ。

子ウィンドウの作成。

子のウィンドウプロシージャはすべてDefWindowProc。

ライトグレーの部分が子ウィンドウ
ライトグレーの部分が子ウィンドウ

ライトグレーの部分が子ウィンドウ。

Sample/winapi/WNDCLASS/WNDCLASS/src/WNDCLASS at master · bg1bgst333/Sample · GitHub

PRINTER_DEFAULTS

PRINTER_DEFAULTSも、プリンタの設定の一つだが、特に気になるのはアクセス属性。

PRINTER_DEFAULTS structure (Winspool.h) - Win32 apps | Microsoft Docs

前回、設定変更で、pd.DesiredAccessをPRINTER_ALL_ACCESSにしたけど、常にそれでいいのではとおもうかもしれない。
しかし、

PageSetup(ページ設定コモンダイアログ)

ここでは、PRINTER_ALL_ACCESSで失敗する例を示している。

					// 取得したIDごとに処理を分岐.
					// Printが選択された時.
					case ID_ITEM_PRINT:

						// ID_ITEM_PRINTブロック
						{

							// 変数の宣言と初期化.
							PAGESETUPDLG psd = {0};	// PAGESETUPDLG構造体psdを0で初期化.
							DEVMODE *pDevMode = NULL;	// DEVMODE構造体ポインタpDevModeをNULLで初期化.
							PRINTER_DEFAULTS pd = {0};	// PRINTER_DEFAULTS構造体pdを{0}で初期化.
							BOOL bRet = FALSE;	// BOOL型bRetをFALSEで初期化.
							HANDLE hPrinter = NULL;	// HANDLE型hPrinterをNULLで初期化.

							// psdの初期設定
							psd.lStructSize = sizeof(PAGESETUPDLG);	// sizeofでPAGESETUPDLG構造体のサイズを指定.
							psd.hwndOwner = hwnd;		// hwndを指定.
							psd.Flags = PSD_INHUNDREDTHSOFMILLIMETERS;	// ミリ単位に設定.

							// PageSetupDlgの表示.
							bRet = PageSetupDlg(&psd);	// PageSetupDlgにpsdを渡して表示し, 戻り値をbRetに格納.
							if (bRet){	// TRUEの時.
								pDevMode = (DEVMODE *)GlobalLock(psd.hDevMode);	// psd.hDevModeをロック.
								if (pDevMode != NULL){	// pDevModeがNULLでない時.
									pd.DesiredAccess = PRINTER_ALL_ACCESS;	// 全ての権限.
									bRet = OpenPrinter(pDevMode->dmDeviceName, &hPrinter, &pd);	// OpenPrinterでプリンタを開く.
									if (bRet){	// TRUE.
										MessageBox(hwnd, _T("OpenPrinter OK!"), _T("PRINTER_DEFAULTS"), MB_OK);	// "OpenPrinter OK!"と表示.
										ClosePrinter(hPrinter);	// ClosePrinterで閉じる.
									}
									else{	// FALSE.
										MessageBox(hwnd, _T("OpenPrinter NG!"), _T("PRINTER_DEFAULTS"), MB_OK);	// "OpenPrinter NG!"と表示.
									}
									GlobalUnlock(psd.hDevMode);	// アンロック.
								}
							}

						}

						// 既定の処理へ向かう.
						break;	// breakで抜けて, 既定の処理(DefWindowProc)へ向かう.
NGになる
NGになる

NGになる。

PageSetupDlgの選択結果が、読み取り専用だからPRINTER_ALL_ACCESSはダメなのかな。(個人の感想)

PRINTER_ACCESS_USEにすると、

OKになる
OKになる

OKになる。
ただ、Windows10だと、PRINTER_ALL_ACCESSでもOKになる。
(7はFaxとXPS Document Writerのみ、10は実機プリンタありなので、それもあるかな・・・。)

Sample/winapi/PRINTER_DEFAULTS/PRINTER_DEFAULTS/src/PRINTER_DEFAULTS at master · bg1bgst333/Sample · GitHub

SetPrinter

SetPrinterで、プリンタの設定をする。

SetPrinter function (WinSpool.h) - Win32 apps | Microsoft Docs
https://support.microsoft.com/ja-jp/help/140285/how-to-modify-printer-settings-by-using-setprinter

これで、プリンタ設定の変更が完了する。

	// プリンタを開く.
	pd.DesiredAccess = PRINTER_ACCESS_USE;	// ユーザ権限.
	bOpen = OpenPrinter(ptszBuf, &hPrinter, &pd);	// OpenPrinterでプリンタ名ptszBufとなるプリンタを開く.(この時, pdを渡す.)
	if (bOpen){	// プリンタを開けたら.
		if (hPrinter != NULL){	// NULLではない.
			_tprintf(_T("hPrinter = 0x%08x\n"), (unsigned long)hPrinter);	// hPrinterの値を出力.
			// プリンタ情報(Level2)の取得.
			GetPrinter(hPrinter, 2, NULL, 0, &dwNeeded);	// まずはGetPrinterにNULLを渡してLevel2で必要なサイズを取得.
			_tprintf(_T("dwNeeded = %lu\n"), dwNeeded);	// dwNeededを出力.
			if (dwNeeded > 0){	// 0より大きい.
				// メモリの確保.
				hPrinterInfo2 = GlobalAlloc(GHND, dwNeeded);	// GlobalAllocでdwNeeded分メモリ確保.
				if (hPrinterInfo2 != NULL){	// 確保成功.
					// メモリのロック.
					pi2 = (PRINTER_INFO_2 *)GlobalLock(hPrinterInfo2);	// GlobalLockでロックしてポインタを取得.
					if (pi2 != NULL){	// NULLでなければ.
						// プリンタ情報の取得.
						bRet = GetPrinter(hPrinter, 2, (LPBYTE)pi2, dwNeeded, &dwNeeded);	// GetPrinterでpi2を取得.
						if (bRet){	// TRUEなら.
							if (pi2->pDevMode != NULL){	// DEVMODEへのポインタがあれば.
								_tprintf(_T("GetPrinter Get OK!\n"));	// "GetPrinter Get OK!"と出力.
								// さまざまな情報を出力.
								_tprintf(_T("pi2->pDevMode->dmDeviceName = %s\n"), pi2->pDevMode->dmDeviceName);	// pi2->pDevMode->dmDeviceNameを出力.
								_tprintf(_T("pi2->pPrinterName = %s\n"), pi2->pPrinterName);	// pi2->pPrinterNameを出力.
								_tprintf(_T("pi2->pPortName = %s\n"), pi2->pPortName);	// pi2->pPortNameを出力.
								_tprintf(_T("pi2->pDriverName = %s\n"), pi2->pDriverName);	// pi2->pDriverNameを出力.
								_tprintf(_T("pi2->pPrintProcessor = %s\n"), pi2->pPrintProcessor);	// pi2->pPrintProcessorを出力.
								_tprintf(_T("pi2->pDatatype = %s\n"), pi2->pDatatype);	// pi2->pDatatypeを出力.
								// 印刷方向を横にする.
								pi2->pDevMode->dmFields = DM_ORIENTATION;	// 方向を設定.
								pi2->pDevMode->dmOrientation = DMORIENT_LANDSCAPE;	// 横に設定.
								lFlag = DocumentProperties(NULL, hPrinter, ptszBuf, pi2->pDevMode, pi2->pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER);	// DocumentPropertiesでデバイス依存部分のアップデート.
								if (lFlag == IDOK){	// IDOKなら.
									_tprintf(_T("DocumentProperties Update OK!\n"));	// "DocumentProperties Update OK!"と出力.
									lFlag = SetPrinter(hPrinter, 2, (LPBYTE)pi2, 0);	// SetPrinterで更新した設定をプリンタに反映.
									if (lFlag > 0){	// 0以上.
										_tprintf(_T("SetPrinter OK!\n"));	// "SetPrinter OK!"を出力.
									}
									else{	// 負の値.
										DWORD e = GetLastError();	// GetLstErrorでエラー番号取得.
										_tprintf(_T("SetPrinter NG! e = %lu\n"), e);	// "SetPrinter NG!"とエラー番号を出力.
									}
								}
							}

SetPrinterしてみると、

C:\Users\bg1\Documents\test>SetPrinter.exe
Default Printer: EPSON PX-S06 Series
hPrinter = 0x00453b2c
dwNeeded = 8944
GetPrinter Get OK!
pi2->pDevMode->dmDeviceName = EPSON PX-S06 Series
pi2->pPrinterName = EPSON PX-S06 Series
pi2->pPortName = USB001
pi2->pDriverName = EPSON PX-S06 Series
pi2->pPrintProcessor = winprint
pi2->pDatatype = RAW
DocumentProperties Update OK!
SetPrinter NG! e = 5

C:\Users\bg1\Documents\test>

Win32エラーコード一覧

5は『アクセスが拒否されました。』となっている。

でも設定は変わっている
でも設定は変わっている

でも設定は変わっている。

	// プリンタを開く.
	//pd.DesiredAccess = PRINTER_ACCESS_USE;	// ユーザ権限.
	pd.DesiredAccess = PRINTER_ALL_ACCESS;	// 全ての権限.
	bOpen = OpenPrinter(ptszBuf, &hPrinter, &pd);	// OpenPrinterでプリンタ名ptszBufとなるプリンタを開く.(この時, pdを渡す.)
	if (bOpen){	// プリンタを開けたら.
		if (hPrinter != NULL){	// NULLではない.
			_tprintf(_T("hPrinter = 0x%08x\n"), (unsigned long)hPrinter);	// hPrinterの値を出力.
			// プリンタ情報(Level2)の取得.
			GetPrinter(hPrinter, 2, NULL, 0, &dwNeeded);	// まずはGetPrinterにNULLを渡してLevel2で必要なサイズを取得.
			_tprintf(_T("dwNeeded = %lu\n"), dwNeeded);	// dwNeededを出力.
			if (dwNeeded > 0){	// 0より大きい.
				// メモリの確保.
				hPrinterInfo2 = GlobalAlloc(GHND, dwNeeded);	// GlobalAllocでdwNeeded分メモリ確保.
				if (hPrinterInfo2 != NULL){	// 確保成功.
					// メモリのロック.
					pi2 = (PRINTER_INFO_2 *)GlobalLock(hPrinterInfo2);	// GlobalLockでロックしてポインタを取得.
					if (pi2 != NULL){	// NULLでなければ.
						// プリンタ情報の取得.
						bRet = GetPrinter(hPrinter, 2, (LPBYTE)pi2, dwNeeded, &dwNeeded);	// GetPrinterでpi2を取得.
						if (bRet){	// TRUEなら.
							if (pi2->pDevMode != NULL){	// DEVMODEへのポインタがあれば.
								_tprintf(_T("GetPrinter Get OK!\n"));	// "GetPrinter Get OK!"と出力.
								// さまざまな情報を出力.
								_tprintf(_T("pi2->pDevMode->dmDeviceName = %s\n"), pi2->pDevMode->dmDeviceName);	// pi2->pDevMode->dmDeviceNameを出力.
								_tprintf(_T("pi2->pPrinterName = %s\n"), pi2->pPrinterName);	// pi2->pPrinterNameを出力.
								_tprintf(_T("pi2->pPortName = %s\n"), pi2->pPortName);	// pi2->pPortNameを出力.
								_tprintf(_T("pi2->pDriverName = %s\n"), pi2->pDriverName);	// pi2->pDriverNameを出力.
								_tprintf(_T("pi2->pPrintProcessor = %s\n"), pi2->pPrintProcessor);	// pi2->pPrintProcessorを出力.
								_tprintf(_T("pi2->pDatatype = %s\n"), pi2->pDatatype);	// pi2->pDatatypeを出力.
								// 印刷方向を横にする.
								pi2->pDevMode->dmFields = DM_ORIENTATION;	// 方向を設定.
								pi2->pDevMode->dmOrientation = DMORIENT_LANDSCAPE;	// 横に設定.
								lFlag = DocumentProperties(NULL, hPrinter, ptszBuf, pi2->pDevMode, pi2->pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER);	// DocumentPropertiesでデバイス依存部分のアップデート.
								if (lFlag == IDOK){	// IDOKなら.
									_tprintf(_T("DocumentProperties Update OK!\n"));	// "DocumentProperties Update OK!"と出力.
									lFlag = SetPrinter(hPrinter, 2, (LPBYTE)pi2, 0);	// SetPrinterで更新した設定をプリンタに反映.
									if (lFlag > 0){	// 0以上.
										_tprintf(_T("SetPrinter OK!\n"));	// "SetPrinter OK!"を出力.
									}
									else{	// 負の値.
										DWORD e = GetLastError();	// GetLstErrorでエラー番号取得.
										_tprintf(_T("SetPrinter NG! e = %lu\n"), e);	// "SetPrinter NG!"とエラー番号を出力.
									}
								}
							}

pd.DesiredAccessを、PRINTER_ACCESS_USEから、PRINTER_ALL_ACCESSに変更。
変更はこちらにするべきだったかな。

C:\Users\bg1\Documents\test>SetPrinter.exe
Default Printer: EPSON PX-S06 Series
hPrinter = 0x0061c134
dwNeeded = 17144
GetPrinter Get OK!
pi2->pDevMode->dmDeviceName = EPSON PX-S06 Series
pi2->pPrinterName = EPSON PX-S06 Series
pi2->pPortName = USB001
pi2->pDriverName = EPSON PX-S06 Series
pi2->pPrintProcessor = winprint
pi2->pDatatype = RAW
DocumentProperties Update OK!
SetPrinter NG! e = 87

C:\Users\bg1\Documents\test>

87は、『パラメータが間違っています。』である。
なんでだろう・・・。

オフラインだったので接続してオンラインにした
オフラインだったので接続してオンラインにした

実はここまでオフラインだったので接続してオンラインにした。

C:\Users\bg1\Documents\test>SetPrinter.exe
Default Printer: EPSON PX-S06 Series
hPrinter = 0x0057cc24
dwNeeded = 17144
GetPrinter Get OK!
pi2->pDevMode->dmDeviceName = EPSON PX-S06 Series
pi2->pPrinterName = EPSON PX-S06 Series
pi2->pPortName = USB001
pi2->pDriverName = EPSON PX-S06 Series
pi2->pPrintProcessor = winprint
pi2->pDatatype = RAW
DocumentProperties Update OK!
SetPrinter OK!

C:\Users\bg1\Documents\test>

あれ、成功・・・。
オフラインの状態じゃダメなのか・・・。
というわけで、設定変更と印刷を同時に。

// ヘッダファイルのインクルード
#include <windows.h>	// 標準WindowsAPI
#include <tchar.h>		// TCHAR型
#include <shlwapi.h>	// シェルAPI

// _tmain関数の定義
int _tmain(int argc, TCHAR *argv[]){	// main関数のTCHAR版.

	// 変数の宣言と初期化.
	TCHAR tszModulePath[MAX_PATH] = {0};	// tszModulePath(長さMAX_PATH)を{0}で初期化.
	HANDLE hFile = NULL;	// HANDLE型ファイルハンドルhFileをNULLで初期化.
	DWORD dwFileSize = 0;	// ファイルサイズdwFileSizeを0で初期化.
	BYTE *pBytes = NULL;	// BYTE動的配列ポインタpBytesをNULLで初期化.
	DWORD dwSize = 0;	// サイズdwSizeを0で初期化.
	TCHAR *ptszBuf = NULL;	// 文字列バッファポインタptszBufをNULLで初期化.
	BOOL bOpen = FALSE;	// BOOL型のbOpenをFALSEで初期化.
	HANDLE hPrinter = NULL;	// HANDLE型hPrinterをNULLで初期化.
	PRINTER_DEFAULTS pd = {0};	// PRINTER_DEFAULTS構造体pdを{0}で初期化.
	DWORD dwNeeded = 0;	// DWORD型dwNeededを0で初期化.
	HGLOBAL hPrinterInfo2 = NULL;	// HGLOBAL型hPrinterInfo2をNULLで初期化.
	PRINTER_INFO_2 *pi2 = NULL;	// PRINTER_INFO_2構造体ポインタpi2をNULLで初期化.
	BOOL bRet = FALSE;	// BOOL型bRetをFALSEで初期化.
	TCHAR tszDMDeviceName[CCHDEVICENAME + 64] = {0};	// tszDMDeviceNameを{0}で初期化.(サイズはCCHDEVICENAME + 64.)
	LONG lFlag = 0;	// LONG型lFlagを0で初期化.
	HGLOBAL hDevMode = NULL;	// HGLOBAL型hDevModeをNULLで初期化.
	DOC_INFO_1 di1 = {0};	// DOC_INFO_1構造体di1を{0}で初期化.
	DWORD dwJob = 0;	// DWORD型dwJobを0で初期化.
	BOOL bPage = FALSE;	// BOOL型のbPageをFALSEで初期化.
	BOOL bWrite = FALSE;	// BOOL型のbWriteをFALSEで初期化.
	DWORD dwWritten = 0;	// DWORD型のdwWrittenを0で初期化.

	// test_text.txtのパスを生成.
	GetModuleFileName(NULL, tszModulePath, MAX_PATH);	// GetModuleFileNameでこの実行ファイルのフルパスを取得.
	PathRemoveFileSpec(tszModulePath);	// PathRemoveFileSpecでファイル名の部分を取り除く.
	_tcscat(tszModulePath, _T("\\test_text.txt"));	// _tcscatで"\test_text.txt"を連結.
	_tprintf(_T("tszModulePath = %s\n"), tszModulePath);	// tszModulePathを出力.

	// test_text.txtの読み込み.
	hFile = CreateFile(tszModulePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);	// CreateFileでtszModulePathを開いて, 取得したハンドルをhFileに格納.
	if (hFile == INVALID_HANDLE_VALUE){	// hFileがINVALID_HANDLE_VALUEなら.
		_tprintf(_T("test_text.txt not found.\n"));	// "test_text.txt not found."を出力.
		return -1;	// -1を返して異常終了.
	}
	dwFileSize = GetFileSize(hFile, NULL);	// GetFileSizeで"test_text.txt"のファイルサイズを取得する.
	_tprintf(_T("dwFileSize = %lu\n"), dwFileSize);	// dwFileSizeの出力.
	pBytes = new BYTE[dwFileSize];	// BYTE配列を確保.
	ReadFile(hFile, pBytes, dwFileSize, &dwFileSize, NULL);	// ReadFileでhFileの内容をpBytesに読み込む.
	CloseHandle(hFile);	// CloseHandleでhFileを閉じる.

	// バッファサイズを取得.
	GetDefaultPrinter(NULL, &dwSize);	// GetDefaultPrinterにNULLを渡してバッファサイズを取得.

	// バッファの確保.
	ptszBuf = new TCHAR[dwSize];	// サイズdwSize分のバッファ確保.

	// 既定のプリンタ名を取得.
	GetDefaultPrinter(ptszBuf, &dwSize);	// GetDefaultPrinterでプリンタ名を取得し, バッファに格納.

	// 既定のプリンタ名の出力.
	_tprintf(_T("Default Printer: %s\n"), ptszBuf);	// ptszBufを出力.

	// プリンタを開く.
	//pd.DesiredAccess = PRINTER_ACCESS_USE;	// ユーザ権限.
	pd.DesiredAccess = PRINTER_ALL_ACCESS;	// 全ての権限.
	bOpen = OpenPrinter(ptszBuf, &hPrinter, &pd);	// OpenPrinterでプリンタ名ptszBufとなるプリンタを開く.(この時, pdを渡す.)
	if (bOpen){	// プリンタを開けたら.
		if (hPrinter != NULL){	// NULLではない.
			_tprintf(_T("hPrinter = 0x%08x\n"), (unsigned long)hPrinter);	// hPrinterの値を出力.
			// プリンタ情報(Level2)の取得.
			GetPrinter(hPrinter, 2, NULL, 0, &dwNeeded);	// まずはGetPrinterにNULLを渡してLevel2で必要なサイズを取得.
			_tprintf(_T("dwNeeded = %lu\n"), dwNeeded);	// dwNeededを出力.
			if (dwNeeded > 0){	// 0より大きい.
				// メモリの確保.
				hPrinterInfo2 = GlobalAlloc(GHND, dwNeeded);	// GlobalAllocでdwNeeded分メモリ確保.
				if (hPrinterInfo2 != NULL){	// 確保成功.
					// メモリのロック.
					pi2 = (PRINTER_INFO_2 *)GlobalLock(hPrinterInfo2);	// GlobalLockでロックしてポインタを取得.
					if (pi2 != NULL){	// NULLでなければ.
						// プリンタ情報の取得.
						bRet = GetPrinter(hPrinter, 2, (LPBYTE)pi2, dwNeeded, &dwNeeded);	// GetPrinterでpi2を取得.
						if (bRet){	// TRUEなら.
							if (pi2->pDevMode != NULL){	// DEVMODEへのポインタがあれば.
								_tprintf(_T("GetPrinter Get OK!\n"));	// "GetPrinter Get OK!"と出力.
								// さまざまな情報を出力.
								_tprintf(_T("pi2->pDevMode->dmDeviceName = %s\n"), pi2->pDevMode->dmDeviceName);	// pi2->pDevMode->dmDeviceNameを出力.
								_tprintf(_T("pi2->pPrinterName = %s\n"), pi2->pPrinterName);	// pi2->pPrinterNameを出力.
								_tprintf(_T("pi2->pPortName = %s\n"), pi2->pPortName);	// pi2->pPortNameを出力.
								_tprintf(_T("pi2->pDriverName = %s\n"), pi2->pDriverName);	// pi2->pDriverNameを出力.
								_tprintf(_T("pi2->pPrintProcessor = %s\n"), pi2->pPrintProcessor);	// pi2->pPrintProcessorを出力.
								_tprintf(_T("pi2->pDatatype = %s\n"), pi2->pDatatype);	// pi2->pDatatypeを出力.
								// 印刷方向を横にする.
								pi2->pDevMode->dmFields = DM_ORIENTATION;	// 方向を設定.
								pi2->pDevMode->dmOrientation = DMORIENT_LANDSCAPE;	// 横に設定.
								lFlag = DocumentProperties(NULL, hPrinter, ptszBuf, pi2->pDevMode, pi2->pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER);	// DocumentPropertiesでデバイス依存部分のアップデート.
								if (lFlag == IDOK){	// IDOKなら.
									_tprintf(_T("DocumentProperties Update OK!\n"));	// "DocumentProperties Update OK!"と出力.
									lFlag = SetPrinter(hPrinter, 2, (LPBYTE)pi2, 0);	// SetPrinterで更新した設定をプリンタに反映.
									if (lFlag > 0){	// 0以上.
										_tprintf(_T("SetPrinter OK!\n"));	// "SetPrinter OK!"を出力.
										// di1の設定.
										di1.pDocName = _T("StartPagePrinter");	// ドキュメント名は"StartPagePrinter".
										di1.pOutputFile = NULL;	// 出力ファイルはひとまずNULL.
										di1.pDatatype = _T("TEXT");	// "TEXT"モードにしてみる.
										// ドキュメントの開始.
										dwJob = StartDocPrinter(hPrinter, 1, (LPBYTE)&di1);	// StartDocPrinterでドキュメント開始, dwJobを取得.
										if (dwJob > 0){	// 0より大きいなら成功.
											_tprintf(_T("dwJob = %lu\n"), dwJob);	// dwJobを出力.
											// ページの開始.
											bPage = StartPagePrinter(hPrinter);	// StartPagePrinterでページの開始.
											if (bPage){	// TRUEなら成功.
												bWrite = WritePrinter(hPrinter, pBytes, dwFileSize, &dwWritten);	// WritePrinterで書き込み.
												if (bWrite){	// TRUEなら成功.
													_tprintf(_T("dwFileSize = %lu\n"), dwFileSize);	// dwFileSizeを出力.
													_tprintf(_T("dwWritten = %lu\n"), dwWritten);	// dwWrittenを出力.
												}
												EndPagePrinter(hPrinter);	// EndPagePrinterでページの終了.
											}
											EndDocPrinter(hPrinter);	// ドキュメントの終了.
										}
									}
									else{	// 負の値.
										DWORD e = GetLastError();	// GetLstErrorでエラー番号取得.
										_tprintf(_T("SetPrinter NG! e = %lu\n"), e);	// "SetPrinter NG!"とエラー番号を出力.
									}
								}
							}
							else{	// DEVMODEのポインタがNULLの時.
								_tprintf(_T("pi2->pDevMode == NULL!\n"));	// NULLであることを出力.
								// DocumentPropertiesで取得する方法.
								dwNeeded = DocumentProperties(NULL, hPrinter, ptszBuf, NULL, NULL, 0);	// まずサイズを取得.
								if (dwNeeded > 0){	// 0より大きい.
									hDevMode = GlobalAlloc(GHND, dwNeeded);	// dwNeeded分のメモリ確保.
									if (hDevMode != NULL){	// NULLでない時.
										pi2->pDevMode = (DEVMODE *)GlobalLock(hDevMode);	// pi2->pDevModeにロックしたメモリのポインタを格納.
										if (pi2->pDevMode != NULL){	// NULLでない.
											lFlag = DocumentProperties(NULL, hPrinter, ptszBuf, pi2->pDevMode, NULL, DM_OUT_BUFFER);	// DocumentPropertiesでDEVMODEを取得.
											if (lFlag == IDOK){	// IDOKなら.
												_tprintf(_T("DocumentProperties Get OK!\n"));	// "DocumentProperties Get OK!"と出力.
												// 印刷方向を横にする.
												pi2->pDevMode->dmFields = DM_ORIENTATION;	// 方向を設定.
												pi2->pDevMode->dmOrientation = DMORIENT_LANDSCAPE;	// 横に設定.
												lFlag = DocumentProperties(NULL, hPrinter, ptszBuf, pi2->pDevMode, pi2->pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER);	// DocumentPropertiesでデバイス依存部分のアップデート.
												if (lFlag == IDOK){	// IDOKなら.
													_tprintf(_T("DocumentProperties Update OK!\n"));	// "DocumentProperties Update OK!"と出力.
													lFlag = SetPrinter(hPrinter, 2, (LPBYTE)pi2, 0);	// SetPrinterで更新した設定をプリンタに反映.
													if (lFlag > 0){	// 0より大きい.
														_tprintf(_T("SetPrinter OK!\n"));	// "SetPrinter OK!"を出力.
														// di1の設定.
														di1.pDocName = _T("StartPagePrinter");	// ドキュメント名は"StartPagePrinter".
														di1.pOutputFile = NULL;	// 出力ファイルはひとまずNULL.
														di1.pDatatype = _T("TEXT");	// "TEXT"モードにしてみる.
														// ドキュメントの開始.
														dwJob = StartDocPrinter(hPrinter, 1, (LPBYTE)&di1);	// StartDocPrinterでドキュメント開始, dwJobを取得.
														if (dwJob > 0){	// 0より大きいなら成功.
															_tprintf(_T("dwJob = %lu\n"), dwJob);	// dwJobを出力.
															// ページの開始.
															bPage = StartPagePrinter(hPrinter);	// StartPagePrinterでページの開始.
															if (bPage){	// TRUEなら成功.
																bWrite = WritePrinter(hPrinter, pBytes, dwFileSize, &dwWritten);	// WritePrinterで書き込み.
																if (bWrite){	// TRUEなら成功.
																	_tprintf(_T("dwFileSize = %lu\n"), dwFileSize);	// dwFileSizeを出力.
																	_tprintf(_T("dwWritten = %lu\n"), dwWritten);	// dwWrittenを出力.
																}
																EndPagePrinter(hPrinter);	// EndPagePrinterでページの終了.
															}
															EndDocPrinter(hPrinter);	// ドキュメントの終了.
														}
													}
													else{	// 負の値.
														DWORD e = GetLastError();	// GetLstErrorでエラー番号取得.
														_tprintf(_T("SetPrinter NG! e = %lu\n"), e);	// "SetPrinter NG!"とエラー番号を出力.
													}
												}
											}
											GlobalUnlock(hDevMode);	// アンロック.
										}
										GlobalFree(hDevMode);	// 解放.
									}
								}
							}
						}
						GlobalUnlock(hPrinterInfo2);	// アンロック.
					}
					GlobalFree(hPrinterInfo2);	// 解放.
				}
			}
			ClosePrinter(hPrinter);	// ClosePrinterでhPrinterを閉じる.
		}
	}

	// バッファの解放.
	delete[] ptszBuf;	// ptszBufの解放.
	delete[] ptszBuf;	// ptszBufの解放.

	// プログラムの終了.
	return 0;

}

これだと、

縦のまま
縦のまま

縦のまま・・・。
ハンドル閉じてないから、設定変更が、印刷に反映されない。

こうすると、

C:\Users\bg1\Documents\test>SetPrinter.exe
tszModulePath = C:\Users\bg1\Documents\test\test_text.txt
dwFileSize = 8562
Default Printer: EPSON PX-S06 Series
hPrinter = 0x005cb76c
dwNeeded = 17144
GetPrinter Get OK!
pi2->pDevMode->dmDeviceName = EPSON PX-S06 Series
pi2->pPrinterName = EPSON PX-S06 Series
pi2->pPortName = USB001
pi2->pDriverName = EPSON PX-S06 Series
pi2->pPrintProcessor = winprint
pi2->pDatatype = RAW
DocumentProperties Update OK!
SetPrinter OK!
hPrinter = 0x005cb76c
dwJob = 4
dwFileSize = 8562
dwWritten = 8562

C:\Users\bg1\Documents\test>

で、

横に設定変更されて印刷もできた
横に設定変更されて印刷もできた

横に設定変更されて印刷もできた。

Sample/winapi/SetPrinter/SetPrinter/src/SetPrinter at master · bg1bgst333/Sample · GitHub

DocumentProperties

DocumentPropertiesは、プリンタ情報の取得、変更、プリンタ構成プロパティシートの表示、とあるけど、よくあるのは、あるプリンタの設定を変更した時に、依存している部分の設定も更新するということらしい。

DocumentProperties function (Winspool.h) - Win32 apps | Microsoft Docs

実行すると、

C:\Users\bg1\Documents\test>DocumentProperties.exe
Default Printer: EPSON PX-S06 Series
hPrinter = 0x00553c0c
dwNeeded = 8944
GetPrinter Get OK!
pi2->pDevMode->dmDeviceName = EPSON PX-S06 Series
pi2->pPrinterName = EPSON PX-S06 Series
pi2->pPortName = USB001
pi2->pDriverName = EPSON PX-S06 Series
pi2->pPrintProcessor = winprint
pi2->pDatatype = RAW
DocumentProperties Update OK!

C:\Users\bg1\Documents\test>

更新されたらしい。
ただ、この時点ではまだプリンタの設定が変わったわけではない。
ここまではまだ準備段階。

まだ縦のまま
まだ縦のまま

まだ縦のまま。

Sample/winapi/DocumentProperties/DocumentProperties/src/DocumentProperties at master · bg1bgst333/Sample · GitHub

PRINTER_INFO_2

PRINTER_INFO_2は、PRINTER_INFO_1より詳細なプリンタ情報を持っている。

PRINTER_INFO_2 structure (Winspool.h) - Win32 apps | Microsoft Docs

わかりやすいものを出力してみた。

実行すると、

C:\Users\bg1\Documents\test>PRINTER_INFO_2.exe
Default Printer: EPSON PX-S06 Series
hPrinter = 0x004a35bc
dwNeeded = 8944
pi2->pDevMode->dmDeviceName = EPSON PX-S06 Series
pi2->pPrinterName = EPSON PX-S06 Series
pi2->pPortName = USB001
pi2->pDriverName = EPSON PX-S06 Series
pi2->pPrintProcessor = winprint
pi2->pDatatype = RAW

C:\Users\bg1\Documents\test>

わかりやすいのはこの辺かな。

Sample/winapi/PRINTER_INFO_2/PRINTER_INFO_2/src/PRINTER_INFO_2 at master · bg1bgst333/Sample · GitHub

GetPrinter

GetPrinterで、プリンタ情報を取得する。

GetPrinter function (Winspool.h) - Win32 apps | Microsoft Docs
https://support.microsoft.com/ja-jp/help/140285/how-to-modify-printer-settings-by-using-setprinter

プリンタの設定変更となると、DEVMODEが必要となり、プリンタ情報(Level2)の取得が必要となる。

GetPrinterにNULLを渡して必要なサイズを取得して、サイズ分GlobalAllocして、ハンドルをGlobalLockして、GetPrinterでPRINTER_INFO_2を取得。

C:\Users\bg1\Documents\test>GetPrinter.exe
Default Printer: EPSON PX-S06 Series
hPrinter = 0x005bb57c
dwNeeded = 8944
pi2->pDevMode->dmDeviceName = EPSON PX-S06 Series

C:\Users\bg1\Documents\test>

こうやってデバイス名を取得出来たりする。

Sample/winapi/GetPrinter/GetPrinter/src/GetPrinter at master · bg1bgst333/Sample · GitHub

StartPagePrinter

StartPagePrinterで、印刷するページの開始を通知する。

StartPagePrinter function (Winspool.h) - Win32 apps | Microsoft Docs

test_text.txtを、

2ページ分の量に増やした
2ページ分の量に増やした

2ページ分の量に増やした。
しかし、複数ページある場合、ページごとに複数回呼び出すのかと思いきや、試行錯誤した結果、複数ページ印刷でもWritePrinterの前に1回呼び出すだけで印刷できてしまった。

StartPagePrinterの後に、MessageBoxを挟んで、キューの状態を見ることにした。

メッセージボックスを表示
メッセージボックスを表示

メッセージボックスを表示して止める。

スプール中
スプール中

スプール中。

印刷中になる
印刷中になる

そこを抜けると、印刷中になる。

C:\Users\bg1\Documents\test>StartPagePrinter.exe
tszModulePath = C:\Users\bg1\Documents\test\test_text.txt
dwFileSize = 8562
Default Printer: EPSON PX-S06 Series
hPrinter = 0x004faaac
dwJob = 33
dwFileSize = 8562
dwWritten = 8562

C:\Users\bg1\Documents\test>

WritePrinterで、2ページ分バイナリデータを送ると、ページごとに分割されるわけではなく、まるまる書き込み成功となる。
なので2ページでもStartPagePrinterは1回で良さそう。
(今のところの設定とやり方では。)

2ページ印刷されてる
2ページ印刷されてる

2ページ印刷されてる。
いろいろネットでも調べたけど、複数ページ印刷で、StartPagePrinterをループで繰り返してる例は見当たらなかった。

Sample/winapi/StartPagePrinter/StartPagePrinter/src/StartPagePrinter at master · bg1bgst333/Sample · GitHub