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

保存確認が聞かれない。

環境/言語:[XP,VB.net,NET Framework2.0,postgres]
分類:[.NET]

VB.netで、エクセルを新規作成し、そのエクセルを保存して、表示させるプログラムを作成しています。

エクセル出力した際、そのエクセルのプロセスで
別ファイルをオープンし、変更−クローズをした際に、確認メッセージが
表示されずに、閉じられる。

これは、なぜなんでしょう?

エクセル出力箇所です。
''' <summary>
''' エクセル出力処理
''' </summary>
''' <param name="fName">ファイル名</param>
''' <returns></returns>
''' <remarks>作成したエクセルファイルの内容を保存します。</remarks>
Public Function OutputExcel(ByVal fName) As String
Dim rStr As String = ""
Dim fPass As String = System.Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)

Dim SaveFileDialog1 As New Windows.Forms.SaveFileDialog()

SaveFileDialog1.FileName = fName
SaveFileDialog1.InitialDirectory = fPass
SaveFileDialog1.Filter = "Excel ファイル(*.xls)|*.xls||*.*"
SaveFileDialog1.FilterIndex = 2 '「すべてのファイル」
SaveFileDialog1.Title = "ファイル名を付けて保存"
SaveFileDialog1.RestoreDirectory = True
SaveFileDialog1.OverwritePrompt = False
SaveFileDialog1.CheckPathExists = True

If SaveFileDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then
If clsCommon.ShowMSG("Q00008") = Windows.Forms.DialogResult.OK Then
Console.WriteLine(SaveFileDialog1.FileName)
rStr = SaveFileDialog1.FileName
End If
End If

Return rStr
End Function

この作成した、エクセルに対し、

''' <summary>
''' エクセルの保存
''' </summary>
''' <param name="pIndex">インデックス</param>
''' <returns></returns>
''' <remarks></remarks>
Private Function SaveData(ByVal pIndex) As String
Dim rStr As String = ""
objApp.Calculation = xlAutomatic
objBook(pIndex).Save()
Return rStr
End Function

して、
''' <summary>
''' エクセルの表示
''' </summary>
''' <param name="pIndex">インデックス</param>
''' <returns></returns>
''' <remarks></remarks>
Private Function ShowExcel(ByVal pIndex As Integer) As String
Dim rStr As String = ""
'Return control of Excel to the user.
objApp.Visible = True
objApp.UserControl = True

' EXCEL終了処理
If Not IsNothing(objBook(pIndex)) Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(objBook(pIndex))
objBook(pIndex) = Nothing
End If

If Not IsNothing(objBooks(pIndex)) Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(objBooks(pIndex))
objBooks(pIndex) = Nothing
End If

If Not IsNothing(objApp) Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(objApp)
objApp = Nothing
End If
Return rStr
End Function

表示します。
このエクセルに対して、新規にファイルを作成し変更しても、保存メッセージが表示されません。
■No27577に返信(akitoさんの記事)
> エクセル出力した際、そのエクセルのプロセスで 
> 別ファイルをオープンし、変更−クローズをした際に、確認メッセージが 
> 表示されずに、閉じられる。 
起動処理などが省かれていて、全体像が見えないのでなんとも言えませんが、
思いつくところでは DisplayAlerts が False になっているとか、
Excel のオブジェクト解放が十分ではなく、それが問題の原因となっているとか。


> これは、なぜなんでしょう?
コードの意図が読めとれなかったので、そもそも、このプログラムに
どのような処理をさせたいのかが分かりませんでした…。

なので、少し逆質問させてください。


>     Return rStr
> End Function
Function SaveData や Function ShowExcel では、Return されている
変数 rStr が特に使用されていないため、これらのメソッドは
常に空文字列を返すことになりますが、この戻り値の意図は何でしょうか?


> ''' <remarks>作成したエクセルファイルの内容を保存します。</remarks>
> Public Function OutputExcel(ByVal fName) As String
引数のデータ型が記載されていません。As 句をつけましょう。

また、上記の処理は「名前を付けて保存」ダイアログでファイル名を
決めさせているだけで、肝心の保存処理が含まれていませんよね。
実際には、どのようにしてファイルを保存させているのでしょうか?


> Private Function SaveData(ByVal pIndex) As String
>     Dim rStr As String = ""
>     objApp.Calculation = xlAutomatic
ここでいう objApp とは、Excel の Application クラスでしょうか?

>     objBook(pIndex).Save()
SaveAs での「名前を付けて保存」ではなく、
Save での「上書き保存」を使っておられますが、
ここのファイル保存処理は、Function OutputExcel で用意した
ファイル名とは無関係なのでしょうか?
■No27578に返信(魔界の仮面弁士さんの記事)
> 起動処理などが省かれていて、全体像が見えないのでなんとも言えませんが、
> 思いつくところでは DisplayAlerts が False になっているとか、
> Excel のオブジェクト解放が十分ではなく、それが問題の原因となっているとか。

DisplayAlerts が Falseになっています。
ただ、処理の内容としては、

帳票用のテンプレート用のエクセルがあり、それをコピーし、
コピーしたものを開き、編集して、最後に表示させます。



> Function SaveData や Function ShowExcel では、Return されている
> 変数 rStr が特に使用されていないため、これらのメソッドは
> 常に空文字列を返すことになりますが、この戻り値の意図は何でしょうか?

戻り値に意味はないようです。
最上層のFunctionで、Exceptionとしてエラーはキャッチしています。

>>''' <remarks>作成したエクセルファイルの内容を保存します。</remarks>
>>Public Function OutputExcel(ByVal fName) As String
> 引数のデータ型が記載されていません。As 句をつけましょう。
はい、付けます。


> また、上記の処理は「名前を付けて保存」ダイアログでファイル名を
> 決めさせているだけで、肝心の保存処理が含まれていませんよね。
> 実際には、どのようにしてファイルを保存させているのでしょうか?

