-1

I'm learning the new Java FFM API. During the learning, I decided to use Windows SDK to control Taskbar.

The interface ITtaskbarList3 represents the Taskbar and provides functions to control it.

I used the jextract tool to generate necessary classes:

jextract --output target/generated-sources/jextract -t "taskbar_test.gen" -l :shell32 -l :Explorerframe -l :ole32 -I "C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared" -I "C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um" -I "C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\km" -I "C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\km\crt" "C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\ShObjIdl_core.h"

In the code below, I'm trying to obtain CLSID and IID from string and use them to obtain an instance of ITaskbarList3:


package taskbar_test;

import taskbar_test.gen.CLSID;
import taskbar_test.gen.ShObjIdl_core_h;

import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;

public class ComStart {

    public static final String GUID_FORMAT = "{%s}";
    
    // CLSID of ITaskbarList3
    public static final String CLSID_CONST = "56FDF344-FD6D-11d0-958A-006097C9A090";
    // IID of ITaskbarList3
    public static final String IID_CONST = "EA1AFB91-9E28-4B86-90E9-9E9F8A5EEFAF";

    public static void main(String[] args) {

            try (var arena = Arena.ofConfined()) {
                // https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-clsidfromstring#remarks
                // The CLSID format is {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}.
                var clsidString = arena.allocateFrom(GUID_FORMAT.formatted(CLSID_CONST));
                var iidString = arena.allocateFrom(GUID_FORMAT.formatted(IID_CONST));
                var clsid = arena.allocate(CLSID.layout());
                var iid = arena.allocate(CLSID.layout());
                var taskbarPtr = arena.allocate(ShObjIdl_core_h.C_POINTER);

                int hr = ShObjIdl_core_h.CoInitializeEx(MemorySegment.NULL, ShObjIdl_core_h.COINIT_MULTITHREADED());
                if (hr != ShObjIdl_core_h.S_OK()) {
                    throw new RuntimeException("CoInitialize failed with error code: " + hr);
                }

                hr = ShObjIdl_core_h.CLSIDFromString(clsidString, clsid);
                if (hr != ShObjIdl_core_h.S_OK()) {
                    throw new RuntimeException("CLSIDFromString failed with error code: " + hr);
                }
                
                hr = ShObjIdl_core_h.IIDFromString(iidString, iid);
                if (hr != ShObjIdl_core_h.S_OK()) {
                    throw new RuntimeException("IIDFromString failed with error code: " + hr);
                }

                hr = ShObjIdl_core_h.CoCreateInstance(clsid, MemorySegment.NULL, ShObjIdl_core_h.CLSCTX_REMOTE_SERVER(), iid, taskbarPtr);
                if (hr != ShObjIdl_core_h.S_OK()) {
                    if (hr == ShObjIdl_core_h.REGDB_E_CLASSNOTREG()) {
                        System.out.println("COM class is not registered!");
                    }
                    throw new RuntimeException("CoCreateInstance failed with error code: " + hr);
                }

            } finally {
                ShObjIdl_core_h.CoUninitialize();
            }
    }

}

I expect to get the instance, but instead I get error from function CLSIDFromString that the string does not have correct format. I do not understand why, because the format is following documentation.

How the code should look like to be able to obtain instance correctly so I can manage taskbar, namely set progress value.

Thank you.

4
  • 1
    Don't use CLSCTX_REMOTE_SERVER, use CLSCTX_ALL (23) Commented Jan 19 at 16:36
  • On a side note - per MSDN documentation, your app must wait to receive the TaskbarButtonCreated message before it can use the ITaskBarList... interfaces. Commented Jan 19 at 16:50
  • @PetrŠtechmüller - you should answer yourself with all details/changes if your problem is solved Commented Jan 19 at 17:10
  • Oh my bad. It works in the way I'm able to create an instance. I will post the final code asap. Commented Jan 19 at 17:31

1 Answer 1

0

Thanks to advices from all, I was able to create following code:

package taskbar_test;

import taskbar_test.gen.CLSID;
import taskbar_test.gen.ShObjIdl_core_h;

import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.nio.charset.StandardCharsets;

public class ComStart {

    public static final String GUID_FORMAT = "{%s}";
    
    // CLSID of ITaskbarList3
    public static final String CLSID_CONST = "56FDF344-FD6D-11d0-958A-006097C9A090";
    // IID of ITaskbarList3
    public static final String IID_CONST = "EA1AFB91-9E28-4B86-90E9-9E9F8A5EEFAF";

    public static void main(String[] args) {

            try (var arena = Arena.ofConfined()) {
                // https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-clsidfromstring#remarks
                // The CLSID format is {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}.
                var clsidString = arena.allocateFrom(GUID_FORMAT.formatted(CLSID_CONST), StandardCharsets.UTF_16LE);
                var iidString = arena.allocateFrom(GUID_FORMAT.formatted(IID_CONST), StandardCharsets.UTF_16LE);
                var clsid = arena.allocate(CLSID.layout());
                var iid = arena.allocate(CLSID.layout());
                var taskbarPtr = arena.allocate(ShObjIdl_core_h.C_POINTER);

                int hr = ShObjIdl_core_h.CoInitializeEx(MemorySegment.NULL, ShObjIdl_core_h.COINIT_MULTITHREADED());
                if (hr != ShObjIdl_core_h.S_OK()) {
                    throw new RuntimeException("CoInitialize failed with error code: " + hr);
                }

                hr = ShObjIdl_core_h.CLSIDFromString(clsidString, clsid);
                if (hr != ShObjIdl_core_h.S_OK()) {
                    throw new RuntimeException("CLSIDFromString failed with error code: " + hr);
                }
                
                hr = ShObjIdl_core_h.IIDFromString(iidString, iid);
                if (hr != ShObjIdl_core_h.S_OK()) {
                    throw new RuntimeException("IIDFromString failed with error code: " + hr);
                }

                hr = ShObjIdl_core_h.CoCreateInstance(clsid, MemorySegment.NULL, ShObjIdl_core_h.CLSCTX_ALL(), iid, taskbarPtr);
                if (hr != ShObjIdl_core_h.S_OK()) {
                    if (hr == ShObjIdl_core_h.REGDB_E_CLASSNOTREG()) {
                        System.out.println("COM class is not registered!");
                    }
                    throw new RuntimeException("CoCreateInstance failed with error code: " + hr);
                }

            } finally {
                ShObjIdl_core_h.CoUninitialize();
            }
    }

}

Now the instance is created correctly.

Sign up to request clarification or add additional context in comments.

1 Comment

Just a tip: you can add import static taskbar_test.gen.ShObjIdl_core_h.*; so you don't have to prefix everything with ShObjIdl_core_h. if you want. Also, CLSID should have an allocate method that you can use to be a bit more concise CLSID.allocate(arena);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.