Setting Status icon for CFAPI does not work as expected - c++

I try to set the status icon of the placeholder file created with CFAPI to error. (see below)
content of folder T:
I set the error state on the file, but it does not display the error. However the error is displayed on the containing folder.
I use following code to set the error on the file (the complete code is published on github):
void SetTransferStatus(_In_ PCWSTR fullPath, _In_ SYNC_TRANSFER_STATUS status)
{
// Tell the Shell so File Explorer can display the progress bar in its view
try
{
// First, get the Volatile property store for the file. That's where the properties are maintained.
winrt::com_ptr<IShellItem2> shellItem;
winrt::check_hresult(SHCreateItemFromParsingName(fullPath, nullptr, __uuidof(shellItem), shellItem.put_void()));
winrt::com_ptr<IPropertyStore> propStoreVolatile;
winrt::check_hresult(
shellItem->GetPropertyStore(
GETPROPERTYSTOREFLAGS::GPS_READWRITE | GETPROPERTYSTOREFLAGS::GPS_VOLATILEPROPERTIESONLY,
__uuidof(propStoreVolatile),
propStoreVolatile.put_void()));
// Set the sync transfer status accordingly
PROPVARIANT transferStatus;
winrt::check_hresult(
InitPropVariantFromUInt32(
status,
&transferStatus));
winrt::check_hresult(propStoreVolatile->SetValue(PKEY_SyncTransferStatus, transferStatus));
// Without this, all your hard work is wasted.
winrt::check_hresult(propStoreVolatile->Commit());
// Broadcast a notification that something about the file has changed, so that apps
// who subscribe (such as File Explorer) can update their UI to reflect the new progress
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH, static_cast<LPCVOID>(fullPath), nullptr);
//wprintf(L"Succesfully Set Transfer Progress on \"%s\" to %llu/%llu\n", fullPath, completed, total);
}
catch (...)
{
// winrt::to_hresult() will eat the exception if it is a result of winrt::check_hresult,
// otherwise the exception will get rethrown and this method will crash out as it should
wprintf(L"Failed to Set Transfer Progress on \"%s\" with %08x\n", fullPath, static_cast<HRESULT>(winrt::to_hresult()));
}
}
In addition, if I delete the file and create a new file the state will still be on error.

Someone pointed me to an pull request in the windows cloud mirror sample that shows how to accomplish this.
This is the code:
void Utilities::UpdateErrorOnItem(PCWSTR path, bool setError)
{
try
{
winrt::com_ptr<IShellItem2> item;
winrt::check_hresult(SHCreateItemFromParsingName(path, nullptr, IID_PPV_ARGS(item.put())));
winrt::com_ptr<IPropertyStore> propertyStore;
winrt::check_hresult(item->GetPropertyStore(GPS_READWRITE | GPS_EXTRINSICPROPERTIESONLY, IID_PPV_ARGS(propertyStore.put())));
PROPVARIANT propVar{};
if (setError)
{
propVar.vt = VT_UI4;
propVar.ulVal = static_cast<unsigned long>(E_FAIL);
winrt::check_hresult(propertyStore->SetValue(PKEY_LastSyncError, propVar));
}
else
{
// Clear by setting to empty
propVar.vt = VT_EMPTY;
winrt::check_hresult(propertyStore->SetValue(PKEY_LastSyncError, propVar));
}
winrt::check_hresult(propertyStore->Commit());
}
catch (...)
{
// winrt::to_hresult() will eat the exception if it is a result of winrt::check_hresult,
// otherwise the exception will get rethrown and this method will crash out as it should
wprintf(L"Failed to set error state with %08x\n", static_cast<HRESULT>(winrt::to_hresult()));
}

Related

Cannot set Scanner Capability because L_TwainStartCapsNeg returns error -84

I'm trying to use the Leadtools API version 21 for automatically scanning some documents and here is a sudo code of what I have done (it runs in a secondary thread and the unlock has been done in the main thread):
void CheckRetCode(int rc)
{
if (SUCCESS != rc)
{
L_TCHAR errMsg[1024];
memset(errMsg, 0, sizeof(errMsg));
L_GetFriendlyErrorMessage(rc, errMsg, 1024, L_FALSE);
throw TLeadException(errMsg, rc);
}
}
void OnThreadExecute(void)
{
HTWAINSESSION hSession = nullptr;
APPLICATIONDATA appData;
L_INT nRet;
L_TCHAR pszTwnSourceName[1024];
LTWAINSOURCE sInfo;
memset(&appData, 0, sizeof(APPLICATIONDATA));
appData.uStructSize = sizeof(APPLICATIONDATA);
appData.hWnd = hWnd;// hWnd is valid handle of my main window
appData.uLanguage = TWLG_ENGLISH_USA;
appData.uCountry = TWCY_USA;
wcscpy(appData.szManufacturerName, L"MyCompanyName");
wcscpy(appData.szAppProductFamily, L"MyProductName");
wcscpy(appData.szAppName, appData.szAppProductFamily);
wcscpy(appData.szVersionInfo, L"Version 0.1.0.1");
nRet = L_TwainInitSession2(&hSession, &appData, LTWAIN_INIT_MULTI_THREADED);
CheckRetCode(nRet);// the exception gets catched elsewhere but no error reported here
memset(pszTwnSourceName, 0, sizeof(pszTwnSourceName));
wcscpy(pszTwnSourceName, L"EPSON Artisan837/PX830"); // the name of the scanner is verifyed
sInfo.uStructSize = sizeof(LTWAINSOURCE);
sInfo.pszTwainSourceName = pszTwnSourceName;
CheckRetCode(L_TwainSelectSource(hSession, &sInfo)); // No error reported here
CheckRetCode(L_TwainStartCapsNeg(hSession)); // in here I get the return value -84 which is reported as "TWAIN DS or DSM reported error, app shouldn't (no need for your app to report the error)."
// the rest of the code but we cannot get there since above code reports error
}
Can anyone tell me what I'm doing wrong? Is there a step that I'm missing here?
EditThe function L_TwainSelectSource() make no effort to make sure the supplied source is valid and does not even return an error. As result, if you set the selected source to a garbage name, it will act as if it accepted it. From that point on if you try to Get/Set anything or try to acquire an image, every function returns -84.
Thank you
Sam
To test your code, I put the main window’s handle in a global variable:
globalhWnd = hWnd;
And modified your function to use that handle like this:
void OnThreadExecute(void *)
{
...
appData.hWnd = globalhWnd; // hWnd is valid handle of my main window
...
}
Then created a thread for it from the main program like this:
globalhWnd = hWnd;
_beginthread(OnThreadExecute, 0, 0);
I tried this with 5 different Twain sources: 2 virtual and 3 physical scanners (one of them an old Epson). All 5 drivers returned SUCCESS when calling L_TwainStartCapsNeg() from within the thread.
Two possibilities come to mind:
The problem might be caused by something else in your code other than the thread function.
Or the problem could be specific to your Twain driver.
To rule out the first possibility, I suggest creating a small test project that only creates a similar thread and does nothing else and trying it with different scanners. If it causes the same problem with all scanners, send that test project (not your full application) to support#leadtools.com and our support engineers with test it for you.
If the problem only happens with a specific Twain driver, try contacting the scanner’s vendor to see if they have an updated driver.

Windows Event Hooks for File Saved

Every time I save a certain script file I'm working on in NotePad++, I am required to upload the changes to our server so that we can deploy the changes to various machines.
I sometimes forget to upload the changes after refactoring my code in NotePad++ and I was wondering if there was a way for me to create a simple application that would listen for a 'Save' event and automatically upload the file for me.
I am currently running on a Windows OS and was hoping to do this using C++. I'd like to explore Windows Events and possibly tie into an event hook to accomplish this. Any other languages would be welcome as well.
Any ideas or tips?
Here is my code thus far following Josh's recommendations below:
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
void RefreshDirectory(LPTSTR);
void WatchDirectory(LPTSTR);
void _tmain(int argc, TCHAR *argv[])
{
if (argc != 2)
{
_tprintf(TEXT("Usage: %s <dir>\n"), argv[0]);
return;
}
WatchDirectory(argv[1]);
}
void WatchDirectory(LPTSTR lpDir)
{
DWORD dwWaitStatus;
HANDLE dwChangeHandles[2];
TCHAR lpDrive[4];
TCHAR lpFile[_MAX_FNAME];
TCHAR lpExt[_MAX_EXT];
_tsplitpath_s(lpDir, lpDrive, 4, NULL, 0, lpFile, _MAX_FNAME, lpExt, _MAX_EXT);
lpDrive[2] = (TCHAR)'\\';
lpDrive[3] = (TCHAR)'\0';
// Watch the directory for file creation and deletion.
dwChangeHandles[0] = FindFirstChangeNotification(
lpDir, // directory to watch
FALSE, // do not watch subtree
FILE_NOTIFY_CHANGE_LAST_WRITE); // watch file name changes
if (dwChangeHandles[0] == INVALID_HANDLE_VALUE)
{
printf("\n ERROR: FindFirstChangeNotification function failed.\n");
ExitProcess(GetLastError());
}
// Make a final validation check on our handles.
if ((dwChangeHandles[0] == NULL))
{
printf("\n ERROR: Unexpected NULL from FindFirstChangeNotification.\n");
ExitProcess(GetLastError());
}
// Change notification is set. Now wait on both notification
// handles and refresh accordingly.
while (TRUE)
{
// Wait for notification.
printf("\nWaiting for notification...\n");
// Waits until the specified object is in the signaled state or
// the time-out interval elapses.
// Because our second parameter is set to INFINITE, the function will
// return only when the object is signaled.
dwWaitStatus = WaitForSingleObject(dwChangeHandles, INFINITE);
switch (dwWaitStatus)
{
// Our return value, WAIT_OBJECT_0 signifies that the first object
// signaled the event.
case WAIT_OBJECT_0:
// A file was created, renamed, or deleted in the directory.
// Refresh this directory and restart the notification.
RefreshDirectory(lpDir);
if (FindNextChangeNotification(dwChangeHandles[0]) == FALSE)
{
printf("\n ERROR: FindNextChangeNotification function failed.\n");
ExitProcess(GetLastError());
}
break;
case WAIT_TIMEOUT:
// A timeout occurred, this would happen if some value other
// than INFINITE is used in the Wait call and no changes occur.
// In a single-threaded environment you might not want an
// INFINITE wait.
printf("\nNo changes in the timeout period.\n");
break;
default:
printf("\n ERROR: Unhandled dwWaitStatus.\n");
ExitProcess(GetLastError());
break;
}
}
}
void RefreshDirectory(LPTSTR lpDir)
{
// This is where you might place code to refresh your
// directory listing, but not the subtree because it
// would not be necessary.
_tprintf(TEXT("Directory (%s) changed.\n"), lpDir);
}
You can monitor the filesystem for changes using FindFirstChangeNotification. When you call this function, you get a HANDLE back. You can wait on that handle using WaitSingleObject (or similar). When the wait returns, you can use ReadDirectoryChanges to figure out exactly what happened. If whatever happens matches some event or change you care about for your file, you can take the appropriate action... otherwise ignore the event.
Because you'll be waiting (and thus blocking the thread), you may want to perform this work on a worker thread if you want your program in question to be doing anything else.
A simple way to start might be to listen for events with the FILE_NOTIFY_CHANGE_LAST_WRITE filter; this will release your wait when files in the monitored directory are written to.
Note that not all programs save files in the same way; some open the existing file and write to it, others delete it and replace, or some combination thereof (first writing to a temporary file, then swapping it with the original). Consequently it may not be as straightforward as waiting for just last-write notifications to accomplish precisely what you're after.
Think about writing a NP++ plugin instead.
You can register your plugin to be notified whenever a file is saved or about to be saved using NPPN_FILESAVED or NPPN_FILEBEFORESAVE.
Please look at this link:
http://docs.notepad-plus-plus.org/index.php/Messages_And_Notifications

qt ip camera stream libvlc return values

I am using Qt and libvlc to create a gui for an ip camera stream. After i finished it i started testing it against wrong values NULLs... etc. My problem is that when i give a wrong string as network link i dont get NULL as return values. A portion of the code is this
const char * const vlc_args[] = {
"--preferred-resolution=576",
"--network-caching=250",
"--no-audio"
};
my_vlcInstance = libvlc_new(3, vlc_args);
if (my_vlcInstance == NULL){
emit sendDebugMessage("Couldn't create vlc instance", "Red");
return;
}
my_LiveMedia = libvlc_media_new_location(my_vlcInstance, link.toStdString().c_str());
if (my_LiveMedia == NULL){
emit sendDebugMessage("Error installing media", "Red");
return;
}
my_LiveMediaPlayer = libvlc_media_player_new_from_media(my_LiveMedia);
if (my_LiveMediaPlayer == NULL){
emit sendDebugMessage("Error creating media player", "Red");
return;
}
now link is a QString containing the network link. I know that bad things happen as i can see the errors in the Visual studio debug window. "core input error: open of `dsfgdfgfg' failed" "Your input can't be opened" and stuff like that. So why cant i catch these errors?
Furthermore... when i push my start recording button a file is produced (corrupted obviously as there is no stream) and libvlc function calls dont return the errors as specified in the documentation. For this for example:
if (libvlc_media_player_play(my_LiveMediaPlayer) == 0){
emit sendDebugMessage("Live mode started successfully", "Green");
isLive = true;
}
So how do i catch the bad link?
I solved my problem with the libvlc_media_player_get_state function. I ignore the libvlc_media_player_play return value and i just poll the current state of the media player until i get a different state from IDLE/CLOSE and OPENING. On the bad links i get an ERROR state and on the correct links i get PLAYING state.

Second use of CFileDialog in my program gets the run-time error Debug Assertion failed

I have developed a simple program with MFC. It's responsible for reading and writing geotiff files using GDAL library. For this purpose, I have derived two classes from CFileDialog class named ManageOpenGeoTiffFiles and ManageSaveGeoTiffFiles each have 3 functions to support reading and writing geotiffs.
this is the header of the constructor and destructor for one of them:
ManageOpenGeoTiffFiles::ManageOpenGeoTiffFiles(void):CFileDialog(true,0,0,OFN_ENABLESIZING | OFN_HIDEREADONLY,_T("Tiff Files (*.tif)|*.tif|"),0,0,true)
ManageOpenGeoTiffFiles::~ManageOpenGeoTiffFiles(void)
{
}
and this is how I use it in my code:
void CInitialJobProject2FinalDlg::OnBnClickedBtnopen()
{
// TODO: Add your control notification handler code here
m_oglWindow1.WantToPan = false;
m_oglWindow1.WantToUseZoomTool = false;
CString fullpath;
if ( m_openFiles.DoModal() == IDOK )
{
fullpath = m_openFiles.GetPathName();
try{
m_openFiles.OpenGeoTiffAsReadonly(fullpath);
}
catch(CFileException *e){
MessageBox(_T("the file could not be opened"),_T("error"),MB_OK);
this ->ExitMFCApp();
}
m_openFiles.ReadRasterData();
}
else
MessageBox(_T("you pressed cancel and can not proceed."),_T("error"),MB_ICONERROR);
}
everythings ok when I use the Open or Save button for the first time in my program but when it comes to second use I get the error:
and if I click ignore:
this error occurs in the line:
if ( m_openFiles.DoModal() == IDOK )
of each dialog and even if I click cancel the first time,the error occures in the second use of dialog.
Line 398 of dlgFile.cpp is as follows:
hr = (static_cast<IFileDialog*>(m_pIFileDialog))->SetFileTypes(nFilterCount, pFilter);
ENSURE(SUCCEEDED(hr));
Edited section:
Answering one of the comments and providing information for others too:
When I set a breakpoint there saw these results when the assertion fails:
pFilter 0x00fc3660 {pszName=0x00fc36a8 "Tiff Files (*.tif)" pszSpec=0x00fc3788 "*.tif" }
hr E_UNEXPECTED
and the results for the first time when the assertion does not fail is as follows:
pFilter 0x004cfca0 {pszName=0x004cfce8 "Tiff Files (*.tif)" pszSpec=0x004cfdc8 "*.tif" }
hr S_OK
You are passing a malformed filter string to CFileDialog::CFileDialog. The Remarks sections states the following condition:
The lpszFilter parameter [...] ends with two '|' characters.

Trouble sending a MAPI message

I am trying to send a message using Extended MAPI, but keep getting an E_ACCESSDENIED error. I am using a C# class which invokes a cpp dll. I am able to check mail and delete messages, but not send. Below is the C# I use to create the message:
using (MAPIMessage message = new MAPIMessage())
{
if (message.Create(this))
{
message.SetSender(send.SenderName, send.SenderAddress);
message.SetSubject(send.Subject);
message.SetBody(send.Message);
message.AddRecipient(send.RecipientAddress);
// High: Add attachments
#if DEBUG
ConfirmMessageCreation(send, message);
#endif
Logger.Log("Message created...\nSending message...", Verbose.LogEverything);
result = message.Send();
}
else
Logger.Log("There was a problem creating the email.", Verbose.LogImportant);
}
The actual cpp that sends the message follows:
BOOL MessageSend(CMAPIMessage* pMessage)
{
return pMessage->Send();
}
...
BOOL CMAPIMessage::Send()
{
HRESULT result = Message()->SubmitMessage(0);
if(Message() && result==S_OK)
{
Close();
return TRUE;
}
return FALSE;
}
Even though I am properly logged in and can check or delete messages, I get an E_ACCESSDENIED error when calling Send(). Any insight into this issue would be greatly appreciated.
The sender related properties need to be removed.