I'm implementing a credential provider, and inside the credential's method there is this function to look for the correct authentication package to use
HRESULT RetrieveNegotiateAuthPackage(ULONG * pulAuthPackage)
{
HRESULT hr;
HANDLE hLsa;
NTSTATUS status = LsaConnectUntrusted(&hLsa);
if (SUCCEEDED(HRESULT_FROM_NT(status)))
{
ULONG ulAuthPackage;
LSA_STRING lsaszKerberosName;
LsaInitString(&lsaszKerberosName, NEGOSSP_NAME);
status = LsaLookupAuthenticationPackage(hLsa, &lsaszKerberosName, &ulAuthPackage);
if (SUCCEEDED(HRESULT_FROM_NT(status)))
{
*pulAuthPackage = ulAuthPackage;
hr = S_OK;
}
else
{
hr = HRESULT_FROM_NT(status);
}
LsaDeregisterLogonProcess(hLsa);
}
else
{
hr= HRESULT_FROM_NT(status);
}
return hr;
}
When I call the API LsaLookupAuthenticationPackage, it returns 0xc00000fe (an error). Here is the values of the parameters I got from debugging:
hLsa (it can vary each time) 0x00391c60
lsaszKerberosName L"Negotiate"
Does anyone know what possibly causes this? And what to do to fix it? Thanks :)
according to ms api doc, the package name parameter is defined by the following macros:
MSV1_0_PACKAGE_NAME
MICROSOFT_KERBEROS_NAME_A
NEGOSSP_NAME_A
the macro defines the type of the authentication package that you want to use
and furthermore, you must use the ascii type intead of unicode
https://learn.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-lsalookupauthenticationpackage
Related
Following the Microsoft documentation, calling the SHGetDesktopFolder() function should return the file system root:
Retrieves the IShellFolder interface for the desktop folder, which is
the root of the Shell's namespace.
So I ran the following code:
void LogDesktopFolderContent()
{
IShellFolder* pDesktopFolder = nullptr;
// get the desktop folder
HRESULT hr = ::SHGetDesktopFolder(&pDesktopFolder);
if (FAILED(hr))
return;
IEnumIDList* pEnumIDList;
// list its content
hr = pDesktopFolder->EnumObjects(nullptr, SHCONTF_NONFOLDERS, &pEnumIDList);
if (FAILED(hr))
{
pDesktopFolder->Release();
return;
}
do
{
LPITEMIDLIST pItem;
hr = pEnumIDList->Next(1, &pItem, nullptr);
if (pItem)
{
wchar_t buffer[MAX_PATH + 1];
if (::SHGetPathFromIDListW(pItem, buffer))
{
::OutputDebugString(buffer);
::OutputDebugString(L"\r\n");
}
::CoTaskMemFree(pItem);
}
if (hr != S_OK)
break;
} while (1);
pDesktopFolder->Release();
}
As a result, I get these files:
C:\Users\Admin\Desktop\StartSystem.bat
C:\Users\Admin\Desktop\Private dev.lnk
C:\Users\Admin\Desktop\Rad Studio Common Dir.lnk
C:\Users\Admin\Desktop\raw_registry_connections.png
C:\Users\Admin\Desktop\The Alien Cube.url
C:\Users\Admin\Desktop\Tormented Souls.url
C:\Users\Admin\Desktop\Notes.txt
Well, this is the content of my Desktop folder. But THIS IS NOT THE ROOT OF MY FILE SYSTEM.
So, what I'm doing wrong, or what is the correct manner to get the file system root with the Shell API?
It is the root. c:\Windows\Notepad.exe for example is located at (Desktop)\This PC\c:\Windows\Notepad.exe in the shell namespace.
One problem is that "This PC" is a folder and you are asking for nonfolders. Another problem is that you are calling SHGetPathFromIDListW and this only works on things that have filesystem paths and "This PC" does not. To walk the namespace you should only use IShellFolder+pidl and/or IShellItem. To get the "real" name of an item, call IShellFolder::GetDisplayNameOf and ask for SHGDN_FORPARSING.
I have a COM interface exposed from my application which is used by the third party plugins. Now, I need to add a new method to this interface but can not change the GUID of the interface as it will break all the existing plugins. I was told that if I add the new methods at the end of the interface it will work without issues as finally COM interface is a table of function pointers. These new methods will only be used by newly written plugins. I read this post and the first comment in Raymond Chen's blog: http://blogs.msdn.com/b/oldnewthing/archive/2005/11/01/487658.aspx but the situation mentioned in comment won't happen in my case as it is Windows only application. I know theoretically I should change the interface GUID. What would be the correct solution in this case? or will this approach work?
You can usually get away with adding new methods to the end of an existing interface without breaking compatibility. But as you have been reading, there are subtle cases where this can break. Especially when multiple inheritance is already being used.
The correct solution is to simply declare a new interface for the new methods. Leave your existing interfaces alone. Then have your existing objects implement both interfaces or use inheritance to have the new interface inherit from the old.
For example, if this is our original code. (I'll pretend this is done without IDL files for brevity).
Original code:
class IPublicInterface : public IUnknown
{
public:
virtual void M1() = 0;
virtual void M2() = 0;
}
class MyPublicClass : IPublicInterface
{
public:
// IPublicInterface
void M1();
void M2();
// IUnknown
HRESULT QueryInterface(...);
ULONG AddRef();
ULONG Release();
};
Now let's say we want to add a new method to this object called M3 without breaking users of the existing interface and object. The correct solution would be to add a new interface. For convenience, it can just inherit from the original interface.
class IPublicInterface2 : public IPublicInterface
{
public:
virtual void M3() = 0;
};
Now modify the class to inherit from both this new derived interface:
class MyPublicClass : public IPublicInterface2
{
public:
// IPublicInterface
void M1();
void M2();
// IPublicInterface2
void M3();
// IUnknown
HRESULT QueryInterface(...);
ULONG AddRef();
ULONG Release();
};
Update QueryInterface to support both calls for both the original UUID of IPublicInterface as well as IPublicInterface2.
HRESULT MyPublicClass::QueryInterface(GUID& iid, void** ppv)
{
// QI request for original interface
if ((iid == uuidof(IPublicInterface) || (iid == uuidof(IUnknown))
{
*ppv = (IPublicInterface*)this;
AddRef();
return S_OK;
}
else if (iid == uuidof(IPublicInterface2)
{
*ppv = (IPublicInterface2*)this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
Alternatively, IPublicInterface2 does not need to inherit from the original IPublicInterface. In that case, the implementing class inherits from both interfaces. In the QueryInterface implementation, you will need to be consistent about how you handle a possible ambiguous cast to IUnknown.
I'm using the common file dialog with FOS_PICKFOLDERS to let the user pick a location to save files. If the user selects a library, e.g. Library\Documents then my current code fails at the point where I call IShellItem::GetDisplayName to extract a file system name. If the item were a file then this would succeed and the library's default save location would be used.
What I would like to do is to detect that the shell item is a library, then obtain an IShellLibrary interface, and then query it to find the default save location. Then I would save my files there.
What is the correct way to detect that an IShellItem refers to a Library?
Use SHLoadLibraryFromItem() to get an IShellLibrary from an IShellItem, eg:
IShellItem *pItem, *pSave;
IShellLibrary *pLibrary;
...
if (SUCCEEDED(SHLoadLibraryFromItem(pItem, STGM_READWRITE, IID_IShellLibrary, (void**)&pLibrary)))
{
pLibrary->GetDefaultSaveFolder(DSFT_DETECT, IID_IShellItem, (void**)&pSave);
pLibrary->Release();
}
else
{
pSave = pItem;
pSave->AddRef();
}
...
pSave->GetDisplayName(...);
pSave->Release();
The only way I found was to use IShellLibrary::LoadLibraryFromItem (MSDN here), to which you pass an IShellItem interface.
If it fails (i.e. HRESULT != S_OK), then the IShellItem is not a library.
So something like this:
bool IsLibrary(IShellItem *pItem)
{
bool bIsLibrary = false;
IShellLibrary *plib = NULL;
HRESULT hr = CoCreateInstance(CLSID_ShellLibrary, NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&plib));
if (SUCCEEDED(hr))
{
hr = plib->LoadLibraryFromItem(pItem, STGM_READ);
if (SUCCEEDED(hr)) bIsLibrary = true;
plib->Release();
}
return bIsLibrary;
}
I have no idea if it's the "correct" way, but it may be useful anyway.
As I get it there're three ways to implement marshalling in COM:
typelib marshalling
proxy/stub marshalling
implementing IMarshal by the object
now how does the component consumer (user) choose which one will be used? Does it decide on its own and use the preferred way or does it call some built-in function and it solves the problem for it?
I currently experience the following: my component implements a custom interface ICustomInterface that is also implemented by a component from another company. My component doesn't have a typelib and doesn't implement IMarshal. The system registry contains the HKCR\Interface{uuidof(ICustomInterface)}\ProxyStubClsid32 key with a GUID of the proxy/stub that can be traced to a library provided by that other company.
Now when my component consumer initializes my component it calls QueryInterface() requesting IMarshal from my component and when returned E_NOINTERFACE it just does nothing. Why is this - why doesn't proxy/stub library from the other company kick in?
The COM runtime will use typelib (oleautomation) marshalling if you mark your interface as using the standard marshaler by adding its CLSID {00020424-0000-0000-C000-000000000046} under HKCR\Interfaces\{iid}\ProxyStubClsid (where {iid} is the GUID of your interface). You'll need to have a typelibrary registered too, in order for the runtime to extract the parameter information, and you can only use a certain subset of types. There's some more (old) information here and here.
If you want to use a custom proxy/stub, as generated by the MIDL compiler from your IDL, then you'll need to change the interface registry entry to be the CLSID of that proxy object instead. This enables you to use a wider range of types, e.g. "raw" arrays.
If you support IMarshal then that's what'll be used in preference to either of these mechanisms. This means you can change your object to aggregate the free-threaded marshaler (using its implementation of IMarshal) without having to change anything in the registry. This will avoid any proxies being created.
Hope this helps.
I am a bit rusty at this, but do you have a function named blindquery in your project ? (its usually declared by the wizard if you created a C++ ATL project). Breakpoint inside the function. The function is generated by the wizard often has problems with queryinterface returning E_NOINTERFACE due to buggy code.
edit (found sample code) from my old project _blindquery
class ATL_NO_VTABLE CChildEvents :
public CComObjectRootEx <CComSingleThreadModel>,
public CComCoClass<CChildEvents, &CLSID_ChildEvents>,
public IDispatchImpl<IChildEvents, &IID_IChildEvents, &LIBID_XXX>
{
public:
CChildEvents(void) :
m_pItfMgr(0)
{
}
/* called from internalQI to tear off a new blind interface */
static HRESULT WINAPI _BlindQuery(void *pvThis, REFIID riid, void **ppv, DWORD dw);
DECLARE_REGISTRY_RESOURCEID(IDR_CHILDEVENTS)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CChildEvents)
COM_INTERFACE_ENTRY(IChildEvents)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY_FUNC_BLIND(0, _BlindQuery)
END_COM_MAP()
};
HRESULT WINAPI CChildEvents::_BlindQuery(void *pvThis, REFIID riid, void **ppv, DWORD /* dw */ )
{
HRESULT hr = E_NOINTERFACE;
USES_CONVERSION;
try
{
if(pvThis == NULL)
{
ATLASSERT(FALSE);
}
else
{
/*
* cast the pvThis pointer to the actual class £
* so we can use it here £
* reinterpret_cast should be safe since we're calling ourself
*/
CChildEvents *pThis = reinterpret_cast < CChildEvents * > (pvThis);
if(pThis == NULL)
{
ATLASSERT(FALSE);
}
else
{
/* check to see if it matches on of our children's DIID */
if(memcmp(&riid,&l_someotherguid,sizeof(GUID)) == 0) {
/* if so cast to a IDispatch -- the standard for event interfaces */
*ppv = reinterpret_cast < IDispatch * > (pvThis);
/* addref */
pThis->AddRef();
/* reply */
hr = S_OK;
}
}
}
}
catch(...)
{
ATLASSERT(FALSE);
}
/* must not be in our map - tell them to GO FISH */
return(hr);
}
XMLNotepad provides the following text (for example) when a transform fails:
Error Transforming XML
The variable
or parameter
'saturated-background-color' was
duplicated with the same import
precedence.
How would I go about getting this error text programmatically? My code looks like this:
CComPtr<IXSLTemplate> tmpl;
HRESULT hr = CoCreateInstance(CLSID_XSLTemplate, NULL, CLSCTX_INPROC_SERVER, IID_IXSLTemplate, (void**)&tmpl);
if (SUCCEEDED(hr)) {
hr = tmpl->putref_stylesheet(xslt_doc);
if (SUCCEEDED(hr)) {
// Huzzah; do stuff.
} else {
// How do I get the error text? I want to log it!
}
}
If IXSLTemplate supports IErrorInfo (AFAIK, it does), then you can query that for additional information.
(jeffamaphone clued me in on the proper way to get this - using the GetErrorInfo() API:)
CComPtr<IErrorInfo> error;
if (SUCCEEDED( GetErrorInfo(0, &error) ) && error)
{
// call IErrorInfo::GetDescription(), etc.
}