• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1130
  • Last Modified:

byRef collection won't compile

I have a DLL with a function that receives a byRef collection as one of its arguments.  I recently upgraded my hardware and now I can't compile my executable that uses this DLL function.  I get a byRef Type mismatch.  This same executable compiles just fine on my old machine.  Am I missing some component or upgrade?  I'm running NT 4.0 SP4, VB 6.0 SP3

It is a new machine, I have re-installed NT SP4 & VS6 SP3 again
I wrote the DLL in VB
I use Wise to install the DLL
I have also re-compiled the DLL successfully on the new machine
The DLL is registered and maintains binary compatibility
The projet group (exe & dll) will run in debug mode
The exe runs on the new machine if I compile on the old machine

I had this problem once before on the old machine.  It happened when I upgraded from VB5 to VB6.  So I broke compatibility in my DLL and changed the function to not use a byRef Collection.  About 1 month later I was forced to go back to the original compatibility chain.  I didn't have the compile problem after that.  I assumed that some upgrade cured the problem but I didn't know what.
1 Solution
>byRef Type mismatch
try passing also library name, VBA.Collection
ArgonautAuthor Commented:
Been there, done that.

Here is some test code that I can duplicate the problem with.  Make sure you do not run this as a group project.  It works fine when the DLL is open as part of the project.  I have tested this on sereral machines and have found 3 of 10 that fail.  I just can't find what is common in them.


Private Sub Command1_Click()
   Dim col() As Collection
   Dim Index As Integer
   Dim clsT As CTest

   Set clsT = New CTest

   ReDim col(1 To 50)

   For Index = 1 To 50
      Set col(Index) = New Collection
   Next Index

   clsT.Test col()
   'Compile fails here with the error---
   '    Compile Error:
   '    ByRef argument type mismatch
End Sub


Option Explicit

Public Sub Test(col() As Collection)
   MsgBox "UBound(col) = " & UBound(col) & vbCrLf _
        & "col(10.Count = " & col(1).Count
End Sub
I assume you did a FULL install (dependency files et al). If that is the case, it sounds like a versioning problem.. check out this hyperlink from MSDN (it has a graphic) or read the text of the article below:


From MSDN:
Visual Basic Concepts

Using Binary Version Compatibility

Whenever you begin work on a new version of an existing component, you need to specify a type library which Visual Basic can use as a reference point for determining compatibility. In most cases, this will be the type library included in executable (.exe, .dll, or .ocx file) for the last version of the component you distributed.

Each time you build an interim version of your updated component, Visual Basic extracts information about the old interfaces from this .exe file and compares it to the new interfaces of your class modules.

"Providing a Reference Point for Compatibility" explains the procedure for creating a reference point.

Keeping the Reference Version Separate from Interim Builds
Important   Keep the copy of the .exe file you specify as your reference version separate from the build copy of the new version.

Each time you make an interim build, Visual Basic adds a new set of interface identifiers to the executable, one identifier for each class module. If you specify your build copy as the reference version, it will accumulate a complete set of interface identifiers for every version-compatible interim build you have ever done. (Interface identifiers do not change for version-identical builds.)

In addition to the sixteen bytes taken up by each interface identifier, having unused interface identifiers in your executable — only your test applications ever use the interim versions — can slow down cross-process access to your component in some situations, and the Windows Registry of any computer your component is installed on will be cluttered with unused interface identifiers.

If your reference version is a copy of your last released executable, all your interim builds will have the same interface version number, and your final build will have only the interface identifiers it needs: all the sets from the reference version (to provide backward compatibility) plus the set of interface identifiers for all the classes in your new release.

Note   When you’re developing the first version of a component, using Project Compatibility instead of Binary Compatibility, exactly the opposite is true: The reference version should be your interim build. This does not bulk up the type library, because Project Compatibility never saves the interface identifiers.

Avoiding Version Trees
Because Visual Basic produces the version number for the new type library by incrementing the type library version number it finds in the reference version, the released versions of your component form a chain, each link derived from its predecessor. As mentioned earlier, each new release contains all the interface identifiers for preceding versions, so that a client application compiled with any previous version will still work with the latest.

What’s a Version Tree?
Version trees arise when your component’s version history acquires branches — that is, when you produce two physically distinct components based on the same source code. It’s important to keep the version history of your component straight, and avoid such branching.

Figure 7.4 shows some of the problems that can be caused by version trees. (The version numbers are for illustrative purposes only, and are not intended to represent actual type library version numbers.)

Figure 7.4   Problems with version trees

The long branch at the right shows four successive versions of a component executable, and a new executable that has been created by adding to the source code for the executable whose type library version is 1.3.

The correct continuation of this version history is for the latest executable to be compiled with the version 1.3 executable as its reference version. The new type library version number is 1.4. The .exe file maintains compatibility with client applications compiled using any of its predecessors.

Because it’s at the end of a chain of compatible versions, the new executable could also be compiled with the version 1.0 executable as its reference version. In this case, its type library version number will be 1.1. This could cause problems for clients compiled to take advantage of features of the new version. If they’re placed on a computer with the earlier version 1.1 executable, the new features will not be available, and the applications will fail.

A different problem arises when the new component is installed on computers that have client applications compiled with type library version numbers 1.1, 1.2, and 1.3. Standard practice is to increase the file version number of each new executable file, to ensure that Setup will replace earlier versions of the executable. (Remember that file version numbers are independent of type library version numbers.)

Thus the new executable, containing interface identifiers for type library versions 1.0 and 1.1, will replace older executables that contained interface identifiers for type library versions 1.0 through 1.3.

If the computer already has client applications compiled with type library versions 1.2 and 1.3, those clients will be unable to use the new version of the component.

Divergent Versions
The left side of the tree shows divergent versions. This can arise when the source code for an early version of your component is taken as the basis of a new component, and classes are added that do not exist in your main version history.

If the executable for your component is used as the reference version for the divergent version, the type library version numbers of the divergent version and its successors will overlap the version numbers of your components. The results for client applications will be disastrous.

Tip   You can easily avoid the creation of version trees by always setting aside a copy of the previous version of your component’s executable file (.exe, .dll, or .ocx) as the reference version for the next release, as described earlier in this topic.

Tip   If you decide to use the source code of an earlier version of your component as the basis of a new component, give the new component a different project name and executable name.

Version Trees with Project Compatibility
Version trees can also arise when you’re using Project Compatibility, the difference being that it’s the major version number of the type library that changes (instead of the minor version number, as shown in Figure 7.4). The consequences to client applications can be equally disastrous.

As with Binary Compatibility, the best way to avoid this is not to split your source tree. If you take a copy of your source code at a particular stage of the project as the basis for another component, use a different project name and executable name for this new project.

Version Compatibility Messages
For performance reasons, Visual Basic does not fully compare interfaces as you edit. When you run your component project, Visual Basic will always display a compatibility warning if the new version is incompatible with the old. (Version-identical and version-compatible interfaces will compile without compatibility warnings.)

Note   Version compatibility is judged on a project-wide basis. A change in the declaration of just one method in one class module causes the entire project to be marked as incompatible with the previous version. See "Levels of Version Compatibility," earlier in this chapter, for a listing of changes that will cause a version incompatibility.

Version Incompatibility Warnings
Suppose you add a new argument to the Spin method of the Widget object. When you run the project, you’ll get a warning that binary compatibility has been broken. You can examine the old declaration by clicking the Declaration button on this message. If you made the change accidentally, you can click Edit to bring up the code and fix it.

If you choose to accept the warning, the component will retain the type library identifier and the class IDs. Interface IDs are changed only for classes that are no longer binary compatible. This is the same behavior as Project Compatibility.

If, however, you choose to ignore the warning, the component will also maintain the interface IDs. This option is only available when the compiler determines that there was a change in the signature of a method.

Caution   You should only choose to ignore the warning if you are absolutely sure that the changes you have made won't break compatibility. If you aren't absolutely sure, take the safe alternative.

Important   The option to override the compiler's warning represents a change in behavior from Visual Basic 5.0. It is important that you fully understand the implications of incompatible changes before proceeding with this option.

Incompatible EXE File
If you have not changed the project name, when you use the Make EXE File command, you will get a warning that your application is incompatible with the .exe file you specified as your reference version, as shown in Figure 7.5.

Figure 7.5   Warning for incompatible .exe file

Clicking Continue at this point creates an executable file that could cause existing client applications to fail. In order for existing clients to continue working, you must take the following steps when you create an incompatible version of a component:

Change the file name.

Change the project name.

Compile with Version Compatibility set to No Compatibility.
These steps are discussed in detail in "Levels of Binary Version Compatibility."

For More Information   See "Version Compatibility" for a list of topics related to this feature.

Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

ArgonautAuthor Commented:

I'm using binary compatibility with a reference to the original build.  I don't think there is any problem here as the example code above is not using any compatibility.
You are passing ARRAY of collections (I think this is sick :)

The trick is to use:
Public Sub Test(col As Variant)
ArgonautAuthor Commented:

As I mentioned I must maintain compability.  There are many things I could change if I could break compability.
Then use late bound call

   clsT.Test col()
   CallByName clsT, "Test", VbMethod, col()
The solution to this problem is defining the parameter as object instead of collection, because defining the parameter as collection creates error "Type Mismatch" sometimes but it does work sometimes.
ArgonautAuthor Commented:
As I pointed out in my original question and in a comment.  The function cannot be changed because I must maintain compatibility in the DLL.  Sure this may work, but if I could break compatibility there would be many solutions and I would not need to ask the question.  Also I have not see any bug report from Microsoft regarding type mismatch problems with collections.

Ameba has a better solution.  Even though it does not explain why this problem exists Ameba does offer a viable solution.

Ameba, submit your comment as an answer.  Thanks
ArgonautAuthor Commented:
Thanks for the points.

>why this problem exists
This was not easy to implement so MS postponed solving it. :-)

Similarly, to pass control array, one must use 'As Object':
   Sub Test(ctrlArr As Object)
instead of
   Sub Test(ctrlArr() As TextBox)
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Introducing Cloud Class® training courses

Tech changes fast. You can learn faster. That’s why we’re bringing professional training courses to Experts Exchange. With a subscription, you can access all the Cloud Class® courses to expand your education, prep for certifications, and get top-notch instructions.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now