CHM文件打開方式


CHM是英語“Compiled Help Manual”的簡寫,即“已編譯的幫助文件”

第一步:右鍵選擇打開方式

第二步:選擇在電腦中查找C:\Windows\hh.exe

直到找到這個文件:

使用MCI(媒體控制接口)播放音頻文件,MCI為程序員提供了兩種方式訪問MCI設備或文件:一種是基於消息的命令接口函數;另一種是使用字符串接口函數。兩者的區別在於基本命令結構和發送信息到設備的原理。 

 

A.基於消息的MCI 

    消息命令控制接口使用消息控制MCI設備,將消息和控制信息以數據結構的形式作為函數參數發送,並接收返回的數據,MCI直接把設備消息和控制消息發送到設備。一條基於MCI的命令包含以下3個部分。 

數據結構:該結構包含可傳遞給MCI驅動程序的信息和從驅動程序返回的值,指定要執行的MCI命令一個常量,如MCI_OPEN、MCI_CLOSE... 

一個或一組用來指定MCI信息子選項的標志:這些標志用來確定可以得到什么類型的信息和如何執行函數。 

一個確定命令附加參數。

    Windows SDK為使用命令消息接口發送MCI消息提供了3個核心函數。 

1、mciSendCommand函數。

該函數用於向MCI設備發送一個命令消息,原型為:

MCIERROR mciSendCommand(MCIDEVICEID IDDevice, UINT uMsg, DWORD fdwCommand, DWORD dwParam);
參數說明如下: 

IDDevice:用來表示一個MCI設備。MCI使用MCI_OPEN消息打開一個設備時自動創建一個標識號用以唯一標識要操作的設備,以后的命令操作均使用此標識。

uMsg:表示要發出的消息,取值如下所示。

MCI_OPEN 打開一個設備

MCI_CLOSE 關閉一個設備

MCI_PLAY 播放全部或部分音頻,從暫停狀態恢復播放

MCI_STOP 停止播放

MCI_PAUSE 暫停播放

MCI_SEEK 改變當前位置

MCI_CUE 提示一個設備以最小的延遲開始播放或錄制

MCI_RECORD 在一個設備上開始錄制

MCI_SAVE 保存一個文件

MCI_INFO 查詢設備信息,如產品名稱等

MCI_GETDEVCAPS 查詢產品特征,如設備類型等

MCI_STATUS 查詢設備當前狀態,如播放位置、媒體格式等

MCI_SET 設置設備參數,如時間格式、波形數據格式等

fdwCommand:消息指定標志。

dwParam:指定一個指向消息數據結構的指針。
    如果mciSendCommand函數調用成功則返回0,否則返回錯誤代碼消息。所返回的DWORD低位字是錯誤代碼,可以將它發送到mciGetErrorString函數,已獲得對錯誤的文本描述。若錯誤事設備特有的,高位包含了設備ID,否則高位為0。 

    MMSYSTEM.H頭文件中還定義了MCI命令所需要的數據結構類型。以下是MCI命令常用的數據結構。

MCI_OPEN_PARMS MCI_OPEN命令消息參數的數據結構

MCI_PLAY_PARMS MCI_PLAY命令消息參數的數據結構

MCI_RECORD_PARMS MCI_RECORD命令消息參數的數據結構

2、mciGetDevicelID函數。

    當打開一個設備時,該函數用來獲得此設備的ID,原型為: 

MCIDEVICEID mciGetDevicelID(LPCTSTR lpszDevice);
    參數lpszDevice指定要打開的MCI設備名。若函數調用成功,則返回設備的標志號,否則返回0。 

3、mciGetErrorString函數。

該函數用於返回一個錯誤代碼的文本描述,原型為: 

BOOL mciGetErrorString(DWORD fdwError, LPTSTR lpszErrorText, UINT cchErrorText);
    參數說明如下: 

fdwError:上一次mciSendCommand函數調用的返回值。

lpszErrorText:用來接收返回的文本描述的緩沖區指針。

cchErrorText:指定lpszErrorText的長度。

B.基於字符串的MCI 

    命令字符串接口使用文本命令控制MCI設備。文本串中包含執行一個命令所需要的所有信息。MCI分析文本串,並把它翻譯成命令消息接口中的消息和控制信息。由於加入了翻譯過程,命令字符串接口的速度要慢於命令消息接口。

    Windows也為字符串接口定義了3個核心操作函數。 

