Wednesday, February 18, 2004

Unicode question

A couple of days ago I wrote a simple function and a part of it looked like this:


CString str;
str.Format(_T("this is only a test"));
int idx = str.Find('o');
if( idx >= 0 )
str = str.Left(idx);

The project have UNICODE defined so when today I reviewed this piece of code it looked wrong because the Find method as a character parameter that is not treated really as an unicode character. However it did compile well (and work too) under Visual C++ 6.

So when I got home I decided I need to understand why it works. I opened my Microsoft Visual C++ .NET 2003 wrote this little test console app and I generated the asm and the results (in debug configuration) are:

 




; 22   :     int idx = str.Find('o');

mov esi, esp
push 0
push 111 ; 0000006fH
lea ecx, DWORD PTR _str$[ebp]
call DWORD PTR __imp_?Find@?$CStringT@GV? (...)
cmp esi, esp
call __RTC_CheckEsp
mov DWORD PTR _idx$[ebp], eax
; 22   :     int idx = str.Find(_T('o'));

mov esi, esp
push 0
push 111 ; 0000006fH
lea ecx, DWORD PTR _str$[ebp]
call DWORD PTR __imp_?Find@?$CStringT@GV? (...)
cmp esi, esp
call __RTC_CheckEsp
mov DWORD PTR _idx$[ebp], eax

So both of them are compiled in the same manner. That's explain why it did compile successfully and why it works but I still doesn't understand why it didn't require the L (or TEXT or _T) macro.

Tuesday, February 17, 2004

MFC and taskbar

To make your application to not have a taskbar button, you need to have you main window owned by an invisible window or the main window should have the WS_EX_TOOLWINDOW style.

Friday, February 13, 2004

VARIANT_BOOL hint

When you are writing COM objects with support for OLE Automation types, you may have to deal with VARIANT_BOOL types. They are boolean values but unlink BOOL and bool its legal values are -1 (VARIANT_TRUE) and 0 (VARIANT_FALSE).

That means that if you call by mistake one of those methode with a bool or BOOL value, it will be implicitily converted to 0 and 1 values making it a perfectly legal call, but if you do have something like:

 

HRESULT foocall(VARIANT_BOOL boolParam)

{

    if( boolParam == VARIANT_TRUE )

        return S_OK;

    return S_FALSE;

}

 

Than you are in big trouble if you mismatch what you pass to the method. When you are dealing with VARIANT_BOOL types is always better to check for VARIANT_FALSE which is always 0 as for bool and BOOL types, so you should write the previous method like:

 

HRESULT foocall(VARIANT_BOOL boolParam)

{

    if( boolParam == VARIANT_FALSE )

        return S_FALSE;

    return S_OK;

}

 

Microsoft Win32 to Microsoft .NET Framework API Map

This link is something really useful for who is learning .net and have a tough win32 background.

 

Wednesday, February 11, 2004

The Ten Rules of Performance

From Paul Vick the 10 rules to work out perfomances problem:

http://www.panopticoncentral.net/PermaLink.aspx/eacfc5e0-42df-44b0-bb9a-94354b689b17

I like the 9th and 10th rule, they are so true.

Monday, February 09, 2004

Callbacks in C++

While reading Raymond Chen today I came across a technique to implement callback in c++. Having already implemented such things on my own, I'll give it a try and eventually update my code.

Thursday, February 05, 2004

Goggle's power

Don Box was having problems looking up SOAP 1.1 protocol specs.

A simple google query would have give him the needed help.

Friday, January 30, 2004

CMake

From Eric Sink's blog:

"One of the toughest parts of cross-platform development is the build system.  No matter how clean and portable your C code is, getting the tree to build on multiple platforms is a whole different problem.

One solution I have used in the past is to do a completely Unix-centric build system with bash and make, using cygwin to run it under Windows.  This works very well, except that it really annoys the folks who prefer Visual Studio project files.

[...]

This week I discovered a nifty tool I had never seen before.  It's called CMake, and it's the build system used for Kitware's Visualization Toolkit.  I've seen lots of alternatives to 'make', but this tool is surprisingly different and deeply neato."

 

Tuesday, January 27, 2004

Thursday, January 08, 2004

Sviluppare senza essere Amministratori della macchina

From Marco Russo's blog:

Molti blog (tra cui quello di Paolo) hanno già notificato questo documento su MSDN che riassume gli interventi da fare per sviluppare senza essere amministratori.
Dopo 6 mesi di questa esperienza quello che posso dire è che la cosa più difficile, in realtà, non è sviluppare ma essere utenti "avanzati". Quello che nessuno spiega, infatti, è come far funzionare quelle centinaia di programmi e utility che vogliamo installare sul PC che usiamo tutti i giorni anche per lavorare.
Per venirne a capo, esistono due tool assolutamente indispensabili e di cui non posso più fare a meno: FileMon e RegMon.
Quando un programma non vuol saperne di funzionare senza avere un utente amministratore, in genere i problemi sono:
  • apre dei file di configurazione in read/write anche se deve solo leggerli, e questi file sono nella directory di installazione del programma (sotto Programmi/Program Files, che per un utente normale è tutta read-only) - con FileMon si capisce quale file tenta di aprire (fallendo) e quindi, modificando i diritti di accesso su tale file, si risolve il problema
  • apre una chiave di registry all'interno di HKEY_LOCAL_MACHINE in read/write, quando deve solo leggere (le scritture, al di fuori dell'installazione, andrebbero fatte sempre e solo su HKEY_CURRENT_USER) - con RegMon si individua il problema e... se si riesce, si modificano gli accessi al registry (usare REGEDT32.EXE su Windows 2000, da Windows XP in poi è tutto integrato in REGEDIT.EXE)
  • tenta di aprire in scrittura qualcosa nelle directory di sistema di Windows: qui è meglio sbarazzarsi del software e trovarne uno scritto meglio...
  • registrano dei componenti COM/ActiveX a ogni avvio dell'applicazione: anche qui insultate i programmatori... perché questo comportamento non dovrebbe essere ammissibile al di fuori dell'attività di setup - non ci sono grandi soluzioni se non eseguire tali programmi con RunAs...
A parte questi inconvenienti, sviluppare con un utente che non è amministratore è non solo possibile ma addirittura vantaggioso, perché consente di avere coscienza di cosa un programma deve fare e cosa no... prima che ve lo dica qualche utente/amministratore di rete un po' arrabbiato...
[Marco Russo's BLog]

Monday, December 29, 2003

Adobe Illustrator 10 SDK - Jpeg export of the page

How to actually do a Jpeg export.

After having found out which is the correct format name you could use this piece of code:

 

AIErr   error   = kNoErr;
AIActionParamValueRef valueParameterBlock = NULL;
ActionDialogStatus dialogStatus  = kDialogOff;
TCHAR   pszPath[255];
   
error = sAIActionManager->AINewActionParamValue(&valueParameterBlock);
ASSERT(!error );
ASSERT(valueParameterBlock);

error = sAIActionManager->AIActionSetString(valueParameterBlock, kAIExportDocumentNameKey, W2A(pszPath));
ASSERT(!error);

const char* szJPEGFileFormat = "JPEG file format";
error = sAIActionManager->AIActionSetString(valueParameterBlock, kAIExportDocumentFormatKey, szJPEGFileFormat);
ASSERT(!error);
error = sAIActionManager->AIActionSetString(valueParameterBlock, kAIExportDocumentExtensionKey, "jpg");
ASSERT(!error);

error = sAIActionManager->PlayActionEvent( kAIExportDocumentAction, dialogStatus, valueParameterBlock );
ASSERT(!error);

 

 

Adobe Illustrator 10 SDK beauties

How to find out which is the name of a particular file format.

You have to acquire the sAIFileFormat suite and then do something like this:

 

 if( sAIFileFormat )
 {
  long count = 0;
  AIErr er = sAIFileFormat->CountFileFormats(&count);
  if( !er )
  {
   for(long i = 0; i < count; i++)
   {
    AIFileFormatHandle fh = NULL;
    er = sAIFileFormat->GetNthFileFormat(i, &fh);
    if( !er )
    {
     char szName[255];

     ZeroMemory(&szName, 255);
     er = sAIFileFormat->GetFileFormatExtension(fh, szName);
     if( !er )
     {
      OutputDebugStringA(szName);
      OutputDebugStringA("\n");
     }
     if( strcmp(szName, "jpg") == 0 )
     {
      char* szNames = NULL;

      er = sAIFileFormat->GetFileFormatName(fh, &szNames);
      if( !er )
      {
       OutputDebugStringA(szNames);
       OutputDebugStringA("\n");
      }
     }
    }
   }
  }
 }

in this case I was interested in the jpeg file format (extension jpg).

 

Friday, December 19, 2003

WTL Control - message reflection

If you have a wtl control (like a CListViewCtrl or a CTreeViewCtrl) and you want to handle notify messages into that class, you should have something like this in you message map:

BEGIN_MSG_MAP(CDeriveListViewCtrl)

        REFLECTED_NOTIFY_CODE_HANDLER(LVN_COLUMNCLICK, OnColumnClick)

        DEFAULT_REFLECTION_HANDLER()

END_MSG_MAP()

LRESULT OnColumnClick(int idCtrl, LPNMHDR pNmh, BOOL& bHandled);

 

it is important that you didn't specify REFLECT_NOTIFICATIONS, otherwise messages will be sent to the wrong window.

 

Wednesday, December 17, 2003

WTL list control

I always had refresh problem with the list control, now I think I had the solution:

LRESULT CEMRecycleBinListCtrl::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)

{

// we shouldn't use begin paint to obtain the HDC,

// otherwise we will loose the update region for the parent

WTL::CDC dc = GetDC();

WTL::CRgn rgn = CreateRectRgn(0,0,0,0);

if( GetUpdateRgn(rgn) != ERROR )

{

CRect headerRC;

CRect listRC;

WTL::CBrush hbrBkgnd = CreateSolidBrush(dc.GetBkColor());

CHeaderCtrl header = GetHeader();

header.GetClientRect(&headerRC);

LVHITTESTINFO htInfo;

ZeroMemory(&htInfo, sizeof(LVHITTESTINFO));

htInfo.pt.x = 1;

htInfo.pt.y = headerRC.bottom + 1;

int idx = HitTest(&htInfo);

if( idx >= 0 )

{

CRect rc;

int count = GetCountPerPage();

if( GetItemRect(idx+count, &rc, LVIR_BOUNDS) )

{

listRC.top = headerRC.bottom;

listRC.left = rc.left + 2;

listRC.bottom = rc.bottom;

listRC.right = rc.right;

WTL::CRgn headerRgn = CreateRectRgnIndirect(headerRC);

WTL::CRgn listRgn = CreateRectRgnIndirect(listRC);

rgn.CombineRgn(listRgn, RGN_DIFF);

rgn.CombineRgn(headerRgn, RGN_DIFF);

}

}

dc.FillRgn(rgn, hbrBkgnd);

}

ReleaseDC(dc);

// we should let the parent to draw himself

bHandled = FALSE;

return 0;

} // OnPaint

 

Monday, December 15, 2003

Atl COM Controls

When you are adding window support to a windowless control you have to remember to add

m_bWindowOnly = TRUE;

In the constructor if you want your CreateControlWindow virtual function to be called.

 

Friday, September 26, 2003

Property Sheets

I playing with WTL's PropertySheets and with my surprise I found out that if you embed only and ActiveX control or you subclass the only one item in the property page, on win XP you will have a very awful effect, the property sheet seems to be filled with the wrong, old dialog color.

To overcome this behavior you can insert a static control and make it invisible and the problem will vanish. If you already have other control on the dialog (like buttons, edit controls, etc.) you will not suffer from the problem.

Monday, September 22, 2003

CSS Zen

CSS at the cubic power look here.

Wednesday, September 17, 2003

AI export to PDF

Illustrator is still hurting my nerves. I give up reading the documentation and I currently reading comments inside the include files. My current task is to produce a PDF on the document. Easy.

Looking in an include file it says that with the export action you can specify the pdf file format and also you can specifiy additional parameters for that action.
The mistake here is that you must not use the export action but the saveas action.

Another very obscure point (for me at least) is that for some of the options (enum options) you have to use the specific set method (setEnumerated) but this method requires a name in addition to the value. The name is a string value so it's not obvious that you have to use the same name used in the enum in the include file. Probably it derives from the automation model, I don't know. So, for example, in the include file there is:


typedef enum _MyOption
{
opt1 = 1,
opt2
} MyOption


Then in the setEnumerated method you have to use it like:


setEnumerated( "MyOption", opt1 );


Not very intuitive (because you have defines and const for everything else).

And listen, if you want to generate the pdf using you own preferences (pdf version, color settings, and so on), you have to tell him to use the custom set and then specify the options you want.

Last but not least, if AI keeps telling you that the save command is not available at this time, most probably means you have specified wrong parameters....

Good luck.

Tuesday, September 16, 2003

Visual Studio .NET editor

I daily read some blogs on the net and I found this one Wine Thirty about the VS.NET editor and I want to share with you my opinion on it.

What left me most suprised in the VS.NET editor is the build output window. It worked near perfection if VS6 why do they changed it? With VS6 you can compile the project, the output window is automatically opened to show you the build in progress, if you have a couple of errors you can simply click on the ESC key, correct the first mistake, then ALT+2 brings you back the output window were you can navigate with arrows, choose which error you want to correct and with the RETURN key you will jump directly to the line with the error and clicking on the ESC key close the output window. Now all of this works only partially with VS.NET. You have to make the output window a docking window with the autohide feature, but if you click ESC, sometimes that window goes away and sometimes not. It's frustrating.

It looks like the new editor has been designed to be used mostly with the mouse. But that's a thing a developer want to avoid in favor of writing speed.

Illustrator: Command locale

I haven't found a way to obtain the commands using the SDK interfaces (I'm talking about menu commands), so I come up with the following idea, I get the hwnd of the main window, ask for the menu handle and get info from it. Pretty simple.

You have to use the ADMWinHostSuite (that's not portable to the Mac side but there is an equivalent ADMMacHostSuite):

ADMWinHostSuite4* sADMWinHost = NULL;
error = sSPBasic->AcquireSuite(kADMWinHostSuite, kADMWinHostSuiteVersion4, (const void **)&sADMWinHost);

And then you can ask for the window:

HWND hwnd = (HWND)sADMWinHost->GetPlatformAppWindow();

Now you have all the things you need, if you call it in the plugin startup you may need to call getparent on that window to obtain the correct window holding the menu, anyway calling it from the plugin startup you will not be able to obtain the command in the correct locale because Illustrator use some sort of identifier in the menu that are translated to the correct values at runtime.