• ベストアンサー

Wordのプロパティ・総ページ数について(VBA絡み)

 初心者です。 エクセルVBAでWordのプロパティ値を取得するためBuiltinDocumentProperties("Number of Pages")を使っているのですが、なぜかページ数が正しく表示されません。  例えば6ページある文書の総ページ数が2というふうに全然関係ない数字が返ってきます。念のためマクロ後にプロパティ値を再確認すると、表示された2に変わってしまっているんです。もちろん実際の文書に存在するページ枚数は変わっていません。  文書自体を開いて上書きしてやると、ページ数の数字は戻るのですが、マクロを実行すると同じ結果になります。どうしてでしょうか?  EXCEL2000です。詳しい方お願いします。  

質問者が選んだベストアンサー

  • ベストアンサー
  • KenKen_SP
  • ベストアンサー率62% (785/1258)
回答No.10

> なぜかウチのEXCELはページ数ではなくて、総文字数を返します。 それは、恐らく参照設定の問題ですね。実行時バインド(CreateObject) 方式では ComputeStatistics に渡す引数のインデックス番号が正しく 渡らないのだと思います。参照設定を行えば問題なく動作します。 ちなみに私は昔から BuiltinDocumentProperties は当てにならない、、 と思いこんでましたから、ComputeStatistics を使ってました。 今回、Wendy02 さんが良い情報を提供して下さいましたので、私も今後は BuiltinDocumentProperties 派でいこうと思います。 ただ、今回このスレッドで紹介された方法はいずれもファイル全体を一度 は読み込む方法ですから、処理速度は遅いですね。機会があれば、 バイナリー解析でページ数を取得する関数を作ってみたいと思います。 それから、蛇足で恐縮ですが、#8 発言の手前、一応アップしておきます。 ユーザー定義関数を作ってみました。が、、関数にする必要性はあまり 無かったです(;-ω-) =3 Word ファイルのパスを渡すと、各種情報が一次元配列で返されます。 使いかたは、サンプルコードを見てください。 Variant型の変数で関数の戻り値を一次元配列で受けます。その変数の 添え字に取得したい BuiltinDocumentProperties のインデックス番号 を指定します。 まぁ。。ファイル処理周りの例外処理をメインルーチン側で省けるので 意義は在ると言えば在るのですが。 Sub 使い方サンプルコード()   Dim Fname  As String   Dim aryInfo As Variant   Dim sMes(8) As String   Dim Sp   As String     Fname = Application.GetOpenFilename("MsWordファイル(*.doc),*.doc")   If UCase$(Fname) = "FALSE" Then     Exit Sub   End If   '関数の戻り値は一次元配列なので Variant型 の変数で受ける   aryInfo = GetMsWordBuiltinProperties(Fname)   '結果表示   If IsArray(aryInfo) = False Then Exit Sub     Sp = vbTab & ": "   sMes(0) = "ファイル名" & Sp & Dir(Fname)   sMes(1) = "バイト数" & Sp & Format(aryInfo(22) / 1024, "#,##0") & " KB"   sMes(2) = "タイトル" & Sp & aryInfo(1)   sMes(3) = "文字数" & Sp & aryInfo(16)   sMes(4) = "(SP含む)" & Sp & aryInfo(30)   sMes(5) = "行数" & Sp & aryInfo(23)   sMes(6) = "ページ数" & Sp & aryInfo(14)   sMes(7) = "段落数" & Sp & aryInfo(24)   sMes(8) = "単語数" & Sp & aryInfo(15)   MsgBox Join$(sMes, vbCr)   End Sub 'MsWord ドキュメントの各種統計情報を取得 Function GetMsWordBuiltinProperties(strFilePath As String) As Variant   '要参照設定:Microsoft Word x.x Object Library      Dim wdApp   As Word.Application   Dim wdDoc   As Word.Document   Dim aryRet(1 To 30) As Variant     On Error GoTo ErrorHandler      '初期化   GetMsWordBuiltinProperties = False   'ファイルが無いまたは拡張子が異なる場合は False を返す   If Dir(strFilePath) = "" _     Or UCase$(Right$(strFilePath, 4)) <> ".DOC" Then     Exit Function   End If     'MsWord ファイルオープン   Set wdApp = New Word.Application   Set wdDoc = wdApp.Documents.Open(strFilePath, ReadOnly:=True)   'ドキュメントの統計情報を取得   With wdDoc     .Repaginate 'Thanks Wendy02 san!     For i = 1 To 30       aryRet(i) = .BuiltinDocumentProperties(i)       'Index 24-29 は Word では使わないと思います       If i = 24 Then i = 29     Next i   End With   '戻り値をセット   GetMsWordBuiltinProperties = aryRet   Terminate:   On Error Resume Next   wdDoc.Close False   wdApp.Application.Quit   Set wdDoc = Nothing   Set wdApp = Nothing   Exit Function ErrorHandler:   '想定外のエラー発生の場合には False を返す   GetMsWordBuiltinProperties = False   On Error GoTo 0   GoTo Terminate End Function

idbr2
質問者

お礼

こんにちはidbr2です。 お礼が大変遅くなり恐縮しております。こちらが質問しておきながら済みませんでした。 ちょっと忙しくなってしまったので、ゆっくりブックを開くこともままなりません。 せっかくですので、教えていただいたコードが意味する内容も含めて、独学していく上での糧にするため色々確認したいのですが、そこはやはり初心者ということでそういった作業にさえある程度時間を要してしまいます。 よって、まだ示していただいたマクロに手を付けられずにいるのですが、用事の方がもう少しかかわりそうなので、とりあえずお礼のほうを先にいたします。 いろいろありがとうございました。今回、大変勉強になりました。

その他の回答 (10)

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.11

KenKen_SPさん、idbr2さん。 こんにちは、Wend02です。 >バイナリー解析でページ数を取得する関数を作ってみたいと思います。 それは、どのようにして行われるのか、C++でも使うでしょうか?今回、私は、プロパティを取得するタイプライブラリは、すでに、存在しているはずだと思っています。理由は、 Application.GetOpenFilename("MsWordファイル(*.doc),*.doc") で、プロパティの内容は見てとれますですね。それは、そういう機能のあるプログラムが存在していることに他なりません。ファイルの表層部分にでも記録があるものだと思っています。私の場合は、未だ、いろんな資料が少ないもので、なかなか分らない部分も多いです。 今回、それを調べる過程で、MSの資料が出てきただけで、本来の目的とは違いました。もう少し、私も本格的な勉強をしないと、こういうところがクリアできないのです。

idbr2
質問者

お礼

こんにちはidbr2です。 お礼が大変遅くなり恐縮しております。こちらが質問しておきながら済みませんでした。 ちょっと忙しくなってしまったので、ゆっくりブックを開くこともままなりません。 せっかくですので、教えていただいたコードが意味する内容も含めて、独学していく上での糧にするため色々確認したいのですが、そこはやはり初心者ということでそういった作業にさえある程度時間を要してしまいます。 よって、まだ示していただいたマクロに手を付けられずにいるのですが、用事の方がもう少しかかわりそうなので、とりあえずお礼のほうを先にいたします。 いろいろありがとうございました。今回、大変勉強になりました。

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.9

Wendy02です。以下は、修正版です。 Sub MsWordタイトル取得2()   Dim wdApp As Word.Application   Dim wdDoc As Word.Document   Dim Fname As String   Dim FileSize As Long, myWait As Long     Dim wdCnt As Long, wdtitle As String   Set wdApp = New Word.Application   Fname = Application.GetOpenFilename("MsWordファイル(*.doc),*.doc")   If Fname = "False" Then    Exit Sub   End If   Set wdDoc = wdApp.Documents.Open(Fname, , True)   With wdDoc    .Repaginate '書き換えた部分    wdtitle = .BuiltinDocumentProperties(wdPropertyTitle)    wdCnt = .BuiltinDocumentProperties(wdPropertyPages)    .Close False   End With    wdApp.Quit   Set wdDoc = Nothing   Set wdApp = Nothing   MsgBox wdtitle & vbCrLf & " 総ページ数" & wdCnt End Sub 以下を参考にしました。 http://support.microsoft.com/default.aspx?scid=kb;en-us;212653  (http://support.microsoft.com/kb/212653/ja) 英語からの拙訳: WD2000: BuiltInDocumentPropertiesで誤ったページ・カウント表示を返す場合。 記事ID:212653 本記事は、Q212653の元で以前に発表された。 ドキュメントにページ改行を挿入し、マクロを使ってBuiltInDocumentProperties のプロパティを用いてページ・カウントを返した時に、返されるページが誤っている場合。 そのドキュメントはページ数を返す前に、"repaginate"で再ページカウントする必要がある。   Sub GetNumberOfPages()    ActiveDocument.Repaginate    MsgBox ActiveDocument.BuiltInDocumentProperties(wdPropertyPages)   End Sub

  • KenKen_SP
  • ベストアンサー率62% (785/1258)
回答No.8

こんにちは、idbr2 さん、Wendy02 さん。 こちらも色々検証してみましたが、どうも CreateObject では無理みたいですね、、原因は不明ですが。 参照設定必須みたいです、、、 関数化したものをアップしますので、よろしければ、 暫しお待ちを。

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.7

Wendy02です。 ごめんなさい。 >基本的なミスとしては、WordのApplicationが終了していません。 その元のwdApp.Quit を入れずに書いたのは私でした。 m(__)m なんと言ってよいのか、引っ込みつきません。すぐに気が付いてよかったです。重ねてすみません。

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.6

こんにちは。Wendy02です。 >おそらく完全に文書を読み込み切れていないのが原因なのかなと、自分では推測しております。 確認しました。おっしゃる通りです。ただし、そのコードは、とても危険な内容です。あやうく、フリーズをするところでした。とりあえず以下のようにしてみてください。基本的なミスとしては、WordのApplicationが終了していません。もしも、Applicationをオープンしたままでしたら、GetObjectを使いながら、取得すればもっと速く取れるはずです。Visible を入れてみて気が付きました。 今回、API関数を入れ、Waitを付けてみました。その値(FileSize/50000)自体は、PCのスペックに依存するものですから、最適値は、変わります。もちろん、KenKen_SPさんのComputeStatisticsの方法でも、切り替えれば、取得可能なはずです。 それから、CreateObjectでも取れるはずですが、安定を考えて、参照設定を使いました。 Option Explicit Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Sub MsWordタイトル取得()   Dim wdApp As Word.Application   Dim wdDoc As Word.Document   Dim Fname As String   Dim FileSize As Long, myWait As Long     Dim wdCnt As Long, wdtitle As String   Set wdApp = New Word.Application     Fname = Application.GetOpenFilename("MsWordファイル(*.doc),*.doc")   If Fname = "False" Then    Exit Sub   End If   FileSize = FileLen(Fname)   Set wdDoc = wdApp.Documents.Open(Fname, , True)   'wdApp.Visible = True   myWait = Int(FileSize / 50000) * 1000   Sleep myWait   With wdDoc    wdtitle = .BuiltinDocumentProperties("Title")    wdCnt = .BuiltinDocumentProperties("Number of Pages")    .Close False   End With    wdApp.Quit   Set wdDoc = Nothing   Set wdApp = Nothing   MsgBox wdtitle & vbCrLf & " 総ページ数" & wdCnt End Sub

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.5

#2のWendy02ですが、 自分の発言を撤回します。 #Wordを開いていませんか?そうすると、コードが違ってきてしまいます。 ではなくて、開け方が問題ではないでしょうか?オートメーションで開ける分には、ドキュメントが開いていようがいまいが、関係がありません。それで、私は、この問題は、環境の違いによって途中で書き換わっていると考えています。Officeのプロパティは、元々、外部ツールなどで閲覧できるように作られているので、開いて書き換えなければ、変わらないはずです。 Sub WhatTPages_inWDDoc()   Dim WdApp As Object   Dim WdDoc As Object   Dim myRange As Object   Dim myFile As String   Dim Pagecount As Integer   myFile = "C:\MyFavorite.Doc"   On Error GoTo ErrHandler   Set WdApp = CreateObject("Word.Application")   With WdApp.Documents.Open(myFile, , True)    Set myRange = .Content    myRange.Collapse Direction:=0    Pagecount = .BuiltinDocumentProperties(14)    .Close 0   End With   MsgBox Pagecount & " ページ" ErrHandler:   Set WdApp = Nothing End Sub

idbr2
質問者

お礼

お礼が遅くなって済みませんでした。 さっそく教えていただいたマクロを試しましたが、やはりページ数は2と表示されます。おそらく完全に文書を読み込み切れていないのが原因なのかなと、自分では推測しております。 それと、ご質問があったマクロの最終目的なのですが、ワード文書がひとつ出来上がるごとに、作成日時と文書タイトル、総ページ数などをエクセルの一覧表に記入していくという作業をしたかったので、ダイアログから選択した文書のプロパティ値をマクロで取得して、エクセルの表に書き込んでくためのものです。 最初の状況報告があいまいで申し訳ありませんでした。 下記に途中まで作ってみたマクロを載せます。 Sub MsWordタイトル取得() Dim wdApp As Object, Fname As String, wdDoc As Object Dim wdCnt As Long Dim wdtitle As String Set wdApp = CreateObject("Word.Application") Fname = Application.GetOpenFilename("MsWordファイル(*.doc),*.doc") If Fname = "False" Then Exit Sub End If Set wdDoc = wdApp.Documents.Open(Fname) wdtitle = wdDoc.BuiltinDocumentProperties("Title") wdCnt = wdDoc.BuiltinDocumentProperties("Number of Pages") wdDoc.Close False MsgBox wdtitle & vbCrLf & " 総ページ数" & wdCnt Set wdApp = Nothing End Sub

  • KenKen_SP
  • ベストアンサー率62% (785/1258)
