Add url_launcher_windows (#3015)

Adds a federated Windows implementation of url_launcher (not yet endorsed).

Since this is the first C++ plugin, this also adds a .clang-format file to the repo root for formatting C++ plugins.

Part of flutter/flutter#41721 (will need follow-up to endorse it in url_launcher)
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..f6cb8ad
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: Google
diff --git a/packages/url_launcher/url_launcher_windows/.gitignore b/packages/url_launcher/url_launcher_windows/.gitignore
new file mode 100644
index 0000000..53e92cc
--- /dev/null
+++ b/packages/url_launcher/url_launcher_windows/.gitignore
@@ -0,0 +1,3 @@
+.packages
+.flutter-plugins
+pubspec.lock
diff --git a/packages/url_launcher/url_launcher_windows/.metadata b/packages/url_launcher/url_launcher_windows/.metadata
new file mode 100644
index 0000000..720a459
--- /dev/null
+++ b/packages/url_launcher/url_launcher_windows/.metadata
@@ -0,0 +1,10 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+  revision: 6d1c244b79f3a2747281f718297ce248bd5ad099
+  channel: master
+
+project_type: plugin
diff --git a/packages/url_launcher/url_launcher_windows/CHANGELOG.md b/packages/url_launcher/url_launcher_windows/CHANGELOG.md
new file mode 100644
index 0000000..dd3395a
--- /dev/null
+++ b/packages/url_launcher/url_launcher_windows/CHANGELOG.md
@@ -0,0 +1,3 @@
+## 0.0.1
+
+* Initial Windows implementation of `url_launcher`.
diff --git a/packages/url_launcher/url_launcher_windows/LICENSE b/packages/url_launcher/url_launcher_windows/LICENSE
new file mode 100644
index 0000000..5075698
--- /dev/null
+++ b/packages/url_launcher/url_launcher_windows/LICENSE
@@ -0,0 +1,25 @@
+Copyright 2019 The Chromium Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of Google Inc. nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/packages/url_launcher/url_launcher_windows/README.md b/packages/url_launcher/url_launcher_windows/README.md
new file mode 100644
index 0000000..685adc5
--- /dev/null
+++ b/packages/url_launcher/url_launcher_windows/README.md
@@ -0,0 +1,31 @@
+# url_launcher_windows
+
+The Windows implementation of [`url_launcher`][1].
+
+## Backward compatible 1.0.0 version is coming
+The plugin has reached a stable API, we guarantee that version `1.0.0` will be backward compatible with `0.0.y+z`. If you use
+url_launcher_windows directly, rather than as an implementation detail
+of `url_launcher`, please use `url_launcher_windows: '>=0.0.y+x <2.0.0'`
+as your dependency constraint to allow a smoother ecosystem migration.
+For more details see: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0
+
+## Usage
+
+### Import the package
+
+This package has not yet been endorsed. Once it is you only need to add
+`url_launcher` as a dependency in your `pubspec.yaml`, but for now you
+need to include both `url_launcher` and `url_launcher_windows`.
+
+This is what the above means to your `pubspec.yaml`:
+
+```yaml
+...
+dependencies:
+  ...
+  url_launcher: ^5.5.3
+  url_launcher_windows: ^0.0.1
+  ...
+```
+
+[1]: ../url_launcher/url_launcher
diff --git a/packages/url_launcher/url_launcher_windows/example/.gitignore b/packages/url_launcher/url_launcher_windows/example/.gitignore
new file mode 100644
index 0000000..9d532b1
--- /dev/null
+++ b/packages/url_launcher/url_launcher_windows/example/.gitignore
@@ -0,0 +1,41 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+**/ios/Flutter/.last_build_id
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+.packages
+.pub-cache/
+.pub/
+/build/
+
+# Web related
+lib/generated_plugin_registrant.dart
+
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json
diff --git a/packages/url_launcher/url_launcher_windows/example/.metadata b/packages/url_launcher/url_launcher_windows/example/.metadata
new file mode 100644
index 0000000..82cce8b
--- /dev/null
+++ b/packages/url_launcher/url_launcher_windows/example/.metadata
@@ -0,0 +1,10 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+  revision: 6d1c244b79f3a2747281f718297ce248bd5ad099
+  channel: master
+
+project_type: app
diff --git a/packages/url_launcher/url_launcher_windows/example/README.md b/packages/url_launcher/url_launcher_windows/example/README.md
new file mode 100644
index 0000000..e444852
--- /dev/null
+++ b/packages/url_launcher/url_launcher_windows/example/README.md
@@ -0,0 +1,3 @@
+# url_launcher_windows_example
+
+Demonstrates the url_launcher_windows plugin.
diff --git a/packages/url_launcher/url_launcher_windows/example/lib/main.dart b/packages/url_launcher/url_launcher_windows/example/lib/main.dart
new file mode 100644
index 0000000..db59af1
--- /dev/null
+++ b/packages/url_launcher/url_launcher_windows/example/lib/main.dart
@@ -0,0 +1,93 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ignore_for_file: public_member_api_docs
+
+import 'dart:async';
+import 'package:flutter/material.dart';
+import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart';
+
+void main() {
+  runApp(MyApp());
+}
+
+class MyApp extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    return MaterialApp(
+      title: 'URL Launcher',
+      theme: ThemeData(
+        primarySwatch: Colors.blue,
+      ),
+      home: MyHomePage(title: 'URL Launcher'),
+    );
+  }
+}
+
+class MyHomePage extends StatefulWidget {
+  MyHomePage({Key key, this.title}) : super(key: key);
+  final String title;
+
+  @override
+  _MyHomePageState createState() => _MyHomePageState();
+}
+
+class _MyHomePageState extends State<MyHomePage> {
+  Future<void> _launched;
+
+  Future<void> _launchInBrowser(String url) async {
+    if (await UrlLauncherPlatform.instance.canLaunch(url)) {
+      await UrlLauncherPlatform.instance.launch(
+        url,
+        useSafariVC: false,
+        useWebView: false,
+        enableJavaScript: false,
+        enableDomStorage: false,
+        universalLinksOnly: false,
+        headers: <String, String>{},
+      );
+    } else {
+      throw 'Could not launch $url';
+    }
+  }
+
+  Widget _launchStatus(BuildContext context, AsyncSnapshot<void> snapshot) {
+    if (snapshot.hasError) {
+      return Text('Error: ${snapshot.error}');
+    } else {
+      return const Text('');
+    }
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    const String toLaunch = 'https://www.cylog.org/headers/';
+    return Scaffold(
+      appBar: AppBar(
+        title: Text(widget.title),
+      ),
+      body: ListView(
+        children: <Widget>[
+          Column(
+            mainAxisAlignment: MainAxisAlignment.center,
+            children: <Widget>[
+              const Padding(
+                padding: EdgeInsets.all(16.0),
+                child: Text(toLaunch),
+              ),
+              RaisedButton(
+                onPressed: () => setState(() {
+                  _launched = _launchInBrowser(toLaunch);
+                }),
+                child: const Text('Launch in browser'),
+              ),
+              const Padding(padding: EdgeInsets.all(16.0)),
+              FutureBuilder<void>(future: _launched, builder: _launchStatus),
+            ],
+          ),
+        ],
+      ),
+    );
+  }
+}
diff --git a/packages/url_launcher/url_launcher_windows/example/pubspec.yaml b/packages/url_launcher/url_launcher_windows/example/pubspec.yaml
new file mode 100644
index 0000000..8d6c220
--- /dev/null
+++ b/packages/url_launcher/url_launcher_windows/example/pubspec.yaml
@@ -0,0 +1,19 @@
+name: url_launcher_example
+description: Demonstrates the Windows implementation of the url_launcher plugin.
+
+dependencies:
+  flutter:
+    sdk: flutter
+  url_launcher_platform_interface: any
+  url_launcher_windows:
+    path: ../
+
+dev_dependencies:
+  integration_test:
+    path: ../../../integration_test
+  flutter_driver:
+    sdk: flutter
+  pedantic: ^1.8.0
+
+flutter:
+  uses-material-design: true
diff --git a/packages/url_launcher/url_launcher_windows/example/test_driver/url_launcher_e2e.dart b/packages/url_launcher/url_launcher_windows/example/test_driver/url_launcher_e2e.dart
new file mode 100644
index 0000000..7a33e00
--- /dev/null
+++ b/packages/url_launcher/url_launcher_windows/example/test_driver/url_launcher_e2e.dart
@@ -0,0 +1,20 @@
+// Copyright 2019, the Chromium project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:flutter_test/flutter_test.dart';
+import 'package:integration_test/integration_test.dart';
+import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart';
+
+void main() {
+  IntegrationTestWidgetsFlutterBinding.ensureInitialized();
+
+  test('canLaunch', () async {
+    UrlLauncherPlatform launcher = UrlLauncherPlatform.instance;
+
+    expect(await launcher.canLaunch('randomstring'), false);
+
+    // Generally all devices should have some default browser.
+    expect(await launcher.canLaunch('http://flutter.dev'), true);
+  });
+}
diff --git a/packages/url_launcher/url_launcher_windows/example/test_driver/url_launcher_e2e_test.dart b/packages/url_launcher/url_launcher_windows/example/test_driver/url_launcher_e2e_test.dart
new file mode 100644
index 0000000..7a2c213
--- /dev/null
+++ b/packages/url_launcher/url_launcher_windows/example/test_driver/url_launcher_e2e_test.dart
@@ -0,0 +1,17 @@
+// Copyright 2019, the Chromium project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+import 'package:flutter_driver/flutter_driver.dart';
+
+Future<void> main() async {
+  final FlutterDriver driver = await FlutterDriver.connect();
+  final String data =
+      await driver.requestData(null, timeout: const Duration(minutes: 1));
+  await driver.close();
+  final Map<String, dynamic> result = jsonDecode(data);
+  exit(result['result'] == 'true' ? 0 : 1);
+}
diff --git a/packages/url_launcher/url_launcher_windows/lib/url_launcher_windows.dart b/packages/url_launcher/url_launcher_windows/lib/url_launcher_windows.dart
new file mode 100644
index 0000000..83435f9
--- /dev/null
+++ b/packages/url_launcher/url_launcher_windows/lib/url_launcher_windows.dart
@@ -0,0 +1,3 @@
+// The url_launcher_platform_interface defaults to MethodChannelUrlLauncher
+// as its instance, which is all the Windows implementation needs. This file
+// is here to silence warnings when publishing to pub.
diff --git a/packages/url_launcher/url_launcher_windows/pubspec.yaml b/packages/url_launcher/url_launcher_windows/pubspec.yaml
new file mode 100644
index 0000000..8a0beb7
--- /dev/null
+++ b/packages/url_launcher/url_launcher_windows/pubspec.yaml
@@ -0,0 +1,21 @@
+name: url_launcher_windows
+description: Windows implementation of the url_launcher plugin.
+# 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump
+# the version to 2.0.0.
+# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0
+version: 0.0.1
+homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_windows
+
+flutter:
+  plugin:
+    platforms:
+      windows:
+        pluginClass: UrlLauncherPlugin
+
+environment:
+  sdk: ">=2.1.0 <3.0.0"
+  flutter: ">=1.12.8 <2.0.0"
+
+dependencies:
+  flutter:
+    sdk: flutter
diff --git a/packages/url_launcher/url_launcher_windows/windows/.gitignore b/packages/url_launcher/url_launcher_windows/windows/.gitignore
new file mode 100644
index 0000000..b3eb2be
--- /dev/null
+++ b/packages/url_launcher/url_launcher_windows/windows/.gitignore
@@ -0,0 +1,17 @@
+flutter/
+
+# Visual Studio user-specific files.
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# Visual Studio build-related files.
+x64/
+x86/
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
diff --git a/packages/url_launcher/url_launcher_windows/windows/CMakeLists.txt b/packages/url_launcher/url_launcher_windows/windows/CMakeLists.txt
new file mode 100644
index 0000000..57d87e3
--- /dev/null
+++ b/packages/url_launcher/url_launcher_windows/windows/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 3.10)
+set(PROJECT_NAME "url_launcher_windows")
+project(${PROJECT_NAME} LANGUAGES CXX)
+
+set(PLUGIN_NAME "${PROJECT_NAME}_plugin")
+
+add_library(${PLUGIN_NAME} SHARED
+  "url_launcher_plugin.cpp"
+)
+apply_standard_settings(${PLUGIN_NAME})
+set_target_properties(${PLUGIN_NAME} PROPERTIES
+  CXX_VISIBILITY_PRESET hidden)
+target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
+target_include_directories(${PLUGIN_NAME} INTERFACE
+  "${CMAKE_CURRENT_SOURCE_DIR}/include")
+target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin)
+
+# List of absolute paths to libraries that should be bundled with the plugin
+set(file_chooser_bundled_libraries
+  ""
+  PARENT_SCOPE
+)
diff --git a/packages/url_launcher/url_launcher_windows/windows/include/url_launcher_windows/url_launcher_plugin.h b/packages/url_launcher/url_launcher_windows/windows/include/url_launcher_windows/url_launcher_plugin.h
new file mode 100644
index 0000000..cdd018a
--- /dev/null
+++ b/packages/url_launcher/url_launcher_windows/windows/include/url_launcher_windows/url_launcher_plugin.h
@@ -0,0 +1,26 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifndef PACKAGES_URL_LAUNCHER_URL_LAUNCHER_WINDOWS_WINDOWS_INCLUDE_URL_LAUNCHER_WINDOWS_URL_LAUNCHER_PLUGIN_H_
+#define PACKAGES_URL_LAUNCHER_URL_LAUNCHER_WINDOWS_WINDOWS_INCLUDE_URL_LAUNCHER_WINDOWS_URL_LAUNCHER_PLUGIN_H_
+
+#include <flutter_plugin_registrar.h>
+
+#ifdef FLUTTER_PLUGIN_IMPL
+#define FLUTTER_PLUGIN_EXPORT __declspec(dllexport)
+#else
+#define FLUTTER_PLUGIN_EXPORT __declspec(dllimport)
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+FLUTTER_PLUGIN_EXPORT void UrlLauncherPluginRegisterWithRegistrar(
+    FlutterDesktopPluginRegistrarRef registrar);
+
+#if defined(__cplusplus)
+}  // extern "C"
+#endif
+
+#endif  // PACKAGES_URL_LAUNCHER_URL_LAUNCHER_WINDOWS_WINDOWS_INCLUDE_URL_LAUNCHER_WINDOWS_URL_LAUNCHER_PLUGIN_H_
diff --git a/packages/url_launcher/url_launcher_windows/windows/url_launcher_plugin.cpp b/packages/url_launcher/url_launcher_windows/windows/url_launcher_plugin.cpp
new file mode 100644
index 0000000..dfb4063
--- /dev/null
+++ b/packages/url_launcher/url_launcher_windows/windows/url_launcher_plugin.cpp
@@ -0,0 +1,148 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "include/url_launcher_windows/url_launcher_plugin.h"
+
+#include <flutter/method_channel.h>
+#include <flutter/plugin_registrar_windows.h>
+#include <flutter/standard_method_codec.h>
+#include <windows.h>
+
+#include <memory>
+#include <sstream>
+#include <string>
+
+namespace {
+
+using flutter::EncodableMap;
+using flutter::EncodableValue;
+
+// Converts the given UTF-8 string to UTF-16.
+std::wstring Utf16FromUtf8(const std::string& utf8_string) {
+  if (utf8_string.empty()) {
+    return std::wstring();
+  }
+  int target_length =
+      ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8_string.data(),
+                            static_cast<int>(utf8_string.length()), nullptr, 0);
+  if (target_length == 0) {
+    return std::wstring();
+  }
+  std::wstring utf16_string;
+  utf16_string.resize(target_length);
+  int converted_length =
+      ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8_string.data(),
+                            static_cast<int>(utf8_string.length()),
+                            utf16_string.data(), target_length);
+  if (converted_length == 0) {
+    return std::wstring();
+  }
+  return utf16_string;
+}
+
+// Returns the URL argument from |method_call| if it is present, otherwise
+// returns an empty string.
+std::string GetUrlArgument(const flutter::MethodCall<>& method_call) {
+  std::string url;
+  const auto* arguments = std::get_if<EncodableMap>(method_call.arguments());
+  if (arguments) {
+    auto url_it = arguments->find(EncodableValue("url"));
+    if (url_it != arguments->end()) {
+      url = std::get<std::string>(url_it->second);
+    }
+  }
+  return url;
+}
+
+class UrlLauncherPlugin : public flutter::Plugin {
+ public:
+  static void RegisterWithRegistrar(flutter::PluginRegistrar* registrar);
+
+  virtual ~UrlLauncherPlugin();
+
+ private:
+  UrlLauncherPlugin();
+
+  // Called when a method is called on plugin channel;
+  void HandleMethodCall(const flutter::MethodCall<>& method_call,
+                        std::unique_ptr<flutter::MethodResult<>> result);
+};
+
+// static
+void UrlLauncherPlugin::RegisterWithRegistrar(
+    flutter::PluginRegistrar* registrar) {
+  auto channel = std::make_unique<flutter::MethodChannel<>>(
+      registrar->messenger(), "plugins.flutter.io/url_launcher",
+      &flutter::StandardMethodCodec::GetInstance());
+
+  // Uses new instead of make_unique due to private constructor.
+  std::unique_ptr<UrlLauncherPlugin> plugin(new UrlLauncherPlugin());
+
+  channel->SetMethodCallHandler(
+      [plugin_pointer = plugin.get()](const auto& call, auto result) {
+        plugin_pointer->HandleMethodCall(call, std::move(result));
+      });
+
+  registrar->AddPlugin(std::move(plugin));
+}
+
+UrlLauncherPlugin::UrlLauncherPlugin() = default;
+
+UrlLauncherPlugin::~UrlLauncherPlugin() = default;
+
+void UrlLauncherPlugin::HandleMethodCall(
+    const flutter::MethodCall<>& method_call,
+    std::unique_ptr<flutter::MethodResult<>> result) {
+  if (method_call.method_name().compare("launch") == 0) {
+    std::string url = GetUrlArgument(method_call);
+    if (url.empty()) {
+      result->Error("argument_error", "No URL provided");
+      return;
+    }
+    std::wstring url_wide = Utf16FromUtf8(url);
+
+    int status = static_cast<int>(reinterpret_cast<INT_PTR>(
+        ::ShellExecute(nullptr, TEXT("open"), url_wide.c_str(), nullptr,
+                       nullptr, SW_SHOWNORMAL)));
+
+    if (status <= 32) {
+      std::ostringstream error_message;
+      error_message << "Failed to open " << url << ": ShellExecute error code "
+                    << status;
+      result->Error("open_error", error_message.str());
+      return;
+    }
+    result->Success(EncodableValue(true));
+  } else if (method_call.method_name().compare("canLaunch") == 0) {
+    std::string url = GetUrlArgument(method_call);
+    if (url.empty()) {
+      result->Error("argument_error", "No URL provided");
+      return;
+    }
+
+    bool can_launch = false;
+    size_t separator_location = url.find(":");
+    if (separator_location != std::string::npos) {
+      std::wstring scheme = Utf16FromUtf8(url.substr(0, separator_location));
+      HKEY key = nullptr;
+      if (::RegOpenKeyEx(HKEY_CLASSES_ROOT, scheme.c_str(), 0, KEY_QUERY_VALUE,
+                         &key) == ERROR_SUCCESS) {
+        can_launch = ::RegQueryValueEx(key, L"URL Protocol", nullptr, nullptr,
+                                       nullptr, nullptr) == ERROR_SUCCESS;
+        ::RegCloseKey(key);
+      }
+    }
+    result->Success(EncodableValue(can_launch));
+  } else {
+    result->NotImplemented();
+  }
+}
+
+}  // namespace
+
+void UrlLauncherPluginRegisterWithRegistrar(
+    FlutterDesktopPluginRegistrarRef registrar) {
+  UrlLauncherPlugin::RegisterWithRegistrar(
+      flutter::PluginRegistrarManager::GetInstance()
+          ->GetRegistrar<flutter::PluginRegistrarWindows>(registrar));
+}