解决QT程序自动启动时找不到DLL的问题

最近写了一个自动启动的QT程序,将程序及DLL都放到了同一个目录下。
双击启动,当然没有问题。
但设置为自动启动的时候,就提示找不到需要的DLL了。

最简单的方法,当然就是将DLL放到System32下面或者将DLL放到其他PATH的路径下面。
但我自己的环境已经够复杂了,实在是不想有其他冲突了。

于是,用VS写了一个启动用的Loader。
这个Loader啥都不干,就是先设置PATH,然后将参数传递给QT的EXE,启动之。

Android读取并解析Json

1、不可以在UI线程直接读取网络数据,所以另起线程处理这件事情

public class MainActivity extends ActionBarActivity implements IParseJsonCallback,IParseHtmlCallback{

    public void ParseJsonPage(List<PhaseResultBean> resultList) {
        new ParseJson(this).execute(resultList);
    }

    @Override
    public void ParseJsonDone(List<PhaseResultBean> resultList) {
        //回调函数
    }
}

2、回调接口

package com.neohope.android.gpjj;

import java.util.List;

public interface IParseJsonCallback {
        void ParseJsonDone(List<PhaseResultBean> resultList);
}

3、解析Json类

package com.neohope.android.gpjj;

import android.os.AsyncTask;
import android.util.Log;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

public class ParseJson extends AsyncTask<String,Void,List<PhaseResultBean>>{

    private IParseJsonCallback jsonCallback;

    public ParseJson(IParseJsonCallback jsonCallback)
    {
        this.jsonCallback = jsonCallback;
    }

    @Override
    protected List<PhaseResultBean> doInBackground(String... params) {
        if(params==null)return null;
        List<PhaseResultBean> resultList= new ArrayList<PhaseResultBean>();

        String jsonString = params[0];
        try {
            JSONObject json= new JSONObject(jsonString);
            JSONArray jijinlist = json.getJSONArray("jijinlist");

            for(int i=0;i<jijinlist.length();i++)
            {
                JSONObject JJ= jijinlist.getJSONObject(i);
                PhaseResultBean result = new PhaseResultBean();
                result.code = JJ.getString("code");
                resultList.add(result);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return resultList;
    }

    @Override
    protected void onPostExecute(List<PhaseResultBean> resultList) {
        super.onPostExecute(resultList);
        jsonCallback.ParseJsonDone(resultList);
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }
}

Android用JSoup解析网页

1、不可以在UI线程直接读取网络数据,所以另起线程处理这件事情

public class MainActivity extends ActionBarActivity implements IParseJsonCallback,IParseHtmlCallback{

    public void ParseHtmlPage(List<PhaseResultBean> resultList) {
        new ParseHtml(this).execute(resultList);
    }

    @Override
    public void ParseHtmlDone(List<PhaseResultBean> resultList) {
        //回调函数
    }
}

2、回调接口

package com.neohope.android.gpjj;

import java.util.List;

public interface IParseHtmlCallback {
    void ParseHtmlDone(List<PhaseResultBean> resultList);
}

3、解析HTML类

package com.neohope.android.gpjj;

import android.os.AsyncTask;
import android.util.Log;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.IOException;
import java.util.List;

public class ParseHtml extends AsyncTask<List<PhaseResultBean>,Void,List<PhaseResultBean>>{

    private IParseHtmlCallback htmlCallback;

    public ParseHtml(IParseHtmlCallback htmlCallback)
    {
        this.htmlCallback = htmlCallback;
    }

    @Override
    protected List<PhaseResultBean> doInBackground(List<PhaseResultBean>... paramList) {
        if(paramList==null)return null;
        List<PhaseResultBean> params = paramList[0];
        for(PhaseResultBean bean : params) {
            Document doc = null;
            String url = bean.httpUrl;
            try {
                doc = Jsoup.connect(url).userAgent("Mozilla/5.0 (Windows; U; WindowsNT 5.1; en-US; rv1.8.1.6) Gecko/20070725 Firefox/2.0.0.6").timeout(5000).followRedirects(true).get();
            } catch (IOException ex) {
                Log.w("", ex.getMessage());
                return null;
            }

            Document content = Jsoup.parse(doc.toString());
            Element dodydiv = content.getElementById("bodydiv");
            Element div = dodydiv.child(6).child(1).child(0).child(0);

            Element code = div.child(0).child(2);
            String szCode = code.text();

            Element title = div.child(0).child(1);
            String szTitle = title.text();

            bean.code = szCode;
            bean.name = szTitle;
        }

        return params;
    }

    @Override
    protected void onPostExecute(List<PhaseResultBean> listResult) {
        super.onPostExecute(listResult);
        htmlCallback.ParseHtmlDone(listResult);
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }
}

QT使用Timer

void MainWindow::initTimer()
{
    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(timerRecalc()));
    timer->start(1000*6);
}


void MainWindow::timerRecalc()
{
    for(int i=0;i<eventArray->size();i++)
    {
        NMyEvent myEvent = eventArray->at(i);
        ui->tableMain->setItem(i, 0, new QTableWidgetItem(myEvent.EventName));
        ui->tableMain->setItem(i, 1, new QTableWidgetItem(NMyUtils::formatDate(myEvent.TimeBegin)));
        ui->tableMain->setItem(i, 2, new QTableWidgetItem(NMyUtils::formatDate(myEvent.TimeDue)));
        myEvent.reCalcDaysLeft();
        ui->tableMain->setItem(i, 3, new QTableWidgetItem(myEvent.DaysLeft));
        ui->tableMain->setItem(i, 4, new QTableWidgetItem(myEvent.Comments));
    }
}

QT读取JSON

void MainWindow::readJson(QString fileName)
{
    QString szContent = NMyUtils::readFile(NMyUtils::getFileFullPath(fileName));

    QJsonDocument jDoc = QJsonDocument::fromJson(szContent.toUtf8());
    QJsonObject jObj = jDoc.object();
    QJsonArray jReminderItems = jObj.value(QString("Reminder")).toArray();

    foreach (const QJsonValue & item, jReminderItems)
    {
        QJsonValue eName = (item.toObject())["EventName"];
        QJsonValue tBegin = (item.toObject())["TimeBegin"];
        QJsonValue tDue = (item.toObject())["TimeDue"];
        QJsonValue comments = (item.toObject())["Comments"];
        const NMyEvent *myevent = NMyEvent::newEvent(eName.toString(),tBegin.toString(),tDue.toString(),comments.toString());

        eventArray->append(*myevent);
    }
}

QT实现自动启动(Windows)

QString NMyUtils::getExeFullPathWithArgs()
{
    QString exePath = QCoreApplication::applicationFilePath().replace("/","\\").replace("Reminder.exe","QTLoader.exe");
    QString argPath = "\""+exePath+"\" TrayIcon";
    qDebug()<<argPath;
    return argPath;
}

bool NMyUtils::isAutoStart()
{
    QSettings reg("HKEY_LOCAL_MACHINE\\SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\RUN", QSettings::NativeFormat);
    QString val = reg.value("NReminder").toString();
    if(val.length()>0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

void NMyUtils::setAutoStart()
{
    QSettings reg("HKEY_LOCAL_MACHINE\\SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\RUN", QSettings::NativeFormat);
    reg.setValue("NReminder",NMyUtils::getExeFullPathWithArgs());
}

void NMyUtils::removeAutoStart()
{
    QSettings reg("HKEY_LOCAL_MACHINE\\SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\RUN", QSettings::NativeFormat);
    reg.remove("NReminder");
}

QT实现TrayIcon

void MainWindow::initTrayIcon()
{
    trayIcon=new QSystemTrayIcon(this);
    appIcon =new QIcon(NMyUtils::getFileFullPath("Reminder.png"));
    trayIcon->setIcon(*appIcon);
    this->setWindowIcon(*appIcon);

    autoStartAction = new QAction(tr("AutoStart"),this);
    autoStartAction->setCheckable(true);
    if(NMyUtils::isAutoStart())
    {
        autoStartAction->setChecked(true);
    }
    connect(autoStartAction, SIGNAL(triggered()), this, SLOT(autoStart()));
    showHideAction = new QAction(tr("Show"),this);
    showHideAction->setCheckable(true);
    showHideAction->setChecked(true);
    connect(showHideAction, SIGNAL(triggered()), this, SLOT(showHide()));
    quitAction = new QAction(tr("Quit"),this);
    connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));

    trayIconMenu = new QMenu(this);
    trayIconMenu->addAction(autoStartAction);
    trayIconMenu->addAction(showHideAction);
    trayIconMenu->addSeparator();
    trayIconMenu->addAction(quitAction);
    trayIcon->setContextMenu(trayIconMenu);

    trayIcon->setToolTip(tr("Reminder"));
    connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
    trayIcon->show();
}

Android任务栏通知

        private static int nId = 0;

        private void RaiseSysTrayAlert(List<NEventBean> eventList)
        {
            NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            Context context = getApplicationContext();

            for(NEventBean bean : eventList)
            {
                Builder mBuilder = new Builder(context);
                mBuilder.setTicker("XXXX");
                mBuilder.setSmallIcon(R.drawable.ic_launcher);
                mBuilder.setContentTitle("XXXX");
                mBuilder.setContentText(bean.msg);
                mBuilder.setAutoCancel(true);

                Intent notifyIntent = new Intent(context, MainActivity.class);
                notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                PendingIntent pIntent = PendingIntent.getActivity(context, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
                mBuilder.setContentIntent(pIntent);

                nId++;
                nm.notify(nId, mBuilder.build());
            }
        }

Android后台服务及自动运行

1、修改AndroidManifest.xml文件

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<application ...>
        <service
            android:name="com.neohope.android.service.NService"
            android:enabled="true"
            android:exported="true" >
        </service>

        <receiver android:name="com.neohope.android.receiver.NBroadcastReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
</application>

2、新增服务类

package com.neohope.android.service;

import android.app.Service;
import android.content.Context;
import android.content.Intent;

public class NService extends Service {

    public NService() {
        
    }

    @Override
    public void onCreate() {
        mainThread = new WorkThread ();
        mainThread.start();
    }

    @Override
    public void onDestroy() {
        mainThread.bEnd = true;
    }

    class WorkThread extends Thread
    {
        private int nInterval = 1000*60;
        private boolean bEnd = false;

        public JsonReaderThread()
        {
        }

        @Override
        public void run()
        {
            while(!bEnd)
            {
                DoSomething();

                try {
                    Thread.sleep(nInterval);
                } catch (InterruptedException e) {
                    Log.w("", "");
                }
            }
        }

        private void DoSomething()
        {
        }

}

3、新增广播处理类

package com.neohope.android.receiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

import com.neohope.android.service.NService;

public class NBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent startServiceIntent = new Intent(context, NService.class);
        context.startService(startServiceIntent);
    }
}

4、在Activity中添加启动代码

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        doStartService();
    }

    public void doStartService() {
        Context context = getApplicationContext();
        Intent startServiceIntent = new Intent(context, NService.class);
        context.startService(startServiceIntent);
    }

Android读取网页内容

1、修改AndroidManifest.xml文件

<uses-permission android:name="android.permission.INTERNET" />

2、网页读取类

package com.neohope.android.web;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;

public class HttpUtils {

    public static String readStringFromUrl(String szUrl,String szCharcode) throws IOException {
        URL url = new URL(szUrl);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(5 * 1000);
        conn.setRequestMethod("GET");

        String szJson = "";
        int resPonseCode = conn.getResponseCode();
        if (conn.getResponseCode() == 200)
        {
            InputStream is = conn.getInputStream();
            byte[] data = readStream(is);
            szJson = new String(data,szCharcode);
        }

        return szJson;
    }

    private static byte[] readStream(InputStream inputStream) throws IOException {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inputStream.read(buffer)) != -1) {
            bout.write(buffer, 0, len);
        }
        bout.close();
        inputStream.close();

        return bout.toByteArray();
    }
}