altosui: Add windows installer build using 'nsis'
[fw/altos] / ao-tools / altosui / Instdrv / NSIS / Contrib / InstDrv / InstDrv.c
1 /*\r
2 \r
3 InstDrv.dll - Installs or Removes Device Drivers\r
4 \r
5 Copyright © 2003 Jan Kiszka (Jan.Kiszka@web.de)\r
6 \r
7 This software is provided 'as-is', without any express or implied\r
8 warranty. In no event will the authors be held liable for any damages\r
9 arising from the use of this software.\r
10 \r
11 Permission is granted to anyone to use this software for any purpose,\r
12 including commercial applications, and to alter it and redistribute\r
13 it freely, subject to the following restrictions:\r
14 \r
15 1. The origin of this software must not be misrepresented; \r
16    you must not claim that you wrote the original software.\r
17    If you use this software in a product, an acknowledgment in the\r
18    product documentation would be appreciated but is not required.\r
19 2. Altered versions must be plainly marked as such,\r
20    and must not be misrepresented as being the original software.\r
21 3. This notice may not be removed or altered from any distribution.\r
22 \r
23 */\r
24 \r
25 \r
26 #include <windows.h>\r
27 #include <setupapi.h>\r
28 #include <newdev.h>\r
29 #include "../exdll/exdll.h"\r
30 \r
31 \r
32 char    paramBuf[1024];\r
33 GUID    devClass;\r
34 char    hwIdBuf[1024];\r
35 int     initialized = 0;\r
36 \r
37 \r
38 \r
39 void* memset(void* dst, int val, unsigned int len)\r
40 {\r
41     while (len-- > 0)\r
42         *((char *)dst)++ = val;\r
43 \r
44     return NULL;\r
45 }\r
46 \r
47 \r
48 \r
49 void* memcpy(void* dst, const void* src, unsigned int len)\r
50 {\r
51     while (len-- > 0)\r
52         *((char *)dst)++ = *((char *)src)++;\r
53 \r
54     return NULL;\r
55 }\r
56 \r
57 \r
58 \r
59 int HexCharToInt(char c)\r
60 {\r
61     if ((c >= '0') && (c <= '9'))\r
62         return c - '0';\r
63     else if ((c >= 'a') && (c <= 'f'))\r
64         return c - 'a' + 10;\r
65     else if ((c >= 'A') && (c <= 'F'))\r
66         return c - 'A' + 10;\r
67     else\r
68         return -1;\r
69 }\r
70 \r
71 \r
72 \r
73 BOOLEAN HexStringToUInt(char* str, int width, void* valBuf)\r
74 {\r
75     int i, val;\r
76 \r
77 \r
78     for (i = width - 4; i >= 0; i -= 4)\r
79     {\r
80         val = HexCharToInt(*str++);\r
81         if (val < 0)\r
82             return FALSE;\r
83         *(unsigned int *)valBuf += val << i;\r
84     }\r
85 \r
86     return TRUE;\r
87 }\r
88 \r
89 \r
90 \r
91 BOOLEAN StringToGUID(char* guidStr, GUID* pGuid)\r
92 {\r
93     int i;\r
94 \r
95 \r
96     memset(pGuid, 0, sizeof(GUID));\r
97 \r
98     if (*guidStr++ != '{')\r
99         return FALSE;\r
100 \r
101     if (!HexStringToUInt(guidStr, 32, &pGuid->Data1))\r
102         return FALSE;\r
103     guidStr += 8;\r
104 \r
105     if (*guidStr++ != '-')\r
106         return FALSE;\r
107 \r
108     if (!HexStringToUInt(guidStr, 16, &pGuid->Data2))\r
109         return FALSE;\r
110     guidStr += 4;\r
111 \r
112     if (*guidStr++ != '-')\r
113         return FALSE;\r
114 \r
115     if (!HexStringToUInt(guidStr, 16, &pGuid->Data3))\r
116         return FALSE;\r
117     guidStr += 4;\r
118 \r
119     if (*guidStr++ != '-')\r
120         return FALSE;\r
121 \r
122     for (i = 0; i < 2; i++)\r
123     {\r
124         if (!HexStringToUInt(guidStr, 8, &pGuid->Data4[i]))\r
125             return FALSE;\r
126         guidStr += 2;\r
127     }\r
128 \r
129     if (*guidStr++ != '-')\r
130         return FALSE;\r
131 \r
132     for (i = 2; i < 8; i++)\r
133     {\r
134         if (!HexStringToUInt(guidStr, 8, &pGuid->Data4[i]))\r
135             return FALSE;\r
136         guidStr += 2;\r
137     }\r
138 \r
139     if (*guidStr++ != '}')\r
140         return FALSE;\r
141 \r
142     return TRUE;\r
143 }\r
144 \r
145 \r
146 \r
147 DWORD FindNextDevice(HDEVINFO devInfoSet, SP_DEVINFO_DATA* pDevInfoData, DWORD* pIndex)\r
148 {\r
149     DWORD   buffersize = 0;\r
150     LPTSTR  buffer     = NULL;\r
151     DWORD   dataType;\r
152     DWORD   result;\r
153 \r
154 \r
155     while (1)\r
156     {\r
157         if (!SetupDiEnumDeviceInfo(devInfoSet, (*pIndex)++, pDevInfoData))\r
158         {\r
159             result = GetLastError();\r
160             break;\r
161         }\r
162 \r
163       GetDeviceRegistryProperty:\r
164         if (!SetupDiGetDeviceRegistryProperty(devInfoSet, pDevInfoData, SPDRP_HARDWAREID,\r
165                                               &dataType, (PBYTE)buffer, buffersize,\r
166                                               &buffersize))\r
167         {\r
168             result = GetLastError();\r
169 \r
170             if (result == ERROR_INSUFFICIENT_BUFFER)\r
171             {\r
172                 if (buffer != NULL)\r
173                     LocalFree(buffer);\r
174 \r
175                 buffer = (LPTSTR)LocalAlloc(LPTR, buffersize);\r
176 \r
177                 if (buffer == NULL)\r
178                     break;\r
179 \r
180                 goto GetDeviceRegistryProperty;\r
181             }\r
182             else if (result == ERROR_INVALID_DATA)\r
183                 continue;   // ignore invalid entries\r
184             else\r
185                 break;      // break on other errors\r
186         }\r
187 \r
188         if (lstrcmpi(buffer, hwIdBuf) == 0)\r
189         {\r
190             result  = 0;\r
191             break;\r
192         }\r
193     }\r
194 \r
195     if (buffer != NULL)\r
196         LocalFree(buffer);\r
197 \r
198     return result;\r
199 }\r
200 \r
201 \r
202 \r
203 DWORD FindFirstDevice(HWND hwndParent, const GUID* pDevClass, const LPTSTR hwId,\r
204                       HDEVINFO* pDevInfoSet, SP_DEVINFO_DATA* pDevInfoData,\r
205                       DWORD *pIndex, DWORD flags)\r
206 {\r
207     DWORD   result;\r
208 \r
209 \r
210     *pDevInfoSet = SetupDiGetClassDevs((GUID*)pDevClass, NULL, hwndParent, flags);\r
211     if (*pDevInfoSet == INVALID_HANDLE_VALUE)\r
212         return GetLastError();\r
213 \r
214     pDevInfoData->cbSize = sizeof(SP_DEVINFO_DATA);\r
215     *pIndex = 0;\r
216 \r
217     result = FindNextDevice(*pDevInfoSet, pDevInfoData, pIndex);\r
218 \r
219     if (result != 0)\r
220         SetupDiDestroyDeviceInfoList(*pDevInfoSet);\r
221 \r
222     return result;\r
223 }\r
224 \r
225 \r
226 \r
227 /*\r
228  * InstDrv::InitDriverSetup devClass drvHWID\r
229  *\r
230  *  devClass    - GUID of the driver's device setup class\r
231  *  drvHWID     - Hardware ID of the supported device\r
232  *\r
233  * Return:\r
234  *  result      - error message, empty on success\r
235  */\r
236 void __declspec(dllexport) InitDriverSetup(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
237 {\r
238     EXDLL_INIT();\r
239 \r
240     /* convert class GUID */\r
241     popstring(paramBuf);\r
242 \r
243     if (!StringToGUID(paramBuf, &devClass))\r
244     {\r
245         popstring(paramBuf);\r
246         pushstring("Invalid GUID!");\r
247         return;\r
248     }\r
249 \r
250     /* get hardware ID */\r
251     memset(hwIdBuf, 0, sizeof(hwIdBuf));\r
252     popstring(hwIdBuf);\r
253 \r
254     initialized = 1;\r
255     pushstring("");\r
256 }\r
257 \r
258 \r
259 \r
260 /*\r
261  * InstDrv::CountDevices\r
262  *\r
263  * Return:\r
264  *  result      - Number of installed devices the driver supports\r
265  */\r
266 void __declspec(dllexport) CountDevices(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
267 {\r
268     HDEVINFO            devInfoSet;\r
269     SP_DEVINFO_DATA     devInfoData;\r
270     int                 count = 0;\r
271     char                countBuf[16];\r
272     DWORD               index;\r
273     DWORD               result;\r
274 \r
275 \r
276     EXDLL_INIT();\r
277 \r
278     if (!initialized)\r
279     {\r
280         pushstring("Fatal error!");\r
281         return;\r
282     }\r
283 \r
284     result = FindFirstDevice(hwndParent, &devClass, hwIdBuf, &devInfoSet, &devInfoData,\r
285                              &index, DIGCF_PRESENT);\r
286     if (result != 0)\r
287     {\r
288         pushstring("0");\r
289         return;\r
290     }\r
291 \r
292     do\r
293     {\r
294         count++;\r
295     } while (FindNextDevice(devInfoSet, &devInfoData, &index) == 0);\r
296 \r
297     SetupDiDestroyDeviceInfoList(devInfoSet);\r
298 \r
299     wsprintf(countBuf, "%d", count);\r
300     pushstring(countBuf);\r
301 }\r
302 \r
303 \r
304 \r
305 /*\r
306  * InstDrv::CreateDevice\r
307  *\r
308  * Return:\r
309  *  result      - Windows error code\r
310  */\r
311 void __declspec(dllexport) CreateDevice(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
312 {\r
313     HDEVINFO            devInfoSet;\r
314     SP_DEVINFO_DATA     devInfoData;\r
315     DWORD               result = 0;\r
316     char                resultBuf[16];\r
317 \r
318 \r
319     EXDLL_INIT();\r
320 \r
321     if (!initialized)\r
322     {\r
323         pushstring("Fatal error!");\r
324         return;\r
325     }\r
326 \r
327     devInfoSet = SetupDiCreateDeviceInfoList(&devClass, hwndParent);\r
328     if (devInfoSet == INVALID_HANDLE_VALUE)\r
329     {\r
330         wsprintf(resultBuf, "%08X", GetLastError());\r
331         pushstring(resultBuf);\r
332         return;\r
333     }\r
334 \r
335     devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);\r
336     if (!SetupDiCreateDeviceInfo(devInfoSet, hwIdBuf, &devClass, NULL,\r
337                                  hwndParent, DICD_GENERATE_ID, &devInfoData))\r
338     {\r
339         result = GetLastError();\r
340         goto InstallCleanup;\r
341     }\r
342 \r
343     if (!SetupDiSetDeviceRegistryProperty(devInfoSet, &devInfoData, SPDRP_HARDWAREID,\r
344                                           hwIdBuf, (lstrlen(hwIdBuf)+2)*sizeof(TCHAR))) \r
345     {\r
346         result = GetLastError();\r
347         goto InstallCleanup;\r
348     }\r
349 \r
350     if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, devInfoSet, &devInfoData))\r
351         result = GetLastError();\r
352 \r
353   InstallCleanup:\r
354     SetupDiDestroyDeviceInfoList(devInfoSet);\r
355 \r
356     wsprintf(resultBuf, "%08X", result);\r
357     pushstring(resultBuf);\r
358 }\r
359 \r
360 \r
361 \r
362 /*\r
363  * InstDrv::InstallDriver infPath\r
364  *\r
365  * Return:\r
366  *  result      - Windows error code\r
367  *  reboot      - non-zero if reboot is required\r
368  */\r
369 void __declspec(dllexport) InstallDriver(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
370 {\r
371     char    resultBuf[16];\r
372     BOOL    reboot;\r
373 \r
374 \r
375     EXDLL_INIT();\r
376     popstring(paramBuf);\r
377 \r
378     if (!initialized)\r
379     {\r
380         pushstring("Fatal error!");\r
381         return;\r
382     }\r
383 \r
384     if (!UpdateDriverForPlugAndPlayDevices(hwndParent, hwIdBuf, paramBuf,\r
385                                            INSTALLFLAG_FORCE, &reboot))\r
386     {\r
387         wsprintf(resultBuf, "%08X", GetLastError());\r
388         pushstring(resultBuf);\r
389     }\r
390     else\r
391     {\r
392         wsprintf(resultBuf, "%d", reboot);\r
393         pushstring(resultBuf);\r
394         pushstring("00000000");\r
395     }\r
396 }\r
397 \r
398 \r
399 \r
400 /*\r
401  * InstDrv::DeleteOemInfFiles\r
402  *\r
403  * Return:\r
404  *  result      - Windows error code\r
405  *  oeminf      - Path of the deleted devices setup file (oemXX.inf)\r
406  *  oempnf      - Path of the deleted devices setup file (oemXX.pnf)\r
407  */\r
408 void __declspec(dllexport) DeleteOemInfFiles(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
409 {\r
410     HDEVINFO                devInfo;\r
411     SP_DEVINFO_DATA         devInfoData;\r
412     SP_DRVINFO_DATA         drvInfoData;\r
413     SP_DRVINFO_DETAIL_DATA  drvInfoDetail;\r
414     DWORD                   index;\r
415     DWORD                   result;\r
416     char                    resultBuf[16];\r
417 \r
418 \r
419     if (!initialized)\r
420     {\r
421         pushstring("Fatal error!");\r
422         return;\r
423     }\r
424 \r
425     result = FindFirstDevice(NULL, &devClass, hwIdBuf, &devInfo, &devInfoData, &index, 0);\r
426     if (result != 0)\r
427         goto Cleanup1;\r
428 \r
429     if (!SetupDiBuildDriverInfoList(devInfo, &devInfoData, SPDIT_COMPATDRIVER))\r
430     {\r
431         result = GetLastError();\r
432         goto Cleanup2;\r
433     }\r
434 \r
435     drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA);\r
436     drvInfoDetail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);\r
437 \r
438     if (!SetupDiEnumDriverInfo(devInfo, &devInfoData, SPDIT_COMPATDRIVER, 0, &drvInfoData))\r
439     {\r
440         result = GetLastError();\r
441         goto Cleanup3;\r
442     }\r
443 \r
444     if (!SetupDiGetDriverInfoDetail(devInfo, &devInfoData, &drvInfoData,\r
445                                     &drvInfoDetail, sizeof(drvInfoDetail), NULL))\r
446     {\r
447         result = GetLastError();\r
448 \r
449         if (result != ERROR_INSUFFICIENT_BUFFER)\r
450             goto Cleanup3;\r
451 \r
452         result = 0;\r
453     }\r
454 \r
455     pushstring(drvInfoDetail.InfFileName);\r
456     if (!DeleteFile(drvInfoDetail.InfFileName))\r
457         result = GetLastError();\r
458     else\r
459     {\r
460         index = lstrlen(drvInfoDetail.InfFileName);\r
461         if (index > 3)\r
462         {\r
463             lstrcpy(drvInfoDetail.InfFileName+index-3, "pnf");\r
464             pushstring(drvInfoDetail.InfFileName);\r
465             if (!DeleteFile(drvInfoDetail.InfFileName))\r
466                 result = GetLastError();\r
467         }\r
468     }\r
469 \r
470   Cleanup3:\r
471     SetupDiDestroyDriverInfoList(devInfo, &devInfoData, SPDIT_COMPATDRIVER);\r
472 \r
473   Cleanup2:\r
474     SetupDiDestroyDeviceInfoList(devInfo);\r
475 \r
476   Cleanup1:\r
477     wsprintf(resultBuf, "%08X", result);\r
478     pushstring(resultBuf);\r
479 }\r
480 \r
481 \r
482 \r
483 /*\r
484  * InstDrv::RemoveAllDevices\r
485  *\r
486  * Return:\r
487  *  result      - Windows error code\r
488  *  reboot      - non-zero if reboot is required\r
489  */\r
490 void __declspec(dllexport) RemoveAllDevices(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
491 {\r
492     HDEVINFO                devInfo;\r
493     SP_DEVINFO_DATA         devInfoData;\r
494     DWORD                   index;\r
495     DWORD                   result;\r
496     char                    resultBuf[16];\r
497     BOOL                    reboot = FALSE;\r
498     SP_DEVINSTALL_PARAMS    instParams;\r
499 \r
500 \r
501     EXDLL_INIT();\r
502 \r
503     if (!initialized)\r
504     {\r
505         pushstring("Fatal error!");\r
506         return;\r
507     }\r
508 \r
509     result = FindFirstDevice(NULL, &devClass, hwIdBuf, &devInfo, &devInfoData, &index, 0);\r
510     if (result != 0)\r
511         goto Cleanup1;\r
512 \r
513     do\r
514     {\r
515         if (!SetupDiCallClassInstaller(DIF_REMOVE, devInfo, &devInfoData))\r
516         {\r
517             result = GetLastError();\r
518             break;\r
519         }\r
520 \r
521         instParams.cbSize = sizeof(instParams);\r
522         if (!reboot &&\r
523             SetupDiGetDeviceInstallParams(devInfo, &devInfoData, &instParams) &&\r
524             ((instParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT)) != 0))\r
525         {\r
526             reboot = TRUE;\r
527         }\r
528 \r
529         result = FindNextDevice(devInfo, &devInfoData, &index);\r
530     } while (result == 0);\r
531 \r
532     SetupDiDestroyDeviceInfoList(devInfo);\r
533 \r
534   Cleanup1:\r
535     if ((result == 0) || (result == ERROR_NO_MORE_ITEMS))\r
536     {\r
537         wsprintf(resultBuf, "%d", reboot);\r
538         pushstring(resultBuf);\r
539         pushstring("00000000");\r
540     }\r
541     else\r
542     {\r
543         wsprintf(resultBuf, "%08X", result);\r
544         pushstring(resultBuf);\r
545     }\r
546 }\r
547 \r
548 \r
549 \r
550 /*\r
551  * InstDrv::StartSystemService serviceName\r
552  *\r
553  * Return:\r
554  *  result      - Windows error code\r
555  */\r
556 void __declspec(dllexport) StartSystemService(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
557 {\r
558     SC_HANDLE       managerHndl;\r
559     SC_HANDLE       svcHndl;\r
560     SERVICE_STATUS  svcStatus;\r
561     DWORD           oldCheckPoint;\r
562     DWORD           result;\r
563     char            resultBuf[16];\r
564 \r
565 \r
566     EXDLL_INIT();\r
567     popstring(paramBuf);\r
568 \r
569     managerHndl = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);\r
570     if (managerHndl == NULL)\r
571     {\r
572         result = GetLastError();\r
573         goto Cleanup1;\r
574     }\r
575 \r
576     svcHndl = OpenService(managerHndl, paramBuf, SERVICE_START | SERVICE_QUERY_STATUS);\r
577     if (svcHndl == NULL)\r
578     {\r
579         result = GetLastError();\r
580         goto Cleanup2;\r
581     }\r
582 \r
583     if (!StartService(svcHndl, 0, NULL) || !QueryServiceStatus(svcHndl, &svcStatus))\r
584     {\r
585         result = GetLastError();\r
586         goto Cleanup3;\r
587     }\r
588 \r
589     while (svcStatus.dwCurrentState == SERVICE_START_PENDING)\r
590     {\r
591         oldCheckPoint = svcStatus.dwCheckPoint;\r
592 \r
593         Sleep(svcStatus.dwWaitHint);\r
594 \r
595         if (!QueryServiceStatus(svcHndl, &svcStatus))\r
596         {\r
597             result = GetLastError();\r
598             break;\r
599         }\r
600 \r
601         if (oldCheckPoint >= svcStatus.dwCheckPoint)\r
602         {\r
603             if ((svcStatus.dwCurrentState == SERVICE_STOPPED) &&\r
604                 (svcStatus.dwWin32ExitCode != 0))\r
605                 result = svcStatus.dwWin32ExitCode;\r
606             else\r
607                 result = ERROR_SERVICE_REQUEST_TIMEOUT;\r
608         }\r
609     }\r
610 \r
611     if (svcStatus.dwCurrentState == SERVICE_RUNNING)\r
612         result = 0;\r
613 \r
614   Cleanup3:\r
615     CloseServiceHandle(svcHndl);\r
616 \r
617   Cleanup2:\r
618     CloseServiceHandle(managerHndl);\r
619 \r
620   Cleanup1:\r
621     wsprintf(resultBuf, "%08X", result);\r
622     pushstring(resultBuf);\r
623 }\r
624 \r
625 \r
626 \r
627 /*\r
628  * InstDrv::StopSystemService serviceName\r
629  *\r
630  * Return:\r
631  *  result      - Windows error code\r
632  */\r
633 void __declspec(dllexport) StopSystemService(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)\r
634 {\r
635     SC_HANDLE       managerHndl;\r
636     SC_HANDLE       svcHndl;\r
637     SERVICE_STATUS  svcStatus;\r
638     DWORD           oldCheckPoint;\r
639     DWORD           result;\r
640     char            resultBuf[16];\r
641 \r
642 \r
643     EXDLL_INIT();\r
644     popstring(paramBuf);\r
645 \r
646     managerHndl = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);\r
647     if (managerHndl == NULL)\r
648     {\r
649         result = GetLastError();\r
650         goto Cleanup1;\r
651     }\r
652 \r
653     svcHndl = OpenService(managerHndl, paramBuf, SERVICE_STOP | SERVICE_QUERY_STATUS);\r
654     if (svcHndl == NULL)\r
655     {\r
656         result = GetLastError();\r
657         goto Cleanup2;\r
658     }\r
659 \r
660     if (!ControlService(svcHndl, SERVICE_CONTROL_STOP, &svcStatus))\r
661     {\r
662         result = GetLastError();\r
663         goto Cleanup3;\r
664     }\r
665 \r
666     while (svcStatus.dwCurrentState == SERVICE_STOP_PENDING)\r
667     {\r
668         oldCheckPoint = svcStatus.dwCheckPoint;\r
669 \r
670         Sleep(svcStatus.dwWaitHint);\r
671 \r
672         if (!QueryServiceStatus(svcHndl, &svcStatus))\r
673         {\r
674             result = GetLastError();\r
675             break;\r
676         }\r
677 \r
678         if (oldCheckPoint >= svcStatus.dwCheckPoint)\r
679         {\r
680             result = ERROR_SERVICE_REQUEST_TIMEOUT;\r
681             break;\r
682         }\r
683     }\r
684 \r
685     if (svcStatus.dwCurrentState == SERVICE_STOPPED)\r
686         result = 0;\r
687 \r
688   Cleanup3:\r
689     CloseServiceHandle(svcHndl);\r
690 \r
691   Cleanup2:\r
692     CloseServiceHandle(managerHndl);\r
693 \r
694   Cleanup1:\r
695     wsprintf(resultBuf, "%08X", result);\r
696     pushstring(resultBuf);\r
697 }\r
698 \r
699 \r
700 \r
701 BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)\r
702 {\r
703     return TRUE;\r
704 }\r