Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SetCommState return False but GetLastError return 0 (Success). And when used RegOpenKeyEx, SetCommState will fail. #925

Closed
FengChendian opened this issue Nov 13, 2024 · 3 comments
Labels
bug Something isn't working as expected

Comments

@FengChendian
Copy link

FengChendian commented Nov 13, 2024

Description

  1. SetCommState(handler, dcb) == FALSE, But GetLastError give me 0. 0 means ERROR_SUCCESS. Why SetCommState returns false but GetLastError() says it is successful. Is GetLastError() doesn't work #384 not fixed yet? How can I get real error code for debug it?

image

  1. Actually, I use these codes in serial_port_win32 package to get available ports and open a COM port.
    But I found that if I use RegOpenKeyEx function, then I cannot use SetCommState function with any handle which was created by CreateFile function. My package issues 38

The console app dart test code is here:

import 'package:register_open_close_test/register_open_close_test.dart'
    as register_open_close_test;
import 'package:win32/win32.dart';
import 'dart:ffi';
import 'package:ffi/ffi.dart';

final _keyPath = TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM");

int getRegistryKeyValue() {
  final hKeyPtr = calloc<IntPtr>();
  int lResult;
  try {
    lResult = RegOpenKeyEx(
        HKEY_LOCAL_MACHINE, _keyPath, 0, REG_SAM_FLAGS.KEY_READ, hKeyPtr);
    if (lResult != WIN32_ERROR.ERROR_SUCCESS) {
      // RegCloseKey(hKeyPtr.value);
      throw Exception("RegistryKeyValue Not Found");
    } else {
      return hKeyPtr.value;
    }
  } finally {
    free(hKeyPtr);
  }
}

String? enumerateKey(int hKey, int dwIndex) {
  /// [lpValueName]
  /// A pointer to a buffer that receives the name of the value as a null-terminated string.
  /// This buffer must be large enough to include the terminating null character.
  final lpValueName = wsalloc(MAX_PATH);

  /// [lpcchValueName]
  /// A pointer to a variable that specifies the size of the buffer pointed to by the lpValueName parameter
  final lpcchValueName = calloc<DWORD>();
  lpcchValueName.value = MAX_PATH;

  /// A pointer to a variable that receives a code indicating the type of data stored in the specified value.
  final lpType = calloc<DWORD>();

  /// A pointer to a buffer that receives the data for the value entry.
  /// This parameter can be NULL if the data is not required.
  final lpData = calloc<BYTE>(MAX_PATH);

  /// [lpcbData]
  /// A pointer to a variable that specifies the size of the buffer pointed to by the lpData parameter, in bytes.
  /// When the function returns, the variable receives the number of bytes stored in the buffer.
  final lpcbData = calloc<DWORD>();
  lpcbData.value = MAX_PATH;

  try {
    final status = RegEnumValue(hKey, dwIndex, lpValueName, lpcchValueName,
        nullptr, lpType, lpData, lpcbData);

    switch (status) {
      case WIN32_ERROR.ERROR_SUCCESS:
        return lpData.cast<Utf16>().toDartString();
      case WIN32_ERROR.ERROR_MORE_DATA:
        throw Exception("ERROR_MORE_DATA");
      case WIN32_ERROR.ERROR_NO_MORE_ITEMS:
        return null;
      default:
        throw Exception("Unknown error!");
    }
  } finally {
    /// free all pointer
    free(lpValueName);
    free(lpcchValueName);
    free(lpType);
    free(lpData);
    free(lpcbData);
  }
}

List<String> getAvailablePorts() {
  /// availablePorts String list
  List<String> portsList = [];
  final int hKey;

  /// Get registry key of Serial Port
  try {
    hKey = getRegistryKeyValue();
  } on Exception {
    return portsList;
  }

  /// The index of the value to be retrieved.
  /// This parameter should be zero for the first call to the RegEnumValue function and then be incremented for subsequent calls.
  int dwIndex = 0;

  String? item;
  item = enumerateKey(hKey, dwIndex);
  if (item == null) {
    portsList.add('');
  }

  while (item != null) {
    portsList.add(item);
    dwIndex++;
    item = enumerateKey(hKey, dwIndex);
  }

  RegCloseKey(hKey);

  return portsList;
}

void testOpenPort(String portName) {
  final dcb = calloc<DCB>();

  var handler = CreateFile(
      TEXT('\\\\.\\$portName'),
      GENERIC_ACCESS_RIGHTS.GENERIC_READ | GENERIC_ACCESS_RIGHTS.GENERIC_WRITE,
      0,
      nullptr,
      FILE_CREATION_DISPOSITION.OPEN_EXISTING,
      FILE_FLAGS_AND_ATTRIBUTES.FILE_FLAG_OVERLAPPED,
      NULL);

  if (handler == INVALID_HANDLE_VALUE) {
    final lastError = GetLastError();
    if (lastError == WIN32_ERROR.ERROR_FILE_NOT_FOUND) {
      throw Exception("not available");
    } else {
      throw Exception('Open port failed, win32 error code is $lastError');
    }
  }

      if (SetCommState(handler, dcb) == FALSE) {
      throw Exception('SetCommState error, win32 error code is ${GetLastError()}');
    } else {
      PurgeComm(handler,
          PURGE_COMM_FLAGS.PURGE_RXCLEAR | PURGE_COMM_FLAGS.PURGE_TXCLEAR);
    }
}

void main(List<String> arguments) async {
  print('Hello world: ${register_open_close_test.calculate()}!');
  var ports = getAvailablePorts();
  print(ports);

testOpenPort("COM5");
  while (true) {
    await Future.delayed(Duration(seconds: 1));
  }
}

projects files

Steps to reproduce

  1. go to bin/register_open_close_test.dart
  2. run it

Expected behavior

  1. GetLastError should not be 0 when functions return FALSE.
  2. SetCommState should success

Environment

Windows 11, 23H2

Screenshots (optional)

No response

Additional context (optional)

No response

@FengChendian FengChendian added the bug Something isn't working as expected label Nov 13, 2024
@halildurmus
Copy link
Owner

halildurmus commented Nov 13, 2024

@FengChendian

  1. SetCommState(handler, dcb) == FALSE, But GetLastError give me 0. 0 means ERROR_SUCCESS. Why SetCommState returns false but GetLastError() says it is successful. Is GetLastError() doesn't work #384 not fixed yet?

It's not fixed yet because it's still blocked on dart-lang/sdk#38832.

How can I get real error code for debug it?

You can do that by calling the relevant APIs in C, C++, or Rust.

  1. Actually, I use these codes in serial_port_win32 package to get available ports and open a COM port.
    But I found that if I use RegOpenKeyEx function, then I cannot use SetCommState function with any handle which was created by CreateFile function. My package issues 38

After running bin/register_open_close_test.dart, I encountered a SetCommState error. I checked Microsoft’s example and saw that the DCB structure is first initialized by setting its DCBlength to the size of the structure. Next, GetCommState is called before SetCommState to populate the DCB structure with the port’s current settings.

So, I modified the code you provided as follows:

void testOpenPort(String portName) {
- final dcb = calloc<DCB>();
+ final dcb = calloc<DCB>()..ref.DCBlength = sizeOf<DCB>();

  var handler = CreateFile(
      TEXT('\\\\.\\$portName'),
      GENERIC_ACCESS_RIGHTS.GENERIC_READ | GENERIC_ACCESS_RIGHTS.GENERIC_WRITE,
      0,
      nullptr,
      FILE_CREATION_DISPOSITION.OPEN_EXISTING,
      FILE_FLAGS_AND_ATTRIBUTES.FILE_FLAG_OVERLAPPED,
      NULL);

  if (handler == INVALID_HANDLE_VALUE) {
    final lastError = GetLastError();
    if (lastError == WIN32_ERROR.ERROR_FILE_NOT_FOUND) {
      throw Exception("not available");
    } else {
      throw Exception('Open port failed, win32 error code is $lastError');
    }
  }

+ // Initialize the DCB structure with current settings
+ if (GetCommState(handler, dcb) == FALSE) {
+  CloseHandle(handler);
+  free(dcb);
+  throw Exception('GetCommState failed');
+ }

  if (SetCommState(handler, dcb) == FALSE) {
    throw Exception(
        'SetCommState error, win32 error code is ${GetLastError()}');
  } else {
    PurgeComm(handler,
        PURGE_COMM_FLAGS.PURGE_RXCLEAR | PURGE_COMM_FLAGS.PURGE_TXCLEAR);
  }
}

With these changes, the call to SetCommState succeeded.

EDIT: I noticed we already have an example in the repo: serial.dart

@FengChendian
Copy link
Author

FengChendian commented Nov 13, 2024

@halildurmus Thanks for your response!

After call GetCommState, there are no SetCommState error.

But it's really weird. I can run it without any getCommState in some old PCs. 😢

Copy link
Contributor

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 27, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working as expected
Projects
None yet
Development

No branches or pull requests

2 participants