跳转到帖子

排行榜


热门内容

显示自从 12/15/20 在所有区域 以来最高声誉的内容

  1. 3 点 积分
    void Uploador::on_submit_photo_clicked() { QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); QHttpPart _uid; _uid.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"uid\"")); _uid.setBody(uid.toUtf8()); multiPart->append(_uid); QHttpPart _key; _key.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"key\"")); _key.setBody("ABCD"); multiPart->append(_key); QHttpPart tit; tit.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"title\"")); tit.setBody(ui->lineEdit_title->text().toUtf8()); multiPart->append(tit); QHttpPart tags; tags.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"tags\"")); tags.setBody(ui->lineEdit_tag->text().toUtf8()); multiPart->append(tags); QHttpPart _filename; _filename.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"filename\"")); _filename.setBody(filename.toUtf8()); multiPart->append(_filename); QString ext = get_ext(filename); QHttpPart imagePart; imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(ext)); imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"stream\"")); file = new QFile(); if(local.length() > 2) { file = new QFile(local); local_file = local; } else { local_file = tmp_folder+filename; file = new QFile(local_file); } file->open(QIODevice::ReadOnly); imagePart.setBodyDevice(file); file->setParent(multiPart); multiPart->append(imagePart); QUrl url("http://www.abc.com/client/api"); QNetworkRequest request(url); QNetworkAccessManager *mgr = new QNetworkAccessManager(); QNetworkReply *reply = mgr->post(request, multiPart); multiPart->setParent(reply); connect(mgr,SIGNAL(finished(QNetworkReply*)),this,SLOT(slot_requestFinished(QNetworkReply*))); }
  2. 2 点 积分
  3. 2 点 积分
  4. 2 点 积分
  5. 2 点 积分
  6. 1 点 积分
    Welcome to thinkh5.com
  7. 1 点 积分
    运行下面的命令: echo "/usr/local/lib" | sudo tee /etc/ld.so.conf.d/openssl-3.2.0.conf echo "/usr/local/lib64" | sudo tee -a /etc/ld.so.conf.d/openssl-3.2.0.conf 然后执行: sudo ldconfig
  8. 1 点 积分
    git fetch --all && git reset --hard origin/master && git pull
  9. 1 点 积分
    let a = {} undefined a {} JSON.stringify(a) === '{}' true
  10. 1 点 积分
    由于有人注册而没有任何人发言,所以专门注册一个马甲来测试一下是不是可以正常回帖
  11. 1 点 积分
    #include <iostream> #include <string> #include <algorithm> bool is_numeric(std::string const &str) { auto it = std::find_if(str.begin(), str.end(), [](char const &c) { return !std::isdigit(c); }); return !str.empty() && it == str.end(); } int main() { std::string str = "1234567890"; std::cout << std::boolalpha << is_numeric(str) << std::endl; // true return 0; }
  12. 1 点 积分
    测试注册功能是不是正常
  13. 1 点 积分
  14. 1 点 积分
    先看效果图: Toast.h #ifndef TOAST_H #define TOAST_H #include <QDialog> namespace Ui { class Toast; } class Toast : public QDialog { Q_OBJECT public: explicit Toast(QWidget *parent = nullptr); ~Toast(); void setText(const QString& text); void setBgColor(const QString& color); void showAnimation(int timeout = 3000); public: static void tip(const QString& text); static void info(const QString& text); static void warn(const QString& text); static void err(const QString& text); static void succ(const QString& text); static void display(const QString& text,QString); protected: virtual void paintEvent(QPaintEvent *event); private: Ui::Toast *ui; }; #endif // TOAST_H Toast.cpp #include "Toast.h" #include "ui_Toast.h" #include <QPropertyAnimation> #include <QScreen> #include <QGuiApplication> #include <QPainter> #include <QTimer> Toast::Toast(QWidget *parent) : QDialog(parent), ui(new Ui::Toast) { ui->setupUi(this); setWindowFlags(windowFlags() | Qt::FramelessWindowHint | Qt::Tool); setAttribute(Qt::WA_TranslucentBackground, true); } Toast::~Toast() { delete ui; } void Toast::setText(const QString& text) { ui->label->setText(text); } void Toast::setBgColor(const QString &color) { QString css = "border-radius: 26px;color: #FFFFFF;font-family: microsoft yahei;font-size: 16px;padding-left:25px;padding-right:25px;"; if("ERROR" == color) { ui->label->setStyleSheet("background-color: #dc3545;"+css); }else if("SUCC" == color) { ui->label->setStyleSheet("background-color: #198754;"+css); } else if("WARNING" == color) { ui->label->setStyleSheet("background-color: #fd7e14;"+css); } else if("INFOMATION" == color) { ui->label->setStyleSheet("background-color: #009ef6;"+css); } else{ ui->label->setStyleSheet("background-color: rgba(0,0,0,0.80);"+css); } } void Toast::showAnimation(int timeout) { // 开始动画 QPropertyAnimation *animation = new QPropertyAnimation(this, "windowOpacity"); animation->setDuration(1000); animation->setStartValue(0); animation->setEndValue(1); animation->start(); show(); QTimer::singleShot(timeout, [&] { // 结束动画 QPropertyAnimation *animation = new QPropertyAnimation(this, "windowOpacity"); animation->setDuration(1000); animation->setStartValue(1); animation->setEndValue(0); animation->start(); connect(animation, &QPropertyAnimation::finished, [&] { close(); deleteLater();// 关闭后析构 }); }); } void Toast::tip(const QString &text) { display(text,"TIP"); } void Toast::info(const QString &text) { display(text,"INFOMATION"); } void Toast::warn(const QString &text) { display(text,"WARNING"); } void Toast::err(const QString &text) { display(text,"ERROR"); } void Toast::succ(const QString &text) { display(text,"SUCC"); } void Toast::display(const QString& text,QString color) { Toast* toast = new Toast(nullptr); toast->setWindowFlags(toast->windowFlags() | Qt::WindowStaysOnTopHint); // 置顶 toast->setText(text); toast->setBgColor(color); toast->adjustSize(); // 测试显示位于主屏的70%高度位置 QScreen* pScreen = QGuiApplication::primaryScreen(); toast->move((pScreen->size().width() - toast->width()) / 2, pScreen->size().height() * 7 / 10); toast->showAnimation(); } void Toast::paintEvent(QPaintEvent *event) { } Toast.ui <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>Toast</class> <widget class="QWidget" name="Toast"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>170</width> <height>52</height> </rect> </property> <property name="minimumSize"> <size> <width>0</width> <height>52</height> </size> </property> <property name="maximumSize"> <size> <width>16777215</width> <height>52</height> </size> </property> <property name="windowTitle"> <string>Toast</string> </property> <layout class="QGridLayout" name="gridLayout"> <property name="leftMargin"> <number>0</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> <number>0</number> </property> <property name="spacing"> <number>0</number> </property> <item row="0" column="0"> <widget class="QLabel" name="label"> <property name="styleSheet"> <string notr="true">background-color: rgba(0,0,0,0.80); border-radius: 26px; color: #FFFFFF; font-family: microsoft yahei; font-size: 16px; padding-left:25px; padding-right:25px;</string> </property> <property name="text"> <string>TextLabel</string> </property> <property name="alignment"> <set>Qt::AlignCenter</set> </property> <property name="indent"> <number>-1</number> </property> </widget> </item> </layout> </widget> <layoutdefault spacing="6" margin="11"/> <resources/> <connections/> </ui>
  15. 1 点 积分
  16. 1 点 积分
    HttpClient.h #ifndef HTTPCLIENT_H #define HTTPCLIENT_H #include <functional> #include <QMap> #include <QVariant> #include <QStringList> #include <QNetworkReply> #include <QNetworkRequest> #include <QNetworkAccessManager> class HttpClientPrivate; /** * 对 QNetworkAccessManager 简单封装的 HTTP 访问客户端,简化 GET、POST、PUT、DELETE、上传、下载等操作。 * 在执行请求前设置需要的参数和回调函数: * 1. 调用 header() 设置请求头 * 2. 调用 param() 设置参数,使用 Form 表单的方式提交请求,GET 请求的 query parameters 也可以用它设置 * 3. 调用 json() 设置 JSON 字符串的 request body,Content-Type 为 application/json, * 当然也可以不是 JSON 格式,因使用 request body 的情况多数是使用 JSON 格式传递复杂对象,故命名为 json * 4. 调用 success() 注册请求成功的回调函数 * 5. 调用 fail() 注册请求失败的回调函数 * 6. 调用 complete() 注册请求结束的回调函数 * success(), fail(), complete() 的回调函数是可选的,根据需要注册对应的回调函数,也可以一个都不注册 * 然后根据请求的类型调用 get(), post(), put(), remove(), download(), upload() 执行 HTTP 请求 * * 默认 HttpClient 会创建一个 QNetworkAccessManager,如果不想使用默认的,调用 manager() 传入即可。 * 调用 debug(true) 设置为调试模式,输出调试信息如 URL、参数等。 */ /** // 在代码块里执行网络访问,是为了测试 HttpClient 对象在被析构后,网络访问的回调函数仍然能正常执行 { // [[1]] GET 请求无参数 HttpClient("http://localhost:8080/device").success([](const QString &response) { qDebug() << response; }).get(); // [[2]] GET 请求有参数,有自定义 header HttpClient("http://localhost:8080/device").success([](const QString &response) { qDebug() << response; }).param("id", "1").param("name", "诸葛亮").header("token", "123AS#D").get(); // [[3]] POST 请求有参数,有自定义 header HttpClient("http://localhost:8080/device").success([](const QString &response) { qDebug() << response; }).param("id", "2").param("name", "卧龙").header("token", "DER#2J7") .header("content-type", "application/x-www-form-urlencoded").post(); // [[4]] 每创建一个 QNetworkAccessManager 对象都会创建一个线程,当频繁的访问网络时,为了节省线程资源,调用 useManager() // 使用共享的 QNetworkAccessManager,它不会被 HttpClient 删除。 // 如果下面的代码不传入 QNetworkAccessManager,从任务管理器里可以看到创建了几千个线程。 QNetworkAccessManager *manager = new QNetworkAccessManager(); for (int i = 0; i < 5000; ++i) { HttpClient("http://localhost:8080/device").success([=](const QString &response) { qDebug() << response << ", " << i; }).manager(manager).get(); } } */ class HttpClient { public: HttpClient(const QString &url); ~HttpClient(); void stop2(); /** * @brief 每创建一个 QNetworkAccessManager 对象都会创建一个线程,当频繁的访问网络时,为了节省线程资源, * 可以传入 QNetworkAccessManager 给多个请求共享 (它不会被 HttpClient 删除,用户需要自己手动删除)。 * 如果没有使用 manager() 传入一个 QNetworkAccessManager,则 HttpClient 会自动的创建一个,并且在网络访问完成后自动删除它。 * * @param manager 执行 HTTP 请求的 QNetworkAccessManager 对象 * @return 返回 HttpClient 的引用,可以用于链式调用 */ HttpClient& manager(QNetworkAccessManager *manager); /** * @brief 参数 debug 为 true 则使用 debug 模式,请求执行时输出请求的 URL 和参数等 * * @param debug 是否启用调试模式 * @return 返回 HttpClient 的引用,可以用于链式调用 */ HttpClient& debug(bool debug); /** * @brief 添加一个请求的参数,可以多次调用添加多个参数 * * @param name 参数的名字 * @param value 参数的值 * @return 返回 HttpClient 的引用,可以用于链式调用 */ HttpClient& param(const QString &name, const QVariant &value); /** * @brief 添加多个请求的参数 * * @param ps QMap 类型的参数,key 为参数名,value 为参数值 * 可以使用 {{"name", 1}, {"box", 2}} 的方式创建 QMap 对象 * @return 返回 HttpClient 的引用,可以用于链式调用 */ HttpClient& params(const QMap<QString, QVariant> &ps); /** * @brief 添加请求的参数 (请求体),使用 Json 格式,例如 "{\"name\": \"Alice\"}" * * @param json 请求体 (request body) 为 Json 格式的参数字符串 * @return 返回 HttpClient 的引用,可以用于链式调用 */ HttpClient& json(const QString &json); /** * @brief 添加请求头 * * @param name 请求头的名字 * @param value 请求头的值 * @return 返回 HttpClient 的引用,可以用于链式调用 */ HttpClient& header(const QString &name, const QString &value); /** * @brief 添加多个请求头 * * @param nameValues 请求头的名字和值对 * 可以使用 {{"name", 1}, {"box", 2}} 的方式创建 QMap 对象 * @return 返回 HttpClient 的引用,可以用于链式调用 */ HttpClient& headers(const QMap<QString, QString> nameValues); /** * @brief 注册请求成功的回调函数 * * @param successHandler 成功的回调函数,参数为响应的字符串 * @return 返回 HttpClient 的引用,可以用于链式调用 */ HttpClient& success(std::function<void(const QString &)> successHandler); /** * @brief 注册请求失败的回调函数 * * @param failHandler 失败的回调函数,参数为失败原因和 HTTP 状态码 * @return 返回 HttpClient 的引用,可以用于链式调用 */ HttpClient& fail(std::function<void(const QString &, int)> failHandler); /** * @brief 注册请求结束的回调函数,不管成功还是失败请求结束后都会执行 * * @param completeHandler 完成的回调函数,无参数 * @return 返回 HttpClient 的引用,可以用于链式调用 */ HttpClient& complete(std::function<void()> completeHandler); /** * @brief 设置请求响应的字符集,默认使用 UTF-8 * * @param cs 字符集 * @return 返回 HttpClient 的引用,可以用于链式调用 */ HttpClient& charset(const QString &cs); /** * @brief 执行 GET 请求 */ void get(); /** * @brief 执行 POST 请求 */ void post(); /** * @brief 执行 PUT 请求 */ void put(); /** * @brief 执行 DELETE 请求,由于 delete 是 C++ 的运算符,所以用同义词 remove * 注意: Qt 提供的 DELETE 请求是不支持传递参数的, * 请参考 QNetworkAccessManager::deleteResource(const QNetworkRequest &request) */ void remove(); /** * @brief 使用 GET 进行下载,下载的文件保存到 savePath * * @param savePath 下载的文件保存路径 */ void download(const QString &savePath); /** * @brief 上传单个文件 * 使用 POST 上传,服务器端获取文件的参数名为 file * * @param path 要上传的文件的路径 */ void upload(const QString &path); /** * @brief 上传文件,文件的内容已经读取到 data 中 * 使用 POST 上传,服务器端获取文件的参数名为 file * * @param path 要上传的文件的路径 */ void upload(const QByteArray &data); /** * @brief 上传多个文件 * 使用 POST 上传,服务器端获取文件的参数名为 files * * @param paths 要上传的文件的路径 */ void upload(const QStringList &paths); private: HttpClientPrivate *d; }; #endif // HTTPCLIENT_H HttpClient.cpp #include "HttpClient.h" #include <QDebug> #include <QFile> #include <QHash> #include <QUrlQuery> #include <QHttpPart> #include <QHttpMultiPart> /*-----------------------------------------------------------------------------| | HttpClientPrivate | |----------------------------------------------------------------------------*/ /** * @brief 请求的类型 * * 注: UPLOAD 不是 HTTP Method,只是为了上传时对请求进行特殊处理而定义的 */ enum class HttpClientRequestMethod { GET, POST, PUT, DELETE, UPLOAD }; /** * @brief 缓存 HttpClientPrivate 的数据成员,方便在异步 lambda 中使用 = 以值的方式访问。 */ class HttpClientPrivateCache { public: std::function<void(const QString &)> successHandler = nullptr; std::function<void(const QString &, int)> failHandler = nullptr; std::function<void()> completeHandler = nullptr; bool debug = false; bool internal = false; QString charset; QNetworkAccessManager* manager = nullptr; }; /** * @brief HttpClient 的辅助类,封装不希望暴露给客户端的数据和方法,使得 HttpClient 只暴露必要的 API 给客户端。 */ class HttpClientPrivate { friend class HttpClient; HttpClientPrivate(const QString &url); ~HttpClientPrivate(); void stop1(); /** * @brief 缓存 HttpClientPrivate 的数据成员 * * @return 返回 HttpClientPrivateCache 缓存对象 */ HttpClientPrivateCache cache(); /** * @brief 获取 Manager,如果传入了 manager 则返回此 manager,否则新创建一个 manager,默认会自动创建一个 manager, * 使用传入的 manager 则 interval 被设置为 false,自动创建的 manager 则设置 interval 为 true * * @return 返回 QNetworkAccessManager 对象 */ QNetworkAccessManager* getManager(); /** * @brief 使用用户设定的 URL、请求头、参数等创建 Request * * @param d HttpClientPrivate 的对象 * @param method 请求的类型 * @return 返回可用于执行请求的 QNetworkRequest */ static QNetworkRequest createRequest(HttpClientPrivate *d, HttpClientRequestMethod method); /** * @brief 执行请求的辅助函数 * * @param d HttpClientPrivate 的对象 * @param method 请求的类型 */ static void executeQuery(HttpClientPrivate *d, HttpClientRequestMethod method); /** * @brief 上传文件或者数据 * * @param d HttpClientPrivate 的对象 * @param paths 要上传的文件的路径(path 和 data 不能同时使用) * @param data 要上传的文件的数据 */ static void upload(HttpClientPrivate *d, const QStringList &paths, const QByteArray &data); /** * @brief 使用 GET 进行下载,下载的文件保存到 savePath * * @param d HttpClientPrivate 的对象 * @param savePath 下载的文件保存路径 */ static void download(HttpClientPrivate *d, const QString &savePath); /** * @brief 使用 GET 进行下载,当有数据可读取时回调 readyRead(), 大多数情况下应该在 readyRead() 里把数据保存到文件 * * @param readyRead 有数据可读取时的回调 lambda 函数 */ static void download(HttpClientPrivate *d, std::function<void(const QByteArray &)> readyRead); /** * @brief 读取服务器响应的数据 * * @param reply 请求的 QNetworkReply 对象 * @param charset 请求响应的字符集,默认使用 UTF-8 * @return 返回服务器端响应的字符串 */ static QString readReply(QNetworkReply *reply, const QString &charset = "UTF-8"); /** * @brief 请求结束的处理函数 * * @param cache HttpClientPrivateCache 缓存对象 * @param reply QNetworkReply 对象,不能为 NULL * @param successMessage 请求成功的消息 * @param failMessage 请求失败的消息 */ static void handleFinish(HttpClientPrivateCache cache, QNetworkReply *reply, const QString &successMessage, const QString &failMessage); /////////////////////////////////////////////////// 成员变量 ////////////////////////////////////////////// QString url; // 请求的 URL QString json; // 请求的参数使用 Json 格式 QUrlQuery params; // 请求的参数使用 Form 格式 QString charset = "UTF-8"; // 请求响应的字符集 QHash<QString, QString> headers; // 请求头 QNetworkAccessManager *manager = nullptr; // 执行 HTTP 请求的 QNetworkAccessManager 对象 bool useJson = false; // 为 true 时请求使用 Json 格式传递参数,否则使用 Form 格式传递参数 bool debug = false; // 为 true 时输出请求的 URL 和参数 bool internal = true; // 是否使用自动创建的 manager std::function<void(const QString &)> successHandler = nullptr; // 成功的回调函数,参数为响应的字符串 std::function<void(const QString &, int)> failHandler = nullptr; // 失败的回调函数,参数为失败原因和 HTTP status code std::function<void()> completeHandler = nullptr; // 结束的回调函数,无参数 }; HttpClientPrivate::HttpClientPrivate(const QString &url) : url(url) { } HttpClientPrivate::~HttpClientPrivate() { manager = nullptr; successHandler = nullptr; failHandler = nullptr; completeHandler = nullptr; } void HttpClientPrivate::stop1() { manager->deleteLater(); } // 缓存 HttpClientPrivate 的数据成员 HttpClientPrivateCache HttpClientPrivate::cache() { HttpClientPrivateCache cache; cache.successHandler = successHandler; cache.failHandler = failHandler; cache.completeHandler = completeHandler; cache.debug = debug; cache.internal = internal; cache.charset = charset; cache.manager = getManager(); return cache; } // 执行请求的辅助函数 void HttpClientPrivate::executeQuery(HttpClientPrivate *d, HttpClientRequestMethod method) { // 1. 缓存需要的变量,在 lambda 中使用 = 捕获进行值传递 (不能使用引用 &,因为 d 已经被析构) // 2. 创建请求需要的变量 // 3. 根据 method 执行不同的请求 // 4. 请求结束时获取响应数据,在 handleFinish 中执行回调函数 // [1] 缓存需要的变量,在 lambda 中使用 = 捕获进行值传递 (不能使用引用 &,因为 d 已经被析构) HttpClientPrivateCache cache = d->cache(); // [2] 创建请求需要的变量 QNetworkRequest request = HttpClientPrivate::createRequest(d, method); QNetworkReply *reply = nullptr; // [3] 根据 method 执行不同的请求 switch (method) { case HttpClientRequestMethod::GET: reply = cache.manager->get(request); break; case HttpClientRequestMethod::POST: reply = cache.manager->post(request, d->useJson ? d->json.toUtf8() : d->params.toString(QUrl::FullyEncoded).toUtf8()); break; case HttpClientRequestMethod::PUT: reply = cache.manager->put(request, d->useJson ? d->json.toUtf8() : d->params.toString(QUrl::FullyEncoded).toUtf8()); break; case HttpClientRequestMethod::DELETE: reply = cache.manager->deleteResource(request); break; default: break; } // [4] 请求结束时获取响应数据,在 handleFinish 中执行回调函数 // 请求结束时一次性读取所有响应数据 QObject::connect(reply, &QNetworkReply::finished, [=] { QString successMessage = HttpClientPrivate::readReply(reply, cache.charset.toUtf8()); QString failMessage = reply->errorString(); HttpClientPrivate::handleFinish(cache, reply, successMessage, failMessage); }); } // 使用 GET 进行下载,下载的文件保存到 savePath void HttpClientPrivate::download(HttpClientPrivate *d, const QString &savePath) { // 1. 打开下载文件,如果打开文件出错,不进行下载 // 2. 给请求结束的回调函数注入关闭释放文件的行为 // 3. 调用下载的重载函数开始下载 QFile *file = new QFile(savePath); // [1] 打开下载文件,如果打开文件出错,不进行下载 if (!file->open(QIODevice::WriteOnly | QIODevice::Truncate)) { file->close(); file->deleteLater(); if (d->debug) { qDebug().noquote() << QString("[错误] 打开文件出错: %1").arg(savePath); } if (nullptr != d->failHandler) { d->failHandler(QString("[错误] 打开文件出错: %1").arg(savePath), -1); } return; } // [2] 给请求结束的回调函数注入关闭释放文件的行为 std::function<void()> userCompleteHandler = d->completeHandler; std::function<void()> injectedCompleteHandler = [=]() { // 请求结束后释放文件对象 file->flush(); file->close(); file->deleteLater(); // 执行用户指定的结束回调函数 if (nullptr != userCompleteHandler) { userCompleteHandler(); } }; d->completeHandler = injectedCompleteHandler; // [3] 调用下载的重载函数开始下载 HttpClientPrivate::download(d, [=](const QByteArray &data) { file->write(data); }); } // 使用 GET 进行下载,当有数据可读取时回调 readyRead(), 大多数情况下应该在 readyRead() 里把数据保存到文件 void HttpClientPrivate::download(HttpClientPrivate *d, std::function<void(const QByteArray &)> readyRead) { // 1. 缓存需要的变量,在 lambda 中使用 = 捕获进行值传递 (不能使用引用 &,因为 d 已经被析构) // 2. 创建请求需要的变量,执行请求 // 3. 有数据可读取时回调 readyRead() // 4. 请求结束时获取响应数据,在 handleFinish 中执行回调函数 // [1] 缓存需要的变量,在 lambda 中使用 = 捕捉使用 (不能使用引用 &,因为 d 已经被析构) HttpClientPrivateCache cache = d->cache(); // [2] 创建请求需要的变量,执行请求 QNetworkRequest request = HttpClientPrivate::createRequest(d, HttpClientRequestMethod::GET); QNetworkReply *reply = cache.manager->get(request); // [3] 有数据可读取时回调 readyRead() QObject::connect(reply, &QNetworkReply::readyRead, [=] { readyRead(reply->readAll()); }); // [4] 请求结束时获取响应数据,在 handleFinish 中执行回调函数 QObject::connect(reply, &QNetworkReply::finished, [=] { QString successMessage = "下载完成"; // 请求结束时一次性读取所有响应数据 QString failMessage = reply->errorString(); HttpClientPrivate::handleFinish(cache, reply, successMessage, failMessage); }); } // 上传文件或者数据的实现 void HttpClientPrivate::upload(HttpClientPrivate *d, const QStringList &paths, const QByteArray &data) { // 1. 缓存需要的变量,在 lambda 中使用 = 捕获进行值传递 (不能使用引用 &,因为 d 已经被析构) // 2. 创建 Form 表单的参数 Text Part // 3. 创建上传的 File Part // 3.1 使用文件创建 File Part // 3.2 使用数据创建 File Part // 4. 创建请求需要的变量,执行请求 // 5. 请求结束时释放 multiPart 和打开的文件,获取响应数据,在 handleFinish 中执行回调函数 // [1] 缓存需要的变量,在 lambda 中使用 = 捕捉使用 (不能使用引用 &,因为 d 已经被析构) HttpClientPrivateCache cache = d->cache(); // [2] 创建 Form 表单的参数 Text Part QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); QList<QPair<QString, QString> > paramItems = d->params.queryItems(); for (int i = 0; i < paramItems.size(); ++i) { QString name = paramItems.at(i).first; QString value = paramItems.at(i).second; QHttpPart textPart; textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QString("form-data; name=\"%1\"").arg(name)); textPart.setBody(value.toUtf8()); multiPart->append(textPart); } if (paths.size() > 0) { // [3.1] 使用文件创建 File Part QString inputName = paths.size() == 1 ? "file" : "files"; // 一个文件时为 file,多个文件时为 files for (const QString &path : paths) { // path 为空时,不上传文件 if (path.isEmpty()) { continue; } // We cannot delete the file now, so delete it with the multiPart QFile *file = new QFile(path, multiPart); // 如果文件打开失败,则释放资源返回,终止上传 if (!file->open(QIODevice::ReadOnly)) { QString failMessage = QString("打开文件失败[%2]: %1").arg(path).arg(file->errorString()); if (cache.debug) { qDebug().noquote() << failMessage; } if (nullptr != cache.failHandler) { cache.failHandler(failMessage, -1); } multiPart->deleteLater(); return; } // 单个文件时,name 为服务器端获取文件的参数名,为 file // 多个文件时,name 为服务器端获取文件的参数名,为 files // 注意: 服务器是 Java 的则用 form-data // 注意: 服务器是 PHP 的则用 multipart/form-data QString disposition = QString("form-data; name=\"%1\"; filename=\"%2\"").arg(inputName).arg(file->fileName()); QHttpPart filePart; filePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(disposition)); filePart.setBodyDevice(file); multiPart->append(filePart); } } else { // [3.2] 使用数据创建 File Part QString disposition = QString("form-data; name=\"file\"; filename=\"no-name\""); QHttpPart dataPart; dataPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(disposition)); dataPart.setBody(data); multiPart->append(dataPart); } // [4] 创建请求需要的变量,执行请求 QNetworkRequest request = HttpClientPrivate::createRequest(d, HttpClientRequestMethod::UPLOAD); QNetworkReply *reply = cache.manager->post(request, multiPart); // [5] 请求结束时释放 multiPart 和文件,获取响应数据,在 handleFinish 中执行回调函数 QObject::connect(reply, &QNetworkReply::finished, [=] { multiPart->deleteLater(); // 释放资源: multiPart + file QString successMessage = HttpClientPrivate::readReply(reply, cache.charset); // 请求结束时一次性读取所有响应数据 QString failMessage = reply->errorString(); HttpClientPrivate::handleFinish(cache, reply, successMessage, failMessage); }); } // 获取 Manager,如果传入了 manager 则返回此 manager,否则新创建一个 manager,默认会自动创建一个 manager QNetworkAccessManager* HttpClientPrivate::getManager() { return internal ? new QNetworkAccessManager() : manager; } // 使用用户设定的 URL、请求头、参数等创建 Request QNetworkRequest HttpClientPrivate::createRequest(HttpClientPrivate *d, HttpClientRequestMethod method) { // 1. 如果是 GET 请求,并且参数不为空,则编码请求的参数,放到 URL 后面 // 2. 调试时输出网址和参数 // 3. 设置 Content-Type // 4. 添加请求头到 request 中 bool get = method == HttpClientRequestMethod::GET; bool upload = method == HttpClientRequestMethod::UPLOAD; bool withForm = !get && !upload && !d->useJson; // PUT、POST 或者 DELETE 请求,且 useJson 为 false bool withJson = !get && !upload && d->useJson; // PUT、POST 或者 DELETE 请求,且 useJson 为 true // [1] 如果是 GET 请求,并且参数不为空,则编码请求的参数,放到 URL 后面 if (get && !d->params.isEmpty()) { d->url += "?" + d->params.toString(QUrl::FullyEncoded); } // [2] 调试时输出网址和参数 if (d->debug) { qDebug().noquote() << "[网址]" << d->url; if (withJson) { qDebug().noquote() << "[参数]" << d->json; } else if (withForm || upload) { QList<QPair<QString, QString> > paramItems = d->params.queryItems(); QString buffer; // 避免多次调用 qDebug() 输入调试信息,每次 qDebug() 都有可能输出行号等 // 按键值对的方式输出参数 for (int i = 0; i < paramItems.size(); ++i) { QString name = paramItems.at(i).first; QString value = paramItems.at(i).second; if (0 == i) { buffer += QString("[参数] %1=%2\n").arg(name).arg(value); } else { buffer += QString(" %1=%2\n").arg(name).arg(value); } } if (!buffer.isEmpty()) { qDebug().noquote() << buffer; } } } // [3] 设置 Content-Type // 如果是 POST 请求,useJson 为 true 时添加 Json 的请求头,useJson 为 false 时添加 Form 的请求头 if (withForm) { d->headers["Content-Type"] = "application/x-www-form-urlencoded"; } else if (withJson) { d->headers["Content-Type"] = "application/json; charset=utf-8"; } // [4] 添加请求头到 request 中 QNetworkRequest request(QUrl(d->url)); for (auto i = d->headers.cbegin(); i != d->headers.cend(); ++i) { request.setRawHeader(i.key().toUtf8(), i.value().toUtf8()); } return request; } // 读取服务器响应的数据 QString HttpClientPrivate::readReply(QNetworkReply *reply, const QString &charset) { QTextStream in(reply); QString result; in.setCodec(charset.toUtf8()); while (!in.atEnd()) { result += in.readLine(); } return result; } // 请求结束的处理函数 void HttpClientPrivate::handleFinish(HttpClientPrivateCache cache, QNetworkReply *reply, const QString &successMessage, const QString &failMessage) { // 1. 执行请求成功的回调函数 // 2. 执行请求失败的回调函数 // 3. 执行请求结束的回调函数 // 4. 释放 reply 和 manager 对象 if (reply->error() == QNetworkReply::NoError) { if (cache.debug) { qDebug().noquote() << QString("[结束] 成功: %1").arg(successMessage); } // [1] 执行请求成功的回调函数 if (nullptr != cache.successHandler) { cache.successHandler(successMessage); } } else { if (cache.debug) { qDebug().noquote() << QString("[结束] 失败: %1").arg(failMessage); } // [2] 执行请求失败的回调函数 if (nullptr != cache.failHandler) { cache.failHandler(failMessage, reply->error()); } } // [3] 执行请求结束的回调函数 if (nullptr != cache.completeHandler) { cache.completeHandler(); } // [4] 释放 reply 和 manager 对象 if (nullptr != reply) { reply->deleteLater(); } if (cache.internal && nullptr != cache.manager) { cache.manager->deleteLater(); } } /*-----------------------------------------------------------------------------| | HttpClient | |----------------------------------------------------------------------------*/ // 注意: 在异步请求中 HttpClient 的 HttpClientPrivate 成员变量 d 已经被析构,所以需要先缓存相关变量为栈对象,使用 = 以值的方式访问 HttpClient::HttpClient(const QString &url) : d(new HttpClientPrivate(url)) { } HttpClient::~HttpClient() { delete d; } void HttpClient::stop2() { d->stop1(); } // 传入 QNetworkAccessManager 给多个请求共享 HttpClient& HttpClient::manager(QNetworkAccessManager *manager) { d->manager = manager; d->internal = (nullptr == manager); return *this; } // 传入 debug 为 true 则使用 debug 模式,请求执行时输出请求的 URL 和参数等 HttpClient& HttpClient::debug(bool debug) { d->debug = debug; return *this; } // 添加一个请求的参数,可以多次调用添加多个参数 HttpClient& HttpClient::param(const QString &name, const QVariant &value) { d->params.addQueryItem(name, value.toString()); return *this; } // 添加多个请求的参数 HttpClient& HttpClient::params(const QMap<QString, QVariant> &ps) { for (auto iter = ps.cbegin(); iter != ps.cend(); ++iter) { d->params.addQueryItem(iter.key(), iter.value().toString()); } return *this; } // 添加请求的参数 (请求体),使用 Json 格式,例如 "{\"name\": \"Alice\"}" HttpClient& HttpClient::json(const QString &json) { d->json = json; d->useJson = true; return *this; } // 添加请求头 HttpClient& HttpClient::header(const QString &name, const QString &value) { d->headers[name] = value; return *this; } // 添加多个请求头 HttpClient& HttpClient::headers(const QMap<QString, QString> nameValues) { for (auto i = nameValues.cbegin(); i != nameValues.cend(); ++i) { d->headers[i.key()] = i.value(); } return *this; } // 注册请求成功的回调函数 HttpClient& HttpClient::success(std::function<void(const QString &)> successHandler) { d->successHandler = successHandler; return *this; } // 注册请求失败的回调函数 HttpClient& HttpClient::fail(std::function<void(const QString &, int)> failHandler) { d->failHandler = failHandler; return *this; } // 注册请求结束的回调函数,不管成功还是失败都会执行 HttpClient& HttpClient::complete(std::function<void()> completeHandler) { d->completeHandler = completeHandler; return *this; } // 设置请求响应的编码 HttpClient& HttpClient::charset(const QString &cs) { d->charset = cs; return *this; } // 执行 GET 请求 void HttpClient::get() { HttpClientPrivate::executeQuery(d, HttpClientRequestMethod::GET); } // 执行 POST 请求 void HttpClient::post() { HttpClientPrivate::executeQuery(d, HttpClientRequestMethod::POST); } // 执行 PUT 请求 void HttpClient::put() { HttpClientPrivate::executeQuery(d, HttpClientRequestMethod::PUT); } // 执行 DELETE 请求 void HttpClient::remove() { HttpClientPrivate::executeQuery(d, HttpClientRequestMethod::DELETE); } // 使用 GET 进行下载,下载的文件保存到 savePath void HttpClient::download(const QString &savePath) { HttpClientPrivate::download(d, savePath); } // 上传文件 void HttpClient::upload(const QString &path) { QStringList paths = { path }; HttpClientPrivate::upload(d, paths, QByteArray()); } // 上传文件,文件的内容以及读取到 data 中 void HttpClient::upload(const QByteArray &data) { HttpClientPrivate::upload(d, QStringList(), data); } // 上传多个文件 void HttpClient::upload(const QStringList &paths) { HttpClientPrivate::upload(d, paths, QByteArray()); } 用法: #include "Component/HttpClient.h" HttpClient("https://www.abc.com/api.php").success([this](const QString &res) { //逻辑处理 }).param("参数1", 参数1).param("USER_TOKEN", USER_TOKEN).post();
  17. 1 点 积分
    #include <windows.h> //设置当前程序开机启动 void AutoPowerOn() { HKEY hKey; //std::string strRegPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"; //1、找到系统的启动项 if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"), 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) ///打开启动项 { //2、得到本程序自身的全路径 TCHAR strExeFullDir[MAX_PATH]; GetModuleFileName(NULL, strExeFullDir, MAX_PATH); //3、判断注册表项是否已经存在 TCHAR strDir[MAX_PATH] = {}; DWORD nLength = MAX_PATH; long result = RegGetValue(hKey, nullptr, _T("GISRestart"), RRF_RT_REG_SZ, 0, strDir, &nLength); //4、已经存在 if (result != ERROR_SUCCESS || _tcscmp(strExeFullDir, strDir) != 0) { //5、添加一个子Key,并设置值,"GISRestart"是应用程序名字(不加后缀.exe) RegSetValueEx(hKey, _T("GISRestart"), 0, REG_SZ, (LPBYTE)strExeFullDir, (lstrlen(strExeFullDir) + 1)*sizeof(TCHAR)); //6、关闭注册表 RegCloseKey(hKey); } } } //取消当前程序开机启动 void CanclePowerOn() { HKEY hKey; //std::string strRegPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"; //1、找到系统的启动项 if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"), 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) { //2、删除值 RegDeleteValue(hKey, _T("GISRestart")); //3、关闭注册表 RegCloseKey(hKey); } } 亲测有用
  18. 1 点 积分
    tmp sln: xinput list 列出列表,找到自带键盘的id 然后执行 xinput set-prop id "Device Enabled" 0 我的电脑自带键盘id为14:,所以如图: this sln is tmp,if you reboot your conputer , you must do this again. so, if you want do something once, your keyboard disable for ever,read this: 打开终端并运行以下命令 $sudo gedit /etc/default/grub 找到以下行 GRUB_CMDLINE_LINUX_DEFAULT="quiet splash" 添加参数i8042.nokbd,上面的行应该是这样的 GRUB_CMDLINE_LINUX_DEFAULT="quiet splash i8042.nokbd" 按以下命令更新grub $sudo update-grub 然后reboot你的笔记本电脑
  19. 1 点 积分

    Version 1.0.0

    22 downloads

    /* Copyright (c) 2011, Aurelien Aptel <aurelien.aptel@gmail.com> Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <string> #include <fstream> #include <iostream> #include <cstdlib> #include <vector> using namespace std; typedef unsigned char uchar; #define PW_MAGIC 0xA3 #define PW_MAXLEN 50 #define PW_FLAG 0xFF string decrypt(string pwd, string key); #ifdef WIN #include <windows.h> #define REG_MAXLEN_KEY 255 #define REG_MAXLEN_VAL 16383 const string session_path = TEXT("SOFTWARE\\Martin Prikryl\\WinSCP 2\\Sessions"); // mostly from MSDN bool reg_get_list (string key, vector<string>& keylist, vector<string>& vallist) { HKEY hKey; TCHAR achKey[REG_MAXLEN_KEY]; // buffer for subkey name DWORD cbName; // size of name string TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name DWORD cchClassName = MAX_PATH; // size of class string DWORD cSubKeys=0; // number of subkeys DWORD cbMaxSubKey; // longest subkey size DWORD cchMaxClass; // longest class string DWORD cValues; // number of values for key DWORD cchMaxValue; // longest value name DWORD cbMaxValueData; // longest value data DWORD cbSecurityDescriptor; // size of security descriptor FILETIME ftLastWriteTime; // last write time DWORD i, retCode; TCHAR achValue[REG_MAXLEN_VAL]; DWORD cchValue = REG_MAXLEN_VAL; retCode = RegOpenKeyExA(HKEY_CURRENT_USER, key.c_str(), 0, KEY_READ, &hKey); if(retCode != ERROR_SUCCESS) { cout << "bark\n"; return false; } // Get the class name and the value count. retCode = RegQueryInfoKey( hKey, // key handle achClass, // buffer for class name &cchClassName, // size of class string NULL, // reserved &cSubKeys, // number of subkeys &cbMaxSubKey, // longest subkey size &cchMaxClass, // longest class string &cValues, // number of values for this key &cchMaxValue, // longest value name &cbMaxValueData, // longest value data &cbSecurityDescriptor, // security descriptor &ftLastWriteTime); // last write time if (cSubKeys) { // printf( "\nNumber of subkeys: %lu\n", cSubKeys); for (i=0; i<cSubKeys; i++) { cbName = REG_MAXLEN_KEY; retCode = RegEnumKeyEx(hKey, i, achKey, &cbName, NULL, NULL, NULL, &ftLastWriteTime); if (retCode == ERROR_SUCCESS) { // printf("(%lu) %s\n", i+1, achKey); keylist.push_back(achKey); } } } if (cValues) { // printf( "\nNumber of values: %lu\n", cValues); for (i=0, retCode=ERROR_SUCCESS; i<cValues; i++) { cchValue = REG_MAXLEN_VAL; achValue[0] = '\0'; retCode = RegEnumValue(hKey, i, achValue, &cchValue, NULL, NULL, NULL, NULL); if(retCode == ERROR_SUCCESS) { // printf("(%lu) %s\n", i+1, achValue); vallist.push_back(achValue); } } } RegCloseKey(hKey); return true; } bool reg_get_key (string location, string name, string& val) { HKEY key; TCHAR value[1024]; DWORD bufLen = 1024*sizeof(TCHAR); long ret; ret = RegOpenKeyExA(HKEY_CURRENT_USER, location.c_str(), 0, KEY_QUERY_VALUE, &key); if(ret != ERROR_SUCCESS) { return false; } ret = RegQueryValueExA(key, name.c_str(), 0, 0, (LPBYTE) value, &bufLen); RegCloseKey(key); if ( (ret != ERROR_SUCCESS) || (bufLen > 1024*sizeof(TCHAR)) ){ return false; } string stringValue = string(value, (size_t)bufLen - 1); size_t i = stringValue.length(); while( i > 0 && stringValue[i-1] == '\0' ){ --i; } val = stringValue; return true; } void decrypt_registry_session (string session) { const string kuser = TEXT("UserName"), khost = TEXT("HostName"), kpw = TEXT("Password"), ktunuser = TEXT("TunnelUserName"), ktunhost = TEXT("TunnelHostName"), ktunpw = TEXT("TunnelPassword"); bool r = true; string user, host, pw; string path = session_path + TEXT("\\") + session; // normal session r = r && reg_get_key(path, kuser, user); r = r && reg_get_key(path, khost, host); r = r && reg_get_key(path, kpw, pw); if(r) cout << user << "@" << host << "\t" << decrypt(pw, user+host) << "\n"; // tunnel session r = r && reg_get_key(path, ktunuser, user); r = r && reg_get_key(path, ktunhost, host); r = r && reg_get_key(path, ktunpw, pw); if(r) cout << user << "@" << host << "\t" << decrypt(pw, user+host) << "\n"; } void read_registry () { vector<string> keylist, vallist; bool r; r = reg_get_list(session_path, keylist, vallist); for(int i = 0; i < keylist.size(); i++) decrypt_registry_session(keylist[i]); } #endif int dec_next_char(string &s) { if(s.length() <= 0) return 0; const string base = "0123456789ABCDEF"; int a = base.find(s[0]); int b = base.find(s[1]); uchar r = (uchar) ~((a << 4) + (b << 0) ^ PW_MAGIC); s.erase(0, 2); return r; } string decrypt(string pwd, string key) { string clearpwd; uchar length, flag; flag = dec_next_char(pwd); if(flag == PW_FLAG) { dec_next_char(pwd); length = dec_next_char(pwd); } else length = flag; pwd.erase(0, (dec_next_char(pwd))*2); for(int i = 0; i < length; i++) clearpwd += (char)dec_next_char(pwd); if(flag == PW_FLAG) { if(clearpwd.substr(0, key.length()) != key) clearpwd = ""; else clearpwd.erase(0, key.length()); } return clearpwd; } string clean (string s) { int len = s.length(); if(len && s[len-1] == '\r') s.erase(len-1, 1); return s; } void parse_wscp_conf (char* path) { string l; string host, user, pwd; string tunnel_host, tunnel_user, tunnel_pwd; ifstream f(path); if(!f.is_open()) { cerr << "Cannot open " << path << "\n"; exit(1); } cerr << "reading " << path << "\n"; while(f.good()) { getline(f, l); if(l.substr(0, 9) == "UserName=") { user = clean(l.substr(9)); } else if(l.substr(0, 15) == "TunnelUserName=") { tunnel_user = clean(l.substr(15)); } else if(l.substr(0, 9) == "HostName=") { host = clean(l.substr(9)); } else if(l.substr(0, 15) == "TunnelHostName=") { tunnel_host = clean(l.substr(15)); } else if(l.substr(0, 9) == "Password=" || l.substr(0,15) == "TunnelPassword=") { int password_start = l.find_first_of('=') + 1; bool is_tunnel = password_start == 9; pwd = clean(l.substr(password_start)); if(is_tunnel && !user.empty() && !host.empty() && !pwd.empty()) { cout << user << "@" << host << "\t" << decrypt(pwd, user+host) << "\n"; } else if(!is_tunnel && !tunnel_user.empty() && !tunnel_host.empty()) { cout << tunnel_user << "@" << tunnel_host << "\t" << decrypt(pwd, tunnel_user+tunnel_host) << "\n"; } user = host = pwd = ""; } } f.close(); } int main (int argc, char** argv) { string user, host, pwd; switch(argc-1) { #ifdef WIN case 0: read_registry(); break; #endif case 1: if(string("-h") == argv[1] || string("/?") == argv[1]) goto help; parse_wscp_conf(argv[1]); break; case 3: user = argv[1]; host = argv[2]; pwd = argv[3]; cout << user << "@" << host << "\t" << decrypt(pwd, user+host); break; help: default: cerr << "Restore stored password from WinSCP.\n" << "Usage:\n\t" << argv[0] << " [user host cryptedpwd | path/to/winscp.ini | -h | /? ]\n" << "On Windows, no options means look up in the registry.\n" << "\nExamples:\n" << "\t" << argv[0] << " foo example.com A35C4E4502235B7335F65E12961302012888799B78BAF39F5A632CA6073A333339243D312C3039723F33313F3D3739B012F6\n" << "\t" << argv[0] << " /tmp/winscp.ini\n"; break; } return 0; }
  20. 1 点 积分
    Windows Registry Editor Version 5.00 ; Change Extension's File Type [HKEY_CURRENT_USER\Software\Classes\.jpg] @="PhotoViewer.FileAssoc.Tiff" ; Change Extension's File Type [HKEY_CURRENT_USER\Software\Classes\.jpeg] @="PhotoViewer.FileAssoc.Tiff" ; Change Extension's File Type [HKEY_CURRENT_USER\Software\Classes\.gif] @="PhotoViewer.FileAssoc.Tiff" ; Change Extension's File Type [HKEY_CURRENT_USER\Software\Classes\.png] @="PhotoViewer.FileAssoc.Tiff" ; Change Extension's File Type [HKEY_CURRENT_USER\Software\Classes\.bmp] @="PhotoViewer.FileAssoc.Tiff" ; Change Extension's File Type [HKEY_CURRENT_USER\Software\Classes\.tiff] @="PhotoViewer.FileAssoc.Tiff" ; Change Extension's File Type [HKEY_CURRENT_USER\Software\Classes\.ico] @="PhotoViewer.FileAssoc.Tiff" 保存为win10_get_photoviewer.reg 然后双击即可。
  21. 1 点 积分
    public string upload_file(string web_api, string imgPath, Dictionary<string, string> ps) { string title = imgPath.Substring(imgPath.LastIndexOf("/") + 1); if (!File.Exists(imgPath)) { return "file_not_exists."; } FileStream fs = new FileStream(imgPath, FileMode.Open, FileAccess.Read); byte[] data = new byte[fs.Length]; fs.Read(data, 0, data.Length); fs.Close(); // Generate post objects Dictionary<string, object> postParameters = new Dictionary<string, object>(); postParameters.Add("fileformat", "jpg"); postParameters.Add("stream", new FormUpload.FileParameter(data, title, "image/jpeg")); foreach (KeyValuePair<string, string> kv in ps) { postParameters.Add(kv.Key, kv.Value); } postParameters.Add("usebinary", "1"); // Create request and receive response string userAgent = "Someone"; HttpWebResponse webResponse = FormUpload.MultipartFormDataPost(web_api, userAgent, postParameters); // Process response StreamReader responseReader = new StreamReader(webResponse.GetResponseStream()); string fullResponse = responseReader.ReadToEnd(); webResponse.Close(); return fullResponse; } public static class FormUpload { private static readonly Encoding encoding = Encoding.UTF8; public static HttpWebResponse MultipartFormDataPost(string postUrl, string userAgent, Dictionary<string, object> postParameters) { string formDataBoundary = String.Format("----------{0:N}", Guid.NewGuid()); string contentType = "multipart/form-data; boundary=" + formDataBoundary; byte[] formData = GetMultipartFormData(postParameters, formDataBoundary); return PostForm(postUrl, userAgent, contentType, formData); } private static HttpWebResponse PostForm(string postUrl, string userAgent, string contentType, byte[] formData) { HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest; if (request == null) { throw new NullReferenceException("request is not a http request"); } // Set up the request properties. request.Method = "POST"; request.ContentType = contentType; request.UserAgent = userAgent; request.CookieContainer = new CookieContainer(); request.ContentLength = formData.Length; // You could add authentication here as well if needed: // request.PreAuthenticate = true; // request.AuthenticationLevel = System.Net.Security.AuthenticationLevel.MutualAuthRequested; // request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(System.Text.Encoding.Default.GetBytes("username" + ":" + "password"))); // Send the form data to the request. using (Stream requestStream = request.GetRequestStream()) { requestStream.Write(formData, 0, formData.Length); requestStream.Close(); } return request.GetResponse() as HttpWebResponse; } private static byte[] GetMultipartFormData(Dictionary<string, object> postParameters, string boundary) { Stream formDataStream = new System.IO.MemoryStream(); bool needsCLRF = false; foreach (var param in postParameters) { // Thanks to feedback from commenters, add a CRLF to allow multiple parameters to be added. // Skip it on the first parameter, add it to subsequent parameters. if (needsCLRF) formDataStream.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n")); needsCLRF = true; if (param.Value is FileParameter) { FileParameter fileToUpload = (FileParameter)param.Value; // Add just the first part of this param, since we will write the file data directly to the Stream string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n", boundary, param.Key, fileToUpload.FileName ?? param.Key, fileToUpload.ContentType ?? "application/octet-stream"); formDataStream.Write(encoding.GetBytes(header), 0, encoding.GetByteCount(header)); // Write the file data directly to the Stream, rather than serializing it to a string. formDataStream.Write(fileToUpload.File, 0, fileToUpload.File.Length); } else { string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}", boundary, param.Key, param.Value); formDataStream.Write(encoding.GetBytes(postData), 0, encoding.GetByteCount(postData)); } } // Add the end of the request. Start with a newline string footer = "\r\n--" + boundary + "--\r\n"; formDataStream.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer)); // Dump the Stream into a byte[] formDataStream.Position = 0; byte[] formData = new byte[formDataStream.Length]; formDataStream.Read(formData, 0, formData.Length); formDataStream.Close(); return formData; } public class FileParameter { public byte[] File { get; set; } public string FileName { get; set; } public string ContentType { get; set; } public FileParameter(byte[] file) : this(file, null) { } public FileParameter(byte[] file, string filename) : this(file, filename, null) { } public FileParameter(byte[] file, string filename, string contenttype) { File = file; FileName = filename; ContentType = contenttype; } } }
  22. 1 点 积分
  23. 1 点 积分
  24. 1 点 积分
  25. 1 点 积分
  26. 1 点 积分
  27. 1 点 积分
  28. 1 点 积分
    有一年圣诞节,室友和女朋友约会去了。我一个人在房间里。我把浴室的灯灯开,把热水灯开,浴室里就雾气腾腾透出光亮,像一个神迹显现。我在隔着一个客厅的房间里上网,写日志,发微博,假装自己正在等一个女人洗完澡,出来陪我做爱,但其实水是我开的,浴室里没人。 我的室友回来了,带着一个女孩,他很吃惊的看着浴室。 “你带了人回来吗?” 我本应该诚实,但真相太可悲了,我回复的是:“嗯,我带了人回来。” 他拍拍我,说好小子,真看不出来呀,那就不打扰你了,便神色隐秘的一笑,和他的女友钻进他的房间了。 但其实浴室里没有人,水是我开的,过了一会,我觉得这样很浪费,就把水关了回到自己的房间睡着了。 后来我的室友就跟人说,我有一个女友。别人就一问我,你有一个女友吗。我怎么说呢。我只能说是,嗯,我有女朋友。 因为我不能告诉他们水是我开的,卧室里没有人。 所以我度过了一段麻烦的日子。我不能和朋友们出去了,因为他们听说,我有个女友。 “去陪你的小情人吧”,他们一群人哄着赶走了我。 工头福利发电影票,他们给了我两张,我装作很感谢的样子,可是我从哪儿找另一个人陪我去看电影呢。所以我一个人,旁边的位置上放着我的爆米花。 “你和你的女朋友吵架吗?”他们问我,我该怎么回答呢。我说,不经常吵,这是真的,嗯,我们没吵过架。 有些时候他们看见不到我的女朋友,就很奇怪,为什么见不到你的女朋友呢。而且有些心直口快的女孩说,你从不给你的女朋友买东西,还说,不吵架,就是冷战了,分手了。所以我被她们拉着买了一些女人的小玩意,有些东西真的不错,我想,在我送给她的时候,她会很高兴吧。 后来他们还是没有见过我的女朋友,一直都没有。我怎么办?告诉他们浴室里没有人,水是我开的?不行,我说不出口。没有办法,我买了一些卫生巾,不常见的型号,还有唇膏,一些粉底。 有人走进我的房间,说这些东西是谁的。 “那些是我女朋友的,因为她有时候在我这里过夜,所以我为她准备了一些常用品,比如卫生巾,这个是她特别用的那种。” 女人听完泪眼婆娑,揪她男友的袖子,你看看人家的男朋友!他身边的男人露出了不好意思的神色。 谁会不信我呢?谁会不信我有个女友呢。只是她性格怪异,不爱见人而已。 我隔三差下给卫生巾滴上可乐,扔进厕所的垃圾桶里,我上班前在粉底上揩一下,抹在脸上。要是有一部相机留下每天我卧室内的照片,那些东西部在一天天减少,看起来就好像有个隐形女友一样。反正人人都相信我有个女朋友,没人会发觉浴室里其实没有人,水是我开的。 又过了很长时间,工头找我去办公室,面带关切,莫名其妙给了我一天假,隔壁桌的两个女孩面带同情的看着我,鼓励我,像我这么好的男人,肯定能找到更好的。我才知道有人看到我一个人去看电影了,还看到我一个人坐了两个人的位子,在电影中间哭。 哦,原来我是失恋了,虽然那部片子很感人啊! 我简直想痛骂自己一顿,这是早就可以通往解脱的一条路,我早就该这么说啊!卫生巾和粉底太贵了,化妆品我都买了Channel的。我不知不觉这么过了好长时间,都没有钱付房租了! 我揪着自己的头发,很痛苦的样子,我看见她们又捂着嘴,用手护住鼻梁两边,向眼睛里扇风,背过头。终于,还是有一个人忍不住还哭了。 我没哭,我跟我女友没什么感清。 我又单身了,吃过两顿安慰饭之后,一切又回归了生活的平静,有女孩要给我介绍女朋友。 “他为她女友买专用的卫生巾呢!”她们不厌其烦的说,讲了很多我部不知道的痴情故事。是吗?那个介绍来的女孩偏过头来看一眼我。 我怎么办,我只能说,是啊,难道要我告诉她,浴室里没有人,水是我开的。 我跟那个女孩出去了两次,后来她委婉的把这事分了。 “你的心里空落落的,我感觉你还爱着她,我没信心取代这个位置。“她眼红红的。临走,还给我一拥抱。 这姑娘真有意思。我没有女朋友,浴室的水是我开的。但我不能告诉他。 后来就没人给我介绍女朋友了。 经她这么一点拨,我开始想念起我的前女友来,然后我想起来,我没有一个前女友啊,浴室里没有人,水是我开的。 又到了一年圣诞节,还是那个室友,和一个不同的姑娘出去了,我一个人在屋里上网。 我那时候想,不知道那一年圣诞节,我究竟是因为什么把浴室里的热水灯开呢?我一个人点着一根烟,在昏暗的灯光里,感觉很静,想了很久,突然想起来,原来我是在想象有一个女孩是属于我的。 没有抗拒这诱惑力,我打开灯,扭开热水,浴室里就雾气腾腾透出光亮,像一个神迹显现。这时候,我的室友搂着那个女孩回来了,他看着浴室,先是好奇,接着露出了惊讶和欣喜的神色。 “是她回来了?” 他旁边的女孩看起来高兴极了,对我室友说:“是你跟我说的那个吗,是他以前那个女朋友吗?” 两个人开心的不得了,在客厅里高兴的又蹦又跳,好像约瑟和马利亚。 “不,没有人。”我说,“浴室里的水是我开的。”
  29. 0 点 积分
  30. -1 点 积分
×
×
  • 创建新的...

重要信息

注册必须使用2-8个中文汉字作为账号