回答No.4

#1 です。重ねて失礼しました。 #3 は変数の宣言が漏れたり、WORD のインスタンスが残ったり、お粗末なコード でした。差し替えさせて頂きます。適当ですみません。 Sub Sample()   Dim wdApp As Object   Dim wdDoc As Object   Dim lngPageCount As Long        Set wdApp = CreateObject("Word.Application")      'ファイルオープン   Set wdDoc = wdApp.Documents.Open("C:\test.doc")   'ページ数取得   lngPageCount = wdDoc.ComputeStatistics( _     Statistic:=wdStatisticPages, _     IncludeFootnotesAndEndnotes:=True)      'WORDを閉じる   wdDoc.Close   wdApp.Application.Quit      'ページ数表示   MsgBox lngPageCount      'オブジェクト変数を解放   Set wdDoc = Nothing   Set wdApp = Nothing End Sub

idbr2
質問者

お礼

お礼が遅くなって済みませんでした。 さっそく教えていただいたマクロを実行してみたのですが、なぜかウチのEXCELはページ数ではなくて、総文字数を返します。 これはコードの問題ではなくて、ブック自体がおかしくなっているのかも知れないと考え、ブックを新たに作って再挑戦をしましたがこれも駄目。アプリの自動修復を試みたのですが、悪いことは続くもので、ただいまCDRのハードの方が故障していてOfficeのCDを読み込めません。 結局、現時点で打つ手なしかなと諦めモードです。 BuiltinDocumentProperties("Number of Pages")を使うと処理が不完全のまま進行する例が確かにあるということは、何とか自分でも調べられました。 教えていただいたComputeStatistics( Statistic:=wdStatisticPages)の動作確認が取れないのが残念です。

  • KenKen_SP
  • ベストアンサー率62% (785/1258)
回答No.3

#1 です。失礼。Excel VBA でしたね。 ページが重たいと BuiltinDocumentProperties("Number of Pages") は不安定 みたいですね。ページを開く途中で、コードが実行されている感じがします。 コーディんグにもよると思いますが。 以下は Excel VBA で書き直しました。ご参考までに。 Sub Sample()   Dim wdApp As Object      Set wdApp = CreateObject("Word.Application")      'ファイルオープン   Set wdDoc = wdApp.Documents.Open("C:\test.doc")   'ページ数取得   lngPageCount = wdDoc.ComputeStatistics( _     Statistic:=wdStatisticPages, _     IncludeFootnotesAndEndnotes:=True)   'WORDを閉じる   wdDoc.Close      'ページ数表示   MsgBox lngPageCount      'オブジェクト変数を解放   Set wdDoc = Nothing   Set wdApp = Nothing End Sub

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.2

こんにちは。 私も、コードを書く時は、BuiltinDocumentProperties("Number of Pages")で、ページ数は取っていますので、その取るまでのコードを見せていただけませんか? もしかしたら、Wordを開いていませんか?そうすると、コードが違ってきてしまいます。アクセスする間に、そのWordが書き換わっている可能性がありますね。実体のある「ファイルのプロパティ」でないと、うまくいきませんからね。 それと、大事なことなのですが、そのコードの最終目的を教えてください。それがないと、見当違いな話になることがありますから。

  • KenKen_SP
  • ベストアンサー率62% (785/1258)
回答No.1

こんにちは。KenKen_SP です。 ページ全体の読み込みが完了しないうちに、コードが実行されているとか? lngPageCount = ActiveDocument.ComputeStatistics( _   Statistic:=wdStatisticPages, _   IncludeFootnotesAndEndnotes:=True) MsgBox lngPageCount だと、どうですか? 以下はオマケ(というより蛇足)の参考ですが、、、  ・IncludeFootnotesAndEndnotes:=False とすると脚注部分を含まない  ・統計情報の取得は文書の変更とみなされる

関連するQ&A

専門家に質問してみよう