Home > Software engineering >  WINAPI in function signature causes errors
WINAPI in function signature causes errors

Time:09-10

Though I have spent some years in other languages, my ability in C is somewhat limited. I currently have a broad goal to figure out how to use a C dll as a function in Excel. This question though is focused on a more narrow area of difficulty in trying to achieve this goal. I am following a tutorial found here. I have created the required files below. These files are based on the tutorial files, but with slight modifications for testing purposes.

SquareLib/SquareLib/SquareLib.h

 #pragma once
  
 #ifdef SQUARELIB_EXPORTS
 #define SQUARELIB_API __declspec(dllexport)
 #else
 #define SQUARELIB_API __declspec(dllimport)
 #endif
  
  
 extern "C" SQUARELIB_API double square_double(double x);
 extern "C" SQUARELIB_API double square_winapi(double* x);

SquareLib/SquareLib/SquareLib.cpp

#include "pch.h"
#include "SquareLib.h"

double square_double(double x){
    return x * x;
}
double WINAPI square_winapi(double* x){
    return *x * *x;
}

Coming from other languages, double WINAPI in the SquareLib.cpp source file looks like it might be a return type, and at the very least part of the function signature. Therefore, I don't understand why WINAPI is not duplicated in the header file prototype so that the square_winapi() prototype looks like the line below.

extern "C" SQUARELIB_API double WINAPI square_winapi(double* x);

I have also found that Visual Studio will not compile this unless this change is made. However, even if I do make this change and successfully compile the dll, I have discovered other errors if the resulting dll is used.

First, trying to use the dll in Excel as the tutorial explains seems to result in garbage data that Excel doesn't understand. To understand what is happening, I have created a C client program that might eventually be able to receive the dll data from get_square_winapi() and check whether it is null, a string, an empty value, or whatever it might be.

SquareClient/SquareClient/SquareClient.cpp

#include <iostream>
#include "SquareLibrary.h"

void printSquare() {
    double factor = 4.1;
    double result = square_double(factor);
    std::cout << "The square of " << factor << " is " << result << std::endl;
}

int main() {
    printSquare();
}

Right now, all this does is use the square_double() function. This client program works fine as long as the winapi prototype and function in SquareLib.h and SquareLib.cpp are commented out. For some reason I don't understand, the winapi prototype/function breaks this code.

C2146 syntax error: missing ';' before identifier 'square_winapi' File: SquareLib.h
C4430 missing type specifier - int assumed.  Note: C   does not support default-int File: SquareLib.h

Why does this happen? How do I fix this?

CodePudding user response:

Coming from other languages, double WINAPI in the SquareLib.cpp source file looks like it might be a return type

Only the double is the return value. WINAPI is a preprocessor macro that resolves to __stdcall, ie it is the calling convention of the function, not part of the return type.

and at the very least part of the function signature.

Correct.

Therefore, I don't understand why WINAPI is not duplicated in the header file prototype

Like any part of the function signature, the calling convention needs to be present in both the declaration and implementation of the function. So, you are correct that you will need to use the following in the SquareLib.h file:

extern "C" SQUARELIB_API double WINAPI square_winapi(double* x);

If you don't specify a calling convention, the compiler's default will be used, which is usually __cdecl, but can be specified in the compiler's configuration, so be aware of that. As such, you should always be explicit about the calling convention used when defining code that will be used across module/language boundaries.

This client program works fine as long as the winapi prototype and function in SquareLib.h and SquareLib.cpp are commented out. For some reason I don't understand, the winapi prototype/function breaks this code. Why does this happen? How do I fix this?

WINAPI is defined in windef.h, which is #include'd by windows.h, which you need to #include in any code that interacts with the Win32 API. If you are not #include'ing windows.h in your PCH, then you can just use __stcall directly instead of using WINAPI at all:

extern "C" SQUARELIB_API double __stdcall square_winapi(double* x);
double __stdcall square_winapi(double* x){
    return *x * *x;
}
  • Related