C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[8]: 印刷ジョブを取り消すプログラム


(過去ログ 96 を表示中)

[トピック内 11 記事 (1 - 11 表示)]  << 0 >>

■57277 / inTopicNo.1)  印刷ジョブを取り消すプログラム
  
□投稿者/ さとすけ (1回)-(2011/02/21(Mon) 11:24:59)

分類:[C#] 

2011/02/21(Mon) 11:56:58 編集(投稿者)
掲題の動作を目的としたプログラムを作成しています。
Webからそれらしい記述を見つけ試したいのですが
エラーが出てしまい実行できません。

このエラーについて調べてみてみますと
どうも印刷処理がどうのこうのというより、
C#の基本的な部分でつまづいているようなのですが
解決方法がわからず困っています。
どなたかご教授頂けないでしょうか?

@エラーメッセージ
-----
NullReferenceException はハンドルされませんでした。
オブジェクト参照がオブジェクト インスタンスに設定されていません。
-----

@ソース
-----
public static void Main(string[] args)
{
	PrintServer server = new PrintServer();
	foreach (PrintQueue queue in server.GetPrintQueues())
	{
		queue.Purge(); // <- ここでエラー
			
		Console.WriteLine(String.Format("{0}", queue.Name));
		Console.WriteLine(String.Format("\t{0}", queue.QueueDriver.Name));
		Console.WriteLine(String.Format("\t{0}", queue.QueuePort.Name));
		Console.WriteLine(String.Format("\t{0}", queue.NumberOfJobs));
		Console.WriteLine(String.Format("\t{0}", (queue.IsOffline) ? "オフライン" : "オンライン"));
	}
	//debug
	Console.ReadLine();
}
-----

@実行環境
-----
CPU:Pentium4 2.6GHz
メモリ:760MB
OS:WindowsXP Professinal Version 2002
    ServicePack2
開発ツール:VisualStdio2005 Professional 8.0.50727.42
.NET Framework 2.0.50727 SP1
C#
-----

@これまでわかったこと
+ クラス queue のメンバ変数 (queue.Nameなど) へはアクセス出来るが
  メンバ関数 (queue.Purge()) へアクセスできない
+ new を置けば解決? しかしどこに置けばよいかわからない

引用返信 編集キー/
■57278 / inTopicNo.2)  Re[1]: 印刷ジョブを取り消すプログラム
□投稿者/ 渋木宏明 (59回)-(2011/02/21(Mon) 11:36:14)
渋木宏明 さんの Web サイト
System.Printing は使ったことがないので間違っているかもしれませんが…

> PrintServer server = new PrintServer();

コンストラクタ引数でサーバ名(ローカルなら "." とか?)を指定しなくて大丈夫ですか?

↑が原因なら

> foreach (PrintQueue queue in server.GetPrintQueues())
> {
> queue.Purge(); // <- ここでエラー

は、実はもう1行上の server.GetPrintQueues() でエラーが起きているような気が。

引用返信 編集キー/
■57284 / inTopicNo.3)  Re[1]: 印刷ジョブを取り消すプログラム
□投稿者/ 魔界の仮面弁士 (2073回)-(2011/02/21(Mon) 14:06:54)
2011/02/21(Mon) 14:10:48 編集(投稿者)

No57277 (さとすけ さん) に返信
> NullReferenceException はハンドルされませんでした。
う〜ん。queue が null でないのにエラーになるのだとしたら、
サービスがまだ起動していないなどの理由で、
内部オブジェクトの一部が正常に取得されていないとか…?


> queue.Purge(); // <- ここでエラー
とりあえず、PrintQueue.Purge はジョブ内の一括削除メソッドらしいので、
一度に削除するのが駄目なら、個別削除するのはどうでしょうか。

