Excel VBA ByRef引数の型?

このQ&Aのポイント
  • Excel2010でセルに関数式を埋め込むマクロを書いています。ByRef引数の型が一致しませんというエラーが出ています。
  • 「test1」というプログラムではByRef引数の型不一致のエラーが発生しましたが、「test2」というプログラムではうまく動作しました。
  • また、他のプログラムに同じ式を埋め込むとまたもやByRef引数の型が一致しないエラーが発生します。
回答を見る
  • ベストアンサー

Excel VBA ByRef引数の型?

Excel2010でセルに関数式を埋め込むマクロを書いています。 そこで、「ByRef引数の型が一致しません」というエラーが出て困っています。 プログラムの中からエラーの出る所だけを取り出してtest1,test2として試したところ、 test1はエラーが出て、test2はプログラムが動いて目的とするセルに関数式が挿入されました。 Sub test1() dim i, myR as integer myR = 30 For i = 7 To 31 Cells(4, i) = "=IF(" & ConvertToLetter(i) & i - 4 & "="""","""",SUM(" & ConvertToLetter(i) & "5:" & ConvertToLetter(i) & myR & ")/(" & myR & "-COUNTIF(" & ConvertToLetter(i) & "5:" & ConvertToLetter(i) & myR & ","""")))" next i End Sub test1でConvertToLetter(i)のiが青色で選択され「ByRef引数の型不一致」エラーとなってしまいます。 そこで、試しに一度変数iの値をkに渡して同じプログラムをtest2として実行してみました。 Sub test2() dim i, k, myR as integer myR = 30 For i = 7 To 31 k=i Cells(4, i) = "=IF(" & ConvertToLetter(k) & i - 4 & "="""","""",SUM(" & ConvertToLetter(k) & "5:" & ConvertToLetter(k) & myR & ")/(" & myR & "-COUNTIF(" & ConvertToLetter(k) & "5:" & ConvertToLetter(k) & myR & ","""")))" next i End Sub このtest2は、きちんと実行され、目的とするG4(~AE4)のセルに =IF(G3="","",SUM(G5:G30)/(30-COUNTIF(G5:G30,""))) という式が挿入されました。 質問1:なぜ、test1がダメで、test2ならうまくいくのかという理由がわかりません。 質問2:うまくいったtest2と同じ式を、もっと長いプログラムの中に入れるとやはり「ByRef引数の型が一致しません」エラーが出てプログラムが止まってしまいます。test2単独のプログラムならうまく動くのに、他のプログラムの一部に埋め込むとエラーが出る理由もわかりません。 VBAプログラムを試行錯誤しながら勉強している初心者です。どなたかご教示お願いします。 ちなみに、ConvertToLetterは、 Function ConvertToLetter(iCol As Integer) As String Dim iAlpha As Integer Dim iRemainder As Integer iAlpha = Int((iCol - 1) / 26) iRemainder = iCol - (iAlpha * 26) If iAlpha > 0 Then ConvertToLetter = Chr(iAlpha + 64) End If If iRemainder > 0 Then ConvertToLetter = ConvertToLetter & Chr(iRemainder + 64) End If End Function という、関数で定義しています。

質問者が選んだベストアンサー

  • ベストアンサー
  • chie65535
  • ベストアンサー率43% (8523/19372)
回答No.1

まず、 Function ConvertToLetter(iCol As Integer) As String は「参照渡し」になっています。 引数の渡し方の指定子であるByVal、ByRefを省略すると、自動的にByRefになります。つまり Function ConvertToLetter(ByRef iCol As Integer) As String と書いているのと同じなのです。 んで、test1では For i = 7 To 31 Cells(4, i) = "=IF(" & ConvertToLetter(i) のように「参照渡しが許されないFor文のループ変数を、参照渡ししようとしている」ので「ByRef引数の型不一致」のエラーになります。 test2では For i = 7 To 31 k=i Cells(4, i) = "=IF(" & ConvertToLetter(k) のように「参照渡しが許されないFor文のループ変数を渡さず、普通の変数を参照渡ししている」ので、エラーにはなりません。 解決方法は「ConvertToLetterの引数を値渡しに変える」です。つまり Function ConvertToLetter(iCol As Integer) As String を Function ConvertToLetter(ByVal iCol As Integer) As String に変えれば、すべて解決します。 引数にByRefを付けたり、何も書かない場合は「引数の値を関数内で書き換えてしまうと、書き換えた結果が呼び出し元にも影響してしまう」ので、故意にそういう事をするのでなければ、必ず「ByVal」を指定しましょう。 自作関数の引数は、バグを産まない為にも「必ずByValかByRefのどちらかを明記する」ようにしましょう。

