DOBON.NET DOBON.NETプログラミング掲示板過去ログ

手差し印刷の指定方法について

分類:[その他]

みなさん、こんにちは。
いつも参考にさせていただいております。

 XPで、プリンタの手差しトレイを指定して印刷を行いたいのですが、どうも
うまくいかず、半年くらい悩み続けています。
下記のコードは、
マイクロソフト サポート技術情報 - 140285
http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/q140/2/85.asp&NoWebContent=1

を参考にしてVisualC 6.0で作ったものですが、用紙サイズ、方向、上下段の
トレイ指定はできるのに、手差し指定だけがうまくいきません。

プリンタは、Canon LBP406G2、Xerox(型番忘却)で行ってみました。
どなたか、解決方法をご存じでないでしょうか?


/**#function#**********************************************
#name      :: SetDevMode
#summary     :: プリンタ制御

int  nBin   :: 給紙トレイ
int  nSize   :: 用紙サイズ
int  nDir   :: 用紙方向
return DEVMODE* :: DEVMODEポインタ
**********************************************#function#***/
static DEVMODE *SetDevMode(int nBin, int nSize, int nDir)
{
  HANDLE hPrinter = NULL;
  DWORD dwNeeded = 0;
  DWORD dwDMSize = 0;
  PRINTER_INFO_2 *pi2 = NULL;
  DEVMODE *pDevMode = NULL;
  PRINTER_DEFAULTS pd;
  BOOL bFlag;
  LONG lFlag;

  // アクセス権設定
  memset(&pd, 0, sizeof(pd));
  pd.DesiredAccess = PRINTER_ALL_ACCESS;

  // プリンタオープン
  bFlag = OpenPrinter(szDevice, &hPrinter, &pd);
  if (!bFlag || (hPrinter == NULL)){
    MsgBox(NULL, MB_OK, "プリンタ(%s)情報を取得できません", szDevice);
    return(NULL);
  }

  // 情報格納サイズの取得
  SetLastError(0);
  bFlag = GetPrinter(hPrinter, 2, 0, 0, &dwNeeded);
  if ((!bFlag) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||
      (dwNeeded == 0)){
    ClosePrinter(hPrinter);
    MsgBox(NULL, MB_OK, "プリンタ情報格納サイズを取得できません");
    return(NULL);
  }

  // PRINTER_INFO_2 用メモリアロケート
  pi2 = (PRINTER_INFO_2 *)AllocMemory(dwNeeded);
  if (pi2 == NULL){
    ClosePrinter(hPrinter);
    MsgBox(NULL, MB_OK, "バッファ(%d)を確保できません", dwNeeded);
    return(NULL);
  }


  // PRINTER_INFO_2 情報格納
  bFlag = GetPrinter(hPrinter, 2, (LPBYTE)pi2, dwNeeded, &dwNeeded);
  if (bFlag != TRUE){
    FreeMemory(pi2);
    ClosePrinter(hPrinter);
    MsgBox(NULL, MB_OK, "プリンタ情報を取得できません");
    return(NULL);
  }

  // DENMODE バッファサイズ取得
  dwDMSize= DocumentProperties(NULL, hPrinter, szDevice,NULL, NULL, 0);
  if (dwDMSize <= 0){
    FreeMemory(pi2);
    ClosePrinter(hPrinter);
    MsgBox(NULL, MB_OK, "DocumentProperties() サイズ取得エラー");
    return(NULL);
  }

  // DEVMODE バッファ確保
  pDevMode = (DEVMODE *)AllocMemory(dwDMSize);
  if (pDevMode == NULL){
    FreeMemory(pi2);
    ClosePrinter(hPrinter);
    MsgBox(NULL, MB_OK, "バッファアロケートエラー");
    return(NULL);
  }

  // PRINTER_INFO_2 に、DEVMODE が格納されていない場合(希)
  if (pi2->pDevMode == NULL){
    MsgBox(NULL, MB_OK, "pi2->pDevMode == NULL !!");

    lFlag = DocumentProperties(NULL, hPrinter,
            szDevice,
            pDevMode, NULL,
            DM_OUT_BUFFER);
    if (lFlag != IDOK || pDevMode == NULL){
      FreeMemory(pDevMode);
      FreeMemory(pi2);
      ClosePrinter(hPrinter);
      MsgBox(NULL, MB_OK, "DocumentProperties()情報取得エラー");
      return(NULL);
    }

    pi2->pDevMode = pDevMode;
  }
  else{
    
    memcpy(pDevMode, pi2->pDevMode, dwDMSize);
  }

  // 印刷設定
  pDevMode->dmOrientation = nDir;
  pDevMode->dmDefaultSource = nBin;
  pDevMode->dmPaperSize = nSize;
  pDevMode->dmFields = DM_ORIENTATION | DM_PAPERSIZE | DM_DEFAULTSOURCE;


  // ドライバ依存部分の更新
  lFlag = DocumentProperties(NULL, hPrinter, szDevice, pDevMode, pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER);
  if (lFlag != IDOK){
    FreeMemory(pi2);
    ClosePrinter(hPrinter);
    FreeMemory(pDevMode);
    MsgBox(NULL, MB_OK, "DocumentProperties()エラー");
    return(NULL);
  }

  // セキュリティなし
  pi2->pSecurityDescriptor = NULL;

  // プリンタ情報の更新
  bFlag = SetPrinter(hPrinter, 2, (LPBYTE)pi2, 0);
  if (!bFlag){
    FreeMemory(pi2);
    ClosePrinter(hPrinter);
    FreeMemory(pDevMode);
    MsgBox(NULL, MB_OK, "SetPrinter() エラー");
    return(NULL);
  }


  FreeMemory(pi2);
  ClosePrinter(hPrinter);

  return(pDevMode);
}


※AllocMemory()、FreeMemory()、MsgBox() は自作の関数です。
ぼくちんも、前にVBからAPI使ってつくったことがあるでしゅ

プリンタドライバによっては、devmode DMBIN_MANUAL = 4 が手差しトレイとは限らないでしゅ
経験上、257,258などメーカー独自の値を採用しているのが多いでしゅ

結論として、コードで手差しトレイを選択するのは不可能だと思うでしゅ
リストボックスに、給紙トレイの一覧を表示させてユーザーに選んでもらうのが無難でしゅ

どうしてもというなら、DeviceCapabilities に DC_BINNAMES を指定して
給紙トレイの一覧を取得して、その中から「手差し」という文字が含まれる
ものを手差しトレイと見なす...というのはどうでしゅか

ぼくちんはCはわからないでしゅ
VBのコードでよければ
http://www.vbvbvb.com/cgi-bin/namazu.cgi?query=%83v%83%8A%83%93%83%5E+%8B%8B%8E%86&whence=0&max=20&result=normal&sort=score&idxname=gtips_nocode
((・。・))))・・・・さん、ありがとうございます。

DMBIN_MANUAL = 4 が手差しトレイとは限らないのですか!!
が〜ん、そんな事があっていいのでしょうか?って言ってもしょうがないですね。

DeviceCapabilities に DC_BINNAMES を指定して給紙トレイの一覧から手差しを
探すのですか...目から鱗が落ちる思いです。
VBのコード、参考にさせていただきます。

どうもありがとうございました。
解決済み!
((・。・))))・・・・さんに教えて頂いた方法で、以下の関数を作成し、
試してみたところ、手差し印刷ができました!
ありがとうございました。

ただし、
・DC_BINNAMES と、DC_BINS によって検索されたもののオフセットが同じ保証はないかな?
・「手差し」という文字列によって検索できない場合もあり得る。(外国製とか、手差し1、手差し2とかあったらどーする?)

等の問題はあります...
やっぱり、ユーザーに選択してもらうのが一番かな?

int SearchManualBin(char *pDevice, char *pPort)
{
 DWORD dwSize;
 BYTE (*arrNames)[24];
 WORD *wBins;
 int i, n, nOffset;

 // 名称バッファに必要なサイズを取得
 dwSize = DeviceCapabilities(pDevice, pPort, DC_BINNAMES, NULL, NULL);
 if(dwSize < 1){
  return(-1);
 }

 // アロケート
 arrNames = (BYTE (*)[24])GlobalAllocPtr(GHND, dwSize * 24);
 if(arrNames == NULL){
  return(-1);
 }

 // 名前格納
 n = (int)DeviceCapabilities(pDevice, pPort, DC_BINNAMES, (LPSTR)arrNames, NULL);
 if(n < 1){
  GlobalFreePtr(arrNames);
  return(-1);
 }

 // "手差し" を検索
 nOffset = -1;
 for(i = 0; i < n; i++){
  if(strstr(arrNames[i], "手差し") != NULL){
   nOffset = i;
  }
 }

 GlobalFreePtr(arrNames);

 if(nOffset < 0){
  return(-1);
 }

 // 番号バッファに必要なサイズを取得
 dwSize = DeviceCapabilities(pDevice, pPort, DC_BINS, NULL, NULL);
 if(dwSize < 1){
  return(-1);
 }

 // アロケート
 wBins = (WORD *)GlobalAllocPtr(GHND, dwSize * sizeof(WORD));
 if(wBins == NULL){
  return(-1);
 }

 // 番号格納
 n = (int)DeviceCapabilities(pDevice, pPort, DC_BINS, (LPSTR)wBins, NULL);
 if(n < nOffset){
  GlobalFreePtr(wBins);
  return(-1);
 }

 n = wBins[nOffset];

 GlobalFreePtr(wBins);
 return(n);

}
解決済み!
> ただし、
> ・DC_BINNAMES と、DC_BINS によって検索されたもののオフセットが同じ保証はないかな?

