Gewusst wie: TrueType Glyph Umrisse zeichnen

SPRACHE AUSWÄHLEN SPRACHE AUSWÄHLEN
Artikel-ID: 243285 - Produkte anzeigen, auf die sich dieser Artikel bezieht
Alles erweitern | Alles schließen

Zusammenfassung

Die Win32-API- GetGlyphOutline -Funktion kann einheitlichen Symbols Gliedern von Daten aus einer TrueType-Schriftart zurückgeben. Um eine Gliederung TrueType-Symbol zu zeichnen, müssen die Daten aus der systemeigenen B-Spline-Definition einer Sequenz von Bézier-Zeilendefinitionen konvertiert werden. Dann kann PolyBezier Win32 API-Funktion verwendet werden, um die Gliederung zu zeichnen.

Weitere Informationen

Die Funktion GetGlyphOutline in Win32 Application Programming Interface(API) kann eine Gliederung TrueType abrufen. Die GGO_NATIVE-Formatoption füllt einen Puffer mit quadratische B-Spline-Kurven für eine TrueType-Gliederung. Quadratische B-Splines werden von TrueType-verwendet, um die Glyph-Gliederung in eine TrueType-Schriftartdatei beschreiben. Zum Zeichnen dieser Kurven Gliederung kann eine implementieren eine Zeichnung B-Spline-Funktion oder die Funktion PolyBezier aus der Win32-API verwenden.

Quadratische B-Spline-Kurven sind eine Klasse von Parametrische Kurven, die den Pfad der mehrere Kurvensegmente über wenige Kontrollpunkte definieren. Eine quadratische Kurve ist eine zweite Reihenfolge Parametrische Kurve. Keine Funktion in der API direkt Zeichnen eines Splines quadratische vorhanden ist wenn die quadratisch konvertiert wird, um eine Kubikmeter gezeichnet werden kann, mit der Win32-API für das Zeichnen einer Bézier-Kurve Funktion sondern PolyBezier aufgerufen.

Quadratische B-Spline-Kurven in bestimmten und Parametrische Kurven sind im Allgemeinen ein well-researched Thema von Grafiken in Informatik. Sie können auch recht komplex werden. Algorithmen wurden in verschiedenen Texte veröffentlicht, um eine Funktion zum Zeichnen eines Splines quadratische implementieren verwendet werden können, aber Beschreibung solcher Algorithmus würde den Rahmen dieses Artikels sprengen.

Die PolyBezier -Funktion können Sie eine quadratische Spline ist eine Bézierkurve eine kubische oder dritten Reihenfolge Parametrische Kurve zeichnen. Da eine quadratische Spline eine zweite Reihenfolge Formel ist, kann es hinsichtlich der die höhere Reihenfolge kubische Gleichung ausgedrückt werden. Obwohl eine Formel für eine Quadratic als einen Kubikmeter Ausdrücken im Beispielcode angegeben ist, ist die Ableitung in in diesem Artikel nicht behandelt.

Der Beispielcode in diesem Artikel ist eine Demonstration zum Analysieren von eines GGO_NATIVE Glyph-Puffers von der GetGlyphOutline -Funktion zurückgegeben wird. Durch das GGO_NATIVE-Format-Flag zurückgegebenen Puffers entspricht der Struktur TTPOLYGONHEADER . Die Struktur TTPOLYGONHEADER und die Daten, die folgt unmittelbar bilden eine Kontur eines Symbols TrueType. Eine Kontur ist eine vollständige Pfad der Kurven, die implizit geschlossen wird, wenn auf diese Weise nicht explizit zurückgegeben wird.

Finden Sie im Platform SDK-Dokumentation auf die TTPOLYGONHEADER und TTPOLYCURVE Strukturen.

Eine Kontur Symbol besteht aus mehreren Kurvensegmente durch TTPOLYCURVE Strukturen dargestellt. In eine Kontur TTPOLYGONHEADER eine oder mehrere TTPOLYCURVE Strukturen und Koordinatenpunkt Daten folgt. Der PfxStart -Member gibt den Koordinaten Ausgangspunkt der Kontur. Die Anzahl der Kurve Datensätze, die die TTPOLYGONHEADER wird durch den Cb -Member angegeben. Der Ausgangspunkt ist relativ zum Ursprung des Symbols für das. Ein Symbol stammt aus der unteren linken Ecke des Zeichens an das Zeichen Basisplan.

Jeder TTPOLYCURVE Kurve Datensatz (ein Kurvensegment) besteht aus entweder quadratische B-Spline-Kontrollpunkte oder einfache Polyline Punkte. Die Anzahl der Punkte wird durch das TTPOLYCURVE - Cpfx -Element angegeben. Die Kurve Art der entweder Spline oder Polylinie wird durch das wType -Element angegeben. Das Array der Koordinatenpunkte sofort die Struktur folgen. Der Anfangspunkt der Kurve wird durch das Apfx -Element angegeben.

Da ein Symbol auf mehr als eine Kontur enthalten kann, enthält der Puffer eine oder mehrere Gruppen von TTPOLYGONHEADER Strukturen und Daten. Nachfolgende Profile werden unmittelbar nach der vorherigen Aufgabe im systemeigenen Puffer gepackt. Nächste Kontur beginnt mit einer TTPOLYGONHEADER an das nächste Byte hinter der letzte Punkt des vorherigen Datensatzes Kurve.

Dieser Beispielcode zeichnet den Umriss eines TrueType-Symbols durch Analysieren des GGO_NATIVE-Puffers eine Liste von Bézier-Liniensegmente erstellen, die jeder Oberfläche bilden. Die Liste der Bézier-Liniensegmente wird dann unter Verwendung der PolyBezier gezeichnet. Der Code, der den Puffer analysiert ist in der DrawT2Outline -Funktion.

Erste Schritt erstellen eine Liste von Bézier-Zeilen besteht darin, die Größe des Puffers für die Liste zu bestimmen. Vier Punkte definiert Bézier-Zeilen. Die Funktion PolyBezier interpretiert ein Array von Punkten als eine kontinuierliche Zeile Bézier-Segmenten, in denen der Anfang der nächsten Zeile miteinander, mit dem Endpunkt der vorherigen Zeile ist. Daher sind nur drei Punkte erforderlich, um eine zusätzliche Bézier-Liniensegment beschreiben.

Der GGO_NATIVE-Puffer kann entweder eine Kurve Polylinie oder eine quadratische B-Spline-Kurve enthalten. Zwei Punkten definieren ein Liniensegment während drei Punkte ein B-Spline definieren. Da jeder Typ ist mit einer PolyBezier mit Bézier-Zeile gezeichnet werden, tritt ein, der schlimmsten Fall, wenn eine Oberfläche, die vollständig von Liniensegmenten zusammengesetzt ist, mehrere Beziers erweitert.

Beachten Sie, dass um eine zusätzliche Kurve auszudrücken Segment in einer B-Spline-Kurve Darstellung nur ein zusätzlicher Punkt erfordert. Diesen Punkt explizit definiert "B" oder deaktiviert Kurve zeigen und definiert implizit Kurve zeigen Sie auf der zusätzlichen. Der auf Kurve Punkt befindet sich der Mittelpunkt auf den nächsten "B". Daher wird eine zusätzliche Liniensegment oder ein zusätzliches Kurvensegment auf drei weitere Punkte einer Bézierkurve Zeile erweitern.

Im Code wird davon ausgegangen, dass der gesamte systemeigene Puffer POINTFX Strukturen bestehen wird damit es die größtmögliche Anzahl von Punkten dargestellt durch den Puffer bestimmen kann. Die tatsächliche Anzahl ist etwas kleiner, da Struktur Aufwand die Profile und Kurven beschreiben. Die Größe des Puffers für die Bézier-Liste wird durch die maximal mögliche Anzahl der Punkte multipliziert die Datengröße des POINT -Struktur und drei multipliziert angegeben. Drei ist die Anzahl der zusätzliche Punkte, die für jede zusätzliche Zeile Segment oder quadratische Spline-Segments beim Konvertieren in einen Bézier erforderlich sind.

Nach Bézier-Puffer reserviert wurde analysiert der Code den systemeigenen Puffer durch starten am ersten TTPOLYGONHEADER . Der Code während einer Iteration der Schleife verarbeitet eine Kontur und zeichnet es. Eine zweite innere Schleife analysiert jeden Typ Kurve.

Im Fall von einer Kurve Polylinie (TT_PRIM_LINE) jedes Liniensegment der Polylinie konvertiert und an die Liste der Beziers mit der Funktion AppendPolyLineToBezier angefügt. Wenn die Kurve eine quadratische B-Spline (TT_PRIM_QSPLINE) ist, wird die AppendQuadBSplineToBezier -Funktion konvertiert und fügt quadratische B-Spline. Jede dieser Funktionen verwendet eine Schleife um jedes Segment der Kurve in seine unabhängige Kontrollpunkte zu analysieren. Der Zeile oder Spline wird in einer Bézierkurve konvertiert und an die Liste der Beziers angefügt.

Eine Bézier Linie kann problemlos zu eine gerade Linie zeichnen. Die Start- und Enddatum Vektoren zeigen einfach am entgegengesetzten Ende das Liniensegment. Dies erfolgt in der MakeBezierFromLine -Funktion.

Quadratische Splines in eine kubische Bezier-Spline konvertieren erfordert Ausdrücken der Kubikmeter Kontrollpunkte hinsichtlich der Kontrollpunkte des Quadratic. Die Formel übersetzt die Kontrollpunkte befindet sich in der MakeBezierFromQBSpline -Funktion.

Vor dem Zeichnen der Kontur, wird der Code sichergestellt, dass der Pfad geschlossen ist, durch den Aufruf der CloseContour -Funktion. Die Funktion wird aufgerufen, nur dann, wenn die Anfangs- und Endpunkt der Sequenz von Beziers nicht miteinander stehen. Anschließend wird die Funktion PolyBezier aufgerufen.

Nach der Kontur gezeichnet wird, ist die nächste Kontur TTPOLYGONHEADER durch Verschieben des Zeigers LpHeader hinter dem Ende der Datensätze in das aktuelle Profil gefunden. Wenn diese einen Zeigerwert hinter dem Ende der systemeigenen Puffer führt, hat der Code aller Profile und beendet verarbeitet.
/****************************************************************************
 *  FUNCTION   : IntFromFixed
 *  RETURNS    : int value approximating the FIXED value.
 ****************************************************************************/ 
int PASCAL NEAR IntFromFixed(FIXED f)
{
    if (f.fract >= 0x8000)
    return(f.value + 1);
    else
    return(f.value);
}

/****************************************************************************
 *  FUNCTION   : fxDiv2
 *  RETURNS    : (val1 + val2)/2 for FIXED values
 ****************************************************************************/ 
FIXED PASCAL NEAR fxDiv2(FIXED fxVal1, FIXED fxVal2)
{
    long l;

    l = (*((long far *)&(fxVal1)) + *((long far *)&(fxVal2)))/2;
    return(*(FIXED *)&l);
}

/****************************************************************************
 *  FUNCTION   : MakeBezierFromLine
 *
 *  PURPOSE    : Converts a line define by two points to a four point Bezier
 *               spline representation of the line in pPts.
 *
 *
 *  RETURNS    : number of Bezier points placed into the pPts POINT array.
 ****************************************************************************/ 
UINT MakeBezierFromLine( POINT *pPts, POINT startpt, POINT endpt )
{
    UINT cTotal = 0;

    // starting point of Bezier
    pPts[cTotal] = startpt;
    cTotal++;

    // 1rst Control, pt == endpoint makes Bezier a line
    pPts[cTotal].x = endpt.x;
    pPts[cTotal].y = endpt.y;
    cTotal++;

    // 2nd Control, pt == startpoint makes Bezier a line
    pPts[cTotal].x = startpt.x;
    pPts[cTotal].y = startpt.y;
    cTotal++;

    // ending point of Bezier
    pPts[cTotal] = endpt;
    cTotal++;
    
    return cTotal;
}

/****************************************************************************
 *  FUNCTION   : MakeBezierFromQBSpline
 *
 *  PURPOSE    : Converts a quadratic spline in pSline to a four point Bezier
 *               spline in pPts.
 *
 *
 *  RETURNS    : number of Bezier points placed into the pPts POINT array.
 ****************************************************************************/ 
UINT MakeBezierFromQBSpline( POINT *pPts, POINTFX *pSpline )
{
    POINT   P0,         // Quadratic on curve start point
            P1,         // Quadratic control point
            P2;         // Quadratic on curve end point
    UINT    cTotal = 0;

    // Convert the Quadratic points to integer
    P0.x = IntFromFixed( pSpline[0].x );
    P0.y = IntFromFixed( pSpline[0].y );
    P1.x = IntFromFixed( pSpline[1].x );
    P1.y = IntFromFixed( pSpline[1].y );
    P2.x = IntFromFixed( pSpline[2].x );
    P2.y = IntFromFixed( pSpline[2].y );

    // conversion of a quadratic to a cubic

    // Cubic P0 is the on curve start point
    pPts[cTotal] = P0;
    cTotal++;
    
    // Cubic P1 in terms of Quadratic P0 and P1
    pPts[cTotal].x = P0.x + 2*(P1.x - P0.x)/3;
    pPts[cTotal].y = P0.y + 2*(P1.y - P0.y)/3;
    cTotal++;

    // Cubic P2 in terms of Qudartic P1 and P2
    pPts[cTotal].x = P1.x + 1*(P2.x - P1.x)/3;
    pPts[cTotal].y = P1.y + 1*(P2.y - P1.y)/3;
    cTotal++;

    // Cubic P3 is the on curve end point
    pPts[cTotal] = P2;
    cTotal++;

    return cTotal;
}


/****************************************************************************
 *  FUNCTION   : AppendPolyLineToBezier
 *
 *  PURPOSE    : Converts line segments into their Bezier point 
 *               representation and appends them to a list of Bezier points. 
 *
 *               WARNING - The array must have at least one valid
 *               start point prior to the address of the element passed.
 *
 *  RETURNS    : number of Bezier points added to the POINT array.
 ****************************************************************************/ 
UINT AppendPolyLineToBezier( LPPOINT pt, POINTFX start, LPTTPOLYCURVE lpCurve )
{
    int     i;
    UINT    cTotal = 0;
    POINT   endpt;
    POINT   startpt;
    POINT   bezier[4];

    endpt.x = IntFromFixed(start.x);
    endpt.y = IntFromFixed(start.y);

    for (i = 0; i < lpCurve->cpfx; i++)
    {
        // define the line segment
        startpt = endpt;
        endpt.x = IntFromFixed(lpCurve->apfx[i].x);
        endpt.y = IntFromFixed(lpCurve->apfx[i].y);

        // convert a line to a bezier representation
        MakeBezierFromLine( bezier, startpt, endpt );

        // append the Bezier to the existing ones
                                    // Point 0 is Point 3 of previous.
        pt[cTotal++] = bezier[1];   // Point 1
        pt[cTotal++] = bezier[2];   // Point 2
        pt[cTotal++] = bezier[3];   // Point 3

    }

    return cTotal;
}


/****************************************************************************
 *  FUNCTION   : AppendQuadBSplineToBezier
 *
 *  PURPOSE    : Converts Quadratic spline segments into their Bezier point 
 *               representation and appends them to a list of Bezier points. 
 *
 *               WARNING - The array must have at least one valid
 *               start point prior to the address of the element passed.
 *
 *  RETURNS    : number of Bezier points added to the POINT array.
 ****************************************************************************/ 
UINT AppendQuadBSplineToBezier( LPPOINT pt, POINTFX start, LPTTPOLYCURVE lpCurve )
{
    WORD                i;
    UINT                cTotal = 0;
    POINTFX             spline[3];  // a Quadratic is defined by 3 points
    POINT               bezier[4];  // a Cubic by 4

    // The initial A point is on the curve.
    spline[0] = start;

    for (i = 0; i < lpCurve->cpfx;)
    {
        // The B point.
        spline[1] = lpCurve->apfx[i++];

        // Calculate the C point.
        if (i == (lpCurve->cpfx - 1))
        {
            // The last C point is described explicitly
            // i.e. it is on the curve.
            spline[2] = lpCurve->apfx[i++];
        }     
        else
        {
            // C is midpoint between B and next B point
            // because that is the on curve point of 
            // a Quadratic B-Spline.
            spline[2].x = fxDiv2(
                lpCurve->apfx[i-1].x,
                lpCurve->apfx[i].x
                );
            spline[2].y = fxDiv2(
                lpCurve->apfx[i-1].y,
                lpCurve->apfx[i].y
                );
        }

        // convert the Q Spline to a Bezier
        MakeBezierFromQBSpline( bezier, spline );
        
        // append the Bezier to the existing ones
                                    // Point 0 is Point 3 of previous.
        pt[cTotal++] = bezier[1];   // Point 1
        pt[cTotal++] = bezier[2];   // Point 2
        pt[cTotal++] = bezier[3];   // Point 3

        // New A point for next slice of spline is the 
        // on curve C point of this B-Spline
        spline[0] = spline[2];
    }

    return cTotal;
}

