I'm trying to build a flutter app that receives a sendMessage from native code, in this case its C++. sendMessage is sent only on relaunch of existing app instance.
Here I'm attaching the code for more clarity on what I'm trying to do.
code for main.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _message = 'Hello world';
@override
void initState() {
super.initState();
//trying to call the c++ sendmessage to read the message and setstate of _message to the Hello from c++
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter App'),
),
body: Center(
child: Text(
_message,
style: TextStyle(fontSize: 24),
),
),
);
}
}
code for main.cpp
#include <Windows.h>
#include <flutter/dart_project.h>
#include <flutter/flutter_view_controller.h>
#include <string>
#include "flutter_window.h"
#include "utils.h"
// Constants
const wchar_t kMutexName[] = L"helloworld"; // Unique name for the mutex
const wchar_t kFlutterWindowTitle[] = L"helloworld"; // Title of the app's window
const wchar_t kClassName[] = L"helloworld"; // Class name for the app's window
const wchar_t kMessage[] = L"Hello from C++"; // Message to send from C++ to Dart
// Global variables
HWND g_hWnd = nullptr; // Handle to the app's window
// Function to check if the app is already running
bool IsAppAlreadyRunning() {
HANDLE hMutex = CreateMutex(nullptr, TRUE, kMutexName);
if (GetLastError() == ERROR_ALREADY_EXISTS) {
CloseHandle(hMutex);
return true;
}
return false;
}
// Function to bring the running instance window to foreground
void BringWindowToForeground() {
if (g_hWnd) {
ShowWindow(g_hWnd, 9);
SetForegroundWindow(g_hWnd);
}
}
// Function to send message from C++ to Dart
void SendMessageToDart() {
if (g_hWnd) {
COPYDATASTRUCT cds;
cds.dwData = 0;
cds.cbData = (DWORD)((wcslen(kMessage) + 1) * sizeof(wchar_t));
cds.lpData = (LPVOID)kMessage;
SendMessage(g_hWnd, WM_COPYDATA, (WPARAM)(HWND)nullptr, (LPARAM)(LPVOID)&cds);
}
}
// Window procedure for the app's window
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_COPYDATA: {
PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT)lParam;
if (pcds->cbData > 0 && pcds->lpData != nullptr) {
// Update the "Hello world" text with the passed message
std::wstring message(reinterpret_cast<const wchar_t*>(pcds->lpData), pcds->cbData / sizeof(wchar_t));
SetWindowText(hWnd, message.c_str());
}
return TRUE;
}
// Add any other window messages to handle here if needed
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
// Entry point of the app
int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
g_hWnd = FindWindow(0, kFlutterWindowTitle);
// Check if the app is already running
if (IsAppAlreadyRunning()) {
// Bring the running instance window to foreground
BringWindowToForeground();
// Send message from C++ to Dart
SendMessageToDart();
return FALSE;
}
// Attach to console when present (e.g., 'flutter run') or create a
// new console when running with a debugger.
if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
CreateAndAttachConsole();
}
// Initialize COM, so that it is available for use in the library and/or
// plugins.
::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
flutter::DartProject project(L"data");
std::vector<std::string> command_line_arguments =
GetCommandLineArguments();
project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
FlutterWindow window(project);
Win32Window::Point origin(10, 10);
Win32Window::Size size(1280, 720);
if (!window.Create(L"helloworld", origin, size)) {
return EXIT_FAILURE;
}
window.SetQuitOnClose(true);
::MSG msg;
while (::GetMessage(&msg, nullptr, 0, 0)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
::CoUninitialize();
return EXIT_SUCCESS;
}
Steps to build and run the following code:
On first instance launch of Flutter app:
- building the Flutter code for Windows using
flutter build window --debug
- open command line and change the command line path to
../helloworld/build/windows/runner/debug
- run the exe
helloworld.exe
Now the app opens:
let the instance be in running state.
On relaunch of flutter app:
4.open command line and change the command line path to ../helloworld/build/windows/runner/debug
5. run the exe helloworld.exe
On relaunch according to main.cpp, it checks the existingApp and then it will foreground the existing app then it does sendMessage(hwnd, msg, wparam, lparam)
. However, I'm not able to handle the sendMessage in Flutter. How can I do this?
Expected results on relaunch are it should replace the hello world text to Hello from C++.
As I'm new to Flutter, I don't know how to implement the Flutter code to read the message that is sent from C++ and I couldn't find any example projects on GitHub that use Windows native code either.