Skip to content

Commit 4168d80

Browse files
shai-almogclaude
andcommitted
Windows port: drop the CN1_HAVE_WINRT guard, always compile real WinRT
The guard was defensive insurance against a build toolchain lacking WinRT, but the cross-compile CI proved otherwise: it had already DEFINED CN1_HAVE_WINRT (the earlier STL error fired inside the #ifdef on the Linux/xwin leg), i.e. the xwin-laid-out SDK ships the WinRT ABI headers + runtimeobject. So stub mode never actually triggered anywhere the port builds. Remove the CMake probe + the per-function #ifdef/#else stub branches and link runtimeobject unconditionally; the compiled output is identical to the prior green build, just simpler. Also drop the now-pointless locationSupported() native (getLocationManager always returns the manager; isNativeShareSupported checks for a host window). Each service still degrades honestly at RUNTIME (no device / disabled / denied -> false/null). status.md updated to drop the gate/stub language. Trade-off (accepted): a future build SDK without WinRT would now fail the build instead of degrading to stubs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 841ec0d commit 4168d80

5 files changed

Lines changed: 48 additions & 124 deletions

File tree

Ports/WindowsPort/nativeSources/cn1_windows_winrt.cpp

Lines changed: 22 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,24 @@
2222
*/
2323

2424
/*
25-
* WinRT-backed services for the Windows port (biometric / Windows Hello, and --
26-
* added incrementally -- location, contacts, share). WinRT is consumed through
27-
* the WRL ABI projection (RoGetActivationFactory + the ABI:: interfaces), the
28-
* same COM-based mechanism the Media Foundation layer already uses, so no
29-
* C++/WinRT (cppwinrt) projection headers are required.
25+
* WinRT-backed services for the Windows port: biometric (Windows Hello), location,
26+
* contacts and system share. WinRT is consumed through the WRL ABI projection
27+
* (RoGetActivationFactory / RoActivateInstance + the ABI:: interfaces), the same
28+
* COM-based mechanism the Media Foundation layer already uses -- no C++/WinRT
29+
* (cppwinrt) projection headers are required, and runtimeobject.lib is linked
30+
* unconditionally. The WinRT ABI headers + runtimeobject ship in every Windows
31+
* SDK the port builds against, including the xwin-laid-out SDK used by the
32+
* Windows-free Linux cross-compile (verified by that CI leg compiling this file).
3033
*
31-
* The whole real implementation is gated on CN1_HAVE_WINRT, which the generated
32-
* CMake defines only after a probe confirms the WinRT ABI headers +
33-
* runtimeobject.lib are present and link on the build toolchain. When it is not
34-
* defined (e.g. a cross-compile sysroot without WinRT) every bridge below
35-
* compiles as an honest "unsupported" stub, so the Windows-free build stays green
36-
* and the matching CN1 capability simply reports false / null.
34+
* Each bridge still degrades honestly at RUNTIME -- a missing device, disabled
35+
* Windows setting or denied permission surfaces as false / null (never fabricated
36+
* data) -- which is what the matching CN1 capability reports as "unsupported".
3737
*/
3838

3939
#ifdef _WIN32
4040

4141
#include "cn1_windows.h"
4242

43-
#ifdef CN1_HAVE_WINRT
44-
4543
#include <roapi.h>
4644
#include <stdlib.h>
4745
#include <string.h>
@@ -74,10 +72,9 @@ using namespace Microsoft::WRL::Wrappers;
7472
/* Blocks the calling (CN1 worker) thread until a WinRT IAsyncOperation<T>
7573
* completes, then fetches its result. Used for the inherently-async WinRT APIs;
7674
* callers invoke these natives off the EDT (via AsyncResource) so blocking is
77-
* fine. */
78-
/* TOp is the operation's logical result type (a value type, or a runtimeclass --
79-
* for which GetResults yields the ABI *interface* pointer, so the result pointer
80-
* type TResultPtr is kept separate from TOp). */
75+
* fine. TOp is the operation's logical result type (a value type, or a
76+
* runtimeclass -- for which GetResults yields the ABI *interface* pointer, so the
77+
* result pointer type TResultPtr is kept separate from TOp). */
8178
template <typename TOp, typename TResultPtr>
8279
static HRESULT cn1AwaitOp(IAsyncOperation<TOp>* op, TResultPtr result) {
8380
Event done(CreateEventExW(nullptr, nullptr, 0, EVENT_ALL_ACCESS));
@@ -162,18 +159,15 @@ static void cn1AppendHString(CN1Buf* out, HSTRING h) {
162159
free(tmp);
163160
}
164161

165-
#endif /* CN1_HAVE_WINRT */
166-
167162
extern "C" {
168163

169164
/* ------------------------------------------------------------- biometric
170165
*
171166
* Maps Windows Hello (UserConsentVerifier) to com.codename1.security.Biometrics.
172167
* Returns the UserConsentVerifierAvailability enum: 0 Available, 1
173168
* DeviceNotPresent, 2 NotConfiguredForUser, 3 DisabledByPolicy, 4 DeviceBusy.
174-
* The Java side treats 0 as supported+ready. The stub reports DeviceNotPresent. */
169+
* The Java side treats 0 as supported+ready; anything else degrades honestly. */
175170
JAVA_INT com_codename1_impl_windows_WindowsNative_biometricAvailability___R_int(CODENAME_ONE_THREAD_STATE) {
176-
#ifdef CN1_HAVE_WINRT
177171
cn1WinRtInit();
178172
ComPtr<IUserConsentVerifierStatics> statics;
179173
HRESULT hr = RoGetActivationFactory(
@@ -191,16 +185,12 @@ JAVA_INT com_codename1_impl_windows_WindowsNative_biometricAvailability___R_int(
191185
return 1;
192186
}
193187
return (JAVA_INT) avail;
194-
#else
195-
return 1; /* DeviceNotPresent: no WinRT -> report unsupported */
196-
#endif
197188
}
198189

199190
/* Shows the Windows Hello consent prompt with the given reason; returns true
200-
* when the user is verified. Stub returns false. */
191+
* when the user is verified. */
201192
JAVA_BOOLEAN com_codename1_impl_windows_WindowsNative_biometricAuthenticate___java_lang_String_R_boolean(
202193
CODENAME_ONE_THREAD_STATE, JAVA_OBJECT message) {
203-
#ifdef CN1_HAVE_WINRT
204194
cn1WinRtInit();
205195
ComPtr<IUserConsentVerifierStatics> statics;
206196
HRESULT hr = RoGetActivationFactory(
@@ -225,32 +215,17 @@ JAVA_BOOLEAN com_codename1_impl_windows_WindowsNative_biometricAuthenticate___ja
225215
return JAVA_FALSE;
226216
}
227217
return result == UserConsentVerificationResult_Verified ? JAVA_TRUE : JAVA_FALSE;
228-
#else
229-
(void) message;
230-
return JAVA_FALSE;
231-
#endif
232-
}
233-
234-
/* True when the port was built with WinRT (so a real Geolocator can be used);
235-
* lets getLocationManager() return null honestly on a stub build. */
236-
JAVA_BOOLEAN com_codename1_impl_windows_WindowsNative_locationSupported___R_boolean(CODENAME_ONE_THREAD_STATE) {
237-
#ifdef CN1_HAVE_WINRT
238-
return JAVA_TRUE;
239-
#else
240-
return JAVA_FALSE;
241-
#endif
242218
}
243219

244220
/* -------------------------------------------------------------- location
245221
*
246222
* Maps Windows.Devices.Geolocation.Geolocator to LocationManager. Fills `out`
247223
* with [latitude, longitude, accuracy(m), altitude(m), direction(deg),
248-
* velocity(m/s), timestampMillis] and returns true; false when location is
249-
* unavailable / disabled (Windows location off, or WinRT stub build) so the
250-
* port reports unsupported honestly rather than fabricating a position. */
224+
* velocity(m/s)] and returns true; false when location is unavailable / disabled
225+
* (Windows location off or permission denied) so the port reports unsupported
226+
* honestly rather than fabricating a position. */
251227
JAVA_BOOLEAN com_codename1_impl_windows_WindowsNative_locationGetCurrent___double_1ARRAY_R_boolean(
252228
CODENAME_ONE_THREAD_STATE, JAVA_OBJECT outArr) {
253-
#ifdef CN1_HAVE_WINRT
254229
if (outArr == JAVA_NULL) {
255230
return JAVA_FALSE;
256231
}
@@ -305,10 +280,6 @@ JAVA_BOOLEAN com_codename1_impl_windows_WindowsNative_locationGetCurrent___doubl
305280
if (n > 4) { out[4] = heading; }
306281
if (n > 5) { out[5] = speed; }
307282
return JAVA_TRUE;
308-
#else
309-
(void) outArr;
310-
return JAVA_FALSE;
311-
#endif
312283
}
313284

314285
/* -------------------------------------------------------------- contacts
@@ -317,10 +288,9 @@ JAVA_BOOLEAN com_codename1_impl_windows_WindowsNative_locationGetCurrent___doubl
317288
* single record-delimited blob: each contact is "id US name US phone US email"
318289
* (field separator 0x1F, record separator 0x1E). The Java side parses it into CN1
319290
* Contact objects. One native call avoids a chatty per-field bridge. Returns null
320-
* when the store is inaccessible (no WinRT, or access denied) and an empty string
321-
* when the store simply has no contacts -- both honest, never fabricated. */
291+
* when the store is inaccessible (access denied) and an empty string when the
292+
* store simply has no contacts -- both honest, never fabricated. */
322293
JAVA_OBJECT com_codename1_impl_windows_WindowsNative_contactsGetAll___R_java_lang_String(CODENAME_ONE_THREAD_STATE) {
323-
#ifdef CN1_HAVE_WINRT
324294
cn1WinRtInit();
325295
ComPtr<IContactManagerStatics2> statics;
326296
if (FAILED(RoGetActivationFactory(
@@ -408,9 +378,6 @@ JAVA_OBJECT com_codename1_impl_windows_WindowsNative_contactsGetAll___R_java_lan
408378
free(blob.data);
409379
return s;
410380
}
411-
#else
412-
return JAVA_NULL;
413-
#endif
414381
}
415382

416383
/* ----------------------------------------------------------------- share
@@ -421,15 +388,12 @@ JAVA_OBJECT com_codename1_impl_windows_WindowsNative_contactsGetAll___R_java_lan
421388
* and cn1WinShareHandleMessage runs here on the pump thread. The text/title are
422389
* stashed in file-static state read by the (same-thread) DataRequested handler.
423390
* Shares text (the common case); image-file sharing is a later addition. */
424-
#ifdef CN1_HAVE_WINRT
425391
static WCHAR* g_shareTextW = NULL;
426392
static WCHAR* g_shareTitleW = NULL;
427393
static bool g_shareHandlerRegistered = false;
428394
static ComPtr<IDataTransferManager> g_shareDtm;
429-
#endif
430395

431396
void cn1WinShareHandleMessage(WPARAM wParam) {
432-
#ifdef CN1_HAVE_WINRT
433397
/* wParam carries [textW, titleW] allocated by the caller; take ownership. */
434398
WCHAR** data = (WCHAR**) wParam;
435399
if (g_shareTextW != NULL) { free(g_shareTextW); }
@@ -475,16 +439,12 @@ void cn1WinShareHandleMessage(WPARAM wParam) {
475439
g_shareHandlerRegistered = true;
476440
}
477441
interop->ShowShareUIForWindow(cn1Win.hwnd);
478-
#else
479-
(void) wParam;
480-
#endif
481442
}
482443

483444
/* Java bridge: marshals the share request to the window thread. Returns false in
484-
* headless / WinRT-less builds. */
445+
* headless mode (no host window). */
485446
JAVA_BOOLEAN com_codename1_impl_windows_WindowsNative_shareText___java_lang_String_java_lang_String_R_boolean(
486447
CODENAME_ONE_THREAD_STATE, JAVA_OBJECT textObj, JAVA_OBJECT titleObj) {
487-
#ifdef CN1_HAVE_WINRT
488448
if (cn1Win.hwnd == NULL) {
489449
return JAVA_FALSE;
490450
}
@@ -496,11 +456,6 @@ JAVA_BOOLEAN com_codename1_impl_windows_WindowsNative_shareText___java_lang_Stri
496456
data[1] = titleObj != JAVA_NULL ? cn1WinJavaStringToWide(threadStateData, titleObj, NULL) : NULL;
497457
PostMessageW(cn1Win.hwnd, WM_CN1_SHARE, (WPARAM) data, 0);
498458
return JAVA_TRUE;
499-
#else
500-
(void) textObj;
501-
(void) titleObj;
502-
return JAVA_FALSE;
503-
#endif
504459
}
505460

506461
} /* extern "C" */

Ports/WindowsPort/src/com/codename1/impl/windows/WindowsImplementation.java

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -355,16 +355,12 @@ public com.codename1.security.Biometrics getBiometrics() {
355355
return biometrics;
356356
}
357357

358-
// WinRT Geolocator-backed location. Returns null (unsupported) on a build
359-
// without WinRT; on a real build getCurrentLocation reports OUT_OF_SERVICE
360-
// honestly when Windows location is disabled.
358+
// WinRT Geolocator-backed location. getCurrentLocation reports OUT_OF_SERVICE
359+
// honestly when Windows location is disabled / denied.
361360
private com.codename1.location.LocationManager locationManager;
362361

363362
@Override
364363
public com.codename1.location.LocationManager getLocationManager() {
365-
if (!WindowsNative.locationSupported()) {
366-
return null;
367-
}
368364
if (locationManager == null) {
369365
locationManager = new WindowsLocationManager();
370366
}
@@ -1831,9 +1827,9 @@ public int getSMSSupport() {
18311827

18321828
@Override
18331829
public boolean isNativeShareSupported() {
1834-
// locationSupported() reports whether WinRT was compiled in (the gate the
1835-
// whole WinRT layer shares); the share UI also needs a host window.
1836-
return WindowsNative.locationSupported();
1830+
// The WinRT DataTransferManager share UI is always compiled in; it just
1831+
// needs a host window (absent only in headless screenshot mode).
1832+
return getDisplayWidth() > 0;
18371833
}
18381834

18391835
@Override

Ports/WindowsPort/src/com/codename1/impl/windows/WindowsNative.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -518,9 +518,6 @@ public static native long editStringAt(int x, int y, int w, int h, String text,
518518

519519
/* -------------------------------------------------- location (WinRT) */
520520

521-
/** True when WinRT is compiled in, so a real {@code Geolocator} is available. */
522-
public static native boolean locationSupported();
523-
524521
/**
525522
* Fills {@code out} with the current fix [latitude, longitude, accuracy(m),
526523
* altitude(m), direction(deg), velocity(m/s)] from the WinRT Geolocator and

Ports/WindowsPort/status.md

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,8 @@ the port does not have yet (gap 5a). `captureVideo` is likewise still to do.
149149
marshals to the window thread (`WM_CN1_SHARE`), where `IDataTransferManagerInterop`
150150
`GetForWindow` + `ShowShareUIForWindow` open the system share flyout for the
151151
unpackaged Win32 window and a `DataRequested` handler supplies the text/title
152-
(`cn1_windows_winrt.cpp`, same `CN1_HAVE_WINRT` gate). Shares text today (the
153-
common case); image-file sharing via `SetStorageItems` is a follow-up. Compiles
154-
(real + stub) on the Windows ARM64 VM; the flyout itself is interactive.
152+
(`cn1_windows_winrt.cpp`, shared WinRT layer). Shares text today (the
153+
common case); image-file sharing via `SetStorageItems` is a follow-up. Compiles and links on the Windows ARM64 VM; the flyout itself is interactive.
155154

156155
**Print — not applicable.** Codename One core exposes no printing API (no
157156
`Printer` class or impl hook), so there is nothing for the port to override; this
@@ -171,7 +170,7 @@ they stay honest until backed by a real implementation:
171170

172171
**Contacts — implemented (WinRT).** `getAllContacts` / `getContactById` read the
173172
user's contacts via the WinRT `ContactStore` (`cn1_windows_winrt.cpp`, same
174-
`CN1_HAVE_WINRT` gate). One native call returns every contact as a delimited blob
173+
shared WinRT layer). One native call returns every contact as a delimited blob
175174
(id / name / phone / email) which the impl parses and briefly caches, so the
176175
base's id-then-fetch loop shares a single store read. Returns nothing when the
177176
store is inaccessible (no WinRT / access denied) -- honest, never fabricated.
@@ -180,12 +179,12 @@ biometric/location.
180179

181180
**Location / GPS — implemented (WinRT).** `getLocationManager()`
182181
`WindowsLocationManager`, backed by the WinRT `Geolocator`
183-
(`cn1_windows_winrt.cpp`, same `CN1_HAVE_WINRT` gate). `getCurrentLocation` /
182+
(`cn1_windows_winrt.cpp`, shared WinRT layer). `getCurrentLocation` /
184183
`getLastKnownLocation` resolve one fix (lat/lon/accuracy/altitude/heading/speed);
185184
a continuous `LocationListener` is served by a polling thread. When Windows
186185
location is disabled or no provider answers, it reports `OUT_OF_SERVICE` / throws
187-
rather than fabricating a position; `getLocationManager` returns `null` on a
188-
WinRT-less build. Verified on the Windows ARM64 VM: the `Geolocator` activates and
186+
rather than fabricating a position. Verified on the Windows ARM64 VM: the
187+
`Geolocator` activates and
189188
`GetGeopositionAsync` returns `E_ACCESSDENIED` (location off on the VM), which the
190189
port surfaces honestly as unavailable.
191190

@@ -194,13 +193,15 @@ port surfaces honestly as unavailable.
194193
/ PIN). `isSupported()` / `canAuthenticate()` map to `CheckAvailabilityAsync`;
195194
`authenticate(...)` runs the system Hello prompt off the EDT and completes the
196195
`AsyncResource`. WinRT is consumed via the WRL ABI projection
197-
(`cn1_windows_winrt.cpp`), gated on `CN1_HAVE_WINRT` (the generated CMake probes
198-
the toolchain and defines it only when the WinRT ABI headers + `runtimeobject`
199-
link), so a cross-compile sysroot without WinRT compiles the natives as honest
200-
"unsupported" stubs and stays green — the same gating model as WebView2. Verified
201-
on a real Windows ARM64 VM: the WRL pattern activates the factory and awaits the
202-
async op; the VM correctly reports `DeviceNotPresent` (no Hello hardware), so the
203-
port reports unsupported there and a real Hello-equipped laptop reports available.
196+
(`cn1_windows_winrt.cpp`) -- the same COM mechanism the Media Foundation layer
197+
uses, no C++/WinRT needed -- and `runtimeobject` is linked unconditionally: the
198+
WinRT ABI headers + import lib ship in every Windows SDK the port builds against,
199+
including the `xwin`-laid-out SDK the Windows-free Linux cross-compile uses (that
200+
CI leg compiles this file, confirming it). The natives still degrade honestly at
201+
runtime (no device / disabled / denied → `false`/`null`). Verified on a real
202+
Windows ARM64 VM: the WRL pattern activates the factory and awaits the async op;
203+
the VM correctly reports `DeviceNotPresent` (no Hello hardware), so the port
204+
reports unsupported there and a real Hello-equipped laptop reports available.
204205

205206
**Audio recording — implemented.** `createMediaRecorder` / `captureAudio` record
206207
from the default microphone via the classic `waveIn` (winmm) API to a 16-bit PCM

vm/ByteCodeTranslator/src/com/codename1/tools/translator/ByteCodeTranslator.java

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,12 @@ private static void writeCmakeProject(File projectRoot, File srcRoot, String app
758758
// comdlg32: GetOpenFileNameW/GetSaveFileNameW (native file picker).
759759
// crypt32: CryptProtectData/CryptUnprotectData (DPAPI secure storage).
760760
// winmm: waveIn audio recording (cn1_windows_audiorec.c).
761-
writer.append(" target_link_libraries(${PROJECT_NAME} d2d1 dwrite dxgi windowscodecs winhttp ws2_32 user32 gdi32 ole32 oleaut32 uuid mf mfplat mfreadwrite mfuuid shell32 comdlg32 crypt32 winmm)\n");
761+
// runtimeobject: WinRT activation (RoGetActivationFactory) for the
762+
// biometric / location / contacts / share natives (cn1_windows_winrt.cpp).
763+
// The WinRT ABI headers + this import lib ship in every Windows SDK the
764+
// port builds against, including the xwin-laid-out SDK the Linux
765+
// cross-compile uses, so it is linked unconditionally.
766+
writer.append(" target_link_libraries(${PROJECT_NAME} d2d1 dwrite dxgi windowscodecs winhttp ws2_32 user32 gdi32 ole32 oleaut32 uuid mf mfplat mfreadwrite mfuuid shell32 comdlg32 crypt32 winmm runtimeobject)\n");
762767
// BrowserComponent is backed by WebView2 (cn1_windows_browser.cpp),
763768
// gated on the SDK being present: when WEBVIEW2_SDK_DIR points at a
764769
// Microsoft.Web.WebView2 build/native folder we link the static
@@ -778,36 +783,6 @@ private static void writeCmakeProject(File projectRoot, File srcRoot, String app
778783
writer.append(" endif()\n");
779784
writer.append(" target_link_libraries(${PROJECT_NAME} shlwapi version shell32 advapi32)\n");
780785
writer.append(" endif()\n");
781-
// WinRT-backed services (biometric / location / contacts / share) are
782-
// consumed through the WRL ABI projection. The WinRT ABI headers
783-
// (windows.security.credentials.ui.h etc.) and runtimeobject.lib are
784-
// part of a full Windows SDK but may be absent from a cross-compile
785-
// sysroot (e.g. an xwin splat), so probe the toolchain: only when a
786-
// minimal WinRT translation unit compiles + links is CN1_HAVE_WINRT
787-
// defined and runtimeobject linked -- otherwise those natives compile
788-
// as stubs and the matching capabilities report unsupported, exactly
789-
// like the WebView2 gate above. This keeps the Windows-free cross-compile
790-
// green while the real services light up on a Windows-host build.
791-
writer.append(" include(CheckCXXSourceCompiles)\n");
792-
writer.append(" set(CMAKE_REQUIRED_FLAGS \"/EHsc /std:c++17\")\n");
793-
writer.append(" set(CMAKE_REQUIRED_LIBRARIES runtimeobject)\n");
794-
writer.append(" check_cxx_source_compiles(\"\n");
795-
writer.append("#include <roapi.h>\n");
796-
writer.append("#include <wrl.h>\n");
797-
writer.append("#include <wrl/wrappers/corewrappers.h>\n");
798-
writer.append("#include <windows.foundation.h>\n");
799-
writer.append("#include <windows.security.credentials.ui.h>\n");
800-
writer.append("using namespace ABI::Windows::Security::Credentials::UI;\n");
801-
writer.append("int main(){ Microsoft::WRL::Wrappers::RoInitializeWrapper i(RO_INIT_MULTITHREADED);\n");
802-
writer.append(" Microsoft::WRL::ComPtr<IUserConsentVerifierStatics> s;\n");
803-
writer.append(" RoGetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Security_Credentials_UI_UserConsentVerifier).Get(), IID_PPV_ARGS(&s)); return 0; }\n");
804-
writer.append("\" CN1_WINRT_AVAILABLE)\n");
805-
writer.append(" unset(CMAKE_REQUIRED_FLAGS)\n");
806-
writer.append(" unset(CMAKE_REQUIRED_LIBRARIES)\n");
807-
writer.append(" if(CN1_WINRT_AVAILABLE)\n");
808-
writer.append(" target_compile_definitions(${PROJECT_NAME} PRIVATE CN1_HAVE_WINRT=1)\n");
809-
writer.append(" target_link_libraries(${PROJECT_NAME} runtimeobject)\n");
810-
writer.append(" endif()\n");
811786
// Release is the shipping default: optimized (/O2 from the Release
812787
// config) and stripped -- no debug info, and the linker dead-strips
813788
// unreferenced functions (/OPT:REF) and folds identical COMDATs

0 commit comments

Comments
 (0)