1、mciSendString函數。

該函數用於向一個MCI的設備驅動程序發送一個字符串,原型為:

MCIERROR mciSendString(LPCTSTR lpszCommand, LPTSTR lpszReturnString, UINT cchReturn, HANDLE hwndCallback);
    參數說明如下: 

lpszCommand:一個以NULL結尾的定義MCI控制命令的字符串,格式為:command device_name argument

lpszReturnString:一個遠指針,它指向由應用程序返回的字符串緩沖區。

cchReturn:指定了緩沖區大小。

hwndCallback:用來指定接收並處理MCI向應用程序發出的MM_MCINOTIFY消息窗口的句柄。
    函數成功調用,則返回0,否則返回錯誤代碼。可以將錯誤代碼傳遞給mciGetErrorString函數獲得對錯誤的文本描述。

2、mciGetErrorString函數。

前面已作了介紹,這里不再敘述。

3、mciExecute函數。

實際上是mciSendString函數的簡化形式,它不占用緩沖區來返回消息。如果調用失敗,則顯示出錯信息消息框,原型為: 

BOOL FAR PASCAL mciExecute(LPCTSTR lpszDevice);
    參數lpszDevice與mciSendString函數的第一個參數含義相同。

 

C.使用

    使用MCI對多媒體進行操作實際上是向設備發送相應的命令。下面介紹各種常用的操作。

 

1、打開多媒體設備 

    使用MCI_OPEN命令消息來打開設備。所有的設備對於MCI命令都需要一個指向消息命令數據結構MCI_OPEN_PARMS的指針。該結構格式如下: 

typedef struct _MCI_OPEN_PARMS

{

DWORD dwCallback; //設置MCI_NOTIFY標志時的回調窗口句柄

MCIDEVICEID wDeviceID; //打開設備成功時返回的設備標識號

LPCSTR lpstrDeviceType; //指定所要打開設備類型

LPCSTR lpstrElementName; //對於復合設備,指定設備元素

LPCSTR lpstrAlias; //設備別名

} MCI_OPEN_PARMS;  

The following additional flags apply to all devices supporting MCI_OPEN:

MCI_OPEN_ALIAS 別名

An alias is included in the lpstrAlias member of the structure identified by lpOpen.

MCI_OPEN_SHAREABLE 共享

The device or file should be opened as shareable.

MCI_OPEN_TYPE lpstrDeviceType已設置

A device type name or constant is included in the lpstrDeviceType member of the structure identified by lpOpen.

MCI_OPEN_TYPE_ID lpstrDeviceType已設置為設備ID

The low-order word of the lpstrDeviceType member of the structure identified by lpOpen contains a standard MCI device type identifier and the high-order word optionally contains the ordinal index for the device. Use this flag with the MCI_OPEN_TYPE flag.



The following additional flags apply to compound devices:

MCI_OPEN_ELEMENT lpstrElementName已設置

A filename is included in the lpstrElementName member of the structure identified by lpOpen.

MCI_OPEN_ELEMENT_ID lpstrElementName已設置為設備ID

The lpstrElementName member of the structure identified by lpOpen is interpreted as a DWORD value and has meaning internal to the device. Use this flag with the MCI_OPEN_ELEMENT flag.


The following additional flags are used with the digitalvideo device type:

MCI_DGV_OPEN_NOSTATIC
The device should reduce the number of static (system) colors in the palette. This increases the number of colors available for rendering the video stream. This flag applies only to devices that share a palette with Windows.
MCI_DGV_OPEN_PARENT
The parent window handle is specified in the hWndParent member of the structure identified by lpOpen.
MCI_DGV_OPEN_WS
A window style is specified in the dwStyle member of the structure identified by lpOpen.
MCI_DGV_OPEN_16BIT
Indicates a preference for 16-bit MCI device support.
MCI_DGV_OPEN_32BIT
Indicates a preference for 32-bit MCI device support.
For digital-video devices, the lpOpen parameter points to an MCI_DGV_OPEN_PARMS structure.
The following additional flags are used with the overlay device type:
MCI_OVLY_OPEN_PARENT
The parent window handle is specified in the hWndParent member of the structure identified by lpOpen.
MCI_OVLY_OPEN_WS
A window style is specified in the dwStyle member of the structure identified by lpOpen. The dwStyle value specifies the style of the window that the driver will create and display if the application does not provide one. The style parameter takes an integer that defines the window style. These constants are the same as the standard window styles (such as WS_CHILD, WS_OVERLAPPEDWINDOW, or WS_POPUP).
For video-overlay devices, the lpOpen parameter points to an MCI_OVLY_OPEN_PARMS structure.
The following additional flag is used with the waveaudio device type:
MCI_WAVE_OPEN_BUFFER
A buffer length is specified in the dwBufferSeconds member of the structure identified by lpOpen.
For waveform-audio devices, the lpOpen parameter points to an MCI_WAVE_OPEN_PARMS structure. The MCIWAVE driver requires an asynchronous waveform-audio device.

簡單設備和復合設備打開方式有所不同。打開簡單設備時,不需要指定設備元素。可以用3種方法打開一個簡單設備。

a、指定設備名。

下面一段代碼通過指定設備名打開一個光盤設備。

WORD wDeviceID;

MCI_OPEN_PARMS mciOpenParms;

//為MCI_OPEN消息數據結構賦值

mciOpenParms.lpstrDeviceType = "cdaudio";

//通過指定設備名打開光盤設備

if (micSendCommand(NULL, MCI_OPEN, MCI_OPEN_TYPE, (DWORD)(LPVOID)&mciOpenParms))

//調用失敗的處理

else

wDeviceID = mciOpenParms.wDeviceID;
b、指定設備驅動程序。

下面一段代碼通過指定設備的驅動程序打開一個光盤設備。 

WORD wDeviceID;

MCI_OPEN_PARMS mciOpenParms;

//為MCI_OPEN消息數據結構賦值

mciOpenParms.lpstrDeviceType = "mcicd.drv";

//通過指定設備名打開光盤設備

if (micSendCommand(NULL, MCI_OPEN, MCI_OPEN_TYPE, (DWORD)(LPVOID)&mciOpenParms))

//調用失敗的處理

else

wDeviceID = mciOpenParms.wDeviceID;
c、指定設備類型參數。

    各個MCI設備的設備類型常量如下所示。 

    MCI命令能夠管理的音頻設備類型所對應的字符串和常量 

cdaudio MCI_DEVTYPE_CD_AUDIO

waveaudio MCI_DEVTYPE_WAVEFORM_AUDIO

sequencer MCI_DEVTYPE_SEQUENCER

animation MCI_DEVTYPE_ANIMATION

dat MCI_DEVTYPE_DAT

digitalvideo MCI_DEVTYPE_DIGITAL_VIDEO

other MCI_DEVTYPE_OTHER

scanner MCI_DEVTYPE_SCANNER

vcr MCI_DEVTYPE_VCR

videodisc MCI_DEVTYPE_VIDEODISC

mpegvideo MP3播放類型(常量不清楚,只知道字符串)
    下面一段代碼通過指定設備的類型參數打開一個光盤設備。 

WORD wDeviceID;

MCI_OPEN_PARMS mciOpenParms;

//為MCI_OPEN消息數據結構賦值

mciOpenParms.lpstrDeviceType = (LPRSTR) MCI_DEVTYPE_CD_AUDIO;

//通過指定設備名打開光盤設備

if (micSendCommand(NULL, MCI_OPEN, MCI_OPEN_TYPE, (DWORD)(LPVOID)&mciOpenParms))

//調用失敗的處理

else

wDeviceID = mciOpenParms.wDeviceID;
    打開復合設備需要指定設備元素,也可以用3種方法打開一個復合設備。 

a、只指定設備。

該方法類似於打開簡單設備,但只適合用於MCI_GETDEVCAPS命令確定設備性能。 

b、同時指定設備和設備元素。

該方法需要指出設備元素。舉例如下: 

WORD wDeviceID;

MCI_OPEN_PARMS mciOpenParms;

//為MCI_OPEN消息數據結構賦值

mciOpenParms.lpstrElementName = "c:\windows\media\chorcd.wav";

//通過指定設備元素參數打開復合設備

if (micSendCommand(NULL, MCI_OPEN, MCI_OPEN_TYPE, (DWORD)(LPVOID)&mciOpenParms))

//調用失敗的處理

else

wDeviceID = mciOpenParms.wDeviceID;
c、只指定設備元素。

在此方式下,MCI根據WIN.INI文件中的[mci extension]字段,從設備的擴展名確定設備。例如: 

#define wPtnLength 255; //緩沖區大小

char lpstrRtnString[wPtnLength]; //指向緩沖區指針

WORD result;

result = mciSendString("open cdaudio", lpstrRtnString, wPtnLength, NULL);

//打開CD設備

if (result != 0)

mciGetErrorString(result, lpstrRtnString, wPtnLength)

//事件處理

else

//設備成功打開后事件處理
    下面一段代碼用來打開一個多媒體復合設備。 

#define wPtnLength 255; //緩沖區大小

char lpstrRtnString[wPtnLength]; //指向緩沖區指針

WORD result;

result = mciSendString("c:\windows\media\chorcd.wav", lpstrRtnString, wPtnLength, NULL);

//打開CD設備

if (result != 0)

mciGetErrorString(result, lpstrRtnString, wPtnLength)

//事件處理

else

//設備成功打開后事件處理


2、播放多媒體設備 

    在成功打開設備后,應用程序就可以通過向MCI發送MCI_PLAY或play字符串命令來播放多媒體設備。MCI_PLAY的數據結構MCI_PLAY_PARMS的格式如下: 

typedef struc{

DWORD dwCallback; //設置MCI_NOTIFY標志時回調窗口句柄

DWORD dwFrom; //播放的起始位置

DWORD dwTo; //播放的結束位置

} MCI_PLAY_PARMS;
    下面一段代碼用來播放已打開的MCI設備。 

WORD wDeviceID;

MCI_PLAY_PARMS mciPlayParams;

//為MCI_PLAY消息數據結構賦值

mciSendCommand(wDeviceID, MCI_PLAY, 0, (DWORD)(LPVOID)&mciPlayParams);
    若不給MCI_PLAY_PARMS數據結構中的dwFrom和dwTo字段賦值,播放從頭至尾進行。 

    而在使用play字符串命令時,如果play命令不加任何參數,則多媒體設備會從目前的位置播放到媒體或文件的結束。play命令支持From和To兩個參數,它們分別指向起始和終止位置。實例如下: 

#define wPtnLength 255; //緩沖區大小

char lpstrRtnString[wPtnLength]; //指向緩沖區指針

//播放CD從第10秒到第15秒位置

mciSendString("play cdaudio from 10000 to 15000", lpstrRtnString, wPtnLength, NULL);

3、關閉媒體設備 

    應用程序在使用完一個打開的多媒體設備后,必須向MCI發送一個MCI_CLOSE消息來關閉設備。應該注意的是,在應用程序退出之前,應關閉所有的MCI設備。這時可以使用MCI_ALL_DEVICE_ID常量,只需一條命令就關閉所有的多媒體設備。下面一段代碼演示了關閉所有設備。 

mciSendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, 0, NULL);
    也可以使用close字符串命令關閉使用完的MCI設備。例如: 

#define wPtnLength 255; //緩沖區大小

char lpstrRtnString[wPtnLength]; //指向緩沖區指針

mciSendString("close cdaudio", lpstrRtnString, wPtnLength, NULL);
    與基於消息的命令一樣,在退出應用程序之前,應關閉所有的設備,這時可以使用all參數,實例如下: 

#define wPtnLength 255; //緩沖區大小

char lpstrRtnString[wPtnLength]; //指向緩沖區指針

mciSendString("close all", lpstrRtnString, wPtnLength, NULL);
 

4、暫停多媒體播放 

    暫停多媒體播放可以通過向MCI發送MCI_PAUSE命令實現,實例如下: 

WORD wDeviceID;

MCI_PLAY_PARMS mciPlayParam;

mciSendCommand(wDeviceID, MCI_PAUSE, NULL, (DWORD)(LPVOID)&mciPlayParam);
 

5、獲取和設置播放信息 

    在播放媒體時,很多時候需要獲取播放信息,如波形音頻的采樣率、通道數和量化位數、CD音頻文件總長度等。這時,可以通過向MCI發送MCI_STATUS命令實現。下面一段代碼可以用來獲取波形音頻的采樣率和通道數。 

