Sdílet prostřednictvím


TN059: Použití převodních maker MBCS/Unicode prostředí MFC

[!POZNÁMKA]

Následující technická poznámka nebyla aktualizována, protože byla poprvé zahrnuta v dokumentaci online.V důsledku toho některé postupy a témata mohou být nesprávné nebo zastaralé.Pro nejnovější informace je vhodné vyhledat téma zájmu v dokumentaci online index.

Tato poznámka popisuje, jak použít makra pro převod znakové sady MBCS/Unicode, které jsou definovány v AFXPRIV.H.Tato makra jsou zvláště užitečné, pokud vaše aplikace obchody přímo s OLE API nebo z nějakého důvodu často potřebuje převést mezi Unicode a znakové sady MBCS.

Přehled

V knihovně MFC 3.x, speciální knihovny DLL byla použita (MFCANS32.Knihovna DLL) automaticky převést mezi Unicode a znakové sady MBCS, když byla volána rozhraní OLE.Tato knihovna DLL byla téměř průhledné vrstvy, kterou aplikace OLE zapsáno jako kdyby OLE API a rozhraní MBCS, přestože jsou vždy ve formátu Unicode (s výjimkou v systému Macintosh).Během této vrstvy je pohodlný a povolené aplikace rychle přenést z Win16 na Win32 (MFC, Microsoft Word, Microsoft Excel a VBA, jsou jen některé aplikace, které používají tuto technologii), měl někdy významné výkonnostní přístupů.Z tohoto důvodu MFC 4.x nepoužívá tuto knihovnu DLL a místo toho pojednává přímo na rozhraní Unicode OLE.Chcete-li to provést, knihovna MFC potřebuje převést do kódování Unicode do znakové sady MBCS, při volání rozhraní OLE a často potřebuje převést do znakové sady MBCS v kódování Unicode při implementaci rozhraní OLE.Obejdete snadno a efektivně tak, aby se počet maker vytvořených usnadnit tento převod.

Jedním z největších mezní hodnoty pro vytvoření sady maker je přidělení paměti.Protože řetězec nelze převést na místě, musí být přiděleny nové paměti pro uložení převedené výsledky.To by bylo provést pomocí kódu podobná následující:

// 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;

Tento přístup jako mnoho problémů.Hlavním problémem je, že je velké množství kódu k psaní, testování a ladění.Něco, co bylo jednoduché funkce volání, je nyní mnohem složitější.Režie přitom je navíc významné runtime.Paměti musí být přiděleny na haldě modulu a uvolnění pokaždé, když se provádí převod.Nakonec z kódu výše musel mít odpovídající #ifdefs přidané pro sestavení Unicode a Macintosh, (které nevyžadují tento převod uskutečnit).

Chcete-li vytvořit některá makra, které masky 1) rozdíl mezi různými platformami a 2) používání režimu přidělení paměti pro efektivní a 3) jsou snadno vložit do existující zdrojový kód je řešení, které jsme obdrželi s.Zde je příklad jedné z definic:

#define A2W(lpa) (\
    ((LPCSTR)lpa == NULL) ? NULL : (\
          _convert = (strnlen(lpa)+1),\
        AfxA2WHelper((LPWSTR) alloca(_convert*2), 
      lpa, _convert)\
    )\
)

Pomocí tohoto makra namísto výše uvedeného kódu a věci jsou mnohem jednodušší:

// use it to call OLE here
USES_CONVERSION;
pI->SomeFunctionThatNeedsUnicode(T2OLE(lpszA));

Existují další volání, kde převodu je nutné, ale pomocí maker je jednoduchý a účinný.

Provádění každé makro používá funkci _alloca() k přidělení paměti ze zásobníku místo haldy.Přidělování paměti ze zásobníku je mnohem rychlejší než přiděluje paměť na haldě a paměť je automaticky uvolněno, když funkce skončí.Kromě toho makra vyhnout volací MultiByteToWideChar (nebo Funkce WideCharToMultiByte) více než jednou.To se provádí pomocí přidělování trochu více paměti, než je nezbytné.Víme, že MBC převede do nejvýše jeden WCHAR a z WCHAR máme maximálně dva bajty MBC.Přidělením o něco více než potřebná, ale vždy dostatečně ke zpracování převodu druhé volání druhé volání funkce převodu se vyhnout.Volání funkce pomocníka AfxA2Whelper snižuje počet argument posuny, které je třeba provést za účelem provedení převodu (vede menší kódu, než-li volán MultiByteToWideChar přímo).

