Welcome to NetFxFactory Sign in | Join | Help

articles

  • Création d'une liste personnalisée SharePoint 2007

    Introduction

    SharePoint 2007 est une révolution dans le monde SharePoint. En effet, il apporte un lot considérable de nouveautés dans le développement. L’architecture a été revue entièrement, elle est basé sur ASP.NET 2.0 et offre même la possibilité d’utiliser AJAX avec le SP1 de SharePoint. SharePoint est devenue à la fois un portail web avec ses template de site, une plateforme de développement avec son framework, et une solution serveur d’entreprise avec son server de recherche et d’indexation ou encore avec Excel Services. Beaucoup d’articles sur internet parlent de la création de WebPart dans SharePoint, mais il n’y a pas que les WebParts dans cette énorme plateforme de développement. Dans cette article nous allons voir comment faire une liste personnalisée qui affiche des vidéos de Youtube et quelles sont les avantages par rapport a la création d’une webpart qui aurait fait la même chose. Avec le temps je me suis rendu compte qu’il fallait rester au plus prés de sharepoint pour pouvoir offrir aux nouvelles fonctionnalités toute la puissance de sharepoint en terme de recherche, de trie ou de filtre.

    Les outils de développements

    Pour développer avec SharePoint, il vous faut Visual studio 2008 ou Visual studio 2005 avec les VseWSS (WSS Visual studio extension). C’est la version Visual Studio 2005 qu’on utilisera. Ces extensions sont téléchargeables sur le site de Microsoft.com. Une fois que vous avez installé les extensions, plusieurs nouveaux types de projets apparaissent dans Visual studio 2005. La copie d’écran a été faite avec les extensions WSS (Windows SharePoint Services) et MOSS (Microsoft Office SharePoint Server).

    Les types de projets sont :

    Type de projet

    Description

    Team Site Definition

    Création d’un modèle de site de collaboration

    Blank Site Definition

    Création d’un modèle de site Vide

    List Definition

    Définition d’une liste sharepoint personnalisé

    WebPart

    Création d’une webpart

    Empty

    Projet vide

    Sharepoint Server Sequential Workflow

    Création d’un workflow séquentiel

    Sharepoint Server State Machine

    Création d’un workflow machine à état

    Les avantages de l’utilisation des extensions pour Visual Studio sont le débogage et le déploiement qui se font en appuyant sur la touche F5. Prenons un exemple, la création d’un site de collaboration. Je créé un projet de type Team Site Definition que je nomme MyTeamSite :

    On peut regarder ce qui se trouve dans l’explorateur de solution :

    Nous avons la définition du site avec onet.xml, la page d’accueil default et le Provisioning Handler qui gère les événements d’activation et de remplissage du site. Je vais dans le code SiteProvisioning.cs et sur la gestion de l’événement OnActivated je mets du code :

    public void OnActivated(SPFeatureReceiverProperties properties)
    {
    SPWeb web = (SPWeb)properties.Feature.Parent;
    if (web == null)
    throw new Exception("Ne peut récupérer le site web parent");
    web.TreeViewEnabled = true;
    web.Update();
    }

    Avant les extensions, il fallait compiler et déployer à la main, maintenant il suffit d’appuyer sur la touche magique F5. Lorsqu’on appuit dessus Visual Studio compile, package et déploit la feature. Si l’on regarde d’ailleurs dans l’explorateur Windows ce qui a été créé voici ce que l’on obtient :

    Nous avons un setup.bat qui installera ou désinstallera la feature, nous avons aussi un WSP qui est le package créé par visual studio et un dossier solution qui contient les informations sur la features, fichier XML de déploiement etc…

    Ensuite il lance internet explorer sur le site racine de SharePoint.

    On créé un site SharePoint du type MyTeamSite :

    Lorsqu’on clique sur Create le site passe en Provisioning et entre donc dans l’événement OnActivated ce qui nous permet de déboguer notre feature comme si on déboguer un site web.

    Si l’on regarde notre site on a bien le treeview qui est activé comme on lui a demandé :

    La Custom list

    Mais revenons a ce qui nous intéresse, la custom list. Pour cela on va créer une Custom list qu’on appellera youtubeList :

    Le template de site demande quelle liste doit être considérée comme liste de base, dans notre exemple on choisira CustomList et on demandera à Visual studio de créer une instance de cette liste :

    Visual studio créer automatiquement les fichiers nécessaire a la création de la liste :

    On reconnait les pages de la liste (AllItems.aspx), d’affichage d’un item (DispForm.aspx) d’édition d’un item (EditForm.aspx) et d’ajout d’un item (NewForm.aspx)

    La liste est une collection de content type, on va donc ajouter un type de contenu a notre projet. Clique avec le bouton droit de la souris sur le projet Add/ New item

    On ajout un ContentType nommé YoutubeItem. Il demande quel est le type de base de l’item. On Choisira item dans la liste :

    Si on regarde dans l’explorateur de solution l’item n’apparait pas. En fait il faut afficher tous les fichiers et aller dans pkg, la le content type apparait :

    On va commencer par le content type

    Content Type

    Pour paramétrer le content type on va aller dans elementManifest.xml. Dans le nœud FieldRefs on va ajouter les 3 propriétés que l’on veut en plus de notre content type Item. Item contenant déjà Title on ne va pas le renseigner, comme il s’agit d’un héritage youtubeitem contiendra par défaut une propriété Title.

    Voici donc le code :

    <?xml version="1.0" encoding="utf-8"?> 
    <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> 
    <ContentType Name="YoutubeItem" ID="0x010086ac23fd903c468faf40fdc673a0a2fa" Group="Development" Version="0"> 
    <FieldRefs> 
    <FieldRef Name="Description" ID="{8F51D2FB-1F5B-4c09-96EE-FD53A6805CFD}"/> 
    <FieldRef Name="MovieID" ID="{3DA59372-F977-477c-B4FC-7DF2BF673295}"/> 
    <FieldRef Name="Preview" ID="{0BDE7F01-B6EC-49fd-8890-F5E7050DFFA0}" 
    ShowInDisplayForm="TRUE" 
    ShowInFileDlg="FALSE" 
    ShowInEditForm="FALSE" 
    ShowInNewForm="FALSE"/> 
    </FieldRefs> 
    </ContentType> 
    </Elements>

    On spécifie que pour l’on veut la prévisualisation que dans l’affichage de l’élément.

    Maintenant que notre content type est fait on peut aller dans la définition de la liste

    La définition de la liste

    On ouvre schema.xml. La première chose à faire et de lier le content type a la liste. Voici la définition de mon content type dans elementManifest.xml :

    <ContentType Name="YoutubeItem" ID="0x010086ac23fd903c468faf40fdc673a0a2fa" Group="Development" Version="0"> 

    Je change l’ID et le nom du content type dans la définition de ma liste :

    <ContentTypes> 
    <ContentTypeRef ID="0x010086ac23fd903c468faf40fdc673a0a2fa"> 
    <Folder TargetName="Youtube Item"/> 
    </ContentTypeRef> 
    <ContentTypeRef ID="0x0120"/> 
    </ContentTypes>

    Maintenant je spécifie les champs de ma liste qui doivent correspondre aux champs définis dans mon content type :

    <Fields> 
    <Field Name="Description" ID="{8F51D2FB-1F5B-4c09-96EE-FD53A6805CFD}" DisplayName="Description" Required="TRUE" Type="Note" ShowInNewForm="TRUE"/> 
    <Field Name="MovieID" ID="{3DA59372-F977-477c-B4FC-7DF2BF673295}" DisplayName="MovieID" Required ="TRUE" Type="Text" ShowInNewForm="TRUE"/> 
    <Field Name="Preview" ID="{0BDE7F01-B6EC-49fd-8890-F5E7050DFFA0}" DisplayName="Previsualisation" Type="Computed" ShowInNewForm="FALSE"> 
    <FieldRefs> 
    <FieldRef Name=" MovieID"/> 
    </FieldRefs> 
    <DisplayPattern> 
    <HTML><![CDATA[<object width="425" height="355"><param name="movie" value="http://www.youtube.com/v/]]></HTML> 
    <Column Name=" MovieID"/> 
    <HTML> 
    <![CDATA[&rel=1"> 
    </param> 
    <param name="wmode" value="transparent"></param> 
    <embed src="http://www.youtube.com/v/]]> 
    </HTML> 
    <Column Name=" MovieID"/> 
    <HTML> 
    <![CDATA[&rel=1" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"> 
    </embed></object>]]> 
    </HTML> 
    </DisplayPattern> 
    </Field> 
    </Fields>

    Attention les ID des champs doivent être les mêmes que les id définis dans le ContentType. Remarque le champ preview, ce champ est de type computed, en fait il affichera le code HTML faisant une instance du flash en utilisant l’id de la vidéo fournit par la propriété MovieID.

    Les colonnes sont définies. Cependant elles ne sont pas encore affichées dans les vues. Le code en dessous de la définition des champs définit les vues. On va donc ajouter l’affichage de nos champs dans les vues.

    On a deux vues de définies, la première est la vue par défaut, la deuxième est la vue de la liste allitems. On va donc ajouter nos champs dans l’affichage des deux vues. Pour cela on repère le nœud ViewFields, il se situe à deux endroits, un pour chaque vue, le premier est a peu prés au milieu du fichier et le deuxième est à la fin.

    Voici le code qui le remplace :

    <ViewFields> 
    <FieldRef Name="LinkTitleNoMenu"/> 
    <FieldRef Name="Description"/> 
    <FieldRef Name="MovieID"/> 
    <FieldRef Name="Preview"/> 
    </ViewFields>

    Une fois que l’on a fait cela on peut déployer notre feature. Pour cela, soit on fait F5, ce qui n’a que peu d’intérêt ici car on n’a pas de code réel. Soit on fait un clic avec le bouton droit de la souris sur le projet et on sélectionne deploy. La plupart des erreurs se passeront au déploiement, car c’est qu’a ce moment la que SharePoint vérifie la syntaxe et l’exactitude des informations fournies dans le XML.

    La feature déployé, il nous reste plus qu’a tester. Etant donné que l’on a demandé la création d’une instance de la liste, on n’a pas besoin d’en créer une, elle est créée automatiquement. Dans View all site content on a YoutubeList Instance:

    On clique dessus et on sélectionne new :

    Vous pouvez remarquer que les champs sont obligatoires. Ceci est du au fait qu’on a mis Required=«true» dans la déclaration de la liste.

    Une fois notre item créé on peut le voir dans la liste avec la vidéo :

    Et si on sélectionne un item on voit la vidéo s’afficher aussi :

    L’avantage de faire une liste est qu’on peut modifier l’affichage, trier ou regrouper les items. Par exemple si on ajoute une colonne catégorie a notre liste et qu’on créé une vue de regroupement on obtient :

    On peut donc vraiment utiliser toute la puissance des listes.

    Conclusion

    Beaucoup de développement SharePoint se basent uniquement sur les WebParts. Alors que le framework SharePoint est beaucoup poussé. La création de liste est vraiment l’un des points les plus puissants de SharePoint car on reste proche de la philosophie de SharePoint

     
    							
  • Viewport2DVisual3D: Enter the 3D Matrix expander

    Afin d'illustrer une des plus importantes innovations apportées par WPF 3.5, je remets au goût du jour un contrôle que j'avais réalisé avec la CTP de février 2005: le contrôle MatrixExpander. A cette occasion, le contrôle aura subit des améliorations de conception. C'est toujours un dérivé du contrôle Expander intégrant une interface audio et vidéo, mais cette fois les media sont compilés avec le source et le contrôle sera en 3D full interactif.

    Enter the matrix expander

     

    Introduction

    WPF 3.5 améliore la richesse du Viewport3D par l'ajout de la classe Viewport2DVisual3D qui permet de rendre n'importe quel visuel 2D totalement interactif en tant que modèle 3D. Autrefois appliqué comme texture à un modèle 3D, le contrôle reste totalement opérationnel. J'ai alors considéré la conception du contrôle de manière indépendante, tel qu'il sera utilisé dans n'importe quelle application puis je lui rajoute une décoration 3D que je façonne selon le résultat final à obtenir. Le contrôle n'a par conséquent pas besoin d'être conçu dans la perspective d'être appliqué sur un modèle 3D.

    Custom Expander

    Le contrôle dérive de la classe de base Expander et encapsule le template pour fournir le visuel. Un contrôle ToggleButton templaté est utilisé pour être bindé à la propriété IsExpanded de l'Expander.

    <Expander.Template> 
        <ControlTemplate TargetType="{x:Type lc:RDExpander}"> 
          <Grid x:Name="EnterTheMatrix" Width="168" Height="210"> 
            <Grid> 
              <Grid x:Name="_expanderContent" Panel.ZIndex="0"> 
                <Image Source="../Images/MatrixFrame.png" Width="160" Height="101" Stretch="Uniform" StretchDirection="Both" /> 
                <ContentPresenter /> 
                <Grid.RenderTransform> 
                  <TranslateTransform X="0" Y="0" /> 
                </Grid.RenderTransform> 
              </Grid> 
              <Image x:Name="PART_MatrixBg" Width="168" Height="109" Stretch="Uniform" StretchDirection="Both" Source="../Images/MatrixScreen.png" Panel.ZIndex="10" VerticalAlignment="Top" /> 
              <Border x:Name="PART_Border" Width="168" Height="101" Background="Transparent" Panel.ZIndex="-10" VerticalAlignment="Bottom" /> 
            </Grid> 
            <ContentPresenter x:Name="_header" ContentSource="Header" /> 
            <ToggleButton x:Name="_matrix" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}"> 
              <ToggleButton.Template> 
                <ControlTemplate> 
                  <Grid> 
                    <MediaElement x:Name="MatrixMovie" Width="135" Height="77" Stretch="UniformToFill" Opacity="0"> 
                      <MediaElement.Triggers> 
                        <EventTrigger RoutedEvent="MediaElement.MediaOpened"> 
                          <EventTrigger.Actions> 
                            <BeginStoryboard> 
                              <Storyboard> 
                                <DoubleAnimation Duration="0:0:0.5" To="1" Storyboard.TargetProperty="Opacity" /> 
                              </Storyboard> 
                            </BeginStoryboard> 
                          </EventTrigger.Actions> 
                        </EventTrigger> 
                      </MediaElement.Triggers> 
                    </MediaElement> 
                  </Grid> 
                  <ControlTemplate.Triggers> 
                    <EventTrigger RoutedEvent="FrameworkElement.Loaded"> 
                      <EventTrigger.Actions> 
                        <BeginStoryboard> 
                          <Storyboard> 
                            <MediaTimeline Source="{local:EmbeddedMedia Source='pack://application:,,,/FX/matrix.avi'}" RepeatBehavior="Forever" Storyboard.TargetName="MatrixMovie" /> 
                          </Storyboard> 
                        </BeginStoryboard> 
                      </EventTrigger.Actions> 
                    </EventTrigger> 
                  </ControlTemplate.Triggers> 
                </ControlTemplate> 
              </ToggleButton.Template> 
            </ToggleButton> 
          </Grid>

    La difficulté est de fournir le comportement adéquat selon la direction de l'expander. Dans le cas précis, je décide de ne fournir que les comportements pour les directions Down et Up. Les autres sont assimilées à la direction Down. Il semble que plusieurs méthodes soient possibles pour animer le comportement de l'expander. Pour ma part, j'override la méthode OnExpanded et exécute les Storyboards en conséquence.

    protected override void OnExpanded()
        {
          base.OnExpanded();
          Grid __expanderContent = (Grid)base.GetTemplateChild("_expanderContent");
          switch (base.ExpandDirection)
          {
            case ExpandDirection.Up:
              __expanderContent.BeginStoryboard((Storyboard)this.Resources["Expanded_Up"]);
              break;
    
            case ExpandDirection.Down:
            case ExpandDirection.Left:
            case ExpandDirection.Right:
            default:
              __expanderContent.BeginStoryboard((Storyboard)this.Resources["Expanded_Down"]);
              break;
          }
        }

    Une autre nouveauté réside dans l'intégration des fichiers audio et vidéo dans l'application. Effectivement, le contrôle MediaElement n'accepte toujours pas des URI pointant vers des ressources embedded. Un MarkupExtension nommé EmbeddedMedia permettra de combler cette lacune. La seule contrainte est la création d'un dossier caché afin de "descendre" les fichiers sur le disque avant de les charger (merci à Avalonboy pour sa contribution).

    <MediaTimeline Source="{local:EmbeddedMedia Source='pack://application:,,,/FX/matrix.avi'}" RepeatBehavior="Forever" Storyboard.TargetName="MatrixMovie" />
    public sealed class EmbeddedMediaExtension : MarkupExtension
      {
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
          StreamResourceInfo __resourceStream = Application.GetResourceStream(this._source);
          DirectoryInfo __directoryInfo = new DirectoryInfo(string.Format("{0}\\{1}", Directory.GetCurrentDirectory(), CACHE_FOLDER));
    
          if (!__directoryInfo.Exists)
          {
            __directoryInfo.Create();
            __directoryInfo.Attributes = FileAttributes.Hidden;
          }
    
          FileInfo __fileInfo = new FileInfo(string.Format("{0}/{1}", __directoryInfo.FullName, this._source.Segments[this._source.Segments.Length - 1]));
          if (!_cache.ContainsKey(this._source))
          {
            if (!__fileInfo.Exists)
            {
              int __byte;
              FileStream stream = new FileStream(__fileInfo.FullName, FileMode.CreateNew);
              while ((__byte = __resourceStream.Stream.ReadByte()) != -1)
              {
                stream.WriteByte((byte)__byte);
              }
              stream.Close();
              __resourceStream.Stream.Close();
            }
            _cache.Add(this._source, __fileInfo);
            return new Uri(__fileInfo.FullName);
          }
          return new Uri(_cache[this._source].FullName);
        }
      }

    Décoration 3D

    Les contrôles sont prêts à être consommés par l'application tant en visuel 2D qu'en 3D. La classe Viewport2DVisual3D va jouer son rôle de décorateur 3D pour les contrôles Expander. Son utilisation est simple puisqu'elle s'ajoute comme élément enfant du contrôle Viewport3D tel qu'un Model3D classique. Il suffit de définir la Geometry3D à utiliser, dans mon cas une forme de type Plane sera suffisant, de définir le contrôle en tant qu'élément visuel et de spécifier que la texture à utiliser est un élément interactif.

    <Viewport3D ClipToBounds="False" Width="168" Height="210">
              <Viewport3D.Camera>
                <PerspectiveCamera FarPlaneDistance="10" LookDirection="0,0,-1" UpDirection="0,1,0" NearPlaneDistance="1" Position="0,0,1.9" FieldOfView="45" />
              </Viewport3D.Camera>
    
              <Viewport2DVisual3D>
                <Viewport2DVisual3D.Geometry>
                  <MeshGeometry3D Positions="-1,1,0 -1,-1,0 1,-1,0 1,1,0" TextureCoordinates="0,0 0,1 1,1 1,0" TriangleIndices="0,1,2 2,3,0" />
                </Viewport2DVisual3D.Geometry>
    
                <Viewport2DVisual3D.Material>
                  <DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True" />
                </Viewport2DVisual3D.Material>
    
                <Viewport2DVisual3D.Transform>
                  <Transform3DGroup>
                    <ScaleTransform3D ScaleX="0.8" ScaleY="1" ScaleZ="1" />
                    <RotateTransform3D>
                      <RotateTransform3D.Rotation>
                        <AxisAngleRotation3D Angle="18" Axis="1 0 0"/>
                      </RotateTransform3D.Rotation>
                    </RotateTransform3D>
                    <TranslateTransform3D OffsetX="-0.25" OffsetY="-0.045" OffsetZ="0.24" />
                  </Transform3DGroup>
                </Viewport2DVisual3D.Transform>
    
                <lc:RDExpander Margin="2" ExpandDirection="Up" MouseEnter="_ExpanderEnter">
                  <lc:RDExpander.Header>
                    <lc:MatrixTextBlock Text="Enter Thor's matrix" ImmediateWrite="False" Width="128" Height="Auto" TextAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center" TextWrapping="WrapWithOverflow" />
                  </lc:RDExpander.Header>
                  <Grid>
                    <StackPanel Width="130" Height="70">
                      <TextBlock Margin="2">
                                          <Hyperlink NavigateUri="http://blog.rioterdecker.net/blogs/valhalla">Thor's blog</Hyperlink>
                                      </TextBlock>
                      <TextBlock Margin="2">
                                          <Hyperlink NavigateUri="http://www.netfxfactory.org">NetFXFactory</Hyperlink>
                                      </TextBlock>
                      <TextBlock Margin="2">
                                          <Hyperlink NavigateUri="http://www.mexedge.com">MexEdge</Hyperlink>
                                      </TextBlock>
                    </StackPanel>
                  </Grid>
                </lc:RDExpander>
              </Viewport2DVisual3D>
    
              <ModelVisual3D>
                <ModelVisual3D.Content>
                  <Model3DGroup>
                    <AmbientLight Color="#333333" />
                    <DirectionalLight Color="#FFFFFF" Direction="-0.612372,-0.5,-0.612372" />
                    <DirectionalLight Color="#FFFFFF" Direction="0.612372,-0.5,-0.612372" />
                  </Model3DGroup>
                </ModelVisual3D.Content>
              </ModelVisual3D>
            </Viewport3D>

    Le projet est attaché ainsi que le binaire.
    J'adore WPF !! Une seule limite...celle de votre imagination !!

  • Vista Thumbnail live en 3D

    Introduction

    Les thumbnail de vista sont, les miniatures qui représente les application en train de fonctionner sur le systéme d'exploitation. Un exemple de thumbnail est le Flip 3D, qui affiche les application en 3D et les fait defiler. Jusque maintenant pour récupérer les thumbnail dans nos applications, on avait que la possibilité de le faire en 2D, j'ai d'ailleur écrit un article dessus.
    http://netfxfactory.org/blogs/articles/archive/2007/03/30/dwm-api-et-milcore.aspx

    Jeremiah Morril a reussi a trouver comment récupérer les Live thumbnail pour en faire des texture Directx. Voici comment il a procédé.

    Dans Windows Visa, chaque fenêtre est un objet 3D qui est géré par DirectX. Le bureau est entiérement gérer par DwmApi qui est une api de plus haut niveau que l'api MilCore (Api qui gére d'ailleur le WPF).

    Les méthodes cachées

    Les méthodes cachées qui permettent de récupérer les textures, sont des méthodes cachées et non documenté de DWMAPI: DwmpDxGetWindowSharedSurface et DwmpDxUpdateWindowSharedSurface.

    Leur signature est la suivante.

    typedef
    
    int (__stdcall *PFNDWM_DXGETWINDOWSHAREDSURFACE)(HWND hWnd, LUID adapterLuid, DWORD one, DWORD two, DWORD *pD3DFormat, HANDLE *pSharedHandle, unsigned __int64 *arg7); 
    typedef
    
    int (__stdcall *PFNDWM_DwmpDxUpdateWindowSharedSurface)(HWND hWnd, int, int, int, HMONITOR hMonitor, void* test); 

    Chargement des fonctions

    Bien entendu comme les fonctions ne sont pas documentées, on ne peut pas les récupérer à partir d'un simple fichier H à inclure, voici donc comment on les chargera:

    HMODULE hDwmApi = LoadLibrary(L"dwmapi.dll"); 
    pDwmpDxGetWindowSharedSurface = (PFNDWM_DXGETWINDOWSHAREDSURFACE)GetProcAddress(hDwmApi, (LPCSTR)100);
    pDwmpDxUpdateWindowSharedSurface = (PFNDWM_DwmpDxUpdateWindowSharedSurface)GetProcAddress(hDwmApi, (LPCSTR)101);
    

    Récupérer les SharedTexture

    Maintenant qu'on a les fonction on peut les utiliser pour récupérer les "textures" des fenêtres:

    hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
    monitorInfo.cbSize =sizeof(monitorInfo); 
    GetMonitorInfo(hMonitor, &monitorInfo);
    
    memcpy(&openDev.DeviceName, monitorInfo.szDevice, 32);
    HRESULT hr;
    hr = pOpenAdapterFromGdiDisplayName(&openDev);
    adapterLuid = openDev.AdapterLuid;
    closeDev.hAdapter = openDev.hAdapter;
    hr = pCloseAdapter(&closeDev);
    hr = pDwmpDxGetWindowSharedSurface(hWnd, adapterLuid, 0, 0, d3dFormat, sharedHandle, &unknown);
    
    

    Dans ce code on utilise pDwmpDxGetWindowSharedSurface auquel on passe le Handle de fenêtre dont on veut récupérer la texture, cette fonction retournera un pointeur sur la texture a utiliser

    Mettre la Shared Texture dans une texture DirectX 3D

    voici le bout de code qui permet de le récupérer:

    HANDLE texHandle = NULL;
    
    DWORD fmt = 0;
    
    RECT winRect;
    
    HWND h;
    
    h = FindWindow(NULL, L"directx or wpf application"); 
    
    GetWindowRect(h, &winRect); 
    
    HRESULT res;
    
    SIZE sWin = { winRect.right - winRect.left, winRect.bottom - winRect.top };
    
    GetWindowSharedSurfaceHandle(h, &texHandle, &fmt); //
    
    IDirect3DTexture9 *texture;
    
    hr = g_pd3dDevice->CreateTexture(sWin.cx, sWin.cy, 1, D3DUSAGE_RENDERTARGET, (D3DFORMAT)fmt, D3DPOOL_DEFAULT, &g_pTexture, &sharedHandle);
    
    pDwmpDxUpdateWindowSharedSurface(h, 0, 0, 0, 0, 0);

    En piéce jointe il y a le code de textures.cpp, ce code prendra la place de Textures.cpp qui est le tutorial 5 du SDK DirectX. C'est ce même code qui est utilisé pour la vidéo présente sur le site de Jeremiah:

    http://jmorrill.hjtcentral.com/Portals/21/Blog/Files/14/111/dwmhack.zip

    il suffit de modifier la ligne 380 avec le titre de la fenêtre que vous voulez monitorer. Pour l'instant seul les fenêtre utilisant Directx ou WPF peuvent être utiliser en tant que texture mais tres vite les fenêtre GDI en feront partie aussi

    Merci beaucoup a jeremiah pour avoir partager l'information et m'avoir permis d'en parler si librement.

  • WF et Biztalk 2006 R2

    Deux Webcast illustrant l'article sont disponibles :
    http://www.netfxfactory.org/blogs/video___la_demande/archive/2007/07/04/n3rd-s4-composer-son-portefeuille-d-activit-m-tier-avec-wf-le-premier-pas-vers-le-management-des-processus.aspx
    et a la fin de l'article

    Introduction

    Business activity monitoring ou supervision des activité métier est une fonctionnalité de biztalk permettant de superviser et de voir les performances du déroulement d'un processus métier. Cela permet de savoir les temps d'exécution du processus et de tracer, par exemple, les temps d'attente ou les goulets d'étranglement dans l'execution d'un processus. En effet BAM se base sur un mapping entre l'exécution d'une orchestration Biztalk et un fichier Excel qui contient les données, les dimensions et les mesures du processus métiers. Avec la version 2006 R2 de biztalk on voit apparaitre le BamTrackingService. Celui ci permet d'envoyer à BAM les informations concernant l'exécution non pas d'une orchestration Biztalk, mais d'un Workflow WF. Dans cet article nous allons un peu detourner le comportement de BAM pour tracer non pas les performances ou les temps d'attentes d'un processus mais plutot compter le nombre d'occurence de la valeur d'une variable dans le processus métier.

    Application Exemple

    L'application exemple est un simple hello world. Voici le résultat d'execution du workflow:

    image

    Ce workflow demande le nom, prenom et le sexe de la personne qui utilise le workflow. Le workflow en lui même est le suivant:

    image

    Dans notre exemple on va compter les genres de personnes qui utiliseront le workflow (fille, garçon et erreur) l'erreur sera utilisé en cas de faute de frappe par exemple.

    BamTrackingService

    Comme son nom l'indique, le BamTrackingService est un service WF. Il s'utilise très simplement dans le sens ou son implémentation est identique à celle d'un autre service comme le tracking ou la persistence. Pour cela on créer une instance de BamTrackingService auquel on ajoute la chaine de connexion à la base de données, ainsi que l'intervalle de pooling:

    System.Collections.Specialized.NameValueCollection parameters = new System.Collections.Specialized.NameValueCollection(); 
    parameters.Add("PollingIntervalSec", "5"); 
    parameters.Add("ConnectionString", "Integrated Security=SSPI;Data Source=.;Initial Catalog=BAMPrimaryImport");
    workflowRuntime.AddService(new BamTrackingService(parameters)); 

     

    Voila pour le workflow il n'y a rien d'autre a faire. Maintenant on va paramétrer BAM pour qu'il puisse tracer notre workflow.

     

    BamActivity

    Premiérement on va paramétrer BAM en utilisant le plugin BAM pour excel. Pour cela on lance Excel sur le serveur Biztalk et on va crée une activity bam et une vue pour afficher les données. On lance l'assistant de création d'activité Bam d'excel:

    image

    On créé une activité auquel on ajoute un item Gender qui récuperera les données venant du workflow:

    image

    image

    Une fois l'activité créé l'assistant de création de vue se lance a son tour:

    image

    On créé une vue en adéquation avec l'activité qu'on vient de créer puis on ajoute les items de l'activité et les alias sur les items:

    image

    image

    Bien maintenant on créé la mesure et la dimension qui permettront de compter le nombre de garçon, de fille ou les erreurs:

    image

    Voici la mesure:

    image

    et voici la dimension:

    image

    Maintenant qu'on a les données et les mesures on va les insérer dans la pivot table:

    image

    Le principe est le même qu'un cube OLAP.

    Pour l'exemple je vais utiliser des données LIVE pour cela j'active le bouton RTA (Real Time Aggregation):

    image
    Quand on a finit notre tableau avec nos données on peut le déployer sur le serveur avec l'outil BM:

    image

    BM fait deux choses quand on l'utilise avec un fichier XLS, la premiére c'est de déployer l'activité et la vue sur le serveur, puis il créé un fichier live qu'on utilisera plus tard.

    BamConfiguration

    C'est la partie la plus complexe du processus. Non pas que le principe soit complexe, mais, pour une raison que j'ignore, il n'y a pas d'assistant ou d'aide à la création du fichier qui fera la relation entre la vue et l'activité déployé sur le serveur et le workflow.

    Voici le code complet du fichier:

    <?xml version="1.0" encoding="utf-8" ?> 
    <ic:InterceptorConfiguration xmlns:ic="http://schemas.microsoft.com/BizTalkServer/2004/10/BAM/InterceptorConfiguration xmlns:wf="http://schemas.microsoft.com/BizTalkServer/2004/10/BAM/WorkflowInterceptorConfiguration> 
        <ic:EventSource Technology="WF" Name="Workflow1" Manifest="HelloWorldWorkflowLib.Workflow1, HelloWorldWorkflowLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>    
            <ic:BamActivity Name="HelloWorldActivity"> 
                <ic:OnEvent Name="HelloWorldEvent" Source="Workflow1" IsBegin="true" IsEnd="true"> 
                    <ic:Filter> 
                        <ic:Expression> 
                            <wf:Operation Name="GetActivityName" /> 
                            <ic:Operation Name="Constant"> 
                                <ic:Argument>AskGender</ic:Argument> 
                            </ic:Operation> 
                            <ic:Operation Name="Equals" /> 
                            <wf:Operation Name="GetActivityEvent" /> 
                            <ic:Operation Name="Constant"> 
                                <ic:Argument>Closed</ic:Argument> 
                            </ic:Operation> 
                            <ic:Operation Name="Equals" /> 
                            <ic:Operation Name="And" /> 
                        </ic:Expression> 
                    </ic:Filter> 
                    <ic:CorrelationID> 
                        <ic:Expression> 
                            <wf:Operation Name="GetContextProperty"> 
                                <wf:Argument>EventTime</wf:Argument> 
                            </wf:Operation> 
                        </ic:Expression> 
                    </ic:CorrelationID> 
                    <ic:Update DataItemName="Gender" Type="NVARCHAR"> 
                        <ic:Expression> 
                            <wf:Operation Name="GetWorkflowProperty"> 
                                <wf:Argument>Gender</wf:Argument> 
                            </wf:Operation> 
                        </ic:Expression> 
                    </ic:Update> 
                </ic:OnEvent> 
            </ic:BamActivity>      
    </ic:InterceptorConfiguration> 
    
    

     

    Regardons comment il fonctionne:

    Premiérement on créé la source des événements. La source des événements est le manifest de la classe du Workflow. On donne un nom à l'event source, par principe on utilise le nom du workflow ici Name="Workflow1" mais on pourrait mettre ce qu'on veut. Ensuite fait le mapping avec l'activité créé par le fichier Excel, ici HelloWorldActivity.

    On base le mapping sur un événement du Workflow, l'événement que j'ai choisit et la sortie de l'activité AskGender qui demande le sexe et le mets dans la propriété Gender.

    Voici le bout de code qui permet de faire cela:

    <ic:OnEvent Name="HelloWorldEvent" Source="Workflow1" IsBegin="true" IsEnd="true">
    

    Ce code permet de crée l'événement par rapport a la source définit plus haut. Ensuite on indique que cette événement sera le début et la fin du tracking. En fait comme on en a pas d'autre le tracking commencera et finira sur cette événement.

    <ic:Filter> 
                        <ic:Expression> 
                            <wf:Operation Name="GetActivityName" /> 
                            <ic:Operation Name="Constant"> 
                                <ic:Argument>AskGender</ic:Argument> 
                            </ic:Operation> 
                            <ic:Operation Name="Equals" /> 
                            <wf:Operation Name="GetActivityEvent" /> 
                            <ic:Operation Name="Constant"> 
                                <ic:Argument>Closed</ic:Argument> 
                            </ic:Operation> 
                            <ic:Operation Name="Equals" /> 
                            <ic:Operation Name="And" /> 
                        </ic:Expression> 
                    </ic:Filter> 
    
    

    Ici on filtre les événements déclenché par le workflow. On récupére l'événement sur L'activité AskGender qu'on récupére grace à GetActivityName. Ensuite on filtre sur la fermeture de l'activité qui correspond a la sortie de celle ci. Pour cela on utilise GetActivityEvent et on spécifie Closed. Le filtre est "quand l'activité est égal à AskGender ET l'évenement est égal à Closed. Les opérations permette de mettre en place les test d'égalité et l'opérateur AND.

    <ic:CorrelationID> 
                        <ic:Expression> 
                            <wf:Operation Name="GetContextProperty"> 
                                <wf:Argument>EventTime</wf:Argument> 
                            </wf:Operation> 
                        </ic:Expression> 
                    </ic:CorrelationID> 
    

    La correlation permet de regrouper les événements. Ici on utilisera le temps car on ne veut pas de regroupement mais dans la plupart des cas on utilisera IntanceID.

    <ic:Update DataItemName="Gender" Type="NVARCHAR"> 
                        <ic:Expression> 
                            <wf:Operation Name="GetWorkflowProperty"> 
                                <wf:Argument>Gender</wf:Argument> 
                            </wf:Operation> 
                        </ic:Expression> 
                    </ic:Update>
    

    Ici on indique ce que l'interceptor doit faire, en l'occurence mettre à jour la propriété Gender avec la valeur de la variable Gender du workflow.

    Maintenant on a plus qu'à déployer notre fichier de configuration, toujours avec l'utilitaire BM:

    image

     

    Execution

    Bien passons à l'éxécution. Pour cela on va exécuter plusieur fois le Workflow pour remplir la base de données BAM:

    image 

    On va commencer par ouvrir le fichier Excel live qui a été créé par le déploiement du fichier Excel de configuration de BAM:

    image

    Comme vous pouvez le voir on a le décompte des informations entré dans le workflow.

    L'avantage de BAM c'est le portail qui se base sur Sharepoint (2003 pour l'instant)

    image

    Dans ce portail on a les même information que dans le fichier Excel.

    Conclusion

    BAM est un tres gros avantage de Biztalk 2006 R2, il permet de facilement tracer l'exécution du processus métier. Le fait qu'il soit possible d'integrer WF avec offre un gros avantage a WF. La question qui se pose est quand est ce que Microsoft vendra BAM sans Biztalk ;)).

    Format: wmv
    Duration: --:--

  • Article d'introduction à Windows Workflow Foundation (WF)

    Ce document vous propose de parcourir les différentes fonctionnalités de la technologie Windows Workflow Foundation (WF). Ce parcours s'appuie sur la mise en pratique d'un exemple simple.

    Au fil de la lecture de ce document, vous appréhenderez la notion de workflow séquentiel, vous la comparerez à celle de machine à états. Vous saurez comment échanger des données avec vos workflows mais également personnaliser ces derniers via le développement de vos propres activités.
    Ce document abordera en conclusion des premiers services offert par WF tel que le service de tracking et de