Merge the WSL Container SDK DLL project into the main feature branch#14172
Merge the WSL Container SDK DLL project into the main feature branch#141721wizkid wants to merge 3 commits intofeature/wsl-for-appsfrom
Conversation
|
I've updated the target branch. |
| #include <windows.h> | ||
| #include <stdint.h> | ||
| #include <winsock2.h> |
There was a problem hiding this comment.
Including <windows.h> before <winsock2.h> can cause Winsock header conflicts for consumers of this public SDK header (unless they happen to define _WINSOCKAPI_ first). Consider including <winsock2.h> before <windows.h> (or define _WINSOCKAPI_/use a lean include strategy) to make the header safe to include standalone.
| #include <windows.h> | |
| #include <stdint.h> | |
| #include <winsock2.h> | |
| #include <winsock2.h> | |
| #include <windows.h> | |
| #include <stdint.h> |
| STDAPI WslcSessionSettingsVHD(_In_ WslcSessionSettings sessionSettings, | ||
| _In_ WSLC_VHD_REQUIREMENTS vhdRequirements); | ||
|
|
||
| STDAPI WslcSessionSettingsTimeout(_In_ WslcSessionSettings sessionSettings, | ||
| uint32_t timeoutMS); | ||
|
|
||
|
|
||
| STDAPI WslcSessionSettingsFlags(_In_ WslcSessionSettings sessionSettings, | ||
| _In_ WSLC_SESSION_FLAGS flags); | ||
|
|
||
| // Pass in Null for callback to clear the termination callback | ||
| STDAPI WslcSessionSettingsTerminateCallback(_In_ WslcSessionSettings sessionSettings, |
There was a problem hiding this comment.
The optional “settings” mutator APIs take the settings structs by value (e.g., WslcSessionSettingsTimeout(_In_ WslcSessionSettings sessionSettings, ...)). Since WslcSessionSettings/WslcContainerSettings/WslcProcessSettings are opaque byte blobs, passing by value means changes cannot propagate back to the caller, making these functions ineffective. These should take an _Inout_ pointer to the settings (and similarly for the container/process settings mutators).
| STDAPI WslcSessionSettingsVHD(_In_ WslcSessionSettings sessionSettings, | |
| _In_ WSLC_VHD_REQUIREMENTS vhdRequirements); | |
| STDAPI WslcSessionSettingsTimeout(_In_ WslcSessionSettings sessionSettings, | |
| uint32_t timeoutMS); | |
| STDAPI WslcSessionSettingsFlags(_In_ WslcSessionSettings sessionSettings, | |
| _In_ WSLC_SESSION_FLAGS flags); | |
| // Pass in Null for callback to clear the termination callback | |
| STDAPI WslcSessionSettingsTerminateCallback(_In_ WslcSessionSettings sessionSettings, | |
| STDAPI WslcSessionSettingsVHD(_Inout_ WslcSessionSettings* sessionSettings, | |
| _In_ WSLC_VHD_REQUIREMENTS vhdRequirements); | |
| STDAPI WslcSessionSettingsTimeout(_Inout_ WslcSessionSettings* sessionSettings, | |
| uint32_t timeoutMS); | |
| STDAPI WslcSessionSettingsFlags(_Inout_ WslcSessionSettings* sessionSettings, | |
| _In_ WSLC_SESSION_FLAGS flags); | |
| // Pass in Null for callback to clear the termination callback | |
| STDAPI WslcSessionSettingsTerminateCallback(_Inout_ WslcSessionSettings* sessionSettings, |
| STDAPI WslcSessionInitSettings(_In_ PCWSTR storagePath, | ||
| _In_ uint32_t cpuCount, | ||
| _In_ uint64_t memoryMb, | ||
| _In_ WslcSessionSettings* sessionSettings); |
There was a problem hiding this comment.
WslcSessionInitSettings writes to sessionSettings, but it is annotated as _In_. This should be an _Out_/_Inout_ annotation (and ideally a size-aware annotation) to match the function’s behavior and avoid incorrect static analysis.
| _In_ WslcSessionSettings* sessionSettings); | |
| _Out_ WslcSessionSettings* sessionSettings); |
| //PROCESS MANAGEMENT | ||
|
|
||
| STDAPI WslcProcessGetPid(_In_ WslcProcess process, | ||
| _Out_ const UINT32* pid); |
There was a problem hiding this comment.
WslcProcessGetPid declares the out parameter as const UINT32*, which prevents the function from writing the PID. This should be a non-const output pointer (e.g., UINT32*) to match the intent of an out parameter.
| _Out_ const UINT32* pid); | |
| _Out_ UINT32* pid); |
| typedef struct WLSC_PULL_IMAGE_OPTIONS | ||
| { | ||
| _In_z_ PCSTR uri; // e.g. "my.registry.io/hello-world:latest" or just "hello-world:latest" which will default to docker | ||
| _In_opt_ WslcContainerImageProgressCallback progressCallback; | ||
| _In_opt_ PVOID progressCallbackContext; | ||
| _In_opt_ WSLC_REGISTRY_AUTHENTICATION_INFORMATION authInfo; | ||
| } WLSC_PULL_IMAGE_OPTIONS; | ||
|
|
||
|
|
||
| STDAPI WslcSessionImagePull(_In_ WslcSession session, | ||
| _In_ const WLSC_PULL_IMAGE_OPTIONS* options, |
There was a problem hiding this comment.
In WLSC_PULL_IMAGE_OPTIONS, the type name prefix is WLSC_... while the rest of the API uses WSLC_..., which looks inconsistent/typo-prone for a public SDK. Also authInfo is marked _In_opt_ but is a by-value struct (cannot be optional); consider making it a pointer or adding an explicit hasAuthInfo flag.
| typedef struct WLSC_PULL_IMAGE_OPTIONS | |
| { | |
| _In_z_ PCSTR uri; // e.g. "my.registry.io/hello-world:latest" or just "hello-world:latest" which will default to docker | |
| _In_opt_ WslcContainerImageProgressCallback progressCallback; | |
| _In_opt_ PVOID progressCallbackContext; | |
| _In_opt_ WSLC_REGISTRY_AUTHENTICATION_INFORMATION authInfo; | |
| } WLSC_PULL_IMAGE_OPTIONS; | |
| STDAPI WslcSessionImagePull(_In_ WslcSession session, | |
| _In_ const WLSC_PULL_IMAGE_OPTIONS* options, | |
| typedef struct WSLC_PULL_IMAGE_OPTIONS | |
| { | |
| _In_z_ PCSTR uri; // e.g. "my.registry.io/hello-world:latest" or just "hello-world:latest" which will default to docker | |
| _In_opt_ WslcContainerImageProgressCallback progressCallback; | |
| _In_opt_ PVOID progressCallbackContext; | |
| _In_opt_ const WSLC_REGISTRY_AUTHENTICATION_INFORMATION* authInfo; | |
| } WSLC_PULL_IMAGE_OPTIONS; | |
| STDAPI WslcSessionImagePull(_In_ WslcSession session, | |
| _In_ const WSLC_PULL_IMAGE_OPTIONS* options, |
| // if you want to override the default binding address | ||
| _In_opt_ struct sockaddr_storage windowsAddress; // accepts ipv4/6 |
There was a problem hiding this comment.
windowsAddress is declared as a by-value sockaddr_storage but annotated _In_opt_ and described as optional. A non-pointer field cannot be null/optional. Consider changing this to a pointer (with an explicit length/family) or add an explicit flag indicating whether the address is present, and update the SAL accordingly.
| // if you want to override the default binding address | |
| _In_opt_ struct sockaddr_storage windowsAddress; // accepts ipv4/6 | |
| // Optional override for the default binding address. If NULL, the default | |
| // address will be used. The buffer must point to a valid sockaddr (IPv4 or | |
| // IPv6) of length windowsAddressLength bytes. | |
| _In_reads_bytes_opt_(windowsAddressLength) const struct sockaddr* windowsAddress; | |
| _In_ INT windowsAddressLength; |
| // Pass in Null for stdIOCallback to clear the callback for the given handle | ||
| STDAPI WslcProcessSettingsIoCallback(_In_ WslcProcessSettings processSettings, | ||
| _In_ WSLC_PROCESS_IO_HANDLE ioHandle, | ||
| _In_ WslcStdIOCallback stdIOCallback); |
There was a problem hiding this comment.
WslcProcessSettingsIoCallback documents passing NULL to clear the callback, but the parameter is annotated _In_ (non-optional). Mark the callback parameter as optional and ensure the implementation handles a null callback consistently.
| _In_ WslcStdIOCallback stdIOCallback); | |
| _In_opt_ WslcStdIOCallback stdIOCallback); |
| _In_ const WSLC_CONTAINER_PORT_MAPPING* portMappings); | ||
|
|
||
| // Add the container volume to the volumes array | ||
| STDAPI WslcContainerSettingsVolume(_In_ WslcContainerSettings containerSettings, _In_ const WSLC_CONTAINER_VOLUME* volumes); | ||
|
|
||
|
|
||
|
|
There was a problem hiding this comment.
WslcContainerSettingsPortMapping/WslcContainerSettingsVolume accept a pointer to mappings/volumes but provide no count/length and no documented terminator convention. Since the internal options struct tracks portsCount/volumesCount, the public API needs a way to specify the number of entries (or clearly document a sentinel-terminated array) to avoid undefined reads.
| _In_ const WSLC_CONTAINER_PORT_MAPPING* portMappings); | |
| // Add the container volume to the volumes array | |
| STDAPI WslcContainerSettingsVolume(_In_ WslcContainerSettings containerSettings, _In_ const WSLC_CONTAINER_VOLUME* volumes); | |
| _In_reads_(portMappingsCount) const WSLC_CONTAINER_PORT_MAPPING* portMappings, | |
| _In_ UINT32 portMappingsCount); | |
| // Add the container volume to the volumes array | |
| STDAPI WslcContainerSettingsVolume(_In_ WslcContainerSettings containerSettings, | |
| _In_reads_(volumesCount) const WSLC_CONTAINER_VOLUME* volumes, | |
| _In_ UINT32 volumesCount); |
| STDAPI WslcSessionSettingsDisplayName(_In_ WslcSessionSettings sessionSettings, | ||
| _In_ PCWSTR displayName) | ||
| { | ||
| UNREFERENCED_PARAMETER(displayName); | ||
| UNREFERENCED_PARAMETER(sessionSettings); | ||
| return E_NOTIMPL; |
There was a problem hiding this comment.
WslcSessionSettingsDisplayName is exported in the .def file, but it isn’t declared in wslcsdk.h. Because of that, this definition will be emitted with C++ name mangling (no prior extern "C" declaration), and the .def export WslcSessionSettingsDisplayName will fail to link. Add the declaration under EXTERN_C_START in wslcsdk.h (or wrap this definition in EXTERN_C_START/END).
| set(SOURCES wslcsdk.cpp) | ||
| set(HEADERS | ||
| wslcsdk.h | ||
| wslcsdkprivate.h | ||
| ) | ||
|
|
||
| add_library(wslcsdk SHARED ${SOURCES} ${HEADERS} wslcsdk.def) | ||
| set_target_properties(wslcsdk PROPERTIES EXCLUDE_FROM_ALL FALSE) | ||
| add_dependencies(wslcsdk wslaserviceidl) | ||
| target_link_libraries(wslcsdk ${COMMON_LINK_LIBRARIES} legacy_stdio_definitions common) | ||
| target_precompile_headers(wslcsdk REUSE_FROM common) | ||
| set_target_properties(wslcsdk PROPERTIES FOLDER windows) |
There was a problem hiding this comment.
This file is named cmakelists.txt, but CMake only auto-loads CMakeLists.txt in an add_subdirectory() directory. As-is, CMake will fail to configure this target unless the file is renamed to CMakeLists.txt (matching exact casing).
OneBlue
left a comment
There was a problem hiding this comment.
Thank you for doing this. Added a couple comments, most of the copilot comments seem to be accurate
| UNREFERENCED_PARAMETER(session); | ||
| return E_NOTIMPL; | ||
| } | ||
| STDAPI WslcContainerSettingsNetworkingMode(_In_ WslcContainerSettings containerSettings, |
There was a problem hiding this comment.
nit: I'd rename to WslcContainerSettingsSetNetworkingMode (same for below method) to follow the get / set naming
| return E_NOTIMPL; | ||
| } | ||
| STDAPI WslcContainerSettingsHostName(_In_ WslcContainerSettings containerSettings, | ||
| _In_ const PCSTR hostName) |
There was a problem hiding this comment.
nit: const is not needed here (already in PCSTR)`
There was a problem hiding this comment.
Also I recommend using the long pointer version (LPCSTR) since that's what modern Windows APIs do
|
|
||
|
|
||
| // SESSION DEFINITIONS | ||
| STDAPI WslcSessionInitSettings(_In_ PCWSTR storagePath, |
There was a problem hiding this comment.
This method can't fail, since I recommend returning the sessions by copy to simplify things. This also remove the need for the "release" method for settings
| UNREFERENCED_PARAMETER(containerSettings); | ||
| return E_NOTIMPL; | ||
| } | ||
| STDAPI WslcContainerSettingsRuntimeName(_In_ WslcContainerSettings containerSettings, |
There was a problem hiding this comment.
I'd just use WslcContainerSettingsSetName (runtime is implied)
| return E_NOTIMPL; | ||
| } | ||
|
|
||
| STDAPI WslcContainerExecProcess(_In_ WslcContainer container, |
There was a problem hiding this comment.
I recommend just WslcContainerExec here
| WSLA_VhdTypeFixed, // Fully allocated VHDX | ||
| } WSLC_VhdType; | ||
|
|
||
| typedef struct WSLC_VHD_REQUIREMENTS |
There was a problem hiding this comment.
I recommend using the same casing for all enum and structures (WSLCVhdRequirements)
Same for below enums
|
|
||
| typedef struct WSLC_CONTAINER_PORT_MAPPING | ||
| { | ||
| _In_ UINT16 windowsPort; // Port on Windows host |
There was a problem hiding this comment.
Let's use uint16_t to match the rest of the API
| typedef __callback VOID(CALLBACK WslcStdIOCallback)(_In_reads_bytes_(dataSize) const BYTE* data, _In_ UINT32 dataSize, _In_opt_ PVOID context); | ||
| typedef enum WSLC_PROCESS_IO_HANDLE | ||
| { | ||
| stdIn = 0, |
There was a problem hiding this comment.
This will conflicts with predefined std handles. I recommend prefixing the enum values with the enum type name (for all enums)
| //#include <wil/result.h> // error handling | ||
|
|
||
| // SESSION DEFINITIONS | ||
| typedef struct WSLC_SESSION_OPTIONS_INTERNAL |
There was a problem hiding this comment.
Let's make this a C++ header (no need for typedef struct)
| PVOID terminationCallbackContext; | ||
| } WSLC_SESSION_OPTIONS_INTERNAL; | ||
|
|
||
| typedef char WSLC_SESSION_OPTIONS_INTERNAL_SIZE_ASSERT[sizeof(WSLC_SESSION_OPTIONS_INTERNAL)];//size = 80 |
There was a problem hiding this comment.
I recommend static_assert instead of this
this adds a new project src/windows/wslcsdk and the necessary .h and cpp files to build the WSLCSDK.DLL.