Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OSD AoT library #1349

Open
wants to merge 17 commits into
base: master
Choose a base branch
from

Conversation

Ace-Radom
Copy link
Contributor

@Ace-Radom Ace-Radom commented Jun 26, 2024

Add possibility for users to show an OSD always on top.

Description

This feature is (or should be) based on a C++/CLI library, using GDI+ for on-screen bitmap drawing. The library creates a pop-up window (with window style WS_POPUP), renders the bitmap and puts it in the window.

Currently it uses a external picture (eject.png) for testing.

This PR adds a new project LenovoLegionToolkit.Lib.AoTOSD into the solution. It contains the AoT OSD library. The C# interface of this library is NotificationWindowAoT under namespace LenovoLegionToolkit.Lib.AoTOSD.

There's only some things need to know:

  1. Unlike the NotificationWindow at the moment, NotificationWindowAoT should only be inited once in each run. This is because the AoT OSD window is registered with the constructor, and unregistered with the destructor of the class. Theoretically when we are sure that the class has already been destructed before it is constructed again, we're able to init NotificationWindowAoT class for more than once, but I don't recommend it. In my debug codes I just put it into the IoC container, and it worked well.

  2. Showing an new AoT OSD window is really simple: just create a managed bitmap (System.Drawing.Bitmap) and pass it to NotificationWindowAoT.Show(). The position and visible duration should also be passed at the same time. And then...there's actually no other thing to worry about. The library convert automatically the managed bitmap to a native C++ bitmap and is responsible for the memory management there.

  3. The new library requires LenovoLegionToolkit.Lib for the global logger.

TODO

  • basic window-base class & layered window
  • a native C++ interface for AoT OSD window
  • animation
  • display on multi-virtual-desktop
  • a C++/CLI interface which is easier for C# to use
  • a wrapper for global logger in C++/CLI
  • converting C# bitmap to native C++ bitmap
  • error handling
  • code refactoring
  • A trigger for user to choose the OSD should be shown whether in classic form / AoT
  • use make.bat to compile

Confirmed Issues

  • Currently the library is functionaly-correct only when it is called in a command-line program. When I test it within the CLI, the AoT OSD works pretty nice, but once it was added into WPF, something just went wrong. The OSD shows little bit smaller than it should be, and it's not AoT any more: I mean, when there's already one window gain the TopMost state, it doesn't work any more.

    I don't know if I'm able to handle this issue, since the project I referenced itself (3RVX) is also a command-line based software. With the creation of the pop-up window an instance handle should be passed to RegisterClassEx & CreateWindowEx API, and this handle is got from GetModuleHandle. Due to something I don't know, it seems that this handle must be a command-line-executable handle. If I cannot fix this bug in current architecture, maybe I'll try another way / a workaround. Nah it is not... I just forgot sth in the notification manager code.

    2024/6/27 update: issue solved.

  • Converting .Net bitmap (System.Drawing.Bitmap) to C++ native bitmap (Gdiplus::Bitmap) losts alpha channal.

    2024/6/28 update: issue solved.

@Ace-Radom
Copy link
Contributor Author

Status update: the bug has been solved, I'll begin code refactoring

@Ace-Radom
Copy link
Contributor Author

Ace-Radom commented Jun 29, 2024

@BartoszCichecki Would you please help me with the compilation with make.bat? In IDE it works fine but I cannot compile it with the make script (on Github Action either, so I removed the proj ref for now). Other OSD AoT functions have been done.

@Ace-Radom Ace-Radom marked this pull request as ready for review June 29, 2024 01:13
@Ace-Radom
Copy link
Contributor Author

Okay after some research seems that the msbuild provided by .net doesn't support compiling C++/CLI project cuz lots of the files are missing. It needs the msbuild provided directly by VS to compile. I'm considering if I should directly rewrite this function in C#, or I should find another way to compile the library.

@BartoszCichecki
Copy link
Owner

I looked at the code, and it isn't much I think that will be problematic to migrate over to P/Invoke, so if building is a challenge, I can take this over (next week I will most likely have some time). It's up to you. No rush.

@Ace-Radom
Copy link
Contributor Author

I looked at the code, and it isn't much I think that will be problematic to migrate over to P/Invoke, so if building is a challenge, I can take this over (next week I will most likely have some time). It's up to you. No rush.

Yeah I actually have another idea, maybe we can use a WinForm window as the OSD container. In this way all codes would be written in C# and there should be no compile problems any more. I'll also give a try on P/Invoke again. (compilation problem...yeah classic C++ stuff)

@Ace-Radom
Copy link
Contributor Author

Ace-Radom commented Jul 4, 2024

After some tests, creating a WinForm window with the following CreateParams:

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        unchecked
        {
            cp.Style |= (int)WS_POPUP;
        }
        cp.ExStyle |= WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE | WS_EX_TOPMOST;
        return cp;
    }
}

does almost the same thing. But the problem is, as noticed in #1053, current OSD cannot show on multiple virtual desktops, and the WinForm OSD Container suffers most likely the same limitation (at least I don't know a simple way to move windows from one vdesktop to another).

With a WinForm OSD Container we don't need (I think, haven't tested yet) to make a bitmap view from the classic OSD window anymore, since WinForm already provides an ElementHost to integrate. But in this way, #1053 won't be solved and would still be a problem. Therefore I'll try with P/Invoke for now, if it is really hard to migrate (mostly because the class pointer required by WndProc & the callback function pointer required by RegisterClassEx, and also I'm not sure if the HBITMAP got from C# can work with native WINAPI calls), the WinForm OSD Container would be a second choice I think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants