tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルExcelのシートをコピーしたときのセルの表示書式
記事No6880
投稿日: 2008/01/23(Wed) 20:32
投稿者す〜
お世話になります。
VBからExcelのシートをコピーしたときにセルの書式設定が変わる現象が起きて困っております。環境は以下のようになります。

環境>
WindowsXP SP2
VB2005
Excel2003

VBからExcelファイルのシートを同ブック内に複数枚コピーし、各シートに値を代入してから別名をつけてExcelファイルを保存しております。そのときに、コピーしたシートのセル(日付が入力されています)の表示形式が変わってしまいます。元の表示形式はユーザ定義で設定しており、コピーしたシートの同じセルと変わっていました。

元シートの表示形式       → コピーしたシートの表示形式
「yyyy"年"mm"月"dd"日"」 → 「yyyy"年"m"月"d"日"」
「yyyy/mm/dd」           → 「yyyy/m/d」

調べてみたところ、以下のこと(少しですが)はわかりました。

1.Excel上で手動でシートコピーしても現象は起きない。
2.Excel上でマクロを使用しても現象は起きない。
3.VBでシートをコピーすると現象は起きる。
4.セルの書式設定を確認すると、ユーザ定義から元の表示形式は削除されていない

とりあえず現在は、シートをコピーした後、対象セルの表示形式を変更して対処していますが、原因・他の対処方法をご存知の方はご教授くださいm(__)m

[ツリー表示へ]
タイトルRe: Excelのシートをコピーしたときのセルの表示書式
記事No6881
投稿日: 2008/01/23(Wed) 22:04
投稿者花ちゃん
>原因・他の対処方法をご存知の方はご教授くださいm(__)m

と言われても現在どのようなコードでコピーされているの投稿されないと
他の方法かどうかも解らないし、原因だって。

私が試した限りでは書式事コピーできてましたが。

