See the question and my original answer on StackOverflow

Depending on various contexts (method being called, packaging, version of Windows, etc.), Windows may not always provide information about the current folder.

One way to get it is to implement IObjectWithSite in the COM object that implements IExplorerCommand, and use the passed-in site to determine what's the current folder, something like this:

IFACEMETHODIMP Invoke(_In_opt_ IShellItemArray* selection, _In_opt_ IBindCtx*) noexcept
{
  try
  {
    ComPtr<IServiceProvider> sp;
    m_site->QueryInterface(sp.GetAddressOf());
    if (sp)
    {
      ComPtr<IShellBrowser> browser;
      sp->QueryService(SID_STopLevelBrowser, browser.GetAddressOf());
      if (browser)
      {
        ComPtr<IShellView> view;
        browser->QueryActiveShellView(&view);
        if (view)
        {
          ComPtr<IFolderView> fview;
          view->QueryInterface(fview.GetAddressOf());
          if (fview)
          {
            ComPtr<IShellItem> folder;
            fview->GetFolder(IID_PPV_ARGS(folder.GetAddressOf()));
            if (folder)
            {
              wil::unique_cotaskmem_string path;
              // SIGDN_FILESYSPATH will give the path for file system folders
              // here we use this SIGDN_DESKTOPABSOLUTEPARSING enum value
              // as not all folders are file system folders
              folder->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &path);
              MessageBox(nullptr, path.get(), L"Debug", MB_OK);
            }
          }
        }
      }
    }
    return S_OK;
  }
  catch (...)
  {
    return E_FAIL;
  }
}

Note: this also work in other IExplorerCommand methods such as GetState, etc.