htpidk 发表于 2020-7-18 15:39

简单版小说搜索阅读(64位程序)

本帖最后由 htpidk 于 2020-7-18 15:48 编辑

今天发现之前写的一个64位小说搜索与阅读程序,代码写的比较挫,不过把写的过程中遇到的一些坑注释出来了,大家以后可以避免这种情况,程序用到了miniblink(github上找的到)和我自己写的一个SDK的界面库,也不算界面库,只是简单的封装了12种常用的组件

#include "xiaoshuo.h"
#include <regex>
HWND xswnd;

#import "C:\\Windows\\SysWOW64\\winhttpcom.dll" no_namespace

IWinHttpRequest* pwin=NULL;
Sedit g_edt,g_jianjieedt,g_textedt;
Slistbox g_pianzhanglist;
char** pppianzhang;//存放文章的篇章标题char*数组
char** pplianjie;//存放文章的篇章链接char*数组
char* wenzhangzhengwen;//文章正文
int wenzhangzhengwenlen;//文章正文长度
wkeWebView miniblinkwindow;//miniblink网页句柄
LRESULT __stdcall webproc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp);//miniblink网页窗口消息子类化过程
LONG_PTR webbackcall;


void xianshi();//显示小说正文
void freelease();//销毁IWinHttpRequest对象

void createhtml(int xuhao){
      WIN32_FIND_DATAFindFileData;
      HANDLE hFind = FindFirstFile(g_edt.getbt(),&FindFileData);
      if ((hFind=INVALID_HANDLE_VALUE) || !(FindFileData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)){
                CreateDirectory(g_edt.getbt(),NULL);
      }
      FindClose(hFind);
      char xuhaobuffer={0};
      std::string name=g_edt.getbt();
      name=name+"\\";
      sprintf(xuhaobuffer,"%d",xuhao);
      name=name+xuhaobuffer+".html";
      //MessageBox(NULL,name.c_str(),"bt",MB_OK);
      FILE* ceshi=fopen(name.c_str(),"r");
      if(ceshi==NULL){
                FILE* hf=fopen(name.c_str(),"wb+");
                fwrite(wenzhangzhengwen,wenzhangzhengwenlen,1,hf);
                fclose(hf);
      }else
                fclose(ceshi);
      char directory={0};
      GetCurrentDirectory(100,directory);
      std::string directorystring=directory;
      directorystring=directorystring+"\\"+name.c_str();

      char* lujing=const_cast<char*>(directorystring.c_str());//文件路径
      wchar_t wlujing={0};
      MultiByteToWideChar(CP_ACP,0,lujing,-1,wlujing,100);
      //MessageBoxW(NULL,wlujing,L"d",MB_OK);
      wkeLoadFileW(miniblinkwindow,wlujing);//wkeLoadFile不能正常加载路径有汉字的网页,只能用W版函数
}

