Ressourcen


ProgrammierenRessourcenSoftwareToolsWindowsMartin Richter - Sa 29 Aug 2009 16:59

Der IconWorkshop von Axialis ist mein bevorzugter Editor für Bitmaps und Icons. Der IconWorkshop integriert sich in Vs-2005 und VS-2008 über ein Plugin.

Wer den IconWorkshop 6.5 noch nicht hat, der hat die Chance bis morgen den 31.08.2009 noch 50% Rabatt zu bekommen. Die Sommerrabatt Aktion gilt auch für alle anderen Axialis Produkte.

Alles weitere bei Axialis:
http://www.axialis.com/purchase/

Axialis

C++MFCProgrammierenRessourcenWindows APIMartin Richter - So 07 Dez 2008 17:59

Wer komplexere UIs baut, der kommt um Drag&Drop oder andere Extrafunktionen mit der Maus nicht herum. Um den Benutzer gut zu unterstützen verwendet man natürlich auch spezielle Cursor.
Auffällig ist aber oft genug der Unterschied zwischen den schönen Standardzeigern im 3D-Stil und den oft flachen Zeigern, die gerade mal zusätzlich ein Plus oder ein Stoppzeichen tragen. Oder ganz und gar der Unterschied , wenn man eigene Cursorstile verwendet, wie z.B. Dirigent oder Hände.

Ich habe mich bei meinem aktuellen Projekt gefragt, warum man eigentlich nicht den aktuellen Standard-Cursor verwendet und diesen zusätzlich mit dem entsprechenden Symbol versieht (Pluszeichen, Stopp, Dragframe etc). Das würde besser aussehen und Arbeit sparen, weil man sich nur noch Gedanken um die Extrasymbolik machen muss und der Benutzer behält seinen eingestellten normalen Cursor.

Schaut man sich den Explorer unter XP+Vista an, dann macht man die Entdeckung, dass der es genauso macht. Der aktuelle Cursor wird beim Drag&Drop Vorgang um ein Stopp- oder Pluszeichen ergänzt.

Warum es also nicht selber auch so machen ❓

Meine Suche im Internet zu diesem Thema: „Wie kombiniert man zwei Cursor zu einem?“, war nicht von Erfolg gekrönt. Beispielcode dazu habe ich nicht gefunden. Aber auch wirklich gar nichts.
Also selbst Hand anlegen.

Bei meinem ersten Versuch wollte ich die Cursor-Bitmaps direkt manipulieren. Bei meiner Untersuchung und dem ersten Democode wurde klar, dass Windows gar keinen Unterschied mehr zwischen Icons und Cursor macht. Erstaunlich ❗ Ob Icon oder Cursor spielt eigentlich keine Rolle. HCURSOR und HICON sind identische Typedefs. Also egal ob toller Farbcursor oder monochromer Cursor, alles gleich.
Mit dieser Entdeckung nahm ich schnell Abstand von BitBlt und Konsorten und verwendete eine Imagelist, die genau diese Funktion des Overlays von Symbolen bereits unterstützt und zudem auch noch perfekt mit Icons umgehen kann.

Herausgekommen ist der folgende Code, der es erlaubt zwei Icons, oder Cursor zu überlagern und ein neues Icon oder einen neuen Cursor zu erzeugen.

Man muss sich aso nur mit LoadCursor, den aktuellen Cursor laden und kann diesen damit ganz einfach modifzieren. Nicht vergessen: Das erzeugte Icon/Cursor muss allerdings mit DestroyIcon auch wieder entsorgt werden. Das Ganze habe ich der Einfachheit halber mit MFC Funktionen geschrieben, aber das Ganze in pure WinAPI zu transformieren dürfte nicht schwer sein. 😉

 Hier nun der Code. Have fun!

HICON CombineIcons(HICON hIcon1, HICON hIcon2)
{
 // Remember that HCURSOR and HICON are identical!
 // hIcon1 is overlayed by hIcon2.
 // hIcon2 isn't adjusted in size or position.
 // It just overlays hIcon1
 // Get bitmaps of icon 1
 ICONINFO iconInfo;
 ::ZeroMemory(&iconInfo,sizeof(iconInfo));
 if (!GetIconInfo(hIcon1,&iconInfo))
  return NULL;

 // Attach the bitmaps to get them automatically freed
 // upon error.
 CBitmap bitmap, mask;
 bitmap.Attach(iconInfo.hbmColor);
 mask.Attach(iconInfo.hbmMask);

 // Get size and width
 BITMAP bm;
 if (bitmap.m_hObject)
  bitmap.GetObject(sizeof(bm),&bm);
 else
  mask.GetObject(sizeof(bm),&bm);

 // Get the color depth from the icon and create an image list
 // Remember we need a
 UINT flags = 0;
 switch (bm.bmBitsPixel)
 {
 case 4:  flags = ILC_COLOR4;  break;
 case 8:  flags = ILC_COLOR8;  break;
 case 16: flags = ILC_COLOR16; break;
 case 24: flags = ILC_COLOR24; break;
 case 32: flags = ILC_COLOR32; break;
 default: flags = ILC_COLOR4;  break;  
 }
 CImageList il;
 // be ware that the monochrom cursor bitmap is twice the height
 if (!il.Create(bm.bmWidth,
      bm.bmHeight/(iconInfo.hbmColor!=NULL ? 1 : 2),
      ILC_MASK|flags,2,2))
  return NULL;

 // Load the both icons into the image list
 il.Add(hIcon1);
 il.Add(hIcon2);

 // Define the second icon as an overlay image
 il.SetOverlayImage(1,1);

 // Get a new icon with icon 2 overlayed
 HICON hCombined = ImageList_GetIcon(il.m_hImageList,0,
              ILD_NORMAL|INDEXTOOVERLAYMASK(1));
 if (!hCombined)
  return NULL;

 // Need the icon infos for this new icon
 ICONINFO iconInfoCombined;
 ::ZeroMemory(&iconInfoCombined,sizeof(iconInfo));
 if (!GetIconInfo(hCombined,&iconInfoCombined))
  return NULL;

 // Destroy the combined icon, we just have the bitmap and the mask
 ::DestroyIcon(hCombined);

 // Get the bitmaps into objects to get them automatically freed
 CBitmap bitmapCombined, maskCombined;
 bitmapCombined.Attach(iconInfo.hbmColor);
 maskCombined.Attach(iconInfo.hbmMask);

 // Get the hotspotinto and cursor data from
 // the ICONINFO of hCursor1
 iconInfoCombined.fIcon = iconInfo.fIcon;
 iconInfoCombined.xHotspot = iconInfo.xHotspot;
 iconInfoCombined.yHotspot = iconInfo.yHotspot;

 // OK we have can create a new Cursor out of the target
 // Don't forget to use DestroyIcon for the new Cursor/Icon
 return ::CreateIconIndirect(&iconInfoCombined);
}
CommunityInternetProgrammierenRessourcenSoftwareToolsMartin Richter - Fr 03 Okt 2008 20:56

Microsoft ist dazu übergangen Artikel, die älter als 8 Jahre sind aus dem MSDN heraus zu nehmen. Leider! Denn viele wertvolle Windows API Artikel gehen damit verloren oder sind nicht mehr verfügbar, so zum Beispiel ist auch die OLE Bibel von Kraig Brockschmidt.

Besonders peinlich finde ich es, wenn Microsoft Artikel entfernt auf die in der KB noch Bezug genommen wird, wie zum Beispiel in diesem KB Artikel INFO: Syntax of the Res: Protocol and Some Known Related Issues.
Mir ging es um den Artikel http://www.microsoft.com/mind/0199/cutting/cutting0199.asp, dessen Link leider ins Leere verläuft.

Bleibt die Frage wie man solche alte Artikel wiederfindet, die noch von anderer Seite her referenziert werden ❓

Sofern man (wie hier) die komplette alte URL noch kennt gibt es zum Glück http://web.archive.org/   ❗

Einfach im Advanced Search die URL angegeben http://www.microsoft.com/mind/0199/cutting/cutting0199.asp

Und siehe da man erhält:
http://web.archive.org/web/*/http://www.microsoft.com/mind/0199/cutting/cutting0199.asp
Wie man sieht ist der Artikel Ende 2007 zuletzt auf den MS Seiten zu sehen gewesen.

Bleibt nur noch die Frage, wie man an die alten Links kommt ❓

Es gibt einen schnellen zweiten Weg, wenn der Artikel vor 2001 bereits veröffentlicht war. Google war so nett und hat uns Google 2001 bereitgestellt ❗

