ATLServer??

For more information on ATL Server, please see http://msdn.microsoft.com/en-us/library/exb5b09w(v=vs.80).aspx and http://atlserver.codeplex.com/ You cannot fully understand much of the content on this page without reviewing the MSDN documentation first.

Q. What is ATL Server?

A. It is a C++/COM based framework for building web apps. For more information on ATL Server, please see ATL Server Reference at http://msdn.microsoft.com/en-us/library/exb5b09w(v=vs.80).aspx

Q. Why would I want to use ATL Server?

A. ATL Server simplifies programming the http protocol. It also enables developers access to low-level Windows apis not normally available in the .NET Framework for example, DeviceIoControl. Using ATL Server to control hardware devices is fairly straightforward, and easy to debug, especially with Visual Studio.

ATL Server Sequence of Events??

  • Client sends HTTP request to w3pi web-server
  • w3pi checks the url for .srf file extension
  • If .srf file extension is found, then w3pi checks the Server Response File Cache
  • If the file to be served is older then the file on disk, the .srf file is loaded, otherwise a cached response is returned to the client.
  • w3pi parses the .srf file Handler tag and checks whether the web application dll associated with the handler is in the DLL cache.
  • If the web application DLL is not in the DLL cache, the DLL is loaded and cached.
  • w3pi returns the response back to the client from the web application DLL

ATL Server Handler Tag Notes??

will include the text file in the directory above the .srf file.

ATL Server Misc. Notes??

  • Asynchronous processing within your ATL Server web-app is not enabled. (but your web-app runs inside an asynchronous threadpool)

  • You must use ANSI strings for things like http headers, server variables and filenames, but you should compile your web application in Unicode.

  • TransmitFile:

    • Use the HSE_IO_DECLARE_PUSH and HSE_IO_SEND_HEADERS in the dwFlags parameter to send an HTTP 2.0 Push request. When using HSE_IO_DECLARE_PUSH, you must only push files that are within the web servers pathinfo portion of the URI (aka virtual directory).
    • content-range header is ignored
    • Use the HSE_IO_FINAL_SEND in the dwFlags parameter if you would like w3pi to close the file handle (only applies to non-push related responses).

ATL Server Projects??

  • Paid users of w3pi may download the ATL Server Project Visual Studio extension wizard, which helps automate creating an atl server web app in Visual Studio
  • Unpaid users will have to create an atl server web app from scratch

Installing Visual Studio??

  1. download visual studio 2017
_images/install-vs1.png
  1. Save it
_images/install-vs2.png
  1. Open it
_images/install-vs3.png
  1. Check the 2 checkboxes as shown below and then choose individual components
_images/install-vs4.png
  1. Scroll the list and check these 3
_images/install-vs5.png
  1. Also check these ones
_images/install-vs6.png
  1. Now check this one
_images/install-vs7.png
  1. Download and install the Windows IOT Project Templates

Preparing your Windows IOT Device for development??

  1. Please visit this to download Windows IOT onto your device
  2. After Windows IOT is installed, you must set the correct time on the device, so you need to log onto Windows IOTs portal
  3. Next you will have to install remote debugging. This is completed by creating a dummy project and then deploying the remote debugger to the device using visual studio.
  4. Create a new C# UWP Iot project
_images/rdbg1.png
  1. Click OK
_images/rdbg2.png
  1. Right Click the project you have created and select properties
_images/rdbg3.png
  1. Configure the settings similar to the picture (change the remote computer name to match the hostname of your device)
_images/rdbg4.png
  1. Click Remote Windows Debugger
_images/rdbg5.png
  1. The operation will take some time
_images/rdbg6.png
  1. Eventually it will time out (this is ok)
_images/rdbg7.png
  1. Check to ensure that the application was deployed
_images/rdbg8.png

Deploy w3pi webserver to the device??

  1. Download w3pi.exe from download section
  1. Copy the w3pi.exe file to the device using ftp

Create atl server web app from template??

This section uses the ATL Server Project Visual Studio extension wizard

  1. Click File Menu->New Project
_images/create-v-project1.png
  1. Select Visual c++ then scroll down to ShowMe and type in a project name
_images/create-v-project2.png
  1. Select ARM from the build target
_images/create-v-project3.png
  1. Right click the project and choose properties
_images/create-v-project4.png

5. Select the debug page and ensure all these settings are similar (If you have not bootstrapped your raspberry pi for remote debugging, please follow these steps)

_images/create-v-project5.png
  1. Right click the start-remote-debugging.ps1 file and choose Open with Powershell ISE
_images/create-v-project6.png
  1. Select each line, and press F8. Change the remote computer name to match the hostname of your raspberry pi. After running the last line, the powershell session will become hung. This is normal, as it indicates the remote debugger is listening for connections.
_images/create-v-project7.png
  1. You may also wish to verify whether msvsmon is running by browsing to http://minwinpc:8080/#Debug
_images/create-v-project8.png
  1. Click Remote Windows Debugger
_images/create-v-project9.png

Create atl server web app from scratch??

Difficult

  1. Create a project in Visual Studio
_images/create-project1.png
  1. Choose DLL, add ATL Support and uncheck SDL
_images/create-project2.png
  1. Right click the project, choose add new item
_images/create-project3.png
  1. Add a new header file named dllmain.h
_images/create-project4.png
  1. Right click the project and choose properties
_images/create-project5.png
  1. Ensure you have selected All Configurations and the correct SDK is selected
_images/create-project6.png
  1. click Configuration Manager
_images/create-project7.png
  1. Click New
_images/create-project8.png
  1. Click OK. You have now added ARM to your build configuration
_images/create-project9.png
  1. Change the Remote Debugging to the values shown below
_images/create-project10.png
  1. downloaded the atl server include files from codeplex
  2. Extract them to a directory (eg. c:\projects\iot\common)
  3. Type in the path to the extracted files in the VC++ Directories page as show below
_images/create-project13.png
  1. Verify sdl check is off
_images/create-project14.png
  1. Open linker properties and click the drop down list box, then choose edit
_images/create-project15.png
  1. ensure your linker dependencies look like this
_images/create-project16.png
  1. ensure the linker ignore specific default libraries looks like this
_images/create-project17.png
  1. copy 3 files from visual studio directory to the c:\projects\iot\common directory , namely atlutil.h, atlbase.h and atlcomcli.h . For VS2017, the source directory is typically C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.10.25017\atlmfc\include Unset the read-only attributes on files if necessary
  2. Comment out line 41 in atlutil.h
41
 //#include <atlpath.h>
  1. Comment out lines 130 - 146, 3043 - 3048, 3242, 3243 in atlcomcli.h
130
131
132
133
134
135
 /*_Check_return_ inline HRESULT AtlSetChildSite(
     _Inout_ IUnknown* punkChild,
     _Inout_opt_ IUnknown* punkParent)
 {
     (...)
 }*/
3043
3044
3045
3046
3047
3048
 /*hr = punkVal->QueryInterface(__uuidof(IPersistStreamInit), (void**)&spStream);
 if (FAILED(hr))
 {
     spStream.Detach();
     return hr;
 }*/
3242
3243
 //hr = punkVal->QueryInterface(__uuidof(IPersistStreamInit), (void**)&spStream);
 //if (FAILED(hr))
  1. Comment out lines 206 - 219, 7205 - 7335 in atlbase.h
206
207
208
209
210
211
 /*HRESULT WINAPI RegisterClassObject(
 _In_ DWORD dwClsContext,
 _In_ DWORD dwFlags)
 {
     (...)
 }*/
7205
7206
7207
7208
 /*ATLINLINE ATLAPI AtlRegisterClassCategoriesHelper
 {
     (...)
 }*/
  1. After you have finished editing these files, you should end up with a directory of modified atl files. Now its time to edit atl server files
  2. atlstencil.h Comment out and replace:
2894
//PathCanonicalizeA(pInfo->m_szFileName, strPath);
2952
2953
2954
2955
/*if (!PathCanonicalize(szFileBuf, strConv))
{
    return STENCIL_INVALIDINDEX;
}*/

and replace it with

2894
2895
2896
 if (0 != strncpy_s(pInfo->m_szFileName, strPath.GetLength(), strPath, MAX_PATH))
     return false;
 return true;
2952
_tcscpy(szFileBuf, strConv);
  1. atlisapi.h Comment out and modify lines
22
//#include <atlpath.h>
65
//#include <dbgautoattach.h>

Modify line 130 so that it looks like the line below

130
#if defined(_M_IA64) || defined (_M_AMD64) || defined (_M_ARM)

Comment out line 525

525
 //return PathCanonicalizeA(szFullFileName, szTemp);

Insert a new line immediately after the last semicolon of line 525 and paste this code in

526
527
528
529
530
531
532
533
534
535
536
 CAtlStringW wszTemp(szTemp);
 HRESULT hr;
 wchar_t wszNewTempPath[MAX_PATH * 2];

 hr = PathCchCanonicalize(wszNewTempPath, MAX_PATH, wszTemp);
 Checked::strcpy_s(szFullFileName, MAX_PATH, CW2A(wszNewTempPath));

 if (S_OK != hr)
     return false;
 else
     return true;

Comment out lines 9725 - 9748, leaving 9749 in-tact, then continue commenting out lines 9750 - 9923

9725
9726
9727
9728
9729
9730
 BOOL ProcessDebug(__inout AtlServerRequest *pRequestInfo)
 {
     // ATLENSURE(pRequestInfo);
    (...)
    return FALSE;//do not comment out return FALSE (line 9749)
     }

Copy lines 10382 - 10383 and paste them directly after, renaming _M_AMD64 to _M_ARM

10384
10385
 #elif defined(_M_ARM)
 #define HANDLER_ENTRY_PRAGMA(class, line) __pragma(comment(linker, "/include:__phdlrEntry_" #class "_" #line));
  1. Modify the line in atlperf.inl
2421
 strXML.Format("\t<perfmon name=\"%s\">\r\n", CT2CA(GetAppName()).m_szBuffer)
  1. Comment out lines in atlsiface.h, except for line 369
20
 //#include <atlpath.h>
358
359
360
361
362
363
364
365
366
367
368
369
370
 //CPath strBrowscapPath;

 //LPTSTR sz = strBrowscapPath.m_strPath.GetBuffer(MAX_PATH);
 //UINT nChars = ::GetModuleFileName(hInstance, sz, MAX_PATH);
 //strBrowscapPath.m_strPath.ReleaseBuffer(nChars);
 //if (nChars != 0 &&
 //  nChars != MAX_PATH &&
 //  strBrowscapPath.RemoveFileSpec())
 //{
 //  strBrowscapPath += _T("\\browscap.ini");
 //  if (SUCCEEDED(Load(strBrowscapPath)))
 return E_FAIL; // do not comment out return, instead replace S_OK with E_FAIL
 //}
  1. Open dllmain.cpp and add the following lines to it:
3
 #include "dllmain.h"
  1. Open stdafx.h and add the following lines to it after line 8:
 9
10
11
12
13
14
15
16
17
18
 #define _CRT_SECURE_NO_WARNINGS
 #define _ATL_NO_COMMODULE
 #define _ATL_NO_COM_SUPPORT
 #define _ATL_NO_WIN_SUPPORT
 #define ATL_NO_MLANG
 #define ATL_NO_SOAP
 #define ATL_NO_ACLAPI
 #define ATL_NO_MMSYS
 #define _ATL_USE_WINAPI_FAMILY_PHONE_APP
 #define _APISET_MINWIN_VERSION 0x0101

Add the following line after line 27

28
29
 #include <pathcch.h>
 #include <atlstencil.h>
  1. Open dllmain.cpp and comment out lines 5 - 19:
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
 //BOOL APIENTRY DllMain( HMODULE hModule,
 //                       DWORD  ul_reason_for_call,
 //                    LPVOID lpReserved
 //                                   )
 //{
 //  switch (ul_reason_for_call)
 //  {
 //  case DLL_PROCESS_ATTACH:
 //  case DLL_THREAD_ATTACH:
 //  case DLL_THREAD_DETACH:
 //  case DLL_PROCESS_DETACH:
 //          break;
 //  }
 //  return TRUE;
 //}
  1. Add the following lines to dllmain.cpp beneath the include statement
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 class CMyModule : public CAtlDllModuleT<CMyModule>
 {
 public:
     BOOL WINAPI DllMain(DWORD dwReason, LPVOID lpReserved) throw()
     {
             return __super::DllMain(dwReason, lpReserved);
     }
 };

 CMyModule _AtlModule;

 BEGIN_HANDLER_MAP()
     HANDLER_ENTRY("Default", CMyHandler)
 END_HANDLER_MAP()

 extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
 {
     hInstance;
     return TRUE;
 }
  1. Open dllmain.h and add the following lines to it :
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
 class CMyHandler : public CRequestHandlerT<CMyHandler>
 {
 public:

     BEGIN_REPLACEMENT_METHOD_MAP(CMyHandler)
         REPLACEMENT_METHOD_ENTRY("Hello", OnHello)
     END_REPLACEMENT_METHOD_MAP()

     HTTP_CODE ValidateAndExchange()
     {
             return HTTP_SUCCESS;
     }
 protected:
     HTTP_CODE OnHello(void)
     {
         m_HttpResponse << "Hello!";
             return HTTP_SUCCESS;
     }
 };
  1. Right click the project, and click Add -> New Item -> Web -> Html page
  2. Add the following line to the top of the new page you just created. Ensure you have the correct dll name which corresponds to your project name. For example, if you named your project showme, the dll file would be called showme.dll
_images/add-handler.png
  1. Now add this line to the body of the html file
_images/hello-replacement-tag.png
  1. Right click the file and choose Rename, giving it an .srf extension
_images/create-project20.png
  1. Build the solution
_images/create-project18.png
  1. After its finished, you should see the dll file built
_images/create-project19.png

Debugging atl server web apps??

  1. First you should have already ran through the procedure called Preparing your Windows IOT Device for development
  2. Configure remote debugging for the raspberry pi in visual studio
_images/configure-rdebug.png
  1. Start the remote debugger on the raspberry pi
_images/start-remote-debugging.png
  1. Right click the project file and choose deployed
_images/debug-deploy2.png
  1. Set a breakpoint and start remote debugging
_images/start-remote-debugging.png
  1. After a couple seconds, you will hit the breakpoint if you request the page at http://minwinpc/atlserver/HTMLPage.srf
_images/debug-break.png

Download the mywebapp.zip - Sample atl server project

http-headers in atl server??

The following request headers are recognized by w3pi and are available to your web application by the m_HttpRequest.GetServerVariable or .GetQueryParams methods

See the showme project for an example

  • cache-control
  • connection
  • date
  • keep-alive
  • pragma
  • trailer
  • transfer-encoding
  • upgrade
  • via
  • warning
  • allow
  • content-length
  • content-type
  • content-encoding
  • content-language
  • content-location
  • content-MD5
  • content-range
  • expires
  • last-modified
  • accept-ranges
  • accept-charset
  • accept-encoding
  • accept-language
  • authorization
  • cookie
  • expect
  • from
  • host
  • if-match
  • if-modified-since
  • if-none-match
  • if-range
  • if-unmodified-since
  • max-forwards
  • proxy-authorization
  • referer
  • range
  • te
  • translate
  • user-agent
  • https - can be ???off??? or ???on???
  • method
  • x-actual-bytes - actual bytes received on the network interface
  • x-local-address - 169.254.227.228
  • x-remote-address - 169.254.227.228
  • url - http://mygalileo:80/atlserver/readme.html?AnyQueryString

The following reponse http headers are recognized by w3pi and are available to your web application for sending using the m_spServerContext->SendResponseHeaders method

  • cache-control
  • connection
  • date
  • keep-alive
  • pragma
  • trailer
  • transfer-encoding
  • upgrade
  • via
  • warning
  • allow
  • content-type
  • content-encoding
  • content-language
  • content-location
  • content-MD5
  • content-range
  • expires
  • last-modified
  • accept-ranges
  • age
  • etag
  • location
  • proxy-authentication
  • retry-after
  • server
  • set-cookie
  • vary
  • www-authenticate

sample atl server web apps??

DirList | Size: 50 KB
- A sample atl server project that shows a directory listing

ReDir | Size: 59 KB
- A sample atl server project that shows how to perform an http redirect

ShowMe | Size: 6 KB
- A sample atl server project that shows retrieving the values of an http GET request

MyAuth | Size: 13 KB
- A sample atl server project that shows how to use the w3pi authentication cache, by building up an authenticated user from a username / password combination submitted by an HTTP POST request (aka. Forms authentication). Then the web app will add the authenticated user to the authentication cache and map their level of access, so requests for static resources (eg. .css or .png files) will be served by w3pi automatically without HTTP 401 errors. All usernames and passwords are handled by the developer of the webapp, the only information stored in the w3pi binary authentication cache is a listing of directories and the type of access required.

FlipLED | Size: 140 KB
- A sample atl server project that shows you how to turn on/off the onboard LED of the raspberry pi. This sample uses the gpiokmdfdemo driver described in https://github.com/ms-iot/samples/tree/develop/DriverSamples/gpiokmdfdemo You must have this driver installed before you can use the FlipLED sample. FlipLED shows you how you can use driver messages generated by a web application to control hardware on the raspberry pi. The author of this article assumes no responsibility for damaging your pi if you select the wrong pins in your own web application. See this https://github.com/ms-iot/samples/blob/develop/DriverSamples/consoleapp/BlinkyApp/BlinkyApp/rpi2.h for more information.
The FlipLED sample toggles the drivers pin 13, which maps to the Pi GPIO pin 27 (onboard LED).
_images/flipled-overview.png

Hosted by: w3pi