void sousuo(){
      if(strcmp("",g_edt.getbt())==0){
                MessageBox(NULL,"请输入要搜索的文章名称","bt",MB_OK);
                return;
      }
      g_pianzhanglist.deleteallstring();
      std::string wenzhangname=g_edt.getbt();
      wenzhangname="https://www.biduo.cc/search.php?q="+wenzhangname;

      pwin->Open("GET",wenzhangname.c_str());//这个网站首页是GBK,搜索页是UTF8编码,坑
      pwin->Send();
      _variant_t xstext=pwin->ResponseBody;
      char* text=(char*)(xstext.parray->pvData);
      //char* hh=(char*)(pwin->ResponseBody.parray->pvData);
      int len=pwin->ResponseBody.parray->rgsabound.cElements;
      //char haha={0};
      //sprintf(haha,"%d",len);
      //MessageBox(NULL,haha,"bt",MB_OK);
      int widelen=MultiByteToWideChar(CP_UTF8,0,text,len,NULL,NULL);
      wchar_t* pwtext=new wchar_t;
      ZeroMemory(pwtext,2*(widelen+1));
      MultiByteToWideChar(CP_UTF8,0,text,len,pwtext,widelen);
      int ansilen=WideCharToMultiByte(CP_ACP,0,pwtext,widelen,NULL,NULL,NULL,FALSE);
      char* ptext=new char;
      ZeroMemory(ptext,ansilen+1);
      WideCharToMultiByte(CP_ACP,0,pwtext,widelen,ptext,ansilen,NULL,FALSE);
      delete[] pwtext;

      std::regex jianjiepipei("<p class=\"result-game-item-desc\">(.*?)</p>");//匹配小说简介
      std::cmatch m;
      std::regex_search((const char*)ptext,(const char*)(ptext+ansilen),m,jianjiepipei);//不需要用循环反复匹配,只匹配第一个就行
      if(strcmp("",const_cast<char*>(m.str(1).c_str()))==0){
                MessageBox(NULL,"没有找到此本小说","bt",MB_OK);
                return;
      }
      g_jianjieedt.setbt(const_cast<char*>(m.str(1).c_str()));


      std::regex lianjiepipei("<a cpos=\"title\" href=\"(.*?)\" title=\"");//匹配搜索到的小说链接
      std::cmatch m2;
      std::regex_search((const char*)ptext,(const char*)(ptext+ansilen),m2,lianjiepipei);//不需要用循环反复匹配,只匹配第一个就行
      
      std::string lianjie=m2.str(1).c_str();
      lianjie="https://www.biduo.cc"+lianjie;//这个网页是GBK编码
      pwin->Open("GET",lianjie.c_str());
      pwin->Send();
      _variant_t pianzhang=pwin->ResponseBody;
      char* pianzhangtext=(char*)pianzhang.parray->pvData;
      int pianzhanglen=pianzhang.parray->rgsabound.cElements;

      std::regex pianzhangpipei("<a href=\"(.*?)\">(.*?)</a>");//匹配小说的篇章名字和对应的链接
      std::cmatch m3;
      int i=0;
      char* kaishi=pianzhangtext;
      std::regex_search((const char*)kaishi,(const char*)(pianzhangtext+pianzhanglen),m3,pianzhangpipei);
      while(std::regex_search((const char*)kaishi,(const char*)(pianzhangtext+pianzhanglen),m3,pianzhangpipei)){
                //pplianjie=const_cast<char*>(m3.str(1).c_str());
                //pppianzhang=const_cast<char*>(m3.str(2).c_str());
                /*
                不能这样赋值,经过反汇编查看,m3.str(1)和m3.str(2)生成的是一个string临时对象,这个对象在调用完c_str()就调用析构函数
                销毁了,导致c_str()返回的字符串指向了乱码,string类对象c_str()返回的字符串指针是直接指向内部数据的,不是new几个char内存
                来存放的,string类对象改变后,原来用c_str()返回的字符串指针指向的内容也会改变

                60:               pplianjie=const_cast<char*>(m3.str(1).c_str());
                000000013FC13486 41 B8 01 00 00 00    mov         r8d,1
                000000013FC1348C 48 8D 94 24 C0 00 00 00 lea         rdx,
                000000013FC13494 48 8D 8C 24 50 01 00 00 lea         rcx,
                000000013FC1349C E8 AF 08 00 00       call      std::tr1::match_results<char const * __ptr64,std::allocator<std::tr1::sub_match<char const * __ptr64> > >::str (13FC13D50h)
                000000013FC134A1 48 89 84 24 58 04 00 00 mov         qword ptr ,rax
                000000013FC134A9 48 8B 8C 24 58 04 00 00 mov         rcx,qword ptr
                000000013FC134B1 E8 7A 06 00 00       call      std::basic_string<char,std::char_traits<char>,std::allocator<char> >::c_str (13FC13B30h)
                000000013FC134B6 48 63 8C 24 40 01 00 00 movsxd      rcx,dword ptr
                000000013FC134BE 48 8B 15 B3 A5 02 00 mov         rdx,qword ptr
                000000013FC134C5 48 89 04 CA          mov         qword ptr ,rax
                000000013FC134C9 48 8D 8C 24 C0 00 00 00 lea         rcx,
                000000013FC134D1 E8 2A 06 00 00       call      std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (13FC13B00h)
                */
                char* lianjie=new char;
                ZeroMemory(lianjie,50);
                strcpy(lianjie,m3.str(1).c_str());//m3.str(1).c_str()在这句命令后,m3.str(1)生成的临时string对象就销毁了,不过无所谓了,复制到申请的内存里了
                if(pplianjie!=NULL){
                        delete pplianjie;
                        pplianjie=0;
                        //删除之前申请的内存再进行下面的赋值
                }
                pplianjie=lianjie;
                g_pianzhanglist.insertstring(i,const_cast<char*>(m3.str(2).c_str()));//显示在列表框里后,m3.str(2)生成的临时string对象就销毁了,不过无所谓了,目的达到了,显示在列表框里就行
                i++;
                kaishi=(char*)m3.suffix().first;

      }
}

void xianshi(){
      if(g_pianzhanglist.getcount()==0){
                return;
      }
      int currentselect=g_pianzhanglist.getcurrentselect();
      char* lianjie=pplianjie;
      std::string wangzhan="https://www.biduo.cc";
      std::string wzlianjie=wangzhan+lianjie;
      pwin->Open("GET",wzlianjie.c_str());
      pwin->Send();
      _variant_t nr=pwin->ResponseBody;
      wenzhangzhengwen=(char*)(nr.parray->pvData);
      wenzhangzhengwenlen=nr.parray->rgsabound.cElements;
      //g_textedt.setbt(nnr);
      createhtml(currentselect);
}

