Пример #1
0
///////////////////////////////////////////////////////////////////////////////
// loads a gls extension. #TODO: Robust name to path resolution.
GLS_EXTENSION_MODULE *gls::gls_extension_load (
												const char *name, 
												unsigned long req_options, 
												ExtensionHost *pHost
												) 
{
	// validate name
	size_t lenName = strlen(name);
	if (lenName == 0 || lenName > GLS_EXTENSION_MAX_PATH_LEN) {
		return NULL;
	}

	// make lib path; keep enough space for path expanding {
	// char libPath [GLS_EXTENSION_MAX_LIB_NAME_LEN + 50];
	char libPath [MAX_PATH];
#ifdef GLS_EXTENSION_LOAD_TREAT_NAME_AS_PATH
	strcpy (libPath, name);
#else
	sprintf (libPath, "extensions\\%s%s.%s", 
			EXT_MOD_NAME_PREFIX, name, EXT_MOD_EXT_NAME
			);
#endif
	// } make lib path

	// load the extension module	
#ifdef WIN32
	HMODULE hExtMod = EXT_LOAD(libPath);
#else
	void *hExtMod = NULL;
#endif

	if (hExtMod == NULL) {
		return NULL; // failed to load the module
	}

	// get extension module entry points
	pfn_gls_extension_initialize		pfn_ext_init;
	pfn_gls_extension_terminate			pfn_ext_term;
	pfn_gls_extension_get_interface		pfn_ext_get_int;	

	EXT_ENTRY_POINT (hExtMod, pfn_ext_init, gls_extension_initialize);
	EXT_ENTRY_POINT (hExtMod, pfn_ext_term, gls_extension_terminate);
	EXT_ENTRY_POINT (hExtMod, pfn_ext_get_int, gls_extension_get_interface);

	// check for missing exports
	if (!pfn_ext_init || !pfn_ext_term || !pfn_ext_get_int) {
		EXT_UNLOAD(hExtMod);
		return NULL;
	}

	// try to initialize the extension
	if (!pfn_ext_init (pHost)) {
		EXT_UNLOAD(hExtMod);
		return NULL; // failed to initialize the extension
	}

	// get the extension interface and query extension capabilities
	Extension *pExtension = pfn_ext_get_int ();
	if (pExtension == NULL) {
		EXT_UNLOAD(hExtMod);
		return NULL;
	}
	
	// get extension's interface version
	unsigned short ext_int_ver = pExtension->GetInterfaceVersion ();
	unsigned char ext_int_ver_maj, ext_int_ver_min;
	ext_int_ver_maj = GLS_VERSION_GET_MAJOR(ext_int_ver);
	ext_int_ver_min = GLS_VERSION_GET_MINOR(ext_int_ver);

	// check for minimum interface version; extension's interface version
	// must be atleast equal to the required interface version
	unsigned char req_int_ver_maj, req_int_ver_min;
	req_int_ver_maj = 0;
	req_int_ver_min = 1;
	if ( (ext_int_ver_maj < req_int_ver_maj) ||
		 (ext_int_ver_maj == req_int_ver_maj && ext_int_ver_min < req_int_ver_min)
		 ) {
		EXT_UNLOAD(hExtMod); // extension interface version is lower than required
		return NULL;
	}

	// query extension capabilities
	unsigned long capabilities = pExtension->GetCapabilities ();
	if ( (capabilities & req_options) != req_options ) {
		EXT_UNLOAD(hExtMod); // one or more capability not supported
		return NULL;
	}

	// query lib features
	GLS_EXTENSION_LIB_INFO libInfo;
	void *pLibInterface;
	if (req_options & GLS_EXTENSION_LIBRARY) {
		pExtension->GetLibInfo (&libInfo);
		pLibInterface = pExtension->GetLibInterface ();
		if (pLibInterface == NULL) {
			EXT_UNLOAD(hExtMod); // library interface not returned
			return NULL;
		}
	}

	// alloc a new extension module instance and return it
	GLS_EXTENSION_MODULE *pExtMod = new GLS_EXTENSION_MODULE ();
	memset (pExtMod, 0, sizeof(GLS_EXTENSION_MODULE));

	strcpy ( pExtMod->path, name );
	pExtMod->interfaceVersion = ext_int_ver;
	pExtMod->capabilities = capabilities;
	pExtMod->hModule = (void *)hExtMod;
	pExtMod->pExtInterface = pExtension;

	if (req_options & GLS_EXTENSION_LIBRARY) {
		memcpy (&pExtMod->libInfo, &libInfo, sizeof(GLS_EXTENSION_LIB_INFO));
		// pExtMod->pLibInterface = reinterpret_cast<_GLScriptExtLib *> (pLibInterface);
		pExtMod->pLibInterface = pLibInterface;
	}

	return pExtMod;
}
HRESULT STDMETHODCALLTYPE GLScript_Engine::require (BSTR bstr_path, VARIANT var_options, 
                                                    IDispatch **ppDispatchExtLib) 
{
    // default loading options to use for the 'require' call for loading extensions
    const long DEF_LOAD_OPTIONS = GLS_EXTENSION_LIBRARY;

    // supported loading options
    const long SUPPORTED_LOAD_OPTIONS = (GLS_EXTENSION_RENDERER | 
                                        GLS_EXTENSION_LIBRARY);

    // check for invalud arguments
    if (bstr_path == NULL || ppDispatchExtLib == NULL) {
        return E_POINTER;
    }
    *ppDispatchExtLib = NULL;

    // parse the variant options argument for the loading options. The loading options
    // can be specified as a string encoded options or as a long interger bitmask. the
    // loading options is optional, in which case default loading options is used.
    long load_options;  
    
    if (var_options.vt == VT_ERROR) {
        // use default loading options variant's internal type is VT_ERROR, which means
        // no value was supplied for this parameter.
        load_options = DEF_LOAD_OPTIONS;
    } else if (var_options.vt == VT_BSTR) {
        // parse load options from string encoded options
        if (!ParseExtensionLoadOptions (var_options.bstrVal, load_options)) {
            return E_INVALIDARG;
        }
    } else {
        // assume load options as a long type and fetch the value from the variant
        if (!gls_comvariant_get_long_value (&var_options, &load_options)) {
            return E_INVALIDARG;
        }
    }

    // check for any option that is not supported in the current environment
    if ( (load_options & SUPPORTED_LOAD_OPTIONS) != load_options ) {
        return E_INVALIDARG;
    }
    
    GLScriptHost_Win32 *pHost = reinterpret_cast<GLScriptHost_Win32 *>(GetParent());
    
    // extension load options has been successfully parsed so next task is to build the 
    // extension path to load it
    UINT path_length = ::SysStringLen(bstr_path);
    char *ascii_path_buff = new char [path_length + 1];
    ::wcstombs (ascii_path_buff, bstr_path, path_length);
    ascii_path_buff [path_length] = '\0';

    // load the extension using the extension host object
    Extension *pExtension = pHost->m_ext_host.LoadExtension (ascii_path_buff, load_options);

    delete ascii_path_buff;

    // check if extension failed to load
    if (pExtension == NULL) {
        // failed to load the extension. notify the host about the error.
        if (pHost->m_pEventListener != NULL) {
            tstring str_error (_T("Failed to load the extension '"));
#ifdef UNICODE
            str_error+= bstr_path;
#else
            str_error+= WS2MBS(bstr_path);
#endif
            str_error+= _T("'.");

            pHost->RaiseHostError (str_error.c_str());
        }
        // #TODO: return error only if strict mode is set
        return E_FAIL;
    }

    // hook render proc if "renderer" option is specified
    if (load_options & GLS_EXTENSION_RENDERER) {
        pHost->m_ext_host.HookRenderProc (pExtension->GetRenderProc(), pExtension);
    }
    
    // Return the lib interface if required
    if (load_options & GLS_EXTENSION_LIBRARY) {
        // return the IDispatch interface
        *ppDispatchExtLib = reinterpret_cast<IDispatch *>(pExtension->GetLibInterface());
        (*ppDispatchExtLib)->AddRef ();
    }

    return NOERROR;
}