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

C - Level JSAPI - Array Object returns crash

New Here ,
Jun 08, 2023 Jun 08, 2023

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.pngexpand image

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
568
Translate
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
 **************************************************************
...
Translate
New Here ,
Jun 19, 2023 Jun 19, 2023
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!

Translate
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