diff --git a/gmap.module gmap.module
index 8b21eb0..52e3504 100644
--- a/gmap.module
+++ gmap.module
@@ -43,7 +43,7 @@ function gmap_defaults() {
   );
   $defaults['behavior'] = array();
   $m = array();
-  $behaviors = module_invoke_all('gmap', 'behaviors', $m);
+  $behaviors = gmap_module_invoke('behaviors', $m);
   foreach ($behaviors as $k => $v) {
     $defaults['behavior'][$k] = $v['default'];
   }
@@ -70,6 +70,26 @@ function gmap_theme() {
 }
 
 /**
+ * Invokes hook_gmap() in every module.
+ *
+ * We can't use module_invoke_all() because we pass $map by reference.
+ */
+function gmap_module_invoke($op, &$map) {
+  foreach (module_implements('gmap') as $module) {
+    $function = $module . '_gmap';
+    $return = array();
+    $result = $function($op, $map);
+    if (isset($result) && is_array($result)) {
+      $return = array_merge_recursive($return, $result);
+    }
+    elseif (isset($result)) {
+      $return[] = $result;
+    }
+  }
+  return $return;
+}
+
+/**
  * Implementation of hook_gmap().
  */
 function gmap_gmap($op, &$map) {
@@ -912,10 +932,7 @@ function theme_gmap($element) {
   // @@@ Bdragon sez: Yeah, would be nice, but hard to guarantee functionality. Not everyone uses the static markerloader.
   $o = '<div style="'. implode('; ', $style) .';" id="'. $element['#id'] .'"'. drupal_attributes($element['#attributes']) .'>'. t('Javascript is required to view this map.') .'</div>';
 
-  // $map can be manipulated by reference.
-  foreach (module_implements('gmap') as $module) {
-    call_user_func_array($module .'_gmap', array('pre_theme_map', &$map));
-  }
+  gmap_module_invoke('pre_theme_map', $map);
 
   if (isset($mapids[$element['#map']])) {
     drupal_set_message(t('Duplicate map detected! GMap does not support multiplexing maps onto one MapID! GMap MapID: %mapid', array('%mapid' => $element['#map'])), 'error');
diff --git a/gmap_macro_builder.module gmap_macro_builder.module
index 4fcd10d..a3d3a84 100644
--- a/gmap_macro_builder.module
+++ gmap_macro_builder.module
@@ -85,9 +85,7 @@ function gmap_macro_builder_form(&$form_state, $settings = array(), $hide = arra
   // @@@ TODO: Roll this next section into an element, it's duplicated from the settings ui.
   $baselayers = array();
 
-  foreach (module_implements('gmap') as $module) {
-    call_user_func_array($module .'_gmap', array('baselayers', &$baselayers));
-  }
+  gmap_module_invoke('baselayers', $baselayers);
 
   $options = array();
   foreach ($baselayers as $name => $layers) {
diff --git a/gmap_parse_macro.inc gmap_parse_macro.inc
index 5332897..47cfe18 100644
--- a/gmap_parse_macro.inc
+++ gmap_parse_macro.inc
@@ -61,7 +61,7 @@ function _gmap_str2coord($str) {
 function _gmap_parse_macro($instring, $ver = 2) {
   // Get a list of keys that are "multiple."
   $m = array();
-  $multiple = module_invoke_all('gmap', 'macro_multiple', $m);
+  $multiple = gmap_module_invoke('macro_multiple', $m);
 
   // Remove leading and trailing tags
   if (substr(trim($instring), -1)==']') {
@@ -347,6 +347,12 @@ function _gmap_parse_macro($instring, $ver = 2) {
   }
 
   // The macro can now be manipulated by reference.
+  // Note: We do NOT use gmap_module_invoke here,
+  // as this $op has weird semantics for backwards
+  // compatibility / convenience reasons.
+  // (Specifically, modules are allowed to do arbitrary
+  // manipulations on $m OR return the changes
+  // they want to apply to $m.)
   foreach (module_implements('gmap') as $module) {
     $additions = call_user_func_array($module .'_gmap', array('parse_macro', &$m));
     if (!empty($additions)) {
diff --git a/gmap_settings_ui.inc gmap_settings_ui.inc
index 4828bb6..90eb6d1 100644
--- a/gmap_settings_ui.inc
+++ gmap_settings_ui.inc
@@ -78,7 +78,7 @@ function gmap_admin_settings(&$form_state) {
 
   // Allow previewable behaviors to affect the preview map.
   $m = array();
-  $behaviors = module_invoke_all('gmap', 'behaviors', $m);
+  $behaviors = gmap_module_invoke('behaviors', $m);
   foreach ($behaviors as $k => $v) {
     if (isset($v['previewable']) && $v['previewable']) {
       $form['gmap_default']['map']['#settings']['behavior'][$k] = $defaults['behavior'][$k];
@@ -171,9 +171,7 @@ function gmap_admin_settings(&$form_state) {
 
   $baselayers = array();
 
-  foreach (module_implements('gmap') as $module) {
-    call_user_func_array($module .'_gmap', array('baselayers', &$baselayers));
-  }
+  gmap_module_invoke('baselayers', $baselayers);
 
   $options = array();
   foreach ($baselayers as $name => $layers) {
@@ -218,7 +216,7 @@ function gmap_admin_settings(&$form_state) {
     '#description' => t('Behavior flags modify how a map behaves. Grayed out flags are not settable here, but may be set on a map by map basis via code or a macro. Changes to behaviors will not affect the preview map shown above until changes are saved.'),
   );
   $m = array();
-  $behaviors = module_invoke_all('gmap', 'behaviors', $m);
+  $behaviors = gmap_module_invoke('behaviors', $m);
   foreach ($behaviors as $k => $v) {
     $form['gmap_default']['behavior'][$k] = array(
       '#type' => 'checkbox',
