Creating COM servers with CMake

I have recently come across a problem when I needed to use CMake to create a visual studio ATL COM Dll project using the MIDL compiler. I haven’t found an example anywhere I looked that provides a fully working solution, only bits and pieces here and there. So here I am posting a fully working example.

I know that CMake is intended for cross platform projects and ATL and COM are far from portable, but this is also the reason why there is no or very little support for Microsoft specific solutions in CMake. I personally do not like this, I would like to see builtin support for ATL (if there is support for MFC) or event for c#.

The CMakeLists.txt file below solves two main issues:

  1. It finds the VS2010 ATL include folder on your computer
  2. and it tells VS that it should use the midl compiler for IDL files.

Please note that the files below are almost the same as if they were generated by the VS ATL wizard with one exception – the generated dllmain.cpp file is merged into ComServerSample.cpp and dllmain.h is merged into ComServerSample.h.

You can access the full source code here.

Register the build output:

>regsvr32 ComServerSample.dll

Then you will be able to find the registered component in the registry by searcing for the CLSID:

regedit

Here is the source for the CMakeLists.txt file:

# Builds the DVEventListener as a dynamic library.

project( ComServerSample )

cmake_minimum_required(VERSION 2.8)

if (NOT VC_DIR)
	if (MSVC10)
        GET_FILENAME_COMPONENT(VS_DIR "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0\\Setup\\VS;ProductDir]" REALPATH CACHE)
    else()
        message("!! Could not find VS 2010 DIR!")
    endif()
    set(VC_DIR ${VS_DIR}/VC CACHE STRING "Visual Studio VC directory path")
endif()
MACRO (MACRO_ADD_FILE_DEPENDENCIES _file)
   get_source_file_property(_deps ${_file} OBJECT_DEPENDS)
   if (_deps)
      set(_deps ${_deps} ${ARGN})
   else ()
      set(_deps ${ARGN})
   endif ()
   set_source_files_properties(${_file} PROPERTIES OBJECT_DEPENDS "${_deps}")
ENDMACRO ()

MACRO (MACRO_ADD_INTERFACES _output_list)
  FOREACH(_in_FILE ${ARGN})
    GET_FILENAME_COMPONENT(_out_FILE ${_in_FILE} NAME_WE)
    GET_FILENAME_COMPONENT(_in_PATH ${_in_FILE} PATH)

    SET(_out_header_name ${_out_FILE}_h.h)
    SET(_out_header ${CMAKE_CURRENT_SOURCE_DIR}/${_out_header_name})
    SET(_out_iid_name ${_out_FILE}.c)
	SET(_out_iid ${CMAKE_CURRENT_SOURCE_DIR}/${_out_iid_name})
    message("_out_header_name=${_out_header_name}, _out_header=${_out_header}, _out_iid=${_out_iid}")
    ADD_CUSTOM_COMMAND(
      OUTPUT ${_out_header} ${_out_iid}
      DEPENDS ${_in_FILE}
      COMMAND midl /header ${_out_header_name} /iid ${_out_iid_name} ${_in_FILE}
      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    )

    MACRO_ADD_FILE_DEPENDENCIES(
      ${_out_header}
      ${_in_FILE}
    )

    SET_SOURCE_FILES_PROPERTIES(
      ${_out_header}
      ${_out_iid}
      PROPERTIES
      GENERATED TRUE
    )
    SET_SOURCE_FILES_PROPERTIES(${_in_FILE} PROPERTIES HEADER_FILE_ONLY TRUE)

    SET(${_output_list} ${${_output_list}}
      ${_out_header}
      ${_out_iid}
    )

  ENDFOREACH(_in_FILE ${ARGN})

ENDMACRO (MACRO_ADD_INTERFACES)

include_directories("${VC_DIR}/atlmfc/include")

set(ATLLIB  "debug"     "${VC_DIR}/atlmfc/lib/atlsd.lib"
			"optimized" "${VC_DIR}/atlmfc/lib/atls.lib")

set(PROJECT_IDL_FILES				ComServerSample.idl )

set(COMSERVERSAMPLE_HEADER_FILES	resource.h
									ComServerSample.h
									MyComClass.h
									ComServerSampleComSupport.h )

set(COMSERVERSAMPLE_SOURCE_FILES	ComServerSample.cpp
									MyComClass.cpp
									ComServerSample.def
									ComServerSample.rc
									ComServerSample.rgs
									MyComClass.rgs )

MACRO_ADD_INTERFACES(GENERATED_FILES_IDL ${PROJECT_IDL_FILES})

SOURCE_GROUP("IDL" FILES ${GENERATED_FILES_IDL} ${PROJECT_IDL_FILES})

add_library(ComServerSample	SHARED
									${COMSERVERSAMPLE_HEADER_FILES}
									${COMSERVERSAMPLE_SOURCE_FILES}
									${PROJECT_IDL_FILES}
									${GENERATED_FILES_IDL})

#set_target_properties(ComServerSample PROPERTIES AUTOMOC true)

target_link_libraries( ComServerSample )
Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s