• 締切済み

Excel VBA ParamArray 可変個引数の渡し方

Excel VBAで 可変個引数関数Fanc1から、その引数を 可変個引数関数Fanc2に渡したい。 下記例では、A1=a, B1=b, C1=cのとき、#VALUE!となります。  Concatenate2(A1:B1,C1,"po")="abcpo" 問題無し  Fanc1(A1:B1,C1,"po")=#VALUE! Fanc1でも上と同じ出力にしたいのです。 Function Concatenate2(ParamArray MyArray()) As String Dim S As String Dim v As Variant Dim c As Variant For Each v In MyArray If TypeName(v) = "Range" Then For Each c In v S = S & c.Value Next Else S = S & v End If Next Concatenate2 = S End Function Function Fanc1(ParamArray MyArray()) As String Fanc1 = Concatenate2(MyArray()) End Function

みんなの回答

  • noah7150
  • ベストアンサー率46% (116/251)
回答No.2

今回の条件で直接Concatenate2を呼び出した場合 MyArray()は3個の配列で渡されますが Fanc1経由で呼び出された場合のConcatenate2での MyArray()は1個の配列です この1個の配列の中身が配列で渡されます。 なので1個の配列引数を持つ共通的な関数で展開する形にするのが妥当かと ただ、ParamArrayは特殊な配列のようでそのまま他の関数に渡そうとするとエラーになるため別な配列に複写して渡さないと動作しませんでした ただ、共通関数の受取をParamArrayにするとエラーにならないので下記 の2通りの方法を考えました。 Function ComFunc(MyArray As Variant) As String Dim S As String Dim v As Variant Dim c As Variant For Each v In MyArray If TypeName(v) = "Range" Then For Each c In v S = S & c.Value Next Else S = S & v End If Next ComFunc = S End Function Function Concatenate2(ParamArray MyArray()) As String Dim wArray() wArray = MyArray Concatenate2 = ComFunc(wArray) End Function Function Fanc1(ParamArray MyArray()) As String Dim wArray() wArray = MyArray Fanc1 = ComFunc(wArray) End Function 若しくは Function ComFunc(ParamArray MyArray()) As String Dim S As String Dim v As Variant Dim c As Variant For Each v In MyArray(0) If TypeName(v) = "Range" Then For Each c In v S = S & c.Value Next Else S = S & v End If Next ComFunc = S End Function Function Concatenate2(ParamArray MyArray()) As String Concatenate2 = ComFunc(MyArray) End Function Function Fanc1(ParamArray MyArray()) As String Fanc1 = ComFunc(MyArray) End Function 実を言うと、もう1通りTypeName(v) = "Variant()"なら この中でFor Eachを行う方法もあります。

p0popo
質問者

お礼

なるほど、そんな対処法が。 下記相違が重要なのですね。 For Each v In MyArray(0) For Each v In MyArray

  • pkh4989
  • ベストアンサー率62% (162/260)
回答No.1

そのまま、引数を渡すとConcatenate2側で、引数が0になります。 良い方法が有ると思いますが、取りあえず、以下のように変更してみてください。 Function Fanc1(ParamArray MyArray()) As String   Fanc1 = Concatenate2(MyArray()) End Function   ↓ Function Fanc1(ParamArray MyArray()) As String   Dim i As Integer   Fanc1 = ""   For i = 0 To UBound(MyArray)     Fanc1 = Fanc1 & Concatenate2(MyArray(i))   Next End Function

p0popo
質問者

お礼