PrintJobInfoCollection jobs = queue.GetPrintJobInfoCollection();
foreach (PrintSystemJobInfo job in jobs) { job.Cancel(); }</pre></pre>
引用返信 編集キー/
■57289 / inTopicNo.4)  Re[2]: 印刷ジョブを取り消すプログラム
□投稿者/ さとすけ (2回)-(2011/02/21(Mon) 15:59:55)
ご回答ありがとうございます。
ご提示いただいたものを確認しましたが
エラーとなってしまいました。
以下に詳細を記述致します。


>> PrintServer server = new PrintServer();
>コンストラクタ引数でサーバ名(ローカルなら "." とか?)を指定しなくて大丈夫ですか?

"."を指定すると以下のメッセージが出てエラーとなってしまいました。
-----
PrintServerException はハンドルされませんでした。
オブジェクト参照がオブジェクト インスタンスに設定されていません。
-----
実際のプリンタ名を指定すると、
指定しないときと同じに
>>queue.Purge(); // <- ここでエラー
この行で止まってしまいました。


> とりあえず、PrintQueue.Purge はジョブ内の一括削除メソッドらしいので、
> 一度に削除するのが駄目なら、個別削除するのはどうでしょうか。
> PrintJobInfoCollection jobs = queue.GetPrintJobInfoCollection();
> foreach (PrintSystemJobInfo job in jobs) { job.Cancel(); }</pre></pre>

こちら試したところ
> PrintJobInfoCollection jobs = queue.GetPrintJobInfoCollection();
の行で queue.Purge(); の時と同じエラーが出てしまいました。
-----
NullReferenceException はハンドルされませんでした。
オブジェクト参照がオブジェクト インスタンスに設定されていません。
-----

以上です。


ひとつ書き漏れがありましたので記述致します。
問題の行
>queue.Purge(); // <- ここでエラー
をコメントアウトするとエラーは発生せず正常に終了しました。
その際はマシンにインストール済みのプリンタ名などが列挙されました。
つまり PrintQueueクラスのメンバ変数(queue.Nameなど)へのアクセスは
問題無く出来ているようです。


マイクロソフトのHPを参照しますと
PrintServerクラス や PrintQueueクラス は
---
サポート対象 :
.NET Framework 3.0
---
となっていましてて .NET Framework 2.0 では動かないのでしょうか。
メンバ変数(queue.Nameなど)の参照が出来たので
ひょっとしたらうまくいくのではと思い試したのですが・・。
上記以外にも印刷ジョブ取り消しの実装方法がありましたら
教えていただけますと幸いです。

引用返信 編集キー/
■57291 / inTopicNo.5)  Re[3]: 印刷ジョブを取り消すプログラム
□投稿者/ 魔界の仮面弁士 (2075回)-(2011/02/21(Mon) 16:59:50)
No57289 (さとすけ さん) に返信
> .NET Framework 3.0
> となっていましてて
まぁ、WPF用の印刷サービスですし。


> となっていましてて .NET Framework 2.0 では動かないのでしょうか。
3.0 や 3.5 をインストールしてある環境には、.NET 2.0 が必ず入っていますが、
その逆は成り立ちません。そして当然、3.0 がインストールされていない環境では動きません。

3.0 がインストールされている場合は動作するかも知れませんが、VS2005 からの利用は
想定されていないと思います。System.Printing を使いたいなら、C# 3.0 以降のコンパイラを
使うのが普通なので、ここは VS2008 か VS2010 で作成された方が無難でしょう。

# ちなみに当方の 2008 でも、稀に NullReferenceException が発生しました。
# 数回リトライしてみたらいつの間にか再現しなくなって、何が何やら。


> 上記以外にも印刷ジョブ取り消しの実装方法がありましたら
> 教えていただけますと幸いです。
.NET 2.0 だと、System.Management 名前空間(System.Management.DLL) 経由で
WMI の Win32_Printer クラスを利用するというのはどうでしょうか。
具体的には CancelAllJobs メソッドです。
http://msdn.microsoft.com/en-us/library/aa384838.aspx
引用返信 編集キー/
■57295 / inTopicNo.6)  Re[4]: 印刷ジョブを取り消すプログラム
□投稿者/ さとすけ (3回)-(2011/02/21(Mon) 19:08:27)
ご回答ありがとうございます。
仰るとおり .NET2.0 上で .NET3.0 のクラスを動かすのは無理があったかもしれません。
ご提示頂きましたWMI の Win32_Printer クラスを使いたく思います。

上記のものを調査しましたところ、
プリンタ名を表示するサンプルソースが見つかり、
プログラムへ実装し正常動作を確認しました。

ただ、そこにジョブをとめるメソッド(CancelAllJobs)を実装しようとすると
次のエラーが出てしまいます。
-----
'System.Management.ManagementObject' に 'CancelAllJobs' の定義がありません。
-----
# メソッド実装箇所は下記ソースの
「//printer.CancelAllJobs(); // <- エラーが発生」の行です

WMI と Win32_Printer の基本的な使い方が間違ってしまっているように思われますが
どうすればよいか判らず困っております。
もしご存知でありましたら教えて下さいますでしょうか。

# SELECT文でシステム情報を取得するってユニークですね
# こんなこともできるんだ、と感心してしまいました

@ソース
-----
using System;
using System.Management;
namespace zedilabs.com
{
	class PrinterOffline
	{
		[STAThread]
		static void Main(string[] args)
		{
			// Set management scope

			ManagementScope scope = new ManagementScope(@"\root\cimv2");
			scope.Connect();

			// Select Printers from WMI Object Collections

			ManagementObjectSearcher searcher = new
			 ManagementObjectSearcher("SELECT * FROM Win32_Printer");


			string printerName = "";
			foreach (ManagementObject printer in searcher.Get())
			{
				printerName = printer["Name"].ToString().ToLower();
				//debug
				Console.WriteLine(printerName);

				//printer.CancelAllJobs(); // <- エラーが発生
			}
			//debug
			Console.ReadLine();
		}
	}
}
-----

引用返信 編集キー/
■57296 / inTopicNo.7)  Re[5]: 印刷ジョブを取り消すプログラム
□投稿者/ 魔界の仮面弁士 (2076回)-(2011/02/21(Mon) 23:04:58)
No57295 (さとすけ さん) に返信
> foreach (ManagementObject printer in searcher.Get())
> {
> 	//printer.CancelAllJobs(); // <- エラーが発生
> }

お気づきのように、ManagementObject に CancelAllJobs メソッドはありません。
そして存在しないメソッドは当然呼べません。(C# 2.0 ではレイトバインドも使えませんし)

ではどうするかというと…InvokeMethod メソッドを使って呼び出すことになります。
下記は他の WMI クラスの例ですが、参考なるかと思います。

http://dobon.net/vb/dotnet/graphics/defaultprinter.html
http://msdn.microsoft.com/ja-jp/library/system.management.managementobject.invokemethod%28VS.71%29.aspx

引用返信 編集キー/
■57302 / inTopicNo.8)  Re[5]: 印刷ジョブを取り消すプログラム
□投稿者/ 魔界の仮面弁士 (2077回)-(2011/02/22(Tue) 10:07:22)
No57295 (さとすけ さん) に返信
> ご提示頂きましたWMI の Win32_Printer クラスを使いたく思います。

WMI の型付クラスを使うと便利ですよ。
http://msdn.microsoft.com/ja-jp/library/2wkebaxa%28VS.80%29.aspx

スタートメニューの Visual Studio 2005 コマンドプロンプトから
 MgmtclassGen Win32_Printer /P C:\folder\filename.cs
のようにすると、カプセル化された『ROOT.CIMV2.Win32.Printer クラス』が生成されます。


using System;
using System.Management;

class Program
{
    static void Main()
    {
        foreach (ROOT.CIMV2.Win32.Printer printer in ROOT.CIMV2.Win32.Printer.GetInstances())
        {
            Console.Write(printer.Name + " のジョブを");
            uint result = printer.CancelAllJobs();
            Console.WriteLine((result == 0) ? "削除しました。" : "削除できませんでした。");

            printer.Dispose();
        }
        Console.Write("Hit Any Key...");
        Console.ReadKey();
    }
}

引用返信 編集キー/
■57315 / inTopicNo.9)  Re[6]: 印刷ジョブを取り消すプログラム
□投稿者/ さとすけ (4回)-(2011/02/22(Tue) 17:04:00)
ご回答ありがとうございました。
ご提示頂きました InvokeMethod のやり方と WMI添付クラス の両者を
それぞれ実装し正常動作を確認しました。

今回のプログラムに対する要求内容は印刷ジョブを取り消すだけでしたので
全体のソース量の少ない InvokeMethod を採用することに致しました。
もっと頻繁に Win32_Printer クラスなどへアクセスする必要がある場合は
WMI添付クラス を採用する予定です。
おかげ様でコーディング方法に選択肢が増えました。

お忙しいところご教授頂きまして、本当にありがとうございました。


----- 採用予定のソース ここから -----
using System;
using System.Management;
namespace zedilabs.com
{
	class PrinterOffline
	{
		[STAThread]
		static void Main(string[] args)
		{
			// Set management scope
			ManagementScope scope = new ManagementScope(@"\root\cimv2");
			scope.Connect();

			// Select Printers from WMI Object Collections
			ManagementObjectSearcher searcher = new
			 ManagementObjectSearcher("SELECT * FROM Win32_Printer");

			foreach (ManagementObject printer in searcher.Get())
			{
				System.Management.ManagementBaseObject mbo =
					printer.InvokeMethod("CancelAllJobs", null, null);
			}
			//debug
			//Console.ReadLine();
		}
	}
}
----- 採用予定のソース ここまで -----

解決済み
引用返信 編集キー/
■57322 / inTopicNo.10)  Re[7]: 印刷ジョブを取り消すプログラム
□投稿者/ 魔界の仮面弁士 (2080回)-(2011/02/22(Tue) 19:13:21)
No57315 (さとすけ さん) に返信
> 全体のソース量の少ない InvokeMethod を採用することに致しました。

こういう用途には、Microsoft PowerShell の方が便利ですよ。
今回の処理も、わずか一行で行えますし。

Get-WmiObject -class Win32_Printer | Foreach-Object { $_.CancelAllJobs() }



> ManagementScope scope = new ManagementScope(@"\root\cimv2");
> scope.Connect();
> ManagementObjectSearcher searcher = new
>  ManagementObjectSearcher("SELECT * FROM Win32_Printer");

変数 scope が使われていないようです。無意味なので最初の 2 行は消しましょう。
(この場合、既定の名前空間が \root\cimv2 ゆえに動いているだけです)

もし、\root\cimv2 という名前空間を明示したいのであれば、WQL 文字列を
ManagementObjectSearcher の (string) なコンストラクタに渡す代わりに、
(ManagementScope, ObjectQuery) のコンストラクタを利用してやれば OK です。

引用返信 編集キー/
■57346 / inTopicNo.11)  Re[8]: 印刷ジョブを取り消すプログラム
□投稿者/ さとすけ (5回)-(2011/02/23(Wed) 12:20:47)
> こういう用途には、Microsoft PowerShell の方が便利ですよ。
> Get-WmiObject -class Win32_Printer | Foreach-Object { $_.CancelAllJobs() }

これはシンプルでわかりやすいですね。
運用環境で Microsoft PowerShell がinstallされているかまだ未確認ですが
いずれにせよ別のやり方もあることが判りとても勉強になります。

>>ManagementScope scope = new ManagementScope(@"\root\cimv2");
>>scope.Connect();
> 変数 scope が使われていないようです。無意味なので最初の 2 行は消しましょう。

サンプルソースを理解せずにそのまま実装してしまっていました。
ご助言ありがとうございます。
削除して実装致します。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -