Index: trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 42505)
+++ trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 42507)
@@ -9900,5 +9900,5 @@
   <interface
     name="IProcess" extends="$unknown"
-    uuid="f55af4a1-e280-40ac-83e1-921c0abcaf18"
+    uuid="83275f41-01ee-4362-ac44-298191b5186c"
     wsmap="managed"
     >
@@ -10033,4 +10033,36 @@
       <param name="handle" type="unsigned long" dir="in">
         <desc>TODO</desc>
+      </param>
+      <param name="flags" type="unsigned long" dir="in">
+        <desc>
+          <link to="ProcessInputFlag"/> flags.
+        </desc>
+      </param>
+      <param name="data" type="octet" dir="in" safearray="yes">
+        <desc>TODO</desc>
+      </param>
+      <param name="timeoutMS" type="unsigned long" dir="in">
+        <desc>TODO</desc>
+      </param>
+      <param name="written" type="unsigned long" dir="return">
+        <desc>TODO</desc>
+      </param>
+    </method>
+    
+    <method name="WriteArray">
+      <desc>
+        TODO
+
+        <result name="VBOX_E_NOT_SUPPORTED">
+          TODO
+        </result>
+      </desc>
+      <param name="handle" type="unsigned long" dir="in">
+        <desc>TODO</desc>
+      </param>
+      <param name="flags" type="ProcessInputFlag" dir="in" safearray="yes">
+        <desc>
+          <link to="ProcessInputFlag"/> flags.
+        </desc>
       </param>
       <param name="data" type="octet" dir="in" safearray="yes">
Index: trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h
===================================================================
--- trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h	(revision 42505)
+++ trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h	(revision 42507)
@@ -133,13 +133,19 @@
     void Destroy(void);
 
-    int FillData(const void *pvToWrite, size_t cbToWrite);
-
     int Init(eVBoxGuestCtrlCallbackType enmType);
 
     eVBoxGuestCtrlCallbackType GetCallbackType(void) { return mType; }
 
+    const void* GetDataRaw(void) const { return pvData; }
+
+    size_t GetDataSize(void) { return cbData; }
+
     const void* GetPayloadRaw(void) const { return pvPayload; }
 
     size_t GetPayloadSize(void) { return cbPayload; }
+
+    int SetData(const void *pvCallback, size_t cbCallback);
+
+    int SetPayload(const void *pvToWrite, size_t cbToWrite);
 
 protected:
@@ -156,5 +162,5 @@
      *  waiting (optional). */
     void                       *pvPayload;
-    /** Size of the payload. */
+    /** Size of the payload (optional). */
     size_t                      cbPayload;
 };
Index: trunk/src/VBox/Main/include/GuestProcessImpl.h
===================================================================
--- trunk/src/VBox/Main/include/GuestProcessImpl.h	(revision 42505)
+++ trunk/src/VBox/Main/include/GuestProcessImpl.h	(revision 42507)
@@ -65,5 +65,6 @@
     STDMETHOD(WaitFor)(ULONG aWaitFlags, ULONG aTimeoutMS, ProcessWaitResult_T *aReason);
     STDMETHOD(WaitForArray)(ComSafeArrayIn(ProcessWaitForFlag_T, aFlags), ULONG aTimeoutMS, ProcessWaitResult_T *aReason);
-    STDMETHOD(Write)(ULONG aHandle, ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten);
+    STDMETHOD(Write)(ULONG aHandle, ULONG aFlags, ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten);
+    STDMETHOD(WriteArray)(ULONG aHandle, ComSafeArrayIn(ProcessInputFlag_T, aFlags), ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten);
     /** @}  */
 
@@ -72,14 +73,14 @@
      * @{ */
     int callbackDispatcher(uint32_t uContextID, uint32_t uFunction, void *pvData, size_t cbData);
-    inline bool callbackExists(ULONG uContextID);
+    inline bool callbackExists(uint32_t uContextID);
     void close(void);
     bool isReady(void);
     ULONG getPID(void) { return mData.mPID; }
-    int readData(ULONG uHandle, ULONG uSize, ULONG uTimeoutMS, BYTE *pbData, size_t cbData, size_t *pcbRead);
+    int readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS, void *pvData, size_t cbData, size_t *pcbRead);
     int startProcess(void);
     int startProcessAsync(void);
     int terminateProcess(void);
     int waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestProcessWaitResult &guestResult);