int WINAPI WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in LPSTR lpCmdLine, __in int nShowCmd ){
      Swindow wnd(hInstance,"classname","小说阅读",50,50,1500,800,NULL,&xswnd);
      Sedit edt(hInstance,xswnd,50,20,300,25,1001,NULL);//用来输入搜索的小说名字
      edt.setfont("四号",FALSE,"宋体");
      g_edt=edt;
      HANDLE jb=LoadImage(hInstance,MAKEINTRESOURCE(IDI_ICON1),IMAGE_ICON,32,32,LR_DEFAULTCOLOR);
      SendMessage(xswnd,WM_SETICON,ICON_SMALL,(LPARAM)jb);

      Sbutton btn(hInstance,xswnd,"搜索",360,20,100,25,1002,NULL);
      btn.setfont("四号",FALSE,"宋体");
      btn.ButtonClick(sousuo);

      Sedit jianjieedt(hInstance,xswnd,50,50,1400,50,1003,NULL);//用来放小说的简介
      jianjieedt.setfont("四号",FALSE,"宋体");
      g_jianjieedt=jianjieedt;

      Slistbox pianzhanglist(hInstance,xswnd,50,120,400,650,1004,NULL);//用来放小说的篇章
      pianzhanglist.setfont("四号",FALSE,"宋体");
      pianzhanglist.selectchange(xianshi);
      g_pianzhanglist=pianzhanglist;

      wkeSetWkeDllPath(L"miniblink_x64.dll");
      wkeInit();
      miniblinkwindow=wkeCreateWebWindow(WKE_WINDOW_TYPE_CONTROL, xswnd, 460, 120, 1000, 640);
      wkeLoadURL(miniblinkwindow, "www.baidu.com");
      wkeShowWindow(miniblinkwindow, TRUE);
      HWND webwindow=FindWindowEx(xswnd,0,"wkeWebWindow","wkeWebWindow");//窗口句柄不是上面的miniblinkwindow,miniblinkwindow是一个结构体的指针
      webbackcall=SetWindowLongPtr(webwindow,GWLP_WNDPROC,reinterpret_cast<LONG_PTR>(webproc));


      pplianjie=new char*;//存放篇章对应的链接
      ZeroMemory(pplianjie,8*8000);//64位程序,指针长度8个字节


      CoInitialize(NULL);
      CoCreateInstance(__uuidof(WinHttpRequest),NULL,CLSCTX_INPROC_SERVER,__uuidof(IWinHttpRequest),(LPVOID*)&pwin);

      wnd.WillDestroy(freelease);
      wnd.SEnd();
      return 0;
}

void freelease(){
      pwin->Release();
      CoUninitialize();
}

LRESULT __stdcall webproc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp){
      if(msg==WM_KEYDOWN){
                if(wp==VK_RIGHT){
                        if(g_pianzhanglist.getcurrentselect()<g_pianzhanglist.getcount()-1){
                              g_pianzhanglist.selectorcancelsome(g_pianzhanglist.getcurrentselect(),FALSE);
                              g_pianzhanglist.selectorcancelsome(g_pianzhanglist.getcurrentselect()+1,TRUE);
                              xianshi();
                        }else
                              MessageBox(NULL,"已经到了最后一章","bt",MB_OK);

                }else if(wp==VK_LEFT){
                        if(g_pianzhanglist.getcurrentselect()>0){
                              g_pianzhanglist.selectorcancelsome(g_pianzhanglist.getcurrentselect(),FALSE);
                              g_pianzhanglist.selectorcancelsome(g_pianzhanglist.getcurrentselect()-1,TRUE);
                              xianshi();
                        }else
                              MessageBox(NULL,"已经是第一章","bt",MB_OK);
                }
      }
      return CallWindowProc(reinterpret_cast<WNDPROC>(webbackcall),hwnd,msg,wp,lp);
}

goldli 发表于 2020-7-18 15:47

C++ ,哈哈。用这个写小说搜索程序,有劲。

quzhaojia 发表于 2020-7-18 16:47

我要做伸手党。。

zhaoya_n 发表于 2020-7-18 17:41

阅读达人

sktter 发表于 2020-7-21 16:42

可以把界面优化一下还是不错的

flyfishlll 发表于 2020-7-22 09:53

佩服 C++写这个不累吗??
页: [1]
查看完整版本: 简单版小说搜索阅读(64位程序)