From 2e32173db80e78e392a6b9918cc50ac821ca9611 Mon Sep 17 00:00:00 2001 From: seuuung Date: Fri, 24 Jul 2026 11:13:31 +0900 Subject: [PATCH] =?UTF-8?q?=EC=95=84=EC=9D=B4=EC=BD=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...a26e37eb-5b6f-417f-8426-dfd11cf0e629.vsidx | Bin 2232 -> 0 bytes .vs/marking_gui.slnx/v18/.suo | Bin 115200 -> 92160 bytes .../v18/DocumentLayout.backup.json | 2 +- .vs/marking_gui.slnx/v18/DocumentLayout.json | 2 +- docs/developer_manual.md | 361 ++++ docs/knowledge_base.md | 69 +- marking_gui.Setup/Bundle.wxs | 13 + marking_gui.Setup/Product.wxs | 147 ++ .../.agents/skills/laser_marking/SKILL.md | 87 + marking_gui/App.xaml.cs | 60 + marking_gui/LoginOptions.json | 23 + marking_gui/MainWindow.xaml | 312 ++- marking_gui/MainWindow.xaml.cs | 1825 +++++++++++++++-- marking_gui/Manual/.obsidian/app.json | 3 + marking_gui/Manual/.obsidian/appearance.json | 1 + .../Manual/.obsidian/core-plugins.json | 33 + marking_gui/Manual/.obsidian/workspace.json | 196 ++ marking_gui/Manual/01_시스템_개요.md | 67 + marking_gui/Manual/02_초기_설정.md | 117 ++ marking_gui/Manual/03_메인_화면.md | 63 + marking_gui/Manual/04_통신_설정.md | 37 + marking_gui/Manual/05_시험_설정.md | 44 + marking_gui/Manual/06_데이터_조회.md | 53 + marking_gui/Manual/07_시험_프로세스.md | 75 + marking_gui/Manual/08_로그_관리.md | 39 + marking_gui/Manual/09_오류_대응.md | 59 + marking_gui/Manual/Manual_Merged.md | 844 ++++++++ marking_gui/Manual/Manual_for_pdf.html | 974 +++++++++ marking_gui/Manual/build_pdf.py | 163 ++ marking_gui/Manual/pdf_style.css | 213 ++ marking_gui/Manual/사용자_메뉴얼.md | 44 + marking_gui/Marking.ico | Bin 0 -> 213165 bytes marking_gui/Models/MarkingRequest.cs | 70 + marking_gui/Models/MarkingResult.cs | 35 + marking_gui/Models/MeasurementLimits.cs | 127 ++ marking_gui/Models/Product.cs | 6 +- marking_gui/PortSettingsWindow.xaml | 82 + marking_gui/PortSettingsWindow.xaml.cs | 156 ++ .../PublishProfiles/FolderProfile.pubxml | 15 + marking_gui/Services/Board4251Service.cs | 389 ++++ marking_gui/Services/CommunicationBase.cs | 142 ++ marking_gui/Services/DatabaseService.cs | 406 ++++ .../Services/EquipmentMeasurementService.cs | 417 ++++ marking_gui/Services/EzdMarkingService.cs | 336 +++ marking_gui/Services/IMarkingService.cs | 32 + marking_gui/Services/IScpiClient.cs | 17 + marking_gui/Services/LoggerService.cs | 96 + marking_gui/Services/LoginServicesStub.cs | 171 +- marking_gui/Services/MarkingConfigService.cs | 259 +++ marking_gui/Services/MockDatabase.cs | 30 - marking_gui/Services/MockMeasurer.cs | 75 - marking_gui/Services/MssqlDatabaseService.cs | 173 -- marking_gui/Services/TcpScpiClient.cs | 200 ++ marking_gui/Setting.ini | 113 + marking_gui/SettingsWindow.xaml | 1 + marking_gui/SettingsWindow.xaml.cs | 8 +- marking_gui/StartupLoginWindow.xaml | 220 +- marking_gui/StartupLoginWindow.xaml.cs | 649 +++--- marking_gui/bin/Debug/marking_gui.exe | Bin 78336 -> 0 bytes marking_gui/bin/Debug/marking_gui.exe.config | 11 - marking_gui/bin/Debug/marking_gui.pdb | Bin 132608 -> 0 bytes marking_gui/marking_gui.csproj | 262 ++- .../marking_gui_1wcr445j_wpftmp.csproj | 363 ++++ marking_gui/marking_gui_TemporaryKey.pfx | Bin 0 -> 1684 bytes .../marking_gui_colf0m00_wpftmp.csproj | 363 ++++ ...ework,Version=v4.7.2.AssemblyAttributes.cs | 4 - marking_gui/obj/Debug/App.baml | Bin 2969 -> 0 bytes marking_gui/obj/Debug/App.g.cs | 77 - marking_gui/obj/Debug/App.g.i.cs | 77 - ...gnTimeResolveAssemblyReferencesInput.cache | Bin 2498 -> 0 bytes marking_gui/obj/Debug/MainWindow.baml | Bin 13846 -> 0 bytes marking_gui/obj/Debug/MainWindow.g.cs | 387 ---- marking_gui/obj/Debug/MainWindow.g.i.cs | 387 ---- marking_gui/obj/Debug/SettingsWindow.baml | Bin 4599 -> 0 bytes marking_gui/obj/Debug/SettingsWindow.g.cs | 177 -- marking_gui/obj/Debug/SettingsWindow.g.i.cs | 177 -- marking_gui/obj/Debug/StartupLoginWindow.baml | Bin 12588 -> 0 bytes marking_gui/obj/Debug/StartupLoginWindow.g.cs | 193 -- .../obj/Debug/StartupLoginWindow.g.i.cs | 193 -- ...marking_gui.Properties.Resources.resources | Bin 180 -> 0 bytes ...marking_gui.csproj.AssemblyReference.cache | Bin 1886 -> 0 bytes ...marking_gui.csproj.CoreCompileInputs.cache | 1 - .../marking_gui.csproj.FileListAbsolute.txt | 41 - .../marking_gui.csproj.GenerateResource.cache | Bin 84 -> 0 bytes marking_gui/obj/Debug/marking_gui.exe | Bin 78336 -> 0 bytes marking_gui/obj/Debug/marking_gui.g.resources | Bin 34384 -> 0 bytes marking_gui/obj/Debug/marking_gui.pdb | Bin 132608 -> 0 bytes .../obj/Debug/marking_gui_MarkupCompile.cache | 20 - .../Debug/marking_gui_MarkupCompile.i.cache | 20 - .../Debug/marking_gui_MarkupCompile.i.lref | 4 - .../obj/Debug/marking_gui_MarkupCompile.lref | 4 - marking_installer/Empty.resx | 15 + marking_installer/Program.cs | 161 ++ marking_installer/app.manifest | 12 + marking_installer/marking_installer.csproj | 38 + program_flow.md | 116 +- {docs => sql}/database_setup.sql | 14 +- 97 files changed, 10548 insertions(+), 2720 deletions(-) delete mode 100644 .vs/marking_gui.slnx/FileContentIndex/a26e37eb-5b6f-417f-8426-dfd11cf0e629.vsidx create mode 100644 docs/developer_manual.md create mode 100644 marking_gui.Setup/Bundle.wxs create mode 100644 marking_gui.Setup/Product.wxs create mode 100644 marking_gui/.agents/skills/laser_marking/SKILL.md create mode 100644 marking_gui/LoginOptions.json create mode 100644 marking_gui/Manual/.obsidian/app.json create mode 100644 marking_gui/Manual/.obsidian/appearance.json create mode 100644 marking_gui/Manual/.obsidian/core-plugins.json create mode 100644 marking_gui/Manual/.obsidian/workspace.json create mode 100644 marking_gui/Manual/01_시스템_개요.md create mode 100644 marking_gui/Manual/02_초기_설정.md create mode 100644 marking_gui/Manual/03_메인_화면.md create mode 100644 marking_gui/Manual/04_통신_설정.md create mode 100644 marking_gui/Manual/05_시험_설정.md create mode 100644 marking_gui/Manual/06_데이터_조회.md create mode 100644 marking_gui/Manual/07_시험_프로세스.md create mode 100644 marking_gui/Manual/08_로그_관리.md create mode 100644 marking_gui/Manual/09_오류_대응.md create mode 100644 marking_gui/Manual/Manual_Merged.md create mode 100644 marking_gui/Manual/Manual_for_pdf.html create mode 100644 marking_gui/Manual/build_pdf.py create mode 100644 marking_gui/Manual/pdf_style.css create mode 100644 marking_gui/Manual/사용자_메뉴얼.md create mode 100644 marking_gui/Marking.ico create mode 100644 marking_gui/Models/MarkingRequest.cs create mode 100644 marking_gui/Models/MarkingResult.cs create mode 100644 marking_gui/PortSettingsWindow.xaml create mode 100644 marking_gui/PortSettingsWindow.xaml.cs create mode 100644 marking_gui/Properties/PublishProfiles/FolderProfile.pubxml create mode 100644 marking_gui/Services/Board4251Service.cs create mode 100644 marking_gui/Services/CommunicationBase.cs create mode 100644 marking_gui/Services/DatabaseService.cs create mode 100644 marking_gui/Services/EquipmentMeasurementService.cs create mode 100644 marking_gui/Services/EzdMarkingService.cs create mode 100644 marking_gui/Services/IMarkingService.cs create mode 100644 marking_gui/Services/IScpiClient.cs create mode 100644 marking_gui/Services/LoggerService.cs create mode 100644 marking_gui/Services/MarkingConfigService.cs delete mode 100644 marking_gui/Services/MockDatabase.cs delete mode 100644 marking_gui/Services/MockMeasurer.cs delete mode 100644 marking_gui/Services/MssqlDatabaseService.cs create mode 100644 marking_gui/Services/TcpScpiClient.cs create mode 100644 marking_gui/Setting.ini delete mode 100644 marking_gui/bin/Debug/marking_gui.exe delete mode 100644 marking_gui/bin/Debug/marking_gui.exe.config delete mode 100644 marking_gui/bin/Debug/marking_gui.pdb create mode 100644 marking_gui/marking_gui_1wcr445j_wpftmp.csproj create mode 100644 marking_gui/marking_gui_TemporaryKey.pfx create mode 100644 marking_gui/marking_gui_colf0m00_wpftmp.csproj delete mode 100644 marking_gui/obj/Debug/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs delete mode 100644 marking_gui/obj/Debug/App.baml delete mode 100644 marking_gui/obj/Debug/App.g.cs delete mode 100644 marking_gui/obj/Debug/App.g.i.cs delete mode 100644 marking_gui/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache delete mode 100644 marking_gui/obj/Debug/MainWindow.baml delete mode 100644 marking_gui/obj/Debug/MainWindow.g.cs delete mode 100644 marking_gui/obj/Debug/MainWindow.g.i.cs delete mode 100644 marking_gui/obj/Debug/SettingsWindow.baml delete mode 100644 marking_gui/obj/Debug/SettingsWindow.g.cs delete mode 100644 marking_gui/obj/Debug/SettingsWindow.g.i.cs delete mode 100644 marking_gui/obj/Debug/StartupLoginWindow.baml delete mode 100644 marking_gui/obj/Debug/StartupLoginWindow.g.cs delete mode 100644 marking_gui/obj/Debug/StartupLoginWindow.g.i.cs delete mode 100644 marking_gui/obj/Debug/marking_gui.Properties.Resources.resources delete mode 100644 marking_gui/obj/Debug/marking_gui.csproj.AssemblyReference.cache delete mode 100644 marking_gui/obj/Debug/marking_gui.csproj.CoreCompileInputs.cache delete mode 100644 marking_gui/obj/Debug/marking_gui.csproj.FileListAbsolute.txt delete mode 100644 marking_gui/obj/Debug/marking_gui.csproj.GenerateResource.cache delete mode 100644 marking_gui/obj/Debug/marking_gui.exe delete mode 100644 marking_gui/obj/Debug/marking_gui.g.resources delete mode 100644 marking_gui/obj/Debug/marking_gui.pdb delete mode 100644 marking_gui/obj/Debug/marking_gui_MarkupCompile.cache delete mode 100644 marking_gui/obj/Debug/marking_gui_MarkupCompile.i.cache delete mode 100644 marking_gui/obj/Debug/marking_gui_MarkupCompile.i.lref delete mode 100644 marking_gui/obj/Debug/marking_gui_MarkupCompile.lref create mode 100644 marking_installer/Empty.resx create mode 100644 marking_installer/Program.cs create mode 100644 marking_installer/app.manifest create mode 100644 marking_installer/marking_installer.csproj rename {docs => sql}/database_setup.sql (88%) diff --git a/.vs/marking_gui.slnx/FileContentIndex/a26e37eb-5b6f-417f-8426-dfd11cf0e629.vsidx b/.vs/marking_gui.slnx/FileContentIndex/a26e37eb-5b6f-417f-8426-dfd11cf0e629.vsidx deleted file mode 100644 index f298f974a1c218e5536a61f32efcf7f58a4163c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2232 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 literal 115200 zcmeHw3t(Jjnf95qga!~R0-~~zmeNJ&Oed4cBxxyhGMTi2rU^}Y0RmwzC+W14nJ_bH zTH3n6UPMG!1w~f5D5!{tRE6c@g^R1ZqN0MU=z3dqU0qn$UH5nWe^>tJIp=&c=bSlb z=1el7llGkCo%5aV_I}s*eZSlLedF2J{P=^1-tZI2^jsh?7v_m=1fNB^S|OXj2V;wenaA{I5YgZGhR}KLO$XS6_fI zGkttcgWK!0c#p-KcuobJ4LAuvKlFPd%u4{r0geH@3UEB&bbyG9s+l2Q3U^8G4Fa)>+z&sA)Jp$MY*ap}R*a5f{a2-J8t@qo4z#zp~%6|I?lQoo~_qX=eW?O`w_mpEU5*fW?3o zfVuy#gdP1l?f)Vj4CD5Hmcslzq)pcY{v7ZZfDZuv3h)-d4FJ}|jd;HeaFh1^4!r+b zGrtG#cLQz)+@jgN7w=m&^KIJu{dj)_aJ%+>C*Jn}J_z^_;BEkMeOP;c6z_Wh9|PP6 z_&DHxz$X9?06qzL5O4_aDFDNo;StzB3V00gIN-B@&jEzL`6V$;n!uk7S-ek5K_X5{!x#rl!X*poxY7gpQ=#i3U6uR_H}*eaHsc>aDkg!I6EWRD1){7RaovsBhNvG}4h$^4hAj zgfvPZUol~`ssBBQ@uwPowS3dSn!p%LVCQHs54#CzC+sSv;2bUg=OIp~`Da;)^1mDs zf3jG!SD+*|AswuLj)+wk+GP#tD-}uCEZYBG1aH@(7*xuf`DgpeAjiYN&61EYj%dSJ zrW1aJ?-E{NIv4r(;v)obn*YCq-{-Xm%t=H(8;{C8|^X+dN``k=r~&JEprUdm}0=YTWkGe=mFC(+uIMoKkG=( z9ekKIiXo=7ErODi|Od9-lXO9#)tC_DA~7bkx5cVCIz^VSD0_?L(8{=s+7e(!rZ z$X9v`dyIIZ$akCMMPKvd-3L<}{(A8}hH~gbi9~>73bE@S`*hmnt8)53anYvc!j*sg z(n&wR=foS%e)>@QXV(p%)$`hM%)M z)(`35DmVoJtVwHMM%%aIQ{W#)dr4@setXcal1eY|mGMKL!UH%<7(ox1M*CAa_64)Z zKSPoS^Qi^D%9nc3TVlYU0B@8qhgEy|Pa_=1>wJv!og;{Q8ZEp~oR7^Z{ZsH|HH`k( zkMid{fS4oDyV;rb^4|`n*A5{^3DAI;B83j3mkEr<-c}yt3XT825l&9)e?9!RpPp#;qCMtRZ??Z8|D1zyn*XQa_r}+& zQC6FOqI|Fibddea>Y@Biyr;m?DSmzZSHnMumM&W%*6bkv)m;7$BkW=={6?kEv)5-( z=V|=*p?{|}I#8|kNfPJ(*_U4nm`(o8ayO}qx(>rsRPPBs;OAT$=i{8>e+Yh02JmtD zKTD0z(aHZKXl3Lpd5ktv=mj$he`5<|kElHMV*3&FM=e8V{8!)qcK|!(HjcVD`kB^v zfESWy2Uc(*SltOLZ(=KdK!0lP|9br9@y~YPFDSgV+Q?T;OY1D~pNXKN|C#ZVyUR$! zZg8V4YJ_#L0d|x*%(5p_5SRsiuF-R?j!z~2QyPD|^52mv|Hbymx!8pK)HCb3Qi1*cMAq>w?^T%L{@1!S0UkK*ZnY?Fjoj zyd7CJ-3NU$+1&0_X2P473m@OEnp=nE!d>@A_sE$-Bs-lc z$hliyXm=RhM8dmMj!k*H$+-D;-hsKALa-za2R1>XHJeKr?T0!S2cPQOw-?v zDE33JZ&i)0N?MI*dgc7?LUw92Hkr-KnY=tY8B=mQHZh$tn1>6oTw!`@Q+6Wt*q!&@ z_WTQfABz^weCU@ePk+R(JYN2qepDB~|KNeP(5gV-Kwm7KmuFBfXK&5RxuINkJe8Ku z9(A0EfmkZDJ=Fusk_EL9qt(*vlTzbVe@=(|L3+kHP4a-M0pQ_6z&V=75zso$D{KO- zQP}HZ4LY{HIbK%trp^ zzL0Sn{2YfRP!~=|fZYF5Yx#4mSgL>H`Uml=vJb}uNk}1;(}Vf{n(=eJzz%1qEl({+SbP`2l%MDH5l^t?&OnQ|9Ya#3pU4U+YdHX9q z0WJY-0Sp6109yg1t=j=R0G9$T16&Rm1zZ8R5-O zo+=HH8*}s_=E~M-y=Seo(sKS_1}RSBFJrN8z|kJLDrpRV>pg#7>-;w}e%lKx;&QC5 zqg@{N#@pLFy}@K$_I3s0_>6VMyV|>A{*Lj$wSW1-iex<5A;&vI-p=vyE^kooI8eTP zQd{=JXi|e{4jWM{oO)Fk0Y_n5eVJp~UH-lkukK!V%14j;(3*cZZggwl7vKEeC!hcQ z*0E>5^_H1`XP+sn+-KIao8b9ctMv6xeWMqxc@t_@rGwlFJAvd(DfL7CSMA~a7wLd# zK-K)y{WE~Yn#W;a;wm$D+Y%q=0XVzP*=@DGjiX5DV>4VRr5PX4f6oc9;+U3cFuGcQ zeHzvp`BnHkG3S6Y20Y}y>Z-SB?P}W0vYCi^4e*opP^NQ=pZ!yWH}g6b5A)2q5YF@q z=~IL-zB&I&n#%HYivMrm_rXPKJnFnR=Nvc(q^|utoqJ&nTz@B>KL+3wKk4N%5^p?x znB9qjk_Yi?zy2obqI`6M@>lQ@Hy<_D%D?0x?<0Z7;|#z3`XBdysF>AXHP*_%$HG~( zf4#iHF3(n|?!@t-{gW7Q{yT|uvMsRvlhT(S%Ae$)0mQzq zt}Lq3IOR`D-<2MYe>k3^FQ@qb7JhHi2%tOvW0;>h>gIoqX zts~JbZN>Sy$!t6|npVUaeU8#{Y_~a&GV<7;8JsR`OUdTU-2kNTzW&~DCYIipPvvhZ zo3g!oGL3g|mjGV|{5{|w0AB$-1NbW7Yk;o< zo&_+zZ{qzez;gi7^zQ&fIi9IAzd>gf?&Lwje7N3~9Zjy7JLp=F39Y z2=nt?O8B<}2giw(#v@q&^1Kdly$QfF)S|8UqU=SU$)^(jh%zAK zj<-qO8k`u1sB#$g|9Fl=JgWgt@skP)`O7JOF+au8fPNj2hU@i*!4D`eD; z==8=4F$^~Tt6U|gHURNEXzCiV6n|wPZ+x1-kFV?J6d<2n~P7cs0Wxgvv{V{sRAOo`8o{tnMv7XZZ03w7eZ`uPXrnhZ}SO(^q( zdP%Z$9^ka!{rQu>=pFcz`%if4oZCO&JT>^v6LZ6>+x7*YKJ)IY;vegE`#;D0v!OU{ z|9AU;ue{LvzxAxxybj_FvvMBL)U%YCLC&D9RrVCrvi{7K?QYCUc4O7Q7ju|B%ABS1 z8BKM^UPbm{k`-!Zl-Q<+tl2zP?WdOWceSsd8~KM@|J<>8^wz(-{&RG%|LCPg^ZK*H z`QPFk2j@9#$eh8t-t)i2dl=_`YtDb2=YMO)ub=;A*}3z7^E3bVU9@_x0sRQ@eE`>s z^iLzK|CClOk-#}TY*SiX6zLp4TnDKsfGK8u_`uuVh~?vJUrKGbxM$`qEtg5x<`lCj zh~bm#K*Uc_!$0|lrOAtXR8PM-sTVZ8fI#}`gZoK zPycMfM+f>wMES{u0_L{z%h&8*t}T$SDO=g0<8XF5myox}Q`vmV+5Q{*Jt(u;|MN~{ zlxwYgoZ)X%JzM;8|II4c2LbF`7GBD%-U=Imzn1g&s+Q2wE*(ZJ*8jvBXc;mKivsL8 z+Tl|Rew*|E9a=hjGMlfYqqb38bXK9j~Db5dN1i+gH)0Q#Fz)=p%c@{<*J z{!oh8g7+&;`$Uf|mABpOo)4*Iicdi*xo3PI=;IVhupK2qty~2q|1wIIREWF#lgyY! zju$KTf|4E3wK-nUwq*Q}cS8xOn<`H{#T%EN99|t4-LFrp_%& zc;=LvllUuAY)l1D=@{Laqf#xH-8ff0jrMzbxF-7j47;?4bv4z`Rprd zu`-5dxmt&3K1dJ6$y;(r_C~hs3A9dPGse|w8<)9-R*PvJVzQzDKAaASf)18WfXu)j zHRi3tNkgVc^t*K^^&ryM2?zkpr4dF+@rH*KN{46bnJ;5*Mv#U^pnBHSU;?R4nNqx? zK~ik4Z6h7CO8IERq}&Nbw93IigXBPP7jqhWqnrB4Uv?GKsrGv6THskKy^h;foMhXJ z6AmHlBpwC#7raxPg>N|Cvk7ru5;I{>YF7K(MXtj2|c+}8qN#D&e`p_q- z7lV9j3Na-?+tLazpTL_mgC`fsHTW>calF-jyby9ciLy&5G>v+2N$soWaADOcYk|~O z<@lvDot#Uei<2BH`>hmRtqY+}?Q&e+H=N|1+T=yj5F zj!G7C&YiaInFX9rA%|1KQzdd$8sOP#N?EEdbG8D?Th(dXLauXB0#5RI)dH^b>b00! zz`0Y;Bm1C~f+GfJGRH!0wL%M}lUB=_l!Z!>Rc*^oa=DOOugE25Rx+3=agyJK)q3@# z%e->VnzCiJd~!Ub2aXh8Q*6zgQ&jJ}piD}6Tu3eS$2m8()$4Bxs2qm#EahRW){iR3 z!@WJu;!)>nO1BhLj@LKqc&WpP^Q;`#RVuYLb--Y~;!q89-#lWTU5XCJY=Lq9wQ^lu zau`ZX9m$zzF)OEY@Gzv4@@#2Nmou&QX(WZ=T*Q$(^Fo?gZI*^5AZBD>R30bc^y@MD zIJnYN4X2?0BAgR^PW&7X-0I9S*Ufl8N;_6~x}`7>Q8P#Yv(9|0e?iQm39}!*^lr2d z0o3(6;Y%OB18yCNKL`xOBH|Q&x$>u)#k&)uF5cG?Mz~J!i6Bf-*mc9s4>Q-qqDT|% z!>~~`KJ~$eAHb6XbmezQ2^mqox)4_%I4kqo36~IJrv8&4-rdSy09d(B8GtQM9dyDr ztl;H2gkJcgKC52EhW7Lqf(_Hdv{S1ibJBy5bc+CAH*m1bn3F!(P%9SKJ3EySOl1Ud z_!XN@xKcNZntsOWhwpB@qe?zI@aDQHXy2#U^}#L#_YMUUU70tgqz(Rh zU}kJxN^U|h1>nLm48ewG=8mPwl558=Q^cHylytFdJ78k^X=18aBWk{QUV~u*cr#^P zaBag^5VnlJO-VCb3rmt^!dtL{_+#m+6X#o!sBjsGqUD6XmW&Veg%ht*W%+OoL#MxyH&$!ZUs*8 zIq_rHN*aN?^(YjSRGGA$`(6V0?E_Wp1brk|pe=6*i@Z6b3-07UY{>!8 zbCq(Fu9H{Ljl85o@voksBgdhuN`V;{V^cX`tl zF_T)8lhAKe!9xzjbW^Wbx03cQxR5_H9O*w}Rk7$0$xQ$%2<8*|kGpyWbcMBhwZ4@^NNx6Bv05!1l9`;=Hia3?n+U#4Wi z5+;wMt~AyMG1E+*OfJhDvb_56#Wa)82H{2-Aq?n&J2_k@zR1;7PDgv<bz3wW3b7gtwzj>h8VTR+U9sYQbNN-$tfN~0f82!!(?xD8! zA$mDH6d!xvcJyT_!dk~~mUHamws*0k6w83sII6b#sy+@s+V+m9yQuZtptS2knCy3; zShbkB#c0>6c!t2(szmB)*(oE^JGV5>E%bc1;Dt=9N_DF4i7BT8!iT8IBB6r8-nU(= zDyLN<{_33g+Rt@31*-j7{fvb6R7%r$6^$NW9twUt`H zwY3>*wmg$$-os_=KkoTI?h!hA&;N0Uvbm*L^=MaJNYWQotbTee)95K zA+1*9QKMb;(PJ7Bn@TGR$At@ugy6q^AI_P*^}0Bg%Sek%%Z?b9BsT}?NFEa>j=IJ$Ru=+9%Q=HW;by0|hp zfgwxtf9hNzB4kQUYC)l3%OW&RqN1n zJe^8hEbkl1?v^v_;+>tbjzmYOt-C!a`@6cYSS2FYr($C)zq1gFr{((Mx`L$XSS`&< zBH78QSWeC@A-3VvHS(*F%5Aaqv^*3`U)-*d7Xm!_k8WHbui1kBvl!N5+P>3|+kD~4qrSn zI5avi*wbGg(86XQ+`oBy|K{Go?YXmidOue6%)IH%X-2UwOKLQB_ zo{u$X@oejlZXX`)4UdFrQj3V9o9Dko>ZwSsu~WZsa3ESrJ%_HI{}8Ds`Ma;7%f5f} z;MS2+@~PF#^O8tD$6}vs=;RNDw}c0xxJ!4qln3rx^88BVfoD|@Es#9uDaC2b#VeO>L*o=BkY;DLegmW%s0Zy4LKwSQD+c1oaiLG;04HWFoS2k`tvq_7oV z(YhqCWf>#>p@{e_eAPYc+b`@g-cbHXPkN95rQEUy8=8uV4zlFH%Uo)$gfy z<C7A=yFIp+8!R=E1bFl2>= z{M26-|BIJ&U3d&clH-n3r1tZWz?N0`@lc*%e(2#0NL$ApcPZVx{Nb^A4_UVGuo#lN z7Q|>e0pGa79M^Ev*v-i8e1-)2lgi6 zAzbosAw8_ekB5y|csLtoEe85+>7fU<9pPbP$wP!5dhxTAwZf*;9L3M6!&B*$dJ+7P z3@!e+r+z~A?P%_U+bJct!CXpQVc)#L7;JcFc1H1tdyAVlE{3DkvmBPL{#T=ROjrM_ z(CVt{p>_4YZt8DEKjEpNEVLvUb0;KeviP9=xLo({0NVcS^zzg<2d@5CSO05c>-4odS86_c zPchF2`jTERMBgXj9ifRm>+H?Fz4Ei&T;Rr*{>)eLD#I}v$C_JTg!mMc#6;J ztNO{lBl8Y2a)fI0)uJZgwfHy*XIJawZq;y_TY(dNPW;%ll1AWe?&+YT`*e`2|5d%I zQ^q~rS?sddt;p179#fk(RXZBw>VG8{to8l{mqNJ|>d0Q5rEF5Zt|{)u;!WYD`&_N$ zqFTb+(I!{_t9vVqdn-(Bx56x}6`gVlz0)dJA62v`W;Zs4t!jvaWTjmS^wVu2q$5 z_A#eG;IWU}-etaP`YM#p!kMc!)?;bch~8e5HZoRxxYI)K$F43}+IoMY4T(6-@tD8o zyS9$RJzVAe$GqE1lzy=~VW=L8b=;%{(Z^7(-OG&6TsUctwUH*cx#{b zX|$v8jUWrU>t{#z`k9^nPu@iPO59PeET}`pj;sF@B(6*&kE{RFnWok&T>YQ*PE>6&$&Wv*h^oH}zfE zvWZ5IhyNUXWUoO+p&w7gy~vz*^u$WDz;X5*>Rv>e+#R*>_B zv8h~k7Zlc8*lbJ5Gx^bt*-4ou-`?0{dTba9^pwxB%d*+Y=0V`vTR&XT#W*>gNhM;` zpT9koNoLE?hI55@HkM0{WT%>kfIVG5>_f3!Y*L1jzr1aJFOekZ(QPa05_PQOTJ4Fh z{@0SST1`Q%tN)eS(_Q_qmN!u03hq#6^SMt3T==anQ zeW}DN%eM;dZNNQIKivJ9!D&?!wv{Zu9mpo@hsY^?-%fp~i= zS=iZ3?d(_A54D3=`nrEd!af??Sk=ivVV@|1CBvp@`R_`?= z47-7@jwG;Z!K&4nu5Za!BfKioNg%DGU|6j>S-LzReN8yAesTJ?`-55Vr* zH~;4QAO8AHFrAj%_KU?E-we~S+i&>dyKemmOy}1`d<-Z?StOfV`F~}yFYtZ z`>IE7c^6D4Pb~T6RckMS>Beo}J$>VE>3ZS=OW%4{=i6XfpFa0h-M@PQVSo3Z$9b;# z=eNS{?_S@t=DWTdVN%lk{B1C8`H!`e-+t!LVTzuYK5@mn?}h2bCm#NbU%vTLnBMe1 zw?F)=hdv0ClA~)LfN5m#OW9i=yBwy!`R!dFxbmy-6R!XK9+=i0_no_^*8S6kOIM?a zIe*!FHGZtugmyIN;AV3P5w5M$2QyqkRDhfPB-Auqtrwd1z{PH%shNjDt78i)pEUNRO94LR`lm2&Y@s~X+-x%aF=H@8rtgEBeWpJSSL;mQ z4;R}^f5M2+kZIo9rpxpL_|!7}NzJHcnm4!|2WWl}KXNrbg{AG?xZZqhVmdXdHxCzL zxx)0+rtCzu@ifJNLqIh)TU7RJ(8%jQ1te96Kl(iA&Cc_q@c2&y*S7j+NEupv2610m z|F}hADd~R*IIfsK9IW$)=aP-;)u9yC-vUR~c~yNi>&?}1h$2(P=SP6-s`)E3ZIt;a zuI7Ux+~u`Rs-*hmbPG~e*V+vTDAu7>2(a>BFMCw}%}n4bRP|9jVSqxZv9xbq4K zVn2WscG78g9P{Nz-VVES9=`jlU-;w>n3nc^?@&|hi*Qv!jC=uhH@X z{!-wahi+NFlvhJ4}fomM8GDv#gq7vwkKYF&`ugo|xKe#?l^z_)tgrpxqm z_|!7}yk=A~eZsf#wOza0Rh=`=`}(rE$$TC5A0NZrSglr(`*in-df@5UJ+bt(JT@jR zVS4y19>CA>TG$QKsU(xzG!|X! zjy<+XJRiMe&(E8``I>ipPP*$KUcK^H9t!A88y^ovbRugq`??O6MPC%UEq&dn_w_bA zUlfaraZxa~jEiz)(HCV%OJ5YcioPg%S^A=+QuIYx#nKl$7=5u4JnUkYzSw1ozMir3 z#Wq&N$W~?**YWQ74|M6s9sl7n;9hwuCu5VMob2O{!I^Asw@O)-uPNlFYk^=A_4XGLD1;N-b_rM9rad`T;Qmqg7@VSQKDu`*hRh^ONz3L6@Hi#s3i~#r z6x49sN~(MzdGOGiLP2Swxe| z^)V4s326=Ps-2ed%00-uAvyt_y_2{Xc^Ws6@NQ(@Wt)VlK6jE3sZGANYU$c&JhSbW zyhV);l}+Ywh!1*-y2ej_>W@#IvFV=MlMmc_#;?0KN#A&ESXy!X|Axy@_OZTPWB*o(RQ~ z9_evU?;1b;_IF3SL%kh6(L={T6h-VS0{&1k(HhTVbsNEqJ3$(R$#M->wooxYcu%k2X?e+&d(HY{MZHZVQkxT{-_PQ045?yybTK}s} zbCjM9vz@^)Mf65}*EG4kB1l&Gwa3f1=|{NvRKo$a`|E#Cz{euZLOlXhjBv-ZoOr^v zE^ta!0?13P(l&)pwc*ZnKe%T3Q;Kkf)B`S?tr~tBd|16VdKY-UnwYiHN@)cme`3zk zPa0f3hBS;RoIa1=G2qJ~UAy3t!1t)+#LqTJE7bLGyti!taZ{oxcl9CeJaX^`z&kB+ zF$4Tb{AGZ@*CctwP~urdTFEHCydTY42D7sl>C)>X@kx6T3$^7)(wTqBRWrD&IwdHd1U1{H}{ z*p^bSPBL4S?);lp?g(;sb#s%z8cI|cs zNjd|mYIF(7OhrnxQq=G3k&E|Q)bHUeTah+SkTec;E|neWvnqkG|A-r3M5mF%hZeA!MmKMi^LY{Rq|eO@X_ zF^+hXHaz3C$V21sZX+dQjyNO5`!4&D1JU{gHG3V>{*gJCznwH}XJ6YK zf=KIfr1dj%POB67$B7?fIdcq{M;}$^C(WhIy;xstn3R{d^2*vccNA7z-&K!OHBPTJwraMU5_J!P z+wxXGQNE|6d>eHnNqVEs4EHNDmXpO)HzU>DefP?*2xOIgKAfAY*HRsG(tLhqI-R~i z>fTu>Os!eHI-l4nPsZ}T$y6ej&1c68KI|7*jST?fdskz-L1;DgcdW)Hw7i@tD9Z9? zACmYtRaXD&%Dl^(E$EPO@x)ELdKXp+nS<-A#>Eu2Sgp8m; zHIV)vMO&tCDjCA|T(NXiVX-iM(gp_H8o^c&+k}z28K{e*Z z<}68LkVb@V(MKv`J+PSn*U_GMrKj{h@ zSv%}>y6S1n*)*miOKyZ5t}k+;8madD2&8shOg-#*B}%N0ibJaPZ-sD=0jI0~t7gUK zw%kxpG%4lPu|BI2O@-?xfYa6gzs7Q?!jiX#${a+ShuX7erwa+LG z*wz14e`4h7|C)oC?CSq2-Pz&l|AKA_SN|7pbkVM$Q7@Wt^?zZdz5o%ytfwplJDs8l zDmu^#BFKP+94sBr*fRE>T{8;I;^4tiAqOZ5v`Jz}{^hLqgGOnXR{}=AY5)+Rl1(2_p zYQ|C3Ngbe@$)OC9T;do!?gaABEOOXbxxCTkk#G`X6

i<#|nNhvhZ1i`z`oGXY=kU1tzg+!aaqMHSUHb+#Rk-@U=Boee*N=Z;|8jMx zKP(pt&}Rtcj{BEWy%$s+t|?nfqvLRPTG9GAmCdIL+1x(pO3X}8$OT_EH$g>?;3-i4 zxCe8xYQ#d1BpnulvPn$?WiK>PrqcNaRXVw9xlrLWrz&w(lDYcd7O1j4SO41_R5uFZ zQP0-z>VKmKI9LB0H8;5W-(3A~bJqvx>VF%>Ird4M1PW-s~->9{ZI<3UXX;=T7o#p{o z|68g5*>M;<`vGt->HxGZThaDh{cm%Zlm!2vegv}~iV{x|CGP5fn=j6yuLpbHF6zP6 z|2F%vVoAG7NtXR(w+Dz*AC?Be{*uH zfStrz!`1(GIBua39HGRsjXM0TM+)j4Wv>3W+3l35t?#<} z-<kCp-sKIn#r^)yU?`C29AEUpieMt%9_k8( zaMN#M+zabYZ!F+XdON#f9c^vxp+HBV&GW(ve_MNZTQG@hrUN0|I-QIKyj|nCc%4{- za(kdF)+Qsi?$CJKc)Q%?9q**KL=xWQWVbieB_{$M3E&I_;4R)2@CU|2UEV~SKjaN| z%0VwO74#XtLBAhy9_}GeNqJ_CYMgC_XWqfXCt5i3pGjW}~l3z1dW&xZ(T2esL$Y>8fhw zQ@9;G;9uoG3{=_Bhi%j;+K=0oqJR)? z%IUz}5K+mCuXfzi)B#fv-@W+q;)bRGOmyvo$&bH2*r_VbYboCv3im)C50~N}nX-BA z@Ho2(%Y1wF?Dymt%XGK0KW75_wI@*ODQ!QPxVw8DTIEWld~Rjjj#BTzT{;1j_(9Zh zd!1wSVa74hq8gnjMlY0Np{N!|f-E+DHv%~7#Gxs_i!2OgNX`j@J z(&gi`4>w3r`B6mT>j4*aQXi$cs-BH|J5d^{JQ*qHd32WqHy{D?D_vahgtsQ zy{Hq43~IgeL)}T#b;eWoT-tH|1ETS>trV5dHCMELA9)g|EBl+{E|-M?q=?{B!Z>7^&0y(sdzZ+`3L z@r*KFG$DSOac;3Kn7nZfXT1G- + + + + + + + + + + + + diff --git a/marking_gui.Setup/Product.wxs b/marking_gui.Setup/Product.wxs new file mode 100644 index 0000000..f1bedbb --- /dev/null +++ b/marking_gui.Setup/Product.wxs @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/marking_gui/.agents/skills/laser_marking/SKILL.md b/marking_gui/.agents/skills/laser_marking/SKILL.md new file mode 100644 index 0000000..db58849 --- /dev/null +++ b/marking_gui/.agents/skills/laser_marking/SKILL.md @@ -0,0 +1,87 @@ +--- +name: laser_marking_integration +description: Guidelines and P/Invoke signatures for integrating the LMC laser marking machine via MarkEzdWrapper.dll without crashes. +--- + +# LMC 레이저 각인기 연동 규격 및 에이전트 행동 규칙 + +이 규칙은 `MarkEzdWrapper.dll` 파일과 WPF 모니터링 시스템 간의 레이저 각인(마킹) 장치 연동 설계 사양을 고정합니다. **이 사양은 어떠한 경우에도 임의로 단순 값 형식의 int 핸들이나 Ansi 마샬링으로 되돌려서는 안 되며, 반드시 이 명세를 유지해야 합니다.** + +--- + +## 1. 연동 핵심 원칙 (Core Rules) + +1. **IntPtr 기반의 기기 세션 핸들 관리**: + - `InitMarkEzd()` 함수를 최초 실행하여 생성되는 장치 관리 메모리 세션 포인터(`IntPtr`)를 받아 전역 변수에 저장합니다. + - 이후 모든 연동 API(`Init`, `LoadEzdFile`, `ChangeTextByName`, `Mark`, `Close`)의 첫 번째 매개변수로 이 `IntPtr` 핸들을 인계하여 호출해야 합니다. 임의의 정수 값(`0` 등)이나 `ref int` 를 대입하여 호출하면 메모리 위반 크래시(`AccessViolationException`)가 발생합니다. + +2. **유니코드(`CharSet.Unicode`) 마샬링 준수**: + - C++ DLL 단의 모든 문자열 인자는 `const wchar_t*` (유니코드)를 사용합니다. + - 따라서 모든 DllImport 선언의 문자셋 속성은 반드시 **`CharSet = CharSet.Unicode`** 여야 합니다. `Ansi`로 지정할 시 경로명 및 파일명이 한자 깨진 글자로 읽혀 `EZCAD.CFG failed` 에러를 냅니다. + +3. **WPF 윈도우 핸들(HWND) 지연 초기화**: + - `Init` API 호출 시 실제 유효한 부모 윈도우 핸들(`IntPtr windowHandle`)이 필요합니다. + - MainWindow의 생성자 시점에는 핸들이 미생성 상태(`IntPtr.Zero`)이므로 즉시 초기화하면 안 됩니다. + - 반드시 WPF **`Dispatcher.BeginInvoke(..., DispatcherPriority.Loaded)`** 지연 큐를 활용하여 메인 윈도우 로드가 완료된 후에 유효한 창 핸들을 추출해 이니셜라이즈 해야 합니다. + +--- + +## 2. P/Invoke 표준 선언부 (Standard C# Declarations) + +```csharp +[DllImport("MarkEzdWrapper.dll", EntryPoint = "InitMarkEzd", CallingConvention = CallingConvention.Cdecl)] +private static extern IntPtr InitMarkEzd(); + +[DllImport("MarkEzdWrapper.dll", EntryPoint = "Init", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] +private static extern int Init(IntPtr hHandle, string strEzCadPath, IntPtr hOwenWnd); + +[DllImport("MarkEzdWrapper.dll", EntryPoint = "LoadEzdFile", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] +private static extern int LoadEzdFile(IntPtr hHandle, string strEzCadFileName); + +[DllImport("MarkEzdWrapper.dll", EntryPoint = "ChangeTextByName", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] +private static extern int ChangeTextByName(IntPtr hHandle, string strTextName, string strTextNew); + +[DllImport("MarkEzdWrapper.dll", EntryPoint = "Mark", CallingConvention = CallingConvention.Cdecl)] +private static extern int Mark(IntPtr hHandle); + +[DllImport("MarkEzdWrapper.dll", EntryPoint = "Close", CallingConvention = CallingConvention.Cdecl)] +private static extern int Close(IntPtr hHandle); +``` + +--- + +## 3. 핵심 비즈니스 흐름 코드 (Core Implementation Patterns) + +### 3.1. 장치 초기화 흐름 +```csharp +// 1. 선행 엔진 초기화 및 포인터 획득 +IntPtr markingHandle = InitMarkEzd(); +if (markingHandle == IntPtr.Zero) +{ + // 보드 또는 동글 락키 인식 실패 예외 처리 + return false; +} + +// 2. WPF 메인 윈도우 실제 창 핸들 획득 (Loaded 시점) +IntPtr windowHandle = new System.Windows.Interop.WindowInteropHelper(this).Handle; + +// 3. 컨트롤러 장비 초기화 수행 +int initResult = Init(markingHandle, ezcadFolderPath, windowHandle); +if (initResult == 0) +{ + // 연결 완료 상태 전환 +} +``` + +### 3.2. 공정 각인 요청 흐름 +```csharp +// 1. 도안 로드 +int loadResult = LoadEzdFile(markingHandle, absoluteEzdPath); + +// 2. 도안 내 변수 태그 치환 (Marking.ini 매핑 기준) +ChangeTextByName(markingHandle, "SERIAL", request.Serial); +ChangeTextByName(markingHandle, "YYMMDD", request.LotNo); + +// 3. 각인 기계 동작 기동 +int markResult = Mark(markingHandle); +``` diff --git a/marking_gui/App.xaml.cs b/marking_gui/App.xaml.cs index 8231783..36ae1aa 100644 --- a/marking_gui/App.xaml.cs +++ b/marking_gui/App.xaml.cs @@ -13,12 +13,72 @@ namespace marking_gui /// public partial class App : Application { + [System.Runtime.InteropServices.DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)] + private static extern bool SetDllDirectory(string lpPathName); + protected override void OnStartup(StartupEventArgs e) { + // 바로가기 등으로 실행 시 작업 디렉토리가 꼬이는 현상을 방지하기 위해 작업 디렉토리를 실행 파일 폴더로 강제 동기화 + try + { + System.IO.Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine("작업 디렉토리 초기화 중 에러: " + ex.Message); + } + + // 전역 예외 처리 이벤트 핸들러 등록 + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + this.DispatcherUnhandledException += App_DispatcherUnhandledException; + TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; + + Services.LoggerService.Info("=================== [프로그램 시작] ==================="); + + try + { + // DLL 탐색 경로에 실행 디렉토리 하위의 libs 폴더 추가 + string libsDir = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "libs"); + if (System.IO.Directory.Exists(libsDir)) + { + SetDllDirectory(libsDir); + Services.LoggerService.Info("libs 폴더 경로 추가 완료: " + libsDir); + } + } + catch (Exception ex) + { + Services.LoggerService.Error("SetDllDirectory 설정 중 예외 발생", ex); + } + base.OnStartup(e); var mainWindow = new MainWindow(); mainWindow.Show(); } + + protected override void OnExit(ExitEventArgs e) + { + Services.LoggerService.Info("=================== [프로그램 정상 종료] ==================="); + base.OnExit(e); + } + + private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + var ex = e.ExceptionObject as Exception; + Services.LoggerService.Error("[비정상 종료] 처리되지 않은 도메인 예외 (UnhandledException) 발생", ex); + } + + private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) + { + Services.LoggerService.Error("[비정상 종료] 처리되지 않은 UI 스레드 예외 (DispatcherUnhandledException) 발생", e.Exception); + // 메인 루프를 유지하기 위해 예외를 처리된 것으로 설정 + e.Handled = true; + } + + private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) + { + Services.LoggerService.Error("[작동 오류] 처리되지 않은 비동기 태스크 예외 (UnobservedTaskException) 발생", e.Exception); + e.SetObserved(); + } } } diff --git a/marking_gui/LoginOptions.json b/marking_gui/LoginOptions.json new file mode 100644 index 0000000..15c0037 --- /dev/null +++ b/marking_gui/LoginOptions.json @@ -0,0 +1,23 @@ +{ + "loginAccounts": [ + { + "id": "su", + "password": "su" + } + ], + "makers": [ + "AMO", + "ABC" + ], + "models": [ + "MODEL-1" + ], + "variant1Values": [], + "variant2Values": [], + "lineValues": [ + "LINE-1" + ], + "jigNoValues": [ + "JIG-1" + ] +} diff --git a/marking_gui/MainWindow.xaml b/marking_gui/MainWindow.xaml index 3316cc2..861f332 100644 --- a/marking_gui/MainWindow.xaml +++ b/marking_gui/MainWindow.xaml @@ -6,6 +6,7 @@ xmlns:local="clr-namespace:marking_gui" mc:Ignorable="d" Title="양산형 테스트 기기 모니터링 시스템" Height="700" Width="900" + Icon="pack://application:,,,/Marking.ico" MinWidth="900" MinHeight="700" WindowState="Maximized" WindowStyle="None" WindowStartupLocation="CenterScreen" Background="#F3F4F6" ContentRendered="Window_ContentRendered"> @@ -111,6 +112,34 @@ + + + @@ -132,35 +161,39 @@ - + + + - - - + + + - + + + - + - + - + - + - + - + -