Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Calliing C++ Routine

JohnNichols
Valued Contributor III
1,753 Views
Dear Steve:

The routine I have been trying to call from Fortran as an interface to C, in this case now C++, resides in a library called SETUPAPI.

SetupAPI is found in the SDK and DDK for Windows 7 available from Microsoft as a separate download.

Unfortunately, as I have slowly learned in translating a C DDK Program to a VS2010 C++ program and then using the programto access the USB device,one needs to reference or in mycase it is easier to add the missing library and header files to VS2010. I use a pragma lib command to reference the libraries in C++.

How do I do the same thing in Fortran so the libary is found by the linker? I have tried several variations in the linker options and directories but I still get the routine not found error. I got the same error in C++ until someone at OSR Forums pointed out my mistake.

Regards

JMN
0 Kudos
15 Replies
mecej4
Honored Contributor III
1,753 Views
Place the following directive in one of your sources:

!DEC$ OBJCOMMENT LIB:'SETUPAPI.LIB'
0 Kudos
JohnNichols
Valued Contributor III
1,753 Views
No that did not work, I tried the different versions of the SETUPAPI libraries in with the Fortran libaries in INTEL Composer.

A bit frustrating this problem.

JMN
0 Kudos
Steven_L_Intel1
Employee
1,753 Views
You will need to make sure that you are declaring the routines the way the library expects. That means STDCALL (most likely) and mixed-case. You should be able to read the declaration in the .h to see what it is expecting.
0 Kudos
JohnNichols
Valued Contributor III
1,753 Views
So looking at the setupapi.h

The definition is below: HDEVINFO is a PVOID:
---------------------------------------------------------------
PCSTR is a

A pointer to a constant null-terminated string of 8-bit Windows (ANSI) characters. For more information, see Character Sets Used By Fonts.

This type is declared in WinNT.h as follows:

typedef CONST CHAR *PCSTR;

-------------------------------------------------------------------
GUID
typedef struct _GUID {
DWORD Data1;
WORD Data2;
WORD Data3;
BYTE Data4[8];
} GUID;

-------------------------------------------------------------------
[bash]__checkReturn
WINSETUPAPI
HDEVINFO
WINAPI
SetupDiGetClassDevsA(
    __in_opt CONST GUID *ClassGuid,
    __in_opt PCSTR Enumerator,
    __in_opt HWND hwndParent,
    __in DWORD Flags
    );

__checkReturn
WINSETUPAPI
HDEVINFO
WINAPI
SetupDiGetClassDevsW(
    __in_opt CONST GUID *ClassGuid,
    __in_opt PCWSTR Enumerator,
    __in_opt HWND hwndParent,
    __in DWORD Flags
    );

#ifdef UNICODE
#define SetupDiGetClassDevs SetupDiGetClassDevsW
#else
#define SetupDiGetClassDevs SetupDiGetClassDevsA
#endif




[/bash]
0 Kudos
Steven_L_Intel1
Employee
1,753 Views
Ok, you would need something like this:

[fortran]interface
function SetupDiGetClassDevs (ClassGuid, Enumerator, hwndParent, Flags)
use IFWINTY
!DEC$ ATTRIBUTES DEFAULT,STDCALL,DECORATE,ALIAS:"SetupDiGetClassDevsA" :: SetupDiGetClassDevs
integer(PVOID) :: SetupDiGetClassDevs ! Function return
type(T_GUID), intent(in) :: ClassGuid
!DEC$ ATTRIBUTES REFERENCE, ALLOW_NULL :: ClassGuid
character(*), intent(in) :: Enumerator
!DEC$ ATTRIBUTES REFERENCE, ALLOW_NULL :: Enumerator
integer(HANDLE), intent(in) :: hwndParent
integer(DWORD), intent(in) :: Flags
end function SetupDiGetClassDevs
end interface[/fortran]
0 Kudos
JohnNichols
Valued Contributor III
1,753 Views
Steve:

Thanks I will try it at home tonight. I can only get the card to work on a 32 bit machine. I had just spent a few hours tracking down through the *.h files looking for the definitions. I had got to PVOID.

MSDN has been updated since the release of WIN8 CTP. Colour changes are nice.

VS2011 CTP is clearly released, I am wondering when the first person will ask you if Fortran works? I am not asking that question. After the last two weeks of gettting one sample from VS to work with the board it was written for, I am amazed your people can get IF to work with MS Studio. They must have freaking nightmares about lost pointers etc.

My questions are:

1. Does Fortran only use ASCII and not W characters?
2. DEC$ ATTRIBUTES DEFAULT,STDCALL,REFERENCE,DECORATE,ALIAS:"SetupDiGetClassDevsA" :: SetupDiGetClassDevs ?? What does decorate mean?

Regards

JMN

0 Kudos
Steven_L_Intel1
Employee
1,753 Views
We work closely with Microsoft's Visual Studio team. Do not expect Intel Fortran to work with new VS versions until we claim support - there's always something we have to do. But with our new VS2010 support it should be easier.

Intel Fortran does not directly support wide characters. You can fake it with arrays of INTEGER(2), but we don't at present provide declarations for those.

Here's an explanation of the various attributes:

DEFAULT - makes this immune to command line changes such as /iface and /names
STDCALL - uses the STDCALL convention and also changes default to be pass by value
REFERENCE - I should not have added this - please remove it
DECORATE - applies the appropriate "name decoration" for the platform and calling convention, so you don't have to fuss with leading underscores or trailing @n

I have edited my reply above to correct some errors.
0 Kudos
JohnNichols
Valued Contributor III
1,753 Views
Dear Steve:

Thanks for your help with the Calling of the C++ routines.

Clearly setupapi interfaceis such an arcane art that only a few brave souls, who mainly live at OSRONLINE and who talk a very arcane language that is very hard to understand, survive in this frigid world.

Interestinglywith a passion they seem to hate Visual Studio and I never mentioned Fortran, I am not that brave. But they helped me get theboard running in C++ with VS 2010.

I had just got theC++ sorted out to access the board and Microsoft announced therelease of WIN8 with VS 2011, which includes the device driver kit now. The few brave souls went into melt down land and uniformly cursed Microsoft for the change, except for the Microsoft people.

There are about 200 C++ calls in the board's C++ program, now that I understand "a smidgen" of C++ it is not worth your time or my time to play with something that works.

JMN

0 Kudos
JohnNichols
Valued Contributor III
1,753 Views
Dear Steve:

I am sure the Intel people work closely with Microsoft. My wife's brother works for Intel and he says they take the software very seriously. I enclose the final code that worked. Unfortunately Enumerator is also a reserved word so I had had to make it enumerator1, otherwise it will not link.

T_GUID also gives an error you need to use GUID only.

JMN

[bash]interface
function SetupDiGetClassDevs (ClassGuid, Enumerator1, hwndParent, Flags)
use IFWINTY
!DEC$ ATTRIBUTES DEFAULT,STDCALL,DECORATE,ALIAS:"SetupDiGetClassDevsA" :: SetupDiGetClassDevs
integer(PVOID) :: SetupDiGetClassDevs ! Function return
type(GUID), intent(in) :: ClassGuid
!DEC$ ATTRIBUTES REFERENCE, ALLOW_NULL :: ClassGuid
character(*), intent(in) :: Enumerator1
!DEC$ ATTRIBUTES REFERENCE, ALLOW_NULL :: Enumerator1
integer(HANDLE), intent(in) :: hwndParent
integer(DWORD), intent(in) :: Flags
end function SetupDiGetClassDevs
end interface
    [/bash]
0 Kudos
JohnNichols
Valued Contributor III
1,753 Views
Dear Steve:

If you use GUID as the type you have no problem,

even through IF defines, T_GUID, the interfaces I have looked at in IFWINTY and other files only use GUID as the type.

The IVF compiler does not like T_GUID. Sample from the def and a use included below.

Interesting, but is there somewhere you define the GUID?

Not a problem now I know.

JMN
[bash]TYPE T_GUID
     SEQUENCE
       integer(ULONG) Data1 ! knowns  unsigned long 
       integer(USHORT) Data2 ! knowns  unsigned short 
       integer(USHORT) Data3 ! knowns  unsigned short 
!DEC$ IF DEFINED(__KEEP_OLD_CHARACTER_ARRAYS)
       character(UCHAR) Data4(8) ! knowns  unsigned char 
!DEC$ ELSE
       character(8) Data4
!DEC$ ENDIF
     END TYPE[/bash]
[bash]  INTERFACE

	FUNCTION CoRegisterClassObject( &
						rclsid,		& ! Class identifier (CLSID) to be registered
						pUnk,		& ! Pointer to the class object
						dwClsContext, & ! Context for running executable code
						flags,      & ! How to connect to the class object
						lpdwRegister) ! Pointer to the value returned
          use ifwinty
          integer(4) :: CoRegisterClassObject ! HRESULT
!DEC$ ATTRIBUTES DEFAULT :: CoRegisterClassObject
!DEC$IF DEFINED(_X86_)
!DEC$ ATTRIBUTES STDCALL, ALIAS:'_CoRegisterClassObject@20' :: CoRegisterClassObject
!DEC$ ELSE
!DEC$ ATTRIBUTES STDCALL, ALIAS:'CoRegisterClassObject' :: CoRegisterClassObject
!DEC$ ENDIF
          TYPE (GUID), INTENT(IN)			:: rclsid 
          !DEC$ ATTRIBUTES REFERENCE		:: rclsid
          integer(LPVOID), intent(in)       :: pUnk
          !DEC$ ATTRIBUTES VALUE            :: pUnk
          integer(DWORD), intent(in)        :: dwClsContext
          !DEC$ ATTRIBUTES VALUE            :: dwClsContext
          integer(DWORD), intent(in)        :: flags
          !DEC$ ATTRIBUTES VALUE            :: flags
          integer(DWORD), intent(out)       :: lpdwRegister
          !DEC$ ATTRIBUTES REFERENCE        :: lpdwRegister
	END FUNCTION CoRegisterClassObject

	FUNCTION CoRevokeClassObject( &
						dwRegister) ! Pointer to the value returned
          use ifwinty
          integer(4) :: CoRevokeClassObject ! HRESULT
!DEC$ ATTRIBUTES DEFAULT :: CoRevokeClassObject
!DEC$IF DEFINED(_X86_)
!DEC$ ATTRIBUTES STDCALL, ALIAS:'_CoRevokeClassObject@4' :: CoRevokeClassObject
!DEC$ ELSE
!DEC$ ATTRIBUTES STDCALL, ALIAS:'CoRevokeClassObject' :: CoRevokeClassObject
!DEC$ ENDIF
          integer(DWORD), intent(in)       :: dwRegister
          !DEC$ ATTRIBUTES VALUE           :: dwRegister
	END FUNCTION CoRevokeClassObject

	FUNCTION CoResumeClassObjects()
          use ifwinty
          integer(4) :: CoResumeClassObjects ! HRESULT
!DEC$ ATTRIBUTES DEFAULT :: CoResumeClassObjects
!DEC$IF DEFINED(_X86_)
!DEC$ ATTRIBUTES STDCALL, ALIAS:'_CoResumeClassObjects@0' :: CoResumeClassObjects
!DEC$ ELSE
!DEC$ ATTRIBUTES STDCALL, ALIAS:'CoResumeClassObjects' :: CoResumeClassObjects
!DEC$ ENDIF
	END FUNCTION CoResumeClassObjects

	FUNCTION CoAddRefServerProcess()
          use ifwinty
          integer(ULONG) :: CoAddRefServerProcess
!DEC$ ATTRIBUTES DEFAULT :: CoAddRefServerProcess
!DEC$IF DEFINED(_X86_)
!DEC$ ATTRIBUTES STDCALL, ALIAS:'_CoAddRefServerProcess@0' :: CoAddRefServerProcess
!DEC$ ELSE
!DEC$ ATTRIBUTES STDCALL, ALIAS:'CoAddRefServerProcess' :: CoAddRefServerProcess
!DEC$ ENDIF
	END FUNCTION CoAddRefServerProcess

	FUNCTION CoReleaseServerProcess()
          use ifwinty
          integer(ULONG) :: CoReleaseServerProcess
!DEC$ ATTRIBUTES DEFAULT :: CoReleaseServerProcess
!DEC$IF DEFINED(_X86_)
!DEC$ ATTRIBUTES STDCALL, ALIAS:'_CoReleaseServerProcess@0' :: CoReleaseServerProcess
!DEC$ ELSE
!DEC$ ATTRIBUTES STDCALL, ALIAS:'CoReleaseServerProcess' :: CoReleaseServerProcess
!DEC$ ENDIF
	END FUNCTION CoReleaseServerProcess

  end interface[/bash]


0 Kudos
Steven_L_Intel1
Employee
1,753 Views
There are no reserved words in Fortran. Please show me the error if you use "Enumerator".
0 Kudos
JohnNichols
Valued Contributor III
1,753 Views
Steve:

I changed the Enumerator back from Enumerator1, and did not generate an error. My apoligies, I mad a mistake.

But enumerator is defined in Fortran:
IVF lists it with bue colour in the text editor and the following is in help. This is why I changed the code, I must have picked up the GUID change at the same time.

JMN

[bash]An enumeration defines the name of a group of related values and the name of each value within the group. It takes the following form:

ENUM, BIND(C)

    ENUMERATOR [ :: ] c1 [= expr][, c2 [= expr]]...

    [ENUMERATOR [ :: ] c3 [= expr][, c4 [= expr]]...]...

END ENUM

c1,c2,c3,c4
 Is the name of the enumerator being defined.
 
expr
 Is an optional scalar integer initialization expression specifying the value for the enumerator.
 

If = appears in an enumerator, a double-colon separator must appear before the enumerator or list of enumerators.

[/bash]
0 Kudos
Steven_L_Intel1
Employee
1,753 Views
Yes, ENUMERATOR is a keyword in Fortran, but it is not a "reserved word". In Fortran, you can have user identifiers that are the same as keywords. There are no reserved words in Fortran. Yes, the source editor does not consider context and will highlight the word wherever it appears.
0 Kudos
JohnNichols
Valued Contributor III
1,753 Views
Steve:

But it is poor programming to use a keyword, it can mask what you are doing to others who come along later.

JMN
0 Kudos
Steven_L_Intel1
Employee
1,752 Views
It depends - if the word makes sense, then use it. But one can go a bit overboard - see attached.
0 Kudos
Reply