Index: cpp/frams/param/multiparamload.cpp
===================================================================
--- cpp/frams/param/multiparamload.cpp	(revision 326)
+++ cpp/frams/param/multiparamload.cpp	(revision 333)
@@ -21,4 +21,5 @@
 aborting=false;
 emptyparam.setParamTab(empty_paramtab);
+linenum=0;
 }
 
@@ -99,5 +100,5 @@
 		Param tmp_param;
 		ParamInterface *pi=lastobject.getParamInterface(tmp_param);
-		pi->load(file,true,&aborting);
+		pi->load(file,true,&aborting,&linenum);
 		if ((status!=Finished) && maybeBreak(AfterObject))
 			break;
@@ -120,4 +121,5 @@
 			continue;
 		}
+	linenum++;
 	if (buf[0]=='#')
 		{
@@ -245,5 +247,5 @@
 Param tmp_param;
 ParamInterface *pi=o.getParamInterface(tmp_param);
-pi->load(file,warn_unknown_fields,&aborting);
+pi->load(file,warn_unknown_fields,&aborting,&linenum);
 status=AfterObject;
 return 0;
Index: cpp/frams/param/multiparamload.h
===================================================================
--- cpp/frams/param/multiparamload.h	(revision 326)
+++ cpp/frams/param/multiparamload.h	(revision 333)
@@ -46,4 +46,5 @@
 Param emptyparam;
 bool aborting;
+int linenum;
 
 void init();
Index: cpp/frams/param/param.cpp
===================================================================
--- cpp/frams/param/param.cpp	(revision 326)
+++ cpp/frams/param/param.cpp	(revision 333)
@@ -37,6 +37,6 @@
 static const char *strchrlimit(const char *t, int ch, const char *limit)
 {
-	if (limit<t) return NULL;
-	return (const char*)memchr((const void*)t,ch,limit-t);
+	if (limit < t) return NULL;
+	return (const char*)memchr((const void*)t, ch, limit - t);
 }
 
@@ -392,5 +392,5 @@
 }
 
-int ParamInterface::load(VirtFILE* f, bool warn_unknown_fields, bool *abortable)
+int ParamInterface::load(VirtFILE* f, bool warn_unknown_fields, bool *abortable, int *linenum)
 {
 	SString buf;
@@ -402,4 +402,5 @@
 	while (((!abortable) || (!*abortable)) && loadSStringLine(f, buf))
 	{
+		if (linenum) (*linenum)++;
 		const char* t = (const char*)buf;
 		p0 = t; while ((*p0 == ' ') || (*p0 == '\t')) p0++;
@@ -417,8 +418,19 @@
 					SString s;
 					czytdotyldy(f, s);
+					int lfcount = 1;
+					const char* tmp = s;
+					while (tmp)
+						if ((tmp = strchr(tmp, '\n')))
+						{
+						lfcount++; tmp++;
+						}
 					removeCR(s);
 					int ch; while ((ch = fgetc(f)) != EOF) if (ch == '\n') break;
 					unquoteTilde(s);
+					if (linenum && (flags(i)&PARAM_LINECOMMENT))
+						s = SString::sprintf("@line %d\n", *linenum + 1) + s;
 					set(i, (const char*)s);
+					if (linenum)
+						(*linenum) += lfcount;
 				}
 				else
@@ -440,4 +452,15 @@
 			SString s;
 			czytdotyldy(f, s);
+			if (linenum)
+			{
+				const char* tmp = s;
+				int lfcount = 1;
+				while (tmp)
+					if ((tmp = strchr(tmp, '\n')))
+					{
+					lfcount++; tmp++;
+					}
+				(*linenum) += lfcount;
+			}
 			int ch; while ((ch = fgetc(f)) != EOF) if (ch == '\n') break;
 		}
@@ -453,18 +476,18 @@
 switch (*(t=type(i)))
 {
-	case 'd':
-	{
-		for (i=atol(get(i));i>=0;i--) if (t) t=strchr(t+1,'~');
-		if (t)
-		{
-			t++;
-			char *t2=strchr(t,'~');
-			if (!t2) t2=t+strlen(t);
-			SString str;
-			strncpy(str.directWrite(t2-t),t,t2-t);
-			str.endWrite(t2-t);
-			return str;
-		}
-	}
+case 'd':
+{
+for (i=atol(get(i));i>=0;i--) if (t) t=strchr(t+1,'~');
+if (t)
+{
+t++;
+char *t2=strchr(t,'~');
+if (!t2) t2=t+strlen(t);
+SString str;
+strncpy(str.directWrite(t2-t),t,t2-t);
+str.endWrite(t2-t);
+return str;
+}
+}
 }
 return get(i);
@@ -502,5 +525,5 @@
 {
 	paInt value;
-	if (!ExtValue::parseInt(str,value,false,true))
+	if (!ExtValue::parseInt(str, value, false, true))
 	{
 		paInt mn, mx, def;
@@ -517,5 +540,5 @@
 {
 	double value;
-	if (!ExtValue::parseDouble(str,value,true))
+	if (!ExtValue::parseDouble(str, value, true))
 	{
 		double mn, mx, def;
@@ -538,6 +561,10 @@
 		{
 			if (v.type == TObj)
+			{
 				FMprintf("ParamInterface", "set", FMLV_WARN, "Getting integer value from object reference (%s)", (const char*)v.getString());
-			return setInt(i, (const char*)v.getString());
+				return 0;
+			}
+			else
+				return setInt(i, (const char*)v.getString());
 		}
 	case 'f':
@@ -546,6 +573,10 @@
 		{
 			if (v.type == TObj)
+			{
 				FMprintf("ParamInterface", "set", FMLV_WARN, "Getting floating point value from object reference (%s)", (const char*)v.getString());
-			return setDouble(i, (const char*)v.getString());
+				return 0;
+			}
+			else
+				return setDouble(i, (const char*)v.getString());
 		}
 	case 's': { SString t = v.getString(); return setString(i, t); }
@@ -995,5 +1026,5 @@
 
 		field_end = strchrlimit(t, ',', end); if (!field_end) field_end = end;
-		next_field=field_end;
+		next_field = field_end;
 		while ((field_end>t) && isblank(field_end[-1])) field_end--;
 		quote = strchrlimit(t, '\"', field_end);
Index: cpp/frams/param/param.h
===================================================================
--- cpp/frams/param/param.h	(revision 326)
+++ cpp/frams/param/param.h	(revision 333)
@@ -32,4 +32,5 @@
 #define PARAM_NOISOLATION 4096  //< don't use proxy object in master/slave interactions
 #define PARAM_DEPRECATED  8192  //< this member is deprecated
+#define PARAM_LINECOMMENT 16384 //< Param::load() adds "@line ..." comment when loading multiline (internal use)
 
 typedef int32_t paInt;
@@ -160,5 +161,5 @@
 	int save(VirtFILE*, const char* altname = NULL, bool force = 0);
 	int saveprop(VirtFILE*, int i, const char* p, bool force = 0);
-	int load(VirtFILE*,bool warn_unknown_fields=true,bool *abortable=NULL);///< @return the number of fields loaded
+	int load(VirtFILE*, bool warn_unknown_fields = true, bool *abortable = NULL, int *linenum = NULL);///< @return the number of fields loaded
 	int load2(const SString &, int &);///< @return the number of fields loaded
 
Index: cpp/frams/param/paramobj.h
===================================================================
--- cpp/frams/param/paramobj.h	(revision 326)
+++ cpp/frams/param/paramobj.h	(revision 333)
@@ -15,5 +15,12 @@
 	int numfields;
 	Param par;
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4200) //Cannot generate copy-ctor or copy-assignment operator when UDT contains a zero-sized array
+#endif
 	ExtValue fields[0];
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
 	ParamObject() { numfields = 0; }
 	~ParamObject();
@@ -21,4 +28,6 @@
 	void* operator new(size_t s, int numfields){ return ::operator new(s + sizeof(ExtValue)*numfields); }
 	void* operator new(size_t s){ return ::operator new(s); }
+	void operator delete(void* ptr, int numfields) { ::operator delete(ptr); }
+	void operator delete(void* ptr) { ::operator delete(ptr); }
 	ParamObject *clone();
 	static void p_new(void* obj, ExtValue *args, ExtValue *ret);
