How To Use CeRapiInvoke()
View products that this article applies to.
Article ID : 299891
Last Review : August 30, 2004
Revision : 1.0
This article was previously published under Q299891
On This Page
SUMMARY
MORE INFORMATION
Using CeRapiInvoke() in Block Mode
Using CeRapiInvoke in Stream Mode
Building Modules That Use RAPI
APPLIES TO
SUMMARY
The remote API (RAPI) CeRapiInvoke() enables you to invoke your routines in the Windows CE device from a desktop application. The routines are implemented in a DLL and the DLL must export those routines. You can use CeRapiInvoke() in two ways: in block mode or in stream mode. This article demonstrates how to use CeRapiInvoke() in both ways.
Back to the top
MORE INFORMATION
The following is a prototype for CeRapiInvoke in RAPI.dll to be used by an application running on the desktop.
CeRapiInvoke() will be called in block mode if IRAPIStream** is NULL. Otherwise it will be called in the stream mode.
The following is a prototype DLL routine that runs on the device: int CallMyFunction(DWORD cbInput, BYTE* pInput,
DWORD* pcbOutput, BYTE** ppOutput,
IRAPIStream* pStream)
Back to the top
Using CeRapiInvoke() in Block Mode
In the block mode, calls to CeRapiInvoke() return only after the DLL routine has executed and returned. The ppOutput pointer must be allocated by the DLL through the use of LocalAlloc() and the desktop application must call LocalFree() on the same [what?]. In block mode, ppIRAPIStream must be set to NULL. The value returned by the DLL routine will be returned by CeRapiInvoke.
The following sample code demonstrates use of CeRapiInvoke() in the block mode by calling a method in the DLL that resides in the \Windows folder of the device. The DLL method returns the available physical memory in the device in kilobytes. // test console application to call in blocking mode
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include "rapi.h"
//Initialize Windows CE RAPI
hr = CeRapiInit();
//Invoke CallMyFunction routine in MyRapi DLL in the \Windows directory.
hr = CeRapiInvoke(L"MyRapi", L"CallMyFunction",
0, NULL, &cbOut, &pOut, NULL, 0);
if(cbOut)
printf("Your device got %s KB of Physical Memory available", pOut);
else
printf("No memory available in the device");
//Uninitialize Windows CE RAPI
hr = CeRapiUninit();
//Free the DLL allocated memory.
if(pOut)
LocalFree(pOut);
return 0;
}
The following code shows implementation of the CallMyFunction routine inside MyRapi.dll: #include <windows.h>
#include "rapi.h"
extern "C"
{
__declspec(dllexport) int CallMyFunction(DWORD cbInput,
BYTE* pInput, DWORD* pcbOutput, BYTE** ppOutput,
IRAPIStream* pStream);
}
int CallMyFunction(DWORD cbInput, BYTE* pInput,
DWORD* pcbOutput, BYTE** ppOutput,
IRAPIStream* pStream)
{
MEMORYSTATUS structMemStatus;
DWORD dwMemAvailPhys;
char szFree[10];
//Initialize buffer to all NULLs
ZeroMemory(szFree, 10);
GlobalMemoryStatus(&structMemStatus);
dwMemAvailPhys = structMemStatus.dwAvailPhys;
sprintf(szFree, "%d", dwMemAvailPhys/1024);
//Provide extra char for NULL
*ppOutput = (BYTE*)LocalAlloc(LPTR, strlen(szFree)+1);
if(*ppOutput)
{
//Copy along with NULL
strncpy((char*)*ppOutput, szFree, strlen(szFree)+1);
*pcbOutput = strlen(szFree) + 1;
}
else
*pcbOutput = 0;
return 0;
}
Back to the top
Using CeRapiInvoke in Stream Mode
The following code demonstrates how to use CeRapiInvoke() in stream mode. It communicates with the device through IRAPIStream interface and displays the available physical memory in an Edit control. This simple application will loop indefinitely when reading data from the RAPI stream until a key is pressed. Once a key is pressed, the application exits the loop and writes to the RAPI stream, notifying code in MyRapi.dll that it is exiting. // test console application to call in stream mode
//
//Serious Error conditions and execution paths are not
//considered in this example. Purpose is just to demonstrate
//the usage of CeRapiInvoke() in Stream mode.
On the device a separate thread is dedicated for reading the notification from the desktop. The read operation will block the thread until it reads the notification from the stream. The main thread writes to the stream every two seconds. struct MY_MEM_STRUCT
{
DWORD dwPhysMemAvail;
DWORD dwPhysTotal;
};
while(1)
{
EnterCriticalSection(&g_structCriticalSect);
if(g_fContinue == FALSE)
{
LeaveCriticalSection(&g_structCriticalSect);
break;
}
LeaveCriticalSection(&g_structCriticalSect);
GlobalMemoryStatus(&structMemStatus);
structMyMem.dwPhysMemAvail = structMemStatus.dwAvailPhys / 1024;
structMyMem.dwPhysTotal = structMemStatus.dwTotalPhys / 1024;
hr = SendToMyRapiStream(pStream, &structMyMem, sizeof(structMyMem));
if(FAILED(hr))
{
break;
}
/*wait for 2 seconds. if WaitForSingleObject() comes out
in less than 2 seconds then client has requested to stop
sending the data or an error has occured.*/
if(WaitForSingleObject(hThread, 2000) != WAIT_TIMEOUT)
break;
}
//Make sure the other thread has terminated
WaitForSingleObject(hThread, 5000);
DeleteCriticalSection(&g_structCriticalSect);
g_fContinue = FALSE;
return 0;
For additional information, see the MSDN CeRapiInvoke function reference:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcesdkr/htm/_wcesdk_cerapiinvoke.asp (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcesdkr/htm/_wcesdk_cerapiinvoke.asp)
Back to the top
Building Modules That Use RAPI
The Rapi.h header file and Rapi.lib library file are available for use in compiling and linking desktop code to use RAPI. The header file and library files for use with RAPI functions are found in the following folder in a typical installation:
C:\Windows CE Tools\wce300\MS Pocket PC\support\ActiveSync\Inc
C:\Windows CE Tools\wce300\MS Pocket PC\support\ActiveSync\Lib
To compile the device-side DLL, you can use the same Rapi.h file mentioned earlier. There is no RAPI library file necessary to create the device DLL.
NOTE: RAPI.dll is not redistributable. It is installed when ActiveSync is installed on the desktop host computer.
QA: How to implement autorun from a storage card?
By Joao Paulo Figueira, June 02, 2003.
Print version
Question
I want to start an application when the user inserts or removes a storage card. How do I implement such functionality?
Answer
You can execute an application when a storage card is inserted or removed from your device. This may allow your users to install applications, perform backups, or other action you like. The protocol is really simple:
Create one directory under the root of the card named after your CPU's ID. For instance, StrongARM is 2577, SH3 is 10003 and MIPS is 4000.
Your application must be named autorun.exe and it must be in that directory.
When the card is inserted, the application is called with 'install' as the command line parameter. When the card is removed, the parameter is 'uninstall'.
Here is a skeleton application. You can create it using eVC's Wizard, choosing the 'WCE Pocket PC 2002 Application'.
// OnCardInsert
//
// The compact flash card has been inserted
//
void OnCardInsert()
{
//
// Get the path from where we are starting up
//
if(!SHGetAutoRunPath(szCFPath))
{
return;
}
}
// OnCardRemove
//
// The compact flash card has been removed
//
void OnCardRemove()
{
}
// WinMain
//
// Main entry point
//
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
if(lstrcmpi(lpCmdLine, _T("install")) == 0)
{
//
// Card has been inserted
//
OnCardInsert();
}
else if(lstrcmpi(lpCmdLine, _T("uninstall")) == 0)
{
//
// Card has been removed
//
OnCardRemove();
}
return 0;
}
Note that your application does not know where it is starting. You cannot infer that the startup path will be the one you are expecting.
안녕하세요? 고수는 절대 아니지만... 제가 아는 문제인것 같아서 답변을
적어봅니다.
^^;...
이 글은 님께서 Pocket PC Version으로 작업 하신다는 가정하에 말씀드립니다.
해주셔야 할 작업은 총 3개가 존재합니다.
그럼... ^^;...
1. PocketPC에는 멤버 변수로 m_bFullScreen를 가지고
있습니다.
일반 WinCE Version에서 있는지는 잘 모르겠구요... ^^;...
이 값은 기본적으로 TRUE로 설정되어 있습니다. 속성은 눈치
채셨듯이...
Full Screen으로 할지 안할지를 결정하는 인자입니다.
이 값만 바꿔준다면, 화면이 초기에 뜰때, 아마 최대화가 아닌 설정한
값으로,
다이얼로그 박스가 나타날 것입니다.
설정은.... 다이얼로그의 생성자 함수에서...
m_bFullScreen = FALSE; //
Full Screen 금지
이렇게 해주시면 됩니다.
위와 같이 한다고 하더라도 Pocket PC Version에서 보면 문제가 생깁니다.
SIP던가요? 키보드를 위로 올리거나, 닫거나 하면 이넘의 다이얼로그가
허락도 안받구...
지 맴데로 전체 창으로 가버립니다.
희한한 화면 구성이 되는데요....
이것은 SIP 관련 이벤트에 구현되어 있는 부분에 문제(?)가
있어서 그렇습니다.
물론 MFC가 구현해준 부분이라 찾아야 하는데요...
딱 2 부분만 고치면 됩니다.
2. 첫번째로 바꿔줘야 할 부분은
OnActivate 이벤트입니다.
dlgcore.cpp 파일을 열어서 찾아보면,
void CDialog::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
{
if (!(GetStyle() & WS_CHILD))
{
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
SHHandleWMActivate(m_hWnd, pThreadState->m_lastSentMsg.wParam,
pThreadState->m_lastSentMsg.lParam, &m_sai, FALSE);
}
이 부분을 찾으실 수 있을 겁니다.
이 부분에서 SHHandleWMActive를 호출하는데요.
MSDN에서 이 함수에 대해서 찾아보면 다음과 같이 나오는군요.
This function is used to help manage the input panel and your application.
In Windows for Pocket PC, when a window is activated, the input panel should
be restored to the state it was in when the window lost activation.
This function helps manage the restoration of the original state
해석을 보면...(참고루... 전 해석 능력이 짧은 관계로 영어랑 욜라 친한 울 회사분께서
번역해주셨음... ㅋㅋㅋ)
이 기능은 입력패널과 당신은 어플리케이션의 관리를 도울때 쓴다.
포켓PC용 윈도우 안에서, 하나의 창이 활성화 되었을 때,
입력 패널은 그 창이 비활성화 될 때 상태로 되돌려져야 한다.
이 기능은 원상태의 복원에 도움을 준다.
결국에는 이 함수를 호출해서 다이얼로그 창이 input panel 의 동작 상태에 따라서,
사이즈가 마음데로... 왔다갔다 하게 되죠.
CDialog의 OnActiveate 에서는 결국 하는 일은 저 함수를 호출 하는 일 밖에 없으므로,
님께서 구현하신 Dialog함수에서 OnActivate함수내부에서,
바로 CWnd::OnActivate를 호출하셔서 저 SHHandleWMActive를 호출하지 않도록
막으시면 될겁니다.
그럼... 다음과 같이...
CWnd::OnSettingChange(uFlags, lpszSection);
}
이 부분의 SHHandleWMSettingChange함수를 MSDN을
찾아보면 다음과 같이 나올 것입니다.
This function is used to help manage the input panel and your application.
If hwnd should size based on the position of the input panel,
then call this function to size your window when the window receives the
WM_SETTINGCHANGE message.
해석을 보면... (역시 이 부분도 영어 고수님의 도움을 받아서... ㅋㅋㅋ, 아!~
난 왜 이리두 영어 실력이 짧은가... ㅡㅡa...)
이 기능은 입력패널과 당신 어플리케이션의 관리를 도울때 쓴다.
만약, hwnd 가 입력패널의 위치에 기반을 두고 어떤 크기로 만들어져야 한다고
가정을 한다면,
그 창이 WM_SETTINGCHANGE 메시지를 받을 때 당신의 창을 사이즈 하기 위해서
이 기능을 사용하라!
이 부분도 결국에는 다이얼로그 창이 마음데로 왔다갔다 하는 몰상식한(?) 기능을
수행하는데요.. ㅋㅋㅋ
이유는 다 아시겠지만 SHHandleWMSettingChange 이 함수를 호출하기 때문에 발생하는 문제입니다.
이 부분도 역시 위와 동일하게 바로 CWnd::OnSettingChange함수를 님께서 구현하신
Dialog 클래스내에서 저 함수를 구현해 놓으시고, 내부에 상위 CDialog 내의 OnSettingChange를 호출하시는게 아니라, 더 상위인 CWnd::OnSettingChange를 호출하시면 됩니다.
따라서 다음과 같이 멤버 함수로,
afx_msg void OnSettingChange(UINT uFlags, LPCTSTR lpszSection);
을 헤더 파일에 넣어주시구요.
내부에는 다음과 같이 처리하면 되겠죠? ^^;
void CUsrDlg::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
{
CWnd::OnSettingChange(uFlags, lpszSection); // Full Screen 금지
}
이와 같이 고쳐 놓으면 아마(?) 다이얼로그의 사이즈가 반항(?)하는 것을 찾기
힘드실 것입니다.
물론... 위의 항목에서 2, 3번 항목은 if (!(GetStyle() & WS_CHILD))
조건에 걸릴 경우만 타는 겁니다.
참고루요..
다이얼로그가 PocketPC Version에서는 모달로 띄우거나, 모달리스로 띄우거나,
메인 메뉴가 자동적으로 사라집니다.
어떻게 해볼라고 해도 안되더군요.
물론 모달리스로 띄우면 메뉴는 선택할 수 있어야 하는 것인데...(WinCE Version에서는 메뉴 사용 가능)
얼마동안 찾아봤는데 잘 안되더군요.
전 이렇게 해서 그 문제를 해결했습니다.
Test환경은 PocketPC Version에서 Test했습니다.
올만에 개발실루 왔더니 아는 부분이 있어서 몇자 적어봤습니다.
만약 틀린 부분이 있다면... 괜한 삽질(?)로 고생시키게 해서 죄송하구요... ^^;...
그럼 이만... ^^;...
이번에 evt를 처음 접하게 되었는데 잘 몰라서요..^^;; 도움을 요청합니다.
sqlce를 설치하고.. 디비를 생성했는데요...
evt에서.. 그 디비에 접근해서.. sql문을 사용해서.. 원하는 자료를 검색해서... 가져 오는 방법을 잘 모르겠어서요... vc++에선 해본적이 있는데 여기선 잘 모르겠습니다. 도와주세여~
SQL Server 엔터프라이즈 관리자이(가) '210.222.0.87'을(를) '210.222.0.87'의 배포자로 구성할 수 없습니다.
오류 18483: 'distributor_admin'이(가) 서버에서 원격 로그인으로 정의되어 있지 않기 때문에 KRNET'서버에 연결할 수 없습니다.
// Local Open
con = new SqlCeConnection( "Data Source = \\Northwind.sdf;" );
cmd = new SqlCeCommand( strSQL, con );
cmd.CommandType = CommandType.Text;