Hola a todos.
Este proyecto consiste en un MSFlexGrid editable, que contiene los datos de una tabla, con un ComboBox en una columna que toma los datos de otra tabla.
En el Load() carga los datos del Grid en un array y al salir lo mismo en otro array, antes de cerrar el programa compara los dos arrays y si se ha modificado algún dato del Grid, actualiza la tabla (o no, según decida el usuario).
En el Form:
- Un Control MSFlexGrid (evidentemente).
- Un ComboBox (en cualquier parte del Form) con la propiedad Style a 2
- Tres CommandButton con los nombres cmdAñadir, cmdEliminarFila y cmdSalir
- Y un Label (Label1) que indica el número de filas del Grid (esto no es necesario, lo puse para controlar)

Bueno, sin más preámbulos, ahí va el código. Si alguien tiene alguna duda o sugerencia que la exponga.

Código:
  1. Option Explicit
  2. Dim cn As New ADODB.Connection
  3. Dim rs As New ADODB.Recordset
  4. Dim rsAux As New ADODB.Recordset
  5. Dim aArray1() As String ' Para cargar los datos del Grid al inicio del programa
  6. Dim aArray2() As String ' Para cargar los datos del Grid al pulsar el botón "Salir"
  7. Const CELDA_COMBO = 2 ' Constante que indica el número de columna del ComboBox
  8. Private Sub cmdAñadir_Click()
  9.  Dim i As Integer
  10.  ' añadimos una fila en blanco y nos posicionamos en la 1ª celda
  11. With MSFlexGrid1
  12.  .Rows = .Rows + 1
  13.  For i = 0 To .Rows - 1
  14.   .RowHeight(i) = 300
  15.  Next
  16.  .Row = i - 1
  17.  .Col = 0
  18.  .TopRow = i - 1
  19.  Label1.Caption = .Rows - 1 & " Filas"
  20.  End With
  21.  MSFlexGrid1_EnterCell
  22.  MSFlexGrid1.SetFocus
  23. End Sub
  24. Private Sub cmdEliminarFila_Click()
  25.  Dim r As Integer, i As Integer
  26.  
  27.  With MSFlexGrid1
  28.  i = .Row
  29.  If .Row = .Rows - 1 Then
  30.   .Col = 0
  31.   If .TextMatrix(.Row, .Col) = "" Then
  32.   ' última fila y en blanco, borramos sin preguntar
  33. .RemoveItem i
  34.   Exit Sub
  35.   End If
  36.  End If
  37.  r = MsgBox("¿Seguro que quieres eliminar este registro?", vbYesNo + vbDefaultButton2 + vbQuestion, "Atención")
  38.  If r = vbYes Then
  39.   .RemoveItem i
  40.   .Col = 0
  41.   .Row = 1
  42.   Label1.Caption = .Rows - 1 & " Filas"
  43.  End If
  44.  End With
  45. End Sub
  46. Private Sub cmdSalir_Click()
  47.  Dim r As Integer, i As Integer, j As Integer
  48.  Dim sql As String
  49.  On Error GoTo hayErr
  50.  
  51.  ' comprobar si la última fila está en blanco y eliminarla
  52. With MSFlexGrid1
  53.  .Row = .Rows - 1
  54.  .Col = 0
  55.  If .TextMatrix(.Row, .Col) = "" Then
  56.   .RemoveItem .Row
  57.  End If
  58.  End With
  59.  ' cargamos en Array2 los datos actuales del Grid y comparamos con
  60. ' los que se cargó en el Load()
  61. CargaArray aArray2()
  62.  ' si los datos son iguales, salimos del programa, si no, preguntamos
  63. If bCompArray(aArray1, aArray2) = True Then
  64.  r = MsgBox("Los datos han cambiado." & Chr(13) & _
  65.   "¿Guardar los cambios?", vbInformation + vbYesNoCancel + vbDefaultButton1, "Salir del programa")
  66.  ' se se ha pulsado el botón "Cancelar" volvemos al Grid sin modificar nada
  67. If r = vbCancel Then Exit Sub
  68.  If r = vbYes Then
  69.   MSFlexGrid1_LeaveCell
  70.   ' borramos todos los registros de la tabla
  71.  sql = "delete * from [PedidosCliente]"
  72.   cn.Execute (sql)
  73.   ' y añadimos los nuevos
  74. For j = 1 To MSFlexGrid1.Rows - 1
  75.   rs.AddNew
  76.   For i = 0 To MSFlexGrid1.Cols - 1
  77.   If Not IsNull(MSFlexGrid1.TextMatrix(j, i)) Then
  78.     rs(i) = MSFlexGrid1.TextMatrix(j, i)
  79.   End If
  80.   Next i
  81.   rs.Update
  82.   Next j
  83.  End If
  84.  End If
  85.  ' finalizar programa
  86. End
  87. hayErr:
  88.  MsgBox Err.Number & " " & Err.Description, vbCritical, "Error"
  89.  
  90. End Sub
  91. Private Function bCompArray(a1() As String, a2() As String) As Boolean
  92.  ' Función que devuelve un valor True si los datos del Grid han cambiado
  93. Dim i As Long
  94.  If UBound(a1) <> UBound(a2) Then
  95.  bCompArray = True
  96.  Exit Function
  97.  Else
  98.  For i = 0 To UBound(a1)
  99.   If StrComp(a1(i), a2(i)) <> 0 Then
  100.   bCompArray = True
  101.   Exit For
  102.   End If
  103.  Next i
  104.  End If
  105. ' MsgBox IIf(bCompArray = True, "Son diferentes", "son iguales")
  106. End Function
  107.  
  108. Private Sub Form_Load()
  109.  ' abrimos la conexión a la BD
  110. cn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Persist Security Info=False;" & _
  111.   "Data Source=" & App.Path & "\Pedidos.mdb"
  112.  ' asignamos los recordset
  113. Set rs = New ADODB.Recordset
  114.  Set rsAux = New ADODB.Recordset
  115.  rsAux.Open "select Portes from CondEntrega", cn, adOpenKeyset, adLockOptimistic
  116.  rsAux.MoveFirst
  117.  ' llenamos el combo con los datos del campo Portes de la Tabla CondEntrega
  118. ' Este campo se corresponde con rs(2) de la tabla [PedidosCliente]
  119. Do Until rsAux.EOF
  120.  Combo1.AddItem rsAux(0)
  121.  rsAux.MoveNext
  122.  Loop
  123.  Combo1.ListIndex = 0
  124.  CargaGrid
  125.  CargaArray aArray1()
  126.  Label1.Caption = MSFlexGrid1.Rows - 1 & " Filas"
  127.  ' estas propiedades hay que ponerlas en tiempo de diseño
  128. '' cmdSalir.TabStop = False
  129. '' cmdAñadir.TabStop = False
  130. '' Combo1.TabStop = False
  131. End Sub
  132. Private Function CargaArray(aArray() As String)
  133.  ' esta función carga los datos del Grid en un array al inicio y
  134. ' al salir para comparar si se han modificado los datos
  135.  
  136.  Dim i As Long, j As Integer
  137.  Dim s As String
  138.  
  139.  ReDim aArray(0 To MSFlexGrid1.Rows - 1)
  140.  For i = 0 To MSFlexGrid1.Rows - 1
  141.  s = ""
  142.  For j = 0 To MSFlexGrid1.Cols - 1
  143.   s = s & MSFlexGrid1.TextMatrix(i, j)
  144.  Next j
  145.  aArray(i) = s
  146.  Next i
  147. End Function
  148. Private Sub CargaGrid()
  149.  Dim i As Integer
  150.  
  151.  ' si el recordset está abierto, lo cerramos
  152. If rs.State = 1 Then rs.Close
  153.  rs.Open "select * from [PedidosCliente]", cn, adOpenKeyset, adLockOptimistic
  154.  ' formateamos y cargamos el Grid
  155. With MSFlexGrid1
  156.  .Rows = 1
  157.  .FocusRect = flexFocusNone
  158.  .AllowBigSelection = False
  159.  ' primero el encabezado
  160. .Cols = rs.Fields.Count
  161.  For i = 0 To .Cols - 1
  162.   .TextMatrix(0, i) = rs.Fields(i).Name
  163.   .ColWidth(i) = rs.Fields(i).DefinedSize * 130
  164.  Next i
  165.  ' ahora los registros del recordset
  166. rs.MoveFirst
  167.  Do Until rs.EOF
  168.   .AddItem rs(0) & vbTab & rs(1) & vbTab & rs(2) & _
  169.   vbTab & rs(3) & vbTab & rs(4) & vbTab & rs(5)
  170.   rs.MoveNext
  171.  Loop
  172.  For i = 0 To .Rows - 1
  173.   .RowHeight(i) = 300
  174.  Next
  175.  .Row = 1
  176.  .Col = 0
  177.  End With
  178.  Combo1.Visible = False
  179. End Sub
  180. Private Sub Combo1_GotFocus()
  181.  Dim i As Integer
  182.  Dim sText As String
  183.  
  184.  sText = MSFlexGrid1.TextMatrix(MSFlexGrid1.Row, CELDA_COMBO)
  185.  For i = 0 To Combo1.ListCount - 1
  186.  If Combo1.List(i) = sText Then
  187.   Combo1.Text = sText
  188.   Exit For
  189.  End If
  190.  Next
  191. End Sub
  192. Private Sub Combo1_KeyDown(KeyCode As Integer, Shift As Integer)
  193.  With MSFlexGrid1
  194.  Select Case KeyCode
  195.  Case vbKeyLeft
  196.   .Col = .Col - 1
  197.  Case vbKeyRight, vbKeyReturn
  198.   .Col = .Col + 1
  199.  Case vbKeyUp
  200.   If .Row <> 1 Then .Row = .Row - 1
  201.  Case vbKeyDown
  202.   If .Row = .Rows - 1 Then
  203.   KeyCode = 0
  204.   Else
  205.   .Row = .Row + 1
  206.   End If
  207.  End Select
  208.  If .Col <> CELDA_COMBO Then Combo1.Visible = False
  209.  End With
  210. End Sub
  211. Private Sub Form_Unload(Cancel As Integer)
  212.  cmdSalir_Click
  213. End Sub
  214. Private Sub MSFlexGrid1_KeyPress(KeyAscii As Integer)
  215.  With MSFlexGrid1
  216.  Select Case KeyAscii
  217.  Case 32 To 127
  218.   ' solo se admiten caracteres imprimibles
  219. .Text = .Text & Chr(KeyAscii)
  220.  Case vbKeyReturn
  221.   If .Col = .Cols - 1 Then
  222.   ' si es la última columna pasamos al principio de la siguiente fila
  223. If .Row = .Rows - 1 Then
  224.   ' es la última fila añadimos una nueva
  225. .Rows = .Rows + 1
  226.   End If
  227.   .Row = .Row + 1
  228.   .Col = 0
  229.   .LeftCol = 0
  230.   Else
  231.   .Col = .Col + 1
  232.   End If
  233.  End Select
  234.  End With
  235. End Sub
  236. Private Sub MSFlexGrid1_KeyDown(KeyCode As Integer, Shift As Integer)
  237.  With MSFlexGrid1
  238.  Select Case KeyCode
  239.  Case vbKeyDelete ' borramos toda la celda
  240.  .Text = ""
  241.  Case vbKeyBack ' borramos el último caracter
  242.  If Len(.Text) > 0 Then
  243.   .Text = Left(.Text, Len(.Text) - 1)
  244.   End If
  245.  End Select
  246.  End With
  247. End Sub
  248. Private Sub MSFlexGrid1_EnterCell()
  249.  With MSFlexGrid1
  250.  If .Col = CELDA_COMBO Then
  251.   ' si es la celda del combo, lo mostramos y le damos el foco
  252. Combo1.Width = .CellWidth
  253.   Combo1.Move .CellLeft + .Left, .CellTop + .Top
  254.   Combo1.Visible = True
  255.   Combo1.SetFocus
  256.   Combo1_GotFocus
  257.  Else
  258.   Combo1.Visible = False
  259.  End If
  260.  End With
  261. End Sub
  262. Private Sub MSFlexGrid1_LeaveCell()
  263.  With MSFlexGrid1
  264.  If .Col = CELDA_COMBO Then
  265.   ' dejamos el valor del combo en la celda
  266.  .TextMatrix(.Row, .Col) = Combo1.Text
  267.   Combo1.Visible = False
  268.  End If
  269.  End With
  270. End Sub
  271. Private Sub MSFlexGrid1_Scroll()
  272.  ' para evitar que se nos quede el combo "pegado"
  273. With MSFlexGrid1
  274.  If .Col = CELDA_COMBO Then
  275.   Combo1.Visible = False
  276.   .Col = .Col + 1
  277.  End If
  278.  End With
  279. End Sub

Espero que le sea de utilidad a alguien.
Saludos.