漫谈WinCE输入法的编写(五)--以DLL替代CIMWnd

//========================================================================
//TITLE:
//    漫谈WinCE输入法的编写(五)--以DLL替代CIMWnd
//AUTHOR:
//    norains
//DATE:
//    Friday  12-October-2007
//Environment:
//        EVC4.0 + Windows CE 5.0 Standard SDK
//========================================================================
    之前的一系列文章(恩,好久以前的文章),輸入法的功能實現都是在CIMWnd中,而本文则是以外部的DLL为替代CIMWnd.以DLL替代CIMWnd类有什么好处呢?恩,这个~其实我也说不上,不过嘛,知道一种新方式,有多一种选择,毕竟不是一件坏事,不是么?何况,这个方法,以我个人观点,还更为灵活些.更换输入法部件时,只需要更新dll即可.
   
    我们首先来回顾一下之前一系列文章中定义的CIMWnd接口功能:
    class CIMWnd 
    {
      public:
        //获取窗口句柄
        HWND GetWindow();;
        //显示输入法的设置窗口
        void ShowUserOptionsDlg(HWND hWndParent,HINSTANCE hInst = NULL);
        //显示输入法界面
        void ShowWindow(BOOL bShow);
        //销毁输入法界面
        void DestroyWindow();           
        //初始化窗口,hWndSip是输入法管理器的句柄
        BOOL Initialize(HINSTANCE hInst, HWND hWndSip);
 
        ...
       
    }

    也就是说,为了和CInputMethod(漫谈WinCE输入法的编写(二))衔接起来,我们在dll中也必须实现这五个功能接口.我们新建一个名为DllWnd工程的DLL工程,并且为了避免和系统的函数重复从而导致出现获取函数入口失败,我们将这五个功能接口分别添上IM前缀:
    //The interface
    //获取窗口句柄
    HWND IMGetWindow();
    //显示输入法的设置窗口
    void IMShowUserOptionsDlg(HWND hWndParent,HINSTANCE hInst);
    //显示输入法界面
    void IMShowWindow(BOOL bShow);
    //销毁输入法界面
    void IMDestroyWindow();
    //初始化窗口
    BOOL IMInitialize(HINSTANCE hInstSip, HWND hWndSip);
   
   
    下面是一个完整的DllWnd代码,其功能是实现一个输入法窗口的创建,并且当点击该窗口时会输出一串测试字符.
    
#include 
" sip.h "
#include 
" resource.h "

// ===================================================================
#define  MYMSG_REGCALLBACK            (WM_USER+100)
// Description:
//     The message is using for registering the input method callback function
//
// Parameters:
//     pImCallback = (IIMCallback *)wParam
//     0 = lParam

// =====================================================================




// ====================================================================
// Macro define
#define  WINDOW_CLASS                    TEXT("IMWND_Class")
#define  WINDOW_TITLE                    TEXT("IMWND_Title")

// The taskbar height
#define  TASKBAR_HEIGHT_AUTOHIDE            5
#define  TASKBAR_HEIGHT                    26

#define  IMG_IMWND_WIDTH                    370
#define  IMG_IMWND_HEIGHT                206

#define  SCREEN_WIDTH                    800
#define  SCREEN_HEIGHT                    480



// ==================================================================
// Forward Declare

// ------------------------------------------------------------------------
// The interface

HWND IMGetWindow();
void  IMShowUserOptionsDlg(HWND hWndParent,HINSTANCE hInst);
void  IMShowWindow(BOOL bShow);
void  IMDestroyWindow();
BOOL IMInitialize(HINSTANCE hInstSip, HWND hWndSip);

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


void  OnDestroy(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam);
void  OnPaint(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam);
void  OnRegCallback(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam);
void  OnLButtonUp(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam);
LRESULT WndProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam);
// ---------------------------------------------------------------------
// The global member
HWND g_hWnd  =  NULL;  // 输入法功能窗口
HWND g_hWndSip  =  NULL;  // IM父窗口
HMODULE g_hInst  =  NULL;  // dll的实例句柄
HINSTANCE g_hInstSip  =  NULL;  // sip dll的实例句柄
IIMCallback  * g_pIMCallback;  // 回调函数指针