-    int writeData(ULONG uHandle, BYTE const *pbData, size_t cbData, ULONG uTimeoutMS, ULONG *puWritten);
+    int writeData(uint32_t uHandle, uint32_t uFlags, void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten);
     /** @}  */
 
@@ -87,6 +88,6 @@
     /** @name Protected internal methods.
      * @{ */
-    inline int callbackAdd(GuestCtrlCallback *pCallback, ULONG *puContextID);
-    inline int callbackRemove(ULONG uContextID);
+    inline int callbackAdd(GuestCtrlCallback *pCallback, uint32_t *puContextID);
+    inline int callbackRemove(uint32_t uContextID);
     inline bool isAlive(void);
     int onGuestDisconnected(GuestCtrlCallback *pCallback, PCALLBACKDATACLIENTDISCONNECTED pData);
Index: trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp	(revision 42505)
+++ trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp	(revision 42507)
@@ -196,4 +196,18 @@
     GuestCtrlEvent::Destroy();
 
+    switch (mType)
+    {
+        case VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT:
+        {
+            PCALLBACKDATAEXECOUT pThis = (PCALLBACKDATAEXECOUT)pvData;
+            AssertPtr(pThis);
+            if (pThis->pvData)
+                RTMemFree(pThis->pvData);
+        }
+
+        default:
+           break;
+    }
+
     mType = VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN;
     if (pvData)
@@ -212,5 +226,63 @@
 }
 
