Serial port differences between WinXP & Win7

I've got an application that has been running successfully on a Windows XP. We are upgrading the computer to Windows 7, 64bit. The application runs correctly on the Windows 7 computer except for a utility that communicates over a serial connection.

I have full access to the code, so I can update/modify/change as needed to solve the problem. We are using VS C++ 2005 with .NET 2.0 SP2. (.NET 3.5 SP1 is installed by not listed in the 'About' dialog box in VS)

Here is a code snipet:

--------
.
.
int result=port.openPort ("COM4", 1); //call in main body to open port
.
.
int RUSerial::openPort (const char *pComPort, const char flag155)
{
//Open the serial port device driver
this->portHandle = CreateFile (pComPort, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);

if (this->portHandle == INVALID_HANDLE_VALUE)
{
printf ("Serial CreateFile failed");
return (1);
}
}


---------

This code works perfectly when run on a Windows XP device, but fails when trying to open the port.

Questions:
1. Is this the correct way to open a serial port on a Windows 7, 64bit computer? Is there a better way and can you point me at some examples?

2. It appears as if the code is using the ANSI version of CreateFile. Should I change this to the Unicode version - ie CreateFileW?

3. Does the CreateFile determine success based on the hardware I/O range and IRQ? Or does CreateFile rely on the OS to handle that level of detail?


Any examples, advice, places to look next are greatly appreciated.

Thanks,

G.

closed account (z05DSL3A)
int result=port.openPort ("COM4", 1); //call in main body to open port

You could try, int result=port.openPort ("\\.\COM4", 1); //call in main body to open port , I seem to remember that the '\\.\' is needed for accessing a device.
Edit it may have even been '\\\\.\'
Last edited on
Thanks...I'll try that later today and will post the results here.
COM4 should work. The \\.\ is only needed for COM10 and above (of course, in a non-raw C++ string \\.\ ends up as \\\\.\\)

What does GetLastError() return when CreateFile() fails?

Andy

PS See "Communications Resources" section of:

CreateFile function
https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx
Last edited on
Did not know that about COM10 and above...explains why I wasn't getting anywhere.

Will add GetLastError() and let you know what it returns. I will not be able to do that until Wednesday though.

Thanks
If the application run correctly on windows xp, but not on windows 7, try running the program as administrator to see what happens.
Update
- GetLastError() returns a value of "2".

- Running the program as administrator does not work. Still fails connecting to COM4.

G
closed account (z05DSL3A)
Update
- GetLastError() returns a value of "2".

ERROR_FILE_NOT_FOUND
2 (0x2)
The system cannot find the file specified.
So you're computer doesn't think it has a COM4 port. Is this the case? Or do you think it does have a COM4 port?

My desktop reports that it only has a COM1 and COM3 (code below; I'm using FormatMessage() to get Windows to tell me what the return code means.)

COM0 could not be opened
openPort returned 2 : The system cannot find the file specified.

COM1 opened successfully

COM2 could not be opened
openPort returned 2 : The system cannot find the file specified.

COM3 opened successfully

COM4 could not be opened
openPort returned 2 : The system cannot find the file specified.

<snip>

COM13 could not be opened
openPort returned 2 : The system cannot find the file specified.

COM14 could not be opened
openPort returned 2 : The system cannot find the file specified.

COM15 could not be opened
openPort returned 2 : The system cannot find the file specified.


Device Manager only shows COM1, which I know is my single physical serial port.

But checking the registry I can see another COM port:

[HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM]
"\\Device\\537"="COM3"
"\\Device\\Serial0"="COM1"

I haven't checked fully, but I do know I have an Intel 537 modem installed so it's probably a virtual port routing to this device.

Andy

How do I get a list of available serial ports in Win32?
http://stackoverflow.com/questions/1388871/how-do-i-get-a-list-of-available-serial-ports-in-win32

"How to use code tags"
http://www.cplusplus.com/articles/jEywvCM9/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// Note as it's just a quick test I'm using -A entrypoints
// to avoid TCHAR confusion...
#define WIN32_LEAN_AND_MEAN
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <stdio.h>

class RUSerial
{
private:
    HANDLE portHandle;
public:
    RUSerial() : portHandle(INVALID_HANDLE_VALUE)
    {
    }

    ~RUSerial()
    {
        if(portIsOpen())
            closePort();
    }

    DWORD openPort(const char* comPort, const char flag155);
    void closePort();

    bool portIsOpen()
    {
        return (INVALID_HANDLE_VALUE != portHandle);
    }
};

int main()
{
    RUSerial port;

    for(int N = 0; 16 > N; ++N)
    {
        char portName[16] = "";
        sprintf(portName, "COM%d", N);

        char portPath[16] = "";
        sprintf(portPath, "\\\\.\\%s", portName);

        DWORD retCode = port.openPort(portPath, 1); //call in main body to open port

        if(port.portIsOpen()) // could/should check retCode, too
        {
            printf("%s opened successfully\n", portName);
            port.closePort();
        }
        else
        {
            printf("%s could not be opened\n", portName);

            char* errMsg = NULL;
            FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
            NULL, retCode, 0, (char*)&errMsg, 1024, NULL);
            printf("openPort returned %d : %s", retCode, errMsg);
            LocalFree(errMsg);
        }

        printf("\n");
    }

    return 0;
}