// -------------------------------------------------------------------
// Description:
//     The DLLMAIN
//
// ------------------------------------------------------------------
BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
                     )
{
    
switch (ul_reason_for_call)
    {
        
case  DLL_PROCESS_ATTACH:
        {
            g_hInst 
=  (HMODULE)hModule;
            
break ;
        }
    }

    
return  TRUE;
}



// -------------------------------------------------------------------
// Description:
//     Get the window handle
//
// ------------------------------------------------------------------
HWND IMGetWindow()
{
    
return  g_hWnd;
}


// -------------------------------------------------------------------
// Description:
//     Show the user options dialog
//
// ------------------------------------------------------------------
void  IMShowUserOptionsDlg(HWND hWndParent,HINSTANCE hInst)
{
    MessageBox(NULL,TEXT(
" 控制面板可以調出的輸入法設置 " ),TEXT( " 設置 " ),MB_OK);
}


// -------------------------------------------------------------------
// Description:
//     Show the window
//
// ------------------------------------------------------------------
void  IMShowWindow(BOOL bShow)
{
    
if (bShow  ==  TRUE)
    {
        ::ShowWindow(g_hWnd,SW_SHOW);
    }
    
else
    {
        ::ShowWindow(g_hWnd,SW_HIDE);
    }
}


// -------------------------------------------------------------------
// Description:
//     Destroy the window
//
// ------------------------------------------------------------------
void  IMDestroyWindow()
{
    ::DestroyWindow(g_hWnd);
}