返答ありがとうございます。 これで取敢えず処理は可能になります。 でも、Concatenate2の処理によりFanc1を変える必要が有、隠蔽化に難。(> < おっしゃるように、もっとよい方法があるとよいのですが。

関連するQ&A

  • excelユーザー関数で

    同じブック内の全てのシートの、引数で指定したセルの文字列をconcatenateするユーザー関数を作成しました。が引数でセルを指定する時に""をつけなければならず少々不便を感じています。どのように修正すれば""をつけなくてよいようになるでしょうか? VBA初心者です。よろしくお願いします。 Function allbookscont(ContCell As String) As String Dim strRet As String For a=2 to Worksheets.Count strRet = strRet & Worksheets(a).Range(ContCell).Value Next a allbookscont = strRet End Function

  • Excel VBA配列をFunctionに渡す

    こんばんは、引数について教えてください。 Excel VBAの関数を作っていましたが、 1.Function ColumnArrayの部分でコンパイルエラーが発生し、  「配列がありません」と表示されます。  引数を配列のみで渡した場合、問題なく渡せるようですが、  他の引数と、CriteriaArrsの配列と一緒に渡せないのでしょうか。  すべて配列として1つにまとめて渡さなければならないのでしょうか。 2.CriteriaArrs = Array("田中", "鈴木")の部分は、文字列の増減が発生しますので  配列はParamArray  CriteriaArrs()とした方がよいのでしょうか 説明が不足している点があるかもしれませんが宜しくお願いいたします。 Function ColumnArray(SheetName As Worksheet, _ StartCell As Range, _ FieldColumn As Long, _ CountColumn As Long, _ CriteriaArrs As Variant _ ) As Long ・・・ End Function ------------------------------------- sub test() Dim CriteriaArrs() As Variant Dim SheetA As WorkSheet DIm RangeA range CriteriaArrs = Array("田中", "鈴木") set SheetA =Worksheet(1) set RangeA=Range("B3") FilterCount = ColumnArray(SheetA, RangeA, 3, 2, CriteriaArrs) end sub

  • Excel VBA 引数が2個のマクロの呼び出し方

    ExcelのVBAで、 シート上のボタンがクリックされた時に呼び出す マクロ(プロシージャ)の引数が1個の時は、 コード1のようにできましたが、 引数が2個ある時は、コード2のように記述しても、 ボタンをクリックするとエラーになりますが、 【?】の部分をどのように記述すればよいのでしょうか。 (Windows10,Excel2010) -------------------コード1---------------------------------------- Sub test1()  Dim row As Integer  Dim wave_file_path As String  For row = 1 To 2   wave_file_path = ThisWorkbook.Worksheets("Sheet1").Cells(row, 1).Value   Call ボタン作成(row, wave_file_path)  Next row End Sub Sub ボタン作成(ByVal row As Integer, ByVal wave_file_path As String)  Dim cell_loc As String  cell_loc = ThisWorkbook.Worksheets("Sheet1").Cells(row, 3).Address  ThisWorkbook.Worksheets("Sheet1").Select  With ActiveSheet.Buttons.Add(Range(cell_loc).Left, _   Range(cell_loc).Top, _   Range(cell_loc).Width, _   Range(cell_loc).Height)   .name = "ボタン_" & cell_loc   .OnAction = "'WAVE_PLAY """ & wave_file_path & "" & "'"   .Characters.Text = "再生"  End With End Sub Sub WAVE_PLAY(ByVal wave_file_path As String)  If Dir(wave_file_path) = "" Then   MsgBox wave_file_path & vbCrLf & "がありません。", vbExclamation   Exit Sub  End If  Shell "C:\Program Files\Windows Media Player\wmplayer.exe /play /close " & wave_file_path End Sub ------------------------------------------------------------------- -------------------コード2---------------------------------------- Sub test2()  Dim row As Integer  Dim wave_file_path As String  For row = 1 To 2   wave_file_path = ThisWorkbook.Worksheets("Sheet1").Cells(row, 1).Value   Call ボタン作成(row, wave_file_path)  Next row End Sub Sub ボタン作成(ByVal row As Integer, ByVal wave_file_path As String)  Dim cell_loc As String  cell_loc = ThisWorkbook.Worksheets("Sheet1").Cells(row, 3).Address  ThisWorkbook.Worksheets("Sheet1").Select  With ActiveSheet.Buttons.Add(Range(cell_loc).Left, _   Range(cell_loc).Top, _   Range(cell_loc).Width, _   Range(cell_loc).Height)   .name = "ボタン_" & cell_loc   .OnAction = "'WAVE_PLAY """ & wave_file_path & "" & "," & row & "'" <==【?】   .Characters.Text = "再生"  End With End Sub Sub WAVE_PLAY(ByVal wave_file_path As String, ByVal row As Integer)  If Dir(wave_file_path) = "" Then   MsgBox wave_file_path & vbCrLf & "がありません。", vbExclamation   Exit Sub  End If  Shell "C:\Program Files\Windows Media Player\wmplayer.exe /play /close " & wave_file_path  ThisWorkbook.Worksheets("Sheet1").Cells(row, 4).Value = "再生済" End Sub -------------------------------------------------------------------

  • 引数をとるプロシージャの記述方法

    Functionプロシージャへ文字型と数値型の両方の引数の指定したいのですが記述方法が解りません。 文字型のAとBと数値型のCを引数に渡したいのですが、文字だけの場合は Public Function Calc_1(A,B As String) As String でいいと思いますが、これに数値型のCを追加したいのですがどのように記述したらいいのか教えていただけないでしょうか。 よろしくお願いいたします。

  • VBAの書き方を教えてください。パート2

    10月12日に、こちらでVBAの書き方をお聞きした内容の続きになります。 http://okwave.jp/qa/q7744550.html FrmLevelInitの実行が定期的に停止し、ログインできなくなる。 または、一度ID、Passを入力してはじかれた後、Passを再入力し直すとログイン出来る。 の2点が発生してしまいます。 環境がRuntimeを使って使用しているので、作成者が何度もVBAを立ち上げて実行し、再配布している状態です。 すみませんがお手伝い頂けますでしょうか。 Public Sub FrmLevelInit(ParamArray v()) On Error Resume Next If (IsMissing(v)) Then sIdSave = "" sNameSave = "" iUserLevel = 0 Else sIdSave = v(0) sNameSave = v(1) iUserLevel = CLng(v(2)) End If End Sub ' 指定されたフォームのコントロールのタグをチェック Public Sub FrmLevelSet(frm As Form) Dim ctl As Control Dim i As Long For Each ctl In frm.Controls With ctl i = InStr(.Tag, "," & iUserLevel & ",") If (i > 0) Then .Enabled = False End With Next End Sub Public Function LoginId() As String ' ID を返す LoginId = sIdSave End Function Public Function LoginName() As String ' 名前を返す LoginName = sNameSave End Function

  • エクセルVBAを教えて下さい

    エクセルの表で -AB C D E F 1年月--1801 2------ 3------ 4------ (-)は空欄でセルE1=18、F1=1とします。 コントロールボックスをつかって Private Sub Command登録_Click() Dim d1 As Long Dim d2 As Long Dim ret As Variant Dim FindValue As String Dim TotalAddress As String If Range("E1").Value = "" Or Range("F1").Value = "" Then MsgBox "該当する場所にデータが入っていません。", vbCritical Exit Sub End If d1 = Range("A65536").End(xlUp).Offset(1).Row d2 = Range("B65536").End(xlUp).Offset(1).Row FindValue = """" & Range("E1").Value & Range("F1").Value & """" TotalAddress = Range("A1").Resize(d1).Address & "&" & Range("B1").Resize(d1).Address ret = Evaluate("MATCH(" & FindValue & "," & TotalAddress & ",0)") If IsError(ret) Then Cells(d1, 1) = Range("E1").Value Cells(d2, 2) = Range("F1").Value Else MsgBox "既に同じ組み合せがあります。", vbInformation End If End Sub というものを作ったのですが、E1=18、F1=1及びコマンドボタンを別シートに作成し、上記の表への登録をできるようにしたいのですが、なにかいい方法はありませんか?

  • vc++のAPI(dll)の引数をVBAでうけとる

    Excelで開発しなければならない事情があり、 vc++のAPIが持っている関数を ExcelVBAでコールしておりますが、エラー1041でExcelが強制終了してしまいます。 VBAからVisual C++にchar*型で渡し、ByRef String型でVBAにて受け取ります。 VCの関数の第四引数「char* 型/attribute_value」をVBAの「String 型/sValue」で受け取る際にエラーになっているようです。 VBAでcharに相当する変数型がないためと思われますが、何かよいアイデアがありましたらご教授願います。 --VC-- XDW_GetDocumentAttributeByName(h, attribute_name, &attribute_type, attribute_value, size, NULL); --VBA-- <宣言部> Public Declare Function XDW_GetDocumentAttributeByName Lib "C:\Users\○○○\Desktop\dwsdk710jpn\XDWAPI\DLL\xdwapi.dll" (ByVal lnghandle As Long, ByVal sName As String, ByRef lngType As Long, ByRef sValue As String, ByVal lngSize As Long, ByVal reserved As String) As Long <呼び出し部> Dim lngHandle As Long Dim sName as String Dim lngType As Long Dim sValue As String Dim lngSize as Long Dim tmpSize as Long lngSize = 0 sName = "keiyaku" tmpSize = XDW_GetDocumentAttributeByName(lngHandle, sName, sType, sValue, lngSize, vbNullString) XDW_GetDocumentAttributeByName lngHandle, sName, sType, vbNullString, tmpSize, vbNullString degug.print sValue

  • Excel VBA 入力規則

    入力規則を利用して、3つのセルを連携させることを考えていますが、 不適合な値を張り付けらられた場合に拒否をする方法があるのでしょうか。 Private Sub Worksheet_Change(ByVal Target As Range) Dim ad As String Dim ma As Range Dim ma2 As Range Dim r As Range Dim r2 As Range Dim r3 As Range Dim r1 As Range Dim m As Long Dim m2 As Long Application.EnableEvents = False If Target = "" Then Range("F7").Validation.Delete Range("F7") = "" If Target.Address(0, 0) = "B7" Then Range("D7").Validation.Delete Range("D7") = "" End If GoTo EXIT_SUB End If With Worksheets("Sheet1") ad = "A4" Set r = .Range(ad) Set ma = r.MergeArea Set r1 = r.Offset(0, 1) m = Application.Match(Range("B7"), .Range(r1, .Cells(r.Row + ma.Count - 1, r1.Column)), 0) Set r2 = .Cells(r.Row + m - 1, r1.Column) Set ma2 = r2.MergeArea If Target.Address(0, 0) = "B7" Then If ma.MergeCells Then setValiS Target.Offset(0, 2), r2 Range("F7").Validation.Delete Target.Offset(0, 2) = "" Target.Offset(0, 4) = "" Else MsgBox "A列が連結されていません。" End If ElseIf Target.Address(0, 0) = "D7" Then Set r3 = r2.Offset(0, 1) m2 = Application.Match(Target, .Range(r3, .Cells(r2.Row + ma2.Count - 1, r3.Column)), 0) setValiS Target.Offset(0, 2), .Cells(r2.Row + m2 - 1, r3.Column) Target.Offset(0, 2) = "" End If End With EXIT_SUB: Application.EnableEvents = True End Sub Sub setVali2() Dim tc As Range Dim c As Range Set tc = Worksheets("登録").Range("D3") Set c = Worksheets("Sheet1").Range("C3") setValiS tc, c End Sub Sub setValiS(tc As Range, c As Range) Dim ss As String Debug.Print tc.Address, c.Address ss = getChildren(c) If ss > "" Then With tc.Validation .Delete .Add Type:=xlValidateList, Formula1:=getChildren(c) End With End If Worksheets("登録").Activate End Sub Function getChildren(c As Range) Dim c1 As Range Dim ss As String Dim s1 As String Worksheets("Sheet1").Activate ss = "" For Each c1 In c.MergeArea s1 = c1.Offset(0, 1) If s1 <> "" Then ss = ss & "," & s1 Next c1 If ss <> "" Then ss = Mid(ss, 2) Else MsgBox "データがありません!" End If getChildren = ss End Function Sub Outline() Dim CheckRow As Long Dim Moji As String Dim TopRow As Long Dim EndRow As Long With ActiveSheet .Range("A2").ClearOutline .Outline.SummaryRow = xlAbove CheckRow0 = .Range("A" & .Rows.Count).End(xlUp).Row CheckRow = CheckRow0 Do If Moji = "" Then Moji = .Cells(CheckRow, 1).Value EndRow = CheckRow ElseIf yy_mm(CDate(.Cells(CheckRow, 1).Value)) = yy_mm(CDate(Moji)) Then TopRow = CheckRow If TopRow = 1 Then .Rows(TopRow + 1 & ":" & EndRow).Rows.Group Exit Do End If Else .Rows(TopRow + 1 & ":" & EndRow).Rows.Group CheckRow = CheckRow + 1 Moji = "" End If CheckRow = CheckRow - 1 Loop Until CheckRow = 1 .Rows(CheckRow + 1 & ":" & EndRow).Rows.Group .Outline.ShowLevels RowLevels:=1 ExecuteExcel4Macro "SHOW.DETAIL(1," & CheckRow0 & ",TRUE)" End With End Sub Function yy_mm(d As Date) yy_mm = Format(d, "yy/mm") End Function

  • エクセルVBAについて

    現在、エクセル2010を使用し文字色が黒だったら1と加算しそれ以外は0というVBAを VBA素人ながら、コピペしながら組んでいました。 以下 'ColorIndex = 1 は、黒です 3は赤 黄色は7 青は 5 '============================================ Function fcolor(a As Range, b As Integer) Dim c As Range, cu As Integer, frg As String Application.Volatile For Each c In a With c.Font If b = 1 Then If .Color = vbBlack Then cu = cu + 1 Else If .ColorIndex = b Then cu = cu + 1 End If End With Next fcolor = cu End Function という風にし、範囲を=fcolor(D3:E37,1)としていますが、 本当なら”0”と表記されるべきなのですが”66”となってしまいます。 VBAど素人なのでよろしくお願いします。

  • エクセルVBA

    A列を基準にBC列が空白ならAの数値を入れて、A>BならB列を更新、A<CならC列を更新 A列が数値以外ならその行をスキップ、という処理をしたいのですが Option Explicit Dim A As Range, B As Range, C As Range Dim i As Long Sub test() For i = 1 To 10 Set A = Cells(i, 1) Set B = A.Offset(0, 1) Set C = A.Offset(0, 2) If IsNumeric(A) Then Else Exit Sub End If If B.Value = "" Then B.Value = A.Value If C.Value = "" Then C.Value = A.Value If A.Value > B.Value Then B.Value = A.Value If A.Value < C.Value Then C.Value = A.Value Next i End Sub とすると数値以外の行の時点で停止してしまいます。 その行を飛ばして次の行に進むにはどうしたらいいのでしょうか?

専門家に質問してみよう