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/

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 api’s not normally available in the .NET Framework for example, DeviceIoControl. Using ATL Server to control hardware devices is fairly straightforward, and easy to debug, when compared to other methods, such as php-gpio .

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’s 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 inside an ATL Server web-application is not enabled.

  • If you use UTF-8 strings for things like http headers, server variables and filenames, 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 server’s 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
  1. Save it
  1. Open it
  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 IOT’s 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 retarget SDK
    _images/retarget.png
  1. Choose your desired Windows SDK Version
    _images/retarget2.png
  1. Right click the project and choose properties
    _images/create-v-project4.png

7. 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 Studio2017EnterpriseVCToolsMSVC14.10.25017atlmfcinclude 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’ve finished editing these files, you should end up with a directory of modified atl files. Now it’s 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
1
 {{handler c:\test\atlserver\mywebapp.dll/Default}}
  1. Now add this line to the body of the html file
9
 {{Hello}}
  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 it’s finished, you should see the dll file built
_images/create-project19.png

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.zip  |  MD5 Hash: 42d5ac406d4f346583887187b4750144  |  Size: 51 KB

A sample atl server project that shows a directory listing

redir.zip  |  MD5 Hash: 3cded4624169950838b3b7dfc1505a47  |  Size: 60 KB

Sample atl server project that shows an http redirect

showme.zip  |  MD5 Hash: 7f7ced4b2a64193909f1786970a4c3d0  |  Size: 7 KB

Sample atl server project that shows retrieving the values of an http GET

myauth.zip  |  MD5 Hash: cbbe27fdc5153a81fe62ff57389c0729  |  Size: 14 KB

Sample atl server project that shows you how to use w3pi’s authentication cache

This sample builds 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 w3pi’s binary authentication cache is a listing of directories and the type of access required.

flipled.zip  |  MD5 Hash: b4f97276e2864adac51ec25441a80198  |  Size: 141 KB

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 Windows IOT Driver Lab 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 arcticle for more information.

The FlipLED sample toggles the driver’s pin 13, which maps to the Pi’s GPIO pin 27 (onboard LED).
overview

mywebapp.zip  |  MD5 Hash: 0f7a16acea6b00529af45252a7ba28a4  |  Size: 8 KB

Sample atl server project