1 #include "stdafx.h"
2 #include <newdev.h>
3 #include <setupapi.h>
4 #include <cfgmgr32.h>
5 #include <regstr.h>
6 #include <strsafe.h>
7 #include <string.h>
8
9
10 #include <Aclapi.h>
11 #include "setup.h"
12
13 #pragma comment(lib,"Advapi32")
14
15
16 #pragma comment(lib, "newdev.lib")
17 #pragma comment(lib, "setupapi.lib")
18
19 void GetHIDList(int nInfIndex);
20
21 DWORD DeleteTree(HKEY RootKey, const WCHAR *pSubKey);
22
23 // 不带变参
24 void ULOG(TCHAR *msg)
25 {
26 OutputDebugString(_T("UsbKitApp:"));
27 OutputDebugString(msg);
28 OutputDebugString(_T("
"));
29 }
30
31 #ifdef DEBUG
32 // 带变参的Log函数
33 void UDBG(TCHAR *msg, ...)
34 {
35 TCHAR strMsg[1024];
36
37 va_list argp;
38 va_start(argp, msg);
39 _vstprintf_s(strMsg, 1024, msg, argp);
40 va_end(argp);
41 OutputDebugString(_T("UsbKitApp:"));
42 OutputDebugString(strMsg);
43 OutputDebugString(_T("
"));
44 }
45 #else
46 void UDBG(TCHAR* msg, ...)
47 {
48
49 }
50 #endif
51
52 PINF_INFO g_InfList[MAX_INF_COUNT];
53 int g_nInfMaxCount = 0;
54 int g_nInfCount = 0; // INF文件数
55
56 PHID_INFO g_HIDInfo[MAX_HID_COUNT];
57 int g_nHIDMaxCount = 0;
58 int g_nHIDCount = 0; // HID个数
59
60 HID_DEVICES g_HIDDevices;
61
62 void FreeDevices()
63 {
64 for(int i = 0; i < g_HIDDevices.nMaxCount; i++)
65 {
66 delete g_HIDDevices.asDeviceInstanceID[i];
67 }
68
69 ZeroMemory(&g_HIDDevices, sizeof(g_HIDDevices));
70 }
71
72 void FreeAllInfFiles()
73 {
74 for(int i = 0; i < g_nHIDMaxCount; i++)
75 delete g_HIDInfo[i];
76
77 g_nHIDMaxCount = g_nHIDCount = 0;
78
79 for(int i = 0; i < g_nInfMaxCount; i++)
80 delete g_InfList[i];
81
82 g_nInfMaxCount = g_nInfCount = 0;
83 }
84
85 //在特定路径下寻找所有的inf文件
86 int FindAllInfFiles(WCHAR* csDir = NULL)
87 {
88 WIN32_FIND_DATA FindFileData;
89 WCHAR dir[MAX_PATH];
90 WCHAR path[MAX_PATH];
91 HANDLE hFind = INVALID_HANDLE_VALUE;
92
93 if(csDir == NULL)
94 {
95 // 在当前路径中搜索所有inf文件
96 GetCurrentDirectory(MAX_PATH, dir);
97 //StringCchCopy(path, MAX_PATH, dir);//此函数不支持win XP SP1
98 wcscpy(path,dir);
99 }
100 else
101 {
102 if(!GetFullPathName(csDir, MAX_PATH, dir, NULL))
103 GetCurrentDirectory(MAX_PATH, dir);
104
105 //StringCchCopy(path, MAX_PATH, dir);
106
107 wcscpy(path,dir);
108 }
109
110 //StringCchCat(path, MAX_PATH, L"\*.inf");//此函数不支持win XP SP1
111 wcscat(path,L"\*.inf");
112
113 wprintf(path);
114 printf("
");
115
116 __try{
117
118 g_nInfCount = 0;
119 g_nHIDCount = 0;
120
121 // 遍历
122 hFind = FindFirstFile(path, &FindFileData);
123
124 if (hFind == INVALID_HANDLE_VALUE)
125 {
126 printf("没有发现inf文件
");
127 __leave;
128 }
129
130 do{
131 if(g_nInfCount >= g_nInfMaxCount)
132 {
133 g_InfList[g_nInfCount] = new INF_INFO;
134 g_nInfMaxCount = g_nInfCount + 1;
135 }
136
137 ZeroMemory(g_InfList[g_nInfCount], sizeof(INF_INFO));
138
139 //StringCchCopy(path, MAX_PATH, dir);
140 wcscpy(path,dir);
141 //StringCchCat(path, MAX_PATH, L"\");
142 wcscat(path,L"\");
143 //StringCchCat(path, MAX_PATH, FindFileData.cFileName);
144 wcscat(path,FindFileData.cFileName);
145 //StringCchCopy(g_InfList[g_nInfCount]->asInfName, MAX_PATH, FindFileData.cFileName);
146 wcscpy(g_InfList[g_nInfCount]->asInfName,FindFileData.cFileName);
147 //StringCchCopy(g_InfList[g_nInfCount]->asFullPath, MAX_PATH, path);
148 wcscpy(g_InfList[g_nInfCount]->asFullPath,path);
149 // 查找每个inf文件中的所有HID
150 wprintf(L"找到文件:%s
", FindFileData.cFileName);
151
152 GetHIDList(g_nInfCount);
153 g_nInfCount ++;
154
155 }while (FindNextFile(hFind, &FindFileData) != 0 && g_nInfMaxCount < MAX_INF_COUNT) ;
156
157 }
158 __finally{
159 if(hFind != INVALID_HANDLE_VALUE)
160 {
161 FindClose(hFind);
162 }
163 }
164
165 return g_nHIDCount;
166 }
167
168 //查找特定inf文件中的所有HID(硬件ID)
169 void GetHIDList(int nInfIndex)
170 {
171 INFCONTEXT infcont;
172 INFCONTEXT infcont_dev;
173
174 HINF hInf = INVALID_HANDLE_VALUE;
175 DWORD config_flags, problem, status;
176 BOOL reboot;
177 WCHAR inf_path[MAX_PATH];
178
179 WCHAR direct[MAX_PATH];
180 WCHAR manu[MAX_PATH];
181 WCHAR manu_os[MAX_PATH];
182 WCHAR hid[MAX_PATH];
183 WCHAR tmp_id[MAX_PATH];
184
185 WCHAR os[8][32];
186
187 __try
188 {
189 // 取INF路径
190 wprintf(g_InfList[nInfIndex]->asFullPath);
191 if(!GetFullPathName(g_InfList[nInfIndex]->asFullPath, MAX_PATH, inf_path, NULL))
192 {
193 printf(".inf文件 %s 未找到
", g_InfList[nInfIndex]->asInfName);
194 __leave;
195 }
196
197 wprintf(L"INF 文件路径:%s
", inf_path);
198
199 // 打开INF文件
200 hInf = SetupOpenInfFile(inf_path, NULL, INF_STYLE_WIN4, NULL);
201
202 if(hInf == INVALID_HANDLE_VALUE)
203 {
204 wprintf(L"打开文件失败:%s", inf_path);
205 __leave;
206 }
207
208 if(!SetupFindFirstLine(hInf, L"version", NULL, &infcont))
209 {
210 printf("找不到[Version]域,不是合法的Inf文件
");
211 __leave;
212 }
213
214 //
215 // 获取Version信息
216 //
217
218 do
219 {
220 if(!SetupGetStringField(&infcont, 0, direct, sizeof(direct), NULL))
221 continue;
222
223 _wcslwr(direct);//把字符串转为小写
224 if(0 == wcscmp(direct, L"class"))
225 {
226 if(SetupGetStringField(&infcont, 1, direct, sizeof(direct), NULL))
227 {
228 //StringCchCopy(g_InfList[nInfIndex]->asClassName, MAX_PATH, direct);
229 wcscpy(g_InfList[nInfIndex]->asClassName,direct);
230 }
231 }
232 else if(0 == wcscmp(direct, L"driverver"))
233 {
234 if(SetupGetStringField(&infcont, 1, direct, sizeof(direct), NULL))
235 {
236 //StringCchCopy(g_InfList[nInfIndex]->asVersion, MAX_PATH, direct);
237 wcscpy(g_InfList[nInfIndex]->asVersion,direct);
238
239 if(SetupGetStringField(&infcont, 2, direct, sizeof(direct), NULL))
240 {
241 //StringCchCat(g_InfList[nInfIndex]->asVersion, MAX_PATH, L", ");
242 wcscat(g_InfList[nInfIndex]->asVersion,L", ");
243 //StringCchCat(g_InfList[nInfIndex]->asVersion, MAX_PATH, direct);
244 wcscat(g_InfList[nInfIndex]->asVersion,direct);
245 }
246 }
247 }
248 else if(0 == wcscmp(direct, L"provider"))
249 {
250 if(SetupGetStringField(&infcont, 1, direct, sizeof(direct), NULL))
251 {
252 //StringCchCopy(g_InfList[nInfIndex]->asProvider, MAX_PATH, direct);
253 wcscpy(g_InfList[nInfIndex]->asProvider,direct);
254 }
255 }
256 else if(wcsstr(direct, L"catalogfile"))//返回第一个子字符创的指针
257 {
258 if(SetupGetStringField(&infcont, 1, direct, sizeof(direct), NULL))
259 {
260 //StringCchCopy(g_InfList[nInfIndex]->asDSign, MAX_PATH, direct);
261 wcscpy(g_InfList[nInfIndex]->asDSign,direct);
262 }
263 }
264 } while (SetupFindNextLine(&infcont, &infcont));
265
266 printf("INF 信息:
");
267 wprintf(L"%s
", g_InfList[nInfIndex]->asClassName);
268 wprintf(L"%s
", g_InfList[nInfIndex]->asProvider);
269 wprintf(L"%s
", g_InfList[nInfIndex]->asDSign);
270 wprintf(L"%s
", g_InfList[nInfIndex]->asVersion);
271
272 if(g_nHIDMaxCount >= MAX_HID_COUNT)
273 __leave;
274
275 //
276 // 搜索设备描述符
277 //
278
279 if(!SetupFindFirstLine(hInf, L"Manufacturer", NULL, &infcont))
280 {
281 printf("没有可用设备描述符
");
282 __leave;
283 }
284
285 SYSTEM_INFO siSysInfo;
286 GetSystemInfo(&siSysInfo);
287
288 do{
289 int i = 0;
290 int j = 0;
291
292 // 一行行搜索
293 if(!SetupGetStringField(&infcont, 1, manu, sizeof(manu), NULL))
294 {
295 continue;
296 }
297
298 wprintf(manu);
299
300 printf("
");
301
302 for(; i < 4; i++)
303 {
304 if(!SetupGetStringField(&infcont, i+2, os[i], sizeof(os[0]), NULL))
305 break;
306 else
307 printf("OS: %s
", os[i]);
308
309 _wcslwr(os[i]);
310 }
311
312 // 寻找最佳的平台匹配
313 if(siSysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) // X64
314 {
315 for(; j < i; j++)
316 {
317 if(wcscmp(os[j], L"ntamd64"))
318 {
319 //StringCchCopy(manu_os, sizeof(manu_os), manu);
320 wcscpy(manu_os,manu);
321 //StringCchCat(manu_os, sizeof(manu_os), L".");
322 wcscat(manu_os,L".");
323 //StringCchCat(manu_os, sizeof(manu_os), os[j]);
324 wcscat(manu_os,os[i]);
325
326 // 如果找到[XXX.ntamd64],就用它;否则去掉os后缀
327 if(SetupFindFirstLine(hInf, manu_os, NULL, &infcont_dev))
328 //StringCchCopy(manu, sizeof(manu), manu_os);
329 wcscpy(manu,manu_os);
330
331 break;
332 }
333 }
334 }
335 else if(siSysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
336 {
337 for(; j < i; j++)
338 {
339 if(0 == wcsstr(os[j], L"ntia64"))
340 {
341 //StringCchCopy(manu_os, sizeof(manu_os), manu);
342 wcscpy(manu_os,manu);
343 //StringCchCat(manu_os, sizeof(manu_os), L".");
344 wcscat(manu_os,L".");
345 //StringCchCat(manu_os, sizeof(manu_os), os[j]);
346 wcscat(manu_os,os[j]);
347
348 // 如果找到[XXX.ntamd64],就用它;否则去掉os后缀
349 if(SetupFindFirstLine(hInf, manu_os, NULL, &infcont_dev))
350 //StringCchCopy(manu, sizeof(manu), manu_os);
351 wcscpy(manu,manu_os);
352
353 break;
354 }
355 }
356 }
357 else if(siSysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
358 {
359 for(; j < i; j++)
360 {
361 if(0 == wcsstr(os[j], L"ntx86"))
362 {
363 //StringCchCopy(manu_os, sizeof(manu_os), manu);
364 wcscpy(manu_os,manu);
365 //StringCchCat(manu_os, sizeof(manu_os), L".");
366 wcscat(manu_os,L".");
367 //StringCchCat(manu_os, sizeof(manu_os), os[j]);
368 wcscat(manu_os,os[j]);
369 wprintf(manu_os);
370 printf("
");
371 // 如果找到[XXX.ntamd64],就用它;否则去掉os后缀
372 if(SetupFindFirstLine(hInf, manu_os, NULL, &infcont_dev))
373 //StringCchCopy(manu, sizeof(manu), manu_os);
374 wcscpy(manu,manu_os);
375
376 break;
377 }
378 }
379 }
380
381 // 最后,如果最符合的版本没有找到,就看看.nt有没有
382 if(NULL == wcsstr(manu, L".ntx86") &&
383 NULL == wcsstr(manu, L".ntia64") &&
384 NULL == wcsstr(manu, L".ntamd64"))
385 {
386 for(j = 0; j < i; j++)
387 {
388 if(0 == wcsstr(os[j], L".nt"))
389 {
390 //StringCchCopy(manu_os, sizeof(manu_os), manu);
391 wcscpy(manu_os,manu);
392 //StringCchCat(manu_os, sizeof(manu_os), L".");
393 wcscat(manu_os,L".");
394 //StringCchCat(manu_os, sizeof(manu_os), os[j]);
395 wcscat(manu_os,os[j]);
396
397 // 如果找到[XXX.ntamd64],就用它;否则去掉os后缀
398 if(SetupFindFirstLine(hInf, manu_os, NULL, &infcont_dev))
399 //StringCchCopy(manu, sizeof(manu), manu_os);
400 wcscpy(manu,manu_os);
401
402 break;
403 }
404 }
405 }
406
407 wprintf(L"设备域名:%s
", manu);
408 if(!SetupFindFirstLine(hInf, manu, NULL, &infcont_dev))
409 {
410 printf("找不到设备模块
");
411 continue;
412 }
413
414 do{
415 if(!SetupGetStringField(&infcont_dev, 2, hid, sizeof(hid), NULL))
416 continue;
417
418 // 保存HID记录
419 //
420
421 _wcslwr(hid);
422 wprintf(L"HID: %s
", hid);
423
424 if(g_nHIDMaxCount <= g_nHIDCount)
425 {
426 g_HIDInfo[g_nHIDCount] = new HID_INFO;
427 g_nHIDMaxCount = g_nHIDCount + 1;
428 }
429
430 ZeroMemory(g_HIDInfo[g_nHIDCount], sizeof(HID_INFO));
431 //StringCchCopy(g_HIDInfo[g_nHIDCount]->asHID, MAX_PATH, hid);
432 wcscpy(g_HIDInfo[g_nHIDCount]->asHID,hid);
433 g_HIDInfo[g_nHIDCount]->nInfNum = nInfIndex;
434 g_nHIDCount++;
435
436 }while(SetupFindNextLine(&infcont_dev, &infcont_dev) && g_nHIDMaxCount < MAX_HID_COUNT);
437
438 // 获取下一个设备ID
439 }while(SetupFindNextLine(&infcont, &infcont) && g_nHIDMaxCount < MAX_HID_COUNT);
440 }
441 __finally
442 {
443 if(hInf != INVALID_HANDLE_VALUE)
444 SetupCloseInfFile(hInf);
445 }
446 }
447
448 BOOL Reboot()
449 {
450 HANDLE Token = NULL;
451 TOKEN_PRIVILEGES NewPrivileges;
452 LUID Luid;
453
454 __try
455 {
456 // 使能ShutDown特权
457 if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&Token))
458 __leave;
459
460 if(!LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME,&Luid))
461 __leave;
462
463 NewPrivileges.PrivilegeCount = 1;
464 NewPrivileges.Privileges[0].Luid = Luid;
465 NewPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
466
467 AdjustTokenPrivileges(Token, FALSE, &NewPrivileges, 0, NULL, NULL);
468 }
469 __finally
470 {
471 if(Token) CloseHandle(Token);
472 }
473
474 //尝试重启
475 return InitiateSystemShutdownEx(NULL, NULL, 0, FALSE, TRUE, REASON_PLANNED_FLAG | REASON_HWINSTALL);
476 }
477
478 // 删除设备对应的驱动程序,调用SetupDiCallClassInstaller函数,并执行DIF_REMOVE动作
479 // 参数Devs和DevInfo用来唯一标识目标设备
480 bool RemoveDevice(__in HDEVINFO Devs, __in PSP_DEVINFO_DATA DevInfo)
481 {
482 UDBG(_T("[RemoveDriverForSpecifiedDevice]"));
483
484 SP_REMOVEDEVICE_PARAMS rmdParams;
485 SP_DEVINSTALL_PARAMS devParams;
486
487 rmdParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
488 rmdParams.ClassInstallHeader.InstallFunction = DIF_REMOVE;
489 rmdParams.Scope = DI_REMOVEDEVICE_GLOBAL;
490 rmdParams.HwProfile = 0;
491
492 if(SetupDiSetClassInstallParams(Devs, DevInfo, &rmdParams.ClassInstallHeader, sizeof(rmdParams)) &&
493 SetupDiCallClassInstaller(DIF_REMOVE, Devs, DevInfo))
494 {
495 wprintf(_T("卸载驱动成功
"));
496
497 // 检查是否需要重启机器
498 devParams.cbSize = sizeof(devParams);
499 if(SetupDiGetDeviceInstallParams(Devs, DevInfo, &devParams) &&
500 (devParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT)))
501 {
502 g_HIDDevices.bNeedReboot = true;
503 }
504
505 return true;
506 }
507
508 return false;
509 }
510
511 void RemoveDevices()
512 {
513 HDEVINFO dev_info;
514 SP_DEVINFO_DATA dev_info_data;
515 int nDevIndex;
516 WCHAR id[MAX_PATH];
517
518 g_HIDDevices.bNeedReboot = false;
519
520 // 寻找所有设备,设置Flag值为DIGCF_ALLCLASSES。
521 dev_info = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES);
522
523 // class名无效
524 if(dev_info == INVALID_HANDLE_VALUE)
525 {
526 printf("无效的HDEVINFO句柄
");
527 return;
528 }
529
530 nDevIndex = 0;
531
532 // 枚举设备
533 dev_info_data.cbSize = sizeof(dev_info_data);
534 while(SetupDiEnumDeviceInfo(dev_info, nDevIndex, &dev_info_data))
535 {
536 if(CR_SUCCESS != CM_Get_Device_ID(dev_info_data.DevInst, id, MAX_PATH, 0))
537 continue;
538
539 _wcslwr(id);
540
541 for(int i = 0; i < g_HIDDevices.nCount; i++)
542 {
543 if(g_HIDDevices.bWillBeDelete[i] &&
544 0 == wcscmp(id, g_HIDDevices.asDeviceInstanceID[i]))
545 {
546 wprintf(id);
547 printf("
");
548 g_HIDDevices.bSuccess[i] = RemoveDevice(dev_info, &dev_info_data);
549 }
550 }
551
552 nDevIndex++;
553 }
554
555 SetupDiDestroyDeviceInfoList(dev_info);
556 }
557
558 //该函数主要就是根据硬件ID查找在本地机器上有没有这样一个设备,
559 把查找到的ID放到全局变量中,还检测设备有没有连接系统
560 void FindAllDevices(const WCHAR* asHID)
561 {
562 HDEVINFO dev_info;
563 SP_DEVINFO_DATA dev_info_data;
564
565 int nDevIndex;
566 WCHAR id[MAX_PATH];
567 WCHAR *p;
568 ULONG problem;
569 ULONG status;
570
571 WCHAR* ashid = _wcsdup(asHID);
572 _wcslwr(ashid);//转换ashid中的大写字母
573
574 printf("FindAllDevices
");
575
576 g_HIDDevices.nCount = 0;
577
578 // 寻找所有设备,设置Flag值为DIGCF_ALLCLASSES。
579 dev_info = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES);
580
581 // class名无效
582 if(dev_info == INVALID_HANDLE_VALUE)
583 {
584 printf("无效的HDEVINFO句柄
");
585 free(ashid);
586 return;
587 }
588
589 nDevIndex = 0;
590
591 // 枚举设备,从0开始枚举设备
592 dev_info_data.cbSize = sizeof(dev_info_data);
593 while(SetupDiEnumDeviceInfo(dev_info, nDevIndex, &dev_info_data))
594 {
595 if(CR_SUCCESS != CM_Get_Device_ID(dev_info_data.DevInst, id, MAX_PATH, 0))
596 continue;
597
598 (id);
599 if(wcsstr(id, ashid))
600 {
601 if(g_HIDDevices.nCount >= g_HIDDevices.nMaxCount)
602 {
603 g_HIDDevices.asDeviceInstanceID[g_HIDDevices.nMaxCount] = new WCHAR[MAX_PATH];
604 g_HIDDevices.nMaxCount++;
605 }
606
607 // Device实例ID。把id拷贝到parameter 1中
608 //StringCchCopy(g_HIDDevices.asDeviceInstanceID[g_HIDDevices.nCount], MAX_PATH, id);
609 wcscpy(g_HIDDevices.asDeviceInstanceID[g_HIDDevices.nCount],id);
610 // 连接状态
611 g_HIDDevices.bLink[g_HIDDevices.nCount] = false;
612 if(CM_Get_DevNode_Status(&status,
613 &problem,
614 dev_info_data.DevInst,
615 0) != CR_NO_SUCH_DEVINST)
616 {
617 g_HIDDevices.bLink[g_HIDDevices.nCount] = true;
618 }
619
620 g_HIDDevices.nCount++;
621 }
622
623 nDevIndex++;
624 }
625
626 SetupDiDestroyDeviceInfoList(dev_info);
627 free(ashid);
628 }
629
630 void InstallDriver()
631 {
632 HDEVINFO dev_info;
633 SP_DEVINFO_DATA dev_info_data;
634 int nDevIndex;
635 WCHAR id[MAX_PATH];
636 WCHAR tmp_id[MAX_PATH];
637 WCHAR *p;
638 ULONG problem;
639 ULONG status;
640 int nInfIndex;
641
642 for(nInfIndex = 0; nInfIndex < g_nInfCount; nInfIndex++)
643 {
644 if(false == g_InfList[nInfIndex]->bWillBeInstall)
645 continue;
646
647 // 拷贝INF文件(预安装到Driver Store中)
648 wprintf(L"Parameter 1 is %s
",g_InfList[nInfIndex] ->asFullPath);
649 //getch();
650 //wprintf(L"Parameter 1 is %s
",g_InfList[nInfIndex] ->asDesPath);
651 if(FALSE == SetupCopyOEMInf(g_InfList[nInfIndex]->asFullPath, NULL, SPOST_PATH,0,
652 0, 0,
653 NULL, NULL))
654 {
655 printf("SetCopyOEMInf1 Error Code is %d
",GetLastError());
656
657 if(GetLastError() == ERROR_FILE_EXISTS)
658 {
659 g_InfList[nInfIndex]->nResultInstall = 1;
660 wprintf(L"located in inf dir's name:%s
",g_InfList[nInfIndex]->asDesPath);
661
662 PWCHAR pSubStr1,pSubWork1;
663 WCHAR OemFileName3[128];
664
665 if(NULL != (pSubStr1 = wcsstr((wchar_t*)g_InfList[nInfIndex]->asDesPath,L"oem")))
666 {
667 pSubWork1 = pSubStr1;
668
669 while((*pSubWork1) != 'f')
670 {
671 pSubWork1++;
672 }
673
674 pSubWork1++;
675
676 *pSubWork1 = '