/****************************************************************************
 *  FUNCTION   : CloseContour
 *
 *  PURPOSE    : Adds a bezier line to close the circuit defined in pt.
 *
 *
 *  RETURNS    : number of points aded to the pt POINT array.
 ****************************************************************************/ 
UINT CloseContour( LPPOINT pt, UINT cTotal )
{
    POINT               endpt, 
                        startpt;    // definition of a line
    POINT               bezier[4];

    // connect the first and last points by a line segment
    startpt = pt[cTotal-1];
    endpt = pt[0];

    // convert a line to a bezier representation
    MakeBezierFromLine( bezier, startpt, endpt );

    // append the Bezier to the existing ones
                                // Point 0 is Point 3 of previous.
    pt[cTotal++] = bezier[1];   // Point 1
    pt[cTotal++] = bezier[2];   // Point 2
    pt[cTotal++] = bezier[3];   // Point 3

    return 3;
}

/****************************************************************************
 *  FUNCTION   : DrawT2Outline
 *
 *  PURPOSE    : Decode the GGO_NATIVE outline, create a sequence of Beziers
 *               for each contour, draw with PolyBezier.  Color and relative 
 *               positioning provided by caller. The coordinates of hDC are
 *               assumed to have MM_TEXT orientation.
 *
 *               The outline data is not scaled. To draw a glyph unhinted
 *               the caller should create the font at its EMSquare size
 *               and retrieve the outline data. Then setup a mapping mode
 *               prior to calling this function.
 *
 *  RETURNS    : none.
 ****************************************************************************/ 
void DrawT2Outline(HDC hDC, LPTTPOLYGONHEADER lpHeader, DWORD size) 
{
    WORD                i;
    UINT                cTotal = 0; // Total points in a contour.
    LPTTPOLYGONHEADER   lpStart;    // the start of the buffer
    LPTTPOLYCURVE       lpCurve;    // the current curve of a contour
    LPPOINT             pt;         // the bezier buffer
    POINTFX             ptStart;    // The starting point of a curve
    DWORD               dwMaxPts = size/size of(POINTFX); // max possible pts.
    DWORD               dwBuffSize;

    dwBuffSize = dwMaxPts *     // Maximum possible # of contour points.
                 sizeof(POINT) * // sizeof buffer element
                 3;             // Worst case multiplier of one additional point
                                // of line expanding to three points of a bezier

   lpStart = lpHeader;
   pt = (LPPOINT)malloc( dwBuffSize );

    // Loop until we have processed the entire buffer of contours.
    // The buffer may contain one or more contours that begin with
    // a TTPOLYGONHEADER. We have them all when we the end of the buffer.
    while ((DWORD)lpHeader < (DWORD)(((LPSTR)lpStart) + size) && pt != NULL)
    {
        if (lpHeader->dwType == TT_POLYGON_TYPE)
        // Draw each coutour, currently this is the only valid
        // type of contour.
        {
            // Convert the starting point. It is an on curve point.
            // All other points are continuous from the "last" 
            // point of the contour. Thus the start point the next
            // bezier is always pt[cTotal-1] - the last point of the 
            // previous bezier. See PolyBezier.
            cTotal = 1;
            pt[0].x = IntFromFixed(lpHeader->pfxStart.x);
            pt[0].y = IntFromFixed(lpHeader->pfxStart.y);

            // Get to first curve of contour - 
            // it starts at the next byte beyond header
            lpCurve = (LPTTPOLYCURVE) (lpHeader + 1);

            // Walk this contour and process each curve( or line ) segment 
            // and add it to the Beziers
            while ((DWORD)lpCurve < (DWORD)(((LPSTR)lpHeader) + lpHeader->cb))
            {
                //**********************************************
                // Format assumption:
                //   The bytes immediately preceding a POLYCURVE
                //   structure contain a valid POINTFX.
                // 
                //   If this is first curve, this points to the 
                //      pfxStart of the POLYGONHEADER.
                //   Otherwise, this points to the last point of
                //      the previous POLYCURVE.
                // 
                //   In either case, this is representative of the
                //      previous curve's last point.
                //**********************************************

                ptStart = *(LPPOINTFX)((LPSTR)lpCurve - sizeof(POINTFX));
                if (lpCurve->wType == TT_PRIM_LINE)
                {
                    // convert the line segments to Bezier segments
                    cTotal += AppendPolyLineToBezier( &pt[cTotal], ptStart, lpCurve );
                    i = lpCurve->cpfx;
                }
                else if (lpCurve->wType == TT_PRIM_QSPLINE)
                {
                    // Decode each Quadratic B-Spline segment, convert to bezier,
                    // and append to the Bezier segments
                    cTotal += AppendQuadBSplineToBezier( &pt[cTotal], ptStart, lpCurve );
                    i = lpCurve->cpfx;
                }
                else
                    // Oops! A POLYCURVE format we don't understand.
                    ; // error, error, error

            // Move on to next curve in the contour.
            lpCurve = (LPTTPOLYCURVE)&(lpCurve->apfx[i]);
            }

            // Add points to close the contour.
            // All contours are implied closed by TrueType definition.
            // Depending on the specific font and glyph being used, these
            // may not always be needed.
            if ( pt[cTotal-1].x != pt[0].x || pt[cTotal-1].y != pt[0].y )
            {
                cTotal += CloseContour( pt, cTotal );
            }

            // flip coordinates to get glyph right side up (Windows coordinates)
            // TT native coordiantes are zero originate at lower-left.
            // Windows MM_TEXT are zero originate at upper-left.
            for (i = 0; i < cTotal; i++)
                pt[i].y = 0 - pt[i].y;

            // Draw the contour
            PolyBezier( hDC, pt, cTotal );
        }
        else
            // Bad, bail, must have a bogus buffer.
            break; // error, error, error

        // Move on to next Contour.
        // Its header starts immediate after this contour
        lpHeader = (LPTTPOLYGONHEADER)(((LPSTR)lpHeader) + lpHeader->cb);
    }

    free( pt );
}
				