WORD wDeviceID;

MCI_STATUS_PARAM StatusParam;

StatusParam.dwItem = MCI_WAVE_STATUS_SAMPLESPERSEC;

mciSendCommand(wDeviceID, MCI_STATUS, MCI_WAIT | MCI_STATUS_ITTEM, &StatusParam);

DWORD samplerate = StatusParam.dwReturn; //該參數返回采樣率

StatusParam.dwItem = MCI_WAVE_STATUS_CHANNLES;

mciSendCommand(wDeviceID, MCI_STATUS, MCI_WAIT | MCI_STATUS_ITTEM, &StatusParam);

DWORD channelnumber = StatusParam.dwReturn; //該參數返回通道數
    也可以采用字符串命令的方式獲得播放信息,實例如下: 

MCIERROR mciError;

mciError = mciSendString("open waveaudio", buf, strlen(buf), NULL);
    同樣,在進行編程時,有時也需要對媒體設備的一些播放信息進行設置。這可以通過向已經打開的媒體設備發送MCI_SET命令實現。例如下面一段代碼用來設置音頻的播放格式為毫秒方式。 

WORD wDeviceID;

MCI_SET_PARMS SetParam;

SetParam.dwFormat = MCI_FORMAT_MILLISECONDS;

DWORD OpenFlag = mciSendCommand(wDeviceID, MCI_SET, MCI_TIME_FORMT, &SetParam);
    采用字符串命令設置媒體播放格式的代碼如下: 

MCIERROR mciError;

mciError = mciSendString("Set file format milliseconds", buf, strlen(buf), NULL);


6、播放的跳轉 

    在媒體播放過程中進行跳轉首先需要聲明一個MCI_SEEK_PARMS結構,並使用該結構的dwTo字段設定需要播放的位置,該位置以毫秒為單位。然后通過mciSendCommand函數向指定設備以MCI_TO為標志發送MCI_SEEK命令,如果只需要跳轉到文件的開始或結束位置,可以直接使用MCI_SEEK_TO_START和MCI_SEEK_TO_END為標識發送MCI_SEEK命令。例如: 

WORD wDeviceID;

int nMinute; //欲跳轉的時間,以分鍾為單位

MCI_SEEK_PARMS SeekParam;

SeekParam.dwTo = (nNinute*60+nSecond)*1000; //跳轉的目標時間,以毫秒為單位

mciSendCommand(wDeviceID, MCI_SEEK, MCI_SEEK_TO | MCI_WAIT, (DWORD)(LPVOID)&SetParam);
    下段代碼通過MCI_SEEK命令使CD音頻在nTrack軌道,第nMinute分鍾,第nSecond秒的nFrame幀進行播放。 

int nTrack, nMinute, nSecond;

WORD wDeviceID;

MCI_SEEK_PARMS SeekParam;

SeekParam.dwTo = MCI_MAKE_TWSF(nTrack, nMinute, nSecond, nFrame);

mciSendCommand(wDevice, MCI_SEEK, MCI_SEEK_TO | MCI_WAIT, (DWORD)(LPVOID)&SetParam);
 

7、波形音頻的錄制和保存 

    在進行波形音頻編程時,記錄音頻設備輸入的音頻信息也能實現錄音功能。可以通過向打開的音頻設備發送MCI_RECORD命令實現該功能。例如: 

WORD wDeviceID;

MCI_RECORD_PARMS RecordParam;

RecFlag = mciSendCommand(wDeviceID, MCI_RECORD, NULL, &RecordParam);
    

8、此外,保存音頻設備的聲音數據wav文件可以通過向設備發送MCI_SAVE命令實現。例如: 

WORD wDeviceID;

MCI_SAVE_PARMS SaveParam;

SaveParam.lpfilename = (LPCSTR) FileName;

DWORD SaveFlag = mciSendCommand(wDeviceID, MCI_SAVE, MCI_SAVE_FILE | MCI_WAIT, &SaveParam);
 

9、常用字符串命令

1.打開:

Dim mName as string

mName = "f://mpeg//mpeg1.avi"

mciSendString "open mName type MPEGVideo Alias movie parent %u Style %u
notify",0&, 0, 0

