From 4220083ac30ee4f45550241a9ad0a1a44e19c779 Mon Sep 17 00:00:00 2001 From: Mike Solar Date: Thu, 3 Aug 2023 16:16:02 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=AF=BC=E8=88=AA=E6=A0=8F?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OfficeAssistant_msvc.VC.db | Bin 86728704 -> 86728704 bytes OfficeAssistant_msvc/MyButton.cpp | 173 +-- OfficeAssistant_msvc/MyButton.h | 137 +- .../OfficeAssistant_msvc.vcxproj | 288 ++--- .../OfficeAssistant_msvc.vcxproj.filters | 262 ++-- .../OfficeAssistant_msvc.vcxproj.user | 24 +- OfficeAssistant_msvc/navbar.cpp | 487 +++---- OfficeAssistant_msvc/netio.cpp | 1118 +++++++++-------- OfficeAssistant_msvc/netio.h | 229 ++-- 9 files changed, 1393 insertions(+), 1325 deletions(-) diff --git a/OfficeAssistant_msvc.VC.db b/OfficeAssistant_msvc.VC.db index afee1567e575a6cfcff58cb3c937e7b027ae253e..9cbee02ec20b12391261d1295a326a3926af3d6c 100644 GIT binary patch delta 36394 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 delta 33468 zcmce;cU%-#^!Gn^=I-unUyzOk1O*ip>cpMMcFZAjOhcz^K?)MIB?J7aK7a z#JVZ!*vk?XjV-aGCN}KGM2&gQnT34w%k%tRujh~7>xZ8A`OLX@?v$N+=Fa3F+TJK1 zY>Bt)9*#@c$8j-dIF4_}aaX#^0oHtO!=*@=XNKdfqPEssI=tV%;e0h zw2V=y<8snGw!0Li)N`rdx?M;s_wBWWMxG-wN2VpG=cbL%Ngk1r+poO z=CCHJ7Bt$uR*}wUCrN_e?7IyHlvr> zT;wDBso$=?f4;}4qMjf_3YtA_rY*{rW7Pxf%k`TAcAu0(^FFu}GsmKHzf>EBXtxXOj6*KJYZs>?jD7NojeRpI9L9_^jmySE>g zIwiBq>Mac=vR-hNW_DHiYTCK9)3vMBPTJB{^+3lx8nUpxKMBP78YWc ziHAWPRY7mG^7Qsu{ml$1^^+CuMsd_;h=giGBUf+nmL{0)y4yN;Q*{=Il{s~pMcfOQ z_fUbU!8EqzJ;cWODy8MZqo+hLt?lS3U6;0WH*L(>d=BYu^3t!ozOHope4}J3P0%-# z<_Y?j(y;SZbq8wWS;F}rlnah3AG8umSQ5bQAgUsLxQIeTfGeycfq6< zjDmXk-}+^oM!mw-7FlBX-R|C0h|i5l%bk>&{Ymo)IXUB+jZvLhpxIX#Kfwvi8LSqV z3z(}deu7)sVyd~w(Y-47a~i$=5wBPA+PMbJh?P$*9=5j{_csDh-3p)T-N8J-JZ(?) zUO%`BUV>H%@A4{8y6Efmr&PFjriXNb&r+=iq zwZc%l52?R*Q0>8l&eD{IvF9sXRBZ{*LJkI!ddzz21FvS`@7_=wBwhk{DnERYlh9A=TEd# zLn)5g=Bj5%3zcgApfZ;aQ>&Q}jENBvo)2ybi)r0NRY!{5-q%ekzSW+x*)Z%W?HHnR zVoUCKBwF_D?>E#8%Lgm4tMUWWpJ7C12|CQXFvCxsp^6SxVFzUuvJ_aeY8D59KsNdN zK+;?154B--2^T1xnHJ92@!m4gG|j`yr6HS@N+COd!-TfuDBVxl_gSyz!0n zXQ9x7-PScAI#vgMgdMEzUnZ4SnmbhG!=6ukOg*LWDP9)IC%le_GQUnJouwhO1rrd&$G&9V5;u{4-tX*kCcFvk)&$I@tyrSTj~lR1{4IhLk#EY0Rvn$NKW&#{E; zv$S})-qJNWdQf7Igl=6Tn{|zgqwl0YceUu^G@xf<*B%l55))%%l<-qq@7*nOm(VQH zo>+LaYfG?JV6DO0fVBl{2i6{}16W6}PGF&6ox#Gu!oj-Oj&_ZRA8OEEG@dlJG!z*$ zx=}Wt;)pKLM%uB5=PZ5r*QYHI7U zDI$+oyBzQKteeKsHaj!2iq}bXH%I7fmdz2HNIP8>S5MEY3kpnyQQ!&8m2V@MD|hnq z(Wn>n{}6_mUG!!fE2wvghOpv{D&8WMZi(olc9{@4`;k8jfhmMYPyLCBRkY|YH1jkK z;qt3nR+iTlTYi3}b}K2>M7&wb#{}xeDpH(aYd#C(8rj*u6R3w*fm>nZe@25Tul)U- z`Cp4-QYyEg1!7@uNxv;(u5@yHL@lXgTf`!1bZJB_&C#f5-@bb;NCl-4pL!Ko3VT#H z>DL67(G%z7S!wKeLAtX&qN`MAOGI0|oG8XhT5Un|wou8tKtHz=28dYT9RPv#@Ovri zojMl4;(3Ys|9ia`zAudc>k1YL)(tEQtUFi_u%2MOz} zmLSe}tf8V-5X%RkxBav*;lQ&XSgN2=Im461<1;||I^=YaZlkg@$BT#Y$fj51uB^iS zQ~QD?g7pLI4>ka7AlM+V!C*tchJpVx%-^!4@LdKbM>TU$!m=^jb7e%b@ly5Jm7+jmaspJ~W% zQftrjU+AzO^lJ9!^}GBlUf-ELy>XXsTNvh@4mK9-6R>e$+SJ%o&*WlTeI)A}9kEK0XR`A3EyW{ejgL6z;Vs0%b7!)^ zCV*vw<$&da<$+BEn*=r)Yzo+?V4vB}otgUhw;BFMk@8xeR{HB5;*P)0A#VF?9paX6 zu|wPpIO-5L0(v>b^?;rZam{zNL;MnO#36q6UF8s00}eaH75_&LaXH|SLtLt#@S{Ur z43Hh-C-+c?xZqpl5a<1gLsSHGcZhR-?;YZ-{{x3Ohj0z(;}9+Zy$g@+p9VG^YzA09SOM5fu+PC} zfz1Y+16Bw&7i=Ebe6R&z3&9qFEe5lKEdg5!whXKYY&qBpu$8uB`=#(#`S8di!;R;)RzY6RNu+?B+f_(+H25c=D z11knw2euw;1K38eO<*NpUxRH1`vzBM;6e zW|L4y7?GJVDt&abF=A4-ZAaQcrg6HKdk*l^xPV_ANVnb5)w zOV5K{ux(iS)7Byv`{$}@oU`C3+Gm2$q9~AtH@H}zwf)_`SvWUML)q}o4V{;F_DVBYq2C2T(MXZ4ekrEqz|}dVo5J>3&fJ1;AV*>J-|&9OQOI{6id2+%M?o@!Hp41 zBEY4JC0)P`7E8jp864kNEa?n`eZ-PbaNWd`j(BS!miINqaFfLHcyL)_c^tTOu{;Lc zaIw4(xFKSBPjHE1c@J>WVtIFPQDS*FaA9J3B)E2Bc~@{DVtE9(#$tIFaDHNW7`WPE zd1tsCZ2Iw!4xJU)E9?1aZg} z$!FIq5658P=AEy=UW2^>`yK2p*dJhjg1rNK5B34A54uMC9e>W{QH7&=1!BFe$#z-yVGV0Q6qk>ahJb4tf^O>ht%4 zS$&8V48bGd_IFkviclfc2n|9+Xc2IRo7G2;Fc5iGA0s*4mpo-L#YXa2c&ocBcUos8 zeY6&Rf6kJZo(#Kzr(r#((y~=sjHGuxJODs=ylAh)*~v>6?YI9Y_6v)Cy@7aJ>ufa= zfC*tnSP)JKXGAT83&IuQhHyuCAUqLX2yaAfL>)w3L_LHL!WU5=;fL@?G(a>Ya-FRK zWJy~=buyWiRR$1WH(JiQWu#6V4iS)glwx@+`8O!s^H#4<;PjcP=_AE_cWcQnfkZC( zr4iXOlefpo3Bwwb#=K`vZg$>?TxX$yFg`UsBWFZ*T3QAiXzj_?70HbWpa~*~$SabY zl8xcypxmLjDLH6@dlv2o_Mx;X*~PByUr+Sf?2%&mEL>;SBRiTBKr=*hL@*)*(E`yD z(F)NT(FV~L(GJlb(E-sB(TT`Mc7&4i%lM?R@`{Mg#4tm6ud~P-4|gWJG*s6B?i~l8 z?o5Vz8b9TVMx>oi~Me!Yob0~IzIDuj-hyy6T2C)alI`a%Ww-uEYLhC`yY6ap85TEY? zu>?gKh(Z*lAf|&TxBwy#MTK%kXaz?;^%QO}M9Skq#G{A-(E~*v5Md~Kf@p)H2Z*L9 zx~ZpVIDb@OR<}731ke=`iRgxiLUc#;K=efPLi9$!p6fOz8WDqtMZ_WE5ebOCh(ts` zBD>A$PgeJl{IC6H5yX}n$@kiCwXByf^e2D;h=D}Dd|?o27ogKU=X7w`)46?b^>{ak z00tw5Acm419`A;c%O?FbO{MlX?H27Aou9U`+^`~v)Dy^XcGDNKXH5H35;2&(!Zcn6 zuZ+~@Qd4PhG~3zc5_R{|tSY6~TgIeLj7ZIPRlCA}+?g6li-$7#qNm`_WEl4p$&zko z2_CHYViIxFncGf>O0A^D@&6NbHibrOL(QSpC1Y9YmkoIjX1SC^Dh;9!adQ`VAzWJA zm%W(zoOfsB=Oj|s9Njp&AsC*mJ4uTZSf}(9;>kjq&%)N9hgCsv|lryM663b+NemH}tO$hOI!=RCewLj8BfRGi@)?01C@8NRrET zxHG>iNkoQJ$>K;hq3~DUUH%IKpAZ&(If=Ao4CYABte{(%LoJYtG>48!OCQ}%THK8- zy^&8`*?lPUFn2O{(snX+nv^~=H%waGgB7QyK$#zu)iZ^;g=xcF!^UNfPS^W!Ebdwo zY0kFXN+M3|n_rU1RG#~m&49s1G8Tn4;9|rhn?6bE0M!{exZInoN8|gAWX@r>_of zOD6vF$oF!C)+yw9V{%h=OGzQ&lyqSOMy8Mfq$S${K3I?z^GY&St64RI{@lu2^k%(b z(K@hBX(^;5ag`^7FX1)4TJ~xV#u|)CAzjqH`dNDU^kU;+AXF0-64expmBCP$I;w{y zs%{i}0|V_e;Q`@(V5}AV!W~TEk(O}J@NsFW6FW+aYq7teiYHqEMegPf0Ui9nsy7Me z>P_MzZW!tgoh=F=68BB}xB=CR*hQVMZz~?`MOjRtn)Yf!~g8G33;sP zg(Om+U5D^IYEp4NYjLm9YPv{P5sgI~Qel<-U`i$KMo5=(Yq6Xv5p=&#iX$_fe+ZS+eTc&NM9h z3r6*FQt>_(qN+_)Bhx0P$4OQ#TiQPWa)}G{sidj%+RohC5DtkqEMby0Xzieb)Kv~O zrV^%aF<0xy)#mdG!MXBzbHJJSyxD4j@O<7%hg*S8@MsQY8a{6xGkL-sk@?of-~q#l z+}LvjIa&tyP}XOsM-aeBB0oEwMqC?G!oT5c&&#CMM9M!utUtS1(UxfS3(Q&Oe&#;r zuI8??;bj_GuN9JnmGaK_X(V5$2WRmf#^upscMxI5<<4T1Cgcti#w6Oo0OfXGJV zAaW6Th>3_vh{=d4M2@TXDG7hclbvjt(`TfKbLchUJ!i>D%Z(jA7VjWKE3D_B05BCX z4KW=t1Cfs?K+GiaIj7Ibj(R-bn&pRlPTsLavo;fxb#9B#31AjtHewE@UU_R^aVa&Fma+N+KIQB+~z?P)=;}sOJ*#A_2F!c9H4X zxl_81OV3J38(m8X5F%moACZ;-yJuQXuIl7`{b$@B_Vo*i__2LJj~NU9Q)2F{~H&pBUEb^q&~k3;a(E>$x~$x_@SEf%TJ@5&^72e1TX^0D? z8aKpi)=_ZXt6n}p@5bF4={Ftj@D{)zzBAl4!nq8PD`$WFW0lTxA{K0aM6 zYt5whZTJ?}w|mwTzy`!d#3n=u;%mfa#5Y8KyJrhA{y@HBs;sT#D6<2n%8?VclC1`E zhdrORm8{Wq&CHt8H7`3SGh6cQ-N{2Gu6HwCXEIdsAjQ@*)3*}9HpF&BDUr`i-$9Or z=ocI38w-q+jhTkothmyJ_}dOy^tnWCwQC1?BnlE4Bm4fa1I~Wz?z=&duve}3`x`S_ z)@A#55I`AXCt??3H<6d^-$V9pBxQ1s)V<^w6@K7WGxMmuWPz9ZFU}Wsu3XW630I;b z%jcrB?tuz`eFz)kTf}#W?-4&B_9G4udC#bWtfhUDd@<%sMR9Hd-F zr{yMh$<579AMOa=auFH{|IeUGZfl*s>>vTih(n0OM4rCv2zmXf^MeR;G4GO>uGxOk zaj&OgX8tJL-ZA4*c+6@%Mr39@PLkj9et)l3ogfW)-$imDh|xm(809f2Wd9To$v?$I z?oaWx>lqaf8AQcH0#WghKa@|2Cy0qa_7o$SJXJj8P8AQSQ^iB(RPm5FRXpTP6%T1s z#Y5Iq@sKoCJmgFj4=Gc{L&j9`kT6yJrTRZA9A=Wq_$8zI6eA&O~k zza|~!NML`W7Al2H!XbI>o!2Cjh~rXoa*|cczGN-K{Dcr|)ZNzv@CNZa;w_P*?*2i% zjJ!}w9{&6fatJO*o-qHHe~?p61Ru_bX;Dldy5VW4dSKYve+}4A;{bDi^#=(ys&{Z+ zHDfHaCPEDGCy^6hy(49Ph!0bRzb89+)d{J%qHkUKDh$E7bzsDMl0iu{I~nz!v~&}* zIJXg*nc3pjAt3b*IlyY^{+<9nApSypMEp$_Si18d2!cll2#Qc4)Cdhilf!sa3o)`;_YVAanM-Xr1!xFtdRe zt%+q>M8`L?W`u!rMazBTVq>GTiAp%TS;GbSMEPOS$O0CO062W7X<|HvgXS` zeu&Prj^n!37U7PRo>!gNXU*Ca$O9T78Y7w@f)Gs+%@EBI!H5t<3q(sqD@1EV8$??~ zJ4Aa#2Si6iCqyWsGa?KT&dXVwy6{i_!c3;`=y6%;;5syef^hG2h`XTxw1|S9^1|bF` zh9HI_h9Qy=$-Mkll>)c&eCS#EL$?(EsJaXEvdT`)&CE{DO&zUz_SE!%YmuIjm6wa% zul`l=5DGkN3UKd%%v)MET#o*HFggXE{4oPKouHo4d2w6{zc?-xY&h5m{$SilK6(im zFUQ;-$#>FI<5TV`Tl{z=e_kWDm+?%?;+~A;y{!d6KpHO>JQ>A*I*Y84KV*&OpQ?nN zq*$(+IGUeJg2suR=E2%7%TCM9%g*SZ3d5h_ZlF&!}jk&h@q%tU;Sn8nMd zHqPeFYuzSfsQW?!6VLv*$|hu_<*HY7w^l{W;pM7`Lf(BlE#W(IlFyQ@K_cIeUm~c5 z2)Xm~LLSm4t6voIw}|sjuGU1n>==_idQ5UwJ9U@e*@9Pvd_b)#&gEYPA#K!MUR#et z31BW_9%4RX0b(Iy5n?gIidceJidcpyLM-RyBaez-$s6<}gXIie$q!~f zc6~-H>;`CGp(*EMCBs(o012@Q@daWv;!DI=h&70{2!<#|tV66vY(Q*8Y(kVEzD8_D ze1q76*oxSO*p4Vg>_C(ub|Q8mb|dy6_9FHnY>00W-yyz7{D9bxIDj~akP(LvhY?2* zM-j&m#}OwGClRL*rxA8UIpRme8D1vC&hnq%W8uV3+*lk?Ef;q=#}6{Fq-E<#Ef3i6 z@oEy&4sc)7b7b<^oXiX{^orF#<{S^GK%7ThK>UQbh`5BfjJSfhiuf7v3*s8$I^qW6 zCNKNP+~Qq-H%*U*oZf)+jFFj>R41-jyGP#U0e29UyxcwVF8{*DOI6#y!P8lgdm2rWW~&?5{8Seaq{O$al>f^b4OBWfXB1Uam~tKd78m0oZa zJmks17kYj6xMU4oh{v8hYwk_BJ<7f5hHyuCAmEli_of%Z8&Mlk2T>PM58;FGMbt<5 zA^Z^y5DgIlh(JNkz1c|c?!((VT9-C%EC8Ayf)Gs+%@EBI!H5t+UfQ^Yu)UH`in4|q zTMB?yh}MWUf*fvaE5!MFr{#*nN^vQs=S)f$llnnEP(K~+`XFlE+N`YrXoqNz=z!=b z$XlCr68aZtgilFhI9N%+DeiscA!VI}b3_W!3Wvu0iPtiiOsQJ)IDth|Y*GL^z@g zA_CDB5sB!Ah(dHn^g#4P^g{GT^g%=;Vi2*2I7GZ4N9;)uI(+8_`K+4%m50f>Quylng+A$ulmqw?b9a34{XL!=!}s$T5)i$TH;dDn#Q z)Qi|)|5!-a->(M=>bgG$L@OOnG-m^jJH%=KnGSKvUtpcz3=*0&^mp`R(H!yp(NT2R z?-PeO6tK}DWWT?d6)LClzF)DIAc9CNtM~gL!PCXp=BTpFcb`Kn@!ie(Kv53wyPq8f zF_rh{SlC;r+_2%7jyj+Cu6KwrzF#{;np>_zjP(1!rbFd#8oI|iBJs{Q93s}edTC;u z&N(8{?tSFwKL!aODDNI)?fusv0WcUb1Thpb43UILMx-E85yKH95F-(3h*5~qh%tzC z#8|{9h;fMVhzvv~A`3AAk&Vbf|-w;Utns$jc~|9kZ@Z#l7%*zBGiR$f`Rcu?$g!SPttZ zZ-wCA#?PLt?5c3G6YV`}r0N885P`i`iN;xHZ(Sh(Rtoa$t&%YHo?0-G5dMm+S+Yu) zM@0S#|A&@o$4FUaqiV~0maY;86TN0Ir%%m;js;0Wte!=y1lhCb3*qBJ5+Hl{tQL+D zH%>Y6l|FR1!w$Dee(Aefa3?|7jYX)hbYpRp%yYQ$LNiX)Owsm6!a%5CFJ!I#Rtt^X zpsxpZDjDilU2V8T=<5Ow z`m@A?9YN}f9THwoolc^3v{l*{w!U=xk6tTa3<*M0uGij zY;o{vVR7)6U|$IbgVzXShqLf?EBQ%M#qKF8RY(#8A zlpwxFY({*8*n-%K*oN4SC`If*lp%H^b|H2n_8|5m_91MDZxP=izDN9k*pE1XIEauD zhY*JmM-WF5#}LO6ClDtQrx2$Rc0@ViN5mP#S;RR+1>!v70^%pcMZ_hP3D7$ts>MBFuC|t2PUg5Y zVZ$ne2iMjim$5q??+H8H3_Ia`lsPJw|Gpncy+bBiOFG>XlYtB3V^?b1z&uiAP9m-!1f9ugbJZXXb>Voi_jtT z2m`{1Fj4u74`zC1IP_iPX5o#y+WmWwQydcB+Tt=CayQ5k4!INLK!@CpGl~-K_93cw z$g|en$rcK5LO3I8AzToy2seZ~!UN%n@IrVaY9s0(>LThPd=S2f`UpRSKcWGmA(eM0 z2hjLpa(;~}kp8)r1k#J_0&o{;#m2{sC-L%SK9K%I4C&+3@Y&Q<7nOmt!fA&B8X+1Z znoxN!4Wh9_=rj5w+^588J(+Jx5N)t_-7hqaom;YyT$9Rnjv2sir3TRva`^Bddfq@@ zGUv=7dROVUmYy?dxLBk)nDSbHyS@Y2K@`xG$_KKWQI`|Ey_fZ;cFidu7!iVKLFJ#? zwWJ|!=}W$mL0WRi;K6*dTGGqx58$7~Pkuh3CGDl-jl<cT@ zep*X9jp*D3B_NjjTVGFaNdc`8t*QKadK=m+0khX9R4n*T5o|2tl{Qosue7DUzmP<^ z@y>RTxD!V4f69@&+tDYyR-F%hYgFQ_6|DWfcGR0A^C*1{>A7PAUqPZG+!oWp5-_mLtTS?h6)hYw0i&F-6(HX?mgdfG_Q z+80UzT@Vq7u82rPH$)VoJE8}b`#SfeJ3`gIB$;M%k|j9!61x%CldcjH)Pv;7@jdA` zR3onCG^&$@EU6Uk9SKM06S_$QLBfzA*R$@(XfrG~x^#)6rd5YZ~r%5<+q+^vcB zXbOly#8NrY9!Iy|*HGv!BuwQPUWI=v!Nann^5;9_=_wL&Np+%JNtJ@I*ND?K;#7?| zsfdfJ6DQcz-SM;#-oE0T=>^q^Zgu#ELe@JaP!o~8 zofGIsN|wuB?g?}hp;|!@u0KWsVAyS)RpRYENVgmwacdL1o|0O-FH)+oXze`PoTA& zdbz1iROw;K1paw{PR^^2kA}FpT0aK8KvqvmpcZ&i{X+KmEP?*a z`A%KuGo9uP5YL0wT-l3h3Dm^}(v>@_tIQPDD;lDfLt$o)`MT={ zkY0i(CwxOM(9_1hO;+=A<1k|)6N?jQ0&l3#hJx_mjRrOm#3H|PTA#A9hzxtiC>Fn7Ma~4|yBL%Z#zbQEjdVzYT`o8))-K2hM+Aa1s zCrSA`X+7<5)qd4()fUw{sVwzX3tsp}I#f*ETfrjGL)1n~VJpBtWgEB-S7$XMmfnNS z10pdXv?!vP=Y|Bj0yFY9whQEE(BX473*MMOb9Hl+@or*g#!?9Q7-7TuPKn_b#;!qZ zTCGAQa20-3Mch)I{E~gLDS@_NzxPd~P3cYii31W7sUO=3fiSX!g_I=FmV(%R9~%wI z#|^41a7+rG@7IWV@){`ION_t3w%`bgp+7MrjzJ;j#6I7gK>cSZMb}g(BNYJ!mKxz& zBTO|yqX?+nvqto&5#4J9^h$vz6i}y|L#UU-qgy3%=4?$-=Nb_zvWDLz&@B`L>>|jH z4q0nU0*%z_R>E3_S#o8!VU75(e2BVfbvqqVH^yMty~9=5gp~%Nribn~$1l`Ii9peg znj%j{{H!|hLEq5PfIE8*4RmyaT4hQh9taF)pzx{~x}9~|nn0V0ICxR);K3%r;8y4X z4a;&#>~fJc*_J>zhy_r588U+GG7Pq3%&{;7K{kU%l9sUfAlqn7UP_}$ zOWA20_E#FcAci^?C`dYxGZC~PqU3cDz+ zT@&qJ*N77H8b@`!0a2QbP>L>y_6_FiTvKcv?_2y)I5rIs@P2?}EWC+P#)?$N`dPF$ zQ^XDR@^>|3;Z2Y?y$*Lbcsr%+b@0-GW3-+J%MvKDwALIUZH3{SaKhZq+|2B6wwTA7 z`|Dfi>%!YxIz4CFXWC{iF{@37Odre<<}zWwkS|PR?G7c-UIyWw=8;gLxvjaZ`B7dB zA)c2PA4#A?3B3=yu>ACB0=+0?Xg+c}&8o++hvC8f-|8V8Zym7*u!}krj5)`l4vFO* z#fF>N+L`3Yx%4fr3gnDS0AP zD&kvqceF55bu#K7)$Jb@=}=2lCqw>;b(TAoC(tZmEzp~tJexpUvyUees26iPmq63W zS(Xnz*l`})12WpD4L=PYza~+=k=!?r;b)qznt}{p7!1Y|p&>~UA8506GsIDv2kI$0 zs>x8jQl-*!G(=#j&nE~`m?gf*;$I}t<(>sDh5G839UH)Fru2;R+Ty6(rK|$p7H!Ld z;pNO8_0;K{N?+hpXsoUp5(-t%VbyYtebT?)EKT&BURXmkC{V?o-q6GTKkts#X3Zh2S6<$9&nc{f52Cf& z&%9x}w_v(16S`kt>3CUHDi%qzM(W==3sw;eh_4tu^|Mb4y{Z=rhv{_~XZ*Z-IVyuh zwnhX?p}s`J{{Ab0Hucb^bCY3AQJhf^D&B;O)){$E!gP*`(72jayiK5uJth^_c03OM zpNa*OU*72PpNc`ApA~xIwBgNCW!l%2`He`4*09tuReTF}@Q(!AO>=D7u7zLja%HJb zm*6ZVLrlZE{+U3VdugW^x>m1fIpA{mqJ}?u3Z0b8W zn!$U&QEQiI{?&p}YNCSA^tR$B`j#m^9g^F(p@N&v?}HM6l=j-DFo_Pn z`<3A-zCS2_g75c=KkBda`@(d)G7Q;v#Y3`P@tA8*fd-O#!DTYe;z_^xijQ-TRXn7@ z6%Wa8#SeFnR6Hd66%V<7#jgyAHKjnW_OlJ&F|k=99cVFa<}8{?^@5b*iFL=ySrA_C zOJisRCl&8Bc(KU1MA}D+TPoI;%RqYZqP~vfpY)tei;$i=!zzB4kVw}vXLCPVSnrMM5ag90wT8wXCgO9N2iR|u_Oz#oRYmKvdss?U#oRg`KpMI4_t-h{) zr!nZaz_oX!da-_^zD%8^9;+UyPBL6q4^+!9;wF()H;4nV#$nwA3N{g1Y0bKR0@{|*UzjzXvCgtDV>Z4)#1 zKmb%p+BF2ew=vI9ryg8k>mQD z+msEHO+5;i95FYKhQI_L9Pcgf^G>FLL>G7XETmq$Wfl2Ix731gigVl-k5A|0|3b;i1q*+hwb(V5UNFEOWDo@7 zqGQHIN10{!SQ;D%tJ?!Yd0!gyR%w^ChYJwnM0evv7wwXs%Ed@G&8l$ik{*I}3{(ev zf*6MwkH|n|BC-$@5ZQ9|1qtu}Wb1 zhhqq3yH75K-dv)Jodgj;X0zBImr_^vS%#&YTXo0dh|G~wB2shU130s--lvvQz%oP; zVmV?3VkJUCtU`Q2W$#m~>8x1&nBn7lVy+506I-{qe@OvfA=V()A{e3=u@12wu>r9W zu?bOv_?pUF+&9xkzI;+|`BJ;h)Hg%7Sb0UvT`XU;_Up~GNpt(=>VSQN=_TC4yNmY4 zAiPm51mTP#3xpO$hCCR?8ZF{geHa9a{s7Si#qS`RqIeAgn<;t;0-Gs%4g#AgdI|!Y zDSC3SY%`_#^n~z;TakY!X2p_Q3*plUBWJNuA>Yu(YP}k6=>L>g!a%6Dtq&K#8#e_R zH~uBU&dZJAjT?^{Hy#x8U|#T!W#7FJ_@iQzD0b8_#W{Cm4p7=Pp|$CFHfqTAArx#=$u+nZ`lfZ7o%F`T*7No&8}oyNULL%8%qGmM4h*u$n={g78NX1;QIeI0$DHp&+y<+FSSk zet-fFB4jG>|NRi{F-Ytxyns~~ohVs+*N4k};ttbpy!IBY{>O?F4%1&)8BonW?R%Kc z5MFZ^*auLD0*t4*A?xpjgG*e0Pk`gwck3R*p)lt7`WsGg^4-Lf^t%td5G1dSKSi4nc=7B^!YLZ4S2e_LvGA<)!1A?yPf<_eX7vIO zIE}C)$`L;z&QRH_?^*h&HeDmEC01jT+UfK zi#BrRG&C;{-?gE6I~=am;ot!t1}BJJu}T*6oP3rx)thLXR@?-UI8ly=$jdX(MLaU< z9HdB%y*U%LOaiB&mWlFI2-fzis~^nO<*6piG6@uXI82jinFvY;D#MZ|?@K>Nd!K+4 z5`2vaUY762Ou^2o-h2Di-fDI+8q>I@{CmNC)I8f91^1a}ReNQZ@Cv$4Me7y6YQmh{ zpTKKa=et$VT`EmSV@F*_Lq~aj?+UnBhwplIDVX8T@}n#0XRJxD3hJp3=G%D$*AE^s zE`5YtFQ$UtUrH7+)$IxzBDVwn&dWh}E9hIjtA}uF(n|AHE?77>X*6C&2sb9V$?cw1 z(9>l`{UeUT$E>usjBhj-nW^|ZW!M{`5z)ifl6pJ7mUN4q-VGmGQd3wij%Qwb0^xO# z&{@tZEhPDgZ z3m>}@2;A2AxN#8>QT{Aq4-v-44`IQF5Q>@8SbZQ7&Ip<|rImg{?iD_ko$thd9S8 zBj@(07cvWs8_$b$K9FvHF90|u+!jsh$aIOSity5-lIo@HA;vp{54-?pP20)WVcn@Kca39PQU7 zQ0vys-=FI-H+X6IlJw7Y5mMYD=!r8)`Wik<7N28MHD%Ltp7ZtD;r119H4a-vto-!a z8902Qj*-voy-KybSlXxhBUlB8!+1CO@9(bC$Aldeey3V?;msSG%R274Kr@&;*IAXx zJoa9o%~<@~H?%R!0zHH;jh3(4u0pE^%g$30?4)&r2UbHlZDaL2t&i5A<)tOhHC}Si z?ep}Js57nDW|u&K)+0PG`Pldy-^bW?w?ZlgM+`;_hz_UJ9D4yIh= z1LGjEw`Q;GZ@EM@)NOI~?VuB6L^PRjhvhP%*M@$M^nmk!`tZSPoXly#UvSI4&*c)G zXcCWers|tM-+}@b3_%ywh@Z~ib#{!;tT2sE@*&qtbS3$J>niVA;5=_^bt?^;!b~i| znK<5kYITl6`4E;ft5@d|?ZA3_T%wCX=zkSY(Vayff@EEH(5u1R03_vVNG}Pj^nY zOxFvZX_RY=w1c!d@jG#%7@~QhDb-BWbW(p*A5za&cT=lWr&ZHb&FMqBiH@T6h3mo! zp_icJ5Ah56C|J~EaClJu*x2W<$zaU7ZD8YXU83D-=M9pDCApOmcbR|CSXECYzqovf z#%rj#KIhMTOU_Ua{k;a7vv3vW6uDugR4_;OV8d=+q7&Fhpr0GGtGoqINK-$2_=kUR za5@Wx!ORz?(TDcfuyPP=nFFXhI|qS~gW;DbU1A{Ic8=SwxrqOmCF=q0#`={tQVo`O zz$q!gY$dlZQJLJnOi7CRXYLMPz%idL;{|v`5Z){B7ZTIjhSRNFw;* zCEG}Noe`3;|0Cz~?>M*WDF2St>3W62JMs}%Xomyj)q!?b>1x`*AK&9A+Ip}AKK0gp zo(O|AUL>NCQwAJoYt5kj^inIQTC$t!Dt)>|qWQEhe>6ZI6z;6rY(7BtQt0t~;K)^Y z?0w{C#4m_zi0g&N(aO9VC#kXzf!<&hzC@@ zF#jQKzL%QJBoSUBdPFCaer!7U{_-!tKL~T{`iRzL!9e=|6I;Nv!lgK8ZGHG6EIdiA zqF2Z+IV18BU8mKU=3uueU*;C`h<1Y))Q5s^tTF2`I)E*Lq3Ig)OdJ}zUm5Umuc8?xFM6X?31D{Hjiebq9i^ z_>aEsaxjekk{6BLxWrED_IFXf_24Rp&3#PQ^Q^4j6Y4Lk7CfeciZ}0+bxR)8$yy%1 zrnt`kJoR8-eesxXU}pF%htA}pYOL}F!+wJLFcv%xKailQUj^B7l}@j6Rxw`~*ei#9 z`IuVa^?y#T`06pe!?Uo}k7?||;>VN^S6|^KP=RMDOEdYlEbR7Ux{SP+FMwC60@Y0* zMPkfb>n0{GSDr{4^9Jk0VL1*xaji~FDnc#)eg83iu|}vP){%DxR>31(dCS}-ic^{ZwI(pCWf?lH+jP0TO$rC!CJqPwVSowtB7UDHpE?#q1 zEMEws2Z{wC!cfcy(FVml5KU3c1>ujP5QI01IUt--%m$%FF^h%#`h;F1Ynk!4C$#5` z6=LaSO!#R)T&fYu6IYD*SBhJ@|iW+gQMktSGajY{nksoV>(w72@l)e-wl)e<2 z6|rKe(wPE7Cu?e-s1e6&#IYK2v_>4M5r=EUA+e0hV?&QVrW1|3paVG!YBeA_%3nWt zLfcbfV|SiBp{-bd81$=kOBwH!Sgt(R#Z?o>CO}Djd3+UYvaor5kc*x^p@gs%5O!zx z??0iz^0jAAXhVxe^O|V+*PK*#XpaAZpep*5L>Zs{fANn+3RN^tF5|0cq{>B%BMnx!CRRs+Iz7W2-MYyyD%_Vv`4XtSfhnlfq?|k9)=I_ zjFsy|d%i;zi}o3C5Qe5>VMQ5(v0eC&x3+EW92t+L;@9MtlSI- zB~YD=m0yeYIiOk?D@#QCY*2y5%1v;r0tIuq5e`?Np!p4O!~zA)uZM${9H_5?mnPYY zag9_5*(+le-82JkT!M_1---5Bpz0edzZLBgC=X+$O|-8BWinRo6YVQNQDfy^(Y_px zdGCysdqjH?sOQGY-J*RNs9%kh@MA9pb=_FGQ?xGub-`F!CMw6;Q^v|2j>GLiV`Zu1 zh`YyFx!v1w)ZJpN+$P!=z$nGW%B`Y(KB$!}Ftd?Ll24nfXuBm;eTuWos^TiDf_^%! zv_4WCvA8#BtbM6{puMTAuoM=)B;PY`Si&u0(%Ozem?j*G%WHo2$!(ekuLe zRnb1|0ep3y2eEZ#JpX~ zZ?|Z_n712ZIwPu`j@WK7Z?hqsJ7rw7OU(Nk)IsB-9b(=_PrT53=JW1wd{cu$pdgee^LsZ>Ea$WzU|F&3H~n*1R#4?mpz0d$ zE)ngoLAfZUuRuB4u(MxFU^}m?pIjYy>u79@SZ=9N_Gc{Xn=0DW^B$aRBmRlLaHz$i z{UvJ!-J#6iuS0ho+MzSmUqp&=}OOp$~z|^rtCZGg&tUeazg4)!kV| zhf6c#d*#YcL4L3D&~1jyJS-sO`rd->QLTTI580~dLw?2+5+oQ;+|t3(8Mb_}T3>?A z@Lnb8&Kzh-iPZ1`ZDOV`gU+N=+I|C!(^2BkD%e?r|5FW3Gc)ucd_(bjdp{> zJ+%21)VVYR2F}C45*z?s0eV)owu7Dw`YcTBIOuWJ`WWbxYJC)RB51n^8x3e!K1Iu* zaYm2AxY(06xLSV)8fO~g--7OrbA1>F_Q3$o_4lB6Ip(x-oKCdI8HzDp84D{gwmP0D z!Yc2diihTLdM|8gS+;Y{&6KIL5s@2DTlG zL*LUtTD3bXgSzf=rd&mrSzI7DCcu5Z<|5fG95lW$z9GAblv);-fLXFWM1C~HqB8Mf zup|31QMywggvnu@omGe7%XznIzF41LdhjacUA-u2fNsP&Y@e z?VSARXNd6p(GcsOH>xP$DdHL8IpPK4CE^w0HI@Io0UuC@kNBUq>2Ck9mFP~VJKDPZ zzuLR<@F=Qmf2-==uIf&AdP^srjZ|kR36ikN5>g4fvV@UQR7L~i8WO>Ag2Q4`QDjp| zP)MVqH<)q!=E*o=5OE$t1py&AAWvbOK}T8D$2Q=5QBcA6yVZ#}&imec@B8L^f4%Ci zTX)~8?mg$8bM8GpF4dpM5oPa};0Shrwk|xU;(1-aLN+s(=wIc0f|3+L-635&-%w*aT4%g#OSSVMO3j-k8c1XU-l zasx?yXS!&vn-E=)s7$<8nNOT_nHC_Z7C}ewoOHH}h84mHzZbSV_^ib9F6W-uDgX2s z->@}b$U{DOnrfC_{~1!b7O9&i+!2c7{7xW3~OWYT6U&8$r?yqrwL$^wosbaXW47aJOai@Slj+0&# z1l9dhVs+pD&+4r^D9Eiv);XMX?~*UBYRQ#X=(iaT zS1u`)a=AL^3LO|=CGLCNX&_WAkIQp??b_mckWWIukN6&-?|y!K_#ql}+;DUFhLjul zH*id+6>Tjt_kXfT3h}c0uh2|Y59>ZXNw@BSt5cyv+g9JgOE#~-;eIlFQk)Ca)Z|og zmZvql?h3GUIqo{1KmQ7yOpUhHGh^flz8N0r8TEtevvG^a!`oKR5DR*z)Q7|f5*Pqq zB38s(KcqgcKBc}E+Y9sCR#$Q3k<&DsaD0KfBY@*fA8Lqu$o){=y%}w*Z?{+b$=ZB% z2XuOXpfO>=6*__+fLZRXEv}8=7P(Zkt^Nt`@T@|Wx1jO5x0cOw)h5=8ZTI8aR!{Gy zdkkK9h30w-3JOwji*%^tt^DYbr;zRugr#^3*eq9puRv^jK-kUE84H!9rX2`^@hyF9 z$3g~+Bn+8ZI~FReJWKnNyhKtLs`p1*r@WHI`?e}`lN?7i{I9<7+qsF*ADjuyAa_1RozelSe3{_Xtjbd7_@f9Ygu)8LCv z56S!rqK%2ZF`aq2IbkeLRMSNi5!*+j7qWsOUVmtW8;g=(7ndowxSxC)pYyg8Y4WgyemxJ@nnUQ#6r_;kFL*+3Z1u>;j%M1{bmcPzut5 z=LjnFm~b&-MU>`mx~Pcq@Z~N#K+e|rZwmdaOzy0XLTkj&t=cPH^eGARXg46~8QV#8 z$?UhsTVI1~P%rUmpwb7WBfJLBsq+4@)}`9ZRKwPIpPRw(FiY~qGo?yWEH)>eeH!QN zfj0YI`3S%UbKS1%?OONdQof%(h{d*D`C)t$oEf|m4e|2hu#aZCxwC2x@6+4Q(z3+N zZcvltlZWZ30I|6*#l}ci1k&T0E}0w;o<6SsO3J1CFBF+g#SZlUrCCNw!80%2z>wM{2bAMyB%W`YF&Ip`TQ=7(|ISPiINIfN^P7{bk`j2SES zvM27OXjMyq3BHr4aCfCeA_GqQGHnz6=83^NUS9dOoZJIqKiUTnD|*#!?HheL#=4-1 zJrH!8W^-md?^9yz__`4vz)rJGOqiBZNHVdx~n{QPux8J_OOQxhL3Em%ktiZ5EZtCz|v$6t|E`?Ji59vJ4(Fk_adWrXl~ z?MUYPn4A3q`d+47?4knGT4{r7oJ{5-lR-lq?0W;jsW4 zridxL89~D%lys2HSd}H{H3HQDN`7{PW7v(@h4+0eLY51PfsRS?j$ribB}!KG$kRED zS7G35RuGzh-bXXPn`i$KkWr)KpA3xU=D`sXi!)<2&@>`PFI;#p9Bq9%pz&gibvHj( z`v)1+ID7v1ThQZ)u2~F5Z~Nr2I64=Me93ba5i8^eP7eb^?0W!+`=FO7er2V~i&1F0 zkjV?#Ux+JC)9v{HEeBo>fTYST#XR5wg)?*h2le2k;Bgp-8@Jt z!tB3Tjz8?#fgMlOd2{?vlv|~19lusP9dWE$`IerRKa{Jlw-{u0yWZj}As}AD|1j$;bV#*8D0g@Oa+0B<`|q;pOyW5 z;7mXJS2p?8O>5U*m2*wxIX}f&4UWls)7K|{Pn_JzKL*z_XzfO*4$+Un;EtWX6Oc0H zXN@V#8f<>2)>tS?+kw(1cWzAVXA8m(w#B_Qo{iGR@L_lRS%PDXC;qUK(Jddn9~JiU z76kN91`+Vd?yQ8sv)X~IrY?DO!{fG;@jTv%SP#iSpU2(fXR~;#?2=hZWBPK{W@!Gf zwej5?QK9olfax1HltNL?29vTO$qVE;A33$ZDHlYwmR2^?Q}C1H-jG zIc^PEDYnU3VCwP+;|&+@Zs{xKMziOKFqNNIN= zrK6EYi>=A%(`yQ^_PjHtv0&NkA4J+&yZMd1mMa=rUvVveaoJ@$J;hrs8Qrn^h(20v zS7*i0V2{eE>0tYg61dza7Me16T&wS9PJPqGO5boe&lF=ub$!^YaW z7@n%OzS-?(>>djzRkKZ!^;$`Q1#N+W{#d64m`j%WS;v3>u2{4>BHasBYvU9_W{~^}?2K~M?Q!u&%wOqZXm3(5!M;;ri3t`Nyi;zk4ORK?QOI!5@^G|u zX`&76m&|@=q>WPkRoPY5yiWkc+Ywdd-;rxJLz3k)zOResA?SnF8=_;=2zsf zA=_GqNMFg;S5F3*`UDU-oXxNe+VNPYdQhy!JsbV{%ZeM-8Wx+Ef3QCNUoS?7+Ur^L z)9~+_8C##)A}Q~bb~kxNagc2*PGC}%U-T9`gWmFV39WrDoEBIdR@O;;p#Uhlj`j!?N?ekS5(?B!f_ghVOglt0IRQ5WpZr)bgs!2aH3s%Y za0fx2!1r_;q14>jfT21d0TCI9i%b^}Jl zuC)PCDG{LpNgE&5iixk$6gm){#6Wh)6oCRZq6RZemG*r8$5U?3&0o<7H>akVm2gepbpSVCm)Mm9Wp| zdtvt}<%IHg;T|cC;t?#!G9;6ihc;$JHck)Z{%7w&Ci0zW32tSn;VyQ!2D=bD8E$BJ^ zdP#9VxSTQ98zsdhczL~OXocm1S8vbpZJ8&RKY#Mk^(UAA`jcgkWj2+ihZu}RW|gHU zv0Xo-TjUJF)7nqd3@fiWiQ&xS`VFUPI^V>T*!4l*%XfPu*{SthDt(ieKbOSvn)D}= z7>qEp^e27(Ol)teI+M(-sxv9CC5#MV=)#ByBU2bz%=)}5n|YV3_$uC%R>{1%awDA_ zZ8$%5L^Q53p)Wt*9+8Lg^JWfPVLjfM!=85YXI3V$#n#IJPd7_am&KZM*jXtW4zS87 zBytO^nkREu#G#ERPHuY_&&oeOx^B6%fdo8t(YjLSpAl5o zQa7B}V%d;1a_;1s{?2DabfczU>}dVmx(^Vm4_;GEF)Z1hxxc9C3rnhJ?t?Ygz!LDx zomN2_GtVD5i7m-Xgvz?^Hf!`uTE zDU+=EPvo*45^s7h2h&#NhdC_0sk14US)EOJY?y&j`!LyL>fcD5zMID;@I5e#tc5WD z!zFFubN-UYbbk1$JT{#_>4!Q=gCW7>s;o_4%kbOa7_snr4kFFJRAU%KS>n`fPjw zOLNc#Y_H6<$^!NU&zw@gZsf% z0B!W>1KWe3q7hlZJaHiue}EJlP}*Js$mzm|00WWiw1k>~q5y_)$rM?+u{#zjb{ix? zID{KPAgsgMbD4%AqLXGDWEx=;b_3;TKrrk8xQid5Iv(OeF`0CcL5ybGsY@h6Oq6eA z6SBvypG1mHpc7=N*^Ii$YkCgT$BU+4D zYkj`pGsq^rc0>V|zv)5&E6}Wig99L3LP)rPr3`Q@&W}Mn6BsEdo4)429?&KT7t+Do zq(!_D;`ICap>R~$kabkU6oveqFuL&rVRUXj8el2taFd$dg6IECnoH7uPjl(T1+Q!- zzxBSGXq>H{nSrh|WB38ump=+M%>n)!gbd{G!>3#_c=qg@Xh{kxh%N^Ev-{F~W6)sq zcO{>V2=^*zFh5XwfaXj>8`5K=4SN?g3?gbw67L@DW?$@GK-k^Xo9)*`5#B2DG$=X@ ze`J~<$GXl}K7g29dUqcUC9EO}BI!g=FfoP#5hCfR^z=d& z5?*E=Am+nzIr538qqK2rkq0pYCB&EM!_FSWB4Xfmpo)W5zeMvJWMo1rP?{FdfL{A_ z9e8s%Y}^%hGf_;vB0*b!E%|rHb{|%`3B*?-Ih+vWF|}+)7Wv2`s=W}w+?ZhGyHHZL zte6;tQb%T9MZSr0#P{zqL0zMy3ZvggeV}I;jS{eONf#gaaIHh^&XDDN>2Z5~5yoJW zd}d~mL3B(YGOF57w1IeJ*=WY%Pf*~}ViRTb{_{lIFz1Xl%LddnH==DCn<9PJJD3F)|nwxIrPEfu`6WdB!!NcW-{wA9K%&LKP^9ypPJ9pN1#G#UNFy>7s%tc!8OvGo1PoUP0O8e z#~lxhY-<5w=D-5zG1`r=h?@V~-U=FJXg`?8a=!AAVK(bmFvW6e5{i+)sg oi0W!qVpbq4l*Q-4b*-A|&-7&aGWqLpmBvL9Bc4boBKB(i7e&4u4FCWD diff --git a/OfficeAssistant_msvc/MyButton.cpp b/OfficeAssistant_msvc/MyButton.cpp index 3602c43..b9ecc60 100644 --- a/OfficeAssistant_msvc/MyButton.cpp +++ b/OfficeAssistant_msvc/MyButton.cpp @@ -1,86 +1,87 @@ -// -// Created by HW on 2023/07/26. -// -#define TEXT_SIZE 7 -#include "MyButton.h" -MyButton::MyButton(ButtonStruct &buttonStruct,int width,int height,QList *buttons,QWidget *parent) : QPushButton(parent) { - this->buttons=buttons; - this->width2=width; - this->height2=height; - this->text=buttonStruct.text; - this->url = buttonStruct.url; - this->logo=buttonStruct.image; - this->logo_cover = buttonStruct.image_cover; - QString style = "background-color:"; - style += buttonStruct.background_color; - style += ";border:none;"; - this->setStyleSheet(style); - this->text_color = buttonStruct.text_color; - this->text_cover_color = buttonStruct.text_cover_color; - this->checked = false; -} - -MyButton::~MyButton() { -} - -void MyButton::paintEvent(QPaintEvent *e) { - QPushButton::paintEvent(e); - QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing); - int logo_width=width()/3; - int logo_x=width()/3; - int logo_y=(height()-logo_width)/3; - setContentsMargins(0,0,0,0); - QFont ft; - ft.setPixelSize(TEXT_SIZE); - //±ðÎÊÎÒΪɶ³Ë3£¬ÎÒÒ²²»ÖªµÀ - int text_x=(width()-TEXT_SIZE*text.length()*scale*3)/2; - int text_y=(logo_width+logo_y+10); - QRectF logo_rect(logo_x, logo_y, logo_width, logo_width); - QRectF text_rect(text_x,text_y, TEXT_SIZE*text.length()*scale*3,TEXT_SIZE*scale*3); - - if(checked){ - painter.setPen(text_cover_color); - painter.drawImage(logo_rect, *logo_cover); - painter.drawText(text_rect, Qt::AlignCenter, text); - } - else { - painter.setPen(text_color); - painter.drawImage(logo_rect, *logo); - painter.drawText(text_rect, Qt::AlignCenter, text); - } - -} -QSize MyButton::sizeHint() const { - return QSize(width2,height2); -} - -void MyButton::enterEvent(QEvent *event) { - QWidget::enterEvent(event); - checked = true; - update(); -} - -void MyButton::leaveEvent(QEvent *event) { - QWidget::leaveEvent(event); - checked = false; - update(); -} - -void MyButton::mousePressEvent(QMouseEvent *event) { - QPushButton::mousePressEvent(event); -} - -void MyButton::mouseReleaseEvent(QMouseEvent *event) { - QPushButton::mouseReleaseEvent(event); - for(auto button:*buttons){ - button->setChecked(false); - button->update(); - } - if(checked) - checked=false; - else - checked=true; - emit clicked1(text, url); -} - +// +// Created by HW on 2023/07/26. +// +#define TEXT_SIZE 7 +#include "MyButton.h" +MyButton::MyButton(ButtonStruct &buttonStruct,int width,int height,QList *buttons,QWidget *parent) : QPushButton(parent) { + this->buttons=buttons; + this->width2=width; + this->height2=height; + this->text=buttonStruct.text; + this->url = buttonStruct.url; + this->logo=buttonStruct.image; + this->logo_cover = buttonStruct.image_cover; + this->background_color = buttonStruct.background_color; + QString style = "background-color:"; + style += buttonStruct.background_color; + style += ";border:none;"; + this->setStyleSheet(style); + this->text_color = buttonStruct.text_color; + this->text_cover_color = buttonStruct.text_cover_color; + this->checked = false; +} + +MyButton::~MyButton() { +} + +void MyButton::paintEvent(QPaintEvent *e) { + QPushButton::paintEvent(e); + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + int logo_width=width()/3; + int logo_x=width()/3; + int logo_y=(height()-logo_width)/3; + setContentsMargins(0,0,0,0); + QFont ft; + ft.setPixelSize(TEXT_SIZE); + //±ðÎÊÎÒΪɶ³Ë3£¬ÎÒÒ²²»ÖªµÀ + int text_x=(width()-TEXT_SIZE*text.length()*scale*3)/2; + int text_y=(logo_width+logo_y+10); + QRectF logo_rect(logo_x, logo_y, logo_width, logo_width); + QRectF text_rect(text_x,text_y, TEXT_SIZE*text.length()*scale*3,TEXT_SIZE*scale*3); + + if(checked){ + painter.setPen(text_cover_color); + painter.drawImage(logo_rect, *logo_cover); + painter.drawText(text_rect, Qt::AlignCenter, text); + } + else { + painter.setPen(text_color); + painter.drawImage(logo_rect, *logo); + painter.drawText(text_rect, Qt::AlignCenter, text); + } + +} +QSize MyButton::sizeHint() const { + return QSize(width2,height2); +} + +void MyButton::enterEvent(QEvent *event) { + QWidget::enterEvent(event); + checked = true; + update(); +} + +void MyButton::leaveEvent(QEvent *event) { + QWidget::leaveEvent(event); + checked = false; + update(); +} + +void MyButton::mousePressEvent(QMouseEvent *event) { + QPushButton::mousePressEvent(event); +} + +void MyButton::mouseReleaseEvent(QMouseEvent *event) { + QPushButton::mouseReleaseEvent(event); + for(auto button:*buttons){ + button->setChecked(false); + button->update(); + } + if(checked) + checked=false; + else + checked=true; + emit clicked1(text, url); +} + diff --git a/OfficeAssistant_msvc/MyButton.h b/OfficeAssistant_msvc/MyButton.h index cce91fb..3b9934e 100644 --- a/OfficeAssistant_msvc/MyButton.h +++ b/OfficeAssistant_msvc/MyButton.h @@ -1,68 +1,69 @@ -// -// Created by HW on 2023/07/26. -// - -#ifndef OFFICEASSISTANT_MYBUTTON_H -#define OFFICEASSISTANT_MYBUTTON_H - -#include -#include -#include -#include -#include -#include "globalvariables.h" -#include "buttonstruct.h" - -class MyButton: public QPushButton{ -Q_OBJECT -signals: - void clicked1(QString text, QString url); -public: - MyButton(ButtonStruct &buttonStruct,int width,int height,QList *buttons,QWidget *parent=nullptr); - ~MyButton() override; - QString getText(){ - return text; - } - - QSize sizeHint() const override; - void setChecked(bool checked){ - this->checked=checked; - } - QSize getLogicalSize() const { - if(scale>=1.25){ - return QSize(width2,height2); - } - else{ - return QSize(width2,height2); - }; - } - void setSize(int width,int height,int logicalwidth,int logicalheight){ - this->width2=width; - this->height2=height; - this->logicalwidth=logicalwidth; - this->logicalheight=logicalheight; - } -protected: - void paintEvent(QPaintEvent *e) override; - void enterEvent(QEvent *event) override; - void leaveEvent(QEvent *event) override; - void mousePressEvent(QMouseEvent *event) override; - void mouseReleaseEvent(QMouseEvent *event) override; -private: - QColor text_color; - QColor text_cover_color; - QList *buttons; - QImage *logo; - QImage *logo_cover; - QVBoxLayout *layout; - QString text; - QString url; - int width2; - int height2; - int logicalwidth; - int logicalheight; - bool checked=false; -}; - - -#endif //OFFICEASSISTANT_MYBUTTON_H +// +// Created by HW on 2023/07/26. +// + +#ifndef OFFICEASSISTANT_MYBUTTON_H +#define OFFICEASSISTANT_MYBUTTON_H + +#include +#include +#include +#include +#include +#include "globalvariables.h" +#include "buttonstruct.h" + +class MyButton: public QPushButton{ +Q_OBJECT +signals: + void clicked1(QString text, QString url); +public: + MyButton(ButtonStruct &buttonStruct,int width,int height,QList *buttons,QWidget *parent=nullptr); + ~MyButton() override; + QString getText(){ + return text; + } + + QSize sizeHint() const override; + void setChecked(bool checked){ + this->checked=checked; + } + QSize getLogicalSize() const { + if(scale>=1.25){ + return QSize(width2,height2); + } + else{ + return QSize(width2,height2); + }; + } + void setSize(int width,int height,int logicalwidth,int logicalheight){ + this->width2=width; + this->height2=height; + this->logicalwidth=logicalwidth; + this->logicalheight=logicalheight; + } +protected: + void paintEvent(QPaintEvent *e) override; + void enterEvent(QEvent *event) override; + void leaveEvent(QEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; +private: + QColor text_color; + QColor text_cover_color; + QString background_color; + QList *buttons; + QImage *logo; + QImage *logo_cover; + QVBoxLayout *layout; + QString text; + QString url; + int width2; + int height2; + int logicalwidth; + int logicalheight; + bool checked=false; +}; + + +#endif //OFFICEASSISTANT_MYBUTTON_H diff --git a/OfficeAssistant_msvc/OfficeAssistant_msvc.vcxproj b/OfficeAssistant_msvc/OfficeAssistant_msvc.vcxproj index d599502..a676907 100644 --- a/OfficeAssistant_msvc/OfficeAssistant_msvc.vcxproj +++ b/OfficeAssistant_msvc/OfficeAssistant_msvc.vcxproj @@ -1,145 +1,145 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {A49230DF-A869-4AA1-8ACA-3C7322530E46} - QtVS_v304 - $(MSBuildProjectDirectory)\QtMsBuild - 8.1 - - - - Application - v140_xp - - - Application - v140_xp - - - - - - - 5.6.3_msvc2015 - core;gui;widgets;network - debug - - - 5.6.3_msvc2015 - core;gui;widgets - release - - - - - - - - - - - - - - - - - - - - - - $(ProjectDir)\$(Configuration);.\;%(AdditionalIncludeDirectories) - - - - - $(ProjectDir)\$(Configuration);.\;%(AdditionalIncludeDirectories) - - - - - true - true - ProgramDatabase - Disabled - MultiThreadedDebugDLL - - - Console - true - - - - - true - true - None - MaxSpeed - MultiThreadedDLL - - - Windows - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + + {A49230DF-A869-4AA1-8ACA-3C7322530E46} + QtVS_v304 + $(MSBuildProjectDirectory)\QtMsBuild + 8.1 + + + + Application + v140_xp + + + Application + v140_xp + + + + + + + 5.6.3_msvc2015 + core;gui;widgets;network + debug + + + 5.6.3_msvc2015 + core;gui;widgets + release + + + + + + + + + + + + + + + + + + + + + + $(ProjectDir)\$(Configuration);.\;%(AdditionalIncludeDirectories) + + + + + $(ProjectDir)\$(Configuration);.\;%(AdditionalIncludeDirectories) + + + + + true + true + ProgramDatabase + Disabled + MultiThreadedDebugDLL + + + Console + true + + + + + true + true + None + MaxSpeed + MultiThreadedDLL + + + Windows + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OfficeAssistant_msvc/OfficeAssistant_msvc.vcxproj.filters b/OfficeAssistant_msvc/OfficeAssistant_msvc.vcxproj.filters index 07c050c..cf3df22 100644 --- a/OfficeAssistant_msvc/OfficeAssistant_msvc.vcxproj.filters +++ b/OfficeAssistant_msvc/OfficeAssistant_msvc.vcxproj.filters @@ -1,132 +1,132 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - {99349809-55BA-4b9d-BF79-8FDBB0286EB3} - ui - - - {639EADAA-A684-42e4-A9AD-28FC9BCB8F7C} - ts - - - - - Resource Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Form Files - - - Form Files - - - Form Files - - - Form Files - - - Form Files - - - Form Files - - - - - Resource Files - - - - - Resource Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {99349809-55BA-4b9d-BF79-8FDBB0286EB3} + ui + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {639EADAA-A684-42e4-A9AD-28FC9BCB8F7C} + ts + + + + + Resource Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Form Files + + + Form Files + + + Form Files + + + Form Files + + + Form Files + + + Form Files + + + + + Resource Files + + + + + Resource Files + + \ No newline at end of file diff --git a/OfficeAssistant_msvc/OfficeAssistant_msvc.vcxproj.user b/OfficeAssistant_msvc/OfficeAssistant_msvc.vcxproj.user index 9add229..493b678 100644 --- a/OfficeAssistant_msvc/OfficeAssistant_msvc.vcxproj.user +++ b/OfficeAssistant_msvc/OfficeAssistant_msvc.vcxproj.user @@ -1,13 +1,13 @@ - - - - 79c86fb12b36dfa33d1a537c9af100b4c7928a9c - WindowsLocalDebugger - - - 2023-08-01T03:05:45.8140795Z - - - 2023-08-01T03:05:46.4588999Z - + + + + 79c86fb12b36dfa33d1a537c9af100b4c7928a9c + WindowsLocalDebugger + + + 2023-08-03T08:03:42.8435391Z + + + 2023-08-03T08:03:43.2818738Z + \ No newline at end of file diff --git a/OfficeAssistant_msvc/navbar.cpp b/OfficeAssistant_msvc/navbar.cpp index 181c6a4..e3e7add 100644 --- a/OfficeAssistant_msvc/navbar.cpp +++ b/OfficeAssistant_msvc/navbar.cpp @@ -1,228 +1,261 @@ -// -// Created by HW on 2023/07/26. -// - -// You may need to build the project (run Qt uic code generator) to get "ui_NavBar.h" resolved - -#include "navbar.h" -#include "ui_NavBar.h" -#include "config.h" -#include -#include -#include -#include "mainwindowlayout.h" -#include "globalvariables.h" -#ifdef _DEBUG -#pragma comment(lib, "Qt5Svgd.lib") -#else -#pragma comment(lib, "Qt5Svg.lib") -#endif -QString url_param; -NavBar::NavBar(ConfigResponse *configResponse, MainScreen *mainScreen,QWidget *parent) : - QWidget(parent), ui(new Ui::NavBar) { - ui->setupUi(this); - //this->setAttribute(Qt::WA_DeleteOnClose); - buffer = new QByteArray; - /*QString style = "background-color:"; - style += configResponse->basic.backgroud_color.toUpper(); - style += ";"; - setStyleSheet(style);*/ - //setStyleSheet("margin:0"); - setContentsMargins(0, 0, 0, 0); - if (configResponse->succeed&&configResponse->menus.empty()!=true) { - getLogoFromInternet(configResponse); - } - else { - getLogoFromLocal(); - } - layout2 = new QHBoxLayout; - layout_right = new QHBoxLayout; - layout_left = new QHBoxLayout; - logo_label = new QLabel(this); - //*logo = logo->scaled(this->width() / (5 / scale), this->height()); - logo_label->setScaledContents(true); - logo_label->setPixmap(QPixmap::fromImage(*logo)); - logo_label->setMaximumHeight(parent->height() / 8); - layout_left->addWidget(logo_label); - layout_left->setAlignment(Qt::AlignCenter); - for (auto buttonStruct : buttonStructs) { - MyButton *myButton = new MyButton(buttonStruct, height(), height(), &buttons,this); - myButton->setMaximumHeight(parent->height() / 8); - layout_right->addWidget(myButton); - //myButton->show(); - connect(myButton, &MyButton::clicked1, mainWindowLayout, &MainWindowLayout::clickButton); - buttons << myButton; - } - layout_right->setAlignment(Qt::AlignLeft); - if (!buttonStructs.empty()) { - connect(this, &NavBar::firstUrl, mainScreen, &MainScreen::firstUrl); - emit firstUrl(buttonStructs[0].url); - } - layout2->addLayout(layout_left, 1); - layout2->addLayout(layout_right, 4); - layout_right->setMargin(0); - layout2->setMargin(0); - //layout2->setAlignment(Qt::AlignJustify); - this->setLayout(layout2); - logo_label->show(); -} - -NavBar::~NavBar() { - for (auto buttonStruct : buttonStructs) { - delete buttonStruct.image; - delete buttonStruct.image_cover; - } - for(auto button : buttons){ - layout_right->removeWidget(button); - delete button; - } - layout2->removeWidget(logo_label); - delete logo_label; - delete logo; - //delete layout_left; - delete layout_right; - delete layout2; - delete ui; -} - -void NavBar::paintEvent(QPaintEvent *event) { - QWidget::paintEvent(event); - - QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing); - - QRectF rect(0, 0, this->width(), this->height()); - painter.fillRect(rect, qColor); - -} -void NavBar::resizeEvent(QResizeEvent *event) { - QWidget::resizeEvent(event); - for(auto button:buttons){ - button->setMaximumSize(event->size().height(), event->size().height()); - button->update(); - } - logo_label->setMaximumSize(event->size().width() / 5, event->size().height()); -} -void NavBar::getLogoFromInternet(ConfigResponse *configResponse) { - qColor.setNamedColor(configResponse->basic.backgroud_color); - - QUrl url_logo(configResponse->basic.logo_url); - QNetworkRequest *request_logo = new QNetworkRequest(url_logo); - manager = new QNetworkAccessManager; - reply = manager->get(*request_logo); - QTimer timer; - timer.setInterval(5000); - connect(reply, &QNetworkReply::finished, &eventLoop,&QEventLoop::quit); - connect(&timer, &QTimer::timeout,this, &NavBar::cancelDownload); - eventLoop.exec(); - timer.stop(); - buffer = new QByteArray; - delete request_logo; - if (downloadSuccess == true) { - *buffer = reply->readAll(); - logo = new QImage(); - logo->loadFromData(*buffer); - buffer->clear(); - for (auto button : configResponse->menus) { - QUrl url_image(button.img); - QNetworkRequest *request_image = new QNetworkRequest(url_image); - reply = manager->get(*request_image); - QTimer timer; - timer.setInterval(5000); - connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit); - connect(&timer, &QTimer::timeout, this, &NavBar::cancelDownload); - eventLoop.exec(); - timer.stop(); - if (!downloadSuccess) { - break; - } - *buffer = reply->readAll(); - QSvgRenderer *render_image = new QSvgRenderer(*buffer); - QImage *image = new QImage(200, 200, QImage::Format_ARGB32); - QPainter painter_image(image); - render_image->render(&painter_image); - - QUrl url_image_cover(button.img_cover); - QNetworkRequest *request_image_cover = new QNetworkRequest(url_image_cover); - reply = manager->get(*request_image_cover); - timer.setInterval(5000); - connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit); - connect(&timer, &QTimer::timeout, this, &NavBar::cancelDownload); - if (!downloadSuccess) { - break; - } - *buffer = reply->readAll(); - QSvgRenderer *render_image_cover = new QSvgRenderer(*buffer); - QImage *image_cover = new QImage(200, 200, QImage::Format_ARGB32); - QPainter painter_image_cover(image_cover); - render_image_cover->render(&painter_image_cover); - ButtonStruct buttonStruct; - buttonStruct.image = image; - buttonStruct.image_cover = image_cover; - buttonStruct.text = button.title; - buttonStruct.url = button.url; - buttonStruct.background_color = configResponse->basic.backgroud_color; - buttonStruct.text_color.setNamedColor(configResponse->basic.title_color); - buttonStruct.text_cover_color.setNamedColor(configResponse->basic.title_cover_color); - buttonStructs << buttonStruct; - delete request_image; - delete render_image; - delete request_image_cover; - delete render_image_cover; - } - } - delete manager; - manager = nullptr; - -} -void NavBar::storeToBuffer() { - buffer = new QByteArray; - -} -void NavBar::cancelDownload() { - disconnect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit); - eventLoop.quit(); - reply->abort(); - downloadSuccess = false; -} - -void NavBar::getLogoFromLocal() { - QString dir = QApplication::applicationDirPath(); - QFile file(dir + DEFAULT_FILE); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox::warning(nullptr, QString::fromLocal8Bit("´íÎó"), QString::fromLocal8Bit("ÎÞ·¨´ò¿ªÅäÖÃÎļþ")); - exit(1); - } - buffer->clear(); - *buffer = file.readAll(); - file.close(); - QJsonDocument *qJsonDocument = new QJsonDocument; - *qJsonDocument = QJsonDocument::fromJson(*buffer); - QJsonObject *obj_root = new QJsonObject; - if (qJsonDocument->isObject()) { - *obj_root = qJsonDocument->object(); - delete qJsonDocument; - QString logo_path = obj_root->value("basic").toObject().value("logo").toString(); - logo = new QImage(logo_path); - QString color= obj_root->value("basic").toObject().value("backgroud_color").toString(); - qColor.setNamedColor(color); - QJsonArray *array = new QJsonArray; - *array = obj_root->value("menu").toArray(); - for (auto obj : *array) { - ButtonStruct buttonStruct; - buttonStruct.text = obj.toObject().value("title").toString(); - buttonStruct.url = QString(BASE_URL)+obj.toObject().value("url").toString(); - buttonStruct.image = new QImage(obj.toObject().value("img").toString()); - buttonStruct.image_cover = new QImage(obj.toObject().value("img_cover").toString()); - buttonStructs << buttonStruct; - } - delete array; - } - else { - QMessageBox::warning(nullptr, QString::fromLocal8Bit("´íÎó"), QString::fromLocal8Bit("ÅäÖÃÎļþËð»µ")); - delete obj_root; - exit(1); - } - delete obj_root; - +// +// Created by HW on 2023/07/26. +// + +// You may need to build the project (run Qt uic code generator) to get "ui_NavBar.h" resolved + +#include "navbar.h" +#include "ui_NavBar.h" +#include "config.h" +#include +#include +#include +#include "mainwindowlayout.h" +#include "globalvariables.h" +#ifdef _DEBUG +#pragma comment(lib, "Qt5Svgd.lib") +#else +#pragma comment(lib, "Qt5Svg.lib") +#endif +QString url_param; +void ConvertImageToTransparent(QImage &img) +{ + img = img.convertToFormat(QImage::Format_ARGB32); + union myrgb + { + uint rgba; + uchar rgba_bits[4]; + }; + myrgb* mybits = (myrgb*)img.bits(); + int len = img.width()*img.height(); + while (len--> 0) + { + mybits->rgba_bits[3] = (mybits->rgba == 0xFFFFFFFF) ? 0 : 255; + mybits++; + } +} + +NavBar::NavBar(ConfigResponse *configResponse, MainScreen *mainScreen,QWidget *parent) : + QWidget(parent), ui(new Ui::NavBar) { + ui->setupUi(this); + //this->setAttribute(Qt::WA_DeleteOnClose); + buffer = new QByteArray; + /*QString style = "background-color:"; + style += configResponse->basic.backgroud_color.toUpper(); + style += ";"; + setStyleSheet(style);*/ + //setStyleSheet("margin:0"); + setContentsMargins(0, 0, 0, 0); + if (configResponse->succeed&&configResponse->menus.empty()!=true) { + getLogoFromInternet(configResponse); + } + else { + getLogoFromLocal(); + } + layout2 = new QHBoxLayout; + layout_right = new QHBoxLayout; + layout_left = new QHBoxLayout; + logo_label = new QLabel(this); + //*logo = logo->scaled(this->width() / (5 / scale), this->height()); + logo_label->setScaledContents(true); + logo_label->setPixmap(QPixmap::fromImage(*logo)); + logo_label->setMaximumHeight(parent->height() / 8); + layout_left->addWidget(logo_label); + layout_left->setAlignment(Qt::AlignCenter); + for (auto buttonStruct : buttonStructs) { + MyButton *myButton = new MyButton(buttonStruct, height(), height(), &buttons,this); + myButton->setMaximumHeight(parent->height() / 8); + layout_right->addWidget(myButton); + //myButton->show(); + connect(myButton, &MyButton::clicked1, mainWindowLayout, &MainWindowLayout::clickButton); + buttons << myButton; + } + layout_right->setAlignment(Qt::AlignLeft); + if (!buttonStructs.empty()) { + connect(this, &NavBar::firstUrl, mainScreen, &MainScreen::firstUrl); + emit firstUrl(buttonStructs[0].url); + } + layout2->addLayout(layout_left, 1); + layout2->addLayout(layout_right, 4); + layout_right->setMargin(0); + layout2->setMargin(0); + //layout2->setAlignment(Qt::AlignJustify); + this->setLayout(layout2); + logo_label->show(); +} + +NavBar::~NavBar() { + for (auto buttonStruct : buttonStructs) { + delete buttonStruct.image; + delete buttonStruct.image_cover; + } + for(auto button : buttons){ + layout_right->removeWidget(button); + delete button; + } + layout2->removeWidget(logo_label); + delete logo_label; + delete logo; + //delete layout_left; + delete layout_right; + delete layout2; + delete ui; +} + +void NavBar::paintEvent(QPaintEvent *event) { + QWidget::paintEvent(event); + + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + + QRectF rect(0, 0, this->width(), this->height()); + painter.fillRect(rect, qColor); + +} +void NavBar::resizeEvent(QResizeEvent *event) { + QWidget::resizeEvent(event); + for(auto button:buttons){ + button->setMaximumSize(event->size().height(), event->size().height()); + button->update(); + } + logo_label->setMaximumSize(event->size().width() / 5, event->size().height()); +} +void NavBar::getLogoFromInternet(ConfigResponse *configResponse) { + qColor.setNamedColor(configResponse->basic.backgroud_color); + + QUrl url_logo(configResponse->basic.logo_url); + QNetworkRequest *request_logo = new QNetworkRequest(url_logo); + manager = new QNetworkAccessManager; + reply = manager->get(*request_logo); + QTimer timer; + timer.setInterval(5000); + connect(reply, &QNetworkReply::finished, &eventLoop,&QEventLoop::quit); + connect(&timer, &QTimer::timeout,this, &NavBar::cancelDownload); + eventLoop.exec(); + timer.stop(); + buffer = new QByteArray; + delete request_logo; + reply->close(); + if (downloadSuccess == true) { + *buffer = reply->readAll(); + logo = new QImage(); + logo->loadFromData(*buffer); + buffer->clear(); + for (auto button : configResponse->menus) { + QUrl url_image(button.img); + QNetworkRequest *request_image = new QNetworkRequest(url_image); + reply = manager->get(*request_image); + QTimer timer; + timer.setInterval(5000); + connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit); + connect(&timer, &QTimer::timeout, this, &NavBar::cancelDownload); + eventLoop.exec(); + timer.stop(); + if (!downloadSuccess) { + break; + } + *buffer = reply->readAll(); + + QSvgRenderer *render_image = new QSvgRenderer(*buffer); + + QImage *image = new QImage(200, 200, QImage::Format_ARGB32); + QPainter painter_image(image); + painter_image.setCompositionMode(QPainter::CompositionMode_Clear); // Çå³ý»­²¼ + painter_image.fillRect(rect(), Qt::transparent); // Ìî³ä͸Ã÷É« + painter_image.setCompositionMode(QPainter::CompositionMode_SourceOver); // »Ö¸´Ä¬ÈÏÖµ + render_image->render(&painter_image); + buffer->clear(); + reply->close(); + + QUrl url_image_cover(button.img_cover); + QNetworkRequest *request_image_cover = new QNetworkRequest(url_image_cover); + reply = manager->get(*request_image_cover); + timer.setInterval(5000); + connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit); + connect(&timer, &QTimer::timeout, this, &NavBar::cancelDownload); + if (!downloadSuccess) { + break; + } + eventLoop.exec(); + *buffer = reply->readAll(); + qDebug() << *buffer; + QSvgRenderer *render_image_cover = new QSvgRenderer(*buffer); + QImage *image_cover = new QImage(200, 200, QImage::Format_ARGB32); + QPainter painter_image_cover(image_cover); + painter_image_cover.setCompositionMode(QPainter::CompositionMode_Clear); // Çå³ý»­²¼ + painter_image_cover.fillRect(rect(), Qt::transparent); // Ìî³ä͸Ã÷É« + painter_image_cover.setCompositionMode(QPainter::CompositionMode_SourceOver); // »Ö¸´Ä¬ÈÏÖµ + render_image_cover->render(&painter_image_cover); + buffer->clear(); + reply->close(); + + ButtonStruct buttonStruct; + buttonStruct.image = image; + buttonStruct.image_cover = image_cover; + buttonStruct.text = button.title; + buttonStruct.url = button.url; + buttonStruct.background_color = configResponse->basic.backgroud_color; + buttonStruct.text_color.setNamedColor(configResponse->basic.title_color); + buttonStruct.text_cover_color.setNamedColor(configResponse->basic.title_cover_color); + buttonStructs << buttonStruct; + delete request_image; + delete render_image; + delete request_image_cover; + delete render_image_cover; + } + } + delete manager; + manager = nullptr; + +} +void NavBar::storeToBuffer() { + buffer = new QByteArray; + +} +void NavBar::cancelDownload() { + disconnect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit); + eventLoop.quit(); + reply->abort(); + downloadSuccess = false; +} + +void NavBar::getLogoFromLocal() { + QString dir = QApplication::applicationDirPath(); + QFile file(dir + DEFAULT_FILE); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox::warning(nullptr, QString::fromLocal8Bit("´íÎó"), QString::fromLocal8Bit("ÎÞ·¨´ò¿ªÅäÖÃÎļþ")); + exit(1); + } + buffer->clear(); + *buffer = file.readAll(); + file.close(); + QJsonDocument *qJsonDocument = new QJsonDocument; + *qJsonDocument = QJsonDocument::fromJson(*buffer); + QJsonObject *obj_root = new QJsonObject; + if (qJsonDocument->isObject()) { + *obj_root = qJsonDocument->object(); + delete qJsonDocument; + QString logo_path = obj_root->value("basic").toObject().value("logo").toString(); + logo = new QImage(logo_path); + QString color= obj_root->value("basic").toObject().value("backgroud_color").toString(); + qColor.setNamedColor(color); + QJsonArray *array = new QJsonArray; + *array = obj_root->value("menu").toArray(); + for (auto obj : *array) { + ButtonStruct buttonStruct; + buttonStruct.text = obj.toObject().value("title").toString(); + buttonStruct.url = QString(BASE_URL)+obj.toObject().value("url").toString(); + buttonStruct.image = new QImage(obj.toObject().value("img").toString()); + buttonStruct.image_cover = new QImage(obj.toObject().value("img_cover").toString()); + buttonStructs << buttonStruct; + } + delete array; + } + else { + QMessageBox::warning(nullptr, QString::fromLocal8Bit("´íÎó"), QString::fromLocal8Bit("ÅäÖÃÎļþËð»µ")); + delete obj_root; + exit(1); + } + delete obj_root; + } \ No newline at end of file diff --git a/OfficeAssistant_msvc/netio.cpp b/OfficeAssistant_msvc/netio.cpp index d39fe52..a7b7cd5 100644 --- a/OfficeAssistant_msvc/netio.cpp +++ b/OfficeAssistant_msvc/netio.cpp @@ -1,544 +1,574 @@ -// -// Created by HW on 2023/07/27. -// - -#include -#include -#include -#include -#include "netio.h" -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "globalvariables.h" -#pragma comment(lib, "wbemuuid.lib") -#ifdef _DEBUG -#pragma comment(lib, "Qt5Networkd.lib") -#else -#pragma comment(lib, "Qt5Network.lib") -#endif -#pragma comment(lib,"comsuppw.lib") -//¶Áȡע²á±í»ñÈ¡MachineUUID - - -RequestBodyBase::RequestBodyBase(){ - wchar_t unix_time[65]={0}; - wsprintf(unix_time,L"%ld",std::time(0)); - QString request_id=QString::fromWCharArray(unix_time); - //´ò¿ªÅäÖÃÎļþ - QString dir=QApplication::applicationDirPath(); - QFile *infFile=new QFile(dir+"/config/information.kmd"); - if(!infFile->open(QIODevice::ReadOnly|QIODevice::Text)){ - QMessageBox::critical(nullptr,QString::fromLocal8Bit("´íÎó"), QString::fromLocal8Bit("ÎÞ·¨´ò¿ªÅäÖÃÎļþ")); - delete infFile; - exit(1); - } - //¶ÁÈ¡ÅäÖÃÎļþ - QByteArray bytes; - bytes=infFile->readAll(); - infFile->close(); - delete infFile; - //ת»¯Îªjson - qJsonDocument=QJsonDocument::fromJson(bytes); - if(qJsonDocument.isObject()){ - //¶ÁÈ¡Êý¾Ý£¬Ð´Èë¶ÔÓ¦×ֶΠ- QJsonObject obj_root=qJsonDocument.object(); - if(obj_root.value("product")==QJsonValue::Undefined){ - QMessageBox::warning(nullptr, QString::fromLocal8Bit("´íÎó"), QString::fromLocal8Bit("ÅäÖÃÎļþËð»µ")); - exit(1); - } - product=obj_root.value("product").toString(); - if(obj_root.value("parter_id")==QJsonValue::Undefined){ - QMessageBox::warning(nullptr, QString::fromLocal8Bit("´íÎó"), QString::fromLocal8Bit("ÅäÖÃÎļþËð»µ")); - exit(1); - } - parter_id=obj_root.value("parter_id").toString(); - }else{ - //´¦Àí´íÎó - QMessageBox::warning(nullptr, QString::fromLocal8Bit("´íÎó"), QString::fromLocal8Bit("ÅäÖÃÎļþËð»µ")); - exit(1); - } - //»ñÈ¡²Ù×÷ϵͳ°æ±¾ - this->os="Windows"; - OSVERSIONINFOEX os; - os.dwOSVersionInfoSize=sizeof(os); - GetVersionEx((OSVERSIONINFO *)&os); - switch(os.dwMajorVersion){//Ö÷°æ±¾ºÅ - case 5: //²»¼æÈÝWindows 2000£¬Òò´Ë5.xÒ»¶¨ÊÇWindows XP - os_version="Windows XP"; - break; - case 6: - switch(os.dwMinorVersion){ //´Î°æ±¾ºÅ - case 0: - os_version="Windows Vista or Windows Server 2008"; - break; - case 1: - os_version="Windows 7 or Windows Server 2008 R2"; - break; - case 2: - os_version="Windows 8 or Windows Server 2012"; - break; - case 3: - os_version="Windows 8.1 or Windows Server 2012 R2"; - break; - default: - os_version="Unknown"; - } - case 10: //Õ⼸¸öϵͳ¶¼ÊÇ10.0 - os_version="Windows 10, Windows 11, Windows Server 2016 or Windows Server 2019"; - break; - default: - os_version="Unknown"; - } - this->release = RELEASE; - this->version = VERSION; - //¶ÁÈ¡MachineGUID²¢È¡MD5×÷Ϊdevice_id - QByteArray hash = QCryptographicHash::hash(getMachineGUID().toUtf8(), QCryptographicHash::Md5); - device_id = hash.toHex(); - //¼ÓÈëjsonÐòÁÐ - QJsonValue value = device_id; - QJsonObject obj_root = qJsonDocument.object(); - obj_root.insert("device_id", value); - QJsonValue version_json = this->version; - obj_root.insert("version", version_json); - QJsonValue release_json = this->release; - obj_root.insert("release", release_json); - qJsonDocument.setObject(obj_root); - QJsonValue os_json(this->os); - QJsonValue os_version_json(this->os_version); - QString key_hash = QCryptographicHash::hash(QString(KEY).toUtf8(), QCryptographicHash::Md5).toHex(); - QByteArray request_id_byte = request_id.toUtf8(); - QByteArray sign_byte= QCryptographicHash::hash(key_hash.toUtf8()+request_id_byte, QCryptographicHash::Md5); - sign = sign_byte.toHex(); - QJsonValue sign_json(sign); - QJsonValue requestId_json=QJsonValue(request_id); - obj_root=qJsonDocument.object(); - //²åÈërequest_id - obj_root.insert(QString::fromLocal8Bit("request_id"),requestId_json); - obj_root.insert(QString::fromLocal8Bit("os"), os_json); - obj_root.insert(QString::fromLocal8Bit("os_version"), os_version_json); - obj_root.insert(QString::fromLocal8Bit("sign"), sign_json); - qJsonDocument.setObject(obj_root); - url_param = "?"; - url_param += "product="; - url_param += product; - url_param += "&parter_id="; - url_param += parter_id; - url_param += "&os="; - url_param += this->os; - url_param += "&os_version="; - url_param += os_version; - url_param += "&device_id="; - url_param += device_id; - url_param += "&request_id="; - url_param += request_id; - url_param += "&version="; - url_param += version; - url_param += "&release="; - url_param += release; - url_param += "&sign="; - url_param += sign; - qDebug() << url_param; -} - - - -void ConfigRequest::sendRequest(ConfigResponse *configResponse) { - timer = new QTimer(this); - QNetworkAccessManager *httpMgr = new QNetworkAccessManager(); - QNetworkRequest requestInfo; - //HTTPÇëÇó - //ÇëÇóÍ· - QString url = CONFIG_URL; - requestInfo.setUrl(QUrl(CONFIG_URL)); - requestInfo.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("application/json")); - //±£´æÏìÓ¦µÄ±äÁ¿ - reply = httpMgr->post(requestInfo,qJsonDocument.toJson()); - qDebug() << qJsonDocument.toJson(); - //¿ªÆôÒ»¸öÑ­»·£¬Ö±µ½³¬Ê±»òÕß»ñÈ¡µ½Êý¾ÝΪֹ - connect(reply,&QNetworkReply::finished, &eventLoop, &QEventLoop::quit); - //ÉèÖö¨Ê±Æ÷·ÀÖ¹³¬Ê± - connect(timer,&QTimer::timeout,this,&ConfigRequest::cancelDownload); - timer->start(5000); - //Æô¶¯Ñ­»· - eventLoop.exec(); - timer->stop(); - //delete httpMgr; - QJsonDocument result; - configResponse->succeed = false; - //memset(configResponse,0,sizeof(*configResponse)); - auto error = reply->error(); - //Èç¹ûûÓдíÎó - if(reply->error() == QNetworkReply::NoError) { - result = QJsonDocument::fromJson(reply->readAll()); - }else{ - //Èç¹ûÓдíÎó - configResponse->succeed=false; - //delete reply; - delete timer; - delete httpMgr; - return; - } - qDebug() << result.toJson(); - - //Èç¹ûÊý¾ÝÍêÕû - if(result.isObject()){ - QJsonObject obj_root=result.object(); - QJsonArray array; - - array = obj_root.value("data").toObject().value("menu").toArray(); - QJsonObject obj_basic = obj_root.value("data").toObject().value("basic").toObject(); - configResponse->basic.logo_url = obj_basic.value("logo").toString(); - configResponse->basic.device_id = obj_basic.value("device_id").toString(); - configResponse->basic.dev_id = obj_basic.value("dev_id").toString(); - configResponse->basic.token = obj_basic.value("token").toString(); - configResponse->basic.backgroud_color = obj_basic.value("backgroud_color").toString(); - configResponse->basic.title_color = obj_basic.value("title_color").toString(); - configResponse->basic.title_cover_color = obj_basic.value("title_cover_color").toString(); - auto i=0; - for(auto value:array){ - QJsonObject object=value.toObject(); - Menu menu; - menu.img=object.value("img").toString(); - menu.img_cover=object.value("img_cover").toString(); - menu.title=object.value("title").toString(); - menu.func=object.value("func").toString(); - menu.url=object.value("url").toString(); - configResponse->menus << menu; - i++; - } - configResponse->succeed = true; - }else{ - //Êý¾Ý²»ÍêÕû - configResponse->succeed=false; - //delete reply; - delete timer; - delete httpMgr; - return; - } - delete httpMgr; -} -void RequestBodyBase::cancelDownload() { - disconnect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit); - eventLoop.quit(); - reply->abort(); -} -void RequestBodyBase::sendRequest() { - timer = new QTimer(this); - QNetworkAccessManager *httpMgr = new QNetworkAccessManager(); - QNetworkRequest requestInfo; - //HTTPÇëÇó - //ÇëÇóÍ· - requestInfo.setUrl(QUrl(OP_URL)); - requestInfo.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("application/json")); - //±£´æÏìÓ¦µÄ±äÁ¿ - reply = httpMgr->post(requestInfo,qJsonDocument.toJson()); - //¿ªÆôÒ»¸öÑ­»·£¬Ö±µ½³¬Ê±»òÕß»ñÈ¡µ½Êý¾ÝΪֹ - connect(reply,&QNetworkReply::finished, this, &RequestBodyBase::cancelDownload); - //ÉèÖö¨Ê±Æ÷·ÀÖ¹³¬Ê± - connect(timer,&QTimer::timeout,&eventLoop,&QEventLoop::quit); - timer->start(5000); - //Æô¶¯Ñ­»· - eventLoop.exec(); - delete timer; - delete httpMgr; - delete reply; -} - - -DeviceRequest::DeviceRequest() : RequestBodyBase() { - //CPU - QString cpu = QSysInfo::currentCpuArchitecture(); - //ÄÚ´æ´óС - MEMORYSTATUSEX status; - status.dwLength = sizeof(status); - GlobalMemoryStatusEx(&status); - int ram = status.ullTotalPhys / 1024 / 1024; - //Ó²ÅÌ´óС - QStorageInfo storage = QStorageInfo::root(); - int disk = storage.bytesTotal() / static_cast(1024 * 1024 * 1024); - //ÏÔ¿¨ÐͺŠ- QStringList gpus; - BOOL success; - DWORD deviceIndex = 0; - DISPLAY_DEVICE displayDevice; - displayDevice.cb = sizeof(displayDevice); - while (EnumDisplayDevices(NULL, deviceIndex, &displayDevice, 0)) { - WCHAR valueName[128]; - DWORD valueSize; - DWORD valueType; - BYTE valueData[MAX_PATH]; - HKEY hKey; - WCHAR keyName[128]; - wsprintf(keyName, L"SYSTEM\\CurrentControlSet\\Control\\Video\\%s\\HardwareInformation", - displayDevice.DeviceID); - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { - valueSize = sizeof(valueData); - wsprintf(valueName, L"HardwareInformation.AdapterString"); - if (RegQueryValueEx(hKey, valueName, NULL, &valueType, valueData, &valueSize) == ERROR_SUCCESS) { - Q_ASSERT(valueType == REG_SZ); - QString adapterString = QString::fromWCharArray((wchar_t *) valueData, valueSize / sizeof(wchar_t) - 1); - gpus.append(adapterString); - } - RegCloseKey(hKey); - } - deviceIndex++; - displayDevice.cb = sizeof(displayDevice); - } - //Ö÷°åÐͺŠ- QString motherboard = QSysInfo::prettyProductName(); - //WMI»ñÈ¡Íø¿¨ÐͺŠ- HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED); - if (FAILED(hr)) { - std::cerr << "Failed to initialize COM library." << std::endl; - return; - } - QStringList netCards; - hr = CoInitializeSecurity( - NULL, - -1, - NULL, - NULL, - RPC_C_AUTHN_LEVEL_DEFAULT, - RPC_C_IMP_LEVEL_IMPERSONATE, - NULL, - EOAC_NONE, - NULL - ); - if (FAILED(hr)) { - std::cerr << "Failed to initialize security." << std::endl; - CoUninitialize(); - return; - } - - IWbemLocator* pLoc = NULL; - hr = CoCreateInstance( - CLSID_WbemLocator, - NULL, - CLSCTX_INPROC_SERVER, - IID_IWbemLocator, - (LPVOID*)&pLoc - ); - if (FAILED(hr)) { - std::cerr << "Failed to create IWbemLocator object." << std::endl; - CoUninitialize(); - return; - } - - IWbemServices* pSvc = NULL; - hr = pLoc->ConnectServer( - _bstr_t(L"ROOT\\CIMV2"), - NULL, - NULL, - 0, - NULL, - 0, - 0, - &pSvc - ); - if (FAILED(hr)) { - std::cerr << "Failed to connect to WMI service." << std::endl; - pLoc->Release(); - CoUninitialize(); - return; - } - - hr = CoSetProxyBlanket( - pSvc, - RPC_C_AUTHN_WINNT, - RPC_C_AUTHZ_NONE, - NULL, - RPC_C_AUTHN_LEVEL_CALL, - RPC_C_IMP_LEVEL_IMPERSONATE, - NULL, - EOAC_NONE - ); - if (FAILED(hr)) { - std::cerr << "Failed to set security blanket." << std::endl; - pSvc->Release(); - pLoc->Release(); - CoUninitialize(); - return; - } - - IEnumWbemClassObject* pEnumerator = NULL; - hr = pSvc->ExecQuery( - _bstr_t("WQL"), - _bstr_t("SELECT * FROM Win32_NetworkAdapter WHERE PhysicalAdapter = TRUE AND NetConnectionStatus = 3"), - WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, - NULL, - &pEnumerator - ); - if (FAILED(hr)) { - std::cerr << "Failed to execute WQL query for Win32_NetworkAdapter." << std::endl; - pSvc->Release(); - pLoc->Release(); - CoUninitialize(); - return; - } - IWbemClassObject* pClassObj = NULL; - ULONG uReturn = 0; - while (pEnumerator) { - hr = pEnumerator->Next(WBEM_INFINITE, 1, &pClassObj, &uReturn); - if (uReturn == 0) { - break; - } - - VARIANT vtProp; - hr = pClassObj->Get(L"Caption", 0, &vtProp, 0, 0); - if (SUCCEEDED(hr)) { - QString str=QString::fromWCharArray(vtProp.bstrVal); - VariantClear(&vtProp); - netCards.append(str); - } - - pClassObj->Release(); - } - //WMI»ñÈ¡Éù¿¨ÐͺŠ- hr = pSvc->ExecQuery( - _bstr_t("WQL"), - _bstr_t("SELECT * FROM Win32_SoundDevice"), - WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, - NULL, - &pEnumerator - ); - if (FAILED(hr)) { - std::cerr << "Failed to execute WQL query for Win32_SoundDevice." << std::endl; - pSvc->Release(); - pLoc->Release(); - CoUninitialize(); - return; - } - QStringList audioCards; - while (pEnumerator) { - hr = pEnumerator->Next(WBEM_INFINITE, 1, &pClassObj, &uReturn); - if (uReturn == 0) { - break; - } - - VARIANT vtProp; - hr = pClassObj->Get(L"Name", 0, &vtProp, 0, 0); - if (SUCCEEDED(hr)) { - QString str=QString::fromWCharArray(vtProp.bstrVal); - VariantClear(&vtProp); - audioCards.append(str); - } - - pClassObj->Release(); - } - hr = pSvc->ExecQuery( - bstr_t("WQL"), - bstr_t("SELECT * FROM Win32_PhysicalMemory"), - WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, - NULL, - &pEnumerator - ); - if (FAILED(hr)) - { - std::cout << "Query failed. Error code: " << hr << std::endl; - pSvc->Release(); - pLoc->Release(); - CoUninitialize(); - return; - } - QStringList RAMModel; - while (pEnumerator) - { - hr = pEnumerator->Next(WBEM_INFINITE, 1, &pClassObj, &uReturn); - if (uReturn == 0) - { - break; - } - - VARIANT vtProp; - hr = pClassObj->Get(L"Manufacturer", 0, &vtProp, 0, 0); - if (SUCCEEDED(hr)) - { - std::wcout << "Manufacturer: " << vtProp.bstrVal << std::endl; - VariantClear(&vtProp); - } - - hr = pClassObj->Get(L"PartNumber", 0, &vtProp, 0, 0); - if (SUCCEEDED(hr)) - { - RAMModel.append(QString::fromWCharArray(vtProp.bstrVal)); - VariantClear(&vtProp); - } - - pClassObj->Release(); - } - pSvc->Release(); - pLoc->Release(); - CoUninitialize(); - DISPLAY_DEVICE d = { sizeof(DISPLAY_DEVICE) }; - ::EnumDisplayDevices(NULL, 0, &d, 0); - QString monitor=QString::fromWCharArray(d.DeviceString, wcslen(d.DeviceString)); - //·¢ËÍ - //¹¹ÔìJSON - QJsonDocument *device=new QJsonDocument; - QJsonObject *object=new QJsonObject; - object->insert("CPU",QJsonValue(cpu)); - object->insert("RAM",QJsonValue(ram)); - object->insert("Hard_Disk",QJsonValue(disk)); - QJsonArray *gpu_array=new QJsonArray; - for(auto gpu:gpus) { - gpu_array->append(gpu); - } - object->insert("GPU",*gpu_array); - delete gpu_array; - object->insert("Mother_Board",motherboard); - QJsonArray *RAMModel_json=new QJsonArray; - for(auto RAM:RAMModel){ - RAMModel_json->append(RAM); - } - object->insert("Net_Card",*RAMModel_json); - delete RAMModel_json; - QJsonArray *netCards_json=new QJsonArray; - for(auto netCard:netCards){ - netCards_json->append(netCard); - } - object->insert("Net_Card",*netCards_json); - delete netCards_json; - QJsonArray *audioCards_json=new QJsonArray; - for(auto audioCard:audioCards){ - audioCards_json->append(audioCard); - } - object->insert("Audio_Card",*audioCards_json); - delete audioCards_json; - object->insert("Monitor",monitor); - device->setObject(*object); - delete object; - QJsonObject obj_root=qJsonDocument.object(); - obj_root.insert("data",QString(device->toJson())); - delete device; - qJsonDocument.setObject(obj_root); - timer = new QTimer(this); - QNetworkAccessManager *httpMgr = new QNetworkAccessManager(); - QNetworkRequest requestInfo; - //HTTPÇëÇó - //ÇëÇóÍ· - requestInfo.setUrl(QUrl(DEVICE_URL)); - requestInfo.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("application/json")); - //±£´æÏìÓ¦µÄ±äÁ¿ - reply = httpMgr->post(requestInfo,qJsonDocument.toJson()); - //¿ªÆôÒ»¸öÑ­»·£¬Ö±µ½³¬Ê±»òÕß»ñÈ¡µ½Êý¾ÝΪֹ - connect(reply,&QNetworkReply::finished, &eventLoop, &QEventLoop::quit); - //ÉèÖö¨Ê±Æ÷·ÀÖ¹³¬Ê± - connect(timer,&QTimer::timeout,this,&DeviceRequest::cancelDownload); - timer->start(5000); - //Æô¶¯Ñ­»· - eventLoop.exec(); - delete httpMgr; -} +// +// Created by HW on 2023/07/27. +// + +#include +#include +#include +#include +#include "netio.h" +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "globalvariables.h" +#pragma comment(lib, "wbemuuid.lib") +#ifdef _DEBUG +#pragma comment(lib, "Qt5Networkd.lib") +#else +#pragma comment(lib, "Qt5Network.lib") +#endif +#pragma comment(lib,"comsuppw.lib") +//¶Áȡע²á±í»ñÈ¡MachineUUID +bool IsWin11AndLater() +{ + + //Windows 10 ´ÓÄÚ²¿°æ±¾ 10240 ¿ªÊ¼£¬ÒÔÄÚ²¿°æ±¾ 19044 ½áÊø¡£Windows 11 ´ÓÄÚ²¿°æ±¾ 22000 ¿ªÊ¼£¬ÄÇô£º + //Environment.OSVersion.Version.Build >= 22000; + NTSTATUS(WINAPI * RtlGetVersion)(LPOSVERSIONINFOEXW); + OSVERSIONINFOEXW osInfo; + *(FARPROC*)&RtlGetVersion = GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion"); + if (NULL != RtlGetVersion) + { + osInfo.dwOSVersionInfoSize = sizeof(osInfo); + RtlGetVersion(&osInfo); + + return (osInfo.dwMajorVersion >= 10 && osInfo.dwBuildNumber >= 22000); + } + + return false; +} +RequestBodyBase::RequestBodyBase(){ + wchar_t unix_time[65]={0}; + wsprintf(unix_time,L"%ld",std::time(0)); + QString request_id=QString::fromWCharArray(unix_time); + //´ò¿ªÅäÖÃÎļþ + QString dir=QApplication::applicationDirPath(); + QFile *infFile=new QFile(dir+"/config/information.kmd"); + if(!infFile->open(QIODevice::ReadOnly|QIODevice::Text)){ + QMessageBox::critical(nullptr,QString::fromLocal8Bit("´íÎó"), QString::fromLocal8Bit("ÎÞ·¨´ò¿ªÅäÖÃÎļþ")); + delete infFile; + exit(1); + } + //¶ÁÈ¡ÅäÖÃÎļþ + QByteArray bytes; + bytes=infFile->readAll(); + infFile->close(); + delete infFile; + //ת»¯Îªjson + qJsonDocument=QJsonDocument::fromJson(bytes); + if(qJsonDocument.isObject()){ + //¶ÁÈ¡Êý¾Ý£¬Ð´Èë¶ÔÓ¦×ֶΠ+ QJsonObject obj_root=qJsonDocument.object(); + if(obj_root.value("product")==QJsonValue::Undefined){ + QMessageBox::warning(nullptr, QString::fromLocal8Bit("´íÎó"), QString::fromLocal8Bit("ÅäÖÃÎļþËð»µ")); + exit(1); + } + product=obj_root.value("product").toString(); + if(obj_root.value("parter_id")==QJsonValue::Undefined){ + QMessageBox::warning(nullptr, QString::fromLocal8Bit("´íÎó"), QString::fromLocal8Bit("ÅäÖÃÎļþËð»µ")); + exit(1); + } + parter_id=obj_root.value("parter_id").toString(); + }else{ + //´¦Àí´íÎó + QMessageBox::warning(nullptr, QString::fromLocal8Bit("´íÎó"), QString::fromLocal8Bit("ÅäÖÃÎļþËð»µ")); + exit(1); + } + //»ñÈ¡²Ù×÷ϵͳ°æ±¾ + this->os="Windows"; + OSVERSIONINFOEXW os; + os.dwOSVersionInfoSize=sizeof(os); + GetVersionEx((OSVERSIONINFO *)&os); + NTSTATUS(WINAPI * RtlGetVersion)(LPOSVERSIONINFOEXW); + *(FARPROC*)&RtlGetVersion = GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion"); + if (RtlGetVersion != nullptr) { + RtlGetVersion(&os); + switch (os.dwMajorVersion) {//Ö÷°æ±¾ºÅ + case 5: //²»¼æÈÝWindows 2000£¬Òò´Ë5.xÒ»¶¨ÊÇWindows XP + os_version = "Windows XP"; + break; + case 6: + switch (os.dwMinorVersion) { //´Î°æ±¾ºÅ + case 0: + os_version = "Windows Vista or Windows Server 2008"; + break; + case 1: + os_version = "Windows 7 or Windows Server 2008 R2"; + break; + case 2: + os_version = "Windows 8 or Windows Server 2012"; + break; + case 3: + os_version = "Windows 8.1 or Windows Server 2012 R2"; + break; + default: + os_version = "Unknown"; + } + case 10: //Õ⼸¸öϵͳ¶¼ÊÇ10.0 + if (IsWin11AndLater()) { + os_version = "Windows 11 or Windows Server 2022"; + } + else { + os_version = "Windows 10, Windows Server 2016 or Windows Server 2019"; + } + break; + default: + os_version = "Unknown"; + } + } + else { + os_version = "Unknown"; + } + + this->release = RELEASE; + this->version = VERSION; + //¶ÁÈ¡MachineGUID²¢È¡MD5×÷Ϊdevice_id + QByteArray hash = QCryptographicHash::hash(getMachineGUID().toUtf8(), QCryptographicHash::Md5); + device_id = hash.toHex(); + //¼ÓÈëjsonÐòÁÐ + QJsonValue value = device_id; + QJsonObject obj_root = qJsonDocument.object(); + obj_root.insert("device_id", value); + QJsonValue version_json = this->version; + obj_root.insert("version", version_json); + QJsonValue release_json = this->release; + obj_root.insert("release", release_json); + qJsonDocument.setObject(obj_root); + QJsonValue os_json(this->os); + QJsonValue os_version_json(this->os_version); + QString key_hash = QCryptographicHash::hash(QString(KEY).toUtf8(), QCryptographicHash::Md5).toHex(); + QByteArray request_id_byte = request_id.toUtf8(); + QByteArray sign_byte= QCryptographicHash::hash(key_hash.toUtf8()+request_id_byte, QCryptographicHash::Md5); + sign = sign_byte.toHex(); + QJsonValue sign_json(sign); + QJsonValue requestId_json=QJsonValue(request_id); + obj_root=qJsonDocument.object(); + //²åÈërequest_id + obj_root.insert(QString::fromLocal8Bit("request_id"),requestId_json); + obj_root.insert(QString::fromLocal8Bit("os"), os_json); + obj_root.insert(QString::fromLocal8Bit("os_version"), os_version_json); + obj_root.insert(QString::fromLocal8Bit("sign"), sign_json); + qJsonDocument.setObject(obj_root); + url_param = "?"; + url_param += "product="; + url_param += product; + url_param += "&parter_id="; + url_param += parter_id; + url_param += "&os="; + url_param += this->os; + url_param += "&os_version="; + url_param += os_version; + url_param += "&device_id="; + url_param += device_id; + url_param += "&request_id="; + url_param += request_id; + url_param += "&version="; + url_param += version; + url_param += "&release="; + url_param += release; + url_param += "&sign="; + url_param += sign; + qDebug() << url_param; +} + + + +void ConfigRequest::sendRequest(ConfigResponse *configResponse) { + timer = new QTimer(this); + QNetworkAccessManager *httpMgr = new QNetworkAccessManager(); + QNetworkRequest requestInfo; + //HTTPÇëÇó + //ÇëÇóÍ· + QString url = CONFIG_URL; + requestInfo.setUrl(QUrl(CONFIG_URL)); + requestInfo.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("application/json")); + //±£´æÏìÓ¦µÄ±äÁ¿ + reply = httpMgr->post(requestInfo,qJsonDocument.toJson()); + qDebug() << qJsonDocument.toJson(); + //¿ªÆôÒ»¸öÑ­»·£¬Ö±µ½³¬Ê±»òÕß»ñÈ¡µ½Êý¾ÝΪֹ + connect(reply,&QNetworkReply::finished, &eventLoop, &QEventLoop::quit); + //ÉèÖö¨Ê±Æ÷·ÀÖ¹³¬Ê± + connect(timer,&QTimer::timeout,this,&ConfigRequest::cancelDownload); + timer->start(5000); + //Æô¶¯Ñ­»· + eventLoop.exec(); + timer->stop(); + //delete httpMgr; + QJsonDocument result; + configResponse->succeed = false; + //memset(configResponse,0,sizeof(*configResponse)); + auto error = reply->error(); + //Èç¹ûûÓдíÎó + if(reply->error() == QNetworkReply::NoError) { + result = QJsonDocument::fromJson(reply->readAll()); + }else{ + //Èç¹ûÓдíÎó + configResponse->succeed=false; + //delete reply; + delete timer; + delete httpMgr; + return; + } + qDebug() << result.toJson(); + + //Èç¹ûÊý¾ÝÍêÕû + if(result.isObject()){ + QJsonObject obj_root=result.object(); + QJsonArray array; + + array = obj_root.value("data").toObject().value("menu").toArray(); + QJsonObject obj_basic = obj_root.value("data").toObject().value("basic").toObject(); + configResponse->basic.logo_url = obj_basic.value("logo").toString(); + configResponse->basic.device_id = obj_basic.value("device_id").toString(); + configResponse->basic.dev_id = obj_basic.value("dev_id").toString(); + configResponse->basic.token = obj_basic.value("token").toString(); + configResponse->basic.backgroud_color = obj_basic.value("backgroud_color").toString(); + configResponse->basic.title_color = obj_basic.value("title_color").toString(); + configResponse->basic.title_cover_color = obj_basic.value("title_cover_color").toString(); + auto i=0; + for(auto value:array){ + QJsonObject object=value.toObject(); + Menu menu; + menu.img=object.value("img").toString(); + menu.img_cover=object.value("img_cover").toString(); + menu.title=object.value("title").toString(); + menu.func=object.value("func").toString(); + menu.url=object.value("url").toString(); + configResponse->menus << menu; + i++; + } + configResponse->succeed = true; + }else{ + //Êý¾Ý²»ÍêÕû + configResponse->succeed=false; + //delete reply; + delete timer; + delete httpMgr; + return; + } + delete httpMgr; +} +void RequestBodyBase::cancelDownload() { + disconnect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit); + eventLoop.quit(); + reply->abort(); +} +void RequestBodyBase::sendRequest() { + timer = new QTimer(this); + QNetworkAccessManager *httpMgr = new QNetworkAccessManager(); + QNetworkRequest requestInfo; + //HTTPÇëÇó + //ÇëÇóÍ· + requestInfo.setUrl(QUrl(OP_URL)); + requestInfo.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("application/json")); + //±£´æÏìÓ¦µÄ±äÁ¿ + reply = httpMgr->post(requestInfo,qJsonDocument.toJson()); + //¿ªÆôÒ»¸öÑ­»·£¬Ö±µ½³¬Ê±»òÕß»ñÈ¡µ½Êý¾ÝΪֹ + connect(reply,&QNetworkReply::finished, this, &RequestBodyBase::cancelDownload); + //ÉèÖö¨Ê±Æ÷·ÀÖ¹³¬Ê± + connect(timer,&QTimer::timeout,&eventLoop,&QEventLoop::quit); + timer->start(5000); + //Æô¶¯Ñ­»· + eventLoop.exec(); + delete timer; + delete httpMgr; + delete reply; +} + + +DeviceRequest::DeviceRequest() : RequestBodyBase() { + //CPU + QString cpu = QSysInfo::currentCpuArchitecture(); + //ÄÚ´æ´óС + MEMORYSTATUSEX status; + status.dwLength = sizeof(status); + GlobalMemoryStatusEx(&status); + int ram = status.ullTotalPhys / 1024 / 1024; + //Ó²ÅÌ´óС + QStorageInfo storage = QStorageInfo::root(); + int disk = storage.bytesTotal() / static_cast(1024 * 1024 * 1024); + //ÏÔ¿¨ÐͺŠ+ QStringList gpus; + BOOL success; + DWORD deviceIndex = 0; + DISPLAY_DEVICE displayDevice; + displayDevice.cb = sizeof(displayDevice); + while (EnumDisplayDevices(NULL, deviceIndex, &displayDevice, 0)) { + WCHAR valueName[128]; + DWORD valueSize; + DWORD valueType; + BYTE valueData[MAX_PATH]; + HKEY hKey; + WCHAR keyName[128]; + wsprintf(keyName, L"SYSTEM\\CurrentControlSet\\Control\\Video\\%s\\HardwareInformation", + displayDevice.DeviceID); + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { + valueSize = sizeof(valueData); + wsprintf(valueName, L"HardwareInformation.AdapterString"); + if (RegQueryValueEx(hKey, valueName, NULL, &valueType, valueData, &valueSize) == ERROR_SUCCESS) { + Q_ASSERT(valueType == REG_SZ); + QString adapterString = QString::fromWCharArray((wchar_t *) valueData, valueSize / sizeof(wchar_t) - 1); + gpus.append(adapterString); + } + RegCloseKey(hKey); + } + deviceIndex++; + displayDevice.cb = sizeof(displayDevice); + } + //Ö÷°åÐͺŠ+ QString motherboard = QSysInfo::prettyProductName(); + //WMI»ñÈ¡Íø¿¨ÐͺŠ+ HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED); + if (FAILED(hr)) { + std::cerr << "Failed to initialize COM library." << std::endl; + return; + } + QStringList netCards; + hr = CoInitializeSecurity( + NULL, + -1, + NULL, + NULL, + RPC_C_AUTHN_LEVEL_DEFAULT, + RPC_C_IMP_LEVEL_IMPERSONATE, + NULL, + EOAC_NONE, + NULL + ); + if (FAILED(hr)) { + std::cerr << "Failed to initialize security." << std::endl; + CoUninitialize(); + return; + } + + IWbemLocator* pLoc = NULL; + hr = CoCreateInstance( + CLSID_WbemLocator, + NULL, + CLSCTX_INPROC_SERVER, + IID_IWbemLocator, + (LPVOID*)&pLoc + ); + if (FAILED(hr)) { + std::cerr << "Failed to create IWbemLocator object." << std::endl; + CoUninitialize(); + return; + } + + IWbemServices* pSvc = NULL; + hr = pLoc->ConnectServer( + _bstr_t(L"ROOT\\CIMV2"), + NULL, + NULL, + 0, + NULL, + 0, + 0, + &pSvc + ); + if (FAILED(hr)) { + std::cerr << "Failed to connect to WMI service." << std::endl; + pLoc->Release(); + CoUninitialize(); + return; + } + + hr = CoSetProxyBlanket( + pSvc, + RPC_C_AUTHN_WINNT, + RPC_C_AUTHZ_NONE, + NULL, + RPC_C_AUTHN_LEVEL_CALL, + RPC_C_IMP_LEVEL_IMPERSONATE, + NULL, + EOAC_NONE + ); + if (FAILED(hr)) { + std::cerr << "Failed to set security blanket." << std::endl; + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); + return; + } + + IEnumWbemClassObject* pEnumerator = NULL; + hr = pSvc->ExecQuery( + _bstr_t("WQL"), + _bstr_t("SELECT * FROM Win32_NetworkAdapter WHERE PhysicalAdapter = TRUE AND NetConnectionStatus = 3"), + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &pEnumerator + ); + if (FAILED(hr)) { + std::cerr << "Failed to execute WQL query for Win32_NetworkAdapter." << std::endl; + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); + return; + } + IWbemClassObject* pClassObj = NULL; + ULONG uReturn = 0; + while (pEnumerator) { + hr = pEnumerator->Next(WBEM_INFINITE, 1, &pClassObj, &uReturn); + if (uReturn == 0) { + break; + } + + VARIANT vtProp; + hr = pClassObj->Get(L"Caption", 0, &vtProp, 0, 0); + if (SUCCEEDED(hr)) { + QString str=QString::fromWCharArray(vtProp.bstrVal); + VariantClear(&vtProp); + netCards.append(str); + } + + pClassObj->Release(); + } + //WMI»ñÈ¡Éù¿¨ÐͺŠ+ hr = pSvc->ExecQuery( + _bstr_t("WQL"), + _bstr_t("SELECT * FROM Win32_SoundDevice"), + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &pEnumerator + ); + if (FAILED(hr)) { + std::cerr << "Failed to execute WQL query for Win32_SoundDevice." << std::endl; + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); + return; + } + QStringList audioCards; + while (pEnumerator) { + hr = pEnumerator->Next(WBEM_INFINITE, 1, &pClassObj, &uReturn); + if (uReturn == 0) { + break; + } + + VARIANT vtProp; + hr = pClassObj->Get(L"Name", 0, &vtProp, 0, 0); + if (SUCCEEDED(hr)) { + QString str=QString::fromWCharArray(vtProp.bstrVal); + VariantClear(&vtProp); + audioCards.append(str); + } + + pClassObj->Release(); + } + hr = pSvc->ExecQuery( + bstr_t("WQL"), + bstr_t("SELECT * FROM Win32_PhysicalMemory"), + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &pEnumerator + ); + if (FAILED(hr)) + { + std::cout << "Query failed. Error code: " << hr << std::endl; + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); + return; + } + QStringList RAMModel; + while (pEnumerator) + { + hr = pEnumerator->Next(WBEM_INFINITE, 1, &pClassObj, &uReturn); + if (uReturn == 0) + { + break; + } + + VARIANT vtProp; + hr = pClassObj->Get(L"Manufacturer", 0, &vtProp, 0, 0); + if (SUCCEEDED(hr)) + { + std::wcout << "Manufacturer: " << vtProp.bstrVal << std::endl; + VariantClear(&vtProp); + } + + hr = pClassObj->Get(L"PartNumber", 0, &vtProp, 0, 0); + if (SUCCEEDED(hr)) + { + RAMModel.append(QString::fromWCharArray(vtProp.bstrVal)); + VariantClear(&vtProp); + } + + pClassObj->Release(); + } + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); + DISPLAY_DEVICE d = { sizeof(DISPLAY_DEVICE) }; + ::EnumDisplayDevices(NULL, 0, &d, 0); + QString monitor=QString::fromWCharArray(d.DeviceString, wcslen(d.DeviceString)); + //·¢ËÍ + //¹¹ÔìJSON + QJsonDocument *device=new QJsonDocument; + QJsonObject *object=new QJsonObject; + object->insert("CPU",QJsonValue(cpu)); + object->insert("RAM",QJsonValue(ram)); + object->insert("Hard_Disk",QJsonValue(disk)); + QJsonArray *gpu_array=new QJsonArray; + for(auto gpu:gpus) { + gpu_array->append(gpu); + } + object->insert("GPU",*gpu_array); + delete gpu_array; + object->insert("Mother_Board",motherboard); + QJsonArray *RAMModel_json=new QJsonArray; + for(auto RAM:RAMModel){ + RAMModel_json->append(RAM); + } + object->insert("Net_Card",*RAMModel_json); + delete RAMModel_json; + QJsonArray *netCards_json=new QJsonArray; + for(auto netCard:netCards){ + netCards_json->append(netCard); + } + object->insert("Net_Card",*netCards_json); + delete netCards_json; + QJsonArray *audioCards_json=new QJsonArray; + for(auto audioCard:audioCards){ + audioCards_json->append(audioCard); + } + object->insert("Audio_Card",*audioCards_json); + delete audioCards_json; + object->insert("Monitor",monitor); + device->setObject(*object); + delete object; + QJsonObject obj_root=qJsonDocument.object(); + obj_root.insert("data",QString(device->toJson())); + delete device; + qJsonDocument.setObject(obj_root); + timer = new QTimer(this); + QNetworkAccessManager *httpMgr = new QNetworkAccessManager(); + QNetworkRequest requestInfo; + //HTTPÇëÇó + //ÇëÇóÍ· + requestInfo.setUrl(QUrl(DEVICE_URL)); + requestInfo.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("application/json")); + //±£´æÏìÓ¦µÄ±äÁ¿ + reply = httpMgr->post(requestInfo,qJsonDocument.toJson()); + //¿ªÆôÒ»¸öÑ­»·£¬Ö±µ½³¬Ê±»òÕß»ñÈ¡µ½Êý¾ÝΪֹ + connect(reply,&QNetworkReply::finished, &eventLoop, &QEventLoop::quit); + //ÉèÖö¨Ê±Æ÷·ÀÖ¹³¬Ê± + connect(timer,&QTimer::timeout,this,&DeviceRequest::cancelDownload); + timer->start(5000); + //Æô¶¯Ñ­»· + eventLoop.exec(); + delete httpMgr; +} diff --git a/OfficeAssistant_msvc/netio.h b/OfficeAssistant_msvc/netio.h index 521d3b3..0799869 100644 --- a/OfficeAssistant_msvc/netio.h +++ b/OfficeAssistant_msvc/netio.h @@ -1,113 +1,116 @@ -// -// Created by HW on 2023/07/27. -// - -#ifndef OFFICEASSISTANT_NETIO_H -#define OFFICEASSISTANT_NETIO_H -#include -#include -#include -#include -#include -#include -#include -#include - - -typedef struct { - QString img; - QString img_cover; - QString title; - QString func; - QString url; -} Menu; -typedef struct { - bool succeed; - struct { - QString logo_url; - QString device_id; - QString dev_id; - QString token; - QString backgroud_color; - QString title_color; - QString title_cover_color; - }basic; - QList