Die Suche ergab hier schnell das folgende Ergebnis:
http://www.google.com/search2001/search?hl=en&q=%22Pluggable+Protocols%22+res

Und siehe da, wir erhalten zusätzlich wieder einen Link auf das bereits erwähnte http://web.archive.org :
http://web.archive.org/web/2001/http://msdn.microsoft.com/library/periodic/period99/cutting0199.htm

Google 2001 kann hier also auch ein richtig gutes Helferlein sein um verschollene Informationen und Artikel wieder aufzufinden.

C++ProgrammierenRessourcenSonstigesWindows APIMartin Richter - So 08 Jun 2008 19:40

Immer wieder taucht die Frage auf, wie die Funktionen zum Laden von Ressourcen (LoadImage, LoadCursor, LoadMenu etc.) eigentlich arbeiten und entscheiden aus welcher LANGID-Sektion die Ressource geladen wird.

Die Dokumentation von FindResource – auf der alle diese Funktionen basieren – gibt leider keine Auskunft.

Wenn man jedoch etwas sucht wird man in der Dokumentation von Developing International Software fündig. Dort findet sich der folgende Abschnitt mit dem Titel Multiple Language Resources, in dem auch beschrieben wird wie FindResource arbeitet und wie eine Ressource gesucht wird:

If the FindResource and FindResourceEx functions do not find any resources that match the language ID’s primary language, they search for resources tagged as „language-neutral.“ This language ID is useful for resource elements such as icons or cursors that are identical for all languages. If a bitmap or an icon will differ for some languages, you can define one language-neutral bitmap as the default and specify language IDs for as many other customized bitmaps as required. For example, bidirectional applications might require bitmaps with right-to-left directionality. Because the FindResource and FindResourceEx functions always search for specific language IDs first, they will always find a bitmap tagged with that language ID before they find one tagged as language-neutral. The search algorithm they follow is summarized in the following list:

1. Primary language/sublanguage
2. Primary language
3. Language-neutral
4. English (skipped if primary language is English)
5. Any

ProgrammierenRessourcenMartin Richter - Di 01 Mai 2007 07:30

Ich habe in einem größeren Projekt nach einem Problem gesucht, dass nach der Umstellung auf UNICODE auftrat. Durch Erzeugen von Dialogen mit älteren Visual Studio Editionen wurden manche Dialoge mit dem nachfolgenden Font Eintrag erzeugt:

FONT 8, „MS Sans Serif“, 0, 0, 0x1

Die Folge war eine inkorrekte Anzeige wenn UNICODE Zeichensequenzen eingegeben wurden.
Richtig wäre der folgende Eintrag, wie ich es haben wollte

FONT 8, „MS Shell Dlg“, 0, 0, 0x0

in Verbindung mit den Flags DS_SETFONT und DS_SHELLFONT.
Im Resource-Editor findet sich dazu eine Extra Eigenschaft „Use System Font“ direkt unter der „Font (Size)“ Eigenschaft.

Was steht nun in der Ressourcen Datei, wenn man „Use System Font“ anklickt?

🙄 STYLE DS_SETFONT | DS_FIXEDSYS | …

Und die Doku in der MSDN sagt zu DS_FIXEDSYS:
Causes the dialog box to use the SYSTEM_FIXED_FONT instead of the default SYSTEM_FONT. This is a monospace font compatible with the System font in 16-bit versions of Windows earlier than 3.0.

😮 Habe ich hier einen Bug im Ressoure-Editor entdeckt? Was soll ein altes Windows 3.0 Flag in meinem 32bit Programm?

Die Antwort lautet: Nein!
Das ganze klärt sich auf, wenn man die Definitionen dieser Werte ansieht:

#define DS_SETFONT 0x40L /* User specified font for Dlg controls */
#define DS_FIXEDSYS 0x0008L
#define DS_SHELLFONT (DS_SETFONT | DS_FIXEDSYS)

Es ist nur einfach verwirrend, weil der Resource Editor aus der Eigenschaft „Use System Font“ und dem Font „MS Shell Dlg“ die Flags DS_SETFONT | DS_FIXEDSYS im STYLE Eintrag macht und die Bits einzeln auflöst.
Es ist natürlich alles OK, aber wirklich sehr verwirrend, aber ich wiederhole mich.