Informationsquellen

Weitere Informationen über die TrueType-Spezifikation finden Sie unter:
Microsoft TrueType Specifications (http://www.microsoft.com/typography/tt/tt.htm)

Steht unter Spezifikationen auf der Microsoft Developer Network Library CD zur Verfügung.

Eigenschaften

Artikel-ID: 243285 - Geändert am: Montag, 12. Februar 2007 - Version: 1.5
Die Informationen in diesem Artikel beziehen sich auf:
  • Microsoft Win32 Application Programming Interface
  • Microsoft Windows XP Professional
  • the operating system: Microsoft Windows XP 64-Bit Edition
Keywords: 
kbmt kbdswgdi2003swept kbdraw kbfont kbgdi kbhowto KB243285 KbMtde
Maschinell übersetzter Artikel
Wichtig: Dieser Artikel wurde maschinell und nicht von einem Menschen übersetzt. Die Microsoft Knowledge Base ist sehr umfangreich und ihre Inhalte werden ständig ergänzt beziehungsweise überarbeitet. Um Ihnen dennoch alle Inhalte auf Deutsch anbieten zu können, werden viele Artikel nicht von Menschen, sondern von Übersetzungsprogrammen übersetzt, die kontinuierlich optimiert werden. Doch noch sind maschinell übersetzte Texte in der Regel nicht perfekt, insbesondere hinsichtlich Grammatik und des Einsatzes von Fremdwörtern sowie Fachbegriffen. Microsoft übernimmt keine Gewähr für die sprachliche Qualität oder die technische Richtigkeit der Übersetzungen und ist nicht für Probleme haftbar, die direkt oder indirekt durch Übersetzungsfehler oder die Verwendung der übersetzten Inhalte durch Kunden entstehen könnten.
Den englischen Originalartikel können Sie über folgenden Link abrufen: 243285
Microsoft stellt Ihnen die in der Knowledge Base angebotenen Artikel und Informationen als Service-Leistung zur Verfügung. Microsoft übernimmt keinerlei Gewährleistung dafür, dass die angebotenen Artikel und Informationen auch in Ihrer Einsatzumgebung die erwünschten Ergebnisse erzielen. Die Entscheidung darüber, ob und in welcher Form Sie die angebotenen Artikel und Informationen nutzen, liegt daher allein bei Ihnen. Mit Ausnahme der gesetzlichen Haftung für Vorsatz ist jede Haftung von Microsoft im Zusammenhang mit Ihrer Nutzung dieser Artikel oder Informationen ausgeschlossen.

Ihr Feedback an uns

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com