マルオです。
いつも勉強させてもらっています。
またまた、教えていただきたいのですが、構造体配列の中に配列を用意して、
それぞれでRedim(Preserve)が実行できるかをテストしようと思いました。
そしたら、下記のコンパイルエラーが発生して、原因がわからずに困っています。
「パブリック オブジェクト モジュールで定義されたユーザー定義型に限り、変数に割り当てることができ、実行時バインディングの関数に渡すことができます。」
多分、何か私のコードに問題があると思うのですが、ぜひ教えていただけないでしょうか?
ちなみに、UboundSpを用いずに、Uboundを用いると、正常に動作します。
'---以下の内容をForm1に記述---
Private Sub Form_Load()
ReDim structText(0) As structArray
ReDim structText(0).testA(2) As String
ReDim structText(0).testB(2) As String
structText(0).testA(0) = "testA0-0"
structText(0).testA(1) = "testA0-1"
structText(0).testA(2) = "testA0-2"
structText(0).testB(0) = "testB0-0"
structText(0).testB(1) = "testB0-1"
structText(0).testB(2) = "testB0-2"
ReDim Preserve structText(1) As structArray
ReDim Preserve structText(1).testA(1) As String
ReDim Preserve structText(1).testB(1) As String
structText(1).testA(0) = "testA1-0"
structText(1).testA(1) = "testA1-1"
structText(1).testB(0) = "testB1-0"
structText(1).testB(1) = "testB1-1"
Debug.Print UboundSp(structText) '★ここの引数でコンパイルエラー
Debug.Print UboundSp(structText(0).testA)
Debug.Print UboundSp(structText(0).testB)
Debug.Print UboundSp(structText(1).testA)
Debug.Print UboundSp(structText(1).testB)
End Sub
'---以下の内容をModule1に記述---
Public structText() As structArray
Public Type structArray
testA() As String
testB() As String
End Type
Public Function UboundSp(v As Variant) As Long
On Error Resume Next
UboundSp = UBound(v)
If Err <> 0 Then UboundSp = -1
On Error GoTo 0
End Function
開発環境は,VB6です。
エラーメッセージの通りではないかと思います。
つまり
Public Type structArray
testA() As String
testB() As String
End Type
がパブリックオブジェクトモジュールで定義されていないからです。
これはVB6の仕様みたいで
http://www.int21.co.jp/pcdn/vb/noriolib/vbmag/9812/vb6/
にヒントがあります。
結論から言うと
上記構造体を外部コンポーネント(ActiveX.Dll,OCX)などでパブリック宣言してやれば
エラー無くあなたのコードは動作します。
030さん、回答ありがとうございます。
外部コンポーネントを作成するのは、初めてなので、
ちょっとヒントいただきたいのですが、
下記の手順についてコメントいただけるとうれしいです。
まず、ActiveXコントロールに構造体をPublic宣言するために、以下の作業を行う。
-----------
① VB6を起動して、「ActiveXコントロール」を選択して、追加する。
② デフォルトで、「UserControl1」というのがあるので、それには触れずに、標準モジュール(Module1)を追加する。
③ 下記のユーザー定義型を定義する。
Public Type structArray
testA() As String
testB() As String
End Type
④ コンパイルして「testtest.ocx」を作成する。
-----------
次に、コンパイルエラーが発生しているプロジェクトに対して「testtest.ocx」を参照設定してあげる。
-----------
① コンパイルエラーが発生しているプロジェクトを開いて、
[プロジェクト]-[参照設定]の順に選択して、「testtest.ocx」を選択する。
② そして、コンパイル!
-----------
うーん。何か間違っていると思うのですが、どこが間違っているかわかりますでしょうか?
よろしくお願いします。
いい忘れました。
>② そして、コンパイル!
ってところで、同じエラーが発生して、コンパイルができません。(>_<)
ご指摘ください。m(_ _)m
パブリックオブジェクトモジュールは、
GlobalMultiUseに設定されたクラス…だったかな。(ほかにもあるかも)
※でも、わざわざ構造体を使いたいと言うだけで
外部モジュールにするのは抵抗ありませんか?
構造体ではなく素直にクラスを作った方がいいと思うのですが…
ActiveX.ocxは参照設定じゃなくてコンポーネントの追加じゃない?
>※でも、わざわざ構造体を使いたいと言うだけで
> 外部モジュールにするのは抵抗ありませんか?
> 構造体ではなく素直にクラスを作った方がいいと思うのですが…
激しく同意
外部から参照できるのはUserControlモジュールに記述したパブリックメンバだけだったかと。
よって構造体の宣言を標準モジュールではなくUserControlモジュールでパブリック宣言して
ActiveXコントロールを参照設定してやればよいかと。
ガッさん。abuさん。030さん。
回答ありがとうございます。
ほんと初心者ですいません。
クラスに追加しても、同じことが出来るのであれば、そうしたいです。
また家に帰ったら、試して、結果報告させてください。
宜しくお願いします。
こんばんわ。マルオです。
教えてもらったクラスを作成する方法で、早速試してみたのですが、
うまくできませんでした。
うーん。うーん。(-_-;)
クラスってほとんど追加したことなくて、
よく分からないのですが、下記のやり方だとコンパイルエラーが発生してしまいます。
「プライベートオブジェクトモジュール内ではパブリックのユーザー定義型は定義できません。」
どっか間違いがあると思うのですが、ご指摘してもらえないでしょうか?
'---以下の内容をForm1に記述---
Private Sub Form_Load()
ReDim structText(0) As structArray
ReDim structText(0).testA(2) As String
ReDim structText(0).testB(2) As String
structText(0).testA(0) = "testA0-0"
structText(0).testA(1) = "testA0-1"
structText(0).testA(2) = "testA0-2"
structText(0).testB(0) = "testB0-0"
structText(0).testB(1) = "testB0-1"
structText(0).testB(2) = "testB0-2"
ReDim Preserve structText(1) As structArray
ReDim Preserve structText(1).testA(1) As String
ReDim Preserve structText(1).testB(1) As String
structText(1).testA(0) = "testA1-0"
structText(1).testA(1) = "testA1-1"
structText(1).testB(0) = "testB1-0"
structText(1).testB(1) = "testB1-1"
Debug.Print UboundSp(structText)
Debug.Print UboundSp(structText(0).testA)
Debug.Print UboundSp(structText(0).testB)
Debug.Print UboundSp(structText(1).testA)
Debug.Print UboundSp(structText(1).testB)
End Sub
'---------以下の内容をModule1に記述-------
Public structText() As structArray
Public Function UboundSp(v As Variant) As Long
On Error Resume Next
UboundSp = UBound(v)
If Err <> 0 Then UboundSp = -1
On Error GoTo 0
End Function
'---------以下の内容をClass1に記述-------
Public Type structArray
testA() As String
testB() As String
End Type
よろしくお願いします。
なんか勘違いが多いですね。
ガッさんがおっしゃっているのは
「構造体を使わずにクラスを作成して」
という意味ですよ。
「クラスモジュールで構造体を宣言」とは一言もいっていません。
それと
>よって構造体の宣言を標準モジュールではなくUserControlモジュールでパブリック宣言して
>ActiveXコントロールを参照設定してやればよいかと。
はためしたんですか?
>なんか勘違いが多いですね。
すいません。確かにお叱りごもっともですね。
ガッさんの言いたいことは下記のようなことでよいでしょうか?
他にいい方法ありますでしょうか?
'---以下の内容をForm1に記述---
Private Sub Form_Load()
ReDim structText(0) As New structArray
'---------------------------------------
' structArrayをクラス定義したので、不要
' ReDim structText(0).testA(2) As String
' ReDim structText(0).testB(2) As String
'---------------------------------------
structText(0).testA(0) = "testA0-0"
structText(0).testA(1) = "testA0-1"
structText(0).testA(2) = "testA0-2"
structText(0).testB(0) = "testB0-0"
structText(0).testB(1) = "testB0-1"
structText(0).testB(2) = "testB0-2"
ReDim Preserve structText(1) As New structArray
'---------------------------------------
' structArrayをクラス定義したので、不要
' ReDim Preserve structText(1).testA(1) As String
' ReDim Preserve structText(1).testB(1) As String
'---------------------------------------
structText(1).testA(0) = "testA1-0"
structText(1).testA(1) = "testA1-1"
structText(1).testB(0) = "testB1-0"
structText(1).testB(1) = "testB1-1"
Debug.Print UboundSp(structText)
Debug.Print structText(0).count_testA
Debug.Print structText(0).count_testB
'---------------------------------------
' structArrayをクラス定義したので、不要
' Debug.Print UboundSp(structText(0).testA)
' Debug.Print UboundSp(structText(0).testB)
'
' Debug.Print UboundSp(structText(1).testA)
' Debug.Print UboundSp(structText(1).testB)
'---------------------------------------
End Sub
'---以下の内容をstructArrayクラスに記述---
Option Explicit
Private m_testA() As String
Private m_testB() As String
Public Function count_testA() As Integer
count_testA = UboundSp(m_testA)
End Function
Public Function count_testB() As Integer
count_testB = UboundSp(m_testB)
End Function
Public Property Get testA(Index As Integer) As String
If UboundSp(m_testA) < Index Then
ReDim Preserve m_testA(Index) As String '配列の確保
m_testA(Index) = "" '初期化
End If
testA = m_testA(Index)
End Property
Public Property Let testA(Index As Integer, ByVal NewValue As String)
If UboundSp(m_testA) < Index Then
ReDim Preserve m_testA(Index) As String '配列の確保
End If
m_testA(Index) = NewValue
End Property
Public Property Get testB(Index As Integer) As String
If UboundSp(m_testB) < Index Then
ReDim Preserve m_testB(Index) As String '配列の確保
m_testB(Index) = "" '初期化
End If
testB = m_testB(Index)
End Property
Public Property Let testB(Index As Integer, ByVal NewValue As String)
If UboundSp(m_testB) < Index Then
ReDim Preserve m_testB(Index) As String '配列の確保
End If
m_testB(Index) = NewValue
End Property
'---以下の内容をModule1に記述---
Public structText() As New structArray
Public Function UboundSp(v As Variant) As Long
On Error Resume Next
UboundSp = UBound(v)
If Err <> 0 Then UboundSp = -1
On Error GoTo 0
End Function
単純に、
> Public Function UboundSp(v As Variant) As Long
を
Public Function UboundSp(v() As structArray) As Long
とするわけには行かないのでしょうか? 一般化する必要は
ないように思えます。
実行時バインディングがだめだと言ってるんだから、ちょっと工夫して
事前バインディングにしたらいいのでは、たとえば
*****Module1側******
Public Const intStruct = 0
Public Const intString = 1
Public Type structArray
testA() As String
testB() As String
End Type
Public structText() As structArray
Public Function UboundSp(v() As structArray, dt() As String, dimNo As Integer) As Long
On Error Resume Next
If dimNo = intStruct Then
UboundSp = UBound(v) 'ユーザー定義型
Else
UboundSp = UBound(dt) '配列
End If
If Err <> 0 Then UboundSp = -1
On Error GoTo 0
End Function
***Form1側****
Debug.Print UboundSp(structText, structText(0).testA, intStruct)
Debug.Print UboundSp(structText, structText(0).testA, intString)
Debug.Print UboundSp(structText, structText(1).testA, intString)
Debug.Print UboundSp(structText, structText(1).testB, intString)
K.J.K.さん。我龍院忠太さん。
回答ありがとうございます。
事前バインディングにしてあげればうまく動くんですか?
その発想は、全然ありませんでした。
我龍院忠太さんの方法で実施すれば、シンプルなコードで汎用性があるので、使いまわせますよね!(゜〇゜)
家帰ったら、早速試してみます。
また、報告させてください。
宜しくお願いします。
投稿する前に確かめなかったので被ってしまいましたが、
K.J.K.さんの方法も基本的には私と同じに事前バインディング
を勧めています。
回答遅くなってすいません。
事前バインディングで試してみたところ、うまく行きましたので、
その方法にて、対処いたします。
みなさん、ほんとに回答ありがとうございました。
素人の私の質問に付き合っていただいて、非常に感謝です。
m(_ _)m
ツイート | ![]() |