nori8823
質問者

お礼

ありがとうございました。Byval,ByRefの意味や違いがまだ理解できていませんが、すっきりしました。 ご回答いただいた内容を勉強します。ありがとうございました。

その他の回答 (3)

  • end-u
  • ベストアンサー率79% (496/625)
回答No.4

入力したい数式はそれであってますか? H4セルが=IF(H4="","",SUM(H5:H30)/(30-COUNTIF(H5:H30,"")))循環しちゃってますけど? 単純なAVERAGEとも違うって事なんですよね.. ..って事はおいといて。 ループインデックスを参照渡しする事の是非もおいとくとして。 コンパイルエラーですよね。 >質問1:なぜ、test1がダメで、test2ならうまくいくのかという理由がわかりません。 提示されたtest2でもうまくいきません。 問題は >dim i, myR as integer >dim i, k, myR as integer ここ。 変数iもkも型宣言が省略されているとみなされ、Variant型になっています。 だから型不一致コンパイルエラーです。 ByVal値渡しだと暗黙的に型変換されるのでコンパイルエラーにひっかからないとは思いますが ループインデックスをVariantにする必然性はないので、ちゃんと型宣言しておくほうが良いでしょう。 カンマで繋ぐ場合は Dim i As Integer, myR As Integer と書いてください。

  • chie65535
  • ベストアンサー率43% (8523/19372)
回答No.3

更に追記。 i=7 Cells(4,i).FormulaR1C1 = "=R[1]C[0]" と書くと、Cells(4,i)に「=G5」って言う式が代入されます。 この方式だと「自分のセルからの相対位置」で指定出来るので「固定の文字列」で大丈夫になります。 例えば、 G4セルに対して「FormulaR1C1 = "=R[1]C[0]"」ってやれば「=G5」に H4セルに対して「FormulaR1C1 = "=R[1]C[0]"」ってやれば「=H5」に I4セルに対して「FormulaR1C1 = "=R[1]C[0]"」ってやれば「=I5」に になります。 式の中の「[1]」や「[0]」の部分が「固定の文字列」である事に注目して下さい。変数にする必要がありません。 これは「参照する先が、常に、自分自身のセルの1行下」なので「参照する式が一定」になるからです。 これをうまく応用すれば「式が固定の文字列で済む」ので、余計な処理がすべて不要になります。

  • chie65535
  • ベストアンサー率43% (8523/19372)
回答No.2

因みに、OFFSETワークシート関数を使えば「数値をそのままセル指定に使える」ので、ConvertToLetterなどと言う関数は要りません。 例えば =IF(G3="","",SUM(G5:G30)/(30-COUNTIF(G5:G30,""))) は =IF(OFFSET($A$1,5,7,1,1)="","",SUM(OFFSET($A$1,5,7,26,1))/(30-COUNTIF(OFFSET($A$1,5,7,26,1),""))) と言う式にする事が出来ます。 また、INDIRECTワークシート関数を使えば「R1C1」と言うセル指定も使えます。 例えば =IF(G3="","",SUM(G5:G30)/(30-COUNTIF(G5:G30,""))) は =IF(INDIRECT("R3C7",0)="","",SUM(INDIRECT("R5C7:R30C7",0))/(30-COUNTIF(INDIRECT("R5C7:R30C7",0),""))) と言う式にする事が出来ます。 こうすると「1なら"A"、2なら"B"を返す関数」なんか要りません。 あと、作った「式」をセルに代入する時は Cells(4, i) = 式の文字列 ではなく Cells(4, i).Formula = 式の文字列 にしないといけません。 もし「代入しようとしたセルの表示形式が、文字列になっている場合」に Cells(4, i) = 式の文字列 と書くと、式としてではなく「ただの文字列」としてセルに値が代入されてしまい、式が計算されません。

関連するQ&A

  • 「ByRef引数の型が一致しません」助けてください。

    お世話になります。 現在VBAでHTMLの書き出し用プログラムを書いています。 書き出したHTMLをUTF-8に変換するため、 ■UTF-8ファイル作成 for VBA http://www.vector.co.jp/soft/dl/winnt/prog/se320375.html のクラスモジュールを利用させていただいております。 Sub testAで定義した内容を書き出すために、 Sub createTestでtestA fNum(i)とした場合、 「ByRef引数の型が一致しません」と怒られてしまいます…。 単数の生成であれば、testA f1で生成可能なのですが、 生成ファイルが複数あり、配列に格納して処理したいのです。 どなたかお力をお貸しください。 プログラムの知識はほぼ素人レベルですorz 宜しくお願いします。 ▼コード Option Explicit Public Sub createTest() Dim fNum As Variant Dim f1 As New TextFile, f2 As New TextFile, f3 As New TextFile, f4 As New TextFile, f5 As New TextFile, f6 As New TextFile Dim f7 As New TextFile, f8 As New TextFile, f9 As New TextFile, f10 As New TextFile, f11 As New TextFile, f12 As New TextFile Dim f13 As New TextFile, f14 As New TextFile, f15 As New TextFile, f16 As New TextFile, f17 As New TextFile Dim Header As String, BodyS_T As String, BodyS_L As String, GlNavi As String, Promo As String, Contents As String, PrNavi As String, SeNavi As String, Footer As String, BodyE As String Dim ContentsM As String, ContentsS As String Dim WBK As Workbook Dim SH2 As Worksheet Dim TplBox As Variant Dim createCurPath As String Dim i As Integer Set WBK = ThisWorkbook Set SH2 = WBK.Sheets(2) createCurPath = ThisWorkbook.path & "\" & UserForm1.TextBox1.Value fNum = Array(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17) '<HEADER> Header = "Header" '<BODY-START> BodyS_T = "BodyS_T>" BodyS_L = "BodyS_L" '<GLOBAL NAVI> GlNavi = "GlNavi" '<PROMO> Promo = "Promo" '<CONTENTS> Contents = "Contents" ContentsM = "ContentsM" ContentsS = "ContentsS" '<PRIMRY NAVi> PrNavi = "PrNavi" '<SECONDARY NAVI> SeNavi = "SeNavi" '<FOOTER> Footer = "Footer" '<BODY-END> BodyE = "BodyE" For i = 0 To 16 If i = 0 Then fNum(i).FileCreate createCurPath & "\index.html", "UTF-8" ElseIf UserForm1("TextBox" & i + 1).Value <> "" Then fNum(i).FileCreate createCurPath & "\" & UserForm1("TextBox" & i + 1).Value & "\index.html", "UTF-8" End If fNum(i).TextWriteLine Header If i = 0 Then fNum(i).TextWriteLine BodyS_T ElseIf UserForm1("TextBox" & i + 1).Value <> "" Then fNum(i).TextWriteLine BodyS_L End If TplBox = SH2.Range("C" & i + 3).Value If TplBox <> "" Or TplBox <> "選択" Then If InStr(TplBox, "-TA-") > 0 Then testA fNum(i) fNum(i).TextWriteLine Promo fNum(i).TextWriteLine PrNavi ElseIf InStr(TplBox, "-TB-") > 0 Then testA fNum(i) fNum(i).TextWriteLine "<hr />" ElseIf InStr(TplBox, "-TC-") > 0 Then fNum(i).TextWriteLine ContentsS End If End If fNum(i).FileClose Next i End Sub Public Sub testA(f As TextFile) f.TextWriteLine "テスト1" End Sub

  • String だと「 ByRef引数の型が一致しません 」というエラーが出ます。なぜ?

    ここで「Kaplan-Meyer 生存分析に便利なソフトを教えて」と質問した shuu_01 です。ここで VisualBasic のソースのありかを教えて頂き、自分に使いやすいようソースを書き換えようと奮闘中です(それまで VisualBasic の経験がなく 無謀!と実感中です)。 元々のソースはグラフが1本だけだったので、肺癌だと「腺癌」「扁平上皮癌」「小細胞癌」、、といろんな癌の種類別にグラフを数本 書くのが目標です。そこで、 Sub km_test() Dim nc As Integer, gr() As String nc = 2 ReDim gr(nc) gr(0) = "腺癌" gr(1) = "扁平上皮癌" gr(2) = "小細胞癌" km_group_test nc, gr End Sub Sub km_group_test(nc As Integer, gr As String) End Sub というソースを書くと: String の変数 gr の色が変わり、「 ByRef引数の型が一致しません 」というエラーが出ます。 Integer の変数 nc ではエラーが出ません。 きちんと型を一致させているつもりなのに、なぜ???

  • VBAのUserFormでサブルーチンを用いる

    UserFormのコードに次のように書いてbuttomを押してみると コンパイルエラー:ByRef引数の型が一致しません。 と出てしまいます。 どこが間違っているのでしょうか?ご回答お願いします。 Private Sub buttom_Click() Dim i As Integer Dim name As String i = 1 name = "名前" Call test(i , name) End Sub ---------------------------------------------- Sub test(i As Integer, name As String) Cells(i , 1) = name End Sub

  • 配列を引数で渡したりするには?

    初心者なので困っています。配列をほかのサブルーチンへ渡して、その中で配列の値を書き換えて、上層のルーチンへ渡すにはどうしたらよいのでしょうか? 初心者なので、みなまさまのお知恵を拝借させてください。よろしくお願いします。 Private Sub Print() Dim C_ALL(3) As Integer Dim D_ALL(3) As Integer Data_Set(C_ALL(), D_ALL()) MsgBox(C_ALL() & " " & D_ALL()) '配列内容すべて表示 End Sub Private Sub Data_set(ByRef C_ALL As Integer, ByRef D_ALL As Integer) Dim i As Integer For i = 0 To 4 C_ALL(i) += i D_ALL(i) += i i += 1 Next End Sub

  • [Excel2000_VBA] 型が一致しませんメッセージが表示

    各サイトを調べたのですが、自分のレベルに合った解答内容がなくよく理解できなかったので、質問させて頂きます(初歩的な質問で申し訳ありません) ユーザー定義を使用し、以下のコードを作ってみました。 配列を引数にして、まとめて返したいと考えていますが、構造体を使用すると「型が一致しません」と表示されてしまいます。 何が原因しているのでしょうか? さっぱり分かりませんので、ご教示お願いいたします。 Type test aaaa As Integer End Type Sub sbTest() Dim myAns() As test myAns = Sample1(myAns) End Sub Function Sample1(ByRef Ans() As test) Dim i As Integer Dim ret(0 To 9) As test For i = 0 To 9 ret(i).aaaa = i Next Ans = ret '配列名で配列を戻り値 End Function

  • Excel VBA ・・・教えてください

    何度も質問させて頂いてます。すみません、 下記のプログラムはこの場で教えて頂いたプログラムで、 実行すると●の後を▲や■が追いかける動きをします。 下記のプログラムをある程度使用して 1~20の数字が順々で追いかけっこする プログラムを作成するにはどのようにすればいいのでしょうか… できればプログラムは長めにならず 20の数字から簡単に増やすことのできるような そんなプログラムが作成したいです… どなたかアドバイスお持ちの方 教えて下さいお願いします... Dim time1 As Integer, time As Integer Dim X As Integer, Y As Integer Dim X1 As Integer, Y1 As Integer Dim X2 As Integer, Y2 As Integer Dim maru As String, yoko As String, tate As String Dim sankaku As String, shikaku As String Sub 描画() Cells(Y2, X2).Value = shikaku Cells(Y1, X1).Value = sankaku Cells(Y, X).Value = maru End Sub Sub 削除() Cells(Y2, X2).Value = "" End Sub Sub 待機() For time1 = 0 To 1000 For time2 = 0 To 1000 Next Next End Sub Sub 座標移動() X2 = X1 Y2 = Y1 X1 = X Y1 = Y If yoko = "右" Then X = X + 1 Else X = X - 1 End If If X = 30 Then yoko = "左" ElseIf X = 1 Then yoko = "右" End If If tate = "上" Then Y = Y + 1 Else Y = Y - 1 End If If Y = 20 Then tate = "下" ElseIf Y = 1 Then tate = "上" End If End Sub Sub main() maru = "●" sankaku = "▲" shikaku = "■" X = 1 Y = 1 X1 = 1 Y1 = 1 X2 = 1 Y2 = 1 yoko = "右" tate = "上" Do 描画 待機 削除 待機 座標移動 Loop End Sub

  • エクセルのVBAで質問があります。

    現在自分はカレンダーを作成していて、カレンダーに祝日を入れたいと思っています そこで これを if文もしくはselectcase どっちを使ったら楽か教えてもらいたいです Sub MakeCalendar(hi As Date) Dim i As Integer 'カレンダーにセットする日付 Dim g As Integer '日付をセットする行番号 Dim r As Integer '日付をセットする列番号 Dim lastDay As Integer '作成するカレンダーの月末 g = 2 'その月の開始曜日を算出 r = Weekday(DateSerial(Year(hi), Month(hi), 1), vbSunday) '指定された日付の翌月1日をもとて、日付の前の日を計算する lastDay = Day(DateSerial(Year(hi), Month(hi) + 1, 1) - 1) For i = 1 To lastDay 'iに日付の設定 Cells(g, r).Value = i If r = 7 Then r = 1 '戻して g = g + 1 '1行下に書く Else r = r + 1 '1列→に移動する End If Next End Sub Sub test() Range("A2:G7").Value = "" 'A2~G2にカレンダー表示 MakeCalendar Range("I2").Value 'I2に日付を入力する End Sub Sub test() Range("A2:G7").Value = "" 'A2~G2にカレンダー表示 MakeCalendar Range("I2").Value 'I2に日付を入力する End Sub このようなマクロを組んでいまして、祝日(ゴールデンウィークなど)を赤で塗りつぶすような物を考えています。 VBAは初心者でまだあまりわかっていないので、ご教授ください

  • エクセルVBAの繰り返し処理の質問

    C列にある項目とG列にある項目を比較して、 一致し、H列にある数字が10以上ならば、B列にフラグ1を立てる という処理を行いたいんですが、 下記ぐらいまでしか作れず、うまくいきません・・・ Sub フラグを立てる処理() Dim i As Integer Dim j As Integer Dim k As Integer i = 1 j = 1 Do j = j + 1 Do i = i + 1 If Cells(j, 8) > 9 Then Cells(i - 1, 4) = 1 End If Loop Until Cells(i, 3) <> Cells(j, 7) Or Cells(i, 3) = "" Loop Until Cells(j, 7) = "" End Sub わかる方がいらっしゃいましたら、お願いします。

  • スレッドで Byref の引数を渡したい場合

    VB2005 の初心者です。 スレッドに Byref の引数を渡すやり方が分かりません。 Byval だとエラーは出ないのですが、 Byref だとどうしてもエラーが消えません。 ソースは下記です。 Private CDF As clsCDF Public Class clsCDF Public LOOP1 As clsLoop1 Public LOOP2 As clsLoop2 End Class Protected Overrides Sub OnStart(ByVal args() As String) Thread = New Thread(AddressOf ABC) Thread.Start(CDF) End Sub Private Sub prvABC ( ByRef CDF As Object ) End Sub 何かヒントになることでも良いので、 皆様の知恵をお借りできれば幸いです。 よろしくお願い致します。

  • ▲ExcelのVBA▼困っています

    何度もVBAで質問させてもらい助けてもらっています。 懲りずにまた質問ですが… 下のプログラムは"●"が跳ね返るものなのですが… ●の後を■と▲が追うようなプログラムにするには なにを追加すればいいのでしょうか…?; どなたか教えて下さい;;お願いします;; Dim time1 As Integer, time As Integer Dim X As Integer, Y As Integer Dim maru As String, yoko As String, tate As String Sub 描画() Cells(X, Y).Value = maru End Sub Sub 削除() Cells(X, Y).Value = "" End Sub Sub 待機() For time1 = 0 To 1000 For time2 = 0 To 1000 Next Next End Sub Sub 座標移動() If yoko = "右" Then Y = Y + 1 Else Y = Y - 1 End If If Y = 30 Then yoko = "左" ElseIf Y = 1 Then yoko = "右" End If If tate = "上" Then X = X + 1 Else X = X - 1 End If If X = 20 Then tate = "下" ElseIf X = 1 Then tate = "上" End If End Sub Sub main() maru = "●" X = 1 Y = 1 yoko = "右" tate = "上" Do 描画 待機 削除 待機 座標移動 Loop End Sub

専門家に質問してみよう