Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: Linker error when using find_or_create_playlist() (Read 1367 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

Linker error when using find_or_create_playlist()

Hi,

using some tutorial at http://yirkha.fud.cz/tmp/496351ef.tutorial-draft.html I was able to get a "useless component" compiled and running. Some most basic API calls work fine as well, but it seems I am not linking against everything I should be linking against. (the tutorial is a bit outdated and I had to figure various stuff out myself)

Currently I am linking these libraries:
Code: [Select]
foobar2000\shared\shared.lib
foobar2000\SDK\Debug\foobar2000_SDK.lib
foobar2000\foobar2000_component_client\Debug\foobar2000_component_client.lib
pfc\Debug\pfc.lib
(Replacing Debug for Release for Release build)

Compiling the following gives me a linker error.
Code: [Select]
	static_api_ptr_t<playlist_manager> pm;
t_size playlist = pm->find_or_create_playlist("Foo");

The error:
Code: [Select]
Severity	Code	Description	Project	File	Line	Suppression State
Error LNK2019 unresolved external symbol __imp__StrCmpLogicalW@8 referenced in function __catch$??$service_add_ref_safe@Vmetadb_handle@@@@YAXPAVmetadb_handle@@@Z$0 foo_smart_queue D:\Projects\Code\C++\FoobarExtensions\foobar2000\SDK\foo_smart_queue\foobar2000_SDK.lib(metadb_handle_list.obj) 1

I'm really not sure what else I need. Ideas?

Another thing that struck me as odd was that I was not able to use the << operator on console::formatter(). I worked around it by using an std::stringstream.
Code: [Select]
console::formatter() << "Hello! Version = " << core_version_info::g_get_version_string() << ".";
This yields "no operator '<<' matches these operands".

Disclaimer: I haven't used C++ in over 3 years.

Re: Linker error when using find_or_create_playlist()

Reply #1
There's foo_sample component bundled with the SDK that has ready-made solution and project files. You can use it as a reference.

Re: Linker error when using find_or_create_playlist()

Reply #2
I went through this process myself recently (i.e. yesterday), and I think you're better off skipping some half-assed or out-of-date tutorial and going straight to the source. Download the 1.4 SDK and play around with foo_sample. It does way more stuff than whatever you have probably set up.

While you're at it, download the Visual Studio 2017 Community edition. It's free and pretty good for this stuff. On install, choose Desktop Development with C++. Aside from the default options you'll also need to install Windows 8.1 SDK and UCRT SDK (might not need this one), Windows XP support for C++, MFC and ATL support, C++/CLI support.

Then load up the foo_sample solution. You might have some other dependencies missing, but if you can't find them in a search of this forum, ask here and I can walk you through it.

BTW, I think the recommended way to do send text to the console is:
FB2K_console_formatter() << "blah";

Re: Linker error when using find_or_create_playlist()

Reply #3
Found the solution here https://hydrogenaud.io/index.php/topic,63308.0.html

If I ever make another component, I will base it on foo_sample. Luckily I only wanted some really simple context menu entry which adds songs to a playlist and makes an entry in the playback queue to transition to that playlist. It's kinda amazing I was able to pull this off just by power of educated guesses alone (especially the bit_array part - I just guess(ed) it's a mask for what items from data to add). Anyone fancy a read?

Code: [Select]
#include "stdafx.h"

