--- a/plugins/fn-lookup/functions.c
+++ b/plugins/fn-lookup/functions.c
@@ -1686,10 +1686,10 @@ static GnmFuncHelp const help_hyperlink[] = {
 static GnmValue *
 gnumeric_hyperlink (GnmFuncEvalInfo *ei, GnmValue const * const *args)
 {
-	GnmValue const * v = args[1];
+	GnmValue const * v = args[1], *uri = args[0];
 	if (v == NULL)
-		v = args[0];
-	return value_dup (v);
+		v = uri;
+	return value_new_hlink_nocopy (value_get_as_string (v), value_get_as_string(uri));
 }
 
 /***************************************************************************/
diff --git a/src/collect.c b/src/collect.c
index 03f1b9e..3e9952c 100644
--- a/src/collect.c
+++ b/src/collect.c
@@ -357,6 +357,7 @@ callback_function_collect (GnmEvalPos const *ep, GnmValue const *value,
 		x = value_get_as_float (value);
 		break;
 
+	case VALUE_HLINK:
 	case VALUE_STRING:
 		if (cl->flags & COLLECT_COERCE_STRINGS) {
 			GnmValue *vc = format_match_number (value_peek_string (value),
diff --git a/src/gnm-format.c b/src/gnm-format.c
index bf77536..f35dabc 100644
--- a/src/gnm-format.c
+++ b/src/gnm-format.c
@@ -48,6 +48,7 @@ format_nonnumber (GnmValue const *value)
 
 	case VALUE_ERROR:
 	case VALUE_STRING:
+	case VALUE_HLINK:
 		return value_peek_string (value);
 
 	case VALUE_CELLRANGE:
diff --git a/src/gnumeric-fwd.h b/src/gnumeric-fwd.h
index 09993bb..11841c3 100644
--- a/src/gnumeric-fwd.h
+++ b/src/gnumeric-fwd.h
@@ -81,6 +81,7 @@ typedef struct _GnmValueErr		GnmValueErr;
 typedef struct _GnmValueFloat		GnmValueFloat;
 typedef struct _GnmValueRange		GnmValueRange;
 typedef struct _GnmValueStr		GnmValueStr;
+typedef struct _GnmValueHLink		GnmValueHLink;
 typedef struct _PrintInformation        PrintInformation;
 typedef struct _Sheet			Sheet;
 typedef struct _SheetControl		SheetControl;
diff --git a/src/hlink.c b/src/hlink.c
index 3bff0b6..fc34720 100644
--- a/src/hlink.c
+++ b/src/hlink.c
@@ -38,6 +38,7 @@
 #include "expr.h"
 #include "value.h"
 #include "mstyle.h"
+#include "cell.h"
 
 #include <goffice/goffice.h>
 #include <gsf/gsf-impl-utils.h>
@@ -74,7 +75,14 @@ gnm_hlink_activate (GnmHLink *lnk, WBCGtk *wbcg)
 GnmHLink *
 sheet_hlink_find (Sheet const *sheet, GnmCellPos const *pos)
 {
-	GnmStyle const *style = sheet_style_get (sheet, pos->col, pos->row);
+	GnmCell const *cell = sheet_cell_get (sheet, pos->col, pos->row);
+	GnmHLink const *link = cell? value_get_hlink (cell->value): NULL;
+	GnmStyle const *style;
+
+	if (link)
+		return (GnmHLink *) link;
+	
+	style = sheet_style_get (sheet, pos->col, pos->row);
 	return gnm_style_get_hlink (style);
 }
 
diff --git a/src/libgnumeric.c b/src/libgnumeric.c
index c771998..40e952e 100644
--- a/src/libgnumeric.c
+++ b/src/libgnumeric.c
@@ -189,7 +189,9 @@ gnm_pre_parse_init (int argc, gchar const **argv)
 #if !GLIB_CHECK_VERSION(2,32,0)
 	g_thread_init (NULL);
 #endif
+#if !GLIB_CHECK_VERSION(2,36,0)
 	g_type_init ();
+#endif
 
 	/* On win32 argv contains 'ansi' encoded args.  We need to manually
 	 * pull in the real versions and convert them to utf-8 */
diff --git a/src/value.c b/src/value.c
index 3704d4b..1fcc8a8 100644
--- a/src/value.c
+++ b/src/value.c
@@ -43,6 +43,7 @@ static GOMemChunk *value_error_pool;
 static GOMemChunk *value_string_pool;
 static GOMemChunk *value_range_pool;
 static GOMemChunk *value_array_pool;
+static GOMemChunk *value_hlink_pool;
 #define CHUNK_ALLOC(T,p) ((T*)go_mem_chunk_alloc (p))
 #define CHUNK_FREE(p,v) go_mem_chunk_free ((p), (v))
 #else
@@ -440,6 +441,35 @@ value_new_array_empty (guint cols, guint rows)
 	return (GnmValue *)v;
 }
 
+static GnmValue *
+value_new_hlink_str (GOString *str, GOString *uri)
+{
+	GnmValueHLink *v;
+
+	g_return_val_if_fail (str != NULL && uri != NULL, NULL);
+
+	v = CHUNK_ALLOC (GnmValueHLink, value_hlink_pool);
+	*((GnmValueType *)&(v->type)) = VALUE_HLINK;
+	v->fmt = NULL;
+	v->val = str;
+	v->uri = uri;
+	v->link = (GnmHLink *) g_object_new (GNM_HLINK_URL_TYPE, NULL);
+	gnm_hlink_set_target (v->link, uri->str);
+	return (GnmValue *)v;
+}
+
+GnmValue *
+value_new_hlink (char const *str, char const *uri)
+{
+	return value_new_hlink_str (go_string_new (str), go_string_new (uri));
+}
+
+GnmValue *
+value_new_hlink_nocopy (char *str, char *uri)
+{
+	return value_new_hlink_str (go_string_new_nocopy (str), go_string_new_nocopy (uri));
+}
+
 /*
  * Returns TRUE, FALSE, or -1.
  */
@@ -519,6 +549,10 @@ value_new_from_string (GnmValueType t, char const *str, GOFormat *sf,
 		res = value_new_string (str);
 		break;
 
+	case VALUE_HLINK:
+		res = value_new_hlink (str, str); /* not sure this is a good idea */
+		break;
+
 	case VALUE_ARRAY:
 	case VALUE_CELLRANGE:
 	default:
@@ -585,6 +619,13 @@ value_release (GnmValue *value)
 		CHUNK_FREE (value_range_pool, &value->v_range);
 		return;
 
+	case VALUE_HLINK:
+		go_string_unref (value->v_hlink.val);
+		go_string_unref (value->v_hlink.uri);
+		g_object_unref (value->v_hlink.link);
+		CHUNK_FREE (value_hlink_pool, &value->v_hlink);
+		return;
+
 	default:
 		/*
 		 * If we don't recognize the type this is probably garbage.
@@ -652,6 +693,17 @@ value_dup (GnmValue const *src)
 		break;
 	}
 
+	case VALUE_HLINK: {
+		GnmValueHLink *hlink = CHUNK_ALLOC (GnmValueHLink, value_hlink_pool);
+		*((GnmValueType *)&(hlink->type)) = VALUE_HLINK;
+		hlink->fmt = NULL;
+		hlink->val = go_string_ref (src->v_hlink.val);
+		hlink->uri = go_string_ref (src->v_hlink.uri);
+		hlink->link = (GnmHLink *) g_object_ref (src->v_hlink.link);
+		res = (GnmValue *) hlink;
+		break;
+	}
+
 	default:
 		g_warning ("value_dup problem.");
 		res = value_new_empty ();
@@ -733,6 +785,10 @@ value_equal (GnmValue const *a, GnmValue const *b)
 		} else
 			return FALSE;
 
+	case VALUE_HLINK:
+		return go_string_equal (a->v_hlink.val, b->v_hlink.val)
+			&& go_string_equal (a->v_hlink.uri, b->v_hlink.uri);
+
 #ifndef DEBUG_SWITCH_ENUM
 	default:
 		g_assert_not_reached ();
@@ -784,6 +840,9 @@ value_hash (GnmValue const *v)
 		return h;
 	}
 
+	case VALUE_HLINK:
+		return go_string_hash (v->v_hlink.uri); /* may be the displayed string should be used too */
+
 #ifndef DEBUG_SWITCH_ENUM
 	default:
 		g_assert_not_reached ();
@@ -809,6 +868,7 @@ value_get_as_bool (GnmValue const *v, gboolean *err)
 	case VALUE_BOOLEAN:
 		return v->v_bool.val;
 
+	case VALUE_HLINK:
 	case VALUE_STRING: {
 		int i = value_parse_boolean (value_peek_string (v), FALSE);
 		if (i == -1) {
@@ -890,6 +950,7 @@ value_get_as_gstring (GnmValue const *v, GString *target,
 	}
 
 	case VALUE_STRING:
+	case VALUE_HLINK:
 		g_string_append (target, v->v_str.val->str);
 		return;
 
@@ -1013,6 +1074,7 @@ value_get_as_int (GnmValue const *v)
 	case VALUE_EMPTY:
 		return 0;
 
+	case VALUE_HLINK:
 	case VALUE_STRING:
 		return atoi (v->v_str.val->str);
 
@@ -1052,6 +1114,7 @@ value_get_as_float (GnmValue const *v)
 	case VALUE_EMPTY:
 		return 0.;
 
+	case VALUE_HLINK:
 	case VALUE_STRING:
 		return gnm_strto (v->v_str.val->str, NULL);
 
@@ -1185,7 +1248,7 @@ value_diff (GnmValue const *a, GnmValue const *b)
 	tb = VALUE_IS_EMPTY (b) ? VALUE_EMPTY : b->type;
 
 	/* string > empty */
-	if (ta == VALUE_STRING) {
+	if (ta == VALUE_STRING || ta == VALUE_HLINK) {
 		switch (tb) {
 		/* Strings are > (empty, or number) */
 		case VALUE_EMPTY :
@@ -1194,6 +1257,7 @@ value_diff (GnmValue const *a, GnmValue const *b)
 			return DBL_MAX;
 
 		/* If both are strings compare as string */
+		case VALUE_HLINK:
 		case VALUE_STRING :
 			if (go_string_equal (a->v_str.val, b->v_str.val))
 				return 0.;
@@ -1203,7 +1267,7 @@ value_diff (GnmValue const *a, GnmValue const *b)
 			return DBL_MAX;
 		}
 
-	} else if (tb == VALUE_STRING) {
+	} else if (tb == VALUE_STRING || ta == VALUE_HLINK) {
 		switch (ta) {
 		/* (empty, or number) < String */
 		case VALUE_EMPTY :
@@ -1295,7 +1359,7 @@ value_compare_real (GnmValue const *a, GnmValue const *b,
 	tb = VALUE_IS_EMPTY (b) ? VALUE_EMPTY : b->type;
 
 	/* string > empty */
-	if (ta == VALUE_STRING) {
+	if (ta == VALUE_STRING || ta == VALUE_HLINK) {
 		switch (tb) {
 		/* Strings are > (empty, or number) */
 		case VALUE_EMPTY :
@@ -1310,6 +1374,7 @@ value_compare_real (GnmValue const *a, GnmValue const *b,
 			return IS_LESS;
 
 		/* If both are strings compare as string */
+		case VALUE_HLINK:
 		case VALUE_STRING :
 			t = (default_locale) ?
 				(case_sensitive
@@ -1333,7 +1398,7 @@ value_compare_real (GnmValue const *a, GnmValue const *b,
 		default :
 			return TYPE_MISMATCH;
 		}
-	} else if (tb == VALUE_STRING) {
+	} else if (tb == VALUE_STRING || tb == VALUE_HLINK) {
 		switch (ta) {
 		/* (empty, or number) < String */
 		case VALUE_EMPTY :
@@ -1424,6 +1489,7 @@ criteria_inspect_values (GnmValue const *x, gnm_float *xr, gnm_float *yr,
 
 	case VALUE_EMPTY:
 	case VALUE_STRING:
+	case VALUE_HLINK:
 		return CRIT_STRING;
 
 	default:
@@ -1940,6 +2006,27 @@ filter_row:
 	return g_slist_reverse (rows);
 }
 
+/**
+ * value_get_hlink:
+ * @value: #GnmValue
+ *
+ * Returns: (transfer none): the hyperlink when the value has the VALUE_HLINK
+ * type or NULL.
+ **/
+GnmHLink const *
+value_get_hlink (GnmValue const *value)
+{
+	if (value == NULL)
+		return NULL;
+
+	switch (value->type) {
+	case VALUE_HLINK:
+		return ((GnmValueHLink *) value)->link;
+	default:
+		return NULL;
+	}
+}
+
 /****************************************************************************/
 
 GType
diff --git a/src/value.h b/src/value.h
index 9cf6210..c5064ad 100644
--- a/src/value.h
+++ b/src/value.h
@@ -6,6 +6,7 @@
 #include "position.h"
 #include "numbers.h"
 #include "parse-util.h"
+#include "hlink.h"
 #include <glib-object.h>
 
 G_BEGIN_DECLS
@@ -22,7 +23,8 @@ typedef enum {
 	VALUE_ERROR	= 50,
 	VALUE_STRING	= 60,
 	VALUE_CELLRANGE = 70,
-	VALUE_ARRAY	= 80
+	VALUE_ARRAY	= 80,
+	VALUE_HLINK     = 90
 } GnmValueType;
 
 /*
@@ -67,6 +69,13 @@ struct _GnmValueArray {
 	int x, y;
 	GnmValue ***vals;  /* Array [x][y] */
 };
+struct _GnmValueHLink {
+	GnmValueType const type;
+	GOFormat *fmt;
+	GOString *val;
+	GOString *uri;
+	GnmHLink *link;
+};
 
 union _GnmValue {
 	GnmValueType const type;
@@ -77,12 +86,13 @@ union _GnmValue {
 	GnmValueStr	v_str;
 	GnmValueRange	v_range;
 	GnmValueArray	v_array;
+	GnmValueHLink   v_hlink;
 };
 
 #define	VALUE_FMT(v)			((v)->v_any.fmt)
 #define VALUE_IS_EMPTY(v)		(((v) == NULL) || ((v)->type == VALUE_EMPTY))
 #define VALUE_IS_EMPTY_OR_ERROR(v)	(VALUE_IS_EMPTY(v) || (v)->type == VALUE_ERROR)
-#define VALUE_IS_STRING(v)		((v)->type == VALUE_STRING)
+#define VALUE_IS_STRING(v)		((v)->type == VALUE_STRING || (v)->type == VALUE_HLINK)
 #define VALUE_IS_BOOLEAN(v)		((v)->type == VALUE_BOOLEAN)
 #define VALUE_IS_ERROR(v)		((v)->type == VALUE_ERROR)
 #define VALUE_IS_NUMBER(v)		(((v)->type == VALUE_FLOAT) || \
@@ -115,6 +125,9 @@ GnmValue *value_new_error_NA         (GnmEvalPos const *pos);
 GnmValue *value_new_string           (char const *str);
 GnmValue *value_new_string_nocopy    (char *str);
 GnmValue *value_new_string_str       (GOString *str);
+GnmValue *value_new_hlink            (char const *str, char const *uri);
+GnmValue *value_new_hlink_nocopy     (char *str, char *uri);
+
 GnmValue *value_new_cellrange_unsafe (GnmCellRef const *a, GnmCellRef const *b);
 GnmValue *value_new_cellrange        (GnmCellRef const *a, GnmCellRef const *b,
 				      int eval_col, int eval_row);
@@ -223,6 +236,9 @@ GSList *parse_database_criteria (GnmEvalPos const *ep,
 int     find_column_of_field	(GnmEvalPos const *ep,
 				 GnmValue const *database, GnmValue const *field);
 
+GnmHLink const *value_get_hlink (GnmValue const *value);
+
+
 /* Protected */
 void value_init     (void);
 void value_shutdown (void);