其中:

open 操作命令

mName 全路徑文件名

type MPEGVideo 是指打開MPEG,AVI等類型,如果不加這一句,就是打開WAV,MP3等

Alias movie 定義了該操作的別名為movie,后續操作只要指明別名即可

parent %u 源

Style %u 風格、樣式

notify 通知


2.播放:

mciSendString "play movie", 0&, 0, 0

mciSendString "play movie fullscreen", 0&, 0, 0 '全屏播放

3.暫停:
mciSendString "pause movie", 0&, 0, 0

4.繼續:
mciSendString "resume movie", 0&, 0, 0
5.停止:
mciSendString "stop movie", 0&, 0, 0
6.關閉:
mciSendString "close movie", 0&, 0, 0
7.前進到下一個位置:
mciSendString "step movie", 0&, 0, 0

8.后退到上一個位置:
mciSendString "step movie reverse", 0&, 0, 0

9.前進或后退 N 個位置(其中 N<0 即表示后退)
mciSendString "step movie by " & str(N), 0&, 0, 0

10.獲取當前播放位置:
Dim ST As String*64
mciSendString "status movie position", st, len(st), 0

11. 獲取媒體的總長度:
mciSendString "status movie length", st, len(st), 0
l=val(st) 'L就是所播放文件的長度


12.獲取播放信息:

Dim ST As String*64

mciSendString "status movie mode", ST, Len(ST), 0

If Left(ST, 7) = "stopped" Then (處理代碼) '播放完畢

13.循環播放:
mciSendString "play movie repeat", 0&, 0, 0

14.控制聲音大小:
Dim V As Long
mciSendString "status movie volume", V, 0, 0 'V是獲取的音量大小值。

V = 50

mciSendString "setaudio movie volume to " & V, &0, 0, 0 'V是設置的音量值

15.控制亮度(如果是播放視頻)
Dim B As Long
mciSendString "status movie brightness", B, 0, 0 'B是獲取的亮度值。

B = 50

mciSendString "setvideo movie brightness to " & B, &0, 0, 0 'B是設置的亮度值

16.到指定的位置播放。
Dim P1 as Long, P2 as Long
P1 = 100: P2 = 3000
mciSendString "seek movie to ", P1, 0, 0 'P1是當前起始位置,單位:毫秒

mciSendString "seek movie to start", 0&, 0, 0 '定位到開頭位置
mciSendString "play movie", 0&, 0, 0 '定位后再播放

或者:

mciSendString "play movie FROM P1 to P2",0&, 0, 0 'P1是起始位置,P2是停止位置。單位:毫秒
  mciSendString "seek movie to end", 0&, 0, 0 '定位到最后位置


17.在指定控件上播放視頻:

mciSendString "open AVI 文件名 parent hWnd style child", 0&, 0, 0

其中,hWnd 是控件的句柄

執行上述命令之后,影片會被放置在控件的左上角,且影片的大小不受控件大小的影響,如果想要改變

影片播放的位置及大小,可以在執行 play 指令前先執行 put 指令,格式如下:

mciendString "put AVI 文件名 window at X Y [Width Height]", 0&, 0, 0

其中 X 及 Y 參數須填入位置,而 Width 及 Height 參數則填入影片顯示出來的寬度及高度


18.錄音設置:

  錄音前,用以下語句初始化

  1.設為8位:

mciSendString "set wave bitpersample 8", "", 0, 0

  2.設為11025Hz

mciSendString "set wave samplespersec 11025", "", 0, 0

  3.設為立體聲:

mciSendString "set wave channels 2", "", 0, 0

  4.實現PCM格式(不一定正確):

MCISENDSTRING "set wave format tag pcm","", 0, 0

  5.開始錄音:

mciSendString "close movie",0&,0,0

mciSendString "open new type WAVEAudio alias movie",0&,0,0

mciSendString "record movie",0&,0,0

  6.保存錄音到c:/123.wav

mciSendString "stop movie",0&,0,0

mciSendString "save movie C://123.wav",0&,0,0

mciSendString "close movie",0&,0,0


19.開關光驅:

mciSendString "set cdaudio door open", "", 0, 0 '打開
mciSendString "set cdaudio door close", "", 0, 0 '關閉

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM