Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bazen sahte konsol, ConPTY veya Windows PTY olarak da adlandırılan Windows Pseudoconsole, varsayılan konsol konak penceresinin kullanıcı etkileşim bölümünün yerini alan karakter modu alt sistemi etkinlikleri için bir dış konak oluşturmak için tasarlanmış bir mekanizmadır.
Psödokonol oturumunu barındırmak, geleneksel konsol oturumundan biraz farklıdır. Geleneksel konsol oturumları, işletim sistemi karakter modu uygulamasının çalışmak üzere olduğunu algıladığında otomatik olarak başlar. Buna karşılık, barındırılacak alt karakter modu uygulamasıyla işlem oluşturulmadan önce, bir psödokonsole oturumu ve iletişim kanalları barındırma uygulaması tarafından oluşturulmalıdır. Alt işlem Yine CreateProcess işlevi kullanılarak oluşturulur, ancak işletim sistemini uygun ortamı oluşturmaya yönlendirecek bazı ek bilgilerle.
Bu sistem hakkında ek arka plan bilgilerini ilk duyuru blog gönderisinde bulabilirsiniz.
Pseudoconsole kullanımına ilişkin tüm örnekler, samples dizinindeki GitHub depomuz microsoft/terminalde bulunabilir.
İletişim kanallarını hazırlama
İlk adım, barındırılan uygulamayla çift yönlü iletişim için psödokonol oturumu oluşturulurken sağlanacak bir çift zaman uyumlu iletişim kanalı oluşturmaktır. Bu kanallar, zaman uyumlu G/Ç ile ReadFile ve WriteFile kullanılarak sahte şirket sistemi tarafından işlenir. Zaman uyumsuz iletişim için ÇAKıŞAN bir yapı gerekmediği sürece dosya akışı veya kanal gibi dosya veya G/Ç cihaz tanıtıcıları kabul edilebilir.
Uyarı
Yarış koşullarını ve kilitlenmeleri önlemek için, iletişim kanallarının her birine kendi istemci arabellek durumunu ve uygulamanızın içindeki mesajlaşma kuyruğunu koruyan ayrı bir iş parçacığında hizmet vermenizi kesinlikle öneririz. Aynı iş parçacığındaki tüm sahte kullanıma hazır etkinliklere hizmet vermek, iletişim arabelleklerinden birinin doldurulduğu ve siz başka bir kanala engelleme isteği göndermeye çalışırken eyleminizi beklediği bir kilitlenmeye neden olabilir.
Pseudoconsole oluşturma
Oluşturulan iletişim kanallarıyla, giriş kanalının "okuma" ucunu ve çıkış kanalının "yazma" ucunu belirleyin. Bu tanıtıcı çifti, nesneyi oluşturmak için CreatePseudoConsole çağrısında sağlanır.
Oluşturma işleminde, X ve Y boyutlarını temsil eden bir boyut (karakter sayısı cinsinden) gerekir. Bunlar, son (terminal) sunu penceresi için ekran yüzeyine uygulanacak boyutlardır. Değerler, sahte harf sistemi içinde bellek içi arabellek oluşturmak için kullanılır.
Arabellek boyutu, GetConsoleScreenBufferInfoEx gibi istemci tarafı konsol işlevlerini kullanarak bilgi yoklayan ve istemciler WriteConsoleOutput gibi işlevler kullandığında metnin düzenini ve konumunu belirleyen istemci karakter modu uygulamalarına yanıt sağlar.
Son olarak, özel işlevler gerçekleştirmek için sahte bir taban oluşturulurken bayraklar alanı sağlanır. Varsayılan olarak, özel bir işleve sahip olmaması için bunu 0 olarak ayarlayın.
Şu anda, sözde konsol API'sinin çağırıcısına eklenmiş olan bir konsol oturumundan imleç konumunun devralınmasını istemek için yalnızca bir özel bayrak kullanılabilir. Bu, psödokonol oturumu hazırlayan bir barındırma uygulamasının kendisi de başka bir konsol ortamının istemci karakter modu uygulaması olduğu daha gelişmiş senaryolarda kullanıma yöneliktir.
Aşağıda createPipe kullanarak bir iletişim kanalı çifti oluşturmak ve sahte kural oluşturmak için örnek bir kod parçacığı verilmiştir.
HRESULT SetUpPseudoConsole(COORD size)
{
HRESULT hr = S_OK;
// Create communication channels
// - Close these after CreateProcess of child application with pseudoconsole object.
HANDLE inputReadSide, outputWriteSide;
// - Hold onto these and use them for communication with the child through the pseudoconsole.
HANDLE outputReadSide, inputWriteSide;
if (!CreatePipe(&inputReadSide, &inputWriteSide, NULL, 0))
{
return HRESULT_FROM_WIN32(GetLastError());
}
if (!CreatePipe(&outputReadSide, &outputWriteSide, NULL, 0))
{
return HRESULT_FROM_WIN32(GetLastError());
}
HPCON hPC;
hr = CreatePseudoConsole(size, inputReadSide, outputWriteSide, 0, &hPC);
if (FAILED(hr))
{
return hr;
}
// ...
}
Uyarı
Bu kod parçacığı eksiktir ve yalnızca bu belirli çağrının gösterimi için kullanılır. HANDLE'larınkullanım ömrünü uygun şekilde yönetmeniz gerekir. HANDLE'larınömrünün doğru yönetilememesi, özellikle zaman uyumlu G/Ç çağrılarında kilitlenme senaryolarına neden olabilir.
Pseudoconsole'a bağlı istemci karakter modu uygulamasını oluşturmak için CreateProcess çağrısı tamamlandıktan sonra, oluşturma sırasında verilen tanıtıcılar bu işlemden kurtarılmalıdır. Bu, temel alınan cihaz nesnesinde başvuru sayısını azaltır ve sahte konsol oturumu tanıtıcıların kopyasını kapattığında G/Ç işlemlerinin bozuk kanalı düzgün bir şekilde algılamasına olanak sağlar.
Alt İşlemin Oluşturulmasına Hazırlanma
Sonraki aşama, alt işlemi başlatırken sahte ipokonol bilgilerini aktaracak STARTUPINFOEX yapısını hazırlamaktır.
Bu yapı, işlem ve iş parçacığı oluşturma öznitelikleri de dahil olmak üzere karmaşık başlangıç bilgileri sağlama özelliğini içerir.
InitializeProcThreadAttributeList öğesini çift çağrılı bir şekilde kullanarak önce listeyi tutmak için gereken bayt sayısını hesaplayın, istenen belleği ayırın, sonra öznitelik listesi olarak ayarlanması için opak bellek işaretçisini sağlayarak yeniden çağırın.
Ardından, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE bayrağı, psödokonol tanıtıcısı ve psödokonol tutamacının boyutuyla başlatılan öznitelik listesini geçirerek UpdateProcThreadAttribute'u çağırın.
HRESULT PrepareStartupInformation(HPCON hpc, STARTUPINFOEX* psi)
{
// Prepare Startup Information structure
STARTUPINFOEX si;
ZeroMemory(&si, sizeof(si));
si.StartupInfo.cb = sizeof(STARTUPINFOEX);
// Discover the size required for the list
size_t bytesRequired;
InitializeProcThreadAttributeList(NULL, 1, 0, &bytesRequired);
// Allocate memory to represent the list
si.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, bytesRequired);
if (!si.lpAttributeList)
{
return E_OUTOFMEMORY;
}
// Initialize the list memory location
if (!InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &bytesRequired))
{
HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
return HRESULT_FROM_WIN32(GetLastError());
}
// Set the pseudoconsole information into the list
if (!UpdateProcThreadAttribute(si.lpAttributeList,
0,
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
hpc,
sizeof(hpc),
NULL,
NULL))
{
HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
return HRESULT_FROM_WIN32(GetLastError());
}
*psi = si;
return S_OK;
}
Barındırılan İşlemi Oluşturma
Ardından, çalıştırılabilir dosyanın yolu ve varsa ek yapılandırma bilgileriyle birlikte STARTUPINFOEX yapısını geçirerek CreateProcess'i çağırın. Genişletilmiş bilgilerde psödokonol başvurusunun yer aldığı konusunda sistemi uyarmak için çağrı yapılırken EXTENDED_STARTUPINFO_PRESENT bayrağının ayarlanması önemlidir.
HRESULT SetUpPseudoConsole(COORD size)
{
// ...
PCWSTR childApplication = L"C:\\windows\\system32\\cmd.exe";
// Create mutable text string for CreateProcessW command line string.
const size_t charsRequired = wcslen(childApplication) + 1; // +1 null terminator
PWSTR cmdLineMutable = (PWSTR)HeapAlloc(GetProcessHeap(), 0, sizeof(wchar_t) * charsRequired);
if (!cmdLineMutable)
{
return E_OUTOFMEMORY;
}
wcscpy_s(cmdLineMutable, charsRequired, childApplication);
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
// Call CreateProcess
if (!CreateProcessW(NULL,
cmdLineMutable,
NULL,
NULL,
FALSE,
EXTENDED_STARTUPINFO_PRESENT,
NULL,
NULL,
&siEx.StartupInfo,
&pi))
{
HeapFree(GetProcessHeap(), 0, cmdLineMutable);
return HRESULT_FROM_WIN32(GetLastError());
}
// ...
}
Uyarı
Barındırılan işlem hala başlatılırken ve bağlanırken psödokonol oturumunun kapatılması, istemci uygulaması tarafından bir hata iletişim kutusunun gösterilmesine neden olabilir. Barındırılan işleme başlatma için geçersiz bir sahte sunucu tanıtıcısı verildiğinde aynı hata iletişim kutusu gösterilir. Barındırılan işlem başlatma kodu için iki durum aynıdır. Hata durumunda barındırılan istemci uygulamasından açılan iletişim kutusu, başlatılamamasıyla ilgili ayrıntıları içeren yerelleştirilmiş bir iletiyle birlikte okunur 0xc0000142 .
Pseudoconsole Oturumuyla İletişim Kurma
İşlem başarıyla oluşturulduktan sonra, barındırma uygulaması kullanıcı etkileşim bilgilerini sahte konsola göndermek için giriş kanalının yazma ucunu ve sahte konsoldan grafik sunu bilgilerini almak için çıkış kanalının okuma ucunu kullanabilir.
Daha fazla etkinliğin nasıl işleneceğini belirlemek tamamen barındırma uygulamasına kalmış. Barındırma uygulaması, kullanıcı etkileşimi girişini toplamak ve takma ad ve barındırılan karakter modu uygulaması için giriş kanalının yazma ucuna seri hale getirmek için başka bir iş parçacığında bir pencere başlatabilir. Psödokonol için çıkış kanalının okuma ucunu boşaltmak, metin ve sanal terminal dizisi bilgilerinin kodunu çözmek ve bunu ekrana sunmak için başka bir iş parçacığı başlatılabilir.
İş parçacıkları, sahte kod kanallarından gelen bilgileri başka bir işlem veya makineye uzak bilgilere ağ da dahil olmak üzere farklı bir kanala veya cihaza aktarmak ve bilgilerin yerel olarak çevrilmesinden kaçınmak için de kullanılabilir.
Pseudoconsole'yi yeniden boyutlandırma
Çalışma zamanı boyunca, bir kullanıcı etkileşimi veya başka bir görüntüleme/etkileşim cihazından bant dışına alınan istek nedeniyle arabellek boyutunun değiştirilmesi gereken bir durum olabilir.
Bu işlem ResizePseudoConsole işleviyle, arabelleğin hem yüksekliğini hem de genişliğini karakter sayısı olarak belirterek yapılabilir.
// Theoretical event handler function with theoretical
// event that has associated display properties
// on Source property.
void OnWindowResize(Event e)
{
// Retrieve width and height dimensions of display in
// characters using theoretical height/width functions
// that can retrieve the properties from the display
// attached to the event.
COORD size;
size.X = GetViewWidth(e.Source);
size.Y = GetViewHeight(e.Source);
// Call pseudoconsole API to inform buffer dimension update
ResizePseudoConsole(m_hpc, size);
}
Pseudoconsole Oturumunu Sonlandırma
Oturumu sonlandırmak için ClosePseudoConsole işlevini özgün sözdeconsole oluşturma tutamacıyla çağırın. Oturum kapatıldığında CreateProcess çağrısındaki gibi ekli istemci karakter modu uygulamaları sonlandırılır. Özgün alt öğe başka işlemler oluşturan kabuk türündeki bir uygulamaysa, ağaçtaki ilişkili ekli işlemler de sonlandırılır.
Uyarı
Oturumu kapatmanın birkaç yan etkisi vardır ve bu da psödokonizyon tek iş parçacıklı zaman uyumlu bir şekilde kullanılıyorsa kilitlenme durumuna neden olabilir. Psödokonol oturumunu kapatma eylemi, iletişim kanalı arabelleğinden boşaltılması gereken son bir çerçeve güncelleştirmesi hOutput yayabilir. Buna ek olarak, psödokonol oluşturulurken seçilirse PSEUDOCONSOLE_INHERIT_CURSOR , imleç devralma sorgu iletisine yanıt vermeden (üzerinde hOutput alınan ve yoluyla hInputyanıtlanan) sahte kondisyon kapatılmaya çalışılması başka bir kilitlenme koşuluna neden olabilir. Psödokonol için iletişim kanallarının tek tek iş parçacıklarında hizmet vermeleri ve istemci uygulamasından çıkılarak veya ClosePseudoConsole işlevini çağırmadaki yırtılma etkinliklerinin tamamlanmasıyla kendi kendilerine bozulana kadar boşaltılıp işlenmeleri önerilir.