Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Opmerking
De volgende technische opmerking is niet bijgewerkt sinds deze voor het eerst is opgenomen in de onlinedocumentatie. Als gevolg hiervan zijn sommige procedures en onderwerpen mogelijk verouderd of onjuist. Voor de meest recente informatie is het raadzaam om te zoeken naar het onderwerp waarin u geïnteresseerd bent in de onlinedocumentatie-index.
In deze opmerking wordt beschreven hoe u de macro's gebruikt voor MBCS-/Unicode-conversie, die zijn gedefinieerd in AFXPRIV.H. Deze macro's zijn het handigst als uw toepassing rechtstreeks met de OLE-API te maken heeft of om een of andere reden vaak moet worden geconverteerd tussen Unicode en MBCS.
Overzicht
In MFC 3.x werd een speciale DLL gebruikt (MFCANS32.DLL) om automatisch te converteren tussen Unicode en MBCS toen OLE-interfaces werden aangeroepen. Dit DLL-bestand was een bijna transparante laag waarmee OLE-toepassingen konden worden geschreven alsof de OLE-API's en interfaces MBCS waren, ook al zijn ze altijd Unicode (behalve op de Macintosh). Hoewel deze laag handig was en toepassingen snel konden worden overgezet van Win16 naar Win32 (MFC, Microsoft Word, Microsoft Excel en VBA, zijn slechts enkele van de Microsoft-toepassingen die deze technologie gebruikten), had het een soms aanzienlijke prestatietreffer. Daarom gebruikt MFC 4.x deze DLL niet en praat in plaats daarvan rechtstreeks met de Unicode OLE-interfaces. Hiervoor moet MFC converteren naar Unicode naar MBCS bij het aanroepen van een OLE-interface en moet MFC vaak converteren naar MBCS vanuit Unicode bij het implementeren van een OLE-interface. Om dit efficiënt en eenvoudig te kunnen afhandelen, zijn er een aantal macro's gemaakt om deze conversie gemakkelijker te maken.
Een van de grootste obstakels voor het maken van een dergelijke set macro's is geheugentoewijzing. Omdat de tekenreeksen niet ter plekke kunnen worden geconverteerd, moet nieuw geheugen worden toegewezen om de geconverteerde resultaten op te slaan. Dit kan zijn gedaan met code die vergelijkbaar is met de volgende:
// we want to convert an MBCS string in lpszA
int nLen = MultiByteToWideChar(CP_ACP,
0,
lpszA, -1,
NULL,
NULL);
LPWSTR lpszW = new WCHAR[nLen];
MultiByteToWideChar(CP_ACP,
0,
lpszA, -1,
lpszW,
nLen);
// use it to call OLE here
pI->SomeFunctionThatNeedsUnicode(lpszW);
// free the string
delete[] lpszW;
Deze aanpak heeft een aantal problemen. Het belangrijkste probleem is dat het veel code is om te schrijven, testen en fouten op te sporen. Iets wat een eenvoudige functie-aanroep was, is nu veel complexer. Daarnaast is er een aanzienlijke runtime-overhead om dit te doen. Er moet geheugen op de heap worden toegewezen en vrijgemaakt telkens wanneer een conversie wordt uitgevoerd. Ten slotte moet de juiste #ifdefs aan de bovenstaande code worden toegevoegd voor Unicode- en Macintosh-builds (waarbij deze conversie niet hoeft te worden uitgevoerd).
De oplossing die we hebben bedacht, is het maken van enkele macro's die 1) het verschil tussen de verschillende platforms maskeren, en 2) een efficiënt geheugentoewijzingsschema gebruiken, en 3) zijn eenvoudig in te voegen in de bestaande broncode. Hier volgt een voorbeeld van een van de definities:
#define A2W(lpa) (\
((LPCSTR)lpa == NULL) NULL : (\
_convert = (strnlen(lpa)+1),\
AfxA2WHelper((LPWSTR) alloca(_convert*2),
lpa,
_convert)\)\)
Het gebruik van deze macro in plaats van de bovenstaande code en dingen zijn veel eenvoudiger:
// use it to call OLE here
USES_CONVERSION;
pI->SomeFunctionThatNeedsUnicode(T2OLE(lpszA));
Er zijn extra aanroepen waar conversie nodig is, maar het gebruik van de macro's is eenvoudig en effectief.
De implementatie van elke macro maakt gebruik van de functie _alloca() om geheugen toe te wijzen vanuit de stack in plaats van de heap. Het toewijzen van geheugen van de stack is veel sneller dan het toewijzen van geheugen op de heap en het geheugen wordt automatisch vrijgemaakt wanneer de functie wordt afgesloten. Bovendien vermijden de macro's meer dan één keer aanroepen MultiByteToWideChar (of WideCharToMultiByte). Dit wordt gedaan door iets meer geheugen toe te wijzen dan nodig is. We weten dat een MBC wordt omgezet in maximaal één WCHAR en dat we voor elke WCHAR maximaal twee MBC-bytes hebben. Door iets meer toe te wijzen dan nodig is, maar altijd genoeg om de conversie af te handelen, wordt de tweede aanroep naar de conversiefunctie vermeden. De aanroep van de helperfunctie AfxA2Whelper vermindert het aantal pushes van argumenten dat moet worden uitgevoerd om de conversie uit te voeren (dit resulteert in kleinere code, dan als deze rechtstreeks wordt aangeroepen MultiByteToWideChar ).
Als u wilt dat de macro's ruimte hebben om de tijdelijke lengte op te slaan, moet u een lokale variabele met de naam _convert declareren die dit doet in elke functie die gebruikmaakt van de conversiemacro's. Dit wordt gedaan door de USES_CONVERSION macro aan te roepen, zoals hierboven in het voorbeeld wordt weergegeven.
Er zijn zowel algemene conversiemacro's als OLE-specifieke macro's. Deze twee verschillende macrosets worden hieronder besproken. Alle macro's bevinden zich in AFXPRIV.H.
Algemene conversiemacro's
De algemene conversiemacro's vormen het onderliggende mechanisme. Het macrovoorbeeld en de implementatie in de vorige sectie, A2W, is een dergelijke 'algemene' macro. Het is niet specifiek gerelateerd aan OLE. De set algemene macro's wordt hieronder weergegeven:
A2CW (LPCSTR) -> (LPCWSTR)
A2W (LPCSTR) -> (LPWSTR)
W2CA (LPCWSTR) -> (LPCSTR)
W2A (LPCWSTR) -> (LPSTR)
Naast het uitvoeren van tekstconversies zijn er ook macro's en helperfuncties voor het converteren van TEXTMETRIC, DEVMODE, BSTR en door OLE toegewezen tekenreeksen. Deze macro's vallen buiten het bereik van deze discussie. Raadpleeg AFXPRIV. H voor meer informatie over deze macro's.
OLE-Conversiemacro's
De OLE-conversiemacro's zijn speciaal ontworpen voor het verwerken van functies die OLESTR-tekens verwachten. Als u de OLE-headers bekijkt, ziet u veel verwijzingen naar LPCOLESTR en OLECHAR. Deze typen worden gebruikt om te verwijzen naar het type tekens dat wordt gebruikt in OLE-interfaces op een manier die niet specifiek is voor het platform.
OLECHAR wordt toegewezen aan char in Win16 en Macintosh platforms en WCHAR in Win32.
Om het aantal #ifdef instructies in de MFC-code tot een minimum te houden, hebben we een vergelijkbare macro voor elke conversie waarbij OLE-tekenreeksen betrokken zijn. De volgende macro's worden het meest gebruikt:
T2COLE (LPCTSTR) -> (LPCOLESTR)
T2OLE (LPCTSTR) -> (LPOLESTR)
OLE2CT (LPCOLESTR) -> (LPCTSTR)
OLE2T (LPCOLESTR) -> (LPCSTR)
Nogmaals, er zijn vergelijkbare macro's voor het uitvoeren van TEXTMETRIC, DEVMODE, BSTR en OLE toegewezen tekenreeksen. Raadpleeg AFXPRIV. H voor meer informatie.
Andere overwegingen
Gebruik de macro's niet in een strakke lus. U wilt bijvoorbeeld niet het volgende type code schrijven:
void BadIterateCode(LPCTSTR lpsz)
{
USES_CONVERSION;
for (int ii = 0; ii <10000; ii++)
pI->SomeMethod(ii, T2COLE(lpsz));
}
De bovenstaande code kan leiden tot het toewijzen van megabytes aan geheugen op de stack, afhankelijk van wat de inhoud van de tekenreeks lpsz is. Het kost ook tijd om de tekenreeks te converteren voor elke iteratie van de lus. Plaats in plaats daarvan dergelijke constante conversies buiten de lus:
void MuchBetterIterateCode(LPCTSTR lpsz)
{
USES_CONVERSION;
LPCOLESTR lpszT = T2COLE(lpsz);
for (int ii = 0; ii <10000; ii++)
pI->SomeMethod(ii, lpszT);
}
Als de tekenreeks niet constant is, wordt de methodeaanroep ingekapseld in een functie. Hierdoor kan de conversiebuffer elke keer worden vrijgemaakt. Voorbeeld:
void CallSomeMethod(int ii, LPCTSTR lpsz)
{
USES_CONVERSION;
pI->SomeMethod(ii, T2COLE(lpsz));
}
void MuchBetterIterateCode2(LPCTSTR* lpszArray)
{
for (int ii = 0; ii <10000; ii++)
CallSomeMethod(ii, lpszArray[ii]);
}
Retourneer nooit het resultaat van een van de macro's, tenzij de retourwaarde impliceert dat een kopie van de gegevens wordt gemaakt vóór de retour. Deze code is bijvoorbeeld ongeldig:
LPTSTR BadConvert(ISomeInterface* pI)
{
USES_CONVERSION;
LPOLESTR lpsz = NULL;
pI->GetFileName(&lpsz);
LPTSTR lpszT = OLE2T(lpsz);
CoMemFree(lpsz);
return lpszT; // bad! returning alloca memory
}
De bovenstaande code kan worden opgelost door de retourwaarde te wijzigen in iets waarmee de waarde wordt gekopieerd:
CString BetterConvert(ISomeInterface* pI)
{
USES_CONVERSION;
LPOLESTR lpsz = NULL;
pI->GetFileName(&lpsz);
LPTSTR lpszT = OLE2T(lpsz);
CoMemFree(lpsz);
return lpszT; // CString makes copy
}
De macro's zijn eenvoudig te gebruiken en eenvoudig in uw code in te voegen, maar zoals u in de bovenstaande opmerkingen kunt zien, moet u voorzichtig zijn bij het gebruik ervan.
Zie ook
Technische notities per nummer
Technische Aantekeningen Per Categorie