diff --git a/src/plugins/qt4projectmanager/qt-s60/qt-s60-todo.txt b/src/plugins/qt4projectmanager/qt-s60/qt-s60-todo.txt
index e0c197c7eeef6b20695cb6986fd3e15ad2024ad1..81636f56bd1e1a689a68bf1586da8b53e2d079fe 100644
--- a/src/plugins/qt4projectmanager/qt-s60/qt-s60-todo.txt
+++ b/src/plugins/qt4projectmanager/qt-s60/qt-s60-todo.txt
@@ -28,6 +28,10 @@
 * Run on device
     * Finish runner when application exits
     * passphrase for signing
+    * time stamp of copied sisx is ridiculous
+    * maybe don't copy the sisx all the time
+    * don't hardcode com port
+    * don't hardcode copy destination
 
 * Add compile output parser winscw at least
 
diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp
index 91a22bab6a1e74b32b9a49a457ec149e818bc3c7..4484dbff16bc72c89753e248daf5cbff23bf53dd 100644
--- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp
+++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp
@@ -431,15 +431,6 @@ S60DeviceRunControl::S60DeviceRunControl(QSharedPointer<RunConfiguration> runCon
             this, SLOT(signsisProcessFailed()));
     connect(m_signsis, SIGNAL(finished(int,QProcess::ExitStatus)),
             this, SLOT(signsisProcessFinished()));
-    m_install = new QProcess(this);
-    connect(m_install, SIGNAL(readyReadStandardError()),
-            this, SLOT(readStandardError()));
-    connect(m_install, SIGNAL(readyReadStandardOutput()),
-            this, SLOT(readStandardOutput()));
-    connect(m_install, SIGNAL(error(QProcess::ProcessError)),
-            this, SLOT(installProcessFailed()));
-    connect(m_install, SIGNAL(finished(int,QProcess::ExitStatus)),
-            this, SLOT(installProcessFinished()));
     m_run = new QProcess(this);
     connect(m_run, SIGNAL(readyReadStandardError()),
             this, SLOT(readStandardError()));
@@ -489,7 +480,6 @@ void S60DeviceRunControl::stop()
 {
     m_makesis->kill();
     m_signsis->kill();
-    m_install->kill();
     m_run->kill();
 }
 
@@ -552,29 +542,12 @@ void S60DeviceRunControl::signsisProcessFinished()
         emit finished();
         return;
     }
-    QString applicationInstaller = "cmd.exe";
-    QStringList arguments;
-    arguments << "/C" << QDir::toNativeSeparators(m_baseFileName + ".sisx");
-    m_install->setWorkingDirectory(m_workingDirectory);
-    emit addToOutputWindow(this, tr("%1 %2").arg(QDir::toNativeSeparators(applicationInstaller), arguments.join(tr(" "))));
-    m_install->start(applicationInstaller, arguments, QIODevice::ReadOnly);
-}
-
-void S60DeviceRunControl::installProcessFailed()
-{
-    processFailed("ApplicationInstaller", m_install->error());
-}
-
-void S60DeviceRunControl::installProcessFinished()
-{
-    if (m_install->exitCode() != 0) {
-        error(this, tr("An error occurred while installing the package."));
-        emit finished();
-        return;
-    }
     QString trklauncher = QApplication::applicationDirPath() + "/../tests/manual/trk/debug/trklauncher.exe";
     QStringList arguments;
-    arguments << "COM5" << QString("C:\\sys\\bin\\%1.exe").arg(m_targetName); //TODO com selection and file path
+    //TODO com selection, sisx destination and file path user definable
+    arguments << "COM5" << "-I" << (m_baseFileName + ".sisx")
+            << QString("C:\\Data\\%1.sisx").arg(QFileInfo(m_baseFileName).fileName())
+            << QString("C:\\sys\\bin\\%1.exe").arg(m_targetName);
     emit addToOutputWindow(this, tr("%1 %2").arg(QDir::toNativeSeparators(trklauncher), arguments.join(tr(" "))));
     m_run->start(trklauncher, arguments, QIODevice::ReadOnly);
 }
diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h
index 63491f2959e66ae39c0720c1d8b005eb2946185c..24b5495a79add2625e2152160514fde0c4ecb8e7 100644
--- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h
+++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h
@@ -147,8 +147,6 @@ private slots:
     void makesisProcessFinished();
     void signsisProcessFailed();
     void signsisProcessFinished();
-    void installProcessFailed();
-    void installProcessFinished();
     void runProcessFailed();
     void runProcessFinished();
 
@@ -165,7 +163,6 @@ private:
     QString m_customKeyPath;
     QProcess *m_makesis;
     QProcess *m_signsis;
-    QProcess *m_install;
     QProcess *m_run;
 };
 
diff --git a/tests/manual/trk/launcher.cpp b/tests/manual/trk/launcher.cpp
index a83985a0849a934159c5c7945b904bbefe3311fd..8111a58a30b669c2b41dbf6298f385c59ccf3273 100644
--- a/tests/manual/trk/launcher.cpp
+++ b/tests/manual/trk/launcher.cpp
@@ -33,6 +33,7 @@
 #include <QtCore/QFile>
 #include <QtCore/QQueue>
 #include <QtCore/QTimer>
+#include <QtCore/QDateTime>
 
 #include <QtNetwork/QTcpServer>
 #include <QtNetwork/QTcpSocket>
@@ -88,6 +89,8 @@ public:
     ~Adapter();
     void setTrkServerName(const QString &name) { m_trkServerName = name; }
     void setFileName(const QString &name) { m_fileName = name; }
+    void setCopyFileName(const QString &srcName, const QString &dstName) { m_copySrcFileName = srcName; m_copyDstFileName = dstName; }
+    void setInstallFileName(const QString &name) { m_installFileName = name; }
     bool startServer();
 
 private:
@@ -128,6 +131,8 @@ private:
     void timerEvent(QTimerEvent *ev);
     byte nextTrkWriteToken();
 
+    void handleFileCreation(const TrkResult &result);
+    void handleFileCreated(const TrkResult &result);
     void handleCpuType(const TrkResult &result);
     void handleCreateProcess(const TrkResult &result);
     void handleWaitForFinished(const TrkResult &result);
@@ -136,6 +141,10 @@ private:
 
     void handleAndReportCreateProcess(const TrkResult &result);
     void handleResult(const TrkResult &data);
+
+    void copyFileToRemote();
+    void installRemotePackageSilently(const QString &filename);
+    void installAndRun();
     void startInferiorIfNeeded();
 
 #if USE_NATIVE
@@ -158,6 +167,9 @@ private:
     Session m_session; // global-ish data (process id, target information)
 
     QString m_fileName;
+    QString m_copySrcFileName;
+    QString m_copyDstFileName;
+    QString m_installFileName;
 };
 
 Adapter::Adapter()
@@ -198,11 +210,22 @@ bool Adapter::startServer()
     sendTrkMessage(TrkSupported, CB(handleSupportMask));
     sendTrkMessage(TrkCpuType, CB(handleCpuType));
     sendTrkMessage(TrkVersions); // Versions
-//    sendTrkMessage(0x09); // Unrecognized command
-    startInferiorIfNeeded();
+    if (!m_copySrcFileName.isEmpty() && !m_copyDstFileName.isEmpty())
+        copyFileToRemote();
+    else
+        installAndRun();
     return true;
 }
 
+void Adapter::installAndRun()
+{
+    if (!m_installFileName.isEmpty()) {
+        installRemotePackageSilently(m_installFileName);
+        startInferiorIfNeeded();
+    } else {
+        startInferiorIfNeeded();
+    }
+}
 void Adapter::logMessage(const QString &msg)
 {
     qDebug() << "ADAPTER: " << qPrintable(msg);
@@ -508,6 +531,38 @@ void Adapter::handleResult(const TrkResult &result)
     }
 }
 
+void Adapter::handleFileCreation(const TrkResult &result)
+{
+    // we don't do any error handling yet, which is bad
+    const char *data = result.data.data();
+    uint copyFileHandle = extractInt(data + 2);
+    qDebug() << copyFileHandle;
+    QFile file(m_copySrcFileName);
+    file.open(QIODevice::ReadOnly);
+    QByteArray src = file.readAll();
+    file.close();
+    const int BLOCKSIZE = 1024;
+    int size = src.length();
+    int pos = 0;
+    while (pos < size) {
+        QByteArray ba;
+        appendInt(&ba, copyFileHandle, TargetByteOrder);
+        appendString(&ba, src.mid(pos, BLOCKSIZE), TargetByteOrder, false);
+        sendTrkMessage(TrkWriteFile, 0, ba);
+        pos += BLOCKSIZE;
+    }
+    QByteArray ba;
+    appendInt(&ba, copyFileHandle, TargetByteOrder);
+    appendInt(&ba, QDateTime::currentDateTime().toTime_t(), TargetByteOrder);
+    sendTrkMessage(TrkCloseFile, CB(handleFileCreated), ba);
+}
+
+void Adapter::handleFileCreated(const TrkResult &result)
+{
+    Q_UNUSED(result)
+    installAndRun();
+}
+
 void Adapter::handleCpuType(const TrkResult &result)
 {
     logMessage("HANDLE CPU TYPE: " + result.toString());
@@ -618,6 +673,22 @@ void Adapter::cleanUp()
     // Error: 0x00
 }
 
+void Adapter::copyFileToRemote()
+{
+    QByteArray ba;
+    appendByte(&ba, 0x10);
+    appendString(&ba, m_copyDstFileName.toLocal8Bit(), TargetByteOrder, false);
+    sendTrkMessage(TrkOpenFile, CB(handleFileCreation), ba);
+}
+
+void Adapter::installRemotePackageSilently(const QString &fileName)
+{
+    QByteArray ba;
+    appendByte(&ba, 'C');
+    appendString(&ba, fileName.toLocal8Bit(), TargetByteOrder, false);
+    sendTrkMessage(TrkInstallFile, 0, ba);
+}
+
 void Adapter::startInferiorIfNeeded()
 {
     if (m_session.pid != 0) {
@@ -635,9 +706,13 @@ void Adapter::startInferiorIfNeeded()
 
 int main(int argc, char *argv[])
 {
-    if (argc < 3) {
-        qDebug() << "Usage: " << argv[0] << "<trkservername> <remotefilename>";
+    if ((argc != 3 && argc != 5 && argc != 6)
+            || (argc == 5 && QString(argv[2]) != "-i")
+            || (argc == 6 && QString(argv[2]) != "-I")) {
+        qDebug() << "Usage: " << argv[0] << "<trk_port_name> [-i remote_sis_file | -I local_sis_file remote_sis_file] <remote_executable_name>";
         qDebug() << "for example" << argv[0] << "COM5 C:\\sys\\bin\\test.exe";
+        qDebug() << "           " << argv[0] << "COM5 -i C:\\Data\\test_gcce_udeb.sisx C:\\sys\\bin\\test.exe";
+        qDebug() << "           " << argv[0] << "COM5 -I C:\\Projects\\test\\test_gcce_udeb.sisx C:\\Data\\test_gcce_udeb.sisx C:\\sys\\bin\\test.exe";
         return 1;
     }
 
@@ -649,7 +724,16 @@ int main(int argc, char *argv[])
 
     Adapter adapter;
     adapter.setTrkServerName(argv[1]);
-    adapter.setFileName(argv[2]);
+    if (argc == 3) {
+        adapter.setFileName(argv[2]);
+    } else if (argc == 5) {
+        adapter.setInstallFileName(argv[3]);
+        adapter.setFileName(argv[4]);
+    } else {
+        adapter.setCopyFileName(argv[3], argv[4]);
+        adapter.setInstallFileName(argv[4]);
+        adapter.setFileName(argv[5]);
+    }
     if (adapter.startServer())
         return app.exec();
     return 4;
diff --git a/tests/manual/trk/trkutils.cpp b/tests/manual/trk/trkutils.cpp
index d29acb535e735ff6ba41c02a0eae890646685557..1a1c7345edfab24c5a9885c069a21dea5d552eaa 100644
--- a/tests/manual/trk/trkutils.cpp
+++ b/tests/manual/trk/trkutils.cpp
@@ -261,13 +261,15 @@ void appendInt(QByteArray *ba, uint i, Endianness endian)
     }
 }
 
-void appendString(QByteArray *ba, const QByteArray &str, Endianness endian)
+void appendString(QByteArray *ba, const QByteArray &str, Endianness endian, bool appendNullTerminator)
 {
     const int n = str.size();
-    appendShort(ba, n+1, endian); // count the terminating \0
+    const int fullSize = n + (appendNullTerminator ? 1 : 0);
+    appendShort(ba, fullSize, endian); // count the terminating \0
     for (int i = 0; i != n; ++i)
         ba->append(str.at(i));
-    ba->append('\0');
+    if (appendNullTerminator)
+        ba->append('\0');
 }
 
 QByteArray errorMessage(byte code)
diff --git a/tests/manual/trk/trkutils.h b/tests/manual/trk/trkutils.h
index 95b000133072756e52c8d43565c71852cc9d39c6..4e62bb5a24c58ff8e2b12740d1630c3b1a878c5c 100644
--- a/tests/manual/trk/trkutils.h
+++ b/tests/manual/trk/trkutils.h
@@ -40,14 +40,22 @@ typedef unsigned char byte;
 namespace trk {
 
 enum Command {
+    TrkPing = 0x00,
     TrkConnect = 0x01,
     TrkVersions = 0x04,
     TrkSupported = 0x05,
     TrkCpuType = 0x06,
+    TrkHostVersions = 0x09,
     TrkContinue = 0x18,
     TrkCreateItem = 0x40,
     TrkDeleteItem = 0x41,
 
+    TrkWriteFile = 0x48,
+    TrkOpenFile = 0x4a,
+    TrkCloseFile = 0x4b,
+    TrkInstallFile = 0x4d,
+    TrkInstallFile2 = 0x4e,
+
     TrkNotifyAck = 0x80,
     TrkNotifyNak = 0xff,
     TrkNotifyStopped = 0x90,
@@ -83,7 +91,7 @@ enum Endianness
 void appendByte(QByteArray *ba, byte b);
 void appendShort(QByteArray *ba, ushort s, Endianness = TargetByteOrder);
 void appendInt(QByteArray *ba, uint i, Endianness = TargetByteOrder);
-void appendString(QByteArray *ba, const QByteArray &str, Endianness = TargetByteOrder);
+void appendString(QByteArray *ba, const QByteArray &str, Endianness = TargetByteOrder, bool appendNullTerminator = true);
 
 enum CodeMode
 {