Aby maker do místa pro ukládání dočasné délky, je nutné deklarovat místní proměnnou s názvem _convert, který to v každé funkci, používá makra převodu.To se provádí voláním USES_CONVERSION makro popsané výše v příkladu.

Existují i převod obecné a zvláštní makra OLE.Tyto dvě sady jiné makro jsou uvedeny níže.Všechna makra jsou umístěny v AFXPRIV.H.

Obecný převod makra

Obecný převod makra formuláře základní mechanismus.Příklad makra a provádění uvedené v předchozí části A2W, je jedno "obecný" makro.Nesouvisí s OLE zvlášť.Sadu maker, Obecné jsou uvedeny níže:

A2CW      (LPCSTR) -> (LPCWSTR)
A2W      (LPCSTR) -> (LPWSTR)
W2CA      (LPCWSTR) -> (LPCSTR)
W2A      (LPCWSTR) -> (LPSTR)

Kromě dělá převody text, jsou k dispozici také makra a podporu funkcí pro převod TEXTMETRIC, DEVMODE, BSTRa přidělený řetězec OLE.Tato makra jsou nad rámec této diskuse – naleznete na AFXPRIV.H Další informace o těchto maker.

Převod makra OLE

Určené pro funkce, které očekávají zpracování makra převodu OLE OLESTR znaky.Pokud si prohlédnete záhlaví OLE, zobrazí se mnoho odkazů na LPCOLESTR a OLECHAR.Tyto typy se používají k odkazování na typ znaků používaných v rozhraní OLE způsobem, který není specifický pro platformu.OLECHAR odpovídá char v Win16 a Macintosh platformy a WCHAR v systému Win32.

S cílem zachovat počet #ifdef směrnic v knihovny MFC kódu minimální máme podobně jako makro pro každý převod, pokud se jedná o řetězec OLE.Nejčastěji se používají následující makra:

T2COLE   (LPCTSTR) -> (LPCOLESTR)
T2OLE   (LPCTSTR) -> (LPOLESTR)
OLE2CT   (LPCOLESTR) -> (LPCTSTR)
OLE2T   (LPCOLESTR) -> (LPCSTR)

Opět existují podobné makra to TEXTMETRIC, DEVMODE, BSTRa přidělený řetězec OLE.Naleznete na AFXPRIV.H Další informace.

Ostatní úvahy

Nepoužívejte makra v těsné smyčky.Například nechcete psát následující druh kódu:

void BadIterateCode(LPCTSTR lpsz)
{
   USES_CONVERSION;
   for (int ii = 0; ii < 10000; ii++)
      pI->SomeMethod(ii, T2COLE(lpsz));
}

Výše uvedený kód může vést k přidělení megabajtů paměti zásobníku v závislosti na obsahu řetězce lpsz je!Má také čas pro převedení řetězce za každé opakování smyčky.Místo toho přesunete tyto stálé převody ze smyčky:

void MuchBetterIterateCode(LPCTSTR lpsz)
{
   USES_CONVERSION;
   LPCOLESTR lpszT = T2COLE(lpsz);
   for (int ii = 0; ii < 10000; ii++)
      pI->SomeMethod(ii, lpszT);
}

Pokud řetězec není konstantní, pak zapouzdřují volání metody do funkce.To vám umožní vyrovnávací převod na každém uvolnění.Příklad:

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]);
}

Nikdy vrátit výsledek jednoho z makra, pokud je vrácená hodnota znamená vytvoření kopie dat před návratu.Například tento kód je špatný:

LPTSTR BadConvert(ISomeInterface* pI)
{
   USES_CONVERSION;
   LPOLESTR lpsz = NULL;
   pI->GetFileName(&lpsz);
   LPTSTR lpszT = OLE2T(lpsz);
   CoMemFree(lpsz);
   return lpszT; // bad! returning alloca memory
}

Výše uvedený kód by dlouhodobého změnou vrácenou hodnotu na něco, co zkopíruje hodnotu:

CString BetterConvert(ISomeInterface* pI)
{
   USES_CONVERSION;
   LPOLESTR lpsz = NULL;
   pI->GetFileName(&lpsz);
   LPTSTR lpszT = OLE2T(lpsz);
   CoMemFree(lpsz);
   return lpszT; // CString makes copy
}

Makra jsou snadno ovladatelný a snadno vložit do kódu, ale jak můžete zjistit z výše uvedené upozornění, musíte být opatrní při jejich použití.

Viz také

Další zdroje

Technické poznámky podle čísel

Technické poznámky podle kategorií