Page 1 of 1

SerialPort Class Using CreateObject (...)

Posted: Wed Jul 08, 2009 12:39 pm
by angelo.c
Hello All


I was wondering if anyone has had some success in using the Class SerialPort in the System.IO.Ports Namespace
using FWH CreateObject(...) routine.



I have used the following with success:
//The following all work
//cTry := "ScriptPW.Password"
//cTry := "ADODB.Connection"
//cTry := "CDO.Message"
//cTry := "Wscript.Shell"
//cTry := "InternetExplorer.Application"
cTry := "OUTLOOK.APPLICATION"
try
oLoc := CreateObject( cTry )
catch
MsgAlert("Error from Try/Catch: CreateObject( " + cTry + " ) ")
end

with:
FWH 9.05
xHarbour Compiler build 1.2.1 (SimpLex) (Rev. 6406)
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland


I have tried with NO success the following:
CreateObject("System.Serialport"), CreateObject("System.IO.Ports"), CreateObject("SerialPort" ),
CreateObject("System.ComponentModel.component.SerialPort"), CreateObject("SerialPort.application"),
CreateObject("System.IO")

Does anyone know the correct string to use?

For background information I have provided the following which is extracted from:
MSDN .NET Framework Developer Center at:
http://msdn.microsoft.com/en-us/library ... lport.aspx
SerialPort Class
Represents a serial port resource.

Namespace: System.IO.Ports
Assembly: System (in System.dll)

[SNIP]

Remarks
Use this class to control a serial port file resource. This class provides synchronous and event-driven I/O, access to pin and break states, and access to serial driver properties. Additionally, the functionality of this class can be wrapped in an internal Stream object, accessible through the BaseStream property, and passed to classes that wrap or use streams.
[SNIP]
Best Regards,
Angelo.c

Re: SerialPort Class Using CreateObject (...)

Posted: Mon Jul 13, 2009 3:10 pm
by byron.hopp
I believe that the problem is that CreateObject is used to create a comm object, and you are attempting to create this object from a dot.net namespace. I don't think this is going to work. I have not been on this board for a while but I don't believe that FiveWin supports the dot.net framework. In fact many people probably use FiveWin just to avoid the dot.net framework :-)

Thanks,

Byron...

Re: SerialPort Class Using CreateObject (...)

Posted: Sun Jul 19, 2009 3:29 am
by angelo.c
Hello all.

Firstly, Thanks Byron for your reply. It confirmed what I thought. However I think it is still useful to access DOT.NET from FWH and so the following .....