// -------------------------------------------------------------------
// Description:
//     Initialize the window
//
// ------------------------------------------------------------------
BOOL IMInitialize(HINSTANCE hInstSip, HWND hWndSip)
{
    g_hInstSip 
=  hInstSip;
    g_hWndSip 
=  hWndSip;



    
    UnregisterClass(WINDOW_CLASS,g_hInst);
    
    WNDCLASS wc 
=  { 0 };
    wc.style 
=  CS_VREDRAW  |  CS_HREDRAW;;
    wc.lpfnWndProc 
=  WndProc; 
    wc.cbClsExtra 
=   0 ;
    wc.cbWndExtra 
=   0 ;
    wc.hInstance 
=  g_hInst;
    wc.hIcon 
=  NULL;
    wc.hCursor 
=  NULL;
    wc.hbrBackground 
=  (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName 
=  NULL;
    wc.lpszClassName 
=  WINDOW_CLASS;
    
if (RegisterClass( & wc)  ==   0 )
    {    
        
return  FALSE;
    }

    

    
    
// Set the window area to suit with the image
    RECT rcClientWnd  =  { 0 };
    GetClientRect (hWndSip, 
& rcClientWnd);
    RECT rcSipWnd 
=  { 0 };
    GetWindowRect(hWndSip,
& rcSipWnd);
    
// It may be the frame for the parent window,so we must hold it.
     int  iWidth  =  (rcSipWnd.right  -  rcSipWnd.left )  -  (rcClientWnd.right  -  rcClientWnd.left)  +  IMG_IMWND_WIDTH; 
    
int  iHeight  =  (rcSipWnd.bottom  -  rcSipWnd.top)  -  (rcClientWnd.bottom  -  rcClientWnd.top)  +  IMG_IMWND_HEIGHT;
    rcSipWnd.left 
=  SCREEN_WIDTH  -  iWidth;
    rcSipWnd.top 
=  SCREEN_HEIGHT  -  iHeight  -  TASKBAR_HEIGHT;
    SetWindowPos(hWndSip,hWndSip,rcSipWnd.left,rcSipWnd.top,iWidth,iHeight,NULL);

    
//  Create SIP window.  
    g_hWnd  =  CreateWindowEx( 0 ,
                        WINDOW_CLASS,
                        WINDOW_TITLE,
                        WS_CHILD 
|  WS_BORDER ,
                        rcClientWnd.left,
                        rcClientWnd.top,
                        IMG_IMWND_WIDTH,
// rcWnd.right - rcWnd.left,
                        IMG_IMWND_HEIGHT, // rcWnd.bottom - rcWnd.top,
                        hWndSip,
                        NULL,
                        g_hInst,
                        NULL
                        );
            
    




    
if (IsWindow(g_hWnd) == FALSE)
    {
        
return  FALSE;
    }



    
return  TRUE;
}



// -------------------------------------------------------------------
// Description:
//     The window process
//
// ------------------------------------------------------------------
LRESULT WndProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
{
    
switch (wMsg)
    {
        
case  WM_PAINT:
            OnPaint(hWnd,wMsg,wParam,lParam);
            
return   0 ;
        
case  MYMSG_REGCALLBACK:
            OnRegCallback(hWnd,wMsg,wParam,lParam);
            
return   0 ;
        
case  WM_ERASEBKGND:
            
// Do nothing in order not to flash the window
             return   0 ;
        
case  WM_LBUTTONUP:
            OnLButtonUp(hWnd,wMsg,wParam,lParam);
            
return   0 ;

    }
    
return  DefWindowProc(hWnd,wMsg,wParam,lParam);
}



// -------------------------------------------------------------------
// Description:
//     On message WM_PAINT
//
// ------------------------------------------------------------------
void  OnPaint(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
{
    
    PAINTSTRUCT ps;
    HDC hdc 
=  BeginPaint(hWnd, & ps);
    
// Create a DC that matches the device
    HBITMAP hBitmap  =  CreateCompatibleBitmap(hdc,IMG_IMWND_WIDTH,IMG_IMWND_HEIGHT);
    HDC hdcMem 
=  CreateCompatibleDC(hdc);
    
// Select the bitmap into to the compatible device context
    HGDIOBJ hOldSel  =  SelectObject(hdcMem,hBitmap);
    
    
// Create a DC that matches the device
    HDC hdcBmp  =  CreateCompatibleDC(hdc);
    
// Load the bitmap
    HANDLE hBmp =  LoadImage(g_hInst,MAKEINTRESOURCE(IDB_PANNEL),IMAGE_BITMAP, 0 , 0 , 0 );
    
// Select the bitmap into to the compatible device context
    HGDIOBJ hOldBmpSel  =  SelectObject(hdcBmp,hBmp);
    
// Copy the bitmap image to the memory DC.
    BitBlt(hdcMem, 0 , 0 ,IMG_IMWND_WIDTH,IMG_IMWND_HEIGHT,hdcBmp, 0 , 0 ,SRCCOPY);


    
// Draw to the screen
    BitBlt(hdc, 0 , 0 ,IMG_IMWND_WIDTH,IMG_IMWND_HEIGHT,hdcMem, 0 , 0 ,SRCCOPY);
    
    
// Restore original bitmap selection and destroy the memory DC
    SelectObject(hdcBmp,hOldBmpSel);
    SelectObject(hdcMem,hOldSel);
    DeleteObject(hBitmap);
    DeleteDC(hdcBmp);
    DeleteDC(hdcMem);
    EndPaint(hWnd,
& ps);
}

// -------------------------------------------------------------------
// Description:
//     On message MYMSG_REGCALLBACK
//
// ------------------------------------------------------------------
void  OnRegCallback(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
{
    g_pIMCallback 
=  (IIMCallback  * )wParam;

}

// -------------------------------------------------------------------
// Description:
//     On message WM_LBUTTONUP
//
// ------------------------------------------------------------------
void  OnLButtonUp(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
{
    
if (g_pIMCallback  !=  NULL)
    {
        g_pIMCallback
-> SendString(TEXT( " 輸入法測試程序  " ), 8 );    
    }
}


    当然,上部接口CInputMethod也需要更改.为了方便和CIMWnd契合,我们设置两个宏定义:IMWND_FROM_CODE和IMWND_FROM_DLL.
   
    IMWND_FROM_CODE定义时,我们采用CIMWnd作为功能实现窗口;而IMWND_FROM_DLL则是采用上文所说的dllwnd.dll.


/ //    
//  InputMethod.h: interface for the CInputMethod class.
//
/ /

#ifndef IMPUTMETHOD_H
#define  IMPUTMETHOD_H

#include 
" stdafx.h "
#include 
" sip.h "
#include 
" IMWnd.h "


// -----------------------------------------------------------------
class  CInputMethod :  public  IInputMethod
{
public :

    
// IUnknown methods
    STDMETHODIMP_(ULONG) Release(THIS);
    STDMETHODIMP_(ULONG) AddRef(THIS);
    STDMETHODIMP QueryInterface(THIS_ REFIID riid, LPVOID 
* ppv);

    
// IInputMethod
    HRESULT STDMETHODCALLTYPE SetImData (DWORD dwSize,  void   * pvImData);
    HRESULT STDMETHODCALLTYPE GetImData (DWORD dwSize, 
void   * pvImData);
    HRESULT STDMETHODCALLTYPE RegisterCallback(IIMCallback 
* pIMCallback);
    HRESULT STDMETHODCALLTYPE ReceiveSipInfo(SIPINFO 
* psi);
    HRESULT STDMETHODCALLTYPE GetInfo(IMINFO 
* pimi);
    HRESULT STDMETHODCALLTYPE Hiding();
    HRESULT STDMETHODCALLTYPE Showing();
    HRESULT STDMETHODCALLTYPE Deselect();
    HRESULT STDMETHODCALLTYPE Select(HWND hWndSip);
    HRESULT STDMETHODCALLTYPE UserOptionsDlg (HWND hwndParent);
    CInputMethod(
long   * plDllCnt,HINSTANCE hInst);
    
virtual   ~ CInputMethod();

protected :

    HINSTANCE m_hInst; 
// The dll instance
     long   * m_plDllCnt; // point to the Global DLL reference count
     long  m_lRef;




#ifdef IMWND_FROM_CODE
    CIMWnd 
* m_pIMWnd;  // The input method window pointer
     #define  GETINSTANCE()                    (m_pIMWnd = CIMWnd::GetInstance())
    
#define  GETWINDOW()                    (m_pIMWnd->GetWindow())
    
#define  SHOWUSEROPTIONSDLG(x,y)        (m_pIMWnd->ShowUserOptionsDlg(x,y))
    
#define  SHOWWINDOW(x)                (m_pIMWnd->ShowWindow(x))
    
#define  DESTROYWINDOW()                (m_pIMWnd->DestroyWindow())
    
#define  INITIALIZE(x,y)                (m_pIMWnd->Initialize(x,y))
#endif   // #ifdef IMWND_FROM_CODE



#ifdef IMWND_FROM_DLL

    BOOL m_bLoadLib;

    
// I don't need get instance from the dll.
     #define  GETINSTANCE()

    typedef HWND (WINAPI 
* DLL_GETWINDOW)( void );    
    typedef 
void  (WINAPI  * DLL_SHOWUSEROPTIONSDLG)(HWND,HINSTANCE  =  NULL);
    typedef 
void  (WINAPI  * DLL_SHOWWINDOW)(BOOL);
    typedef 
void  (WINAPI  * DLL_DESTROYWINDOW)( void );
    typedef BOOL (WINAPI 
* DLL_INITIALIZE)(HINSTANCE,HWND);

    
    DLL_GETWINDOW                GETWINDOW;
    DLL_SHOWUSEROPTIONSDLG        SHOWUSEROPTIONSDLG;
    DLL_SHOWWINDOW                SHOWWINDOW;
    DLL_DESTROYWINDOW            DESTROYWINDOW;
    DLL_INITIALIZE                INITIALIZE;

#endif   // #ifdef IMWND_FROM_DLL
};

// --------------------------------------------------------------------------------
#endif   //  IMPUTMETHOD_H



/ /
//  InputMethod.cpp: implementation of the CInputMethod class.
//
/ /
#include  " InputMethod.h "

// --------------------------------------------------------------------
// Macro define
#define  SIP_WND_WIDTH            200
#define  SIP_WND_HEIGHT            180

#define  IMWND_DLL_PATH   TEXT("window/dllwnd.dll")
// ----------------------------------------------------------------------
/ /
//  Construction/Destruction
/ /

CInputMethod::CInputMethod(
long   * plDllCnt, HINSTANCE hInst)
{    
    GETINSTANCE();    
    m_hInst 
=  hInst;
    m_plDllCnt 
=  plDllCnt;
    (
* m_plDllCnt) ++ ;
    m_lRef 
=   1 ;      //  Set ref count to 1 on create.


#ifdef IMWND_FROM_DLL
    
    GETWINDOW 
=  NULL;
    SHOWUSEROPTIONSDLG 
=  NULL;
    SHOWWINDOW 
=  NULL;
    DESTROYWINDOW 
=  NULL;
    INITIALIZE 
=  NULL;

    HINSTANCE hInstDll;
    hInstDll 
=  LoadLibrary(IMWND_DLL_PATH);
    
if (hInstDll  !=  NULL)
    {
        GETWINDOW 
=  (DLL_GETWINDOW) GetProcAddress(hInstDll,TEXT( " IMGetWindow " ));
        SHOWUSEROPTIONSDLG 
=  (DLL_SHOWUSEROPTIONSDLG) GetProcAddress(hInstDll,TEXT( " IMShowUserOptionsDlg " ));
        SHOWWINDOW 
=  (DLL_SHOWWINDOW) GetProcAddress(hInstDll,TEXT( " IMShowWindow " ));
        DESTROYWINDOW 
=  (DLL_DESTROYWINDOW) GetProcAddress(hInstDll,TEXT( " IMDestroyWindow " ));
        INITIALIZE 
=  (DLL_INITIALIZE) GetProcAddress(hInstDll,TEXT( " IMInitialize " ));
    }

    
if (GETWINDOW  ==  NULL  ||
        SHOWUSEROPTIONSDLG 
==  NULL  ||
        SHOWWINDOW 
==  NULL  ||
        DESTROYWINDOW 
==  NULL  ||
        INITIALIZE 
==  NULL )
    {
        m_bLoadLib 
=  FALSE;
    }
    
else
    {
        m_bLoadLib 
=  TRUE;
    }

#endif

}

CInputMethod::
~ CInputMethod()
{
    (
* m_plDllCnt) -- ;
}


// -------------------------------------------------------------------------------------------
// Description:
//     This method is implemented to create the windows and image list for the input method (IM).
// ----------------------------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CInputMethod::Select(HWND hWndSip)
{

    
if (INITIALIZE(m_hInst,hWndSip)  ==  FALSE)
    {
        
return  E_FAIL;
    }

    SHOWWINDOW(TRUE);


    
return  S_OK;
}

// -------------------------------------------------------------------------------------------
// Description:
//     This method is implemented to select the input method (IM) out of the software-based 
// input panel window and to destroy the IM windows. 
// ----------------------------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CInputMethod::Deselect()
{
    DESTROYWINDOW();
    
return  S_OK;
}

// -------------------------------------------------------------------------------------------
// Description:
//     This method is implemented to perform any initialization before the software-based 
// input panel window is displayed
// ----------------------------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CInputMethod::Showing()
{
    SHOWWINDOW(TRUE);
    
return  S_OK;
}

// -------------------------------------------------------------------------------------------
// Description:
//     This method is implemented to perform any saving routines before the software-based 
// input panel is hidden.
// ----------------------------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CInputMethod::Hiding()
{
    SHOWWINDOW(FALSE);

    
return  S_OK;
}


// -------------------------------------------------------------------------------------------
// Description:
//     This method is implemented to return information about the current input 
// method (IM) to the operating system.
// ----------------------------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CInputMethod::GetInfo(IMINFO  * pimi)
{

    pimi
-> cbSize  =   sizeof  (IMINFO);
    pimi
-> hImageNarrow  =   0 ;
    pimi
-> hImageWide  =   0 ;
    pimi
-> iNarrow  =   0 ;
    pimi
-> iWide  =   0 ;  
    pimi
-> fdwFlags  =  SIPF_DOCKED;

    pimi
-> rcSipRect.left  =   0 ;
    pimi
-> rcSipRect.top  =   0 ;
    pimi
-> rcSipRect.right  =  SIP_WND_WIDTH;
    pimi
-> rcSipRect.bottom  =  SIP_WND_HEIGHT;
    
return  S_OK;
}

// -------------------------------------------------------------------------------------------
// Description:
//     This method is implemented for the IM to receive information about the size,
// placement, and docked status of the software-based input panel.
// ----------------------------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CInputMethod::ReceiveSipInfo(SIPINFO  * psi)
{
    
return  S_OK;
}

// -------------------------------------------------------------------------------------------
// Description:
//     This method is implemented to receive a pointer to an IIMCallback interface. 
// An input method (IM) uses the IIMCallback interface to send keystrokes to applications 
// and to change the icons on the Input Panel button.
// ----------------------------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CInputMethod::RegisterCallback(IIMCallback  * pIMCallback)
{

    
// Tell the IM window to register the callback
    HWND hWnd  =  GETWINDOW();
    SendMessage(hWnd,MYMSG_REGCALLBACK,(WPARAM)pIMCallback,
0 );
    
return  S_OK;
}

// -------------------------------------------------------------------------------------------
// Description:
//     This method is implemented to send data from the current 
// input method (IM) to the current application.
// ----------------------------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CInputMethod::GetImData(DWORD dwSize,  void   * pvImData)
{
    
return  S_OK;
}

// -------------------------------------------------------------------------------------------
// Description:
//     This method is implemented to respond to an application's request to 
// set input method (IM)-specific data within the IM.
// ----------------------------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CInputMethod::SetImData(DWORD dwSize,  void   * pvImData)
{
    
return  S_OK;
}

// ---------------------------------------------------------------------
// Description:
//     Increment object ref count
// ----------------------------------------------------------------------
STDMETHODIMP CInputMethod::QueryInterface(REFIID riid, LPVOID  * ppv)
{


#ifdef IMWND_FROM_DLL
    
if (m_bLoadLib  ==  FALSE)
    {
        
return  E_NOINTERFACE;
    }
#endif   // #ifdef IMWND_FROM_DLL


    
//  If caller wants our IUnknown or IID_IInputMethod2 object, 
    
//  return a pointer to the object.
     if  (IsEqualIID (riid, IID_IUnknown)  ||  IsEqualIID (riid, IID_IInputMethod)  ||  IsEqualIID (riid, IID_IInputMethod2))
    {
        
//  Return ptr to object.
         * ppv  =  (IInputMethod  * ) this ;
        AddRef();                
//  Increment ref to prevent delete on return.
         return  NOERROR;
    }
    
* ppv  =  NULL;
    
return  (E_NOINTERFACE);

}


// ---------------------------------------------------------------------
// Description:
//     Increment object ref count
// ----------------------------------------------------------------------
STDMETHODIMP_(ULONG) CInputMethod::AddRef()
{
   
    ULONG cnt;   
    cnt 
=  (ULONG)InterlockedIncrement ( & m_lRef);
    
return  cnt;
}

// ---------------------------------------------------------------------
// Description:
//     Increment object ref count
// ----------------------------------------------------------------------
STDMETHODIMP_(ULONG) CInputMethod::Release()
{
    ULONG cnt;
   
    cnt 
=  (ULONG)InterlockedDecrement ( & m_lRef);
    
if  (cnt  ==   0
    {
        delete 
this ;
        
return   0 ;
    }
    
return  cnt;
}


// ---------------------------------------------------------------------
// Description:
//     The SIP Control Panel applet is asking for a configuration dialog box to be displayed.
// ----------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CInputMethod::UserOptionsDlg(HWND hwndParent)
{

    SHOWUSEROPTIONSDLG(hwndParent,m_hInst);
    
return  S_OK;
}

   
    OK,编译完毕,大功告成!
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值