none
レイトバインドしたMicrosoft Projectでコレクションを列挙すると例外が発生する RRS feed

  • 質問

  • はじめまして、ほげたんです。

     

    VB.NET で、Microsoft Project をレイトバインドして、プロジェクトの情報を取得するサンプルを作成しました。ところが、Microsoft Project 2003 では期待通りに動作するものの、2000/2002 では例外が発生する場合があり、困っています。どなたかお知恵を拝借できないでしょうか。

     

    [問題が発生するコード]

    以下のようなサンプルコードを作成しました。

    1. ' Microsoft Project を起動する
    2. app = CreateObject("MSProject.Application")
    3. ' プロジェクトファイルを開く
    4. app.FileOpen(Name:="ファイル名", ReadOnly:=True)
    5. ' すべてのタスクを列挙して処理
    6. For Each task As Object In app.ActiveProject.Tasks
    7.     ' すべてのリンクを列挙して処理
    8.     For Each dependency As Object In task.TaskDependencies
    9.             :
    10.         (ここでは dependency のプロパティを参照するのみ)
    11.             :
    12.     Next
    13. Next

    [困っている問題]

    Microsoft Project 2000/2002 の場合、14行目部分で例外が送出されることがあります。

    Microsoft Project 2003 では問題なく処理が完了します。

    2000/2002 でも、常に例外が送出されるのではなく、条件もまだわかっていません。

    (TaskDependenciesコレクションの要素数が1,2個程度の場合は送出されず、3個以上になると送出される確率が高くなるようです)

    TaskDependencies以外のコレクション、TasksやAssignmentsなどで例外が送出されたことはありません。

    問題発生時に使用していたプロジェクトファイルの内容は、タスクを20個程度作成し、それらにリンクを作成したのみです(タスクのプロパティ等は一切変更していません)。

     

    [発生する例外]

    例外の型:System.Runtime.InteropServices.COMException

    ErrorCode:-2147417851(0x80010105)

    Message:サーバーによって例外が返されました。

    Source:mscorlib

    StackTrace:at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32 errorCode, IntPtr errorInfo)
           at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32 errorCode)
           at System.Runtime.InteropServices.CustomMarshalers.EnumeratorViewOfEnumVariant.GetNextElems()
           at System.Runtime.InteropServices.CustomMarshalers.EnumeratorViewOfEnumVariant.MoveNext()
           at (上記サンプルコードの14行目)

     

    [調査したこと]

    Microsoft Project の各バージョンのヘルプを参照して、これらの処理に必要なメソッド(NewEnumやItem)が変更されていないこと、互換性の問題として注意されていないことなど確認しました。また、各バージョンのタイプライブラリを生成し、バージョン間で序数や引数の変更などがないことも確認しました。

    インターネットで検索しても、それらしき問題を見つけることができず、困っています。

     

    1点気になっているのが、問題が発生するTaskDependenciesコレクションと、問題が発生しないTasks,Assignmentsコレクションでは Item() メソッドのシグネチャが異なることです。これが原因のような気がしていますが、知識が足りなく、よくわかっていません。

    TaskDependenciesコレクション    ->    LPDISPATCH get_Item(long Index)

    Tasks,Assignmentsコレクション    ->    LPDISPATCH get_Item(VARIANT Index)

     

    こんな情報あるよ、とか、こんなことを試したら? など、ご教授いただければ助かります。

    2007年5月14日 17:05

回答

  •  ほげたん さんからの引用
    「鬼門だと考え」ている理由があれば教えていただけますか。

    For Each は For の亜種と考えることができますが、
    RCW の参照カウントの問題があるので、制御構造はなるべく原始レベルに近い方が良い程度のお話です。

    まあ、それを言ったら遅延バインディングの方がかなりの 「鬼門」 ですね。
    たとえば、Worksheet をコピーする場合、遅延バインディングですと参照カウントが 2 つ増えてしまいます。
    気付かぬままだとそのまま Process 解放されず、ですね。

    ○○やったらこんなことが起きた、とか、RCWって結構問題が多いらしいよ、とかでかまいません。

    似たような経験がある程度では、説得力にかけるかもしれませんが。
    OLE オートメーション サーバや HRESULT からの例外の多くは、COM ラッパの不具合か
    もしくは対応していない機能を使ったという場合がほとんどなのですが。

    「それっぽい」という理由では説得力に欠けてしまうので

    私は、ほげたんさんではないので、確認する術はないですね...
    今の情報量からでは 「それっぽい」 としか言えません、ごめんなさい。
    2007年5月15日 6:59
  • 今回のは遅延バインディングありきの For Each ですからモロに鬼門な気がしてきました。
    For Each で順次 Object で受け取っていますから、Worksheet をコピーした時と同じ問題が起きるのではないでしょうか?

    それを前提にすると、

    Microsoft Project 2003 では問題なく処理が完了します。
    2000/2002 でも、常に例外が送出されるのではなく、条件もまだわかっていません。

    これの辻褄が合います。
    2003 では COM ラッパが適切に対処してくれているのかもしれません。
    (なんせ、Office PIA は 2003 バージョンを使うことが推奨されているくらいですから)

    というわけで、各 COM ラッパの実際の 「残り参照カウント」 を、調べてみてもらえませんか?
    ただし、検証する場合は 2000/2002 のラッパを使うようにしてください。
    2007年5月15日 7:07

すべての返信

  • あー、MS Project ではないですが経験ありです。

    内部的な原因はわかりませんが、Enumerator 系の問題であればただの For に置き換えると良いでしょう。
    私は COM との相互運用で For Each ステートメントは使わないようにしています。(鬼門だと考えています)
    2007年5月15日 0:42
  • 回答ありがとうございます。

     

    「鬼門だと考え」ている理由があれば教えていただけますか。

    ○○やったらこんなことが起きた、とか、RCWって結構問題が多いらしいよ、とかでかまいません。

     

    「COM相互運用におけるEnumeratorの問題」ということが確定できれば、開発の規約としてガイドライン化して完了なのですが、「それっぽい」という理由では説得力に欠けてしまうので、引き続き識者の方の情報・助言をお待ちしています。

     

    2007年5月15日 4:05
  •  ほげたん さんからの引用
    「鬼門だと考え」ている理由があれば教えていただけますか。

    For Each は For の亜種と考えることができますが、
    RCW の参照カウントの問題があるので、制御構造はなるべく原始レベルに近い方が良い程度のお話です。

    まあ、それを言ったら遅延バインディングの方がかなりの 「鬼門」 ですね。
    たとえば、Worksheet をコピーする場合、遅延バインディングですと参照カウントが 2 つ増えてしまいます。
    気付かぬままだとそのまま Process 解放されず、ですね。

    ○○やったらこんなことが起きた、とか、RCWって結構問題が多いらしいよ、とかでかまいません。

    似たような経験がある程度では、説得力にかけるかもしれませんが。
    OLE オートメーション サーバや HRESULT からの例外の多くは、COM ラッパの不具合か
    もしくは対応していない機能を使ったという場合がほとんどなのですが。

    「それっぽい」という理由では説得力に欠けてしまうので

    私は、ほげたんさんではないので、確認する術はないですね...
    今の情報量からでは 「それっぽい」 としか言えません、ごめんなさい。
    2007年5月15日 6:59
  • 今回のは遅延バインディングありきの For Each ですからモロに鬼門な気がしてきました。
    For Each で順次 Object で受け取っていますから、Worksheet をコピーした時と同じ問題が起きるのではないでしょうか?

    それを前提にすると、

    Microsoft Project 2003 では問題なく処理が完了します。
    2000/2002 でも、常に例外が送出されるのではなく、条件もまだわかっていません。

    これの辻褄が合います。
    2003 では COM ラッパが適切に対処してくれているのかもしれません。
    (なんせ、Office PIA は 2003 バージョンを使うことが推奨されているくらいですから)

    というわけで、各 COM ラッパの実際の 「残り参照カウント」 を、調べてみてもらえませんか?
    ただし、検証する場合は 2000/2002 のラッパを使うようにしてください。
    2007年5月15日 7:07
  • じゃんぬねっと さん回答ありがとうございます。

    # 出張していたためレスポンス遅れてすみません。

     

    ご教授いただいたアドバイスをもとに来週少し調べてみます。

    2007年5月19日 0:30