Excel (VBA)

Excel VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 11全般 : Microsoft 365)
画像を選択してコピーするコードが安定して動作しない
投稿日時: 23/11/05 10:30:01
投稿者: keightofsheep

やりたいこと:
大量にあるリンクされた画像を埋め込み画像に変えたいです。
検索したところ、画像をコピー→貼り付けでリンクが切れるということを知り、実際にその方法でできることを確認しています。
  
困っていること:
下記コードが安定して動作してくれません。
問題なく処理してくれるときもあれば、「pic.select」のところで「オブジェクトが必要です」となるときもあり、なぜこのエラーが出てしまうのかがわからない状況です。
体感では10回に1回成功するかどうかぐらいで、エラーがでるときのほうが圧倒的に高いです。
このコードを大量のブックに対して実行したいため、毎回複数回トライするという手法は取りたくありません。
pic.Selectを消すと、pic.Copyのところでエラーが出ます。
変数は省略していますが全て宣言しています。
 

Set MainXl = Workbooks.Open(処理したいブック)
Set MainSheet = MainXl.Sheets(処理したいシート番号)

i = 1

For Each pic In MainSheet.Shapes

    '埋め込みファイルだったらスキップ。ここでエラーが出たことはない
    If pic.Type = msoEmbeddedOLEObject Then
        GoTo skipLoop
    End If
	
    Set oriPicCell = pic.TopLeftCell 'ここでもエラーはでない

    'それ以外の画像はコピーしてPNG貼り付け
    pic.select 'エラーが出るときは必ずここで出る
    pic.Copy
    oriPicCell.Select
    MainSheet.PasteSpecial Format:="Picture (PNG)", link:=False
    pic.Delete

    i = i + 1

skipLoop:     '埋め込みファイルはここまでスキップ

Next

End Sub

回答
投稿日時: 23/11/05 14:18:15
投稿者: WinArrow

エラーになった場合は、
「エラー」の番号と、エラーメッセージを説明することが重要です。
 
変数の定義を掲示してみてください。
 
特に
PIC
が気になります。
エラーになった時の
PiC.Type
も説明しましょう。

回答
投稿日時: 23/11/05 14:48:55
投稿者: WinArrow

当該シートの中に
セルのコメントや入力規則は存在しますか?

回答
投稿日時: 23/11/05 16:41:47
投稿者: WinArrow

PIC.Type
について、再度確認してみてください。
 
msoLinkedPicture    11    リンク画像
msoPicture     13    画像
msoEmbeddedOLEObject    7    埋め込み OLE オブジェクト(例.Word文書)
msoLinkedOLEObject    10    リンク OLE オブジェクト(例.Word文書)
 
 

投稿日時: 23/11/06 00:08:54
投稿者: keightofsheep

変数は以下です。
Option explicitを使用しており、他のモジュールでも同じ変数を使用しているので定義には問題ないものと思っています。
Public MainXl as Workbook
Public MainSheet as worksheet
Public pic as shape
Public oriPicCell as range
 
エラーの番号は今手元で確認できないのですが、エラーメッセージは質問に記載の通り「オブジェクトが必要です」とだけ出てきます。
 
Pic.typeは11のものと7のものがあり、7のものは「If pic.Type = msoEmbeddedOLEObject〜」でスキップできることを確認しております。
埋め込みオブジェクトのアイコン画像は置き換えてほしくないので、これは期待通りの動きです。
 
エラーが起きるpicのtypeを確認しようとしてpic.Selectの前にdebug.print pic.typeを入れても、エラーが起きるときはこの「debug.print pic.type」で同じエラーが起きてしまうので充分に確認はできていない状況ですが、処理前のファイルの画像はいずれもtype11と7しかない(そして7のものはskipLoopに飛ばされている)ので、エラーが起きている画像はtype11と想定しています。
 
セルのコメントや、入力規則は設定していません。
 
一番の疑問は、前行のSet oriPicCell = pic.TopLeftCellでエラーが起きていないことです。
picのオブジェクトがないのであれば、このpic.TopLeftCellでエラーが出そうなものですが、ここで止まったことはありません。
debu.print oriPicCell.Addressでも正しくセル番号をprintします。

回答
投稿日時: 23/11/06 07:36:10
投稿者: WinArrow

