【先着1,000名様!】1,000円分をプレゼント!

VBScriptにおいて、Win32API関数のGetWindowTitleをExcel経由で使用したいと考えております。
そこで、ネットで検索したところ、VBScriptからAPI関数の指定の引数の値を取り出す方法がありました。
https://blogs.yahoo.co.jp/nobuyuki_tsukasa/53646 …

この情報を基に、最前面画面のウィンドウタイトルを取得する下記サンプルコードを作成して実行したたところ、下段から3行目のところで、下記のエラーが出てしまいます。

コード:
Option Explicit

Dim AppExcel
Dim myHwnd
Dim myFixCaption
Dim myCaption
Dim strMacro
Dim ret

Set AppExcel = CreateObject("Excel.Application")

'最前面のウィンドウのウィンドウハンドルを取得
strMacro = "CALL('user32', 'GetForegroundWindow', 'J'" & ")"
strMacro = Replace(strMacro, "'", """")
myHwnd = AppExcel.ExecuteExcel4Macro(strMacro)

'タイトルの取得
'GetWindowText myHwnd, myFixCaption, Len(myFixCaption)
myFixCaption = Space(255)
strMacro = "CALL('user32', 'GetWindowText', '2JCJ', " & CStr(myHwnd) & ", '" & myFixCaption & "', " & Len(myFixCaption) & ")"
strMacro = Replace(strMacro, "'", """")
myFixCaption = AppExcel.ExecuteExcel4Macro(strMacro) '←ここで下記エラー発生
myCaption = Left(myFixCaption, InStr(myFixCaption, vbNullChar) - 1)

Set AppExcel = Nothing

エラー内容:
Application クラスの ExecuteExcel4Macro プロパティを取得できません。

環境:
OS;Windows10
Excel;Excel2013

どこがまずいのか、教えて下さい。

A 回答 (1件)

こんばんは。



引用先のブログは、開発を投げたものてしょうから、こちらに振っても同じになるには違いないでしょう。はっきりとどこがということがわかりませんし、どこを直しても、このままでは通らないです。ExecuteExcel4Macroの中の数式のパラメータに、null文字が使えないのかとも思いました。数式のカッコ閉じる、が認識しないのです。

"CALL('user32', 'GetWindowText', '2JCJ', " & CStr(myHwnd) & ", '" & myFixCaption & "', " & Len(myFixCaption) & ")"

それと、
myFixCaption = Space(255) -> myCaption = Left(myFixCaption, InStr(myFixCaption, vbNullChar) - 1) これでは、整合性が取れませんよね。

myFixCaption は、 String(255, Chr(0)) だとは思うのですが、それを入れてしまうと、こんどは、数式のカッコが閉じなくなってしまいます。

試しに、DynamicWrapper なら、かろうじて取得できました。DynamicWrapper は、イントールというか、最初に、簡単な regsvr32.exe のレジストレーションが必要になってしまいますので、好まれないとは思いますが。

'-----DynamicWrapper ---
'サンプル
Dim objDynaWrap
Dim hWnd
Dim buf1
Dim myCap

Set objDynaWrap = CreateObject("DynamicWrapper")
objDynaWrap.Register "USER32.DLL", "GetForegroundWindow" ,"r=l" , "f=s"
objDynaWrap.Register "USER32.DLL", "GetWindowText", "i=lrl","r=l", "f=s"
buf1 =Space(20)
buf1 =String(20,Chr(0)) '30ではダメでした。
hWnd = objDynaWrap.GetForegroundWindow()

ret =objDynaWrap.GetWindowText( hWnd, buf1, Len(buf1))
myCap = Replace(buf1,Chr(0),"")
'myCap = Left(buf1,InStr(buf1,Chr(0))-1)
WScript.Echo myCap
Set objDynaWrap = Nothing

'----------------------------
かろうじて取れると書いたのは、なんとなく、このプログラムには、その作り方そのものに論理的な矛盾があるような気がしたからです。一番上のアプリのタイトルを取るけれども、これが、単独で動かしたら自分自身(VBSファイル)である可能性が高いし、そうでなく、他のプログラムから行っても、そのためのアクティベートしてしまったアプリになるわけです。なお、"i=lrl" のパラメータは合っているかわかりません。

p.s. Excelのバージョンの2013以降は、私の記憶では、オートメーションとして別起動しませんから、あえてExcelを使おうとしても、本体を使うのと同じになってしまうはずです。完全な独立プログラム・アプリを作るなら、Excelは使わないほうが良いのかもしれませんね。
    • good
    • 0
この回答へのお礼

WindFaller様

こんばんわ。
新年早々ご回答頂きまして、ありがとうございました。
ご指摘は非常に参考になりました。
API関数の使い方もわからずWebで検索しながら作ってみたものです。GetWindowText関数は、所定の長さの文字列を用意して置くと、呼出し後取得結果の文字列の最後にNull文字が付加されて返されるものと解していました。
いずれにしても、ExcecuteExcel4Macroでは、実現が難しそうなので、アドバイス頂いた方法等も参考にさせて頂き検討して行きたいと考えています。
なお、目的はVBScriptで表示されている画面の一覧を取得することです。

お礼日時:2019/01/03 22:00

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aと関連する良く見られている質問

QVBSでuser32.dll(Win32API)を使用する方法を教えてください。

はじめてネットで質問します。失礼があったらすみません。

VBSでマウスカーソルの座標を設定する方法を教えてください。
このサイトやあちこち検索してみましたが、VBでのやり方は見つかったのですがVBSでのやり方が見つからなくて心が折れてしまいました。

自分で調べた結果、user32.dll(Win32API )のSetCursorPos を使用する必要があるところまではなんとなく理解しましたがどうやってuser32.dllを使用できように宣言するのかが解りません。

宣言さえできれば

SetCursolPos 0,0

で画面左上にマウスカーソルが移動すると思っています。

この問題で会社と家で3日ほどはまってます。
ご回答よろしくお願い致します。

Aベストアンサー

こんにちは。

VBS から API を直接呼び出すことはできません。

  MSDN: [VBA の機能で VBScript に含まれていない機能]
  http://msdn.microsoft.com/ja-jp/library/cc392401.aspx

上記参考 URL は VBA に関するドキュメントですが、中段にある宣言の
項目にありますとおり、Declare ステートメントがサポートされていない
ためです。

  [SFC mini]
  http://kandk.cafe.coocan.jp/sfcmini/catid-19.html

または、

  [Dynacall] DynWrap.DLL ダウンロードページ(En)
  http://freenet-homepage.de/gborn/WSHBazaar/WSHDynaCall.htm
  [Dynacall] サンプル
  http://www.geocities.jp/seiotaq/DynaHP/index.html#three2

などの Dll をインストールして、そこを経由することになります。

私見ですが、新たなインストールを避けたい場合や面倒に感じるので
あれば Excel VBA を使った方が良いと思います。

こんにちは。

VBS から API を直接呼び出すことはできません。

  MSDN: [VBA の機能で VBScript に含まれていない機能]
  http://msdn.microsoft.com/ja-jp/library/cc392401.aspx

上記参考 URL は VBA に関するドキュメントですが、中段にある宣言の
項目にありますとおり、Declare ステートメントがサポートされていない
ためです。

  [SFC mini]
  http://kandk.cafe.coocan.jp/sfcmini/catid-19.html

または、

  [Dynacall] DynWrap.DLL ダウンロードページ(En)
  http:/...続きを読む

QADOで複数のBookから抽出

ADOで複数のBookから抽出
することは可能でしょう
例えば
With objCn
.Provider = "Microsoft.ACE.OLEDB.12.0"
.Properties("Extended Properties") = "TEXT;HDR=YES;FMT=Delimited"
.Open "C:\Users\Desktop\新しいフォルダー (4)"
End With

With objCn
.Provider = "Microsoft.ACE.OLEDB.12.0"
.Properties("Extended Properties") = "Excel 12.0"
.Open "C:\Users\Desktop\Test_1.xlsx"
End With

というかんじで

select とかで必要なデータをとりだす

Aベストアンサー

趣旨が「1個のクエリで複数のBookから」でなければ、複数のConnectionを使えばいいかと思います。
デスクトップのTest_1.xlsxのSheet1とデスクトップの新しいフォルダー (4)内のtest.csvの最初のレコードのフィールドの値を表示します。

Sub sample()
Dim cnn1 As Object
Dim cnn2 As Object
Dim desktop As String
Dim rs1 As Object
Dim rs2 As Object
Dim i As Integer

Set cnn1 = CreateObject("ADODB.Connection")
Set cnn2 = CreateObject("ADODB.Connection")
desktop = CreateObject("WScript.Shell").SpecialFolders("Desktop") & "\"
Set rs1 = CreateObject("ADODB.Recordset")
Set rs2 = CreateObject("ADODB.Recordset")

With cnn1
.Provider = "Microsoft.ACE.OLEDB.12.0"
.Properties("Extended Properties") = "TEXT;HDR=YES;FMT=Delimited;CSV"
.Open desktop & "新しいフォルダー (4)"
End With
Dim es1 As Object

With cnn2
.Provider = "Microsoft.ACE.OLEDB.12.0"
.Properties("Extended Properties") = "Excel 12.0 xml;HDR=YES"
.Open desktop & "Test_1.xlsx"
End With

rs1.Open "SELECT * FROM [test.csv]", cnn1
MsgBox rs1.Fields.Count
For i = 0 To rs1.Fields.Count - 1
MsgBox rs1(i)
Next

rs2.Open "SELECT * FROM [Sheet1$]", cnn2
MsgBox rs1.Fields.Count
For i = 0 To rs1.Fields.Count - 1
MsgBox rs1(i)
Next

rs1.Close
rs2.Close
cnn1.Close
cnn2.Close
End Sub





複数のデータベースを1つのクエリで処理する方法は知りませんが、このVBAがAccessのVBAか、Accessが使える状況のExcelなどのVBAなら、Accessのデータベースにリンクテーブルとして登録すれば、同一データベース内のテーブルとして処理できると思います。

趣旨が「1個のクエリで複数のBookから」でなければ、複数のConnectionを使えばいいかと思います。
デスクトップのTest_1.xlsxのSheet1とデスクトップの新しいフォルダー (4)内のtest.csvの最初のレコードのフィールドの値を表示します。

Sub sample()
Dim cnn1 As Object
Dim cnn2 As Object
Dim desktop As String
Dim rs1 As Object
Dim rs2 As Object
Dim i As Integer

Set cnn1 = CreateObject("ADODB.Connection")
Set cnn2 = CreateObject("ADODB.Connection")
desktop = CreateObject("WScript.Shell...続きを読む

QVBAでのExecuteExcel4Macroの値取得でエラー

こんにちは。
Excel VBAより、ExecuteExcel4Macroを実行して、
外部のExcelファイルの、名前(店名、月度)を定義したセルの値を取得したいと思っています。
店名:文字列型
月度:Date型

そこで、ExecuteExcel4Macro()を実行し、以下のような処理を加えました。

------------------------------------------------------------------------------------

dim 店名 as Variant, 月度 as Variant
If 外部マクロ実行("'c:\[test.xls]出勤簿'!店名", 店名) = False Or _
外部マクロ実行("'c:\[test.xls]出勤簿'!月度", 月度) = False Then
MsgBox "取得失敗", vbExclamation
End
End If


Public Function 外部マクロ実行(com As String, ByRef result As Variant) As Boolean
On Error GoTo erron3
result = ExecuteExcel4Macro(com)
On Error GoTo 0
外部マクロ実行 = True
Exit Function

erron3:
外部マクロ実行 = False
End Function

------------------------------------------------------------------------------------

これを実行したところ、「月度」の値は取得できるのですが、
「店名」の値には「エラー 2042」という値が入ります。
※dirname, filenameは正しい値が入っています。
※シート「出勤簿」および「月度」「店名」のセル名の定義も存在します。

test.xlsを開いてるときは、上記の現象は起こらず、
「店名」の値は正常に取得できます。


また、試しに、test.xlsを開き、
Worksheets("出勤簿").Range("店名")を実行すると、正常な値が取得できました。


まとめると、
・閉じたブックの、あるシートにある、セルに定義された名前を指定して
・ExecuteExcel4Macroで、文字列が入っている値を取得しようとした時、
・正常に値が取得できない
という現象に遭遇しています。

3日ほど調べているのですが、どうしても原因が分かりません。
解決策をお持ちの方、いらっしゃいましたらアドバイスを頂けると助かります。

環境:WindowsXP Pro SP3
Excel 2003 (11.5612.5606)

以上、よろしくお願いいたします。

こんにちは。
Excel VBAより、ExecuteExcel4Macroを実行して、
外部のExcelファイルの、名前(店名、月度)を定義したセルの値を取得したいと思っています。
店名:文字列型
月度:Date型

そこで、ExecuteExcel4Macro()を実行し、以下のような処理を加えました。

------------------------------------------------------------------------------------

dim 店名 as Variant, 月度 as Variant
If 外部マクロ実行("'c:\[test.xls]出勤簿'!店名", 店名) = False Or _
外部マクロ実行("'c:\[test....続きを読む

Aベストアンサー

'-------------------------------------------------
Sub Test()
 Dim 店名
 Dim 月度

 店名 = 外部マクロ実行("'C:\[test.xls]出勤簿'!店名")
 月度 = 外部マクロ実行("'C:\[test.xls]出勤簿'!月度")

   If 店名 = 0 Or 月度 = 0 Then
     MsgBox "取得失敗", vbExclamation
   Else
     MsgBox 店名 & " @ " & Format(月度, "yyyy/m/d")
   End If

End Sub
'-----------------------------------------------

Function 外部マクロ実行(com As String)
  外部マクロ実行 = ExecuteExcel4Macro(com)
End Function
'-----------------------------------------------


●ただ今回の場合は、Functionは無しでもいいような。。。

'----------------------------------------------
Sub Test555()
 Dim 店名
 Dim 月度

 店名 = ExecuteExcel4Macro("'C:\[test.xls]出勤簿'!店名")
 月度 = ExecuteExcel4Macro("'C:\[test.xls]出勤簿'!月度")

   If 店名 = 0 Or 月度 = 0 Then
     MsgBox "取得失敗", vbExclamation
   Else
     MsgBox 店名 & " @ " & Format(月度, "yyyy/m/d")
   End If

End Sub
'----------------------------------------------------

以上。

'-------------------------------------------------
Sub Test()
 Dim 店名
 Dim 月度

 店名 = 外部マクロ実行("'C:\[test.xls]出勤簿'!店名")
 月度 = 外部マクロ実行("'C:\[test.xls]出勤簿'!月度")

   If 店名 = 0 Or 月度 = 0 Then
     MsgBox "取得失敗", vbExclamation
   Else
     MsgBox 店名 & " @ " & Format(月度, "yyyy/m/d")
   End If

End Sub
'-----------------------------------------------

Function 外部マクロ実行(com As String)
  外部...続きを読む

Q起動済みのIEをハンドルから操作するには

既に起動済みのIEブラウザをWSH(VBS)などから、ハンドルを取得して
HTMLソース内のフォームに値をセット(Document forms elementなどで)
する事はできますでしょうか?
出来るとすれば、IEを捕まえて操作するには、どのようにすれば良い
でしょうか?

■補足
起動したIEは、自身のスクリプトからオブジェクトを生成したもの
では無く、ウインドウタイトルくらいしか解りません。

Aベストアンサー

とりあえず
Set ie = GetObject("", "InternetExplorer.Application")
Set ie = GetObject(, "InternetExplorer.Application")
のどちらかで取得できると思います。
Set ie = CreateObject("Shell.Application").Windows(0)
で取得する方法もあるらしいのですが、普通のフォルダもieとして認識してしまうため、純粋にieだけを取得する場合はチェックが必要だと思います。
取得したieでyahooで"おいしいラーメン"の検索結果の件数を表示します。
Sub sample()
Const READYSTATE_COMPLETE = 4
Dim ie As Object
Dim obj As Object
For Each obj In CreateObject("Shell.Application").Windows
If TypeName(obj.Document) = "HTMLDocument" Then
Set ie = obj
Exit For
End If
Next
If ie Is Nothing Then
MsgBox "ありません"
Exit Sub
End If
MsgBox "取得したieの情報" & vbCrLf & ie.LocationName & vbCrLf & ie.LocationURL & vbCrLf & TypeName(ie.Document)
ie.Navigate "www.yahoo.co.jp" 'yahooへ
Do While (ie.ReadyState <> READYSTATE_COMPLETE) Or ie.Busy: Loop '表示待ち
ie.Document.forms("sf1").elements("srchtxt").Value = "おいしいラーメン" '検索文字
ie.Document.forms("sf1").submit '検索
Do While (ie.ReadyState <> READYSTATE_COMPLETE) Or ie.Busy: Loop '表示待ち
If InStr(ie.Document.body.innertext, "に一致するウェブページは見つかりませんでした") > 0 Then
MsgBox "0件"
Else
MsgBox ie.Document.all("yschinfo").all(6).innertext & "件"
End If
Set ie = Nothing
End Sub

とりあえず
Set ie = GetObject("", "InternetExplorer.Application")
Set ie = GetObject(, "InternetExplorer.Application")
のどちらかで取得できると思います。
Set ie = CreateObject("Shell.Application").Windows(0)
で取得する方法もあるらしいのですが、普通のフォルダもieとして認識してしまうため、純粋にieだけを取得する場合はチェックが必要だと思います。
取得したieでyahooで"おいしいラーメン"の検索結果の件数を表示します。
Sub sample()
Const READYSTATE_COMPLETE = 4
Dim ie As Ob...続きを読む

QプログラミングVBAについてです。 やり方を教えて下さい。よろしくお願いいたします。

プログラミングVBAについてです。
やり方を教えて下さい。よろしくお願いいたします。

Aベストアンサー

何かの課題のようなので、ヒントのみです。

どこがわからないのかも不明で、単なる丸投げ的な質問になっちゃってますが、大きく分ければ
・設問の意味や考え方がわからない
 (プログラミング言語とは関係なくアルゴリズム等の理解の問題)
・コードを作成できない
 (プログラムのフローを考える力と、言語知識の問題)
のどちらなのでしょうね?(両方なのかも)

ひとまず、このあたりが参考になるかも?
(検索すれば他にもいろいろ見つかると思いますが)
長方形積分と台形積分の説明とコード(C言語)
https://www.vcssl.org/ja-jp/code/archive/0001/3000-integral-rectangular/
https://www.vcssl.org/ja-jp/code/archive/0001/3000-integral-rectangular/

VBAでの例
https://excelmath.atelierkobato.com/trapzoid/

おまけ(シンプソン法の例)
http://shimaphoto03.com/program/simpson-vba/

何かの課題のようなので、ヒントのみです。

どこがわからないのかも不明で、単なる丸投げ的な質問になっちゃってますが、大きく分ければ
・設問の意味や考え方がわからない
 (プログラミング言語とは関係なくアルゴリズム等の理解の問題)
・コードを作成できない
 (プログラムのフローを考える力と、言語知識の問題)
のどちらなのでしょうね?(両方なのかも)

ひとまず、このあたりが参考になるかも?
(検索すれば他にもいろいろ見つかると思いますが)
長方形積分と台形積分の説明とコード(C言語)
ht...続きを読む

QReDim

下記のコードを詳しく教えて
   
x2 = Range("C3:E5").Value

ReDim ans2(1 To 1, 1 To UBound(x2)) ←この部分の意味

    For i = LBound(x2, 2) To UBound(x2, 2)

      For j = LBound(x2) To UBound(x2)

       この部分の意味 → ans2(1, i) = ans2(1, i) + x2(j, i)

      Next j

    Next i

Aベストアンサー

全体として以下の様な動作をしています。
ans2(1,1) = Range("C3")~Range("C5")の合計を代入
ans2(1,2) = Range("D3")~Range("D5")の合計を代入
ans2(1,3) = Range("E3")~Range("E5")の合計を代入


> x2 = Range("C3:E5").Value

x2は、要素が行方向1~3、列方向1~3の二次元配列になります。
 x2(1,1)がC3セルの値
 x2(1,2)はD3セルの値
 …
 X2(3,3)がE5セルの値



> ReDim ans2(1 To 1, 1 To UBound(x2))

各列の合計を代入するans2は要素が行方向1~1,列方向が1~3の二次元配列の構成が必要となります。
その割り当てを行っています。



そして以下で各列の合計を計算しています。
> For i = LBound(x2, 2) To UBound(x2, 2)   '列方向の要素変化(1~3/C列~E列)
>   For j = LBound(x2) To UBound(x2)    '行方向の要素変化(1~3/3行~5行)
>     ans2(1, i) = ans2(1, i) + x2(j, i) '各列ごとに行の値を足しこむ
>   Next j
> Next i



試しに
 Range("A1:C1").Value = ans2
とすれば対応するセルに計算結果が表示されます。

全体として以下の様な動作をしています。
ans2(1,1) = Range("C3")~Range("C5")の合計を代入
ans2(1,2) = Range("D3")~Range("D5")の合計を代入
ans2(1,3) = Range("E3")~Range("E5")の合計を代入


> x2 = Range("C3:E5").Value

x2は、要素が行方向1~3、列方向1~3の二次元配列になります。
 x2(1,1)がC3セルの値
 x2(1,2)はD3セルの値
 …
 X2(3,3)がE5セルの値



> ReDim ans2(1 To 1, 1 To UBound(x2))

各列の合計を代入するans2は要素が行方向1~1,列方向が1~3の二次元配列の構成が必要となります...続きを読む

Qまちがっているところ

strSQL = " "
strSQL = strSQL & " SELECT "
strSQL = strSQL & " 商品コード, SUM(東京支店) AS TOKO"
strSQL = strSQL & " FROM"
strSQL = strSQL & " ( "
strSQL = strSQL & " SELECT "
strSQL = strSQL & " *"
strSQL = strSQL & " FROM"
strSQL = strSQL & " [3学期$] "
strSQL = strSQL & " UNION ALL "
strSQL = strSQL & " SELECT "
strSQL = strSQL & " *"
strSQL = strSQL & " FROM"
strSQL = strSQL & " [2学期$] "
strSQL = strSQL & " ) "
strSQL = strSQL & " GROUP BY 商品コード"
まちがっているところおしえてくれませんでしょうか

strSQL = " "
strSQL = strSQL & " SELECT "
strSQL = strSQL & " 商品コード, SUM(東京支店) AS TOKO"
strSQL = strSQL & " FROM"
strSQL = strSQL & " ( "
strSQL = strSQL & " SELECT "
strSQL = strSQL & " *"
strSQL = strSQL & " FROM"
strSQL = strSQL & " [3学期$] "
strSQL = strSQL & " UNION ALL "
strSQL = strSQL & " SELECT "
strSQL = strSQL & " *"
strSQL = strSQL & " FROM"
strSQL = strSQL & " [2学期$] "
strSQL = strSQL & " ) "
strSQL = strSQL & " GROU...続きを読む

Aベストアンサー

No.3です。

列数が一致しないとなっているならSheet構成がそれぞれで違うのではないですかね?(検証すると確かに列数が違うとエラーになる)

その場合それぞれのSheetでSELECTしたいフィールドを明確にする為に

strSQL = " "
strSQL = strSQL & " SELECT "
strSQL = strSQL & " 商品コード, SUM(東京支店) AS TOKO"
strSQL = strSQL & " FROM"
strSQL = strSQL & " ( "
strSQL = strSQL & " SELECT "
strSQL = strSQL & " 商品コード,東京支店" '★
strSQL = strSQL & " FROM"
strSQL = strSQL & " [3学期$] "
strSQL = strSQL & " UNION ALL "
strSQL = strSQL & " SELECT "
strSQL = strSQL & " 商品コード,東京支店" '★
strSQL = strSQL & " FROM"
strSQL = strSQL & " [2学期$] "
strSQL = strSQL & " ) AS 合計"
strSQL = strSQL & " GROUP BY 商品コード"

とフィールド名を記載したらエラーは消えましたよ。

No.3です。

列数が一致しないとなっているならSheet構成がそれぞれで違うのではないですかね?(検証すると確かに列数が違うとエラーになる)

その場合それぞれのSheetでSELECTしたいフィールドを明確にする為に

strSQL = " "
strSQL = strSQL & " SELECT "
strSQL = strSQL & " 商品コード, SUM(東京支店) AS TOKO"
strSQL = strSQL & " FROM"
strSQL = strSQL & " ( "
strSQL = strSQL & " SELECT "
strSQL = strSQL & " 商品コード,東京支店" '★
strSQL = strSQL & " FROM"
strSQL = strSQL & " [3学期$] "
...続きを読む

QVBA ReDim と ReDim Preserve の速度差

Public Sub Test(SourceRange As Range, TargetRange As Range)
Dim ResultArray() As Variant
' ここから

' ここまでに該当処理
TargetRange = ResultArray
End Sub

2次元配列について
ReDimで大きな配列を作って1行ずつ代入してからセルに貼り付けるのと、
ReDim Preserveで配列を1行ずつ少しづつ追加してからセルに貼り付けるのと、
5000×5000くらいだとどちらが速いですか?

私のPCだと性能不足で測定困難です。
代わりに試して頂けると助かります。

Aベストアンサー

VBA(MicrosoftのBasic)でRedimすると、配列を増減するのではなく、新たな場所に新しい大きさのメモリを確保して、配列の参照先を変えます。
今までの配列の本体は参照元が無くなるので、空いた時間に削除されます。
ReDim Preserve は、既存のデータをコピーするので、更に時間がかかります。
なので、頻繁にReDim Preserveすると、メモリの確保とデータのコピーと不要になった配列の掃除のために大忙しになるので、やめた方がいいと思います。
これは文字列の追加でも起こるので、文字列の追加も気を付けた方がいいと思います。

それとVariantはどの型になるか不明なので、1データ16バイトの大きさが必要です。
普通の変数ならあまり気にする必要はありませんが、大きな配列だと、不要にメモリを消費します。
ReDim Preserveも要素数が同じでも他の型の変数と違って、大きなメモリのなるので時間がかかる可能性が高くなります。
例えばIntegerなら2バイトなので、必要なメモリは1/8になり、速度も上がります。

ただし、今のExcelは32ビットで動いているのでLongの場合メモリは1データ4バイト必要ですが、全体の処理は速いかもしれません。

とりあえず、Redimは出来るだけしない方がいいと思います。
ReDim Preserveは更に時間がかかります。

VBA(MicrosoftのBasic)でRedimすると、配列を増減するのではなく、新たな場所に新しい大きさのメモリを確保して、配列の参照先を変えます。
今までの配列の本体は参照元が無くなるので、空いた時間に削除されます。
ReDim Preserve は、既存のデータをコピーするので、更に時間がかかります。
なので、頻繁にReDim Preserveすると、メモリの確保とデータのコピーと不要になった配列の掃除のために大忙しになるので、やめた方がいいと思います。
これは文字列の追加でも起こるので、文字列の追加も気を付けた方がい...続きを読む

Q続 こっちもするーしちゃったよぉ

こんばんは

先ほどと同様な質問かもしれませんが、

yahooからオークションサイトをクリックするというものですが
そのなかの処理でオークションリンククリック後 While doc.getelementsbytagname("body").Length <= 0でBODYのレングスが1になるまでループさせるというものですが、
ウオッチウインドウには変数なしでendsub 終了しました。

ただし、①の場所に(wait) 
Application.Wait [Now() + "0:00:01.9"]をつけ再度実行すると
正しく処理されるようになりました。(変数なし→値が入っている)

これは、doc.Links(i).Click後処理が早くてdocumnetオブジェクトが作られていないから
なのでしょうか?


Sub ie_test()

Dim objIE As Object 'IEオブジェクト参照用
'
Set objIE = CreateObject("InternetExplorer.application")
objIE.Visible = True
objIE.Navigate "http://www.yahoo.co.jp"

Do While objIE.busy = True Or objIE.ReadyState < READYSTATE_COMPLETE '表示完了待ち

DoEvents

Loop

While objIE.document.ReadyState <> "complete"

Debug.Print objIE.document.ReadyState&; "naka1"

DoEvents

Wend

Dim doc As Object
Set doc = objIE.document

For i = 0 To doc.Links.Length - 1
If doc.Links(i).innertext = "ヤフオク!" Then

doc.Links(i).Click
'Application.Wait [Now() + "0:00:01.9"] '①これをいれるとうまくいく
While doc.getelementsbytagname("body").Length <= 0
Debug.Print objIE.busy
Wend
Exit For
End If
Next

End Sub

こんばんは

先ほどと同様な質問かもしれませんが、

yahooからオークションサイトをクリックするというものですが
そのなかの処理でオークションリンククリック後 While doc.getelementsbytagname("body").Length <= 0でBODYのレングスが1になるまでループさせるというものですが、
ウオッチウインドウには変数なしでendsub 終了しました。

ただし、①の場所に(wait) 
Application.Wait [Now() + "0:00:01.9"]をつけ再度実行すると
正しく処理されるようになりました。(変数なし→値が入ってい...続きを読む

Aベストアンサー

こんばんは。
>これは、doc.Links(i).Click後処理が早くてdocumnetオブジェクトが作られていないからなのでしょうか?

あまり関係ないようです。Clickしたらおそらくステージが変わるのです。
裏技というか、IEイベントにして、変化する場所を監視して、変化した瞬間に次の動作に移る方法もあるのですが、おなじみの
 Do While objIE.Busy Or objIE.ReadyState <> 4: DoEvents: Loop
を一つ入れるだけで劇的に変わるはずです。

具体的には、こんな感じです。実際に動かしていませんから、正確にできるかはこの場では確かめられません。

Dim doc As Object
Set doc = objIE.Document

For i = 0 To doc.Links.Length - 1
 If doc.Links(i).innerText = "ヤフオク!" Then
  doc.Links(i).Click ←リンク先だったら、URLを取って、.Navigate2 URLでもよい

  Do While objIE.Busy Or objIE.ReadyState <> 4: DoEvents: Loop
  '(このように1行にまとめたほうが見やすいです。)
'画面の切り替わりを待ちます。
  'そして、必要に応じて、
  Set doc =objIE.Document を改めて取得しなおします。 <=これを活かすには、ループを抜けるしかありません。
''以下の場合のdoc は、一度しか取っていないので、何回やっても、変わらないです。
'× While doc.getelementsbytagname("body").Length <= 0
  Exit for
  Loop
End If
Next

こんばんは。
>これは、doc.Links(i).Click後処理が早くてdocumnetオブジェクトが作られていないからなのでしょうか?

あまり関係ないようです。Clickしたらおそらくステージが変わるのです。
裏技というか、IEイベントにして、変化する場所を監視して、変化した瞬間に次の動作に移る方法もあるのですが、おなじみの
 Do While objIE.Busy Or objIE.ReadyState <> 4: DoEvents: Loop
を一つ入れるだけで劇的に変わるはずです。

具体的には、こんな感じです。実際に動かしていませんから、正確にできるかはこの...続きを読む

Qこんばんは。いつもお世話になっております。 数値が任意の数ある場合に小さい順に並び替える処理をvba

こんばんは。いつもお世話になっております。

数値が任意の数ある場合に小さい順に並び替える処理をvbaで作成したいですが、どなたか教えて頂けないでしょうか?

どうぞ宜しくお願い致します。

Aベストアンサー

No2のレイアウトの画像です。


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング