• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
2

C - Level JSAPI - Array Object returns crash

New Here ,
Jun 08, 2023 Jun 08, 2023

Copy link to clipboard

Copied

Hello,

I have been experimenting with the C - level JSAPI in Macromedia Flash 8 and in Animate 23.0.2. I've realized that aside from having to compile to either x86 or x64, the api has remained pretty much the same. However, I discovered that a function that returns an array object would crash Animate, unlike running the same code under Flash 8. Here I have the snippet of code defining a simple test function, which would return an array object, where the 0th element is a + b, and the other a - b:

JSBool computeMath(JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval)
{
	long a, b;
	jsval calcs[2];
	JSObject* arrayObj;

	if (argc != 2)
		return JS_FALSE;

	if (JS_ValueToInteger(cx, argv[0], &a) == JS_FALSE ||
		JS_ValueToInteger(cx, argv[1], &b) == JS_FALSE)
		return JS_FALSE;

	calcs[0] = JS_IntegerToValue(a + b);
	calcs[1] = JS_IntegerToValue(a - b);

	arrayObj = JS_NewArrayObject(cx, sizeof(calcs) / sizeof(calcs[0]), calcs);
	*rval = JS_ObjectToValue(arrayObj);

	return JS_TRUE;
}

 After compiling the .dll under visual studio and moving it to the external libraries folder for Flash 8 (named JSFL_Compute_Math.dll), I run

fl.trace(JSFL_Compute_Math.computeMath(1030, 100));

 Which gives me this in Flash 8's output:

TheBlender18590443wuel_1-1686291197442.png

Meanwhile it instantly crashes Animate for some reason. Perhaps an API function was renamed or rewritten, like JS_ObjectToValue() or JS_NewArrayObject()? This is only an issue when using these functions with Animate. This seems to be the case, since the sample code (which came with Flash 8), whose return jsval is a single integer doesn't have a problem running under Animate:

SBool computeSum(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval)
{
    long a, b, sum;

    // Make sure the right number of arguments were passed in.
    if (argc != 2)
        return JS_FALSE;

    // Convert the two arguments from jsvals to longs.
    if (JS_ValueToInteger(cx, argv[0], &a) == JS_FALSE ||
        JS_ValueToInteger(cx, argv[1], &b) == JS_FALSE)
            return JS_FALSE;

    /* Perform the actual work. */
    sum = a + b;

    /* Package the return value as a jsval. */
    *rval = JS_IntegerToValue(sum);

    /* Indicate success. */
    return JS_TRUE;
}

So, is there a new mm_jsapi.h file for Animate CC, or is this a bug with the current JSAPI?

TOPICS
Code , Error , Other

Views

422

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

New Here , Jun 19, 2023 Jun 19, 2023

Ok, this has been solved!
The problem was in the header file; it didn't explicitly mention that jsvals were 64 bits long for x64 templates; it only defined them as longs, same goes for JSBools. So, I've edited mm_jsapi.h to be able to switch between x86 and x64 templates properly when building:

#ifndef _MM_JSAPI_H_
#define _MM_JSAPI_H_

/*****************************************************************************
 * Public data types
 **************************************************************
...

Votes

Translate

Translate
New Here ,
Jun 19, 2023 Jun 19, 2023

Copy link to clipboard

Copied

LATEST

Ok, this has been solved!
The problem was in the header file; it didn't explicitly mention that jsvals were 64 bits long for x64 templates; it only defined them as longs, same goes for JSBools. So, I've edited mm_jsapi.h to be able to switch between x86 and x64 templates properly when building:

#ifndef _MM_JSAPI_H_
#define _MM_JSAPI_H_

/*****************************************************************************
 * Public data types
 ****************************************************************************/

typedef struct JSContext JSContext;
typedef struct JSObject JSObject;
#if _WIN64 || __x86_64__
typedef long long jsval;
#else
typedef long jsval;
#endif
#ifndef JSBool
#   if _WIN64 || __x86_64__
typedef long long JSBool;
#   else
typedef long JSBool;
#   endif
#endif

typedef JSBool(*JSNative)(JSContext* cx, JSObject* obj, unsigned int argc,
    jsval* argv, jsval* rval);

/* Possible values for JSBool */
#define JS_TRUE 1
#define JS_FALSE 0



/*****************************************************************************
 * Public functions
 ****************************************************************************/

 /* JSBool JS_DefineFunction(unsigned short *name, JSNative call, unsigned int nargs) */
#define JS_DefineFunction(n, c, a) \
    (mmEnv.defineFunction ? (*(mmEnv.defineFunction))(mmEnv.libObj, n, c, a) \
                          : JS_FALSE)

/* unsigned short *JS_ValueToString(JSContext *cx, jsval v, unsigned int *pLength) */
#define JS_ValueToString(c, v, l) \
    (mmEnv.valueToString  ? (*(mmEnv.valueToString))(c, v, l) : (unsigned short *)0)

/* unsigned char *JS_ValueToBytes(JSContext *cx, jsval v, unsigned int *pLength) */
#define JS_ValueToBytes(c, v, l) \
    (mmEnv.valueToBytes  ? (*(mmEnv.valueToBytes))(c, v, l) : (unsigned char *)0)

/* JSBool JS_ValueToInteger(JSContext *cx, jsval v, long *lp); */
#define JS_ValueToInteger(c, v, l) \
    (mmEnv.valueToInteger ? (*(mmEnv.valueToInteger))(c, v, l) : JS_FALSE)

/* JSBool JS_ValueToDouble(JSContext *cx, jsval v, double *dp); */
#define JS_ValueToDouble(c, v, d) \
    (mmEnv.valueToDouble  ? (*(mmEnv.valueToDouble))(c, v, d) : JS_FALSE)

/* JSBool JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp); */
#define JS_ValueToBoolean(c, v, b) \
    (mmEnv.valueToBoolean ? (*(mmEnv.valueToBoolean))(c, v, b) : JS_FALSE)

/* JSBool JS_ValueToObject(JSContext *cx, jsval v, JSObject **op); */
#define JS_ValueToObject(c, v, o) \
    (mmEnv.valueToObject  ? (*(mmEnv.valueToObject))(c, v, o) : JS_FALSE)

/* JSBool JS_StringToValue(JSContext *cx, unsigned short *bytes, uint sz, jsval *vp); */
#define JS_StringToValue(c, b, s, v) \
    (mmEnv.stringToValue  ? (*(mmEnv.stringToValue))(c, b, s, v) : JS_FALSE)

/* JSBool JS_BytesToValue(JSContext *cx, unsigned char *bytes, uint sz, jsval *vp); */
#define JS_BytesToValue(c, b, s, v) \
    (mmEnv.bytesToValue  ? (*(mmEnv.bytesToValue))(c, b, s, v) : JS_FALSE)

/* JSBool JS_DoubleToValue(JSContext *cx, double dv, jsval *vp); */
#define JS_DoubleToValue(c, d, v) \
    (mmEnv.doubleToValue  ? (*(mmEnv.doubleToValue))(c, d, v) : JS_FALSE)

/* jsval JS_IntegerToValue(long lv); */
#define JS_IntegerToValue(lv)       (((jsval)(lv) << 1) | 0x1)

/* jsval JS_BooleanToValue(JSBool bv); */
#define JS_BooleanToValue(bv)       (((jsval)(bv) << 3) | 0x6)

/* jsval JS_ObjectToValue(JSObject *obj); */
#define JS_ObjectToValue(ov)        ((jsval)(ov))

/* unsigned short *JS_ObjectType(JSObject *obj); */
#define JS_ObjectType(o) \
    (mmEnv.objectType     ? (*(mmEnv.objectType))(o) : (unsigned short *)0)

/* JSObject *JS_NewArrayObject(JSContext *cx, unsigned int length, jsval *v) */
#define JS_NewArrayObject(c, l, v) \
    (mmEnv.newArrayObject ? (*(mmEnv.newArrayObject))(c, l, v) : (JSObject *)0)

/* long JS_GetArrayLength(JSContext *cx, JSObject *obj) */
#define JS_GetArrayLength(c, o) \
    (mmEnv.getArrayLength ? (*(mmEnv.getArrayLength))(c, o) : -1)

/* JSBool JS_GetElement(JSContext *cx, JSObject *obj, jsint idx, jsval *vp) */
#define JS_GetElement(c, o, i, v) \
    (mmEnv.getElement     ? (*(mmEnv.getElement))(c, o, i, v) : JS_FALSE)

/* JSBool JS_SetElement(JSContext *cx, JSObject *obj, jsint idx, jsval *vp) */
#define JS_SetElement(c, o, i, v) \
    (mmEnv.setElement     ? (*(mmEnv.setElement))(c, o, i, v) : JS_FALSE)

/* JSBool JS_ExecuteScript(JSContext *cx, JSObject *obj, unsigned short *script,
 *     unsigned int sz, jsval *rval) */
#define JS_ExecuteScript(c, o, s, z, r) \
    (mmEnv.executeScript  ? (*(mmEnv.executeScript))(c, o, s, z, _T(__FILE__), \
        __LINE__, r) : JS_FALSE)

 /* JSBool JS_ReportError(JSContext *cx, unsigned short *error, unsigned int sz) */
#define JS_ReportError(c, e, s) \
    (mmEnv.reportError    ? (*(mmEnv.reportError))(c, e, s) : JS_FALSE)



/*****************************************************************************
 * Private data types, macros, and globals
 ****************************************************************************/

typedef struct {
    JSObject* libObj;
    JSBool(*defineFunction)(JSObject* libObj, unsigned short* name, JSNative call,
        unsigned int nargs);
    unsigned short* (*valueToString)(JSContext* cx, jsval v, unsigned int* pLength);
    unsigned char* (*valueToBytes)(JSContext* cx, jsval v, unsigned int* pLength);
    JSBool(*valueToInteger)(JSContext* cx, jsval v, long* lp);
    JSBool(*valueToDouble)(JSContext* cx, jsval v, double* dp);
    JSBool(*valueToBoolean)(JSContext* cx, jsval v, JSBool* bp);
    JSBool(*valueToObject)(JSContext* cx, jsval v, JSObject** op);
    JSBool(*stringToValue)(JSContext* cx, unsigned short* b, unsigned int sz, jsval* vp);
    JSBool(*bytesToValue)(JSContext* cx, unsigned char* b, unsigned int sz, jsval* vp);
    JSBool(*doubleToValue)(JSContext* cx, double dv, jsval* vp);
    unsigned short* (*objectType)(JSObject* obj);
    JSObject* (*newArrayObject)(JSContext* cx, unsigned int length, jsval* vp);
    long (*getArrayLength)(JSContext* cx, JSObject* obj);
    JSBool(*getElement)(JSContext* cx, JSObject* obj, unsigned int idx,
        jsval* vp);
    JSBool(*setElement)(JSContext* cx, JSObject* obj, unsigned int idx,
        jsval* vp);
    JSBool(*executeScript)(JSContext* cx, JSObject* obj, unsigned short* script,
        unsigned int sz, unsigned short* file, unsigned int lineNum, jsval* rval);
    JSBool(*reportError)(JSContext* cx, unsigned short* error, unsigned int sz);
} MM_Environment;

extern MM_Environment mmEnv;

// Declare the external entry point and linkage
#ifdef _WIN32
#   ifndef _MAC  
    // Windows (32 & 64 bit)
extern __declspec(dllexport) void MM_InitWrapper(MM_Environment * env, unsigned int envSize);
#   else
    // Mac with MSVC++ Win32 portability lib
extern void MM_InitWrapper(MM_Environment * env, unsigned int envSize);
#   endif
#else
    // Codewarrior
#   pragma export on    MM_Environment
extern void MM_InitWrapper(*env, unsigned int envSize);
#   pragma export off
#endif


#define MM_STATE                                                                \
    /* Definitions of global variables */                                       \
    MM_Environment mmEnv;                                                       \
                                                                                \
    void                                                                        \
    MM_InitWrapper(MM_Environment *env, unsigned int envSize)                   \
    {                                                                           \
        extern void MM_Init();                                                  \
                                                                                \
        char **envPtr = (char **)env;                                           \
        char **mmPtr =  (char **)(&mmEnv);                                      \
        char **envEnd = (char **)((char *)envPtr + envSize);                    \
        char **mmEnd =  (char **)((char *)mmPtr  + sizeof(MM_Environment));     \
                                                                                \
        /* Copy fields from env to mmEnv, one pointer at a time */              \
        while (mmPtr < mmEnd && envPtr < envEnd)                                \
            *mmPtr++ = *envPtr++;                                               \
                                                                                \
      /* If env doesn't define all of mmEnv's fields, set extras to NULL */     \
        while (mmPtr < mmEnd)                                                   \
            *mmPtr++ = (char *)0;                                               \
                                                                                \
      /* Call user's MM_Init function */                                        \
      MM_Init();                                                                \
    }                                                                           \

#endif /* _MM_JSAPI_H_ */

 For anyone who reads this post in the future, hope this helps when creating advanced JSAPI tools in Flash/Animate on 64-bit machines!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines