最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - Fail to create instance of ITaskbarList3 - Stack Overflow

programmeradmin2浏览0评论

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()) {
                // 
                // 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.

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.

Share Improve this question edited Jan 19 at 17:10 Simon Mourier 139k22 gold badges262 silver badges310 bronze badges asked Jan 19 at 15:46 Petr ŠtechmüllerPetr Štechmüller 2311 silver badge9 bronze badges 4
  • 1 Don't use CLSCTX_REMOTE_SERVER, use CLSCTX_ALL (23) – Simon Mourier 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. – Remy Lebeau Commented Jan 19 at 16:50
  • @PetrŠtechmüller - you should answer yourself with all details/changes if your problem is solved – Simon Mourier 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. – Petr Štechmüller Commented Jan 19 at 17:31
Add a comment  | 

2 Answers 2

Reset to default 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.

You have used UTF-8 encoding to convert String to MemorySegment, which is the default for allocateFrom(String). Specify Windows Wide character set UTF_16LE as an extra parameter for allocateFrom:

var clsidString = arena.allocateFrom(GUID_FORMAT.formatted(CLSID_CONST), StandardCharsets.UTF_16LE);
var iidString = arena.allocateFrom(GUID_FORMAT.formatted(IID_CONST), StandardCharsets.UTF_16LE);
发布评论

评论列表(0)

  1. 暂无评论