0

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:

  1. building the Flutter code for Windows using flutter build window --debug
  2. open command line and change the command line path to ../helloworld/build/windows/runner/debug
  3. run the exe helloworld.exe

Now the app opens:

enter image description here

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.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
venkat j
  • 1
  • 1

0 Answers0