1) Hi, we works with Pocket PC 2003 (Embedded Visual C++ 4.0). Our target is perform a data call over integrated cellular line. We read that the right mean is TAPI (XDA-Developers forum) because COM2 seem to be owned by RIL layer. We wrote a test program which handles a data call answer. We get the serial port handle returned by "lineGetID()" function for current data call, but when we try to use it through standard communication APIs ("WriteFile()" and "ReadFile()") it doesn't work (no data is read or write from port handle, but there aren't errors returned by APIs). Same code seems to work fine on a HP IPAQ 2210 with a Compact Flash GSM/GPRS card. How can we transfer data so?
2) We noticed a phone answering process is alive (CPROG.EXE) that takes calls' control. We kill this process when we make our tests, but it backs to life after some minutes. How can we take real calls' control?
3) Is the integrated cellular modem Hayes compatible? Is there a way to directly send AT commands to integrated cellular modem?
4) DCB structure "PortDCB" we pass to "SetCommState()" is the following:
PortDCB.DCBlength = sizeof (DCB);
PortDCB.BaudRate = 9600;
PortDCB.fBinary = TRUE;
PortDCB.fParity = TRUE;
PortDCB.fOutxCtsFlow = FALSE;
PortDCB.fOutxDsrFlow = FALSE;
PortDCB.fDtrControl = DTR_CONTROL_ENABLE;
PortDCB.fDsrSensitivity = FALSE;
PortDCB.fTXContinueOnXoff = TRUE;
PortDCB.fOutX = FALSE;
PortDCB.fInX = FALSE;
PortDCB.fErrorChar = FALSE;
PortDCB.fNull = FALSE;
PortDCB.fRtsControl = RTS_CONTROL_ENABLE;
PortDCB.fAbortOnError = FALSE;
PortDCB.ByteSize = 8;
PortDCB.Parity = NOPARITY;
PortDCB.StopBits = ONESTOPBIT;
Is it correct?
Can anybody help me?
Matthew
This DCB params seem do right job....
Code:
PortDCB.BaudRate = 115200;
PortDCB.fBinary = TRUE;
PortDCB.fParity = FALSE;
//PortDCB.fParity = TRUE;
PortDCB.fOutxCtsFlow = FALSE;
PortDCB.fOutxDsrFlow = FALSE;
PortDCB.fDtrControl = DTR_CONTROL_ENABLE;
PortDCB.fDsrSensitivity = FALSE;
//PortDCB.fDsrSensitivity = TRUE;
PortDCB.fTXContinueOnXoff = TRUE;
//PortDCB.fTXContinueOnXoff = FALSE;
PortDCB.fOutX = FALSE;
PortDCB.fInX = FALSE;
PortDCB.fErrorChar = FALSE;
PortDCB.fNull = FALSE;
PortDCB.fRtsControl = RTS_CONTROL_DISABLE;
PortDCB.fAbortOnError = FALSE;
PortDCB.ByteSize = 8;
PortDCB.Parity = NOPARITY;
PortDCB.StopBits = ONESTOPBIT;
problem one shuold be solved ...Hi
Your DCB parameters worked fine.
Hi Matthew.
Your parameters worked fine with my application, i was teting an IMate and you helped me a lot with my next product version.
Thank you.
Cesar Bremer Pinheiro
Bremer Serv. Emp. Ltda.
Raseac Division.
http://www.raseac.com.br
Dear Matthew,
Hi,
I created a similar application to make a call from one PPC to another using data link. The problem is my program couldn't detect incoming calls. Would you please help me solve this issue?
Do you have any source code that I can learn from it? Also which method did you use? TAPI? COM port? RIL?
I'm very confused. Please help....
Best regards,
A. Riazi
Why is your baudrate 115200 when a CSD connection through TAPI is only at 9600 ?
cause it's TAPI
you can't select bearer capabilities
if you wana select rate use RIL or direct access to COM-ports
mathews help!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
hi,
i am facing a similar problem cant send data through writefile api on cellular line
these r code snippets form my cod e
if(dwReturn =lineOpen (
g_hLineApp, // Usage handle for TAPI
g_dwCurrentLineID, // Cannot use the LINEMAPPER value
&g_CurrentLineInfo.hLine, // Line handle
g_CurrentLineInfo.dwAPIVersion,
// API version number
0, // Must set to zero for Windows CE
0, // No data passed back
LINECALLPRIVILEGE_NONE, // Can only make an outgoing call
0, // Media mode
NULL))
g_MakeCallRequestID = lineMakeCall (g_CurrentLineInfo.hLine,
&g_hCall,
szDialablePhoneNum,
0,
NULL);
dwRet =lineGetID(g_CurrentLineInfo.hLine, 0, 0, LINECALLSELECT_LINE, lpVarString,TEXT("comm/datamodem"));
till this its ok it returns a valid comm handle
after that it sends th data over the connected call but doesnt receive anythinga t the other end ...
the problem might be to give a call handle and LINECALLSELECT_CALL in linegteid func tion i tried it but when i use it fails saying cannot obtain the handle .......now i don understand whether its the problem of not obtaining a handle or whether linehandle will work but problem is in communication ...
plz help and add some code snippets for the communication
firstly have you set up the following...
LPLINECALLPARAMS CallParams;
CallParams=(LPLINECALLPARAMS)malloc(sizeof(LINECALLPARAMS)+1024);
memset(CallParams,0,sizeof(LINECALLPARAMS)+1024);
CallParams->dwTotalSize = sizeof(LINECALLPARAMS)+1024;
// This is where we configure the line for DATAMODEM usage.
//its important to note that if you attempt to make a call
//using LINEMEDIAMODE_DATAMODEM, the line must be opened in
//that way to begin with or nothing will happen. ie open lines
//corresponding to what you plan to makecall with.
CallParams->dwBearerMode = LINEBEARERMODE_VOICE;//over voice call
CallParams->dwMediaMode = LINEMEDIAMODE_DATAMODEM;//data transmition
//LINEMEDIAMODE_INTERACTIVEVOICE;//for voice
//specify that we only want to use a call that is not alreay in use.
//Otherwise it can take over calls that are in progress
CallParams->dwCallParamFlags = LINECALLPARAMFLAGS_IDLE;
//specify to use the first address
CallParams->dwAddressMode = LINEADDRESSMODE_ADDRESSID;
CallParams->dwAddressID = 0;
next check the line you want to use and make sure...
if(lpDevCaps->dwBearerModes & callModeData)//datamode
{
if(lpDevCaps->dwBearerModes & callModeVoice)
{
//then check the media mode
if(lpDevCaps->dwMediaModes & LINEMEDIAMODE_DATAMODEM)
{
if(lpDevCaps->dwMediaModes & LINEMEDIAMODE_INTERACTIVEVOICE)
{
//use it
}
}
}
}
next when you get an incoming call etc get the handle......
HANDLE myTapiManager::getHandle()
{
HANDLE hModem=NULL;
CString name="";
classType="comm/datamodem";
DWORD dwSize = sizeof(VARSTRING) + 2048;
DWORD dwRet = 0;
do
{
LPVARSTRING lpVarString = (LPVARSTRING) new BYTE[dwSize];
lpVarString->dwTotalSize = dwSize;
//the commented out values are what microsoft seem to say
//but cause it to return no handle but only the device class name
dwRet = ::lineGetID(/*hOpenedLine*/NULL, 0,hCall,LINECALLSELECT_CALL /*LINECALLSELECT_LINE*/, lpVarString,
classType);
if ( dwRet == 0 )
{
hModem= * (HANDLE*) ((char*) lpVarString + lpVarString->dwStringOffset);
name= * (LPTSTR) ((char*) lpVarString + lpVarString->dwStringOffset + sizeof(HANDLE));
if(hModem==NULL)
{
MessageBox(NULL,_T("null handle"),_T("handle"),MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
}
else
{
MessageBox(NULL,_T("non null handle, about to call init on port"),_T("handle"),MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
hSerialHandle=hModem;
//you must initialize the port but I do not show it here
initializeIOTimeOuts();
}
break;
}
else if ( dwRet == LINEERR_STRUCTURETOOSMALL )
{
dwSize = lpVarString->dwNeededSize;
delete lpVarString;
lpVarString = NULL;
continue;
}
else
{
// handle errors.........
//
hModem=NULL;
}
}
while (1);
return hModem;
}
this works for me. One problem you may be having is the timing. If you get the handle when the call is offering it will be useless. You must ensure that the call is connected, use the LINECALLSTATE_CONNECTED for this.
cprog dose not effect the opperation of your program, only its ui.
Have you looked at the zip I put in this post ?
http://forum.xda-developers.com/viewtopic.php?t=18978
It may help you with the sending part and getting a handle to Readfile/writefile.
I have never worked on the anwering side so I know nothing on that.
to answer the call that is offering, use LineAnswer. I have tried LinePickup but it has not done what I want. When using lineanswer be aware that the os has already set the number of rings it will ring before the call is actually answered after you answer it. It is normally changed through the phone settings but you can do it programatically if you wish.
Also, you have not mentioned what you are doing with regards to threads. The first time I tried using tapi I spent a lot of time avoiding using multiple threads but it is impracticle. A good number would be 1 for the ui 1 for the line status and 1 for data transfer. Getting your serial handle would the require carefull synchronization.
I have not found benefit in altering any of the port settings. The time-outs for the read/write can make a huge difference though.
Have you checked if there is a class name following the handle in the LPVARSTRING? I have found that if you are doing everything correct except the timing, the name is added but not the handle. This means that the name would be 4 places sooner than it should. In that case the name is in the place where the handle should be and the call still succeeded. Try writing to the port using a string instead of a handle and see how far you get(kidding). To test it just treat the handle you have got as if it where a string and put it in a messagebox. If you can read it then your timing is off.
Lastly your problem could come from how you are setting the api version. Have you been checking the errors generated after all your api calls. There are a lot for tapi that tell you most of what is going on. I have noticed that if you are using the event method for getting line state messages from tapi (ie the correct time to grab the handle) there is something wrong with the way the api version gets negotiated. The event method is part of tapi 2.0 i think so it should be expected that an api version of at least 2.0 is a good version to aim for. For win ce 3.0 docs say that 2.0 is fully supported and parts of 2.1. This is not what actually happens though, I have found that I can't get the event method to work at all (among other things) if I don't pass a min version of 1.1 and a max version of 1.3. This is bizar because by that input tapi should not use any features above 1.3 :?:
guys i ve been trying to set up call params
//Configure line device for a data modem
memset(&LineCallParams, 0, sizeof(LineCallParams));
LineCallParams.dwTotalSize = sizeof(LineCallParams);
LineCallParams.dwBearerMode = LINEBEARERMODE_VOICE;
LineCallParams.dwMediaMode = LINEMEDIAMODE_DATAMODEM;
LineCallParams.dwCallParamFlags = LINECALLPARAMFLAGS_IDLE;
//If multiple addresses on the line, use the first address
LineCallParams.dwAddressMode = LINEADDRESSMODE_ADDRESSID;
LineCallParams.dwAddressID = 0;
the problem is when i pass the lpparam instead of null it reaches to dialing the number and says disconnected: unreachable ..
There is no error while lineopen is passed with LINEMEDIAMODE_DATAMODEM as the 8th parameter i think it shoudl have given an error of media mode not supported at that point only ....but it didnt .....it opened the line fine
when i did not set the datamodem media mode in call params and rest remain as it is ..........the call works fine and is connected ....is it because the datacall facility is not supported and if it is not how can it be activated ....
lReturn = lineOpen(m_hLineApp, m_dwDeviceID, &m_hLine, m_dwAPIVersion, 0 , 0,
LINECALLPRIVILEGE_NONE, LINEMEDIAMODE_DATAMODEM, 0);
g_MakeCallRequestID = lineMakeCall (g_CurrentLineInfo.hLine,
&g_hCall,
szDialablePhoneNum,
0,
NULL); // NULL for default voice call
/**************************/
// lpCallParams);
Firstly, is the phone you are trying to dial a ppc. If yes... the ppc you wish to be the one that answers the call must have opened the line the same way as the dialing one, ie supporting data. If not then it will not even ring when a data call is offering and you will never know if your call was really made.
next look at lineopen.
long opnResult=lineOpen(hLineApp,
deviceID,
&hOpenedLine,
apiNegotiatedForUsedDevice,
0,//not used at all
1,//not used by tapi, but is passed back to this //application to help identify the source of the messages.
//in each line state message. It can be used
//to make sure the message is from a line
//opened by this app.
LINECALLPRIVILEGE_OWNER,// tells it can //accept calls.
LINEMEDIAMODE_DATAMODEM,
NULL);
almost the same but try LINECALLPRIVILEGE_OWNER. This must be set on the receiving end but I also set it on the dialing end.
If the media mode is not supported you will get an error message to tell so. That is the primary way my programs determine the identity of the line to use.
What is the device you are using? I have got bi-directional data transfer to work between ppc 2002 (xda I) and wm2003 se (xda mini). Before 2002 not as many features are supported.
also your call params may be too small
try adding a litle to the end
LPLINECALLPARAMS CallParams;
CallParams=(LPLINECALLPARAMS)malloc(sizeof(LINECALLPARAMS)+1024);
memset(CallParams,0,sizeof(LINECALLPARAMS)+1024);
CallParams->dwTotalSize = sizeof(LINECALLPARAMS)+1024;
.
.
.
.
and what about the number to dial in the call params
// Address to dial
//set its location to be after the normal end of the structure
CallParams->dwDisplayableAddressOffset = sizeof(LINECALLPARAMS);
CallParams->dwDisplayableAddressSize = strlen(szPhNumber);
strcpy((LPSTR)CallParams+sizeof(LINECALLPARAMS), szPhNumber));
then pass the szPhNumber into linemakecall, remember that ppc version
takes unicode.
i am trying to pass data from pocket pc to my pc
this is whole part
LPLINETRANSLATEOUTPUT lpTransOutput = NULL;
// Call translate address before dialing.
do
{
// Allocate memory for lpTransOutput.
if (!(lpTransOutput = (LPLINETRANSLATEOUTPUT) LocalAlloc (
LPTR,
dwSizeOfTransOut)))
{
ErrorBox(TEXT("translate fails "));
goto exit;
}
lpTransOutput->dwTotalSize = dwSizeOfTransOut;
if (dwReturn = lineTranslateAddress (
g_hLineApp, // Usage handle for TAPI
g_dwCurrentLineID, // Line device identifier
g_CurrentLineInfo.dwAPIVersion,
// Highest TAPI version supported
lpszPhoneNum, // Address to be translated
0, // Must be 0 for Windows CE
0, // No associated operations
lpTransOutput)) // Result of the address translation
{
ErrorBox(TEXT("lineTranslateAddress fails "));
goto exit;
}
if (lpTransOutput->dwNeededSize <= lpTransOutput->dwTotalSize)
break;
else
{
dwSizeOfTransOut = lpTransOutput->dwNeededSize;
LocalFree (lpTransOutput);
lpTransOutput = NULL;
}
} while (TRUE);
dwSizeOfCallParams += lpTransOutput->dwDisplayableStringSize;
if (!(lpCallParams = (LPLINECALLPARAMS) LocalAlloc (
LPTR,
dwSizeOfCallParams)))
{
ErrorBox(TEXT("lineTranslateAddress open fails "));
goto exit;
}
ZeroMemory(lpCallParams, dwSizeOfCallParams);
// Set the call parameters.
lpCallParams->dwTotalSize = dwSizeOfCallParams;
lpCallParams->dwBearerMode = LINEBEARERMODE_VOICE;
lpCallParams->dwMediaMode = LINEMEDIAMODE_DATAMODEM ;
lpCallParams->dwCallParamFlags = LINECALLPARAMFLAGS_IDLE;
lpCallParams->dwAddressMode = LINEADDRESSMODE_ADDRESSID;
lpCallParams->dwAddressID = g_dwCurrentLineAddr;
lpCallParams->dwDisplayableAddressSize =
lpTransOutput->dwDisplayableStringSize;
lpCallParams->dwDisplayableAddressOffset = sizeof (LINECALLPARAMS);
// Save the translated phone number for dialing.
lstrcpy (szDialablePhoneNum,
(LPTSTR) ((LPBYTE) lpTransOutput +
lpTransOutput->dwDialableStringOffset));
memcpy((LPBYTE) lpCallParams + lpCallParams->dwDisplayableAddressOffset,
(LPBYTE) lpTransOutput + lpTransOutput->dwDisplayableStringOffset,
lpTransOutput->dwDisplayableStringSize);
// Make the phone call. lpCallParams should be NULL if the default
// call setup parameters are requested.
g_MakeCallRequestID = lineMakeCall (g_CurrentLineInfo.hLine,
&g_hCall,
szDialablePhoneNum,
0,
NULL); // NULL for default voice call
/**************************/
// lpCallParams);
plz suggest if i need to change anything but as the call is successfully connected when only media mode is not set i guess problem is not with the memory location or anything but lies with the provider not sure ...............
or better maybe if u can suggest how i can do settings on my pocket pc for data calls
If you can't make a Data Modem type call, but you can make a voice call - Then are you sure you have Data Enabled on your Sim.
I'm sure I had that un-reachable error ages ago and it was due to not having Data Enabled. You have to contact your Sim provider to do that.
I have never included the lineTranslateAddress, i just put it in the way the user entered it( with a little error checking). If it works for voice though it must be OK.
With the sim, I have done this using 3 different sims and never had to set anything special on it. I could be lucky I guess and had sims already enabled. I doubt it though because one is 7 years old pre paid and not had any change since purchase. The second in a new pre paid and the 3rd is a full gprs enabled(not that gprs has anything to do with this). There should not be anything in the os to set either as when you do what you have done it is doing the "setup" just programatically.
I remember reading somewhere that the network had to support it but I can't be more specific.
What is your network? What is your device? what is your os?
When you say the voice call is connected what do you mean?..
1)your program at the other end answered.
2)the phone app on the other end answered.
3)your dialing end app received the connected message.
4)the returned value from linmakecall was > (-1).
5)some phone hardware on a real phone answered.
6) (my favourite way) the monitor next to your phone started buzzing, proving something was going on. Thats how I test my gprs connectivity :lol:
I have a problem in setting controls in a Win32 application.
When I use SendMessage to set a text string in a static control I get error number 120 which translated means: "This function is only valid in Win32 mode."
Here's the background:
I'm using Visual Studio 2005, I've installed the Windows Mobile 5 SDK.
The project was created using the New Project Wizard, with the following settings:
Visual C++/Smart Device
Win32 Smart Device Project
Platform SDK is: Windows Mobile 5.0 Pocket PC SDK
Windows application
I've added a dialog template resource and can bring up a dialog based on that resource. It contains a static control that I can read the text from, but attempting to set the text gives me the above error.
The relevent code (within the WM_INITDIALOG message handler) is:
Code:
char buffer[100];
HWND hCtrl = ::GetDlgItem(hDlg, IDC_TITLE);
LRESULT result = ::SendMessage(hCtrl, WM_GETTEXT, (WPARAM)80, (LPARAM)buffer);
This works, I get the correct text (ie the text I have placed into the static control using the dialog template editor) copied into the buffer. What follows is:
Code:
buffer[0] = 'A'; // Just to set up a different string
result = ::SendMessage(hCtrl, WM_SETTEXT, (WPARAM)0, (LPARAM)buffer);
if (result == 0)
{
LPVOID lpMsgBuf;
DWORD error = ::GetLastError();
::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, 0, (LPTSTR)&lpMsgBuf, 0, NULL);
::MessageBox(NULL, (LPCTSTR)lpMsgBuf, (LPCWSTR)"LError", MB_OK | MB_ICONINFORMATION);
::LocalFree(lpMsgBuf);
}
The attempt to set the changed text string fails (ie result == 0), and the last error is 120, which is translated to the error message above.
This works the same in both the Windows Mobile 5 emulator, and if I run it on my Atom.
What does this mean? How could it be anything other than Win32 mode?
Is there a function or something I have to call to put it into Win32 mode?
Or is it a project setting in VS2005 that I haven't been able to find?
I'd very much appreciate any help on this.
Peter
Hi Peter.
The only problem I can see in your code is that you are using char instead of WCHAR. Windows Mobile devices only use UNICODE for API calls.
I don't think it is causing the error, but it is strange that you manage to get the correct text out using it.
The only thing I can think of is using GetWindowText and SetWindowText APIs instead of sending the message directly.
Maybe this will solve your problem.
I also notice that you did not initialize the buffer. The string needs to be null terminated so try initializeing all the elements before putting your 'A' in.
I thought 120 was not supported on this system ERROR_CALL_NOT_IMPLEMENTED.
Guys,
Thanks very much for the suggestions.
As for not initializing the buffer, I think the WM_GETTEXT call does that, all I do with the buffer[0] = 'A' call is to modify a single character that now contains the text that was copied out from the control.
But I take your point about using WCHAR, I'll do that when I get a chance.
And I'll try the Get and SetWindowText calls.
Thanks again.
Ok, How about this then?
The buffer is initialized by the WM_GETTEXT message, and it is set to the correct value (ie the initial contents of the control).
Changing the first character works.
The WM_SETTEXT message fails (result == 0) and the translated error (120) as displayed in the message box is "This function is only valid in Win32 mode."
The SetWindowText also fails with the same last error.
Does anyone know what "Win32 mode" is? I have spent time searching the MSDN and googling it. I've seen some references to it as an error message, but I haven't found an explanation.
Thanks,
Peter
Code:
WCHAR buffer[100];
HWND hCtl = ::GetDlgItem(hDlg, IDC_TITLE);
LRESULT result = ::SendMessage(hCtl, WM_GETTEXT, (WPARAM)80, (LPARAM)buffer);
buffer[0] = WCHAR('A');
//BOOL textResult = ::SetWindowText(hCtl, (LPCWSTR)buffer);
result = ::SendMessage(hCtl, WM_SETTEXT, (WPARAM)0, (LPARAM)buffer);
if (result == 0)
{
WCHAR errorTitle[] = L"LastError";
LPVOID lpMsgBuf;
DWORD error = ::GetLastError();
::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, 0, (LPTSTR)&lpMsgBuf, 0, NULL);
::MessageBox(NULL, (LPCTSTR)lpMsgBuf, (LPCWSTR)errorTitle, MB_OK | MB_ICONINFORMATION);
::LocalFree(lpMsgBuf);
}
Ok, there is no apparent reason why your code doesn't work. Like OdeeanRDeathshead said according to MSDN error 120 means 'This function is not supported on this system.', something you definitely should not be getting.
One question: is this code inside a class member function? I am asking because of the '::' in front of every API.
Try removing them and see what happens.
Also, no need to use WCHAR('A'), just write L'A' save your self some typing in the long run.
P.S. In my year and a half of programming for Windows Mobile I never heard of a 'Win32 mode' or a function not working because of it. The error may be elsewhere in your code, some problem with name-spaces perhaps?
Are you running this on an actual device or just the emulator?
Hi levenum,
Thanks for the reply. Where to start?
Firstly I tend to use the scope resolution operator wherever possible. In this case ::SendMessage (for example), is meant to be a clear message to the reader that these functions are not member functions of the class, but instead exist in the global namespace. I have tried removing them and there is no difference.
You also asked if the code was in a class member function. Well, yes. It is a static member function of a specialization of a generic dialog class. Both the about box dialog and this setup dialog specialize this generic dialog class. Each has their own static dialog message processing function.
The code is in the part that handles the WM_INITDIALOG message. This is where I would normally (ie in Win32 on good ol' PC type windows) initialize controls before the dialog box is displayed. I have shown the dialog message function, and it is almost identical to the one for the about box that is generated when you create a Win32 project in the wizard.
One other point is that the GetLastError call and the format call are exactly out of the MSDN. If you look up the FormatMessage function, there is example code to translate the error code returned by GetLastError. That's exactly what I have here, and the message it gives is about not being in Win32 mode. So now I'm curious, how do you arrive at the 'This function is not supported on this system' comment. I looked for error and 120, and the only thing I could find was something about ARM messages "improper line syntax; wrong use of local label".
By the way, the SetWindowText function (commented out) gives exactly the same error code. As you say, surely both of these are allowed on this system.
I also appreciate you comment about not having heard of a Win32 mode.
But you have got me wondering if I can simplify the problem further. I will try the initial small project you get generated from the wizard, and in the about box dialog message processing function I will try to set the text in one of the two static controls on the about box.
Thanks again,
Peter
Code:
// Message handler for the setup dalog.
INT_PTR CALLBACK
DialogSetup::DialogSetupDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
{
// Create a Done button and size it.
SHINITDLGINFO shidi;
shidi.dwMask = SHIDIM_FLAGS;
shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN | SHIDIF_EMPTYMENU;
shidi.hDlg = hDlg;
SHInitDialog(&shidi);
// Set up strings
//LRESULT result = ::SendDlgItemMessage(hDlg, IDC_TITLE, WM_SETTEXT, 0, (LPARAM)"Setup");
WCHAR buffer[100];
HWND hCtl = ::GetDlgItem(hDlg, IDC_TITLE);
LRESULT result = ::SendMessage(hCtl, WM_GETTEXT, (WPARAM)80, (LPARAM)buffer);
buffer[0] = WCHAR('A');
//BOOL textResult = ::SetWindowText(hCtl, (LPCWSTR)buffer);
result = ::SendMessage(hCtl, WM_SETTEXT, (WPARAM)0, (LPARAM)buffer);
if (result == 0)
{
WCHAR errorTitle[] = L"LastError";
LPVOID lpMsgBuf;
DWORD error = ::GetLastError();
::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, 0, (LPTSTR)&lpMsgBuf, 0, NULL);
::MessageBox(NULL, (LPCTSTR)lpMsgBuf, (LPCWSTR)errorTitle, MB_OK | MB_ICONINFORMATION);
::LocalFree(lpMsgBuf);
}
}
return (INT_PTR)TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
case IDCANCEL:
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
}
break;
case WM_CLOSE:
EndDialog(hDlg, message);
return TRUE;
#ifdef _DEVICE_RESOLUTION_AWARE
case WM_SIZE:
{
DRA::RelayoutDialog
(
GetInstance(),
hDlg,
DRA::GetDisplayMode() != DRA::Portrait ? MAKEINTRESOURCE(IDD_SETUP_WIDE) : MAKEINTRESOURCE(IDD_SETUP)
);
}
break;
#endif
}
return (INT_PTR)FALSE;
}
Hi levenum,
Thanks for the reply. Where to start?
Firstly I tend to use the scope resolution operator wherever possible. In this case ::SendMessage (for example), is meant to be a clear message to the reader that these functions are not member functions of the class, but instead exist in the global namespace. I have tried removing them and there is no difference.
You also asked if the code was in a class member function. Well, yes. It is a static member function of a specialization of a generic dialog class. Both the about box dialog and this setup dialog specialize this generic dialog class. Each has their own static dialog message processing function.
The code is in the part that handles the WM_INITDIALOG message. This is where I would normally (ie in Win32 on good ol' PC type windows) initialize controls before the dialog box is displayed. I have shown the dialog message function, and it is almost identical to the one for the about box that is generated when you create a Win32 project in the wizard.
One other point is that the GetLastError call and the format call are exactly out of the MSDN. If you look up the FormatMessage function, there is example code to translate the error code returned by GetLastError. That's exactly what I have here, and the message it gives is about not being in Win32 mode. So now I'm curious, how do you arrive at the 'This function is not supported on this system' comment. I looked for error and 120, and the only thing I could find was something about ARM messages "improper line syntax; wrong use of local label".
By the way, the SetWindowText function (commented out) gives exactly the same error code. As you say, surely both of these are allowed on this system.
I also appreciate you comment about not having heard of a Win32 mode.
But you have got me wondering if I can simplify the problem further. I will try the initial small project you get generated from the wizard, and in the about box dialog message processing function I will try to set the text in one of the two static controls on the about box.
Thanks again,
Peter
Code:
// Message handler for the setup dalog.
INT_PTR CALLBACK
DialogSetup::DialogSetupDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
{
// Create a Done button and size it.
SHINITDLGINFO shidi;
shidi.dwMask = SHIDIM_FLAGS;
shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN | SHIDIF_EMPTYMENU;
shidi.hDlg = hDlg;
SHInitDialog(&shidi);
// Set up strings
//LRESULT result = ::SendDlgItemMessage(hDlg, IDC_TITLE, WM_SETTEXT, 0, (LPARAM)"Setup");
WCHAR buffer[100];
HWND hCtl = ::GetDlgItem(hDlg, IDC_TITLE);
LRESULT result = ::SendMessage(hCtl, WM_GETTEXT, (WPARAM)80, (LPARAM)buffer);
buffer[0] = WCHAR('A');
//BOOL textResult = ::SetWindowText(hCtl, (LPCWSTR)buffer);
result = ::SendMessage(hCtl, WM_SETTEXT, (WPARAM)0, (LPARAM)buffer);
if (result == 0)
{
WCHAR errorTitle[] = L"LastError";
LPVOID lpMsgBuf;
DWORD error = ::GetLastError();
::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, 0, (LPTSTR)&lpMsgBuf, 0, NULL);
::MessageBox(NULL, (LPCTSTR)lpMsgBuf, (LPCWSTR)errorTitle, MB_OK | MB_ICONINFORMATION);
::LocalFree(lpMsgBuf);
}
}
return (INT_PTR)TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
case IDCANCEL:
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
}
break;
case WM_CLOSE:
EndDialog(hDlg, message);
return TRUE;
#ifdef _DEVICE_RESOLUTION_AWARE
case WM_SIZE:
{
DRA::RelayoutDialog
(
GetInstance(),
hDlg,
DRA::GetDisplayMode() != DRA::Portrait ? MAKEINTRESOURCE(IDD_SETUP_WIDE) : MAKEINTRESOURCE(IDD_SETUP)
);
}
break;
#endif
}
return (INT_PTR)FALSE;
}
That error message comes from the free evc compilers. In the tool "error lookup" and in the help, it gives that mesage to correspond to that number.
I have just tested everthing you did. My dialog also uses a class with static methods for its routine. I used your exact code in the initial dialog handler and experimented with the origional contents of the controll. I tested on 2002 2003 2005 devices and can't make it fail. The worst i can get to happen is if there is no text to start with, just a square character displays after the A.
the only thing different is that you say two dialogs use that routine, but I am guessing that you are not doing bothe at once at this time.
Guys, thanks again for anything you can give me.
Lets see, I don't have the situation where two dialogs are using the same function. They both use a different message handling function (different name).
As I said in my last post (sorry I seem to have posted it twice), I was going to simplify the example. I've done that and I get the same problem.
I created another project with the same settings I described above, called "TestSetText". I made a change in only one place. In the function called "About", the message handling function for the about box dialog, I have inserted my example code to get and set the text for one of the static controls called IDC_STATIC_2. I have made no other changes to the code. So the modified About function is as below, and I have commented the section I have added:
Code:
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
{
// Create a Done button and size it.
SHINITDLGINFO shidi;
shidi.dwMask = SHIDIM_FLAGS;
shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN | SHIDIF_EMPTYMENU;
shidi.hDlg = hDlg;
SHInitDialog(&shidi);
// Code to check setting text - only change
//LRESULT result = SendDlgItemMessage(hDlg, IDC_STATIC_2, WM_SETTEXT, 0, L"Example");
WCHAR buffer[100];
HWND hCtl = GetDlgItem(hDlg, IDC_STATIC_2);
LRESULT result = SendMessage(hCtl, WM_GETTEXT, (WPARAM)80, (LPARAM)buffer);
MessageBox(NULL, (LPCTSTR)buffer, (LPCWSTR)L"Text from control", MB_OK | MB_ICONINFORMATION);
// Modify the extracted text
buffer[0] = L'A';
//BOOL textResult = SetWindowText(hCtl, (LPCWSTR)buffer);
result = SendMessage(hCtl, WM_SETTEXT, (WPARAM)0, (LPARAM)buffer);
if (result == 0)
{
WCHAR errorTitle[] = L"LastError";
LPVOID lpMsgBuf;
DWORD error = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, 0, (LPTSTR)&lpMsgBuf, 0, NULL);
MessageBox(NULL, (LPCTSTR)lpMsgBuf, (LPCWSTR)errorTitle, MB_OK | MB_ICONINFORMATION);
LocalFree(lpMsgBuf);
}
// End of my change
}
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
case WM_CLOSE:
EndDialog(hDlg, message);
return TRUE;
#ifdef _DEVICE_RESOLUTION_AWARE
case WM_SIZE:
{
DRA::RelayoutDialog(
g_hInst,
hDlg,
DRA::GetDisplayMode() != DRA::Portrait ? MAKEINTRESOURCE(IDD_ABOUTBOX_WIDE) : MAKEINTRESOURCE(IDD_ABOUTBOX));
}
break;
#endif
}
return (INT_PTR)FALSE;
}
So now there are no double colons, no second dialog, no base class, nothing else to confuse the issue. When the app starts all I have to do is invoke the Help|About menu.
When the WM_GETTEXT message is complete, buffer contains exactly the text I would have expected "TestSetText Version 1.0", and this is what is displayed in the message box. So in principle the SendMessage function works and the control handle (hCtl) is correct. This leads me to suspect that all necessary controls are created by the time the WM_INITDIALOG message is processed, and SHOULD be a good place to modify the controls prior to displaying the dialog box.
Modifying the first character in the buffer (setting it to 'A') succeeds as I can see in the debugger.
The attempt to send the WM_SETTEXT message fails (ie result == 0) and GetLastError returns 120 again. The code as I have it there translates this to "This function is only valid in Win32 mode." And this is displayed in the next message box.
When you see the about box, the first character in the IDC_STATIC_2 control has not been changed.
I've also tried using the SetWindowText call which returns non zero (a failure), and the same thing happens (GetLastError returns 120).
One final comment is that if you look up in the MSDN the FormatMessage function, it gives you code (that I have copied) to translate the GetLastError into a string. This gives the Win32 mode message above.
On the other hand, I have found the 120 error in the section "System Errors - Numerical Order" and 120 is listed there as "This function is not valid on this platform." which both of you guys have mentioned.
Ok, two different error messages. The Win32 mode error I don't understand. The not valid error is much more understandable, but how could these functions not be valid?
If you have stayed with me this far then you have a lot of patience.
Thanks
Peter
perhaps you could work around this. Define a value to use as your own message like #define MY_SETUP_MESSAGE ...some value.
Then do nothing in the handler for WM_INITDIALOG except post your own setup message. Do all your normal stuff there. If that succeeds then take a closer look at the timing of WM_INITDIALOG, else there is something waky going on.
Hang on a second, you wrote:
I've also tried using the SetWindowText call which returns non zero (a failure), and the same thing happens (GetLastError returns 120).
Click to expand...
Click to collapse
Is that correct or is it a typo? According to MSDN non zero return for SetWindowText means success, not failure.
One thing you should try is calling SetLastError(0) before calling SetWindowText. Last error is no automatically reset in any way, so it is possible that error 120 is a result of a previous function. Although that still wouldn't account for not seeing the change text in the control.
In any case this is strange. I always initialize controls in WM_INITDIALOG handler and it never failed before.
Ah, you're right. Sorry, I screwed that up. I misread the MSDN there and did a GetLastError anyway, which returned 120.
SetWindowText returns a value of 1, which implies success, but it wasn't successful in the sense of setting the text, when you see the about box it is unchanged.
I also did a SetLastError to zero before the call, and did a GetLastError after it (even though the return code said success), and it was zero. So by all accounts (return code and GetLastError) it should have worked but didn't. The about box is unchanged.
I have also SetLastError to zero before the SendMessage to set the text. That returns zero, and I am sure that the MSDN says should be TRUE if the text is set, so an error. Trouble is, GetLastError then gives zero implying that there was no failure. When you see the about box, the text is not changed so it did fail.
I will have to experiment some more. Maybe I can't set text in a static for some reason. Do I need to call InitCommonControls for that or something (which I haven't done)?
I will also have to try setting text in an edit control.
I used the format message and got the same win32 mode stuff now. However, the text was modified to the new value. I think the win32 mode error message is a bug. Put the same code into the emulator and the error returned is invalid handle. At least invalid handle is something more definite. In both cases, emulator and real device, even though the returned value is 0 for WM_SETTEXT, and the error message is there, I do not think there is an error. Have you just tried it without any error checking?
Are you creating the dialog using creatdialog/dialogbox?
Hi OdeeanRDeathshead, thanks for the reply.
I don't think the invalid handle error is right here because I have used the same control window handle (hCtl) a couple of statements before to retrieve the text and that worked. I guess what I haven't checked is whether the control window handle is changed somehow as a result of the first call, but that would be really weird.
You said that even though SendMessage/WM_SETTEXT returned 0, you thought it probably wasn't an error. Well, there is support for that in that when I SetLastError to zero just prior to calling it, and call GetLastError just after, the error code was zero, thus no error. But the reason I think that there WAS an error is that it did not modify the static control. This is what I get if I effectively don't do any error checking.
As for how I am creating the dialog, the only code I have modified from the original project created from the application wizard is in the WM_INITDIALOG section of the About function that I showed you above. The dialog is created in the WndProc message handling function for the main window, part of which is below. If it is the IDM_HELP_ABOUT command, from the menu, it calls DialogBox specifying the dialog message processing function 'About' where my modified code is.
The code below is produced by the application wizard.
Code:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
static SHACTIVATEINFO s_sai;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
[b]case IDM_HELP_ABOUT:
DialogBox(g_hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, About);
break;[/b]
case IDM_OK:
SendMessage (hWnd, WM_CLOSE, 0, 0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
etc
I think I am going to have to experiment some more on the weekend. Try some other controls etc.
By the way I meant to mention that exactly the same thing happens in both the emulator as well as my Atom. So far, in all of the combinations of code, I have not been able to programmatically change the text content of a static control on a dialog.
And I've just noticed that my attempt to highlight (bold) the relevent part of the code above didn't work.
D'oh!
Actually I have just thought of something that may be relevent.
The emulator and SDK that came by default with VisualStudio2005 is WindowsCE 2003. When I first tried my code in the emulator, it worked. I could not only set text in a static control, I was also successfully manipulating a date/time picker in a separate dialog. I did lots of GDI rendering in the main window as well. And this code also worked on a friend's WindowsCE2003 PDA.
Things looked good until I tried it on my Atom which is WindowsMobile 5.
None of the above worked (except the GDI rendering). I thought it may have been a problem with the development environment. So I downloaded the WindowsMobile 5 SDK which includes a WM5 emulator. I thought this is bound to fix the problem, ie generate the code with the WM5 SDK.
All of my problems above are with WM5 project and emulator. And I said I was using this way back in the first post.
OdeeanRDeathshead, I had a quick look at your profile and you seem to have some earlier XDA machines. Are you using Windows Mobile 5?
If the problem does turn out to be Windows Mobile 5 related, then that says something very bad about backwards compatibility for that platform. Could it also be a WM5 bug? Surely not something so fundamental as this?
I use evc++3 for a compiler, mainly because I am the kind of person who thinks - if its not broaken why change. I have an Atom and do use it to run code on. I have all os, ie 2002,2002pe,2003,2003se,2005, so I don't think this problem is with the device. It may be vis studio 2005, but others have said it works OK.
PPC operating systems have a nasty history of backwards compatibility issues. I could not say that this is the issue here, but it is definately one reason I stick to a lowest common denominator approach. Why not just get evc3 or evc4 and give them a try. They are free.
I guess I was hoping to do it with Visual Studio 2005 because that is what I use at work. These days I mainly program in C#/.NET.
I kind of miss the low level stuff that I used to do on windows a long time ago. But I reminisce.
I'm assuming that evc++ is embedded visual c++? It sounds like really good advice, I'll look for it and it sounds like it will fix all my problems. Especially if as you say, it works for WindowsMobile 5. Can you tell me if you are supposed to use the WindowsMobile 5 SDK with it?
So OdeeanRDeathshead and levenum, thanks a lot for your help guys.
Peter