[ツリー表示へ]
タイトルRe^2: Excelのシートをコピーしたときのセルの表示書式
記事No6883
投稿日: 2008/01/24(Thu) 09:23
投稿者す〜
花ちゃんさん、ありがとうございます。そして、失礼いたしました。
職場外からでコードが書き込めませんでした。
以下がコードになります。
なお、元となるExcelファイルは前もってご用意ください。


Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim xlApplication As New Excel.Application()
        Dim xlInBooks As Excel.Workbooks
        Dim xlInBook As Excel.Workbook
        Dim i As Integer

        Try
            'Excelファイル(C:\Test_moto.xls)のSheet1の各セルには前もって値"2008/1/1"を代入しておき
            '[セルの書式設定]-[表示形式]で以下のように設定し保存しておく。
            'A1 = 未設定
            'A2 = 日付:yyyy/m/d
            'A3 = 日付:yyyy年m月d日
            'A4 = ユーザ定義:yyyy年mm月dd日
            'A5 = ユーザ定義:yyyy年m月d日
            'A6 = ユーザ定義:yyyy/mm/dd

            xlApplication.DisplayAlerts = False
            xlApplication.ScreenUpdating = False

            '元になるExcelファイルを開く
            xlInBooks = xlApplication.Workbooks
            xlInBook = xlInBooks.Open("C:\Test_moto.xls")

            'シートコピー
            For i = 1 To 9
                Call CE_ExcelSheetCopy(xlInBook, 1, i, False)
            Next

            'ファイルを別名で保存
            xlInBook.SaveAs("C:\test.xls")

            xlApplication.DisplayAlerts = True
            xlApplication.ScreenUpdating = True

            'COMオブジェクトを解放
            COM_MRComObject(xlInBook)
            xlInBooks.Close()
            COM_MRComObject(xlInBooks)
            xlApplication.Quit()
            COM_MRComObject(xlApplication)

            MessageBox.Show("End", "Test", MessageBoxButtons.OK)

        Catch ex As Exception
            MessageBox.Show(ex.Message, "Err", MessageBoxButtons.OK)
        End Try
    End Sub

    '*-------------------------------------------------------------------*
    ' 【機  能】Excelのシートコピー
    ' 【引 き 数】xlBook : Excelワークブック
    '             SheetNoMoto : コピー元シート番号
    '             SheetNoIchi : コピー位置のシート番号
    '             BeforeOrAfter : コピー位置の前(True)or後ろ(False)
    ' 【返 り 値】-
    '*-------------------------------------------------------------------*
    Public Sub CE_ExcelSheetCopy(ByVal xlBook As Excel.Workbook, ByVal SheetNoMoto As Integer, ByVal SheetNoIchi As Integer, ByVal BeforeOrAfter As Boolean)
        Dim xlSheets As Excel.Sheets
        Dim xlSheetMoto As Excel.Worksheet
        Dim xlSheetIchi As Excel.Worksheet

        Try
            'シートを指定位置にコピーする
            xlSheets = xlBook.Worksheets
            xlSheetMoto = DirectCast(xlSheets.Item(SheetNoMoto), Excel.Worksheet)
            xlSheetIchi = DirectCast(xlSheets.Item(SheetNoIchi), Excel.Worksheet)
            If BeforeOrAfter = True Then
                xlSheetMoto.Copy(xlSheetIchi)
            Else
                xlSheetMoto.Copy(, xlSheetIchi)
            End If

            'COMオブジェクトの解放
            COM_MRComObject(xlSheetMoto)
            COM_MRComObject(xlSheetIchi)
            COM_MRComObject(xlSheets)

        Catch ex As Exception
            MessageBox.Show(ex.Message, "Err", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

    '*-------------------------------------------------------------------*
    ' 【機  能】COMオブジェクトの解放
    ' 【引 き 数】objCom : COMオブジェクト
    ' 【返 り 値】-
    '*-------------------------------------------------------------------*
    Public Sub COM_MRComObject(ByVal objCom As Object)
        Try
            If Not objCom Is Nothing AndAlso System.Runtime.InteropServices. _
                                                      Marshal.IsComObject(objCom) Then
                Dim I As Integer
                Do
                    I = System.Runtime.InteropServices.Marshal.ReleaseComObject(objCom)
                Loop Until I <= 0
            End If
        Catch
        Finally
            objCom = Nothing
        End Try
    End Sub
End Class

[ツリー表示へ]
タイトルRe^3: Excelのシートをコピーしたときのセルの表示書式
記事No6885
投稿日: 2008/01/24(Thu) 10:18
投稿者魔界の仮面弁士
# 本題以外の部分に反応。

> Do
>    I = System.Runtime.InteropServices.Marshal.ReleaseComObject(objCom)
> Loop Until I <= 0
VB2005 なのですよね?
強制解放が必要なら、FinalReleaseComObject を使った方が良いですよ。

ただ、通常は 1 回だけ呼び出せば良く、連続して解放する必要は無いはずです。
まして、常に(無条件に)最後まで解放してしまうのは、問題があるかと思います。

ReleaseComObject を複数回呼び出すのは、参照カウントが意図せず増加している場合など、
あくまで、限定条件下に限るようにしてください。
http://hpcgi1.nifty.com/MADIA/VBBBS2/wwwlng.cgi?print+200512/05120042.txt

最後まで強制的に解放すると、他の場所で参照しているオブジェクトまでも対象となるため
必要な解放までもが解放(オーバーリリース)されてしまい、弊害がでる事があります。

たとえば、呼び出し元の Button1_Click 側を修正して、
    Dim o As Excel.Worksheet = xlInBook.ActiveSheet
    TextBox1.Text = o.Name
    Call CE_ExcelSheetCopy(xlInBook, 1, i, False)
    TextBox2.Text = o.Name
のように書いた場合、CE_ExcelSheetCopy 内で強制解放を行っているが故に、
オーバーリリースにより、呼び出し元の変数 o の参照先まで解放されてしまい、
TextBox2.Text = o.Name の処理が失敗(InvalidComObjectException)することになります。

また、現コードのままでも、CE_ExcelSheetCopy(xlInBook, 1, 1, False) という
「xlSheetMoto と xlSheetIchi が同じシートを表していた場合」において、
   COM_MRComObject(xlSheetMoto)  '参照カウントが、2 から 0 になる
   COM_MRComObject(xlSheetIchi)  '参照カウントが、0 から -1 になる
という、オーバーリリースが実際に発生しています。

もし、解放処理を 1 回だけに留めておけば、両者が同じシートであった場合も
   COM_MRComObject(xlSheetMoto)  '参照カウントが、2 から 1 になる
   COM_MRComObject(xlSheetIchi)  '参照カウントが、1 から 0 になる
という動作になるので、このような問題は出ません。


> Finally
>     objCom = Nothing
> End Try
引数 objCom が ByVal である以上、この処理には意味がないと思います。

[ツリー表示へ]
タイトルRe^4: Excelのシートをコピーしたときのセルの表示書式
記事No6890
投稿日: 2008/01/24(Thu) 13:18
投稿者す〜
花ちゃんさん、魔界の仮面弁士さん、早々のお返事ありがとうございます。

魔界の仮面弁士さん、分かりやすいご指摘、ありがとうございます。
ご指摘にあったように修正しました。
Excelのプロセスが残っていないことに安心してしまっていました。

別のやり方を探ってみようと思います。
花ちゃんさん、魔界の仮面弁士さん、大変ありがとうございました。

[ツリー表示へ]
タイトルRe: Excelのシートをコピーしたときのセルの表示書式
記事No6884
投稿日: 2008/01/24(Thu) 09:35
投稿者花ちゃん
> 1.Excel上で手動でシートコピーしても現象は起きない。
> 2.Excel上でマクロを使用しても現象は起きない。

だったらその方法でコピーすれば問題がないはずでは。

> 3.VBでシートをコピーすると現象は起きる。

マクロで記録した内容の方法と異なる事をしているからでは。
前回も書きましたが、私がマクロを取ってそれを使ってVBから実行した場合には
書式もコピーされました。

まず、シンプルなコードを書いて試して見て下さい。
それで問題がなければ関数化するなりして下さい。

[ツリー表示へ]