Since I last posted this question on this forum for access to MS .NET from FiveWin, I have been working on it. I have established a way that works for me. It is not elegant. It requires a few steps, but it works for me. I would like to return some hopefully useful information to the FiveWin community as all of you have help me a lot in solving and getting new ideas/approaches for my application. In sharing my approach with everyone, I hope that it too could be useful to you. I specifically asked for "SerialPort" help since I am writing a custom hosting interface between a PC and a USB device (in my case, a Bar Code Reader ... essentially a USB interface is a serial port ... see: http://msdn.microsoft.com/en-us/library/aa908437.aspx ).

I use Windows XP Pro. I have download FWH 9.06 and use the supplied xHarbour and Borlandc c/c++ compiler for all my "normal" application developement. This approach should work for previous versions of FWH. For the DOT.NET interface, I use the supplied Harbour/[x]Harbour MS libraries and headers with Visual Studio 2008 c/c++ compiler and linker.

I apoligise for the length of the post but I think the detailed information would be useful to someone.

------------------------------------------------------------------------------------------------------------
In General, the step taken are as follows:
(1) Write a c/c++ wrapper that interfaces with Harbour/[x]Harbour.
I called this module: XBase_IF.cpp
This takes care of the communication between FWH source and low level c/c++ code.
Use the FWH supplied Borland C++ V5.5.1 for Win32 compiler/linker on this module.

(2) Use a MS compiler/linker that *suports* DOT.NET. Earlier versions of Visual c/c++
do not support it. (here is where you write your c/c++ code to communicate with
DOT.NET namespaces and classes
I called this module: cfuncs_vs.cpp

(3) Write your cfuncs_vs.cpp "DOT.NET interface c/c++" code that accesses DOT.NET and
compile with the /clr compiler option.
Use Multi-threaded DLL (/MD) for the runtime library.
Ensure your targetted Framework is .NET Framework V2.0 or above.
Set to generate a DLL (/DLL linker option). I generate a STATIC DLL which means I
link in an import library with the FWH code. I think this is the easiest and safest
way to interface with my FWH code.

(4) Now generate an Import Library from the generated DLL file suitable to link in with FWH.
Use the impdef and implib routines to generate an OMF formatted library from the DLL that
lists/defines all the exported functions in the DLL. Execute the following
impdef cfuncs_vs.def cfuncs_vs.dll
implib cfuncs_vs.lib cfuncs_vs.def

(5) Include "cfuncs_vs.lib" in your make/build file that generates your FWH application

(6) If all goes well there are no unresolved symbols and an .exe file is generated.

(7) That's it. Hopefully you made sense of "this general recipe". In any case I have included
a cut down version showing all the above steps that actually compiles and links on my system
--------------------------------------------------------------------------------
Step (1) Harbour/[x]Harbour c/c++ wrapper source code

Code: Select all

// ===========================================================================
//  XBase_IF.cpp    July 2009 Angelo C
// ============================1===============================================
    
 #include <winten.h>   // More includes than necessary for this cut down version. 
 #include <stdio.h>    // My complete code needs
 #include <Winsock2.h>
 #include <stdlib.h>
 #include <malloc.h>
 #include <lm.h>
 #include <Icmpapi.h>


#include <Windows.h>
#include <psapi.h>

#include "hbapi.h"      //Need so that FWH can pass parameters back/forth
#include "hbapirdd.h"   //btween XBase and c/c++ code
#include "hbapierr.h"
#include "hbapiitm.h"
#include "hbvm.h"
#include "hbset.h"


#ifdef __cplusplus
   extern "C" {
 #endif


 // Prototypes for function in the cfuncs_vs DLL.  Also used for accessing DOT.NET framework
 extern int TEST_NAMESPACE_in_DLL();
 
//This routine is called from FWH as: TEST_NAMESPACE()
HB_FUNC( TEST_NAMESPACE )
 {
  int nResult;
  OutputDebugString_c("\nIn routine: HB_FUNC( TEST_NAMESPACE ).\n");

  nResult = TEST_NAMESPACE_in_DLL();
  OutputDebugString_c(Int2Hex((unsigned int) nResult));

 }


 #ifdef __cplusplus
 }
 #endif
 




Part output from my make file is below:
  • MAKE Version 5.2 Copyright (c) 1987, 2000 Borland
    C:\Borland\BCC55\bin\bcc32 -c -oXBase_IF.obj -DHB_DBG_TRACE

    -ID:\FIVETECH\FWH\include;D:\FIVETECH\xharbour\include;C:\Borland\BCC55\Include;D:\ac\fwhdb_phx\Inc;D:\ac\fwhdb_phx\Source\c_src XBase_IF.cpp
    Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
    Xbase_IF.cpp:
    C:\Borland\BCC55\bin\bcc32 -c -ocfuncs.obj -DHB_DBG_TRACE -ID:\FIVETECH\FWH\include;D:\FIVETECH\xharbour\include;C:\Borland\BCC55\Include;D:\ac\fwhdb_phx\Inc;D:\ac\fwhdb_phx\Source\c_src cfuncs.cpp
--------------------------------------------------------------------------------

Steps (2) and (3) Write your cfuncs_vs.cpp "DOT.NET interface c/c++" code


stdafx.h : include file follows:

Code: Select all

// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//

#pragma once

// The following macros define the minimum required platform.  The minimum required platform
// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run 
// your application.  The macros work by enabling all features available on platform versions up to and 
// including the version specified.

// Modify the following defines if you have to target a platform prior to the ones specified below.
// Refer to MSDN for the latest info on corresponding values for different platforms.
#ifndef WINVER                          // Specifies that the minimum required platform is Windows Vista.
#define WINVER 0x0600           // Change this to the appropriate value to target other versions of Windows.
#endif

#ifndef _WIN32_WINNT            // Specifies that the minimum required platform is Windows Vista.
#define _WIN32_WINNT 0x0600     // Change this to the appropriate value to target other versions of Windows.
#endif

#ifndef _WIN32_WINDOWS          // Specifies that the minimum required platform is Windows 98.
#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
#endif

#ifndef _WIN32_IE                       // Specifies that the minimum required platform is Internet Explorer 7.0.
#define _WIN32_IE 0x0700        // Change this to the appropriate value to target other versions of IE.
#endif


#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>


// TODO: reference additional headers your program requires here
 
--------------------------------------------------------------------
[

dllmain.cpp Source Follows:

Code: Select all

// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"

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;
}
 
--------------------------------------------------------------------

cfuncs_vs.cpp "DOT.NET interface c/c++" Module follows:

Code: Select all


// ===========================================================================
//  c_funcs.cpp               July 2009 Angelo C.
// ============================1===============================================
// cfuncs_vs.cpp : Defines the exported functions for the DLL application.
//  This is CALLED from other C/C++ modules which can be compiled by Borlandc
//  which interfaces with FWH/[x]Harbour source directly using hb_parYYYY, etc functions


// NOTE.  Function names that are called from the Borlandc c/c++ wrapper routine MUST HAVE
//        an underscore "_" included at the start of the name.
//        Borlandc puts this in automatically.
//        SUMMARY. Put "_" at start of routines called from Borlandc Wrapper module
 

#include "stdafx.h"

#define CFUNCS_VS_API __declspec(dllexport)

using namespace System;
 
// Routine converts system strings to another type
// compile with: /clr
#include <string>
#include <iostream>
using namespace std;
using namespace System;

void MarshalString ( String ^ s, string& os ) {
   using namespace Runtime::InteropServices;
   const char* chars = 
      (const char*)(Marshal::StringToHGlobalAnsi(s)).ToPointer();
   os = chars;
   Marshal::FreeHGlobal(IntPtr((void*)chars));
}

void MarshalString ( String ^ s, wstring& os ) {
   using namespace Runtime::InteropServices;
   const wchar_t* chars = 
      (const wchar_t*)(Marshal::StringToHGlobalUni(s)).ToPointer();
   os = chars;
   Marshal::FreeHGlobal(IntPtr((void*)chars));
}

//----------------------------------------------------------------

#ifdef __cplusplus
   extern "C" {
#endif


#using <System.dll>

//A Test for this namespace
CFUNCS_VS_API int _TEST_NAMESPACE_in_DLL()

{
   string a = "test";

  OutputDebugStringA("\nIn (TEST_NAMESPACE_in_DLL(...): ");

    using namespace System;
    using namespace System::IO::Ports;
    using namespace System::ComponentModel;

    array<String^>^ serialPorts = nullptr;
    try
    {
        // Get a list of serial port names.
        serialPorts = SerialPort::GetPortNames();
    }
    catch (Win32Exception^ ex)
    {
        OutputDebugStringA("\nError: ex->Message: ");
        MarshalString(ex->Message, a);
        OutputDebugStringA(a.c_str());
    }

    OutputDebugStringA("\nThe following serial ports were found:");

    // Display each port name to the console.
    for each(String^ port in serialPorts)
    {
       MarshalString(port, a);
       OutputDebugStringA(a.c_str());
    }
}


//Function prototype descriptions for Windows API functions
// lpOutputString is a pointer to string to be displayed in debug window
WINBASEAPI VOID WINAPI OutputDebugStringA( LPCSTR lpOutputString );


// Converts an integer (2 or 4 bytes) into a hex string ( 4 or 8 chars)
CFUNCS_VS_API char * _Int2Hex_dll( unsigned int wWord )
{
  static far char sIntHex[ 17 ];
  WORD i;

  if (sizeof(int) == 4) //Platform has 4 byte represenattion for int
  { 
    i = 9;
    do
      {
        sIntHex[ i ] = 48 + ( wWord & 0x000000000000000F );
        if( sIntHex[ i ] > 57 )
      sIntHex[ i ] += 7;
        wWord >>= 4;
      } while( i-- > 0 );
    sIntHex[ 16 ] = 0;
  }
  else   //Platform has 2 byte represenattion for int
  {
    i= 3;
    do
      {
        sIntHex[ i ] = 48 + ( wWord & 0x000F );
        if( sIntHex[ i ] > 57 )
      sIntHex[ i ] += 7;
        wWord >>= 4;
      } while( i-- > 0 );
    sIntHex[ 4 ] = 0;
  }
  return sIntHex;
}


/* ============================================================================ 
 * OutputDebugStringCR_DLL( cStr )          
 *
 * Purpose:
 *  Send a string the the system debugger window WITH <CR>+<LF> printed first
 * ========================================================================= */
CFUNCS_VS_API void _OutputDebugStringCR_DLL(char * cMsg) {
    OutputDebugStringA("\n");
    OutputDebugStringA(cMsg);
}
 #ifdef __cplusplus
 }
 #endif

 




Build Log Output from Visual Studio 2008:
  • Build Log Rebuild started: Project: cfuncs_vs, Configuration: Release|Win32
    Command Lines Creating temporary file "d:\ac\fwhdb_phx\cfuncs_vs\cfuncs_vs\Release\RSP00002942085648.rsp" with contents
    [
    /O2 /Oi /GL /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "CFUNCS_VS_EXPORTS" /D "_WINDLL" /D "_UNICODE" /D "UNICODE" /FD /EHa /MD /Gy

    /Yu"stdafx.h" /Fp"Release\cfuncs_vs.pch" /Fo"Release\\" /Fd"Release\vc90.pdb" /W3 /c /Zi /clr /TP .\cfuncs_vs.cpp
    ]
    Creating command line "cl.exe @d:\ac\fwhdb_phx\cfuncs_vs\cfuncs_vs\Release\RSP00002942085648.rsp /nologo /errorReport:prompt"
    Creating temporary file "d:\ac\fwhdb_phx\cfuncs_vs\cfuncs_vs\Release\RSP00002A42085648.rsp" with contents
    [
    /O2 /Oi /GL /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "CFUNCS_VS_EXPORTS" /D "_WINDLL" /D "_UNICODE" /D "UNICODE" /FD /EHa /MD /Gy /Yc"stdafx.h" /Fp"Release\cfuncs_vs.pch" /Fo"Release\\" /Fd"Release\vc90.pdb" /W3 /c /Zi /clr /TP .\stdafx.cpp
    ]
    Creating command line "cl.exe @d:\ac\fwhdb_phx\cfuncs_vs\cfuncs_vs\Release\RSP00002A42085648.rsp /nologo /errorReport:prompt"
    Creating temporary file "d:\ac\fwhdb_phx\cfuncs_vs\cfuncs_vs\Release\RSP00002B42085648.rsp" with contents
    [
    /O2 /Oi /GL /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "CFUNCS_VS_EXPORTS" /D "_WINDLL" /D "_UNICODE" /D "UNICODE" /FD /EHa /MD /Gy /Fo"Release\\" /Fd"Release\vc90.pdb" /W3 /c /Zi /TP .\dllmain.cpp
    ]
    Creating command line "cl.exe @d:\ac\fwhdb_phx\cfuncs_vs\cfuncs_vs\Release\RSP00002B42085648.rsp /nologo /errorReport:prompt"
    Creating temporary file "d:\ac\fwhdb_phx\cfuncs_vs\cfuncs_vs\Release\RSP00002C42085648.rsp" with contents
    [
    /OUT:"D:\ac\fwhdb_phx\cfuncs_vs\Release\cfuncs_vs.dll" /INCREMENTAL:NO /DLL /MANIFEST

    /MANIFESTFILE:"Release\cfuncs_vs.dll.intermediate.manifest" /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /LTCG /DYNAMICBASE /FIXED:No /NXCOMPAT /MACHINE:X86 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib

    shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib

    ".\Release\cfuncs_vs.obj"

    ".\Release\dllmain.obj"

    ".\Release\stdafx.obj"
    ]
    Creating command line "link.exe @d:\ac\fwhdb_phx\cfuncs_vs\cfuncs_vs\Release\RSP00002C42085648.rsp /NOLOGO /ERRORREPORT:PROMPT"
    Creating temporary file "d:\ac\fwhdb_phx\cfuncs_vs\cfuncs_vs\Release\RSP00002D42085648.rsp" with contents
    [
    /outputresource:"..\Release\cfuncs_vs.dll;#2" /manifest

    .\Release\cfuncs_vs.dll.intermediate.manifest
    ]
    Creating command line "mt.exe @d:\ac\fwhdb_phx\cfuncs_vs\cfuncs_vs\Release\RSP00002D42085648.rsp /nologo"
    Creating temporary file "d:\ac\fwhdb_phx\cfuncs_vs\cfuncs_vs\Release\BAT00002E42085648.bat" with contents
    [
    @echo Manifest resource last updated at %TIME% on %DATE% > .\Release\mt.dep
    ]
    Creating command line "d:\ac\fwhdb_phx\cfuncs_vs\cfuncs_vs\Release\BAT00002E42085648.bat"
    Output Window Compiling...
    stdafx.cpp
    Compiling...
    cfuncs_vs.cpp
    Compiling...
    dllmain.cpp
    Linking...
    Creating library D:\ac\fwhdb_phx\cfuncs_vs\Release\cfuncs_vs.lib and object D:\ac\fwhdb_phx\cfuncs_vs\Release\cfuncs_vs.exp
    Generating code
    Finished generating code
    Embedding manifest...
    Results Build log was saved at "file://d:\ac\fwhdb_phx\cfuncs_vs\cfuncs_vs\Release\BuildLog.htm"
    cfuncs_vs - 0 error(s), 0 warning(s)
--------------------------------------------------------------------------------
Step(4)

Result from impdef and implib calls.
  • D:\ac\fwhdb_phx\LIB>impdef cfuncs_vs.def cfuncs_vs.dll
    CodeGear Impdef Version 3.1.0 Copyright (c) 1991-2007 CodeGear

    D:\ac\fwhdb_phx\LIB>implib cfuncs_vs.lib cfuncs_vs.def
    CodeGear Implib Version 3.1.0 Copyright (c) 1991-2007 CodeGear
    Name: 'cfuncs_vs' Ext: '.dll' Base: 0x00000000
    Name: 'CFUNCS_VS.DLL' Ext: '.dll' Base: 0x00000000
--------------------------------------------------------------------------------
Step(5)

Output from my make file:
  • MAKE Version 5.2 Copyright (c) 1987, 2000 Borland
    echo C:\Borland\BCC55\lib\c0w32.obj + > b32.bc
    echo ph_win32.obj, + >> b32.bc
    echo ph_win32.exe, + >> b32.bc
    echo ph_win32.map, + >> b32.bc
    echo D:\ac\fwhdb_phx\lib\cfuncs_vs.lib + >> b32.bc
    echo D:\FiveTech\FWH\lib\FiveHx.lib D:\FiveTech\FWH\lib\FiveHC.lib + >> b32.bc
    echo D:\FiveTech\xHarbour\lib\rtl.lib + >> b32.bc
    echo D:\FiveTech\xHarbour\lib\vm.lib + >> b32.bc
    echo D:\FiveTech\xHarbour\lib\pp.lib + >> b32.bc
    echo D:\FiveTech\xHarbour\lib\rdd.lib + >> b32.bc
    echo D:\FiveTech\xHarbour\lib\dbfntx.lib + >> b32.bc
    echo D:\FiveTech\xHarbour\lib\dbfcdx.lib + >> b32.bc
    echo D:\FiveTech\xHarbour\lib\gtgui.lib + >> b32.bc
    echo D:\FiveTech\xHarbour\lib\lang.lib + >> b32.bc
    echo D:\FiveTech\xHarbour\lib\macro.lib + >> b32.bc
    echo D:\FiveTech\xHarbour\lib\dbffpt.lib + >> b32.bc
    echo D:\FiveTech\xHarbour\lib\hbsix.lib + >> b32.bc
    echo D:\FiveTech\xHarbour\lib\debug.lib + >> b32.bc
    echo D:\FiveTech\xHarbour\lib\common.lib + >> b32.bc
    echo D:\FiveTech\xHarbour\lib\pcrepos.lib + >> b32.bc
    echo D:\FiveTech\xHarbour\lib\ct.lib + >> b32.bc
    echo C:\Borland\BCC55\lib\cw32mt.lib + >> b32.bc
    echo C:\Borland\BCC55\lib\import32.lib + >> b32.bc
    echo C:\Borland\BCC55\lib\uuid.lib + >> b32.bc
    echo C:\Borland\BCC55\lib\psdk\odbc32.lib + >> b32.bc
    echo C:\Borland\BCC55\lib\psdk\rasapi32.lib + >> b32.bc
    echo C:\Borland\BCC55\lib\psdk\nddeapi.lib + >> b32.bc
    echo C:\Borland\BCC55\lib\psdk\msimg32.lib + >> b32.bc
    echo C:\Borland\BCC55\lib\psdk\psapi.lib + >> b32.bc
    echo D:\FiveTech\xHarbour\lib\usrrdd.lib + >> b32.bc
    echo D:\ac\fwhdb_phx\lib\sql.lib + >> b32.bc
    echo D:\ac\fwhdb_phx\lib\odbccp32.lib + >> b32.bc
    echo D:\ac\fwhdb_phx\lib\sqlmt.lib + >> b32.bc
    echo D:\ac\fwhdb_phx\lib\IPHlpApi.Lib, >> b32.bc
    echo D:\ac\fwhdb_phx\Resource\ph_win32.res >> b32.bc
    C:\Borland\BCC55\bin\ilink32 -LC:\Borland\BCC55\Lib -Gn -aa -Tpe -s -v @b32.bc
    Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland
--------------------------------------------------------------------------------
Step(6)

Debug Ouput (in the debug window) from my call to TEST_NAMESPACE()
  • In routine: HB_FUNC( TEST_NAMESPACE ).

    In (TEST_NAMESPACE_in_DLL(...):
    The following serial ports were found:COM3

    Returned test result from TEST_NAMESPACE in a DLL is:
    0000000038 <- this is in hex => 56 Decimal
[/list][/list]
--------------------------------------------------------------------------------
There you have it.

Best Regards,
Angelo.c

Re: SerialPort Class Using CreateObject (...)

Posted: Mon Jul 20, 2009 4:16 am
by anserkk
Dear Mr.Angelo

Very useful information. Appreciate your effort.
You have shown a very good and detailed example. Once again thank you :D

Regards
Anser

Re: SerialPort Class Using CreateObject (...)

Posted: Sat Mar 03, 2012 12:19 pm
by jfl@mafact.com
Nice job, Thanks to you

Re: SerialPort Class Using CreateObject (...)

Posted: Sat Mar 03, 2012 1:01 pm
by Antonio Linares
Angelo,

Here you can see how FiveNet access to .NET:

http://code.google.com/p/fivenet/wiki/architecture

This way you can use C#, etc for your .NET code, and easily access it from FWH/Harbour :-)