DWORD RUSerial::openPort(const char* comPort, const char /*flag155*/)
{
    DWORD retCode = NOERROR;

    //Open the serial port device driver
    portHandle = CreateFileA(comPort, GENERIC_READ | GENERIC_WRITE,
                             0, NULL, OPEN_EXISTING, 0, NULL);

    if(portHandle == INVALID_HANDLE_VALUE)
    {
        retCode = GetLastError();
    }

    return retCode;
}

void RUSerial::closePort()
{
    CloseHandle(portHandle);
    portHandle = INVALID_HANDLE_VALUE;
}

Last edited on
I know for a fact that I have 3 serial ports - COM1, 3 & 4. COM1 is onboard, and I've added a serial card that has 2 serial ports. I've confirmed everything in Device Manager (all drivers are loaded correctly with no errors), so the OS agrees with me that the COM ports exist.

I tried running my application using Win XP, SP3 compatibility mode. The application recognizes and accesses the COM port correctly. Unfortunately, that broke other features in the application that require reading/writing of binary files.

So it looks like the problem is how Win7 references COM ports vs how WinXP does. I'm pretty convinced that if I can figure out the syntax for referencing the COM port, it should work.

I tried using "\\\\.\\COM4" in my code, but that didn't work.

I'll run your code and see what that gives me.
I don't think there's any other syntax than the "\\\\.\\COM4" one, which you've already tried.

As you mention Visual Studio 2005 in your original post, I take it you're talking about a 32-bit app running on a 64-bit computer, yes?

In the absence of further information:

1. Do you know it you can open COM1 successfully with the 32-bit app?

2. Can you build the "port testing" code 64-bit and run it to see if it can open port COM4?

Andy
Correct, 32-bit app, 64-bit computer.

1. Do not know, haven't tried to open COM1 yet.

2. I have built a 64-bit version of the port test code, haven't run it yet (the computer is in a secure area and I have to schedule time on it). I'm also going to build the code using 32-bit to see if there is a difference.

Greg
Andy -

Your code gave me the clue I needed. When I used your code, compiled with a 32bit compiler, it opened all of the COM ports that were present.

The only significant difference between your com-testing code and my application was "CreateFile". I was using "CreateFile(...)" while you had "CreateFileA(...)". I changed my code to use "CreateFileA(...)" and I was able to open and talk to the COM ports.

I have more testing to do to make sure all of the functionality is there, but just being able to talk to the COM port was a big step.

Thank you for your help.

Greg

BTW, my application opens two different COM ports (3 & 4). As a test I used "\\\\.\\COM4" for one and "COM3" for the other. Both worked using CreateFileA.
That doesn't make total sense to me.

CreateFile must have been equivalent to CreateFileA for your code to compile, unless there's something about your code which you didn't post (i.e. an evil cast allowing you to call CreateFileW with an ANSI string?)

Andy
I didn't find any, but it's possible that there is some tricks going on in the code with casts.

So what I suspect is happening (haven't proven it yet), is Windows XP defaults to ANSI, so CreateFileA is called and Windows7 defaults to UNICODE so CreateFileW is called.

Either that, or the values that are returned for the com port are invalid for CreateFileW, but valid for CreateFileA when running on Win7.

Remember, all of this works fine when I run the code on WinXP or on Win7 in XP compatibility mode.

When I used CreateFileA, my code worked fine on Win7.

I think ultimately, it comes down to the difference in how WinXP and Win7 reply to CreateFile when opening a COM port.

When I get a chance, I'll add some more debug to the comm test code to see the differences in the raw data with CreateFileA vs CreateFileW.

Topic archived. No new replies allowed.