53 #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit
79 #include <epicsGuard.h>
81 #define MAX_PATH_LEN 256
83 static epicsThreadOnceId
onceId = EPICS_THREAD_ONCE_INIT;
88 _com_error com_error(hr, perrinfo);
90 std::string message = com_error.Description();
96 CoInitializeEx(NULL, COINIT_MULTITHREADED);
105 throw std::runtime_error(
"m_pxmldom is NULL");
107 epicsGuard<epicsMutex> _lock(
m_lock);
108 std::map<std::string,std::string>::const_iterator it =
m_xpath_map.find(xpath);
113 IXMLDOMNode *pNode = NULL;
115 BSTR bstrValue = NULL;
116 HRESULT hr =
m_pxmldom->selectSingleNode(_bstr_t(xpath.c_str()), &pNode);
117 if (SUCCEEDED(hr) && pNode != NULL)
119 hr=pNode->get_text(&bstrValue);
122 S_res = CW2CT(bstrValue);
123 SysFreeString(bstrValue);
139 throw std::runtime_error(
"m_pxmldom is NULL");
141 epicsGuard<epicsMutex> _lock(
m_lock);
142 std::map<std::string,bool>::const_iterator it =
m_xpath_bool_map.find(xpath);
147 IXMLDOMNode *pNode = NULL;
149 BSTR bstrValue = NULL;
150 std::string bool_str;
151 HRESULT hr =
m_pxmldom->selectSingleNode(_bstr_t(xpath.c_str()), &pNode);
152 if (SUCCEEDED(hr) && pNode != NULL)
154 hr=pNode->get_text(&bstrValue);
157 bool_str = CW2CT(bstrValue);
158 if (bool_str.size() == 0)
164 else if ( (bool_str[0] ==
't') || (bool_str[0] ==
'T') || (bool_str[0] ==
'y') || (bool_str[0] ==
'Y') || (atol(bool_str.c_str()) != 0) )
172 SysFreeString(bstrValue);
186 std::string lvDCOMInterface::doXPATH_old(
const std::string& xpath)
190 throw std::runtime_error(
"m_cfg is NULL");
192 std::map<std::string,std::string>::const_iterator it =
m_xpath_map.find(xpath);
198 TinyXPath::xpath_processor xp_proc(m_root, xpath.c_str());
200 std::string S_res = xp_proc.S_compute_xpath().c_str();
206 bool lvDCOMInterface::doXPATHbool_old(
const std::string& xpath)
210 throw std::runtime_error(
"m_cfg is NULL");
212 std::map<std::string,bool>::const_iterator it =
m_xpath_bool_map.find(xpath);
218 TinyXPath::xpath_processor xp_proc(m_root, xpath.c_str());
219 bool res = xp_proc.o_compute_xpath();
229 std::string S_res =
doXPATH(xpath);
230 char* exp_str = macEnvExpand(S_res.c_str());
233 std::replace(S_res.begin(), S_res.end(),
'/',
'\\');
240 HRESULT hr=CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_SERVER,
241 IID_IXMLDOMDocument2, (
void**)&
m_pxmldom);
244 throw std::runtime_error(
"Cannot load DomFromCom");
249 m_pxmldom->put_validateOnParse(VARIANT_FALSE);
250 m_pxmldom->put_resolveExternals(VARIANT_FALSE);
254 throw std::runtime_error(
"Cannot load DomFromCom");
266 lvDCOMInterface::lvDCOMInterface(
const char *configSection,
const char* configFile,
const char* host,
int options,
const char* progid,
const char* username,
const char* password) :
267 m_configSection(configSection), m_pidentity(NULL), m_pxmldom(NULL), m_options(options),
268 m_progid(progid != NULL? progid :
""), m_username(username != NULL? username :
""), m_password(password != NULL ? password :
"")
272 if (host != NULL && host[0] !=
'\0')
299 short sResult = FALSE;
300 char* configFile_expanded = macEnvExpand(configFile);
302 HRESULT hr =
m_pxmldom->load(_variant_t(configFile_expanded), &sResult);
303 free(configFile_expanded);
306 throw std::runtime_error(
"Cannot load \"" +
m_configFile +
"\" (expanded from \"" + std::string(configFile) +
"\"): load failure");
308 if (sResult != VARIANT_TRUE)
310 throw std::runtime_error(
"Cannot load \"" +
m_configFile +
"\" (expanded from \"" + std::string(configFile) +
"\"): load failure");
312 std::cerr <<
"Loaded config file \"" <<
m_configFile <<
"\" (expanded from \"" << configFile <<
"\")" << std::endl;
319 throw std::runtime_error(
"Cannot find progId " +
m_progid);
324 m_clsid = LabVIEW::CLSID_Application;
325 wchar_t* progid_str = NULL;
326 if ( ProgIDFromCLSID(
m_clsid, &progid_str) == S_OK )
329 CoTaskMemFree(progid_str);
336 wchar_t* clsid_str = NULL;
337 if ( StringFromCLSID(
m_clsid, &clsid_str) == S_OK )
339 std::cerr <<
"Using ProgID \"" <<
m_progid <<
"\" CLSID " << CW2CT(clsid_str) << std::endl;
340 CoTaskMemFree(clsid_str);
344 std::cerr <<
"Using ProgID \"" <<
m_progid <<
"\" but StringFromCLSID() failed" << std::endl;
367 for(vi_map_t::const_iterator it =
m_vimap.begin(); it !=
m_vimap.end(); ++it)
369 LabVIEW::VirtualInstrumentPtr vi_ref = it->second.vi_ref;
370 if ( (!only_ones_we_started || it->second.started) && (vi_ref != NULL) )
372 if (vi_ref->ExecState != LabVIEW::eIdle)
374 std::cerr <<
"stopping \"" << CW2CT(it->first.c_str()) <<
"\" as it was auto-started and is still running" << std::endl;
379 catch(
const std::exception& ex)
381 std::cerr <<
"error stopping vi: " << ex.what() << std::endl;
385 std::cerr <<
"error stopping vi: unknown" << std::endl;
396 _snprintf(control_name_xpath,
sizeof(control_name_xpath),
"/lvinput/section[@name='%s']/vi/param",
m_configSection.c_str());
397 IXMLDOMNodeList* pXMLDomNodeList = NULL;
398 HRESULT hr =
m_pxmldom->selectNodes(_bstr_t(control_name_xpath), &pXMLDomNodeList);
399 if (SUCCEEDED(hr) && pXMLDomNodeList != NULL)
401 pXMLDomNodeList->get_length(&n);
402 pXMLDomNodeList->Release();
411 _snprintf(control_name_xpath,
sizeof(control_name_xpath),
"/lvinput/section[@name='%s']/vi/param",
m_configSection.c_str());
412 IXMLDOMNodeList* pXMLDomNodeList = NULL;
413 HRESULT hr =
m_pxmldom->selectNodes(_bstr_t(control_name_xpath), &pXMLDomNodeList);
414 if (FAILED(hr) || pXMLDomNodeList == NULL)
418 IXMLDOMNode *pNode, *pAttrNode1, *pAttrNode2;
420 pXMLDomNodeList->get_length(&n);
421 for(
long i=0; i<n; ++i)
424 hr = pXMLDomNodeList->get_item(i, &pNode);
425 if (SUCCEEDED(hr) && pNode != NULL)
427 IXMLDOMNamedNodeMap *attributeMap = NULL;
428 pAttrNode1 = pAttrNode2 = NULL;
429 pNode->get_attributes(&attributeMap);
430 hr = attributeMap->getNamedItem(_bstr_t(
"name"), &pAttrNode1);
431 hr = attributeMap->getNamedItem(_bstr_t(
"type"), &pAttrNode2);
432 BSTR bstrValue1 = NULL, bstrValue2 = NULL;
433 hr=pAttrNode1->get_text(&bstrValue1);
434 hr=pAttrNode2->get_text(&bstrValue2);
435 res[std::string(COLE2CT(bstrValue1))] = COLE2CT(bstrValue2);
436 SysFreeString(bstrValue1);
437 SysFreeString(bstrValue2);
438 pAttrNode1->Release();
439 pAttrNode2->Release();
440 attributeMap->Release();
444 pXMLDomNodeList->Release();
449 if (user.size() == 0)
453 COAUTHIDENTITY* pidentity =
new COAUTHIDENTITY;
454 pidentity->Domain = (USHORT*)strdup(domain.c_str());
455 pidentity->DomainLength =
static_cast<ULONG
>(strlen((
const char*)pidentity->Domain));
456 pidentity->Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
457 pidentity->Password = (USHORT*)strdup(pass.c_str());
458 pidentity->PasswordLength =
static_cast<ULONG
>(strlen((
const char*)pidentity->Password));
459 pidentity->User = (USHORT*)strdup(user.c_str());
460 pidentity->UserLength =
static_cast<ULONG
>(strlen((
const char*)pidentity->User));
467 if (pidentity != NULL)
469 hr = CoSetProxyBlanket(pUnk, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
470 RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, pidentity, EOAC_NONE);
473 std::cerr <<
"setIdentity failed" << std::endl;
483 UINT len = SysStringLen(vi_name);
484 std::wstring ws(vi_name, SysStringLen(vi_name));
486 epicsGuard<epicsMutex> _lock(
m_lock);
487 vi_map_t::iterator it =
m_vimap.find(ws);
490 vi = it->second.vi_ref;
511 std::wstring ws(vi_name, SysStringLen(vi_name));
513 if ( (
m_lv != NULL) && (
m_lv->CheckConnection() == S_OK) )
517 else if (
m_host.size() > 0)
519 std::cerr <<
"(Re)Making connection to LabVIEW on " <<
m_host << std::endl;
520 CComBSTR host(
m_host.c_str());
522 COAUTHINFO* pauth =
new COAUTHINFO;
523 COSERVERINFO csi = { 0, NULL, NULL, 0 };
524 pauth->dwAuthnSvc = RPC_C_AUTHN_WINNT;
525 pauth->dwAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT;
526 pauth->dwAuthzSvc = RPC_C_AUTHZ_NONE;
527 pauth->dwCapabilities = EOAC_NONE;
528 pauth->dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
530 pauth->pwszServerPrincName = NULL;
532 csi.pAuthInfo = pauth;
533 MULTI_QI mq[ 1 ] = { 0 };
534 mq[ 0 ].pIID = &IID_IDispatch;
537 hr = CoCreateInstanceEx(
m_clsid, NULL, CLSCTX_REMOTE_SERVER | CLSCTX_LOCAL_SERVER, &csi, 1, mq );
540 hr = CoCreateInstanceEx(
m_clsid, NULL, CLSCTX_ALL, &csi, 1, mq );
544 throw COMexception(
"CoCreateInstanceEx (LabVIEW) ", hr);
546 if( S_OK != mq[ 0 ].hr || NULL == mq[ 0 ].pItf )
548 throw COMexception(
"CoCreateInstanceEx (LabVIEW)(mq) ", mq[ 0 ].hr);
552 m_lv.Attach( reinterpret_cast< LabVIEW::_Application* >( mq[ 0 ].pItf ) );
556 std::cerr <<
"(Re)Making local connection to LabVIEW" << std::endl;
559 hr =
m_lv.CoCreateInstance(
m_clsid, NULL, CLSCTX_LOCAL_SERVER);
567 vi =
m_lv->GetVIReference(vi_name,
"", 1, 8);
573 vi =
m_lv->GetVIReference(vi_name,
"", 0, 0);
577 vi =
m_lv->GetVIReference(vi_name,
"", 1, 8);
582 ViRef viref(vi, reentrant,
false);
585 if (vi->ExecState == LabVIEW::eIdle)
589 std::cerr <<
"Starting \"" << CW2CT(vi_name) <<
"\" on " << (
m_host.size() > 0 ?
m_host :
"localhost") << std::endl;
595 std::cerr <<
"\"" << CW2CT(vi_name) <<
"\" is not running on " << (
m_host.size() > 0 ?
m_host :
"localhost") <<
" and autostart is disabled" << std::endl;
607 throw std::runtime_error(
"getLabviewValue failed (NULL)");
611 _snprintf(vi_name_xpath,
sizeof(vi_name_xpath),
"/lvinput/section[@name='%s']/vi/@path",
m_configSection.c_str());
612 _snprintf(control_name_xpath,
sizeof(control_name_xpath),
"/lvinput/section[@name='%s']/vi/param[@name='%s']/read/@target",
m_configSection.c_str(), param);
613 CComBSTR vi_name(
doPath(vi_name_xpath).c_str());
614 CComBSTR control_name(
doXPATH(control_name_xpath).c_str());
616 if ( v.ChangeType(VT_BSTR) == S_OK )
618 *value = CW2CT(v.bstrVal);
622 throw std::runtime_error(
"getLabviewValue failed (ChangeType BSTR)");
631 throw std::runtime_error(
"getLabviewValue failed (NULL)");
635 _snprintf(vi_name_xpath,
sizeof(vi_name_xpath),
"/lvinput/section[@name='%s']/vi/@path",
m_configSection.c_str());
636 _snprintf(control_name_xpath,
sizeof(control_name_xpath),
"/lvinput/section[@name='%s']/vi/param[@name='%s']/read/@target",
m_configSection.c_str(), param);
637 CComBSTR vi_name(
doPath(vi_name_xpath).c_str());
638 CComBSTR control_name(
doXPATH(control_name_xpath).c_str());
640 if ( v.vt != (VT_ARRAY | CVarTypeInfo<T>::VT) )
642 throw std::runtime_error(
"getLabviewValue failed (type mismatch)");
646 nIn = ( sa.GetCount() > nElements ? nElements : sa.GetCount() );
647 for(LONG i=0; i<nIn; ++i)
649 value[i] = sa.GetAt(i);
654 template <
typename T>
659 throw std::runtime_error(
"getLabviewValue failed (NULL)");
663 _snprintf(vi_name_xpath,
sizeof(vi_name_xpath),
"/lvinput/section[@name='%s']/vi/@path",
m_configSection.c_str());
664 _snprintf(control_name_xpath,
sizeof(control_name_xpath),
"/lvinput/section[@name='%s']/vi/param[@name='%s']/read/@target",
m_configSection.c_str(), param);
665 CComBSTR vi_name(
doPath(vi_name_xpath).c_str());
666 CComBSTR control_name(
doXPATH(control_name_xpath).c_str());
668 if ( v.ChangeType(CVarTypeInfo<T>::VT) == S_OK )
670 *value = v.*(CVarTypeInfo<T>::pmField);
674 throw std::runtime_error(
"getLabviewValue failed (ChangeType)");
681 LabVIEW::VirtualInstrumentPtr vi;
683 *value = vi->GetControlValue(control_name).Detach();
687 throw std::runtime_error(
"getLabviewValue failed");
698 _snprintf(base_xpath,
sizeof(base_xpath), xpath, config_section, param);
720 _snprintf(base_xpath,
sizeof(base_xpath), xpath, config_section, param);
729 CComVariant v(value.c_str()), results;
731 StringItem control_name(
this,
"/lvinput/section[@name='%s']/vi/param[@name='%s']/set/@target",
m_configSection.c_str(), param);
732 StringItem post_button(
this,
"/lvinput/section[@name='%s']/vi/param[@name='%s']/set/@post_button",
m_configSection.c_str(), param);
733 BoolItem post_button_wait(
this,
"/lvinput/section[@name='%s']/vi/param[@name='%s']/set/@post_button_wait",
m_configSection.c_str(), param);
734 BoolItem use_ext(
this,
"/lvinput/section[@name='%s']/vi/param[@name='%s']/set/@extint",
m_configSection.c_str(), param);
738 if (post_button.size() > 0)
746 if (post_button.size() > 0)
751 if (post_button_wait && (post_button.size() > 0) )
764 if ( v.ChangeType(VT_BOOL) == S_OK )
766 done = ( v.boolVal == (value ? VARIANT_TRUE : VARIANT_FALSE) );
769 epicsThreadSleep(0.1);
773 template <
typename T>
776 CComVariant v(value), results;
778 StringItem control_name(
this,
"/lvinput/section[@name='%s']/vi/param[@name='%s']/set/@target",
m_configSection.c_str(), param);
779 StringItem post_button(
this,
"/lvinput/section[@name='%s']/vi/param[@name='%s']/set/@post_button",
m_configSection.c_str(), param);
780 BoolItem post_button_wait(
this,
"/lvinput/section[@name='%s']/vi/param[@name='%s']/set/@post_button_wait",
m_configSection.c_str(), param);
781 BoolItem use_ext(
this,
"/lvinput/section[@name='%s']/vi/param[@name='%s']/set/@extint",
m_configSection.c_str(), param);
785 if (post_button.size() > 0)
793 if (post_button.size() > 0)
798 if (post_button_wait && (post_button.size() > 0) )
807 LabVIEW::VirtualInstrumentPtr vi;
809 hr = vi->SetControlValue(control_name, value);
813 throw std::runtime_error(
"SetLabviewValue failed");
820 CComSafeArray<BSTR> names(6);
821 names[0].AssignBSTR(_bstr_t(L
"VI Name"));
822 names[1].AssignBSTR(_bstr_t(L
"Control Name"));
823 names[2].AssignBSTR(_bstr_t(L
"String Control Value"));
824 names[3].AssignBSTR(_bstr_t(L
"Variant Control Value"));
825 names[4].AssignBSTR(_bstr_t(L
"Machine Name"));
826 names[5].AssignBSTR(_bstr_t(L
"Return Message"));
829 n.vt = VT_ARRAY | VT_BSTR;
830 n.parray = names.Detach();
832 CComSafeArray<VARIANT> values(6);
834 values[1] = control_name;
841 v.vt = VT_ARRAY | VT_VARIANT;
842 v.parray = values.Detach();
850 LabVIEW::VirtualInstrumentPtr vi;
859 hr = vi->Call(&names, &values);
861 CComVariant var(values);
865 throw std::runtime_error(
"CallLabviewValue failed");
872 fprintf(fp,
"XML ConfigFile: \"%s\"\n",
m_configFile.c_str());
873 fprintf(fp,
"XML ConfigFile section: \"%s\"\n",
m_configSection.c_str());
874 fprintf(fp,
"lvDCOMConfigure() Options: %d\n",
m_options);
875 fprintf(fp,
"DCOM Target ProgID: \"%s\"\n",
m_progid.c_str());
876 fprintf(fp,
"DCOM Target Host: \"%s\"\n",
m_host.c_str());
877 fprintf(fp,
"DCOM Target Username: \"%s\"\n",
m_username.c_str());
880 for(vi_map_t::const_iterator it =
m_vimap.begin(); it !=
m_vimap.end(); ++it)
882 vi_name = CW2CT(it->first.c_str());
883 fprintf(fp,
"LabVIEW VI: \"%s\"\n", vi_name.c_str());
887 for(std::map<std::string,std::string>::const_iterator it =
m_xpath_map.begin(); it !=
m_xpath_map.end(); ++it)
889 fprintf(fp,
"Config XPath: \"%s\" = \"%s\"\n", it->first.c_str(), it->second.c_str());
893 fprintf(fp,
"Config XPath: \"%s\" = %s\n", it->first.c_str(), (it->second ?
"true" :
"false") );
898 #ifndef DOXYGEN_SHOULD_SKIP_THIS
static void initCOM(void *)
create an C++ exception from a COM HRESULT.
COAUTHIDENTITY * m_pidentity
std::string m_configSection
section of configFile to load information from
(4) On IOC exit, stop any LabVIEW VIs that we started due to viStartIfIdle being specified ...
CComPtr< LabVIEW::_Application > m_lv
BoolItem(lvDCOMInterface *dcom, const char *xpath, const char *config_section, const char *param)
Header file for various COM utilities.
bool started
did we start this vi because it was idle and viStartIfIdle was specified
void waitForLabviewBoolean(BSTR vi_name, BSTR control_name, bool value)
static void __stdcall my_com_raise_error(HRESULT hr, IErrorInfo *perrinfo)
The Microsoft ATL _com_error is not derived from std::exception hence this bit of code to throw our o...
(8) On IOC exit, stop any LabVIEW VIs that we have connected to
std::string doPath(const std::string &xpath)
IXMLDOMDocument2 * m_pxmldom
void callLabview(BSTR vi_name, VARIANT &names, VARIANT &values, VARIANT_BOOL reentrant, VARIANT *results)
void report(FILE *fp, int details)
Helper for EPICS driver report function.
header for lvDCOMInterface class.
int m_options
the various lvDCOMOptions currently in use
std::map< std::string, bool > m_xpath_bool_map
void getParams(std::map< std::string, std::string > &res)
std::string doXPATH(const std::string &xpath)
std::map< std::string, std::string > m_xpath_map
static void epicsExitFunc(void *arg)
void stopVis(bool only_ones_we_started)
Manager class for LabVIEW DCOM Interaction. Parses an lvinput.xml file and provides access to the Lab...
void setLabviewValue(const char *param, const T &value)
HRESULT setIdentity(COAUTHIDENTITY *pidentity, IUnknown *pUnk)
(1) If the LabVIEW VI is idle when we connect to it, issue a warning message
Hold a reference to a LabVIEW VI.
void getLabviewValue(const char *param, T *value)
(2) If the LabVIEW VI is idle when we connect to it, attempt to start it
static epicsThreadOnceId onceId
COAUTHIDENTITY * createIdentity(const std::string &user, const std::string &domain, const std::string &pass)
bool checkOption(lvDCOMOptions option)
void createViRef(BSTR vi_name, bool reentrant, LabVIEW::VirtualInstrumentPtr &vi)
void setLabviewValueExt(BSTR vi_name, BSTR control_name, const VARIANT &value, VARIANT *results)
bool doXPATHbool(const std::string &xpath)
lvDCOMInterface(const char *configSection, const char *configFile, const char *host, int options, const char *progid, const char *username, const char *password)
section name of configFile to use to configure this asyn port
void getViRef(BSTR vi_name, bool reentrant, LabVIEW::VirtualInstrumentPtr &vi)
StringItem(lvDCOMInterface *dcom, const char *xpath, const char *config_section, const char *param, bool filepath=false)