Another thought:
If the subelement to sort is an udt...
Type tVec3d
  X as Double
  Y as Double
  Z as Double
End Type

Type t3Dpoint
  Pos as tVec3d
  Color as Long
  '... more ...
End Type

Dim myPoint(123) as t3dPoint

Lets say we would sort the points from left to right ( myPoint().pos.x) it would be a little tricky to use a standard sorting routine...

We could use the sorting-powers of dictionary-module, use the value to sort as dictionary-data, probably has to be formatted, like
String sData = Format(myPoint(index).Pos.x, "0.000000")
and the key for the dictionary-slot would be the actual varptr, also formatted to contain no null:
String sKey = Hex$(Varptr(myPoint(index)))

Fill a dictionary with myPoint().Pos.x, let it sort and then order the real array according to the dictionary-keys that hold all pointers in new order now...

Another, very flexible approach for numeric data to sort:

Create String-array like
String toSort(123) ' same number of elements
For i = 1 to CountOf(myPoint)
  toSort(i) = Format$(myPoint(i).Pos.X, "#.######") & Memory_Get(varptr(myPoint(i)), SizeOf(myPoint))
...
put the element-data to sort by in front, should be formatted to same length if numeric
sort this string-array with regular array sort
truncate the leading bytes of every string again
make the string-array to become one string containing all data
poke$ (memory_set) it at the varptr(myPoint(1))
done

If subelement to sort by would be a String we had to fill the leading bytes with $Spc to have it all same length before we sort