Rozwiązywanie problemów z dpi
Coraz większa liczba urządzeń jest wysyłana z ekranami o wysokiej rozdzielczości. Te ekrany zwykle mają ponad 200 pikseli na cal (ppi). Praca z aplikacją na tych komputerach wymaga skalowania zawartości w górę w celu zaspokojenia potrzeb wyświetlania zawartości na normalnym dystansie wyświetlania urządzenia. Od 2014 roku głównym celem wyświetlaczy o wysokiej gęstości jest urządzenia przenośne (tablety, laptopy clamshell i telefony).
System Windows 8.1 lub nowszy zawiera kilka funkcji umożliwiających tym maszynom pracę z wyświetlaczami i środowiskami, w których maszyna jest podłączona zarówno do wyświetlaczy o wysokiej gęstości, jak i standardowej gęstości w tym samym czasie.
System Windows umożliwia skalowanie zawartości na urządzenie przy użyciu ustawienia "Ustaw tekst i inne elementy większe lub mniejsze" (dostępne od systemu Windows XP).
System Windows 8.1 lub nowszy automatycznie skaluje zawartość, aby większość aplikacji była spójna po przeniesieniu między wyświetlaczami o różnych gęstości pikseli. Gdy ekran podstawowy ma wysoką gęstość (200% skalowania), a pomocniczy ekran ma standardową gęstość (100%), system Windows automatycznie skaluje zawartość okna aplikacji w dół na ekranie pomocniczym (1 piksel wyświetlany dla każdego 4 pikseli renderowanego przez aplikację).
System Windows będzie domyślnie skalowany z prawej strony w celu uzyskania gęstości pikseli i odległości wyświetlania dla wyświetlacza (system Windows 7 lub nowszy, konfigurowalny przez producenta OEM).
System Windows może automatycznie skalować zawartość do 250% na nowych urządzeniach, które przekraczają 280 ppi (od systemu Windows 8.1 S14).
System Windows ma sposób radzenia sobie ze skalowaniem w górę interfejsu użytkownika, aby korzystać ze zwiększonej liczby pikseli. Aplikacja decyduje się na ten system, deklarując się jako "systemową świadomość DPI". Aplikacje, które tego nie robią, są skalowane w górę przez system. Może to spowodować "rozmyte" środowisko użytkownika, w którym cała aplikacja jest równomiernie rozciągnięta w pikselach. Na przykład:
Program Visual Studio decyduje się na uwzględnianie skalowania DPI i dlatego nie jest "zwirtualizowany".
System Windows (i Program Visual Studio) korzystają z kilku technologii interfejsu użytkownika, które mają różne sposoby radzenia sobie z czynnikami skalowania ustawionymi przez system. Na przykład:
WPF mierzy kontrolki w sposób niezależny od urządzenia (jednostki, a nie piksele). Interfejs użytkownika WPF automatycznie skaluje się w górę dla bieżącego dpi.
Wszystkie rozmiary tekstu niezależnie od struktury interfejsu użytkownika są wyrażane w punktach, dlatego są traktowane przez system jako niezależne od dpi. Tekst w systemach Win32, WinForms i WPF jest już poprawnie skalowany w górę podczas rysowania na urządzeniu wyświetlania.
Okna dialogowe i okna Win32/WinForms umożliwiają włączenie układu, który zmienia rozmiar tekstu (na przykład za pośrednictwem paneli siatki, przepływu i układu tabeli). Umożliwiają one uniknięcie zakodowanych w kodzie lokalizacji pikseli, które nie są skalowane, gdy rozmiary czcionek zostaną zwiększone.
Ikony udostępniane przez system lub zasoby na podstawie metryk systemu (na przykład SM_CXICON i SM_CXSMICON) są już skalowane w górę.
Starsze interfejsy użytkownika Win32 (GDI, GDI+) i WinForms
Chociaż WPF jest już wysoko świadomy DPI, większość naszego kodu opartego na win32/GDI nie została pierwotnie napisana z myślą o rozpoznawaniu dpi. System Windows udostępnia interfejsy API skalowania DPI. Poprawki problemów z win32 powinny być używane spójnie w całym produkcie. Program Visual Studio udostępnił bibliotekę klas pomocnika, aby uniknąć duplikowania funkcji i zapewnienia spójności w całym produkcie.
Obrazy o wysokiej rozdzielczości
Ta sekcja dotyczy głównie deweloperów rozszerzających program Visual Studio 2013. W przypadku programu Visual Studio 2015 użyj usługi obrazów wbudowanej w program Visual Studio. Może się również okazać, że musisz obsługiwać/kierować do wielu wersji programu Visual Studio, dlatego korzystanie z usługi obrazów w 2015 r. nie jest opcją, ponieważ nie istnieje w poprzednich wersjach. Ta sekcja jest również dla Ciebie.
Skalowanie obrazów w górę, które są zbyt małe
Obrazy, które są zbyt małe, można skalować w górę i renderować na GDI i WPF przy użyciu niektórych typowych metod. Zarządzane klasy pomocnika DPI są dostępne dla wewnętrznych i zewnętrznych integratorów programu Visual Studio do obsługi ikon skalowania, map bitowych, elementów imagestrip i list obrazów. Natywne pomocniki języka C/C++oparte na win32 są dostępne do skalowania HICON, HBITMAP, HIMAGELIST i VsUI::GdiplusImage. Skalowanie mapy bitowej zwykle wymaga tylko zmiany jednowierszowej po włączeniu odwołania do biblioteki pomocnika. Na przykład:
Skalowanie listy obrazów zależy od tego, czy lista obrazów jest ukończona w czasie ładowania, czy jest dołączana w czasie wykonywania. W przypadku ukończenia w czasie ładowania wywołaj LogicalToDeviceUnits()
element z listą obrazów tak, jak w przypadku mapy bitowej. Gdy kod musi załadować pojedynczą mapę bitową przed utworzeniem listy obrazów, pamiętaj o skalowaniu rozmiaru obrazu listy obrazów:
imagelist.ImageSize = DpiHelper.LogicalToDeviceUnits(imagelist.ImageSize);
W kodzie natywnym wymiary można skalować podczas tworzenia listy obrazów w następujący sposób:
ImageList_Create(VsUI::DpiHelper::LogicalToDeviceUnitsX(16),VsUI::DpiHelper::LogicalToDeviceUnitsY(16), ILC_COLOR32|ILC_MASK, nCount, 1);
Funkcje w bibliotece umożliwiają określanie algorytmu zmiany rozmiaru. Podczas skalowania obrazów do umieszczenia na listach obrazów upewnij się, że określono kolor tła używany do przezroczystości lub użyj skalowania NearestNeighbor (co spowoduje zakłócenia przy 125% i 150%).
Zapoznaj się z dokumentacją w witrynie DpiHelper MSDN.
W poniższej tabeli przedstawiono przykłady skalowania obrazów przy odpowiednich współczynnikach skalowania DPI. Obrazy przedstawione w kolorze pomarańczowym oznaczają najlepsze rozwiązanie dla programu Visual Studio 2013 (100%-200% skalowania DPI):
Problemy z układem
Typowe problemy z układem można uniknąć przede wszystkim przez utrzymywanie punktów w interfejsie użytkownika skalowanych i względem siebie, a nie przy użyciu lokalizacji bezwzględnych (w szczególności w jednostkach pikseli). Na przykład:
Pozycje układu/tekstu muszą być dostosowywane do konta dla obrazów skalowanych w górę.
Kolumny w siatkach muszą mieć szerokości dostosowane do tekstu skalowanego w górę.
Zakodowane rozmiary lub spacje między elementami również muszą zostać przeskalowane w górę. Rozmiary oparte tylko na wymiarach tekstu są zwykle poprawne, ponieważ czcionki są automatycznie skalowane w górę.
Funkcje pomocnika są dostępne w DpiHelper klasie, aby umożliwić skalowanie na osi X i Y:
LogicalToDeviceUnitsX/LogicalToDeviceUnitsY (funkcje umożliwiają skalowanie na osi X/Y)
int space = DpiHelper.LogicalToDeviceUnitsX (10);
int height = VsUI::D piHelper::LogicalToDeviceUnitsY(5);
Istnieją przeciążenia LogicalToDeviceUnits umożliwiające skalowanie obiektów, takich jak Rect, Point i Size.
Skalowanie obrazów i układu za pomocą biblioteki DPIHelper/klasy
Biblioteka pomocnika DPI programu Visual Studio jest dostępna w formularzach natywnych i zarządzanych i może być używana poza powłoką programu Visual Studio przez inne aplikacje.
Aby użyć biblioteki, przejdź do przykładów rozszerzalności zestawu VSSDK programu Visual Studio i sklonuj przykład High-DPI_Images_Icons.
W plikach źródłowych uwzględnij element VsUIDpiHelper.h i wywołaj funkcje VsUI::DpiHelper
statyczne klasy:
#include "VsUIDpiHelper.h"
int cxScaled = VsUI::DpiHelper::LogicalToDeviceUnitsX(cx);
VsUI::DpiHelper::LogicalToDeviceUnits(&hBitmap);
Uwaga
Nie używaj funkcji pomocnika w zmiennych statycznych na poziomie modułu ani na poziomie klasy. Biblioteka używa również statycznych danych do synchronizacji wątków i może wystąpić problemy z inicjowaniem kolejności. Przekonwertuj te statyczne zmienne na niestatyczne zmienne członkowskie lub zawijają je do funkcji (więc są tworzone przy pierwszym dostępie).
Aby uzyskać dostęp do funkcji pomocnika DPI z poziomu kodu zarządzanego, który będzie uruchamiany w środowisku programu Visual Studio:
Projekt zużywany musi odwoływać się do najnowszej wersji programu Shell MPF. Na przykład:
<Reference Include="Microsoft.VisualStudio.Shell.14.0.dll" />
Upewnij się, że projekt zawiera odwołania do elementu System.Windows.Forms, PresentationCore i PresentationUI.
W kodzie użyj przestrzeni nazw Microsoft.VisualStudio.PlatformUI i wywołaj funkcje statyczne klasy DpiHelper. W przypadku obsługiwanych typów (punktów, rozmiarów, prostokątów itd.) dostępne są funkcje rozszerzenia, które zwracają nowe skalowane obiekty. Na przykład:
using Microsoft.VisualStudio.PlatformUI; double x = DpiHelper.LogicalToDeviceUnitsX(posX); Point ptScaled = ptOriginal.LogicalToDeviceUnits(); DpiHelper.LogicalToDeviceUnits(ref bitmap);
Obsługa rozmycia obrazu WPF w powiększalnym interfejsie użytkownika
W WPF mapy bitowe są zmieniane automatycznie przez WPF dla bieżącego poziomu powiększenia DPI przy użyciu wysokiej jakości algorytmu bicubic (wartość domyślna), który działa dobrze w przypadku obrazów lub dużych zrzutów ekranu, ale jest nieodpowiedni dla ikon elementów menu, ponieważ wprowadza postrzeganą rozmycie.
Rekomendacje:
W przypadku obrazu logo i grafiki banerów można użyć domyślnego BitmapScalingMode trybu zmiany rozmiaru.
W przypadku elementów menu i obrazów ikonografii element powinien być używany, BitmapScalingMode gdy nie powoduje innych artefaktów zniekształcenia w celu wyeliminowania rozmycia (przy 200% i 300%).
W przypadku dużych poziomów powiększenia nie wielokrotności 100% (na przykład 250% lub 350%), obrazy ikonografii skalowania z bicubicowymi wynikami w rozmytym interfejsie użytkownika. Lepszy wynik jest uzyskiwany przez pierwsze skalowanie obrazu przy użyciu metody NearestNeighbor do największej wielokrotności 100% (na przykład 200% lub 300%) i skalowanie z użyciem bicubic z tego miejsca. Zobacz Specjalny przypadek: wstępne skalowanie obrazów WPF na potrzeby dużych poziomów DPI, aby uzyskać więcej informacji.
Klasa DpiHelper w przestrzeni nazw Microsoft.VisualStudio.PlatformUI udostępnia element członkowski BitmapScalingMode , którego można użyć do powiązania. Dzięki niej powłoka programu Visual Studio będzie kontrolować tryb skalowania map bitowych w całym produkcie w jednolity sposób, w zależności od współczynnika skalowania DPI.
Aby użyć go w języku XAML, dodaj:
xmlns:vsui="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.14.0"
<Setter Property="RenderOptions.BitmapScalingMode" Value="{x:Static vs:DpiHelper.BitmapScalingMode}" />
Powłoka programu Visual Studio ustawia już tę właściwość w oknach i oknach dialogowych najwyższego poziomu. Interfejs użytkownika oparty na WPF uruchomiony w programie Visual Studio będzie już dziedziczyć. Jeśli ustawienie nie jest propagowane do określonych fragmentów interfejsu użytkownika, można go ustawić na głównym elemenie interfejsu użytkownika XAML/WPF. Miejsca, w których tak się dzieje, obejmują wyskakujące okienka, elementy z elementami nadrzędnymi Win32 i okna projektanta, które zabraknie procesu, takie jak Blend.
Niektóre interfejsy użytkownika mogą być skalowane niezależnie od poziomu powiększenia DPI zestawu systemu, takiego jak edytor tekstu programu Visual Studio i projektanci oparty na WPF (WPF Desktop i Windows Store). W takich przypadkach nie należy używać elementu DpiHelper.BitmapScalingMode. Aby rozwiązać ten problem w edytorze, zespół IDE utworzył właściwość niestandardową o nazwie RenderOptions.BitmapScalingMode. Ustaw wartość tej właściwości na HighQuality lub NearestNeighbor w zależności od połączonego poziomu powiększenia systemu i interfejsu użytkownika.
Przypadek specjalny: wstępne skalowanie obrazów WPF dla dużych poziomów DPI
W przypadku bardzo dużych poziomów powiększenia, które nie są wielokrotnościami 100% (na przykład 250%, 350%i tak dalej), skalowanie obrazów ikonografii z bicubicymi wynikami w rozmytym interfejsie użytkownika. Wrażenie tych obrazów obok ostrego tekstu jest prawie jak w przypadku iluzji optycznej. Obrazy wydają się być bliżej oka i poza fokusem w odniesieniu do tekstu. Wynik skalowania w tym powiększonym rozmiarze można poprawić, skalując najpierw obraz z wartościąNearestNeighbor do największej wielokrotności 100% (na przykład 200% lub 300%) i skalowania z bicubicem do reszty (dodatkowe 50%).
Poniżej przedstawiono przykład różnic w wynikach, w których pierwszy obraz jest skalowany przy użyciu ulepszonego algorytmu podwójnego skalowania 100%-200%->>250%, a drugi tylko z bicubic 100%->250%.
Aby umożliwić interfejsowi użytkownika korzystanie z tego podwójnego skalowania, należy zmodyfikować znaczniki XAML do wyświetlania każdego elementu Obrazu. W poniższych przykładach pokazano, jak używać podwójnego skalowania w WPF w programie Visual Studio przy użyciu biblioteki DpiHelper i shell.12/14.
Krok 1. Wstępne skalowanie obrazu do 200%, 300%i tak dalej przy użyciu metody NearestNeighbor.
Wstępne skalowanie obrazu przy użyciu konwertera zastosowanego do powiązania lub rozszerzenia znaczników XAML. Na przykład:
<vsui:DpiPrescaleImageSourceConverter x:Key="DpiPrescaleImageSourceConverter" />
<Image Source="{Binding Path=SelectedImage, Converter={StaticResource DpiPrescaleImageSourceConverter}}" Width="16" Height="16" />
<Image Source="{vsui:DpiPrescaledImage Images/Help.png}" Width="16" Height="16" />
Jeśli obraz również musi być motywowany (większość, jeśli nie wszystkie, powinna), znaczniki mogą użyć innego konwertera, który najpierw wykonuje je obrazu, a następnie skalowanie wstępne. Znaczniki mogą używać wartości DpiPrescaleThemedImageConverter lub DpiPrescaleThemedImageSourceConverter, w zależności od żądanych danych wyjściowych konwersji.
<vsui:DpiPrescaleThemedImageSourceConverter x:Key="DpiPrescaleThemedImageSourceConverter" />
<Image Width="16" Height="16">
<Image.Source>
<MultiBinding Converter="{StaticResource DpiPrescaleThemedImageSourceConverter}">
<Binding Path="Icon" />
<Binding Path="(vsui:ImageThemingUtilities.ImageBackgroundColor)"
RelativeSource="{RelativeSource Self}" />
<Binding Source="{x:Static vsui:Boxes.BooleanTrue}" />
</MultiBinding>
</Image.Source>
</Image>
Krok 2. Upewnij się, że ostateczny rozmiar jest poprawny dla bieżącego dpi.
Ponieważ WPF będzie skalować interfejs użytkownika dla bieżącego dpi przy użyciu właściwości BitmapScalingMode ustawionej na UIElement, kontrolka Obraz używająca wstępnie skalowanego obrazu, ponieważ jego źródło będzie wyglądać dwa lub trzy razy większe niż powinno. Poniżej przedstawiono kilka sposobów przeciwdziałania temu efektowi:
Jeśli znasz wymiar oryginalnego obrazu o wartości 100%, możesz określić dokładny rozmiar kontrolki Obraz. Te rozmiary odzwierciedlają rozmiar interfejsu użytkownika przed zastosowaniem skalowania.
<Image Source="{Binding Path=SelectedImage, Converter={StaticResource DpiPrescaleImageSourceConverter}}" Width="16" Height="16" />
Jeśli rozmiar oryginalnego obrazu nie jest znany, można użyć elementu LayoutTransform do skalowania w dół końcowego obiektu Obrazu. Na przykład:
<Image Source="{Binding Path=SelectedImage, Converter={StaticResource DpiPrescaleImageSourceConverter}}" > <Image.LayoutTransform> <ScaleTransform ScaleX="{x:Static vsui:DpiHelper.PreScaledImageLayoutTransformScale}" ScaleY="{x:Static vsui:DpiHelper.PreScaledImageLayoutTransformScale}" /> </Image.LayoutTransform> </Image>
Włączanie obsługi interfejsu HDPI w usłudze WebOC
Domyślnie kontrolki WebOC (takie jak kontrolka WebBrowser w WPF lub interfejsie IWebBrowser2) nie obsługują wykrywania i obsługi interfejsu HDPI. Wynikiem będzie osadzona kontrolka z zawartością wyświetlania, która jest zbyt mała na wyświetlaczu o wysokiej rozdzielczości. Poniżej opisano sposób włączania obsługi wysokiej rozdzielczości DPI w określonym wystąpieniu internetowego składnika WebOC.
Zaimplementuj interfejs IDocHostUIHandler (zobacz artykuł MSDN w programie IDocHostUIHandler:
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("BD3F23C0-D43E-11CF-893B-00AA00BDCE1A")]
public interface IDocHostUIHandler
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int ShowContextMenu(
[In, MarshalAs(UnmanagedType.U4)] int dwID,
[In] POINT pt,
[In, MarshalAs(UnmanagedType.Interface)] object pcmdtReserved,
[In, MarshalAs(UnmanagedType.IDispatch)] object pdispReserved);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int GetHostInfo([In, Out] DOCHOSTUIINFO info);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int ShowUI(
[In, MarshalAs(UnmanagedType.I4)] int dwID,
[In, MarshalAs(UnmanagedType.Interface)] object activeObject,
[In, MarshalAs(UnmanagedType.Interface)] object commandTarget,
[In, MarshalAs(UnmanagedType.Interface)] object frame,
[In, MarshalAs(UnmanagedType.Interface)] object doc);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int HideUI();
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int UpdateUI();
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int EnableModeless([In, MarshalAs(UnmanagedType.Bool)] bool fEnable);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int OnDocWindowActivate([In, MarshalAs(UnmanagedType.Bool)] bool fActivate);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int OnFrameWindowActivate([In, MarshalAs(UnmanagedType.Bool)] bool fActivate);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int ResizeBorder(
[In] COMRECT rect,
[In, MarshalAs(UnmanagedType.Interface)] object doc,
bool fFrameWindow);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int TranslateAccelerator(
[In] ref MSG msg,
[In] ref Guid group,
[In, MarshalAs(UnmanagedType.I4)] int nCmdID);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int GetOptionKeyPath(
[Out, MarshalAs(UnmanagedType.LPArray)] string[] pbstrKey,
[In, MarshalAs(UnmanagedType.U4)] int dw);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int GetDropTarget(
[In, MarshalAs(UnmanagedType.Interface)] IOleDropTarget pDropTarget,
[MarshalAs(UnmanagedType.Interface)] out IOleDropTarget ppDropTarget);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int GetExternal([MarshalAs(UnmanagedType.IDispatch)] out object ppDispatch);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int TranslateUrl(
[In, MarshalAs(UnmanagedType.U4)] int dwTranslate,
[In, MarshalAs(UnmanagedType.LPWStr)] string strURLIn,
[MarshalAs(UnmanagedType.LPWStr)] out string pstrURLOut);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int FilterDataObject(
IDataObject pDO,
out IDataObject ppDORet);
}
Opcjonalnie zaimplementuj interfejs ICustomDoc (zobacz artykuł MSDN w dokumentacji ICustomDoc:
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("3050F3F0-98B5-11CF-BB82-00AA00BDCE0B")]
public interface ICustomDoc
{
void SetUIHandler(IDocHostUIHandler pUIHandler);
}
Skojarz klasę, która implementuje program IDocHostUIHandler z dokumentem protokołu WebOC. Jeśli zaimplementowano powyższy interfejs ICustomDoc, gdy tylko właściwość dokumentu składnika WebOC jest prawidłowa, rzutuj ją na obiekt ICustomDoc i wywołaj metodę SetUIHandler, przekazując klasę implementjącą program IDocHostUIHandler.
// "this" references that class that owns the WebOC control and in this case also implements the IDocHostUIHandler interface
ICustomDoc customDoc = (ICustomDoc)webBrowser.Document;
customDoc.SetUIHandler(this);
Jeśli interfejs ICustomDoc nie został zaimplementowany, gdy tylko właściwość dokumentu składnika WebOC jest prawidłowa, musisz go rzutować do obiektu IOleObject i wywołać SetClientSite
metodę, przekazując klasę implementjącą metodę IDocHostUIHandler. Ustaw flagę DOCHOSTUIFLAG_DPI_AWARE na doCHOSTUIINFO przekazaną do wywołania GetHostInfo
metody:
public int GetHostInfo(DOCHOSTUIINFO info)
{
// This is what the default site provides.
info.dwFlags = (DOCHOSTUIFLAG)0x5a74012;
// Add the DPI flag to the defaults
info.dwFlags |=.DOCHOSTUIFLAG.DOCHOSTUIFLAG_DPI_AWARE;
return S_OK;
}
Powinno to być wszystko, co musisz uzyskać kontrolę webOC, aby obsługiwać HPDI.
Wskazówki
Jeśli właściwość dokumentu w kontrolce WebOC ulegnie zmianie, może być konieczne ponowne skojarzenie dokumentu z klasą IDocHostUIHandler.
Jeśli powyższe polecenie nie działa, występuje znany problem z brakiem funkcji WebOC podczas wybierania zmiany flagi DPI. Najbardziej niezawodnym sposobem naprawienia tego jest przełączenie optycznego powiększenia webOC, co oznacza dwa wywołania z dwoma różnymi wartościami procentu powiększenia. Ponadto jeśli to obejście jest wymagane, może być konieczne wykonanie go przy każdym wywołaniu nawigacji.
// browser2 is a SHDocVw.IWebBrowser2 in this case // EX: Call the Exec twice with DPI%-1 and then DPI% as the zoomPercent values IOleCommandTarget cmdTarget = browser2.Document as IOleCommandTarget; if (cmdTarget != null) { object commandInput = zoomPercent; cmdTarget.Exec(IntPtr.Zero, OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, ref commandInput, ref commandOutput); }