Friday, October 21, 2011

Run minimized batch file in Task Scheduler

I have a batch file scheduled in Windows Task Scheduler. The problem is it will always popup a window when running. Yes I want to see the window but I want it minimized instead of blocking my current view. Should an error occurs the batch file will pause and I will attend to it.

Some suggested using third-party program to minimize the window. Some suggested using Windows Script.

The solution is simple, use this: cmd /c start "title" /min "batch file"
For example: cmd /c start "Backup" /min "d:\my documents\scripts\backup.bat"

Be cautious that the start command will treat the first double-quoted string as title. So if you do this: 
  • cmd /c start /min "d:\my documents\scripts\backup.bat" 
you will just get a command prompt window entitled "d:\my documents\scripts\backup.bat" without the batch file running. Thus it's a good idea to always put a title to prevent scratching your head later.

There is one problem though, that you have to put an exit at the end of your batch file. Otherwise the batch file window will stay there when it is finished.

This is how you convert the above command into the Action of a scheduled task:
  1. Put "cmd" in Program/script.
  2. Put the rest in Add arguments (optional), eg: /c start "Hello" /min "d:\my documents\scripts\backup.bat"

Saturday, September 24, 2011

Rebuild SQLite driver for Qt in Visual Studio 2010

The default build of SQLite driver in Qt does not have some features such as full text search. You can add the features yourself by rebuilding it. This is how I rebuild using Visual Studio 2010:
  1. Download latest SQLite amalgamation source code from, eg:
  2. Run Visual Studio
  3. Click Qt -> Open Qt Project File (.pro)...
  4. Select  the Qt SQLite project, eg: c:\Qt\4.7.4\src\plugins\sqldrivers\sqlite\
  5. If somehow the project is not opened in Solution Explorer, check the Output window for hints.
  6. In Solution Explorer, open sqlite3.c, right-click on the file tab and select "Open Containing Folder".
  7. Make a backup of that folder.
  8. Extract SQLite source code to that folder, overwriting everything.
  9. Back to Visual Studio.
  10. Right-click sqlite project and click Properties.
  11. Under Configuration, select Debug.
  12. Go to Configuration Properties -> C/C++ -> Preprocessor.
  13. Click "Preprocessor Definitions". Click the down arrow at the far right. Click 
  14. Put whatever SQLite compilation option you want. Here's mine:
  15. Under Configuration, select Release. Visual Studio will prompt you to save. Click "Yes".
  16. Add the same definitions as Debug.
  17. Close any running applications that uses SQLite, such as Qt Assistant.
  18. Rebuild both Debug and Release. Remember to Rebuild, not just Build, Visual Studio may not detect the changes.
  19. If you get error C1033 ("cannot open program database c:\Qt\4.7.4\src\plugins\sqldrivers\sqlite\vc100.pdb"), make sure the folder and files are not read-only.
  20. These files will be created. Check their modified dates to be sure:
    1. C:\Qt\4.7.4\src\plugins\sqldrivers\sqlite\debug\qsqlited4.dll
    2. C:\Qt\4.7.4\src\plugins\sqldrivers\sqlite\release\qsqlite4.dll
  21. IMPORTANT: qssqlite4.dll and qsqlited4.dll may be created in C:\Qt\4.7.4\src\plugins\sqldrivers\sqlite\release (or debug). If this happens, move it to C:\Qt\4.7.4\plugins\sqldrivers\ and overwrite the existing one. When you debug in Visual Studio, the DLL from this folder will be loaded, even though you have copied the SQLite DLL to your project output.

"WARNING: Can't find the Qt version that's associated with this project."

Updated in Sept 2013 for Qt5.

I don't know why. I am always haunted by this whenever I use a new Qt version:
"WARNING: Can't find the Qt version that's associated with this project. Defaulting to <some Qt version> instead. Please assign a valid Qt version to this project in the Qt project settings."

It happens when you are trying to build and you get it in the build Output window. Trying to change the version using Qt Visual Studio Add-in doesn't help.

My workaround:
  1. Open your project file in a text editor. The project file is the one with "vcxproj" extension, eg: AwfulProject.vcxproj
  2. Look for one of these:
    • For Qt4, QtVersion_x0020_Win32
    • For Qt5, Qt5Version_x0020_Win32
  3. Change it to the Qt version you desire, for example:
    • For Qt4, QtVersion_x0020_Win32="4.7.4"
    • For Qt5, Qt5Version_x0020_Win32="5.1.1"
  4. Save the file.
  5. Reopen the project in Visual Studio.
  6. Remember to change other Qt projects that this project depends on.

"Qt version uses an unsupported makefile generator (used: MSBUILD, supported: MSVC.NET)"

Ok, this post is for those who build Qt libraries with Visual C++ and annoyed by this:
"This Qt version uses an unsupported makefile generator (used: MSBUILD, supported: MSVC.NET)"

It may happen when adding your newly built Qt version in Qt Visual Studio Add-in.

Here's a little hack that works for me:
  1. Close Visual Studio.
  2. Run regedit.
  3. Hop to HKEY_CURRENT_USER\Software\Trolltech\Versions
  4. Add a new key named "4.7.4" or whatever version you have.
  5. Under the new key, create a new string "InstallDir" valued with "c:\Qt\4.7.4":
  6. Run Visual Studio
  7. Click Qt -> Qt Options.
  8. The new version should be there.

My particular system:
  • Visual Studio 2010 with SP1
  • Qt 4.7.4 - Instruction to build with Visual Studio 2010 is here
  • Qt Visual Studio Add-in 1.1.9

Wednesday, July 20, 2011

Creating "Debug\blah.unsuccessfulbuild" because "AlwaysCreate" was specified.

Now this 'Creating "Debug\blah.unsuccessfulbuild" because "AlwaysCreate" was specified.' appearing in the Visual Studio 2010 output window is really annoying.

Most of those who had this annoyance have had some of their project files missing. You can look for missing file by opening each project file in Visual Studio. But in my case, I can actually open all project files in Visual Studio. So I had to inspect the Visual Studio log as described here. Unfortunately, my DebugView does not show useful stuff from Visual Studio even when running under Administrative privilege. I have to use file logging instead.

My devenv.exe.config looks like this:

<?xml version="1.0"?>

       <add name="CPS" value="4" />
    <trace autoflush="false" indentsize="2">
         <add name="myListener"
initializeData="e:\\TextWriterOutput.log" />
         <remove name="Default" />

Restart Visual Studio and e:\TextWriterOutput.log will have something. Run your project and check the log, you will see what's wrong. In my particular situation, I have these lines in the log:

  devenv.exe Information: 0 : Project 'D:\projects\bar\blah.vcxproj' is not up to date because 16 build inputs were missing.
  devenv.exe Information: 0 :  up to date is missing: 'D:\PROJECTS\FOO\SRC\STDAFX.H'
  devenv.exe Information: 0 :  up to date is missing: 'D:\PROJECTS\FOO\SRC\DEBUG.H'

"D:\Projects\Foo" was a directory that no longer exists, that's what's wrong. Why did that happen? I renamed the project folder from "D:\Projects\Foo" to "D:\Projects\Bar". Those files can still be opened in Visual Studio, but somehow the build engine is missing the track. Re-adding the files to the project solve the problem.

Sunday, April 3, 2011

Setting user data in Qt's widget items

If you use standard Qt widget such as QTreeWidget, QTableWidget or QListWidget, you may want to attach objects to the items. As an example, here's how to do it with QTreeWidgetItem (NOTE: the code is written from scratch to give you a rough idea, it may not compile correctly and is not optimised):

#include <QVariant>

QTreeWidgetItem* addApple() {
  Apple *apple = new Apple();
  QTreeWidgetItem *item = new QTreeWidgetItem((QTreeWidget*)0, QStringList( ) );
  QVariant v;
  item->setData(0, Qt::UserRole, v); // attach apple to column 0

  return item;

Apple* getApple(QTreeWidgetItem *item) {
  QVariant v = item->data(0, Qt::UserRole); // get the data from column 0
  Apple *apple = v.value<Apple*>(); // convert the data to Apple*
  return apple;

/* The following line will cause a compile error since "const Apple *" 
     is different from "Apple *". If you want to use it, add 
     Q_DECLARE_METATYPE(const Apple*) to Apple.
  //const Apple *apple = v.value<Apple*>();

In Apple.h, you need to declare a metatype:

#include <QMetaType>

class Apple {