namespace {
// Identifier of our context menu group. Substitute with your own when reusing code.
static const GUID guid_smart_queue_item_group = { 0x239af9eb, 0x826a, 0x4b6d, { 0xb6, 0x2e, 0x81, 0x83, 0x97, 0x5a, 0xdf, 0x3c } };


static contextmenu_group_factory g_mygroup(guid_smart_queue_item_group, contextmenu_groups::root, 0);

static void SmartQueue(metadb_handle_list_cref data);

static bool GetPlaylistHasQueuedItems(size_t playlist);

class SmartQueueMenuItem : public contextmenu_item_simple {
public:
enum {
cmd_smart_queue = 0,
cmd_total
};
GUID get_parent() { return guid_smart_queue_item_group; }
unsigned get_num_items() { return cmd_total; }
void get_item_name(unsigned p_index, pfc::string_base & p_out) {
switch (p_index) {
case cmd_smart_queue: p_out = "Smart-queue selection"; break;
default: uBugCheck(); // should never happen unless somebody called us with invalid parameters - bail
}
}
void context_command(unsigned p_index, metadb_handle_list_cref p_data, const GUID& p_caller) {
switch (p_index) {
case cmd_smart_queue:
SmartQueue(p_data);
break;
default:
uBugCheck();
}
}
GUID get_item_guid(unsigned p_index) {
// These GUIDs identify our context menu items. Substitute with your own GUIDs when reusing code.
static const GUID guid_item1 = { 0xd1456e09, 0x6a99, 0x45e5,{ 0xb8, 0x03, 0xff, 0x82, 0x8b, 0xd3, 0x4b, 0x59 } };
switch (p_index) {
case cmd_smart_queue: return guid_item1;
default: uBugCheck(); // should never happen unless somebody called us with invalid parameters - bail
}

}
bool get_item_description(unsigned p_index, pfc::string_base & p_out) {
switch (p_index) {
case cmd_smart_queue:
p_out = "Add selection to playlist \"Queue\" and queue the first track.";
return true;
default:
uBugCheck(); // should never happen unless somebody called us with invalid parameters - bail
}
}
};

static contextmenu_item_factory_t<SmartQueueMenuItem> g_smart_queue_menu_item_factory;

/// Adds all songs in data to a playlist called "Queue". The first item of data will be
/// queued if no item in playlist "Queue" is queued yet and no playback is currently
/// happening on the "Queue" playlist. If playback is active and the currentl playing
/// song matches the first song in data, the second song in data will be queued instead,
/// if possible.
static void SmartQueue(metadb_handle_list_cref data) {
t_size numItems = data.get_count();
if (numItems == 0)
return;

static_api_ptr_t<playlist_manager_v4> pm;
// Make sure that playlist "Queue" exists and get it
t_size queuePlaylist = pm->find_or_create_playlist("Queue");

pfc::bit_array_var_impl ba;
ba.set(numItems, true);

t_size newFirst = pm->playlist_get_item_count(queuePlaylist);
// Add data to the playlist "Queue"
pm->playlist_add_items(queuePlaylist, data, ba);
t_size newEnd = pm->playlist_get_item_count(queuePlaylist);

static_api_ptr_t<playback_control_v3> pc;
if ((!pc->is_playing() || (pm->get_playing_playlist() != queuePlaylist)) && !GetPlaylistHasQueuedItems(queuePlaylist)) {
// We queue the first item in data if "Queue" playlist contains no queued items
// and playback is either inactive or playing from another playlist.
t_size queueIndex = newFirst;
t_size playingPlaylist;
t_size playingItem;
if (pc->is_playing() && pm->get_playing_item_location(&playingPlaylist, &playingItem)) {
metadb_handle_ptr playingTrack = pm->playlist_get_item_handle(playingPlaylist, playingItem);
metadb_handle_ptr addedTrack = pm->playlist_get_item_handle(queuePlaylist, newFirst);
if (playingTrack == addedTrack) {
// We just added the track which is currently playing to "Queue" playlist,
// so instead of queueing it, queue the next one so it doesn't play twice.
queueIndex++;
}
}
// If queueIndex is out of bounds, let's hope the user queues some more songs
// before the playing one ends.
if (queueIndex < newEnd)
pm->queue_add_item_playlist(queuePlaylist, queueIndex);
}
}

/// Returns true if the given playlist contains at least one queued item, false otherwise.
static bool GetPlaylistHasQueuedItems(size_t playlist) {
static_api_ptr_t<playlist_manager_v4> pm;

pfc::list_t<t_playback_queue_item> queueItems;
pm->queue_get_contents(queueItems);
size_t queueCount = queueItems.get_count();
// O(n) but appears to be the fastest way to do it atm.
for (size_t i = 0; i < queueCount; i++) {
if (playlist == queueItems.get_item(i).m_playlist) {
return true;
}
}

return false;
}
}
And thanks for the help!