Public Class MeshPlus
    Implements IDisposable

    Public MasterMesh As Mesh
    Public MMMtrls() As Material
    Public MMTxtrs() As Texture
    Public ReadOnly SubsetsEx As Integer

    Public Sub New(ByVal Filename As String, ByVal Options As MeshFlags, ByVal D As Device)
        Dim Ems() As ExtendedMaterial, LV As Integer
        'Merely holds a material and a filename for a texture.

        'MasterMesh = Mesh.FromFile(Application.StartupPath & "\mball.x", MeshFlags.SoftwareProcessing, D9)

        'You can use the one above if you have a material and texture that you will be supplying to the mesh.

        'However, the material and texture can be included within the .x file.

        MasterMesh = Mesh.FromFile(Filename, Options, D, Ems)
        'Loads the mesh from file.  .x data goes into the Extended Material array.

        'The number of entries corresponds to the number of materials and textures.

        SubsetsEx = Ems.GetUpperBound(0)
        MMMtrls = New Material(SubsetsEx) {}
        MMTxtrs = New Texture(SubsetsEx) {}

        For LV = 0 To SubsetsEx
            MMMtrls(LV) = Ems(LV).Material3D
            'Set the material.  3D means DX3D.

            MMMtrls(LV).Ambient = MMMtrls(LV).Diffuse
            'Ambient property is lost within the loader or in the .x file.
            'But anyway, this property must be set in VB.

            'Not every mesh will have a texture, so meshes without textures will have Texture = Nothing
            If Not (Ems(LV).TextureFilename Is Nothing) Then
                MMTxtrs(LV) = TextureLoader.FromFile(D, Ems(LV).TextureFilename)
            End If

        'All of this information will be used when drawing the mesh.
    End Sub
    Public Sub DrawAllSubsets(ByVal D As Device)
        'Each subset must be drawn separately and is what we extracted data from.
        Dim LV As Integer
        For LV = 0 To SubsetsEx
            D.Material = MMMtrls(LV)
            'Set the appropriate material for this subset.
            If MMTxtrs(LV) Is Nothing Then
                D.SetTexture(0, Nothing)
                'Clear unset texture.
                D.SetTexture(0, MMTxtrs(LV))
                'And the appropriate texture.
            End If

            'Then draw the mesh subset.

    End Sub

    Public Sub Dispose() Implements System.IDisposable.Dispose
        Dim LV As Integer
        For LV = 0 To SubsetsEx
    End Sub
End Class
Sample of usage:
    Dim MM As MeshPlus
        MM = New MeshPlus(Application.StartupPath & "\tree.x", MeshFlags.SoftwareProcessing, D9)
'Set up.

But anyway, what I was going to bring up newly in this the ability to move a mesh to another point in the world - because neither the mesh nor the mesh loader function have any properties telling you where to position the mesh. To position the mesh at a different point, you must apply world transformations - effectively meaning you don't move the mesh to a place in the world, but you move the world in place for the mesh. Sounds weird, but that's the recommended way to move a mesh. Fortunately, it only seems weird in concept - doing it is easy.
    Dim MasterMesh As MeshPlus, Mx As Matrix
For this one, we'll declare an extra matrix for world transformation purposes and we'll end up drawing our mesh like the following (after the transform)
        D9.Transform.World = Mx
        'Applying a world transform allows us to move meshes.
        'By moving the world, then drawing the mesh will cause the world to be changed so that the
        'mesh's default position is not the same as in the original.
        'Resetting the world matrix to the identity fixes everything, except the mesh is now drawn different.

        D9.Transform.World = Matrix.Identity
And to move the mesh, we can rotate it about an axis, scale it to make it bigger or stretch it, and translate (move) it:
        'Matrix rotation so that our tree rotates by 90.
        Mx = Matrix.RotationX(PiHalf)
        'Stretch the tree so that it is four times as tall.
        Mx.Multiply(Matrix.Scaling(1.0F, 1.0F, 4.0F))
        'Move the tree east 2 units and south 2 units.
        Mx.Multiply(Matrix.Translation(2.0F, 2.0F, 0.0F))
Note the RotationX is only assigned (because the matrix is empty at that point), but the subsequent matrix operations are multiplied. They're just like numbers - I have to have something in there that is not a zero before I can start multiplying (otherwise, I'll keep getting zero). Also, the order is very important in matrix multiplication. You will always want to rotate and scale before you translate. If you translate before you rotate, your mesh will be rotated from its current position about the origin, and you probably won't want that. If you scale after translate, your scale will push the mesh away from the origin. Rotation and scaling are all a matter of taste. You'll probably scale before you rotate - the only big problem with the order is if you want to scale only one or two of the dimensions (make X and Y longer, for example). The only reason why I rotate before I scale is because Milkshape wants Y to be up, but I insist that Z should be up.
.vb file