#include "XCircuit.h" #include "XCArc.h" #include "XCPolygon.h" #include "XCText.h" #include "xccom-iface.h" #include extern int number_colors; extern colorindex *colorlist; #define CHECK(expr) if ((hres = expr) != S_OK) goto ERRTAG #ifdef USE_DOTNET #include "XCDotNet.h" IDispatch *dotnet_mgr = NULL; HANDLE dotnet_library = NULL; typedef HRESULT(__stdcall *ClrCreateManagedInstance_t)(LPCWSTR pTypeName, REFIID riid, void **ppObject); HRESULT dotnet_init(XCircuit *xc) { HRESULT hres = S_OK; ClrCreateManagedInstance_t ClrCreateManagedInstance; #define ERRTAG FAILED_dotnet_init if (dotnet_library == NULL) dotnet_library = LoadLibrary("mscoree.dll"); ClrCreateManagedInstance = (ClrCreateManagedInstance_t)GetProcAddress(dotnet_library, "ClrCreateManagedInstance"); CHECK(ClrCreateManagedInstance(L"XCircuit.Proxy.Manager, XCircuit", &IID__Object, (void**)&dotnet_mgr)); if (dotnet_mgr != NULL) { VARIANT retval; DISPPARAMS dispParams = { NULL, NULL, 0, 0 }; DISPID dispID; LPOLESTR str = L"get_top_namespace"; CHECK(IDispatch_GetIDsOfNames(dotnet_mgr, &IID_NULL, &str, 1, LOCALE_USER_DEFAULT, &dispID)); CHECK(IDispatch_Invoke(dotnet_mgr, dispID, &IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispParams, &retval, NULL, NULL)); if (retval.vt == VT_DISPATCH) { BSTR nsName = SysAllocString(L"XCircuitDotNetNS"); XCDotNet *dotnet = make_XCDotNet(retval.pdispVal); IDispatch_QueryInterface(&dotnet->iface, &IID_IDispatch, (void**)&retval.pdispVal); hres = IScriptControl_AddObject(xc->engine, nsName, retval.pdispVal, TRUE); SysFreeString(nsName); } } #undef ERRTAG FAILED_dotnet_init: return hres; } void dotnet_finish() { if (dotnet_mgr != NULL) IDispatch_Release(dotnet_mgr); if (dotnet_library != NULL) FreeLibrary(dotnet_library); } HRESULT create_dotnet_control(BSTR name, BOOL staticFlag, IDispatch **disp, XCircuit *xc) { HRESULT hres; if (dotnet_mgr == NULL) dotnet_init(xc); if (dotnet_mgr != NULL) { VARIANT retval, args[3]; DISPPARAMS dispParams = { NULL, NULL, 0, 0 }; DISPID dispID; LPOLESTR memberName = L"new_dotnet"; #define ERRTAG FAILED_create CHECK(IDispatch_GetIDsOfNames(dotnet_mgr, &IID_NULL, &memberName, 1, LOCALE_USER_DEFAULT, &dispID)); args[2].vt = VT_BSTR; args[2].bstrVal = name; args[1].vt = VT_ARRAY; args[1].parray = NULL; args[0].vt = VT_BOOL; args[0].boolVal = (staticFlag == FALSE ? VARIANT_FALSE : VARIANT_TRUE); dispParams.rgvarg = args; dispParams.cArgs = 3; CHECK(IDispatch_Invoke(dotnet_mgr, dispID, &IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispParams, &retval, NULL, NULL)); if (retval.vt == VT_UNKNOWN) { CHECK(IUnknown_QueryInterface(retval.punkVal, &IID__Object, (void**)disp)); IUnknown_Release(retval.punkVal); } else if (retval.vt == VT_DISPATCH) { *disp = retval.pdispVal; } else goto FAILED_create; #undef ERRTAG { XCDotNet *dotnet = make_XCDotNet(*disp); IDispatch_QueryInterface(&dotnet->iface, &IID_IDispatch, (void**)disp); } FAILED_create: disp; } return hres; } #endif /************************************************************************* ************************************************************************* *************************************************************************/ extern HWND topwin; extern Clientdata areastruct; #define TOXCIRCUIT(This) (XCircuit*)TOCOMOBJ(This) STDMETHODIMP XCircuit_InitScript(IXCircuit *This) { XCircuit *xc = TOXCIRCUIT(This); IDispatch *xcDisp = NULL; HRESULT hres = S_OK; IConnectionPointContainer *engineCPC = NULL; IConnectionPoint *engineCP = NULL; DWORD cookie; BSTR lang = SysAllocString(L"JScript"), xcName = SysAllocString(L"XCircuit"); #define ERRTAG err1 CHECK(CoCreateInstance(&CLSID_ScriptControl, NULL, CLSCTX_INPROC_SERVER, &IID_IScriptControl, (void**)&xc->engine)); CHECK(IScriptControl_put_Language(xc->engine, lang)); CHECK(IXCircuit_QueryInterface(This, &IID_IDispatch, (void**)&xcDisp)); CHECK(IScriptControl_AddObject(xc->engine, xcName, xcDisp, TRUE)); CHECK(IScriptControl_QueryInterface(xc->engine, &IID_IConnectionPointContainer, &engineCPC)); CHECK(IConnectionPointContainer_FindConnectionPoint(engineCPC, &DIID_DScriptControlSource, &engineCP)); CHECK(IConnectionPoint_Advise(engineCP, &xc->com.unk_iface, &cookie)); #undef ERRTAG err1: if (xcDisp != NULL) IDispatch_Release(xcDisp); if (engineCPC != NULL) IConnectionPointContainer_Release(engineCPC); if (engineCP != NULL) IConnectionPoint_Release(engineCP); SysFreeString(lang); SysFreeString(xcName); return hres; } STDMETHODIMP XCircuit_ExecuteStatement(IXCircuit *This, BSTR statement) { XCircuit *xc = TOXCIRCUIT(This); HRESULT hres = IScriptControl_AddCode(xc->engine, statement); return hres; } STDMETHODIMP XCircuit_TermScript(IXCircuit *This) { XCircuit *xc = TOXCIRCUIT(This); IScriptControl_Release(xc->engine); return S_OK; } STDMETHODIMP XCircuit_ScriptError(IXCircuit *This) { XCircuit *xc = TOXCIRCUIT(This); IScriptError *err; BSTR src, desc, txt; long line, column, number; char buf[4096]; if (IScriptControl_get_Error(xc->engine, &err) != S_OK) return S_OK; IScriptError_get_Number(err, &number); IScriptError_get_Line(err, &line); IScriptError_get_Column(err, &column); if (number >= XC_E_FIRST && number < XC_E_LAST) { src = L"XCircuit"; desc = XC_ERROR_MSG(number); } else { IScriptError_get_Source(err, &src); IScriptError_get_Description(err, &desc); } IScriptError_get_Text(err, &txt); IScriptError_Clear(err); IScriptError_Release(err); _snprintf(buf, 4096, "XCircuit encountered a script error (line=%d, column=%d, error=%08x)\n" "\n" "Source: %ls\n" "Description: %ls" "%ls%ls", line, column, number, src, desc, (txt != NULL ? L"\n\nText: " : L""), (txt != NULL ? txt : L"")); MessageBox(topwin, buf, "Script error", MB_OK|MB_ICONERROR); return S_OK; } STDMETHODIMP XCircuit_refresh(IXCircuit *This) { refresh(NULL, NULL, NULL); return S_OK; } STDMETHODIMP XCircuit_quit(IXCircuit *This) { quitcheck(NULL, NULL, NULL); return S_OK; } STDMETHODIMP XCircuit_zoomin(IXCircuit *This) { xccom_put_zoom(1, 0.0); return S_OK; } STDMETHODIMP XCircuit_zoomout(IXCircuit *This) { xccom_put_zoom(2, 0.0); return S_OK; } STDMETHODIMP XCircuit_put_zoom(IXCircuit *This, VARIANT val) { char *cmds[] = { "auto" }; int idx; if ((idx = get_string_index_from_variant(&val, cmds, 1)) >= 0) { xccom_put_zoom(0, 0.0); } else { HRESULT hres = VariantChangeType(&val, &val, 0, VT_R4); if (hres != S_OK) return hres; xccom_put_zoom(4, val.fltVal); } return S_OK; } STDMETHODIMP XCircuit_get_zoom(IXCircuit *This, VARIANT *val) { val->vt = VT_R4; val->fltVal = xccom_get_zoom(); return S_OK; } STDMETHODIMP XCircuit_arc(IXCircuit *This, int x, int y, int radius, float angle1, float angle2, IXCArc **pparc) { XCArc *arcobj = (XCArc*)make_XCArc(); arcptr arc; arc = new_arc(NULL, radius, x, y); arcobj->handle = (long)arc; arcobj->type = ARC; arc->width = 1.0; arc->style = NORMAL; arc->color = -1; if (angle2 > angle1) { arc->angle1 = angle1; arc->angle2 = angle2; } IXCObject_update(&arcobj->iface, 1); IXCArc_QueryInterface(&arcobj->iface, &IID_IXCArc, (void**)pparc); return S_OK; } STDMETHODIMP XCircuit_box(IXCircuit *This, int x, int y, int width, int height, IXCPolygon **pppoly) { XCPolygon *polyobj = (XCPolygon*)make_XCPolygon(); polyptr poly; XPoint *pts = (XPoint*)malloc(sizeof(XPoint)*4); pts[0].x = pts[3].x = x; pts[0].y = pts[1].y = y; pts[1].x = pts[2].x = x+width; pts[2].y = pts[3].y = y+height; poly = new_polygon(NULL, &pts, 4); poly->style = NORMAL; poly->width = 1.0; poly->color = -1; polyobj->handle = (long)poly; polyobj->type = POLYGON; IXCObject_update(&polyobj->iface, 1); IXCPolygon_QueryInterface(&polyobj->iface, &IID_IXCPolygon, (void**)pppoly); return S_OK; } STDMETHODIMP XCircuit_polygon(IXCircuit *This, SAFEARRAY *coords, IXCPolygon **pppoly) { long lb, ub; long i; VARIANT elemX, elemY; XPoint *pts; HRESULT hres; polyptr poly; XCPolygon *polyobj; SafeArrayGetLBound(coords, 1, &lb); SafeArrayGetUBound(coords, 1, &ub); if ((ub-lb+1)%2) return ECODE(XC_E_NUMARGS); pts = (XPoint*)malloc(sizeof(XPoint)*((ub-lb+1)/2)); for (i=lb; i<=ub; i++) { SafeArrayGetElement(coords, &i, &elemX); i++; SafeArrayGetElement(coords, &i, &elemY); if ((hres = VariantChangeType(&elemX, &elemX, 0, VT_I2)) != S_OK || (hres = VariantChangeType(&elemY, &elemY, 0, VT_I2)) != S_OK) { free(pts); if (hres = DISP_E_TYPEMISMATCH) return ECODE(XC_E_TYPEMISMATCH); else return hres; } pts[(i-1)/2].x = elemX.iVal; pts[(i-1)/2].y = elemY.iVal; } poly = new_polygon(NULL, &pts, (ub-lb+1)/2); poly->style |= UNCLOSED; poly->color = -1; poly->width = 1.0; polyobj = (XCPolygon*)make_XCPolygon(); polyobj->handle = (long)poly; polyobj->type = POLYGON; IXCObject_update(&polyobj->iface, 1); IXCPolygon_QueryInterface(&polyobj->iface, &IID_IXCPolygon, (void**)pppoly); return S_OK; } STDMETHODIMP XCircuit_text(IXCircuit *This, BSTR txt, int x, int y, IXCText **pptext) { XCText *labelobj = (XCText*)make_XCText(); labelptr label; char *ctxt = convert_from_bstr(txt); stringpart *parts = string_to_parts(ctxt); label = new_label(NULL, parts, NORMAL, x, y); label->color = -1; label->scale = 1.0; label->justify = 0; free(ctxt); labelobj->handle = (long)label; labelobj->type = LABEL; IXCObject_update(&labelobj->iface, 1); IXCText_QueryInterface(&labelobj->iface, &IID_IXCText, (void**)pptext); return S_OK; } typedef struct script_timeout_data { IScriptControl *engine; BSTR code; } script_timeout_data; static void timeout_handler(void *_data, int *ID) { script_timeout_data *data = (script_timeout_data*)_data; IScriptControl_AddCode(data->engine, data->code); free(data->code); free(data); } STDMETHODIMP XCircuit_setTimeout(IXCircuit *This, BSTR expr, int delay, int *ID) { script_timeout_data *data = (script_timeout_data*)malloc(sizeof(script_timeout_data)); data->engine = (TOXCIRCUIT(This))->engine; data->code = _wcsdup(expr); *ID = WinAddTimeOut(delay, (void(*)())timeout_handler, data); return S_OK; } STDMETHODIMP XCircuit_clearTimeout(IXCircuit *This, int ID) { WinRemoveTimeOut(ID); return S_OK; } BOOL COM_autorefresh = 1; STDMETHODIMP XCircuit_put_autorefresh(IXCircuit *This, VARIANT_BOOL newVal) { COM_autorefresh = (newVal == VARIANT_TRUE ? TRUE : FALSE); return S_OK; } STDMETHODIMP XCircuit_get_autorefresh(IXCircuit *This, VARIANT_BOOL *pVal) { *pVal = (COM_autorefresh ? VARIANT_TRUE : VARIANT_FALSE); return S_OK; } STDMETHODIMP XCircuit_filepopup(IXCircuit *This) { getfile(NULL, NORMAL, NULL); return S_OK; } STDMETHODIMP XCircuit_init_dotnet(IXCircuit *This, BSTR assembly) { HRESULT hres = E_NOTIMPL; #ifdef USE_DOTNET if (dotnet_mgr == NULL) hres = dotnet_init(TOXCIRCUIT(This)); else hres = S_OK; /* TODO: make use of assembly name */ #endif return hres; } STDMETHODIMP XCircuit_import(IXCircuit *This, IDispatch *ns) { HRESULT hres = E_NOTIMPL; #ifdef USE_DOTNET DISPPARAMS dispParams = { NULL, NULL, 0, 0 }; VARIANT retval; DISPID dispID; LPOLESTR str = L"GetNamespace"; XCDotNet *dotnet = (XCDotNet*)ns; IDispatch *code; #define ERRTAG FAILED_import CHECK(IDispatch_GetIDsOfNames(dotnet->m_objectproxy, &IID_NULL, &str, 1, LOCALE_USER_DEFAULT, &dispID)); CHECK(IDispatch_Invoke(dotnet->m_objectproxy, dispID, &IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispParams, &retval, NULL, NULL)); CHECK(IScriptControl_get_CodeObject((TOXCIRCUIT(This))->engine, &code)); hres = IDispatch_GetIDsOfNames(code, &IID_NULL, &retval.bstrVal, 1, LOCALE_USER_DEFAULT, &dispID); if (hres != S_OK) { CHECK(IScriptControl_AddObject((TOXCIRCUIT(This))->engine, retval.bstrVal, ns, TRUE)); } else printf("Namespace already imported\n"); #undef ERRTAG FAILED_import: #endif /* USE_DOTNET */ return hres; } STDMETHODIMP XCircuit_load_dotnet_plugin(IXCircuit *This, BSTR filename) { HRESULT hres = E_NOTIMPL; #ifdef USE_DOTNET DISPPARAMS dispParams = { NULL, NULL, 0, 0 }; DISPID dispID; LPOLESTR str = L"load_plugin"; VARIANT arg; #define ERRTAG FAILED_load_dotnet if (dotnet_mgr == NULL) { CHECK(dotnet_init(TOXCIRCUIT(This))); } CHECK(IDispatch_GetIDsOfNames(dotnet_mgr, &IID_NULL, &str, 1, LOCALE_USER_DEFAULT, &dispID)); arg.vt = VT_BSTR; arg.bstrVal = filename; dispParams.rgvarg = &arg; dispParams.cArgs = 1; CHECK(IDispatch_Invoke(dotnet_mgr, dispID, &IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispParams, NULL, NULL, NULL)); #undef ERRTAG FAILED_load_dotnet: #endif return hres; } STDMETHODIMP XCircuit_new_menu(IXCircuit *This, BSTR parent, BSTR name, VARIANT_BOOL is_popup, BSTR after, IXCMenuItem **ppItem) { char *parent_cstr = convert_from_bstr(parent), *name_cstr = convert_from_bstr(name), *after_cstr = convert_from_bstr(after); Widget menu = WinGetMenu(parent_cstr), item = NULL; Arg args[1] = { -1, NULL }; XCMenuItem *mitem; if (after_cstr != NULL && after_cstr[0] != '\0') XtSetArg(args[0], XtNattachTo, after_cstr); item = WinCreateWidget(name_cstr, (is_popup ? XwcascadeWidgetClass : XwmenubuttonWidgetClass), menu, args, 1, 0); free(parent_cstr); free(name_cstr); free(after_cstr); mitem = make_XCMenuItem(item); IUnknown_QueryInterface(&mitem->com.unk_iface, &IID_IXCMenuItem, (void**)ppItem); return S_OK; } STDMETHODIMP XCircuit_get_menu(IXCircuit *This, BSTR name, IXCMenuItem **ppItem) { char *name_cstr = convert_from_bstr(name); Widget menu = WinGetMenu(name_cstr); XCMenuItem *item = NULL; if (menu != NULL) { item = make_XCMenuItem(menu); IUnknown_QueryInterface(&item->com.unk_iface, &IID_IXCMenuItem, (void**)ppItem); } free(name_cstr); return S_OK; } STDMETHODIMP XCircuit_add_color(IXCircuit *This, int red, int green, int blue) { addnewcolorentry(RGB(red, green, blue)); return S_OK; } STDMETHODIMP XCircuit_put_color(IXCircuit *This, int cval) { int cindex; cval = cval & 0x00FFFFFF; addnewcolorentry(cval); for (cindex=0; cindexcom); xccom_object_add_interface(&ptr->com, &IID_IXCircuit, &vtbl); xccom_object_create_dispatch_interface(&ptr->com, &IID_IXCircuit, COM_get_typeinfo(&IID_IXCircuit)); xccom_object_add_connectionpoint(&ptr->com, &DIID_DXCEvents); return ptr; }