GetFieldByName/SetFieldByName not working?

Are you developing an External using the LiveCode Externals SDK?

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller, robinmiller

Post Reply
Janschenkel
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 977
Joined: Sat Apr 08, 2006 7:47 am
Location: Aalst, Belgium
Contact:

GetFieldByName/SetFieldByName not working?

Post by Janschenkel » Fri Apr 03, 2009 10:56 am

Hi all,

Plodding along with my external development, and though I seem to have conquered my daemons, I am now bumping into a strange problem: I can get and set field context using GetFieldByNum/SetFieldByNum and GetFieldById/SetFieldById - but the GetFieldByName/SetFieldByName pair always results in EXTERNAL_FAILURE.

In all cases I'm interacting with the same field, so I'm not sure why the aforementioned would fail.

Thanks in advance for any ideas!

Jan Schenkel.
Quartam Reports & PDF Library for LiveCode
www.quartam.com

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Location: Berkeley, CA, US
Contact:

Post by mwieder » Fri Apr 03, 2009 10:03 pm

Hmmm... the "byName" functions should be the easiest of the three types to deal with since you don't have to do any type conversions. If your string is formatted properly (trailing null C-string) then it should work. At least it used to work. Example from the docs:

Code: Select all

char *strContents;
int r_error;

/*
   Get the contents of field "Field 1",
   looking only in the foreground for the field,
   and place the contents in a string.
   Then place a copy of the contents in field "Field2" in the
   background.
*/
strContents = GetFieldByName("true", "Field 1", &r_error);
if (!r_error)
{
  SetFieldByName("false", "Field 2", strContents, &r_error);
}
free (strContents);  // free the buffer when we're done

Janschenkel
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 977
Joined: Sat Apr 08, 2006 7:47 am
Location: Aalst, Belgium
Contact:

Post by Janschenkel » Sat Apr 04, 2009 7:01 am

That's why I'm so surprised it didn't work for me. I created a simple test stack with a single field named "testfield" (number: 1, id: 1006) and a button with the following script:

Code: Select all

on mouseUp
   answer "qrttest_getfieldbyname:" && qrttest_getfieldbyname()
   qrttest_setfieldbyname
   answer the result
   answer "qrttest_getfieldbynum:" && qrttest_getfieldbynum()
   qrttest_setfieldbynum
   answer the result
   answer "qrttest_getfieldbyid:" && qrttest_getfieldbyid()
   qrttest_setfieldbyid
   answer the result
end mouseUp
for an external with the following code:

Code: Select all

///////////////////////////////////////////////////////////////////////////////
//
// Revolution external main entry point for 'qrttestbed'
//
// Generated by External Creator V1.00
//
// For language: C++
//

#include <revolution/external.h>

///////////////////////////////////////////////////////////////////////////////
//
// BEGIN USER DEFINITIONS

void qrttest_GetFieldByName(char *p_arguments[], int p_argument_count, char **r_result, Bool *r_pass, Bool *r_error) {
	int t_success;
	char *fieldtext;
	fieldtext = GetFieldByName(NULL, "testfield", &t_success);
	if (t_success == EXTERNAL_SUCCESS) {
		*r_result = strdup("success");
	} else {
		*r_result = strdup("failure");
	}
	free(fieldtext);
	// If we got to here it means there were no errors
	//
	*r_pass = False;
	*r_error = False;
}

void qrttest_SetFieldByName(char *p_arguments[], int p_argument_count, char **r_result, Bool *r_pass, Bool *r_error) {
	int t_success;
	char *fieldtext = "set by qrttestbed";
	SetFieldByName(NULL, "testfield", fieldtext, &t_success);
	if (t_success == EXTERNAL_SUCCESS) {
		*r_result = strdup("success");
	} else {
		*r_result = strdup("failure");
	}
	// If we got to here it means there were no errors
	//
	*r_pass = False;
	*r_error = False;
}

void qrttest_GetFieldByNum(char *p_arguments[], int p_argument_count, char **r_result, Bool *r_pass, Bool *r_error) {
	int t_success;
	char *fieldtext;
	fieldtext = GetFieldByNum(NULL, 1, &t_success);
	if (t_success == EXTERNAL_SUCCESS) {
		*r_result = strdup("success");
	} else {
		*r_result = strdup("failure");
	}
	free(fieldtext);
	// If we got to here it means there were no errors
	//
	*r_pass = False;
	*r_error = False;
}

void qrttest_SetFieldByNum(char *p_arguments[], int p_argument_count, char **r_result, Bool *r_pass, Bool *r_error) {
	int t_success;
	char *fieldtext = "set by qrttestbed";
	SetFieldByNum(NULL, 1, fieldtext, &t_success);
	if (t_success == EXTERNAL_SUCCESS) {
		*r_result = strdup("success");
	} else {
		*r_result = strdup("failure");
	}
	// If we got to here it means there were no errors
	//
	*r_pass = False;
	*r_error = False;
}

void qrttest_GetFieldById(char *p_arguments[], int p_argument_count, char **r_result, Bool *r_pass, Bool *r_error) {
	int t_success;
	char *fieldtext;
	fieldtext = GetFieldById(NULL, 1006L, &t_success);
	if (t_success == EXTERNAL_SUCCESS) {
		*r_result = strdup("success");
	} else {
		*r_result = strdup("failure");
	}
	free(fieldtext);
	// If we got to here it means there were no errors
	//
	*r_pass = False;
	*r_error = False;
}

void qrttest_SetFieldById(char *p_arguments[], int p_argument_count, char **r_result, Bool *r_pass, Bool *r_error) {
	int t_success;
	char *fieldtext = "set by qrttestbed";
	SetFieldById(NULL, 1006L, fieldtext, &t_success);
	if (t_success == EXTERNAL_SUCCESS) {
		*r_result = strdup("success");
	} else {
		*r_result = strdup("failure");
	}
	// If we got to here it means there were no errors
	//
	*r_pass = False;
	*r_error = False;
}

// END USER DEFINITIONS
//
///////////////////////////////////////////////////////////////////////////////


EXTERNAL_BEGIN_DECLARATIONS("qrttestbed")

// BEGIN USER DECLARATIONS

EXTERNAL_DECLARE_COMMAND("qrttest_SetFieldByName", qrttest_SetFieldByName)
EXTERNAL_DECLARE_FUNCTION("qrttest_GetFieldByName", qrttest_GetFieldByName)
EXTERNAL_DECLARE_COMMAND("qrttest_SetFieldByNum", qrttest_SetFieldByNum)
EXTERNAL_DECLARE_FUNCTION("qrttest_GetFieldByNum", qrttest_GetFieldByNum)
EXTERNAL_DECLARE_COMMAND("qrttest_SetFieldById", qrttest_SetFieldById)
EXTERNAL_DECLARE_FUNCTION("qrttest_GetFieldById", qrttest_GetFieldById)

// END USER DECLARATIONS

EXTERNAL_END_DECLARATIONS
Apart from missing the occasional 'free()' statement in this quick test code, I'm not sure what I'm doing wrong.

Thankis for thinking with me,

Jan Schenkel.
Quartam Reports & PDF Library for LiveCode
www.quartam.com

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Location: Berkeley, CA, US
Contact:

Post by mwieder » Sat Apr 04, 2009 7:50 am

I'm a bit surprised that the other calls work - I didn't realize you could set the background parameter to NULL. Assuming that you're working with a field on a card rather than in a background group, try

Code: Select all

fieldtext = GetFieldByName("true", "testfield", &t_success);
and set it to "false" if you're working with a background group field. You can set it to an empty string ("") to search both foreground and background, but that's different from a null string.

Janschenkel
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 977
Joined: Sat Apr 08, 2006 7:47 am
Location: Aalst, Belgium
Contact:

Post by Janschenkel » Sat Apr 04, 2009 3:41 pm

I'm just working from what the comments say in 'external.h'

Code: Select all

//   If p_group is "true" then it has the same effect as searching for
//   'card field'.
//   If p_group is "false" then it has the same effect as searching for
//   'background field'.
//   If p_group is NULL then no modifier is used.
Given that Revolution doesn't really have backgrounds like HyperCard, I figured it didn't need a modifier so I passed NULL. Just tried it with empty, but still no luck.

Even stranger: just to make sure I hadn't made a typo, I changed things slightly so that the short name of the field was passed as a parameter and used that as argument for GetFieldByName/SetFieldByName - but "true", "false", "" and NULL all resulted in failure.

Jan Schenkel.
Quartam Reports & PDF Library for LiveCode
www.quartam.com

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Location: Berkeley, CA, US
Contact:

Post by mwieder » Sat Apr 04, 2009 5:51 pm

Well, that *is* new. I looked in the header file and the comments do indeed say that. That didn't use to be the case. Previously the situation for the p_group argument was

"true" to look for the field on the card
"false" to look for the field on the background
"" to look on both the card and background (recursively)

If p_group is empty and the target stack is in HCaddress mode then the search is performed as if p_group is "true". Maybe the externals api has changed?

Janschenkel
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 977
Joined: Sat Apr 08, 2006 7:47 am
Location: Aalst, Belgium
Contact:

Post by Janschenkel » Tue Apr 07, 2009 9:26 pm

Thanks to the inimitable Mark Wieder, the source of the problem was tracked down to the 'externals.c' file which shipped with the ExternalsEnvironment v3 stack.
Relevant entry in the quality center, with workaround: http://quality.runrev.com/qacenter/show_bug.cgi?id=7913

Hope this helps someone stuck with the same problem. On to the next bug, indubitably hidden in my own code :-)

Jan Schenkel.
Quartam Reports & PDF Library for LiveCode
www.quartam.com

Post Reply

Return to “Building Externals”