simconnect-H 0.2.2__tar.gz → 0.2.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simconnect-H
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: 原生 ctypes SimConnect 库 — 零外部依赖,直接加载 SimConnect.dll 与 MSFS 通讯
5
5
  Author-email: HuJie <150501351+hjznb887@users.noreply.github.com>
6
6
  License-Expression: MIT
@@ -145,6 +145,7 @@ with SimConnect() as sc:
145
145
  | `call_dispatch(callback)` | 设置并触发 dispatch |
146
146
  | `read_double(pData)` | 从回调中解析 float64 值 |
147
147
  | `read_data(pData, datatype=0)` | 从回调指针按类型读取数据(静态方法,零拷贝) |
148
+ | `parse_exception(pData)` | 解析异常消息,返回 (名称, sendID, index)(静态方法) |
148
149
  | `start_background_dispatch(callback=None)` | 启动后台 dispatch 线程 |
149
150
  | `stop_background_dispatch()` | 停止后台 dispatch 线程 |
150
151
  | `get_last_sent_packet_id()` | 获取最后发送的数据包 ID |
@@ -164,7 +165,7 @@ with SimConnect() as sc:
164
165
  | ------ | ------ |
165
166
  | `find_simconnect_dll()` | 自动搜索 SimConnect.dll 路径 |
166
167
  | `read_data_value(pData, datatype=0)` | 从 dispatch 回调中读取指定类型数据 |
167
- | `__version__` | 当前库版本 `"0.2.2"` |
168
+ | `__version__` | 当前库版本 `"0.2.4"` |
168
169
 
169
170
  ## 许可证
170
171
 
@@ -126,6 +126,7 @@ with SimConnect() as sc:
126
126
  | `call_dispatch(callback)` | 设置并触发 dispatch |
127
127
  | `read_double(pData)` | 从回调中解析 float64 值 |
128
128
  | `read_data(pData, datatype=0)` | 从回调指针按类型读取数据(静态方法,零拷贝) |
129
+ | `parse_exception(pData)` | 解析异常消息,返回 (名称, sendID, index)(静态方法) |
129
130
  | `start_background_dispatch(callback=None)` | 启动后台 dispatch 线程 |
130
131
  | `stop_background_dispatch()` | 停止后台 dispatch 线程 |
131
132
  | `get_last_sent_packet_id()` | 获取最后发送的数据包 ID |
@@ -145,7 +146,7 @@ with SimConnect() as sc:
145
146
  | ------ | ------ |
146
147
  | `find_simconnect_dll()` | 自动搜索 SimConnect.dll 路径 |
147
148
  | `read_data_value(pData, datatype=0)` | 从 dispatch 回调中读取指定类型数据 |
148
- | `__version__` | 当前库版本 `"0.2.2"` |
149
+ | `__version__` | 当前库版本 `"0.2.4"` |
149
150
 
150
151
  ## 许可证
151
152
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "simconnect-H"
7
- version = "0.2.2"
7
+ version = "0.2.4"
8
8
  description = "原生 ctypes SimConnect 库 — 零外部依赖,直接加载 SimConnect.dll 与 MSFS 通讯"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simconnect-H
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: 原生 ctypes SimConnect 库 — 零外部依赖,直接加载 SimConnect.dll 与 MSFS 通讯
5
5
  Author-email: HuJie <150501351+hjznb887@users.noreply.github.com>
6
6
  License-Expression: MIT
@@ -145,6 +145,7 @@ with SimConnect() as sc:
145
145
  | `call_dispatch(callback)` | 设置并触发 dispatch |
146
146
  | `read_double(pData)` | 从回调中解析 float64 值 |
147
147
  | `read_data(pData, datatype=0)` | 从回调指针按类型读取数据(静态方法,零拷贝) |
148
+ | `parse_exception(pData)` | 解析异常消息,返回 (名称, sendID, index)(静态方法) |
148
149
  | `start_background_dispatch(callback=None)` | 启动后台 dispatch 线程 |
149
150
  | `stop_background_dispatch()` | 停止后台 dispatch 线程 |
150
151
  | `get_last_sent_packet_id()` | 获取最后发送的数据包 ID |
@@ -164,7 +165,7 @@ with SimConnect() as sc:
164
165
  | ------ | ------ |
165
166
  | `find_simconnect_dll()` | 自动搜索 SimConnect.dll 路径 |
166
167
  | `read_data_value(pData, datatype=0)` | 从 dispatch 回调中读取指定类型数据 |
167
- | `__version__` | 当前库版本 `"0.2.2"` |
168
+ | `__version__` | 当前库版本 `"0.2.4"` |
168
169
 
169
170
  ## 许可证
170
171
 
@@ -58,6 +58,8 @@ __all__ = [
58
58
  "MSFS_EVENTS",
59
59
  # 函数
60
60
  "find_simconnect_dll",
61
+ # 常量
62
+ "HRESULT_NAMES",
61
63
  # 类
62
64
  "SimConnect",
63
65
  # 新增工具
@@ -70,7 +72,7 @@ logger = logging.getLogger(__name__)
70
72
  # 版本
71
73
  # ═══════════════════════════════════════════════════
72
74
 
73
- __version__ = "0.2.2"
75
+ __version__ = "0.2.4"
74
76
 
75
77
  # ═══════════════════════════════════════════════════
76
78
  # 常量
@@ -127,6 +129,16 @@ EXCEPTION_NAMES = {
127
129
  7: "NAME_UNRECOGNIZED", 8: "TOO_MANY_EVENT_NAMES",
128
130
  }
129
131
 
132
+ # HRESULT 常见错误码名称
133
+ HRESULT_NAMES = {
134
+ 0x80004005: "E_FAIL",
135
+ 0x80070005: "E_ACCESSDENIED",
136
+ 0x80070057: "E_INVALIDARG",
137
+ 0x80004001: "E_NOTIMPL",
138
+ 0x8000FFFF: "E_UNEXPECTED",
139
+ 0x800401F0: "CO_E_NOTINITIALIZED",
140
+ }
141
+
130
142
  # ═══════════════════════════════════════════════════
131
143
  # 消息结构体
132
144
  # ═══════════════════════════════════════════════════
@@ -446,9 +458,11 @@ class SimConnect:
446
458
  window_event_handle, config_index,
447
459
  )
448
460
  if err != 0:
449
- raise ConnectionError(
450
- f"SimConnect_Open 失败: HRESULT=0x{err:08x}"
451
- )
461
+ name = HRESULT_NAMES.get(err, "")
462
+ msg = f"SimConnect_Open 失败: HRESULT=0x{err:08x}"
463
+ if name:
464
+ msg += f" ({name})"
465
+ raise ConnectionError(msg)
452
466
  if not hSim or hSim.value is None or hSim.value == 0:
453
467
  raise ConnectionError(
454
468
  "SimConnect_Open 返回空句柄 — MSFS 可能未运行"
@@ -767,6 +781,8 @@ class SimConnect:
767
781
  (request_id, float_value) 元组,解析失败返回 (None, None)。
768
782
  """
769
783
  try:
784
+ if not pData:
785
+ return None, None
770
786
  header = cast(pData, POINTER(SIMOBJECT_DATA_HEADER)).contents
771
787
  base = ctypes.cast(pData, c_void_p).value
772
788
  val = ctypes.cast(base + SIMOBJECT_DATA_HEADER_SIZE, POINTER(c_double)).contents.value
@@ -788,6 +804,8 @@ class SimConnect:
788
804
  数值(int/float/bytes),解析失败返回 None。
789
805
  """
790
806
  try:
807
+ if not pData:
808
+ return None
791
809
  base = ctypes.cast(pData, c_void_p).value
792
810
  data_addr = base + SIMOBJECT_DATA_HEADER_SIZE
793
811
  if datatype == 0: # FLOAT64
@@ -801,9 +819,35 @@ class SimConnect:
801
819
  elif datatype == 4: # INT8
802
820
  return ctypes.cast(data_addr, POINTER(c_int8)).contents.value
803
821
  elif datatype == 5: # STRINGV
804
- # 读取 256 字节的字符串
805
- buf = ctypes.cast(data_addr, POINTER(ctypes.c_char * 256)).contents
806
- return buf.value.decode('utf-8', errors='replace').rstrip('\x00')
822
+ # STRINGV 格式: [4字节长度前缀][字符串数据(无结尾null)]
823
+ # 先读取长度前缀
824
+ str_len = ctypes.cast(data_addr, POINTER(c_int32)).contents.value
825
+ if str_len <= 0 or str_len > 4096:
826
+ return None
827
+ str_addr = data_addr + 4
828
+ buf = ctypes.cast(str_addr, POINTER(ctypes.c_char * str_len)).contents
829
+ return buf.value.decode('utf-8', errors='replace')
807
830
  return None
808
831
  except Exception:
809
832
  return None
833
+
834
+ @staticmethod
835
+ def parse_exception(pData: Any) -> Tuple[Optional[str], Optional[int], Optional[int]]:
836
+ """从 dispatch 回调中解析异常消息。
837
+
838
+ 在 dispatch 回调中收到 SIMCONNECT_RECV_ID_EXCEPTION 时调用。
839
+
840
+ Args:
841
+ pData: POINTER(SIMCONNECT_RECV),dispatch 回调的第一个参数。
842
+
843
+ Returns:
844
+ (异常名称, dwSendID, dwIndex) 元组,解析失败返回 (None, None, None)。
845
+ """
846
+ try:
847
+ if not pData:
848
+ return None, None, None
849
+ exc = cast(pData, POINTER(EXCEPTION_MSG)).contents
850
+ name = EXCEPTION_NAMES.get(exc.dwException, f"UNKNOWN({exc.dwException})")
851
+ return name, exc.dwSendID, exc.dwIndex
852
+ except Exception:
853
+ return None, None, None
File without changes
File without changes