うにたん 補足でしゅ
ぼくちんちにある古いCanon LBP-A309G2 LIPS3 は
---------------------------------------
自動選択 15
上段カセット 259
下段カセット 258
自動選択 15
手差しトレイ 257
---------------------------------------
となったでしゅ (ドライバはXP付属のでしゅ)

あと Canon LBP-910 は、ちゃんと手差しトレイは4になっていたでしゅ。
でも、XPの前のWin98のときは、MSのドライバはちゃんと4で、Canonのドライバは 25? とか変な値になっていた気がするでしゅ。
(ぼくちんは、MSのドライバだと既定の値で、Canonのドライバだと256以上のメーカー独自の値。と思っていたけど違うみたいでしゅ)

ぼくちんも、ユーザーに選択してもらうのが無難だとおもうでしゅ。
(((・。・))))・・・・さん、情報ありがとうございます。

> うにたん 補足でしゅ
> ぼくちんちにある古いCanon LBP-A309G2 LIPS3 は
> ---------------------------------------
> 自動選択 15
> 上段カセット 259
> 下段カセット 258
> 自動選択 15
> 手差しトレイ 257
> ---------------------------------------
> となったでしゅ (ドライバはXP付属のでしゅ)
>
> あと Canon LBP-910 は、ちゃんと手差しトレイは4になっていたでしゅ。
> でも、XPの前のWin98のときは、MSのドライバはちゃんと4で、Canonのドライバは 25? とか変な値になっていた気がするでしゅ。
> (ぼくちんは、MSのドライバだと既定の値で、Canonのドライバだと256以上のメーカー独自の値。と思っていたけど違うみたいでしゅ)
>
> ぼくちんも、ユーザーに選択してもらうのが無難だとおもうでしゅ。


 手元にある、もっと古〜い機種のCanonLBP B40GUですが、Win98までは確かに
DMBIN_MANUAL で手差し指定ができていました。
 Xp Pro上(ドライバはCanon製で、Win2K用)、で調べると

給紙種別名称 0 番目 = 自動選択
給紙種別名称 1 番目 = 上段カセット
給紙種別名称 2 番目 = 下段カセット
給紙種別名称 3 番目 = 自動
給紙種別名称 4 番目 = 手差し(トレイ)

給紙種別ID 0 番目 = 15
給紙種別ID 1 番目 = 259
給紙種別ID 2 番目 = 258
給紙種別ID 3 番目 = 7
給紙種別ID 4 番目 = 257

となり、257で手差し印刷ができました。

わけわからんのは、Xerox のある機種で、XP Pro上(ドライバはXerox製)で
給紙種別名称 0 番目 = 自動
給紙種別名称 1 番目 = トレイ1
給紙種別名称 2 番目 = トレイ2
給紙種別名称 3 番目 = トレイ3
給紙種別名称 4 番目 = トレイ4
給紙種別名称 5 番目 = トレイ5(手差し)
給紙種別名称 6 番目 = 手差しキー操作待ち
給紙種別名称 7 番目 = トレイ6(大容量)

給紙種別ID 0 番目 = 7
給紙種別ID 1 番目 = 1
給紙種別ID 2 番目 = 3
給紙種別ID 3 番目 = 2
給紙種別ID 4 番目 = 257
給紙種別ID 5 番目 = 4
給紙種別ID 6 番目 = 260
給紙種別ID 7 番目 = 11

となり、260番を除き、何を指定しても手差し印刷ができませんでした。
(260は、プリンタの操作パネルボタンを操作しなければならないので、役に立ちません。)
 Win95では、DMBIN_MANUAL が有効でした。
 Xeroxに問い合わせても、「ドライバについては答えられない」との冷たいあしらいなので、もう、あきらめてしまいました。
物事、なかなか、思うようにはいかないですね。

わざわざ情報を提供いただき、ありがとうございました。

DOBON.NET | プログラミング道 | プログラミング掲示板