>エラーが起きている画像はtype11と想定しています。
 
想定ではなく、ステップ実行すれば、ローカルウィンドウで確認できます。
 
それから、エラー番号は、エラーメッセージと一緒に表示されています。
 
実体ファイルが存在するのかも確認してみましょう。

投稿日時: 23/11/06 10:05:23
投稿者: keightofsheep

エラーコードとメッセージは以下でした。
「実行時エラー424: オブジェクトが必要です。」
 
>実体ファイルが存在するのかも確認してみましょう。
こちらではっとしたのですが、今回処理するExcelはすべてクラウド上にあり、現在の保管フォルダではリンクが切れた状態にあるため、実際のマクロの処理としてはリンクが切れていない(画像が正しく表示される)フォルダに移動してから画像の置き換え処理を行っています。
もしかしたらファイル位置移動→アップロード等の関係で画像へのアクセスが追い付いていないのに処理を実行しようとしてしまっているのかもしれません。
一度移動等をすべて完了させてから一括処理というのを試してみます。

回答
投稿日時: 23/11/06 10:38:54
投稿者: WinArrow

ローカル環境ですが、
リンク画像ファイルを移動した場合、または、ファイル名ヲ変更した場合のテストをしてみました。
 
Excelファイルを開いたときに
図のリンクが切れてしまい、画像が正常に表示されていません。
 
VBAで、
Set PIC = Activesheet.Shapes(1)
PIC.Select
 
↑の2行は正常に動作します。エラーにはなりません。
PIC.Type : msoLinkedPicture で正常に取得できます。
 
画僧ファイルのリンク切れとは関係ないような感じです。

回答
投稿日時: 23/11/07 11:57:44
投稿者: gombohori

 >「debug.print pic.type」で同じエラーが起きてしまう
 って書いてありますが、
  If pic.Type = msoEmbeddedOLEObject Then
        GoTo skipLoop
    End If
 ここが通るのに、
 debug.print pic.type
 ができないっておかしくないですか?
 提示されているコードなにか省略してませんか?
 
 If pic.Type = msoEmbeddedOLEObject Then
 と
 debug.print pic.type
 の間にpicがdeleteされている?

投稿日時: 23/11/07 19:39:51
投稿者: keightofsheep

本件、解決しました!
 
原因:
エクセルを移動後、リンク先へのアクセスが追い付いていないことによりリンクが切れた状態で処理を行おうとしていたためでした。
 
画像へのリンクのフォーマットが「Excelが入っているフォルダ直下の画像フォルダへのリンク」となっていたのでもともとリンクが切れていた(@)のを、Excelを移動してリンクがつながっている状態にする(A)→コピペ処理という構成になっていたのですが、クラウド上での処理であったため移動→アップロードされる&ファイルを開いた際に画像が表示される、というのがマクロの実行速度に追いついておらず、リンクが切れた表示(実態のない状態)のままでcopy等が処理されておりました。
 
@もともとのファイル構成
Folder A
 - Excel Aがリンクしている画像フォルダA
Folder Excel
 - Excel A <-この状態ではリンクが切れている
 
 
A移動処理後のファイル構成
Folder A
 - Excel Aがリンクしている画像フォルダA
 - Excel A <-リンクがつながって画像が表示される
 
 
解決策:
・Excelファイルの移動は先行して実施しておくことでアップロード中のコピー処理とならないようにした
・↑を行ってもファイルを開いてから画像が表示されるまでにラグが発生してロード中みたいな画像をコピペしてしまうので、
Set MainSheet = MainXl.Sheets の次の行に
Application.Wait Now() + TimeValue("00:00:05") で画像がロードされる時間を設ける
 
これでほぼ問題は起きなくなりました。
重い画像があるのか、これでも数10件に1件のExcelファイル内の画像数10個に1個あたりは実体がないままコピーしてしまうようですが、件数が少ないので手動で処理できる範囲と判断しました。
 
WinArrowさんの「実体ファイルが存在するのか」というご指摘で気づけました。
ありがとうございました。
 
(gonbohoriさんのご指摘のpic.typeについては、エラー修正しようといろいろいじっている際にご指摘の通り画像の削除等も試みていたのが誤って残ってしまっていたことによるもので、もともとの問題とは関係ありませんでした。混乱させてしまいすみません)