|
24 | 24 | */ |
25 | 25 | #include <jni.h> |
26 | 26 | #include <stdlib.h> |
| 27 | +#include <stdio.h> |
27 | 28 | #include <windows.h> |
28 | 29 | #include <jssc_SerialNativeInterface.h> |
29 | 30 | #include "version.h" |
@@ -643,47 +644,81 @@ JNIEXPORT jobjectArray JNICALL Java_jssc_SerialNativeInterface_waitEvents |
643 | 644 | */ |
644 | 645 | JNIEXPORT jobjectArray JNICALL Java_jssc_SerialNativeInterface_getSerialPortNames |
645 | 646 | (JNIEnv *env, jobject){ |
646 | | - HKEY phkResult; |
| 647 | + HKEY phkResult = NULL; |
647 | 648 | LPCSTR lpSubKey = "HARDWARE\\DEVICEMAP\\SERIALCOMM\\"; |
648 | 649 | jobjectArray returnArray = NULL; |
649 | | - if(RegOpenKeyExA(HKEY_LOCAL_MACHINE, lpSubKey, 0, KEY_READ, &phkResult) == ERROR_SUCCESS){ |
650 | | - boolean hasMoreElements = true; |
651 | | - DWORD keysCount = 0; |
652 | | - char valueName[256]; |
653 | | - DWORD valueNameSize; |
654 | | - DWORD enumResult; |
655 | | - while(hasMoreElements){ |
656 | | - valueNameSize = 256; |
657 | | - enumResult = RegEnumValueA(phkResult, keysCount, valueName, &valueNameSize, NULL, NULL, NULL, NULL); |
658 | | - if(enumResult == ERROR_SUCCESS){ |
659 | | - keysCount++; |
660 | | - } |
661 | | - else if(enumResult == ERROR_NO_MORE_ITEMS){ |
662 | | - hasMoreElements = false; |
663 | | - } |
664 | | - else { |
665 | | - hasMoreElements = false; |
666 | | - } |
| 650 | + byte lpDataOnStack[256]; |
| 651 | + byte *lpData = lpDataOnStack; |
| 652 | + DWORD lpData_capacity = 256; |
| 653 | + char valueName[256]; |
| 654 | + DWORD valueNameSize; |
| 655 | + DWORD enumResult; |
| 656 | + boolean hasMoreElements = true; |
| 657 | + DWORD keysCount = 0; |
| 658 | + if(RegOpenKeyExA(HKEY_LOCAL_MACHINE, lpSubKey, 0, KEY_READ, &phkResult) != ERROR_SUCCESS){ |
| 659 | + returnArray = NULL; |
| 660 | + goto Finally; |
| 661 | + } |
| 662 | + /* Iterate a 1st time to see how long our resulting array has to be. */ |
| 663 | + while(hasMoreElements){ |
| 664 | + valueNameSize = 256; |
| 665 | + enumResult = RegEnumValueA(phkResult, keysCount, valueName, &valueNameSize, NULL, NULL, NULL, NULL); |
| 666 | + if(enumResult == ERROR_SUCCESS){ |
| 667 | + keysCount++; |
667 | 668 | } |
668 | | - if(keysCount > 0){ |
669 | | - jclass stringClass = env->FindClass("java/lang/String"); |
670 | | - returnArray = env->NewObjectArray((jsize)keysCount, stringClass, NULL); |
671 | | - char lpValueName[256]; |
672 | | - DWORD lpcchValueName; |
673 | | - byte lpData[256]; |
674 | | - DWORD lpcbData; |
675 | | - DWORD result; |
676 | | - for(DWORD i = 0; i < keysCount; i++){ |
677 | | - lpcchValueName = 256; |
678 | | - lpcbData = 256; |
679 | | - result = RegEnumValueA(phkResult, i, lpValueName, &lpcchValueName, NULL, NULL, lpData, &lpcbData); |
680 | | - if(result == ERROR_SUCCESS){ |
681 | | - env->SetObjectArrayElement(returnArray, i, env->NewStringUTF((char*)lpData)); |
| 669 | + else if(enumResult == ERROR_NO_MORE_ITEMS){ |
| 670 | + hasMoreElements = false; |
| 671 | + } |
| 672 | + else { |
| 673 | + hasMoreElements = false; |
| 674 | + } |
| 675 | + } |
| 676 | + if(keysCount > 0){ |
| 677 | + jclass stringClass = env->FindClass("java/lang/String"); |
| 678 | + returnArray = env->NewObjectArray((jsize)keysCount, stringClass, NULL); |
| 679 | + DWORD lpcbData; |
| 680 | + DWORD result; |
| 681 | + /* iterate 2nd time but this time our array is ready to catch results. */ |
| 682 | + for(DWORD i = 0; i < keysCount; i++){ |
| 683 | + valueNameSize = 256; |
| 684 | + lpcbData = lpData_capacity; |
| 685 | + result = RegEnumValueA(phkResult, i, valueName, &valueNameSize, NULL, NULL, lpData, &lpcbData); |
| 686 | + if(result == ERROR_SUCCESS){ |
| 687 | + env->SetObjectArrayElement(returnArray, i, env->NewStringUTF((char*)lpData)); |
| 688 | + }else if(result == ERROR_MORE_DATA && lpData_capacity < UINT_MAX){ |
| 689 | + /* whoops our supplied buffer was not large enough. Fallback to a heap |
| 690 | + * allocd one. RegEnumValueA was kind enough to set 'lpcbData' to the |
| 691 | + * required length before return. */ |
| 692 | + lpData = (lpData == lpDataOnStack) ? NULL : lpData; |
| 693 | + /* MS doc is unclear to me if returned size includes the required |
| 694 | + * zero-term. So to stay safe, we provide one byte more. */ |
| 695 | + if(lpcbData < UINT_MAX) lpcbData += 1; |
| 696 | + byte *tmp = (byte*)realloc(lpData, lpcbData*sizeof*tmp); |
| 697 | + if(tmp == NULL){ |
| 698 | + jclass exClz = env->FindClass("java/lang/OutOfMemoryError"); |
| 699 | + if(exClz != NULL) env->ThrowNew(exClz, NULL); |
| 700 | + returnArray = NULL; |
| 701 | + goto Finally; |
682 | 702 | } |
| 703 | + /* install new buffer and reset 'i' so we try the same element again. */ |
| 704 | + lpData_capacity = lpcbData; |
| 705 | + lpData = tmp; |
| 706 | + i -= 1; |
| 707 | + }else{ |
| 708 | + char exMsg[128]; |
| 709 | + snprintf(exMsg, sizeof exMsg, "RegEnumValueA(): Code %ld: " |
| 710 | + "https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes#system-error-codes", |
| 711 | + result); |
| 712 | + jclass exClz = env->FindClass("java/lang/RuntimeException"); |
| 713 | + if(exClz != NULL) env->ThrowNew(exClz, exMsg); |
| 714 | + returnArray = NULL; |
| 715 | + goto Finally; |
683 | 716 | } |
684 | 717 | } |
685 | | - CloseHandle(phkResult); |
686 | 718 | } |
| 719 | +Finally: |
| 720 | + if(lpData != NULL && lpData != lpDataOnStack) free(lpData); |
| 721 | + if(phkResult != NULL) CloseHandle(phkResult); |
687 | 722 | return returnArray; |
688 | 723 | } |
689 | 724 |
|
|
0 commit comments