Feat: Rewritten Windows Bindings - #5
Conversation
…win-bindings-new
| typedef struct { | ||
| char values[WMI_MAX_FIELDS][WMI_FIELD_LEN]; | ||
| } WmiRow; |
There was a problem hiding this comment.
This could be turned into a typedef without being encapsulated in a struct. Is there a specific reason for it to stay inside of a struct?
Also, I think you meant to do char values[WMI_FIELD_LEN][WMI_MAX_FIELDS]
| static void VariantToUtf8Slot(VARIANT &vt, char *dst, int dst_size) { | ||
| if (dst_size <= 0) return; |
There was a problem hiding this comment.
In general, to avoid having to check for negative numbers (especially if talking about a parameter indicating size), you can use unsigned integer types: unsigned int dst_size
The caller is also then forced to ensure the passed value is 100% a positive integer.
There was a problem hiding this comment.
The check dst_size <= 0 already handles both cases in one comparison. Switching to unsigned wouldn't force callers to pass positive values in C (negative ints silently wrap to huge unsigned values, which is worse), and it would require changing the header, the ctypes binding, and all callers for no functional benefit. The current int is consistent with the rest of the ABI (WMI_FIELD_LEN, WMI_MAX_FIELDS are all int-typed).
There was a problem hiding this comment.
Ah yeah, I forgot about that. We could technically use -Werror with -Wsign-conversion and -Wconversion to at least mark when these cases of wrapping are happening, but if you think it's not worth the change, then OK, can mark this as resolved.
| // VT_BSTR fast path. | ||
| if (bstr) { | ||
| int len = WideCharToMultiByte(CP_UTF8, 0, bstr, -1, nullptr, 0, nullptr, nullptr); | ||
| if (len > 0) { | ||
| if (len > dst_size) len = dst_size; | ||
| WideCharToMultiByte(CP_UTF8, 0, bstr, -1, dst, len, nullptr, nullptr); | ||
| dst[dst_size - 1] = '\0'; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Wouldn't it just be easier to move this into the initial if condition block?
There was a problem hiding this comment.
apparently not, according to claude
There was a problem hiding this comment.
Why not? It seems to be doing the exact same thing when analyzing control flow?
There was a problem hiding this comment.
In general I'd like to assert a few points:
- General utility/common header functionality would be a nice addition, some methods are re-used or have the potential for re-usability. Defining macros and such in private scopes is OK as long as they stay only in that scope. Otherwise, they should be moved to a common file as well.
- Graceful handling of Win32/COM API calls should be implemented, i.e. the suggested changes for
WideCharToMultiByte(...)second call, which is meant to allocate data to the buffer, does have the potential to fail; we should react appropriately to this. - We should strive to type data as explicitly as possible, i.e. don't use
intsolely in place whereunsigned intfits better. For readability or ease sake, we can define typedefs liketypedef unsigned int uint; - Even for our internal bindings etc. - we should still devise a system for statuses. It'll be helpful for both the backend and frontend to understand why exactly some call failed if it failed. And that way, we can also design our ABI to be as concise and feature-complete as possible.
|
|
||
| // ---- wide -> UTF-8 ---- | ||
|
|
||
| static std::string WideToUtf8(const wchar_t *src) { |
There was a problem hiding this comment.
Could move this to a common utilities file, seems like it's used throughout the bindings frequently (along with any other functions you might have in mind)
There was a problem hiding this comment.
fair enough tbh, ill refactor in a bit
kernel-dev
left a comment
There was a problem hiding this comment.
For some reason I couldn't add to my previous review, so I published that one and now it let me 😄
Mahasvan
left a comment
There was a problem hiding this comment.
Thanks for the review @kernel-dev, much appreciated.
| static void VariantToUtf8Slot(VARIANT &vt, char *dst, int dst_size) { | ||
| if (dst_size <= 0) return; |
There was a problem hiding this comment.
The check dst_size <= 0 already handles both cases in one comparison. Switching to unsigned wouldn't force callers to pass positive values in C (negative ints silently wrap to huge unsigned values, which is worse), and it would require changing the header, the ctypes binding, and all callers for no functional benefit. The current int is consistent with the rest of the ABI (WMI_FIELD_LEN, WMI_MAX_FIELDS are all int-typed).
| // VT_BSTR fast path. | ||
| if (bstr) { | ||
| int len = WideCharToMultiByte(CP_UTF8, 0, bstr, -1, nullptr, 0, nullptr, nullptr); | ||
| if (len > 0) { | ||
| if (len > dst_size) len = dst_size; | ||
| WideCharToMultiByte(CP_UTF8, 0, bstr, -1, dst, len, nullptr, nullptr); | ||
| dst[dst_size - 1] = '\0'; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
apparently not, according to claude
Check return value of all WideCharToMultiByte write calls. On failure, return empty string or null-terminate the buffer instead of leaving uninitialized contents.
No description provided.