''' <summary>
''' 保存
''' </summary>
''' <returns></returns>
''' <remarks>作成したファイルを保存します。</remarks>
Public Function Temp_SaveData() As String
Return SaveData(C_New)
End Function

で、
''' <summary>
''' エクセルの保存
''' </summary>
''' <param name="pIndex">インデックス</param>
''' <returns></returns>
''' <remarks></remarks>
Private Function SaveData(ByVal pIndex) As String
Dim rStr As String = ""
objApp.Calculation = xlAutomatic
objBook(pIndex).Save()
Return rStr
End Function

を呼びだし、保存しています。

>>Private Function SaveData(ByVal pIndex) As String
>> Dim rStr As String = ""
>> objApp.Calculation = xlAutomatic
> ここでいう objApp とは、Excel の Application クラスでしょうか?

objApp = CreateObject("Excel.Application")
しています。

>> objBook(pIndex).Save()
> SaveAs での「名前を付けて保存」ではなく、
> Save での「上書き保存」を使っておられますが、
> ここのファイル保存処理は、Function OutputExcel で用意した
> ファイル名とは無関係なのでしょうか?

このファイル名のファイルは最終的には、表示された状態になっています。
■No27579に返信(akitoさんの記事)
> DisplayAlerts が Falseになっています。

であれば、(保存確認などの)アラートは表示されません。
表示させるなら、True に戻しては不味いのでしょうか?


> 帳票用のテンプレート用のエクセルがあり、それをコピーし、
> コピーしたものを開き、編集して、最後に表示させます。

現状のコードの全体像が見えないので憶測ですが、もしも
  *.xls ファイルをコピー → コピーした xls を Workbooks.Open
という処理を行っているのであれば、
  *.xlt ファイルを Workbooks.Add
に変更してみてください。


*.xls を Workbooks.Add した場合にも同じような効果が得られますが、
テンプレートならば *.xlt の方が望ましいですね。
(2007/2010 だと、xls => xlsx、xlt => xltx)



> 戻り値に意味はないようです。
であれば、Function ではなく Sub の方が自然であるように思えます。


> を呼びだし、保存しています。
既存のファイルに対して Save しても、単に上書きされるだけです。
ファイル名を指定する必要があるなら、SaveAs を使ってください。

そのブックが未保存の場合は、Save でも「名前を付けて保存」の
効果がありますが、Workbooks.Open 等で開いたファイルの場合は、
単に上書き保存されるだけです。
■No27580に返信(魔界の仮面弁士さんの記事)
> であれば、(保存確認などの)アラートは表示されません。
> 表示させるなら、True に戻しては不味いのでしょうか?

 これをすると、テンプレートのxlsをCloseする際に確認メッセージが
 表示されていしまします。
 出力xlsは、そのまま表示したままでプログラムは終了するので。
 この出力xlsに対して、アラーとをtrueにして保存したいのですが、
 今のつくりでは、無理があるのでしょうか。。。
■No27581に返信(akitoさんの記事)
> これをすると、テンプレートのxlsをCloseする際に確認メッセージが
> 表示されていしまします。
処理の流れが見えていないのですが、テンプレートが
どのように扱われているのかを教えてもらえますか?

それによって、行うべき処理も変わってくるでしょうし。


私のイメージでは、

 (1) テンプレートは、"template.xlt"
 (2) Workbooks.Add で、未保存の Temlate1 ブックが生成される(ファイル名なし)。
 (3) そのブックを加工。
 (4) Save メソッドを呼び、ユーザーにファイル名を付けさせる。

だったのですが、xls ファイルを「テンプレート」と呼んでいる時点で、
この認識は違っていたようですね。


ということは、

 (1) テンプレートは、"template.xls"
 (2) 作業前に、それをコピーして "book1.xls" ファイルを作る。
 (3) そのファイルを Workbooks.Open で開いて加工。
 (4) Save メソッドを呼び、ユーザーにファイル名を付けさせる。

あるいは、
 (1) テンプレートは、"template.xls"
 (2) それを Workbooks.Open で開く。
 (3) さらに、空の新規ブックを Workbooks.Add する。
 (4) (2) のブックの内容をコピーしながら (3) を加工していく。
 (5) (2) のブックは不要になったので、未保存で(ユーザー応答なしで)終了。
 (6) (3) のブックでは、Save メソッドを呼び、ユーザーにファイル名を付けさせる。

といったところなのでしょうか…?


> これをすると、テンプレートのxlsをCloseする際に確認メッセージが
> 表示されていしまします。
保存させたくないのでしょうか、保存させたいのでしょうか。

保存させたいなら、テンプレートブックに対して、
Save メソッド(上書き保存)または SaveAs メソッド(別名保存)を呼びましょう。

保存させずに Close させたいなら、テンプレートブックの
Saved プロパティに True を代入してから Close しましょう。
(このプロパティは、VB の TextBox.Modified プロパティのようなものです)


>  この出力xlsに対して、アラーとをtrueにして保存したいのですが、
>  今のつくりでは、無理があるのでしょうか。。。
「アラートを True にする」ということは、アラートを表示させたいという意味ですね?

DisplayAlerts を False にすると、アラートが表示されなくなり、
DisplayAlerts を True にすると、アラートが表示されるようになります。

ただしファイル保存については、
 ・保存済みのブックなら、DisplayAlerts に関係なく、終了時に保存確認されない。
 ・Saved = True 状態のブックなら、DisplayAlerts に関係なく、終了時に保存確認されない。
 ・DisplayAlerts が何であれ、Excel.Dialog オブジェクト経由でのダイアログ表示は可能。
 ・DisplayAlerts が False でも、未保存ブックに対する Save メソッドではユーザー応答が必要。
 ・DisplayAlerts が False で未保存ブックを Close すると、変更は保存されない。
のように動作します。
http://officetanaka.net/excel/vba/file/file03.htm

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