// ========================================================================== // Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files contain unpublished // information proprietary to Autodesk, Inc. ("Autodesk") and/or its // licensors, which is protected by U.S. and Canadian federal copyright // law and by international treaties. // // The Data is provided for use exclusively by You. You have the right // to use, modify, and incorporate this Data into other products for // purposes authorized by the Autodesk software license agreement, // without fee. // // The copyright notices in the Software and this entire statement, // including the above license grant, this restriction and the // following disclaimer, must be included in all copies of the // Software, in whole or in part, and all derivative works of // the Software, unless such copies or derivative works are solely // in the form of machine-executable object code generated by a // source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY // OR PROBABILITY OF SUCH DAMAGES. // // ========================================================================== // MELCommand.cpp : Implementation of CMELCommand #include "stdafx.h" #include "MELCommand.h" #include "Common.h" /* * Sends a command to the Maya command port. Connects to the command port * if not already connected. The result returned by Maya is stored as a * string in the m_strReply member variable, to be potentially processed * later by the get_Result() member function. * * Parameters * Command [in] Null-terminated string with the command. * * Return Value * Returns S_OK if successful, or an error value otherwise. * * Remarks * The return value from this method only indicates whether the command * was successfully sent to the Maya command port. It does not indicate * if the command was successfully executed by Maya. */ STDMETHODIMP CMELCommand::Execute(BSTR Command) { m_strResult.Empty(); HRESULT hr = Connect(); if (FAILED(hr)) return hr; // convert BSTR to ANSI CAtlString strCommand(Command); CW2A pszCommand(strCommand); // send command to Maya command port int err = send(m_socket, pszCommand, (int)strlen(pszCommand), 0); if (err == SOCKET_ERROR) { Disconnect(); return AtlReportError(GetObjectCLSID(), L"Unable to send command to command port", IID_IMELCommand); } // wait for reply, store result as raw string char* recvBuf = new char[4096+1]; int numBytes = recv(m_socket, recvBuf, 4096, 0); if (numBytes == SOCKET_ERROR) { delete[] recvBuf; Disconnect(); return AtlReportError(GetObjectCLSID(), L"Unable to get reply from command port", IID_IMELCommand); } recvBuf[numBytes] = '\0'; // practising safe string usage CA2W pszRecv(recvBuf); // convert ANSI to Unicode m_strResult = pszRecv; delete[] recvBuf; m_strResult.TrimLeft(L" \r\n"); // trim junk from beginning m_strResult.TrimRight(L" \r\n"); // ...and end return S_OK; } /* * The Result property specifies the result returned by Maya for the most * recent invocation of the Execute method. This property is read-only. * * Parameters * pVal [out] Returns the Result property as a reference to a VARIANT. * * Remarks * The Result property can be a LONG (VT_I4), DOUBLE (VT_R8), * BSTR (VT_BSTR), or an array (VT_ARRAY) of those types. */ STDMETHODIMP CMELCommand::get_Result(VARIANT* pVal) { return MakeVariant(m_strResult).Detach(pVal); } /* * The PortName property specifies the name of the Maya command port. * * Parameters * pVal [out] Returns the PortName property as a reference to a BSTR. * newVal [in] Sets the value of the PortName property to the value of the BSTR. * * Remarks * Changing the PortName property while a connection is established will * close that connection. * The default/initial value of the PortName property is "mayaCommand". */ STDMETHODIMP CMELCommand::get_PortName(BSTR* pVal) { *pVal = m_strPortName.AllocSysString(); return S_OK; } STDMETHODIMP CMELCommand::put_PortName(BSTR newVal) { CAtlString strPortName(newVal); if (m_strPortName != strPortName) { Disconnect(); m_strPortName = strPortName; } return S_OK; } /* * Connects to the Maya command port, if not already connected. * * Return Value * Returns S_OK if successful or already connected, * or an error value otherwise. */ STDMETHODIMP CMELCommand::Connect(void) { if (m_socket != INVALID_SOCKET) // already connected! return S_OK; // initialize Windows Sockets 2 WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 0), &wsaData) == 0) { CW2A pszPortName(m_strPortName); m_socket = ConnectToMayaCommandPortByName(pszPortName); if (m_socket != INVALID_SOCKET) return S_OK; } WSACleanup(); CAtlString strError = L"Unable to connect to command port: "; strError += m_strPortName; return AtlReportError(GetObjectCLSID(), strError, IID_IMELCommand); } /* * Closes the connection to the Maya command port; * does nothing if not connected. * * Return Value * Returns S_OK. */ STDMETHODIMP CMELCommand::Disconnect(void) { if (m_socket != INVALID_SOCKET) { DisconnectFromMayaCommandPort(m_socket); m_socket = INVALID_SOCKET; WSACleanup(); } return S_OK; } /* * The Connected property specifies whether there currently is a connection * established with the Maya command port. This property is read-only. * * Parameters * pVal [out] Returns the whether a connection currently exists. */ STDMETHODIMP CMELCommand::get_Connected(VARIANT_BOOL* pVal) { *pVal = (m_socket == INVALID_SOCKET) ? FALSE : TRUE; return S_OK; } /* * Converts the specified (reply) string into a Variant value. * If the string contains tab characters ('\t), the string is * considered to contain an array of values. */ CComVariant CMELCommand::MakeVariant(const CAtlString& strText) { int tabCount = 0; int tabPos = 0; while (tabPos < strText.GetLength()) { tabPos = strText.Find(L'\t', tabPos); if (tabPos < 0) break; ++tabCount; ++tabPos; } if (!tabCount) { return MakeVariantNotArray(strText); } CComSafeArray safeArray; safeArray.Create(tabCount + 1); int curPos = 0; int index = 0; tabPos = strText.Find(L'\t'); for (;;) { CAtlString strElement; if (tabPos > curPos) { strElement = strText.Mid(curPos, tabPos - curPos).Trim(); } safeArray[index++] = MakeVariantNotArray(strElement); curPos = tabPos + 1; if (curPos == strText.GetLength()) { safeArray[index] = CComVariant(L""); break; } tabPos = strText.Find(L'\t', curPos); if (tabPos < 0) { safeArray[index] = MakeVariant(strText.Mid(curPos).Trim()); break; } } return CComVariant(safeArray); } /* * Converts the specified (sub-)string into a Variant value. */ CComVariant CMELCommand::MakeVariantNotArray(const CAtlString& strText) { CComVariant variant(strText); if (strText.SpanExcluding(L"0123456789.-+e").IsEmpty()) { if (strText.Find(L".") < 0) { variant.ChangeType(VT_I4); } else { variant.ChangeType(VT_R8); } } return variant; }