menus; -}ConfigResponse; - -class RequestBodyBase:public QObject{ - Q_OBJECT; -public: - RequestBodyBase(); - virtual void sendRequest(); -protected: - QString product; - QString parter_id; - QString os; - QString os_version; - QString device_id; - QString request_id; - QString version; - QString release; - QString sign; - QJsonDocument qJsonDocument; - QNetworkReply *reply; - QEventLoop eventLoop; - QTimer *timer; -protected slots: - void cancelDownload(); -}; -class ConfigRequest:public RequestBodyBase{ -public: - ConfigRequest():RequestBodyBase(){} - void sendRequest(ConfigResponse * configResponse); -}; -class OpRequest:public RequestBodyBase{ -public: - OpRequest(QString Op,QString OpValue):RequestBodyBase(),op(Op),op_value(OpValue){ - QJsonObject obj_root=qJsonDocument.object(); - QJsonValue value=op; - obj_root.insert("op",op); - value=op_value; - obj_root.insert("op_value",op_value); - qJsonDocument.setObject(obj_root); - } - QString getOpValue(){ - return op_value; - } - QString getOp(){ - return op; - } - void setOpValue(QString op_value){ - this->op_value=op_value; - } - void setOp(QString op){ - this->op=op; - } - void sendRequest(); -protected: - QString op; - QString op_value; -}; - -class DeviceRequest:RequestBodyBase{ - DeviceRequest(); -}; - -class OpenMulitiWechat:public RequestBodyBase{ -public: - OpenMulitiWechat(): RequestBodyBase(){} -}; -inline QString getMachineGUID() { - HKEY hKey; - RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Cryptography", - 0, KEY_READ | KEY_WOW64_64KEY, &hKey); - DWORD dwType1 = REG_SZ; - DWORD dwLen = MAX_PATH; - WCHAR buf[100]; - RegQueryValueExA(hKey, "MachineGuid", 0, &dwType1, (LPBYTE)buf, &dwLen); - QString guid = QString::fromWCharArray(buf); - return guid; -} - -#endif //OFFICEASSISTANT_NETIO_H +// +// Created by HW on 2023/07/27. +// + +#ifndef OFFICEASSISTANT_NETIO_H +#define OFFICEASSISTANT_NETIO_H +#include +#include +#include +#include +#include +#include +#include +#include + + +typedef struct { + QString img; + QString img_cover; + QString title; + QString func; + QString url; +} Menu; +typedef struct { + bool succeed; + struct { + QString logo_url; + QString device_id; + QString dev_id; + QString token; + QString backgroud_color; + QString title_color; + QString title_cover_color; + }basic; + QList menus; +}ConfigResponse; + +class RequestBodyBase:public QObject{ + Q_OBJECT; +public: + RequestBodyBase(); + virtual void sendRequest(); +protected: + QString product; + QString parter_id; + QString os; + QString os_version; + QString device_id; + QString request_id; + QString version; + QString release; + QString sign; + QJsonDocument qJsonDocument; + QNetworkReply *reply; + QEventLoop eventLoop; + QTimer *timer; +protected slots: + void cancelDownload(); +}; +class ConfigRequest:public RequestBodyBase{ +public: + ConfigRequest():RequestBodyBase(){} + void sendRequest(ConfigResponse * configResponse); +}; +class OpRequest:public RequestBodyBase{ +public: + OpRequest(QString Op,QString OpValue):RequestBodyBase(),op(Op),op_value(OpValue){ + QJsonObject obj_root=qJsonDocument.object(); + QJsonValue value=op; + obj_root.insert("op",op); + value=op_value; + obj_root.insert("op_value",op_value); + qJsonDocument.setObject(obj_root); + } + QString getOpValue(){ + return op_value; + } + QString getOp(){ + return op; + } + void setOpValue(QString op_value){ + this->op_value=op_value; + } + void setOp(QString op){ + this->op=op; + } + void sendRequest(); +protected: + QString op; + QString op_value; +}; + +class DeviceRequest:RequestBodyBase{ + DeviceRequest(); +}; + +class OpenMulitiWechat:public RequestBodyBase{ +public: + OpenMulitiWechat(): RequestBodyBase(){} +}; +inline QString getMachineGUID() { + HKEY hKey; + RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Cryptography", + 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + DWORD dwType1 = REG_SZ; + DWORD dwLen = MAX_PATH; + WCHAR buf[100]; + RegQueryValueExA(hKey, "MachineGuid", 0, &dwType1, (LPBYTE)buf, &dwLen); + QString guid = QString::fromWCharArray(buf); + return guid; +} + +class SoftwareRequest :public RequestBodyBase { + +}; +#endif //OFFICEASSISTANT_NETIO_H