-int GuestCtrlCallback::FillData(const void *pvToWrite, size_t cbToWrite)
+int GuestCtrlCallback::SetData(const void *pvCallback, size_t cbCallback)
+{
+    if (!cbCallback)
+        return VINF_SUCCESS;
+    AssertPtr(pvCallback);
+
+    switch (mType)
+    {
+        case VBOXGUESTCTRLCALLBACKTYPE_EXEC_START:
+        {
+            PCALLBACKDATAEXECSTATUS pThis = (PCALLBACKDATAEXECSTATUS)pvData;
+            PCALLBACKDATAEXECSTATUS pCB   = (PCALLBACKDATAEXECSTATUS)pvCallback;
+            Assert(cbCallback == sizeof(CALLBACKDATAEXECSTATUS));
+
+            pThis->u32Flags  = pCB->u32Flags;
+            pThis->u32PID    = pCB->u32PID;
+            pThis->u32Status = pCB->u32Status;
+            break;
+        }
+
+        case VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT:
+        {
+            PCALLBACKDATAEXECOUT pThis = (PCALLBACKDATAEXECOUT)pvData;
+            PCALLBACKDATAEXECOUT pCB   = (PCALLBACKDATAEXECOUT)pvCallback;
+            Assert(cbCallback == sizeof(CALLBACKDATAEXECOUT));
+
+            pThis->cbData   = pCB->cbData;
+            if (pThis->cbData)
+            {
+                pThis->pvData   = RTMemAlloc(pCB->cbData);
+                AssertPtrReturn(pThis->pvData, VERR_NO_MEMORY);
+                memcpy(pThis->pvData, pCB->pvData, pCB->cbData);
+            }
+            pThis->u32Flags = pCB->u32Flags;
+            pThis->u32PID   = pCB->u32PID;
+            break;
+        }
+
+        case VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS:
+        {
+            PCALLBACKDATAEXECINSTATUS pThis = (PCALLBACKDATAEXECINSTATUS)pvData;
+            PCALLBACKDATAEXECINSTATUS pCB   = (PCALLBACKDATAEXECINSTATUS)pvCallback;
+            Assert(cbCallback == sizeof(CALLBACKDATAEXECINSTATUS));
+
+            pThis->cbProcessed = pCB->cbProcessed;
+            pThis->u32Flags    = pCB->u32Flags;
+            pThis->u32PID      = pCB->u32PID;
+            pThis->u32Status   = pCB->u32Status;
+        }
+
+        default:
+            AssertMsgFailed(("Callback type not handled (%d)\n", mType));
+            break;
+    }
+
+    return VINF_SUCCESS;
+}
+
+int GuestCtrlCallback::SetPayload(const void *pvToWrite, size_t cbToWrite)
 {
     if (!cbToWrite)
Index: trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp	(revision 42505)
+++ trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp	(revision 42507)
@@ -17,4 +17,12 @@
  */
 
+/**
+ * Locking rules:
+ * - When the main dispatcher (callbackDispatcher) is called it takes the
+ *   WriteLock while dispatching to the various on* methods.
+ * - All other outer functions (accessible by Main) must not own a lock
+ *   while waiting for a callback or for an event.
+ * - Only keep Read/WriteLocks as short as possible and only when necessary.
+ */
 
 /*******************************************************************************
@@ -308,5 +316,5 @@
 /////////////////////////////////////////////////////////////////////////////
 
-inline int GuestProcess::callbackAdd(GuestCtrlCallback *pCallback, ULONG *puContextID)
+inline int GuestProcess::callbackAdd(GuestCtrlCallback *pCallback, uint32_t *puContextID)
 {
     const ComObjPtr<GuestSession> pSession(mData.mParent);
@@ -360,5 +368,5 @@
 
         LogFlowThisFunc(("Added new callback (Session: %RU32, Process: %RU32, Count=%RU32) CID=%RU32\n",
-                     uSessionID, mData.mProcessID, uCount, uNewContextID));
+                         uSessionID, mData.mProcessID, uCount, uNewContextID));
     }
 
@@ -370,5 +378,5 @@
 #ifdef DEBUG
     LogFlowThisFunc(("uPID=%RU32, uContextID=%RU32, uFunction=%RU32, pvData=%p, cbData=%RU32\n",
-                 mData.mPID, uContextID, uFunction, pvData, cbData));
+                     mData.mPID, uContextID, uFunction, pvData, cbData));
 #endif
 
@@ -453,5 +461,5 @@
 }
 
-inline bool GuestProcess::callbackExists(ULONG uContextID)
+inline bool GuestProcess::callbackExists(uint32_t uContextID)
 {
     GuestCtrlCallbacks::const_iterator it =
@@ -460,5 +468,5 @@
 }
 
-inline int GuestProcess::callbackRemove(ULONG uContextID)
+inline int GuestProcess::callbackRemove(uint32_t uContextID)
 {
     GuestCtrlCallbacks::iterator it =
@@ -595,5 +603,5 @@
 
     LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32, pCallback=%p, pData=%p\n",
-                 pData->u32PID, pData->u32Status, pData->u32Flags, pCallback, pData));
+                     pData->u32PID, pData->u32Status, pData->u32Flags, pCallback, pData));
 
     int rc = VINF_SUCCESS;
@@ -779,5 +787,5 @@
 
     LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RU32, pvData=%p, cbData=%RU32, pCallback=%p, pData=%p\n",
-                 mData.mPID, pData->u32HandleId, pData->u32Flags, pData->pvData, pData->cbData, pCallback, pData));
+                     mData.mPID, pData->u32HandleId, pData->u32Flags, pData->pvData, pData->cbData, pCallback, pData));
 
     /* Copy data into callback (if any). */
@@ -787,9 +795,5 @@
     if (pCallback)
     {
-        if (pData->pvData && pData->cbData)
-        {
-            rc = pCallback->FillData(pData->pvData, pData->cbData);
-            Assert(pCallback->GetPayloadSize() == pData->cbData);
-        }
+        rc = pCallback->SetData(pData, sizeof(CALLBACKDATAEXECOUT));
 
         int rc2 = pCallback->Signal();
@@ -831,11 +835,11 @@
 }
 
-int GuestProcess::readData(ULONG uHandle, ULONG uSize, ULONG uTimeoutMS,
-                           BYTE *pbData, size_t cbData, size_t *pcbRead)
-{
-    LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uSize=%RU32, uTimeoutMS=%RU32, pbData=%p, cbData=%RU32\n",
-                 mData.mPID, uHandle, uSize, uTimeoutMS, pbData, cbData));
+int GuestProcess::readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS,
+                           void *pvData, size_t cbData, size_t *pcbRead)
+{
+    LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%RU32\n",
+                     mData.mPID, uHandle, uSize, uTimeoutMS, pvData, cbData));
     AssertReturn(uSize, VERR_INVALID_PARAMETER);
-    AssertPtrReturn(pbData, VERR_INVALID_POINTER);
+    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     AssertReturn(cbData >= uSize, VERR_INVALID_PARAMETER);
     /* pcbRead is optional. */
@@ -846,5 +850,5 @@
         return VERR_NOT_AVAILABLE;
 
-    ULONG uContextID = 0;
+    uint32_t uContextID = 0;
     GuestCtrlCallback *pCallbackRead = new GuestCtrlCallback();
     if (!pCallbackRead)
@@ -882,17 +886,23 @@
         {
             rc = pCallbackRead->GetResultCode();
-            LogFlowThisFunc(("Callback returned rc=%Rrc, cbData=%RU32\n", rc, pCallbackRead->GetPayloadSize()));
+            LogFlowThisFunc(("Callback returned rc=%Rrc, cbData=%RU32\n", rc, pCallbackRead->GetDataSize()));
 
             if (RT_SUCCESS(rc))
             {
-                size_t cbDataCB = pCallbackRead->GetPayloadSize();
-                if (cbDataCB)
+                Assert(pCallbackRead->GetDataSize() == sizeof(CALLBACKDATAEXECOUT));
+                PCALLBACKDATAEXECOUT pData = (PCALLBACKDATAEXECOUT)pCallbackRead->GetDataRaw();
+                AssertPtr(pData);
+
+                size_t cbRead = pData->cbData;
+                if (cbRead)
                 {
-                    Assert(cbData >= cbDataCB);
-                    memcpy(pbData, pCallbackRead->GetPayloadRaw(), cbDataCB);
+                    Assert(cbData >= cbRead);
+                    memcpy(pvData, pData->pvData, cbRead);
                 }
 
+                LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
+
                 if (pcbRead)
-                    *pcbRead = cbDataCB;
+                    *pcbRead = cbRead;
             }
         }
@@ -944,4 +954,5 @@
 }
 
+/* Does not do locking; caller is responsible for that! */
 int GuestProcess::setErrorInternal(int rc, const Utf8Str &strMessage)
 {
@@ -958,6 +969,4 @@
 #endif
 
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
     mData.mStatus = ProcessStatus_Error;
     mData.mRC = rc;
@@ -999,5 +1008,5 @@
 
     int rc;
-    ULONG uContextID = 0;
+    uint32_t uContextID = 0;
     GuestCtrlCallback *pCallbackStart = new GuestCtrlCallback();
     if (!pCallbackStart)
@@ -1013,6 +1022,4 @@
     if (RT_SUCCESS(rc))
     {
-      //  AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
         GuestSession *pSession = mData.mParent;
         AssertPtr(pSession);
@@ -1070,4 +1077,5 @@
                 paParms[i++].setUInt32(mData.mProcess.mTimeoutMS);
 
+            /* Note: Don't hold the write lock in here, because setErrorInternal */
             rc = sendCommand(HOST_EXEC_CMD, i, paParms);
         }
@@ -1079,5 +1087,6 @@
         uint32_t uTimeoutMS = mData.mProcess.mTimeoutMS;
 
-        alock.release(); /* Drop the write lock again. */
+        /* Drop the write lock again before waiting. */
+        alock.release();
 
         if (RT_SUCCESS(rc))
@@ -1135,5 +1144,5 @@
 DECLCALLBACK(int) GuestProcess::startProcessThread(RTTHREAD Thread, void *pvUser)
 {
-    LogFlowFuncEnter();
+    LogFlowFuncEnter(("pvUser=%p\n", pvUser));
 
     std::auto_ptr<GuestProcessStartTask> pTask(static_cast<GuestProcessStartTask*>(pvUser));
@@ -1153,5 +1162,5 @@
 
     LogFlowFuncLeaveRC(rc);
-    return VINF_SUCCESS;
+    return rc;
 }
 
@@ -1174,5 +1183,5 @@
 
     LogFlowThisFunc(("fWaitFlags=%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p\n",
-                 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent));
+                     fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent));
 
     ProcessStatus_T curStatus;
@@ -1445,14 +1454,106 @@
 }
 
-int GuestProcess::writeData(ULONG uHandle, const BYTE *pbData, size_t cbData, ULONG uTimeoutMS, ULONG *puWritten)
-{
-    LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, pbData=%p, cbData=%RU32, uTimeoutMS=%RU32, puWritten=%p\n",
-                 mData.mPID, uHandle, pbData, cbData, uTimeoutMS, puWritten));
-    AssertPtrReturn(pbData, VERR_INVALID_POINTER);
-    AssertReturn(pbData, VERR_INVALID_PARAMETER);
+int GuestProcess::writeData(uint32_t uHandle, uint32_t uFlags,
+                            void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten)
+{
+    LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, pvData=%p, cbData=%RU32, uTimeoutMS=%RU32, puWritten=%p\n",
+                     mData.mPID, uHandle, pvData, cbData, uTimeoutMS, puWritten));
+    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
+    AssertReturn(cbData, VERR_INVALID_PARAMETER);
     /* Rest is optional. */
 
-    LogFlowThisFuncLeave();
-    return 0;
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    if (mData.mStatus != ProcessStatus_Started)
+        return VERR_NOT_AVAILABLE;
+
+    uint32_t uContextID = 0;
+    GuestCtrlCallback *pCallbackWrite = new GuestCtrlCallback();
+    if (!pCallbackWrite)
+        return VERR_NO_MEMORY;
+
+    /* Create callback and add it to the map. */
+    int rc = pCallbackWrite->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS);
+    if (RT_SUCCESS(rc))
+        rc = callbackAdd(pCallbackWrite, &uContextID);
+
+    alock.release(); /* Drop the write lock again. */
+
+    if (RT_SUCCESS(rc))
+    {
+        VBOXHGCMSVCPARM paParms[5];
+
+        int i = 0;
+        paParms[i++].setUInt32(uContextID);
+        paParms[i++].setUInt32(mData.mPID);
+        paParms[i++].setUInt32(uFlags);
+        paParms[i++].setPointer(pvData, cbData);
+        paParms[i++].setUInt32(cbData);
+
+        rc = sendCommand(HOST_EXEC_SET_INPUT, i, paParms);
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Let's wait for the process being started.
+         * Note: Be sure not keeping a AutoRead/WriteLock here.
+         */
+        LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS));
+        rc = pCallbackWrite->Wait(uTimeoutMS);
+        if (RT_SUCCESS(rc)) /* Wait was successful, check for supplied information. */
+        {
+            rc = pCallbackWrite->GetResultCode();
+            LogFlowThisFunc(("Callback returned rc=%Rrc, cbData=%RU32\n", rc, pCallbackWrite->GetDataSize()));
+
+            if (RT_SUCCESS(rc))
+            {
+                Assert(pCallbackWrite->GetDataSize() == sizeof(CALLBACKDATAEXECINSTATUS));
+                PCALLBACKDATAEXECINSTATUS pData = (PCALLBACKDATAEXECINSTATUS)pCallbackWrite->GetDataRaw();
+                AssertPtr(pData);
+
+                uint32_t cbWritten = 0;
+                switch (pData->u32Status)
+                {
+                    case INPUT_STS_WRITTEN:
+                        cbWritten = pData->cbProcessed;
+                        break;
+
+                    case INPUT_STS_ERROR:
+                        rc = pData->u32Flags; /** @todo Fix int vs. uint32_t! */
+                        break;
+
+                    case INPUT_STS_TERMINATED:
+                        rc = VERR_CANCELLED;
+                        break;
+
+                    case INPUT_STS_OVERFLOW:
+                        rc = VERR_BUFFER_OVERFLOW;
+                        break;
+
+                    default:
+                        /* Silently skip unknown errors. */
+                        break;
+                }
+
+                LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
+
+                if (puWritten)
+                    *puWritten = cbWritten;
+            }
+        }
+        else
+            rc = VERR_TIMEOUT;
+    }
+
+    alock.acquire();
+
+    AssertPtr(pCallbackWrite);
+    int rc2 = callbackRemove(uContextID);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
 }
 
@@ -1579,5 +1680,6 @@
 }
 
-STDMETHODIMP GuestProcess::Write(ULONG aHandle, ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
+STDMETHODIMP GuestProcess::Write(ULONG aHandle, ULONG aFlags,
+                                 ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
 {
 #ifndef VBOX_WITH_GUEST_CONTROL
@@ -1594,5 +1696,5 @@
 
     com::SafeArray<BYTE> data(ComSafeArrayInArg(aData));
-    int rc = writeData(aHandle, data.raw(), data.size(), aTimeoutMS, aWritten);
+    int rc = writeData(aHandle, aFlags, data.raw(), data.size(), aTimeoutMS, (uint32_t*)aWritten);
     /** @todo Do setError() here. */
     HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
@@ -1603,2 +1705,27 @@
 }
 
+STDMETHODIMP GuestProcess::WriteArray(ULONG aHandle, ComSafeArrayIn(ProcessInputFlag_T, aFlags),
+                                      ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
+{
+#ifndef VBOX_WITH_GUEST_CONTROL
+    ReturnComNotImplemented();
+#else
+    LogFlowThisFuncEnter();
+
+    CheckComArgOutPointerValid(aWritten);
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    /*
+     * Note: Do not hold any locks here while writing!
+     */
+    ULONG fWrite = ProcessInputFlag_None;
+    com::SafeArray<ProcessInputFlag_T> flags(ComSafeArrayInArg(aFlags));
+    for (size_t i = 0; i < flags.size(); i++)
+        fWrite |= flags[i];
+
+    return Write(aHandle, fWrite, ComSafeArrayInArg(aData), aTimeoutMS, aWritten);
+#endif /* VBOX_WITH_GUEST_CONTROL */
+}
+
