text: // Copyright (C) Microsoft Corporation. All rights reserved.
  
  #ifndef H_FABRIC_MACRO_GENERATOR_H
  #define H_FABRIC_MACRO_GENERATOR_H
  
  #ifdef __cplusplus
  #include <cinttypes>
  #include <cstdlib>
  #include <cstddef>
  #else
  #include <inttypes.h>
  #include <stdlib.h>
  #include <stddef.h>
  #endif
  
  #include "windows.h"
  
  #include "macro_utils/macro_utils.h"
  
  #include "c_logging/xlogging.h"
  
  #include "c_pal/gballoc_hl.h"
  #include "c_pal/gballoc_hl_redirect.h"
  #include "c_pal/timer.h"
  #include "c_pal/threadapi.h"
  
  #include "sf_c_util/hresult_to_string.h"
  #include "sf_macros.h"
  
  #include "umock_c/umock_c_prod.h"
  /*this is prefix that is added to all data types and all APIs that are generated with this macro-based generator*/
  /*this is needed to avoid clashes in the C global namespace with existing functions, such as (existing) GetNodeList from ifabricqueryclient10sync.cpp*/
  #define H_FABRIC_PREFIX H /*H comes from "HANDLE"*/
  
  /*the below macro introduces the name of an API of hfabric. The name is composed from the method name of the underlying IFabricInterface*/
  /*for example, if the IFabric method is called GetNodeList then the macro will expands to HGetNodeList (H comes from HANDLE).
  Users should always use H_FABRIC_API(something) when calling/mocking etc*/
  #define H_FABRIC_API(IFABRIC_METHOD_NAME) MU_C2(H_FABRIC_PREFIX, IFABRIC_METHOD_NAME)
  
  /*the below macro introduces the name of the handle with retries. The name is always based on the IFabric interface that it wraps.*/
  /*this is an example: IFabricQueryClient10 -> HIFabricQueryClient10, users should only use H_FABRIC_HANDLE macro*/
  #define H_FABRIC_HANDLE(IFABRIC_INTERFACE_NAME) MU_C2(H_FABRIC_PREFIX, IFABRIC_INTERFACE_NAME)
  
  /*this macro introduces a name for function that is used to create the client*/
  /*the function name should be used through the macro*/
  #define H_FABRIC_HANDLE_CREATE(IFABRIC_INTERFACE_NAME)   MU_C3(H_FABRIC_PREFIX, IFABRIC_INTERFACE_NAME, _create)
  
  /*this macro introduces a name for function that is used to destroy a client*/
  /*the function name should be used through the macro*/
  #define H_FABRIC_HANDLE_DESTROY(IFABRIC_INTERFACE_NAME)   MU_C3(H_FABRIC_PREFIX, IFABRIC_INTERFACE_NAME, _destroy)
  
  /*this macro introduces a name for the structure underneath the H_FABRIC_HANDLE*/
  #define H_FABRIC_HANDLE_STRUCT_TYPE(IFABRIC_INTERFACE_NAME) struct MU_C2(H_FABRIC_HANDLE(IFABRIC_INTERFACE_NAME), _HANDLE_DATA_TAG)
  
  /*this macro introduces the structure of the handle*/
  #define H_FABRIC_DEFINE_STRUCT_TYPE(IFABRIC_INTERFACE_NAME)     \
  H_FABRIC_HANDLE_STRUCT_TYPE(IFABRIC_INTERFACE_NAME)             \
  {                                                               \
      IFABRIC_INTERFACE_NAME* This;                               \
      uint32_t msBetweenRetries;                                  \
      uint32_t nMaxRetries;                                       \
  };                                                              \
  
  /*this macro introduces the HANDLE typedef*/
  #define H_FABRIC_DEFINE_TYPEDEF(IFABRIC_INTERFACE_NAME) \
      typedef H_FABRIC_HANDLE_STRUCT_TYPE(IFABRIC_INTERFACE_NAME)* H_FABRIC_HANDLE(IFABRIC_INTERFACE_NAME);
  
  #if _MSC_VER<1920 /*VS 2017*/
  
  /*the following below macros (ARGS_MOCKABLE_FUNCTION_DECLARATION, ARGS_MOCKABLE_FUNCTION_IN_ARGS, ARGS_MOCKABLE_FUNCTION_PROXY, ARGS_MOCKABLE_FUNCTION_ARG) deal with taking a IN_ARGS(ARG(type1, name1), ARG(type2, name2)
  * and transforming it to , type1, name1, type2, name2... which is something that can be used in a MOCKABLE_FUNCTION argument list.*/
  
  /*expands to something that can be placed in a MOCKABLE_FUNCTION argument list*/
  #define ARGS_MOCKABLE_FUNCTION_ARG(arg_type, arg_name) , arg_type, arg_name
  
  #define ARGS_MOCKABLE_FUNCTION_PROXY(arg) MU_C1(MU_C2(ARGS_MOCKABLE_FUNCTION_, arg))
  
  /*... has the form ARG(type1, name1), ARG(type2, name2),...*/
  #define ARGS_MOCKABLE_FUNCTION_IN_ARGS(...) \
      MU_FOR_EACH_1(ARGS_MOCKABLE_FUNCTION_PROXY, __VA_ARGS__)
  
  /*in_args has the form IN_ARGS(ARG(type1, name1), ARG(type2, name2)...)*/
  /*this macro will chain to ARGS_MOCKABLE_FUNCTION_IN_ARGS (if in_args has the form above) or will error if in_args has any other form*/
  #define ARGS_MOCKABLE_FUNCTION_DECLARATION(in_args) \
      MU_C2A(ARGS_MOCKABLE_FUNCTION_, in_args)
  
  
  
  /*the following below macros (ARGS_C_DECLARATION, ARGS_C_DECLARATION_IN_ARGS, ARGS_C_DECLARATION_PROXY, ARGS_C_DECLARATION_ARG) deal with taking a IN_ARGS(ARG(type1, name1), ARG(type2, name2)
  * and transforming it to , name1 name2... which is something that can be used in a C function declaration.*/
  
  /*expands to something that can be placed in a C function declaration*/
  #define ARGS_C_DECLARATION_ARG(arg_type, arg_name) , arg_type arg_name
  
  /*arg has the form ARG(type, name)*/
  #define ARGS_C_DECLARATION_PROXY(arg) MU_C2(ARGS_C_DECLARATION_, arg)
  
  /*... has the form ARG(type1, name1), ARG(type2, name2),...*/
  #define ARGS_C_DECLARATION_IN_ARGS(...) \
      MU_FOR_EACH_1(ARGS_C_DECLARATION_PROXY, __VA_ARGS__)
  
  /*in_args has the form IN_ARGS(ARG(type1, name1), ARG(type2, name2)...)*/
  /*this macro will chain to ARGS_C_DECLARATION_IN_ARGS (if in_args has the form above) or will error if in_args has any other form*/
  #define ARGS_C_DECLARATION(in_args) \
      MU_C2(ARGS_C_DECLARATION_, in_args)
  
  
  /*the following below macros (ARGS_C_CALL, ARGS_C_CALL_IN_ARGS, ARGS_C_CALL_ARG_PROXY, ARGS_C_CALL_ARG) deal with taking a IN_ARGS(ARG(type1, name1), ARG(type2, name2),...)
  * and transforming it to , name1, name2... which is something that can be used in a C function call*/
  /*expands to something that can be placed in a C function call*/
  #define ARGS_C_CALL_ARG(arg_type, arg_name) , arg_name
  
  /*arg has the form ARG(type, name)*/
  #define ARGS_C_CALL_ARG_PROXY(arg) MU_C2(ARGS_C_CALL_, arg)
  
  /*... has the form ARG(type1, name1), ARG(type2, name2),...*/
  #define ARGS_C_CALL_IN_ARGS(...) \
      MU_FOR_EACH_1(ARGS_C_CALL_ARG_PROXY, __VA_ARGS__)
  
  /*in_args has the form IN_ARGS(ARG(type1, name1), ARG(type2, name2)...)*/
  /*this macro will chain to ARGS_C_CALL_IN_ARGS (if in_args has the form above) or will error if in_args has any other form*/
  #define ARGS_C_CALL(in_args) \
      MU_C2(ARGS_C_CALL_, in_args)
  
  /*expands to a conditional (to be prepended by a false value)*/
  #define RESULT_CHECK(result) || (hr == result)
  
  /*... has the form value1, value2...*/
  #define RESULTS_CHECK_RESULTS(...) \
      MU_FOR_EACH_1(RESULT_CHECK, __VA_ARGS__)
  #define RESULTS_CHECK_NONE(...)
  
  /*results has the form RESULTS(value1, value2...)*/
  #define RESULTS_CHECK(results) \
      MU_C2(RESULTS_CHECK_, results)
  
  #else /*VS 2019*/
  
  /*the following below macros (ARGS_MOCKABLE_FUNCTION_DECLARATION, ARGS_MOCKABLE_FUNCTION_IN_ARGS, ARGS_MOCKABLE_FUNCTION_PROXY, ARGS_MOCKABLE_FUNCTION_ARG) deal with taking a IN_ARGS(ARG(type1, name1), ARG(type2, name2)
  * and transforming it to , type1, name1, type2, name2... which is something that can be used in a MOCKABLE_FUNCTION argument list.*/
  
  /*expands to something that can be placed in a MOCKABLE_FUNCTION argument list*/
  #define ARGS_MOCKABLE_FUNCTION_ARG(arg_type, arg_name) , arg_type, arg_name
  
  #define ARGS_MOCKABLE_FUNCTION_PROXY(arg) MU_EXPAND(MU_NOEXPAND(MU_C2(ARGS_MOCKABLE_FUNCTION_, arg)))
  
  /*... has the form ARG(type1, name1), ARG(type2, name2),...*/
  #define ARGS_MOCKABLE_FUNCTION_IN_ARGS(...) \
      MU_FOR_EACH_1(ARGS_MOCKABLE_FUNCTION_PROXY, __VA_ARGS__)
  
  /*in_args has the form IN_ARGS(ARG(type1, name1), ARG(type2, name2)...)*/
  /*this macro will chain to ARGS_MOCKABLE_FUNCTION_IN_ARGS (if in_args has the form above) or will error if in_args has any other form*/
  #define ARGS_MOCKABLE_FUNCTION_DECLARATION(in_args) \
      MU_C2A(ARGS_MOCKABLE_FUNCTION_, in_args)
  
  
  /*the following below macros (ARGS_C_DECLARATION, ARGS_C_DECLARATION_IN_ARGS, ARGS_C_DECLARATION_PROXY, ARGS_C_DECLARATION_ARG) deal with taking a IN_ARGS(ARG(type1, name1), ARG(type2, name2)
  * and transforming it to , name1 name2... which is something that can be used in a C function declaration.*/
  
  /*expands to something that can be placed in a C function declaration*/
  #define ARGS_C_DECLARATION_ARG(arg_type, arg_name) , arg_type arg_name
  
  /*arg has the form ARG(type, name)*/
  #define ARGS_C_DECLARATION_PROXY(arg) MU_C2(ARGS_C_DECLARATION_, arg)
  
  /*... has the form ARG(type1, name1), ARG(type2, name2),...*/
  #define ARGS_C_DECLARATION_IN_ARGS(...) \
      MU_FOR_EACH_1(ARGS_C_DECLARATION_PROXY, __VA_ARGS__)
  
  /*in_args has the form IN_ARGS(ARG(type1, name1), ARG(type2, name2)...)*/
  /*this macro will chain to ARGS_C_DECLARATION_IN_ARGS (if in_args has the form above) or will error if in_args has any other form*/
  #define ARGS_C_DECLARATION(in_args) \
      MU_C2A(ARGS_C_DECLARATION_, in_args)
  
  
  /*the following below macros (ARGS_C_CALL, ARGS_C_CALL_IN_ARGS, ARGS_C_CALL_ARG_PROXY, ARGS_C_CALL_ARG) deal with taking a IN_ARGS(ARG(type1, name1), ARG(type2, name2)
  * and transforming it to , name1, name2... which is something that can be used in a C function call*/
  /*expands to something that can be placed in a C function call*/
  #define ARGS_C_CALL_ARG(arg_type, arg_name) , arg_name
  
  /*arg has the form ARG(type, name)*/
  #define ARGS_C_CALL_ARG_PROXY(arg) MU_C2(ARGS_C_CALL_, arg)
  
  /*... has the form ARG(type1, name1), ARG(type2, name2),...*/
  #define ARGS_C_CALL_IN_ARGS(...) \
      MU_FOR_EACH_1(ARGS_C_CALL_ARG_PROXY, __VA_ARGS__)
  
  /*in_args has the form IN_ARGS(ARG(type1, name1), ARG(type2, name2)...)*/
  /*this macro will chain to ARGS_C_CALL_IN_ARGS (if in_args has the form above) or will error if in_args has any other form*/
  #define ARGS_C_CALL(in_args) \
      MU_C2A(ARGS_C_CALL_, in_args)
  
  /*expands to a conditional (to be prepended by a false value)*/
  #define RESULT_CHECK(result) || (hr == result)
  
  /*... has the form value1, value2...*/
  #define RESULTS_CHECK_RESULTS(...) \
      MU_FOR_EACH_1(RESULT_CHECK, __VA_ARGS__)
  #define RESULTS_CHECK_NONE(...)
  
  /*results has the form RESULTS(value1, value2...)*/
  #define RESULTS_CHECK(results) \
      MU_C2A(RESULTS_CHECK_, results)
  
  #endif /*VS 2017 or VS2019*/
  
  
  /*the below macro, in_args is a single preprocessor token in the form IN_ARGS(ARG(type1, name1), ARG(type2, name2),...)*/
  #define H_FABRIC_DECLARE_API(IFABRIC_INTERFACE_NAME, IFABRIC_METHOD_NAME, in_args) \
      MOCKABLE_FUNCTION(, HRESULT, H_FABRIC_API(IFABRIC_METHOD_NAME), H_FABRIC_HANDLE(IFABRIC_INTERFACE_NAME), handle ARGS_MOCKABLE_FUNCTION_DECLARATION(in_args))
  
  /*this macro expands to a full function definition. The name of the function is H_FABRIC_API(IFABRIC_METHOD_NAME) and it contains the code to run with retries and timeout.*/
  #define H_FABRIC_DEFINE_API_WITH_RESULTS(IFABRIC_INTERFACE_NAME, IFABRIC_METHOD_NAME, in_args, permanent_failures)                                                                          \
  HRESULT H_FABRIC_API(IFABRIC_METHOD_NAME)(H_FABRIC_HANDLE(IFABRIC_INTERFACE_NAME) handle                                                                                                    \
      ARGS_C_DECLARATION(in_args)                                                                                                                                                             \
  )                                                                                                                                                                                           \
  {                                                                                                                                                                                           \
      HRESULT hr; /*also used a result*/                                                                                                                                                      \
      /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_02_007: [ If handle is NULL then H_FABRIC_API(IFABRIC_METHOD_NAME) shall fail and return NULL. ]*/                                                 \
      if (handle == NULL)                                                                                                                                                                     \
      {                                                                                                                                                                                       \
          LogError("invalid " MU_TOSTRING(HANDLE_TYPE) " handle=%p", handle);                                                                                                                 \
          hr = E_POINTER;                                                                                                                                                                     \
      }                                                                                                                                                                                       \
      else                                                                                                                                                                                    \
      {                                                                                                                                                                                       \
          /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_02_008: [ H_FABRIC_API(IFABRIC_METHOD_NAME) shall record the start time of the request by calling timer_global_get_elapsed_ms. ]*/             \
          double startTime = timer_global_get_elapsed_ms(); /*time spend here cannot exceed timeoutMilliseconds*/                                                                             \
          double elapsed;                                                                                                                                                                     \
          uint32_t retries = 0; /*incremented at every API call - 0 means "it will call once", "1" means it will call 2 times". It is in the name: **re**tries.*/                             \
                                                                                                                                                                                              \
          do                                                                                                                                                                                  \
          {                                                                                                                                                                                   \
              /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_02_009: [ H_FABRIC_API(IFABRIC_METHOD_NAME) shall call IFABRIC_METHOD_NAME on the instance of IFABRIC_INTERFACE_NAME. ]*/                  \
              hr = IFABRIC_METHOD_NAME(handle->This ARGS_C_CALL(in_args));                                                                                                                    \
              if (FAILED(hr))                                                                                                                                                                 \
              {                                                                                                                                                                               \
                  LogHRESULTError(hr, "failure in " MU_TOSTRING(IFABRIC_METHOD_NAME) "(handle->This=%p, ...)",                                                                                \
                      handle->This);                                                                                                                                                          \
                                                                                                                                                                                              \
                  /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_02_011: [ If the result is FABRIC_E_OBJECT_CLOSED, FABRIC_E_GATEWAY_NOT_REACHABLE or E_ABORT then H_FABRIC_API(IFABRIC_METHOD_NAME) shall create a new instance of IFABRIC_INTERFACE_NAME. ]*/ \
                  if ((hr == E_ABORT) || (hr == FABRIC_E_OBJECT_CLOSED) || (hr == FABRIC_E_GATEWAY_NOT_REACHABLE))                                                                            \
                  {                                                                                                                                                                           \
                      IFABRIC_INTERFACE_NAME* newInstance = NULL;                                                                                                                             \
                                                                                                                                                                                              \
                      HRESULT hr_create;                                                                                                                                                      \
                      hr_create = CREATE_IFABRICINSTANCE_NAME(IFABRIC_INTERFACE_NAME)(&newInstance);                                                                                          \
                      if (FAILED(hr_create))                                                                                                                                                  \
                      {                                                                                                                                                                       \
                          /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_02_012: [ If creating the new instance of IFABRIC_INTERFACE_NAME fails then H_FABRIC_API(IFABRIC_METHOD_NAME) shall retry using the existing IFABRIC_INTERFACE_NAME. ]*/ \
                          LogHRESULTError(hr_create, "failure in CREATE_IFABRICINSTANCE_NAME(" MU_TOSTRING(IFABRIC_INTERFACE_NAME) ")(&newInstance=%p)", &newInstance);                       \
                          /*keep retrying until timeout*/                                                                                                                                     \
                      }                                                                                                                                                                       \
                      else                                                                                                                                                                    \
                      {                                                                                                                                                                       \
                          /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_02_013: [ Otherwise H_FABRIC_API(IFABRIC_METHOD_NAME) shall release the existing instance and shall retry using new newly created IFABRIC_INTERFACE_NAME. ]*/ \
                          /*let go of the old instance*/                                                                                                                                      \
                          (void)handle->This->lpVtbl->Release(handle->This);                                                                                                                  \
                                                                                                                                                                                              \
                          /*replace it with the new instance*/                                                                                                                                \
                          handle->This = newInstance;                                                                                                                                         \
                      }                                                                                                                                                                       \
                  }                                                                                                                                                                           \
                  else if (0 RESULTS_CHECK(permanent_failures))                                                                                                                               \
                  {                                                                                                                                                                           \
                      /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_42_001: [ If the result is any value from permanent_failures then H_FABRIC_API(IFABRIC_METHOD_NAME) shall return. ]*/              \
                      break;                                                                                                                                                                  \
                  }                                                                                                                                                                           \
                  else                                                                                                                                                                        \
                  {                                                                                                                                                                           \
                      /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_02_014: [ If the result is any other value except FABRIC_E_OBJECT_CLOSED, FABRIC_E_GATEWAY_NOT_REACHABLE or E_ABORT then H_FABRIC_API(IFABRIC_METHOD_NAME) shall retry. ]*/ \
                      /*some other HRESULT, so retry without re-creating the object*/                                                                                                         \
                  }                                                                                                                                                                           \
              }                                                                                                                                                                               \
              else                                                                                                                                                                            \
              {                                                                                                                                                                               \
                  /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_02_010: [ If the call succeeds then H_FABRIC_API(IFABRIC_METHOD_NAME) shall succeed and return. ]*/                                    \
                  break;                                                                                                                                                                      \
              }                                                                                                                                                                               \
                                                                                                                                                                                              \
              /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_02_015: [ H_FABRIC_API(IFABRIC_METHOD_NAME) shall sleep msBetweenRetries. ]*/                                                              \
              ThreadAPI_Sleep(handle->msBetweenRetries);                                                                                                                                      \
              retries++;                                                                                                                                                                      \
              elapsed = timer_global_get_elapsed_ms() - startTime;                                                                                                                            \
                                                                                                                                                                                              \
              /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_02_016: [ If the total time spend retrying exceeds timeoutMilliseconds then H_FABRIC_API(IFABRIC_METHOD_NAME) shall return the last error code. ]*/ \
              /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_02_017: [ If the total number of retries exceeds nMaxRetries then H_FABRIC_API(IFABRIC_METHOD_NAME) shall return the last error code. ]*/  \
          } while ((retries < handle->nMaxRetries) && (elapsed < timeoutMilliseconds));                                                                                                       \
                                                                                                                                                                                              \
          if(FAILED(hr))                                                                                                                                                                      \
          {                                                                                                                                                                                   \
              LogHRESULTError(hr, "tried for %" PRIu32 " times in %" PRIu32 "[ms] and it failed", retries, timeoutMilliseconds);                                                              \
          }                                                                                                                                                                                   \
      }                                                                                                                                                                                       \
                                                                                                                                                                                              \
      return hr;                                                                                                                                                                              \
  }
  
  /*this macro expands to a full function definition. The name of the function is H_FABRIC_API(IFABRIC_METHOD_NAME) and it contains the code to run with retries and timeout.*/
  #define H_FABRIC_DEFINE_API(IFABRIC_INTERFACE_NAME, IFABRIC_METHOD_NAME, in_args)                                                                                                           \
      H_FABRIC_DEFINE_API_WITH_RESULTS(IFABRIC_INTERFACE_NAME, IFABRIC_METHOD_NAME, in_args, NONE())
  
  /*this macro expands to a full function definition. The name of the function is H_FABRIC_API(IFABRIC_METHOD_NAME) and it contains the code to run with retries.*/
  #define H_FABRIC_DEFINE_API_NO_SF_TIMEOUT_WITH_RESULTS(IFABRIC_INTERFACE_NAME, IFABRIC_METHOD_NAME, in_args, permanent_failures)                                                            \
  HRESULT H_FABRIC_API(IFABRIC_METHOD_NAME)(H_FABRIC_HANDLE(IFABRIC_INTERFACE_NAME) handle                                                                                                    \
      ARGS_C_DECLARATION(in_args)                                                                                                                                                             \
  )                                                                                                                                                                                           \
  {                                                                                                                                                                                           \
      HRESULT hr; /*also used a result*/                                                                                                                                                      \
      /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_01_001: [ If handle is NULL then H_FABRIC_API(IFABRIC_METHOD_NAME) shall fail and return NULL. ]*/                                                 \
      if (handle == NULL)                                                                                                                                                                     \
      {                                                                                                                                                                                       \
          LogError("invalid " MU_TOSTRING(HANDLE_TYPE) " handle=%p", handle);                                                                                                                 \
          hr = E_POINTER;                                                                                                                                                                     \
      }                                                                                                                                                                                       \
      else                                                                                                                                                                                    \
      {                                                                                                                                                                                       \
          uint32_t retries = 0; /*incremented at every API call - 0 means "it will call once", "1" means it will call 2 times". It is in the name: **re**tries.*/                             \
                                                                                                                                                                                              \
          do                                                                                                                                                                                  \
          {                                                                                                                                                                                   \
              /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_01_002: [ H_FABRIC_API(IFABRIC_METHOD_NAME) shall call IFABRIC_METHOD_NAME on the instance of IFABRIC_INTERFACE_NAME. ]*/                  \
              hr = IFABRIC_METHOD_NAME(handle->This ARGS_C_CALL(in_args));                                                                                                                    \
              if (FAILED(hr))                                                                                                                                                                 \
              {                                                                                                                                                                               \
                  LogHRESULTError(hr, "failure in " MU_TOSTRING(IFABRIC_METHOD_NAME) "(handle->This=%p, ...)",                                                                                \
                      handle->This);                                                                                                                                                          \
                                                                                                                                                                                              \
                  /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_01_004: [ If the result is FABRIC_E_OBJECT_CLOSED, FABRIC_E_GATEWAY_NOT_REACHABLE or E_ABORT then H_FABRIC_API(IFABRIC_METHOD_NAME) shall create a new instance of IFABRIC_INTERFACE_NAME. ]*/ \
                  if ((hr == E_ABORT) || (hr == FABRIC_E_OBJECT_CLOSED) || (hr == FABRIC_E_GATEWAY_NOT_REACHABLE))                                                                            \
                  {                                                                                                                                                                           \
                      IFABRIC_INTERFACE_NAME* newInstance = NULL;                                                                                                                             \
                                                                                                                                                                                              \
                      HRESULT hr_create;                                                                                                                                                      \
                      hr_create = CREATE_IFABRICINSTANCE_NAME(IFABRIC_INTERFACE_NAME)(&newInstance);                                                                                          \
                      if (FAILED(hr_create))                                                                                                                                                  \
                      {                                                                                                                                                                       \
                          /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_01_005: [ If creating the new instance of IFABRIC_INTERFACE_NAME fails then H_FABRIC_API(IFABRIC_METHOD_NAME) shall retry using the existing IFABRIC_INTERFACE_NAME. ]*/ \
                          LogHRESULTError(hr_create, "failure in CREATE_IFABRICINSTANCE_NAME(" MU_TOSTRING(IFABRIC_INTERFACE_NAME) ")(&newInstance=%p)", &newInstance);                       \
                          /*keep retrying until retry count is exceeded*/                                                                                                                                     \
                      }                                                                                                                                                                       \
                      else                                                                                                                                                                    \
                      {                                                                                                                                                                       \
                          /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_01_006: [ Otherwise H_FABRIC_API(IFABRIC_METHOD_NAME) shall release the existing instance and shall retry using new newly created IFABRIC_INTERFACE_NAME. ]*/ \
                          /*let go of the old instance*/                                                                                                                                      \
                          (void)handle->This->lpVtbl->Release(handle->This);                                                                                                                  \
                                                                                                                                                                                              \
                          /*replace it with the new instance*/                                                                                                                                \
                          handle->This = newInstance;                                                                                                                                         \
                      }                                                                                                                                                                       \
                  }                                                                                                                                                                           \
                  else if (0 RESULTS_CHECK(permanent_failures))                                                                                                                               \
                  {                                                                                                                                                                           \
                      /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_42_002: [ If the result is any value from permanent_failures then H_FABRIC_API(IFABRIC_METHOD_NAME) shall return. ]*/              \
                      break;                                                                                                                                                                  \
                  }                                                                                                                                                                           \
                  else                                                                                                                                                                        \
                  {                                                                                                                                                                           \
                      /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_01_007: [ If the result is any other value except FABRIC_E_OBJECT_CLOSED, FABRIC_E_GATEWAY_NOT_REACHABLE or E_ABORT then H_FABRIC_API(IFABRIC_METHOD_NAME) shall retry. ]*/ \
                      /*some other HRESULT, so retry without re-creating the object*/                                                                                                         \
                  }                                                                                                                                                                           \
              }                                                                                                                                                                               \
              else                                                                                                                                                                            \
              {                                                                                                                                                                               \
                  /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_01_003: [ If the call succeeds then H_FABRIC_API(IFABRIC_METHOD_NAME) shall succeed and return. ]*/                                    \
                  break;                                                                                                                                                                      \
              }                                                                                                                                                                               \
                                                                                                                                                                                              \
              /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_01_008: [ H_FABRIC_API(IFABRIC_METHOD_NAME) shall sleep msBetweenRetries. ]*/                                                              \
              ThreadAPI_Sleep(handle->msBetweenRetries);                                                                                                                                      \
              retries++;                                                                                                                                                                      \
                                                                                                                                                                                              \
              /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_01_009: [ If the total number of retries exceeds nMaxRetries then H_FABRIC_API(IFABRIC_METHOD_NAME) shall return the last error code. ]*/  \
          } while (retries < handle->nMaxRetries);                                                                                                                                            \
                                                                                                                                                                                              \
          if(FAILED(hr))                                                                                                                                                                      \
          {                                                                                                                                                                                   \
              LogHRESULTError(hr, "tried for %" PRIu32 " times and it failed", retries);                                                                                                      \
          }                                                                                                                                                                                   \
      }                                                                                                                                                                                       \
                                                                                                                                                                                              \
      return hr;                                                                                                                                                                              \
  }
  
  /*this macro expands to a full function definition. The name of the function is H_FABRIC_API(IFABRIC_METHOD_NAME) and it contains the code to run with retries.*/
  #define H_FABRIC_DEFINE_API_NO_SF_TIMEOUT(IFABRIC_INTERFACE_NAME, IFABRIC_METHOD_NAME, in_args)                                                                                             \
      H_FABRIC_DEFINE_API_NO_SF_TIMEOUT_WITH_RESULTS(IFABRIC_INTERFACE_NAME, IFABRIC_METHOD_NAME, in_args, NONE())
  
  /*this macro introduces the declaration for _create for the IFabric type wrapper*/                                                                                                          \
  #define H_FABRIC_DECLARE_CREATE(IFABRIC_INTERFACE_NAME)                                                                                                                                     \
      MOCKABLE_FUNCTION(, H_FABRIC_HANDLE(IFABRIC_INTERFACE_NAME), H_FABRIC_HANDLE_CREATE(IFABRIC_INTERFACE_NAME), uint32_t, nMaxRetries, uint32_t, msBetweenRetries);                        \
  
  /*this macro introduces the definition for _create of for the IFabric type wrapper*/
  #define H_FABRIC_DEFINE_CREATE(IFABRIC_INTERFACE_NAME)                                                                                                                                      \
  H_FABRIC_HANDLE(IFABRIC_INTERFACE_NAME) H_FABRIC_HANDLE_CREATE(IFABRIC_INTERFACE_NAME)(uint32_t nMaxRetries, uint32_t msBetweenRetries)                                                     \
  {                                                                                                                                                                                           \
      H_FABRIC_HANDLE(IFABRIC_INTERFACE_NAME) result;                                                                                                                                         \
      /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_02_001: [ H_FABRIC_HANDLE_CREATE(IFABRIC_INTERFACE_NAME) shall allocate memory to hold nMaxRetries, msBetweenRetries and an instance of IFABRIC_INTERFACE_NAME. ]*/ \
      result = malloc(sizeof(H_FABRIC_HANDLE_STRUCT_TYPE(IFABRIC_INTERFACE_NAME)));                                                                                                           \
      if (result == NULL)                                                                                                                                                                     \
      {                                                                                                                                                                                       \
          /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_02_003: [ If there are any failures then H_FABRIC_HANDLE_CREATE(IFABRIC_INTERFACE_NAME) shall fail and return NULL. ]*/                        \
          LogError("failure in malloc(sizeof(" MU_TOSTRING(H_FABRIC_HANDLE_STRUCT_TYPE(IFABRIC_INTERFACE_NAME)) ")=%zu)", sizeof(H_FABRIC_HANDLE_STRUCT_TYPE(IFABRIC_INTERFACE_NAME)));       \
          /*return as is*/                                                                                                                                                                    \
      }                                                                                                                                                                                       \
      else                                                                                                                                                                                    \
      {                                                                                                                                                                                       \
          result->This = NULL;                                                                                                                                                                \
          /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_02_002: [ H_FABRIC_HANDLE_CREATE(IFABRIC_INTERFACE_NAME) shall create a new instance of IFABRIC_INTERFACE_NAME by calling CREATE_IFABRICINSTANCE_NAME(IFABRIC_INTERFACE_NAME). ]*/ \
          HRESULT hr = CREATE_IFABRICINSTANCE_NAME(IFABRIC_INTERFACE_NAME)(&result->This);                                                                                                    \
          if (FAILED(hr))                                                                                                                                                                     \
          {                                                                                                                                                                                   \
              /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_02_003: [ If there are any failures then H_FABRIC_HANDLE_CREATE(IFABRIC_INTERFACE_NAME) shall fail and return NULL. ]*/                    \
              LogHRESULTError(hr, "failure in CREATE_IFABRICINSTANCE_NAME(" MU_TOSTRING(IFABRIC_INTERFACE_NAME) ")(&result->This=%p))", &result->This);                                       \
          }                                                                                                                                                                                   \
          else                                                                                                                                                                                \
          {                                                                                                                                                                                   \
              result->nMaxRetries = nMaxRetries;                                                                                                                                              \
              result->msBetweenRetries = msBetweenRetries;                                                                                                                                    \
              goto allok;                                                                                                                                                                     \
          }                                                                                                                                                                                   \
          free(result);                                                                                                                                                                       \
          result = NULL;                                                                                                                                                                      \
      }                                                                                                                                                                                       \
  allok:                                                                                                                                                                                      \
      return result;                                                                                                                                                                          \
  }                                                                                                                                                                                           \
  
  
  /*this macro introduces the declaration for _destroy for the IFabric type wrapper*/
  #define H_FABRIC_DECLARE_DESTROY(IFABRIC_INTERFACE_NAME)                                                                                                                                    \
      MOCKABLE_FUNCTION(, void, H_FABRIC_HANDLE_DESTROY(IFABRIC_INTERFACE_NAME), H_FABRIC_HANDLE(IFABRIC_INTERFACE_NAME), handle);                                                            \
  
  /*this macro introduces the definition for _destroy of for the IFabric type wrapper*/
  #define H_FABRIC_DEFINE_DESTROY(IFABRIC_INTERFACE_NAME)                                                                                                                                     \
  void H_FABRIC_HANDLE_DESTROY(IFABRIC_INTERFACE_NAME)(H_FABRIC_HANDLE(IFABRIC_INTERFACE_NAME) handle)                                                                                        \
  {                                                                                                                                                                                           \
      if (handle == NULL)                                                                                                                                                                     \
      {                                                                                                                                                                                       \
          /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_02_004: [ If handle is NULL then H_FABRIC_HANDLE_DESTROY(IFABRIC_INTERFACE_NAME) shall return. ]*/                                             \
          LogError("invalid arguments " MU_TOSTRING(H_FABRIC_HANDLE(IFABRIC_INTERFACE_NAME)) " handle=%p", handle);                                                                           \
      }                                                                                                                                                                                       \
      else                                                                                                                                                                                    \
      {                                                                                                                                                                                       \
          /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_02_005: [ H_FABRIC_HANDLE_DESTROY(IFABRIC_INTERFACE_NAME) shall call ->Release() on the instance of IFABRIC_INTERFACE_NAME. ]*/                \
          (void)handle->This->lpVtbl->Release(handle->This);                                                                                                                                  \
          /*Codes_SRS_H_FABRIC_MACRO_GENERATOR_02_006: [ H_FABRIC_HANDLE_DESTROY(IFABRIC_INTERFACE_NAME) shall free the allocated memory. ]*/                                                 \
          free(handle);                                                                                                                                                                       \
      }                                                                                                                                                                                       \
  }                                                                                                                                                                                           \
  
  
  
  #endif /*H_FABRIC_MACRO_GENERATOR_H*/
  
  