first commit
This commit is contained in:
parent
9790a5757c
commit
f768bbec4b
8
CMakeLists.txt
Normal file
8
CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
project(CMPlatform)
|
||||
|
||||
include(path_config.cmake)
|
||||
CMPlatformSetup(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
add_subdirectory(${CMPLATFORM_ROOT_SOURCE_PATH})
|
207
inc/hgl/platform/InputDevice.h
Normal file
207
inc/hgl/platform/InputDevice.h
Normal file
@ -0,0 +1,207 @@
|
||||
#ifndef HGL_INPUT_DEVICE_INCLUDE
|
||||
#define HGL_INPUT_DEVICE_INCLUDE
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
/**
|
||||
* 鼠标状态枚举定义
|
||||
*/
|
||||
enum MouseButton
|
||||
{
|
||||
mbMove =0x00000001, ///<鼠标移动了
|
||||
|
||||
mbLeft =0x00000002, ///<鼠标左键处于按下状态
|
||||
mbMid =0x00000004, ///<鼠标中键处于按下状态
|
||||
mbRight =0x00000008, ///<鼠标右键处于按下状态
|
||||
|
||||
mbX1 =0x00000010,
|
||||
mbX2 =0x00000020,
|
||||
|
||||
mbShift =0x10000000, ///<Shift键处于按下状态
|
||||
mbCtrl =0x20000000, ///<Ctrl键处于按下状态
|
||||
};
|
||||
|
||||
/**
|
||||
* 按键枚举定义
|
||||
*/
|
||||
enum KeyboardButton
|
||||
{
|
||||
kbBeginRange=0,
|
||||
|
||||
//主键盘区
|
||||
kbEsc, ///<ESC
|
||||
|
||||
//F功能键
|
||||
kbF1, ///<F1
|
||||
kbF2, ///<F2
|
||||
kbF3, ///<F3
|
||||
kbF4, ///<F4
|
||||
kbF5, ///<F5
|
||||
kbF6, ///<F6
|
||||
kbF7, ///<F7
|
||||
kbF8, ///<F8
|
||||
kbF9, ///<F9
|
||||
kbF10, ///<F10
|
||||
kbF11, ///<F11
|
||||
kbF12, ///<F12
|
||||
|
||||
kbGrave, //<`号(主键盘数字键1左边的按钮)
|
||||
|
||||
//10个数字
|
||||
kb0, ///<数字键0
|
||||
kb1, ///<数字键1
|
||||
kb2, ///<数字键2
|
||||
kb3, ///<数字键3
|
||||
kb4, ///<数字键4
|
||||
kb5, ///<数字键5
|
||||
kb6, ///<数字键6
|
||||
kb7, ///<数字键7
|
||||
kb8, ///<数字键8
|
||||
kb9, ///<数字键9
|
||||
|
||||
kbMinus, ///< - (减号)
|
||||
kbEquals, ///< = (等号)
|
||||
kbBackSlash, ///< \ (反斜杠)
|
||||
kbBackSpace, ///< 退格键
|
||||
|
||||
kbTab, ///<Tab键
|
||||
|
||||
kbA, ///<A
|
||||
kbB, ///<B
|
||||
kbC, ///<C
|
||||
kbD, ///<D
|
||||
kbE, ///<E
|
||||
kbF, ///<F
|
||||
kbG, ///<G
|
||||
kbH, ///<H
|
||||
kbI, ///<I
|
||||
kbJ, ///<J
|
||||
kbK, ///<K
|
||||
kbL, ///<L
|
||||
kbM, ///<M
|
||||
kbN, ///<N
|
||||
kbO, ///<O
|
||||
kbP, ///<P
|
||||
kbQ, ///<Q
|
||||
kbR, ///<R
|
||||
kbS, ///<S
|
||||
kbT, ///<T
|
||||
kbU, ///<U
|
||||
kbV, ///<V
|
||||
kbW, ///<W
|
||||
kbX, ///<X
|
||||
kbY, ///<Y
|
||||
kbZ, ///<Z
|
||||
|
||||
kbLeftBracket, ///<[
|
||||
kbRightBracket, ///<]
|
||||
|
||||
kbCapsLock, ///<大写锁定键
|
||||
|
||||
kbSemicolon, ///<; (分号)
|
||||
kbApostrophe, ///<' (单引号)
|
||||
kbEnter, ///<回车键
|
||||
|
||||
kbLeftShift, ///<左边的Shift键
|
||||
|
||||
kbComma, ///<, (逗号)
|
||||
kbPeriod, ///<. (句号)
|
||||
kbSlash, ///</ (除号)
|
||||
kbRightShift, ///<右边的Shift键
|
||||
|
||||
kbLeftCtrl, ///<左边的Ctrl键
|
||||
kbLeftOS, ///<左边的OS键(Win/Apple键)
|
||||
kbLeftAlt, ///<左边的Alt键
|
||||
kbSpace, ///<空格键
|
||||
kbRightAlt, ///<右边的Alt键
|
||||
kbRightOS, ///<右边的OS键(Win/Apple键)
|
||||
kbRightMenu, ///<右边的Menu键
|
||||
kbRightCtrl, ///<右边的Ctrl键
|
||||
|
||||
//中键盘区
|
||||
kbPrintScreen, ///<打印屏幕键
|
||||
kbScrollLock, ///<滚动锁定键
|
||||
kbPause, ///<暂停键
|
||||
|
||||
kbInsert, ///<插入键
|
||||
kbDelete, ///<删除键
|
||||
kbHome, ///<行首键
|
||||
kbEnd, ///<行尾键
|
||||
kbPageUp, ///<向前翻页键
|
||||
kbPageDown, ///<向后翻页键
|
||||
|
||||
kbUp, ///<↑光标键
|
||||
kbDown, ///<↓光标键
|
||||
kbLeft, ///<←光标键
|
||||
kbRight, ///<→光标键
|
||||
|
||||
//小键盘区
|
||||
kbNumLock, ///<小键盘 数字锁定键
|
||||
|
||||
kbNumAdd, ///<小键盘 +
|
||||
kbNumSubtract, ///<小键盘 -
|
||||
kbNumMultiply, ///<小键盘 *
|
||||
kbNumDivide, ///<小键盘 /
|
||||
|
||||
kbNum0, ///<小键盘 0
|
||||
kbNum1, ///<小键盘 1
|
||||
kbNum2, ///<小键盘 2
|
||||
kbNum3, ///<小键盘 3
|
||||
kbNum4, ///<小键盘 4
|
||||
kbNum5, ///<小键盘 5
|
||||
kbNum6, ///<小键盘 6
|
||||
kbNum7, ///<小键盘 7
|
||||
kbNum8, ///<小键盘 8
|
||||
kbNum9, ///<小键盘 9
|
||||
|
||||
kbNumDecimal, ///<小键盘 . (小数点/删除键)
|
||||
kbNumEnter, ///<小键盘 回车键
|
||||
|
||||
kbEndRange,
|
||||
kbRangeSize=kbEndRange-kbBeginRange+1
|
||||
};//enum KeyboardButton
|
||||
|
||||
/**
|
||||
* 手柄按键枚举
|
||||
*/
|
||||
enum JoystickButton
|
||||
{
|
||||
jbBeginRange=0,
|
||||
|
||||
jbUp,
|
||||
jbDown,
|
||||
jbLeft,
|
||||
jbRight,
|
||||
|
||||
jb0, jb1, jb2, jb3, jb4, jb5, jb6, jb7,
|
||||
jb8, jb9, jb10, jb11, jb12, jb13, jb14, jb15,
|
||||
jb16, jb17, jb18, jb19, jb20, jb21, jb22, jb23,
|
||||
jb24, jb25, jb26, jb27, jb28, jb29, jb30, jb31,
|
||||
|
||||
jbEnd,
|
||||
|
||||
//DreamCast/XBOX
|
||||
/* jbX=jb2,
|
||||
jbY=jb3,
|
||||
jbA=jb0,
|
||||
jbB=jb1,
|
||||
jbL=jb4,
|
||||
jbR=jb5,*/
|
||||
|
||||
//PlayStation
|
||||
jbTriangle =jb0, // 三角
|
||||
jbCircle =jb1, // 圆
|
||||
jbFork =jb2, // 叉
|
||||
jbRectangle =jb3, // 方
|
||||
jbL1 =jb6, jbL2 =jb4,
|
||||
jbR1 =jb7, jbR2 =jb5,
|
||||
jbSelect =jb8, jbStart =jb9,
|
||||
|
||||
//XBOX/XBOX360
|
||||
jbXBOX, //西瓜键
|
||||
|
||||
jbEndRange,
|
||||
jbRangeSize=jbEndRange-jbBeginRange+1
|
||||
};
|
||||
}//namespace hgl
|
||||
#endif//HGL_INPUT_DEVICE_INCLUDE
|
12
inc/hgl/platform/Vulkan.h
Normal file
12
inc/hgl/platform/Vulkan.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef HGL_PLATFORM_VULKAN_INCLUDE
|
||||
#define HGL_PLATFORM_VULKAN_INCLUDE
|
||||
|
||||
#include<vulkan/vulkan.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
class Window;
|
||||
|
||||
VkSurfaceKHR CreateVulkanSurface(VkInstance,Window *);
|
||||
}//namespace hgl
|
||||
#endif//HGL_PLATFORM_VULKAN_INCLUDE
|
119
inc/hgl/platform/Window.h
Normal file
119
inc/hgl/platform/Window.h
Normal file
@ -0,0 +1,119 @@
|
||||
#ifndef HGL_GRAPH_WINDOW_INCLUDE
|
||||
#define HGL_GRAPH_WINDOW_INCLUDE
|
||||
|
||||
#include<hgl/type/BaseString.h>
|
||||
#include<hgl/platform/InputDevice.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
class Window
|
||||
{
|
||||
protected:
|
||||
|
||||
uint width,height;
|
||||
bool full_screen;
|
||||
|
||||
OSString win_name;
|
||||
|
||||
bool active;
|
||||
bool is_close;
|
||||
bool is_min;
|
||||
|
||||
bool key_push[kbRangeSize];
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool MessageProc()=0;
|
||||
virtual bool WaitMessage()=0;
|
||||
|
||||
public:
|
||||
|
||||
virtual void ProcMouseMove (int x,int y) {SafeCallEvent(OnMouseMove, (x,y));}
|
||||
virtual void ProcMouseWheel (int v,int h,uint mb) {SafeCallEvent(OnMouseWheel, (v,h,mb));}
|
||||
virtual void ProcMouseDown (int x,int y,uint mb) {SafeCallEvent(OnMouseDown, (x,y,mb));}
|
||||
virtual void ProcMouseUp (int x,int y,uint mb) {SafeCallEvent(OnMouseUp, (x,y,mb));}
|
||||
virtual void ProcMouseDblClick (int x,int y,uint mb) {SafeCallEvent(OnMouseDblClick, (x,y,mb));}
|
||||
|
||||
//virtual void ProcJoystickDown (uint);
|
||||
//virtual void ProcJoystickPress (uint);
|
||||
//virtual void ProcJoystickUp (uint);
|
||||
|
||||
virtual void ProcKeyDown (KeyboardButton);
|
||||
virtual void ProcKeyPress (KeyboardButton kb){SafeCallEvent(OnKeyPress,(kb));}
|
||||
virtual void ProcKeyUp (KeyboardButton);
|
||||
|
||||
virtual void ProcChar (os_char ch){SafeCallEvent(OnChar,(ch));}
|
||||
|
||||
virtual void ProcResize (uint,uint);
|
||||
|
||||
virtual void ProcActive (bool);
|
||||
virtual void ProcClose ();
|
||||
|
||||
public:
|
||||
|
||||
uint GetWidth()const{return width;}
|
||||
uint GetHeight()const{return height;}
|
||||
|
||||
public:
|
||||
|
||||
DefEvent(void,OnMouseMove ,(int,int));
|
||||
DefEvent(void,OnMouseWheel ,(int,int,uint));
|
||||
DefEvent(void,OnMouseDown ,(int,int,uint));
|
||||
DefEvent(void,OnMouseUp ,(int,int,uint));
|
||||
DefEvent(void,OnMouseDblClick ,(int,int,uint));
|
||||
|
||||
//DefEvent(void,OnJoystickDown ,(uint));
|
||||
//DefEvent(void,OnJoystickPress ,(uint));
|
||||
//DefEvent(void,OnJoystickUp ,(uint));
|
||||
|
||||
DefEvent(void,OnKeyDown ,(KeyboardButton));
|
||||
DefEvent(void,OnKeyPress,(KeyboardButton));
|
||||
DefEvent(void,OnKeyUp ,(KeyboardButton));
|
||||
|
||||
DefEvent(void,OnChar ,(os_char));
|
||||
|
||||
DefEvent(void,OnResize ,(uint,uint));
|
||||
|
||||
DefEvent(void,OnActive ,(bool));
|
||||
DefEvent(void,OnClose ,());
|
||||
|
||||
public:
|
||||
|
||||
Window(const OSString &wn)
|
||||
{
|
||||
width=height=0;
|
||||
full_screen=false;
|
||||
win_name=wn;
|
||||
active=false;
|
||||
is_close=true;
|
||||
is_min=false;
|
||||
hgl_zero(key_push);
|
||||
}
|
||||
virtual ~Window()=default;
|
||||
|
||||
virtual bool Create(uint,uint)=0;
|
||||
virtual bool Create(uint,uint,uint)=0;
|
||||
virtual void Close()=0;
|
||||
|
||||
bool IsMin()const{return is_min;}
|
||||
bool IsClose()const{return is_close;}
|
||||
bool IsVisible()const{return (!is_close)&&width&&height;}
|
||||
|
||||
virtual void SetCaption(const OSString &)=0;
|
||||
|
||||
virtual void Show()=0;
|
||||
virtual void Hide()=0;
|
||||
|
||||
virtual void ToMinWindow()=0;
|
||||
virtual void ToMaxWindow()=0;
|
||||
|
||||
virtual void SetSystemCursor(bool){}
|
||||
|
||||
virtual bool Update();
|
||||
};//class Window
|
||||
|
||||
Window *CreateRenderWindow(const OSString &win_name);
|
||||
|
||||
void InitNativeWindowSystem();
|
||||
}//namespace hgl
|
||||
#endif//HGL_GRAPH_WINDOW_INCLUDE
|
9
path_config.cmake
Normal file
9
path_config.cmake
Normal file
@ -0,0 +1,9 @@
|
||||
macro(CMPlatformSetup source_path)
|
||||
|
||||
message("CMPLATFORM_ROOT_PATH: " ${source_path})
|
||||
|
||||
set(CMPLATFORM_ROOT_INCLUDE_PATH ${source_path}/inc)
|
||||
set(CMPLATFORM_ROOT_SOURCE_PATH ${source_path}/src)
|
||||
|
||||
include_directories(${CMPLATFORM_ROOT_INCLUDE_PATH})
|
||||
endmacro()
|
344
src/Android/AndroidMain.cpp
Normal file
344
src/Android/AndroidMain.cpp
Normal file
@ -0,0 +1,344 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "AndroidProject1.NativeActivity", __VA_ARGS__))
|
||||
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "AndroidProject1.NativeActivity", __VA_ARGS__))
|
||||
|
||||
/**
|
||||
* Our saved state data.
|
||||
*/
|
||||
struct saved_state
|
||||
{
|
||||
float angle;
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
};
|
||||
|
||||
/**
|
||||
* Shared state for our app.
|
||||
*/
|
||||
struct engine
|
||||
{
|
||||
struct android_app* app;
|
||||
|
||||
ASensorManager* sensorManager;
|
||||
const ASensor* accelerometerSensor;
|
||||
ASensorEventQueue* sensorEventQueue;
|
||||
ASensorEvent acceleration_event;
|
||||
|
||||
int animating;
|
||||
EGLDisplay display;
|
||||
EGLSurface surface;
|
||||
EGLContext context;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
struct saved_state state;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize an EGL context for the current display.
|
||||
*/
|
||||
static int engine_init_display(struct engine* engine)
|
||||
{
|
||||
// initialize OpenGL ES and EGL
|
||||
|
||||
/*
|
||||
* Here specify the attributes of the desired configuration.
|
||||
* Below, we select an EGLConfig with at least 8 bits per color
|
||||
* component compatible with on-screen windows
|
||||
*/
|
||||
const EGLint config_attrs[] =
|
||||
{
|
||||
EGL_DEPTH_SIZE, 0,
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
EGL_BLUE_SIZE, 8,
|
||||
EGL_ALPHA_SIZE, 8,
|
||||
EGL_STENCIL_SIZE, 8,
|
||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, //即使是用es3这里也写es2
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
const EGLint context_attrs[] =
|
||||
{
|
||||
EGL_CONTEXT_CLIENT_VERSION, 3,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
EGLint w, h, format;
|
||||
EGLint numConfigs;
|
||||
EGLConfig config;
|
||||
EGLSurface surface;
|
||||
EGLContext context;
|
||||
|
||||
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
|
||||
eglInitialize(display, 0, 0);
|
||||
|
||||
EGLint config_count;
|
||||
bool depth_check=false;
|
||||
const EGLint depth_bit_sizes[]={24,16};
|
||||
|
||||
for(uint i=0;i<sizeof(depth_bit_sizes)/sizeof(EGLint);i++)
|
||||
{
|
||||
config_attrs[1]=depth_bit_sizes[i];
|
||||
|
||||
if(eglChooseConfig(display,config_attrs,&egl_config,1,&config_count)==EGL_TRUE)
|
||||
if(config_count>0)
|
||||
{
|
||||
depth_check=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!depth_check)
|
||||
return(-1);
|
||||
|
||||
/* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
|
||||
* guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
|
||||
* As soon as we picked a EGLConfig, we can safely reconfigure the
|
||||
* ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
|
||||
eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
|
||||
|
||||
ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format);
|
||||
|
||||
surface = eglCreateWindowSurface(display, config, engine->app->window, nullptr);
|
||||
|
||||
context = eglCreateContext(display, config, nullptr, context_attrs);
|
||||
|
||||
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
|
||||
{
|
||||
LOGW("Unable to eglMakeCurrent");
|
||||
return -1;
|
||||
}
|
||||
|
||||
eglQuerySurface(display, surface, EGL_WIDTH, &w);
|
||||
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
|
||||
|
||||
engine->display = display;
|
||||
engine->context = context;
|
||||
engine->surface = surface;
|
||||
engine->width = w;
|
||||
engine->height = h;
|
||||
engine->state.angle = 0;
|
||||
|
||||
// Initialize GL state.
|
||||
Cube_setupGL(w, h);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Just the current frame in the display.
|
||||
*/
|
||||
|
||||
static void engine_draw_frame(struct engine* engine)
|
||||
{
|
||||
if (engine->display == nullptr) {
|
||||
// No display.
|
||||
return;
|
||||
}
|
||||
|
||||
Cube_prepare();
|
||||
|
||||
Cube_draw();
|
||||
|
||||
eglSwapBuffers(engine->display, engine->surface);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tear down the EGL context currently associated with the display.
|
||||
*/
|
||||
static void engine_term_display(struct engine* engine)
|
||||
{
|
||||
if (engine->display != EGL_NO_DISPLAY)
|
||||
{
|
||||
eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
|
||||
if (engine->context != EGL_NO_CONTEXT)
|
||||
{
|
||||
eglDestroyContext(engine->display, engine->context);
|
||||
}
|
||||
|
||||
if (engine->surface != EGL_NO_SURFACE)
|
||||
{
|
||||
eglDestroySurface(engine->display, engine->surface);
|
||||
}
|
||||
|
||||
eglTerminate(engine->display);
|
||||
}
|
||||
|
||||
engine->animating = 0;
|
||||
engine->display = EGL_NO_DISPLAY;
|
||||
engine->context = EGL_NO_CONTEXT;
|
||||
engine->surface = EGL_NO_SURFACE;
|
||||
|
||||
Cube_tearDownGL();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the next input event.
|
||||
*/
|
||||
static int32_t engine_handle_input(struct android_app* app, AInputEvent* event)
|
||||
{
|
||||
struct engine* engine = (struct engine*)app->userData;
|
||||
|
||||
if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION)
|
||||
{
|
||||
engine->state.x = AMotionEvent_getX(event, 0);
|
||||
engine->state.y = AMotionEvent_getY(event, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the next main command.
|
||||
*/
|
||||
static void engine_handle_cmd(struct android_app* app, int32_t cmd)
|
||||
{
|
||||
struct engine* engine = (struct engine*)app->userData;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case APP_CMD_SAVE_STATE: // The system has asked us to save our current state. Do so.
|
||||
engine->app->savedState = malloc(sizeof(struct saved_state));
|
||||
*((struct saved_state*)engine->app->savedState) = engine->state;
|
||||
engine->app->savedStateSize = sizeof(struct saved_state);
|
||||
break;
|
||||
|
||||
case APP_CMD_INIT_WINDOW: // The window is being shown, get it ready.
|
||||
if (engine->app->window != nullptr)
|
||||
{
|
||||
engine_init_display(engine);
|
||||
engine_draw_frame(engine);
|
||||
}
|
||||
break;
|
||||
|
||||
case APP_CMD_TERM_WINDOW: // The window is being hidden or closed, clean it up.
|
||||
engine_term_display(engine);
|
||||
break;
|
||||
|
||||
case APP_CMD_GAINED_FOCUS: // When our app gains focus, we start monitoring the accelerometer.
|
||||
if (engine->accelerometerSensor != nullptr)
|
||||
{
|
||||
ASensorEventQueue_enableSensor(engine->sensorEventQueue,engine->accelerometerSensor);
|
||||
// We'd like to get 60 events per second (in us).
|
||||
ASensorEventQueue_setEventRate(engine->sensorEventQueue,engine->accelerometerSensor, (1000L / 60) * 1000);
|
||||
}
|
||||
break;
|
||||
|
||||
case APP_CMD_LOST_FOCUS: // When our app loses focus, we stop monitoring the accelerometer.
|
||||
// This is to avoid consuming battery while not being used.
|
||||
if (engine->accelerometerSensor != nullptr)
|
||||
{
|
||||
ASensorEventQueue_disableSensor(engine->sensorEventQueue,engine->accelerometerSensor);
|
||||
}
|
||||
// Also stop animating.
|
||||
engine->animating = 0;
|
||||
engine_draw_frame(engine);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main entry point of a native application that is using
|
||||
* android_native_app_glue. It runs in its own thread, with its own
|
||||
* event loop for receiving input events and doing other things.
|
||||
*/
|
||||
void android_main(struct android_app* state)
|
||||
{
|
||||
struct engine engine;
|
||||
|
||||
memset(&engine, 0, sizeof(engine));
|
||||
state->userData = &engine;
|
||||
state->onAppCmd = engine_handle_cmd;
|
||||
state->onInputEvent = engine_handle_input;
|
||||
engine.app = state;
|
||||
|
||||
// Prepare to monitor accelerometer
|
||||
engine.sensorManager = ASensorManager_getInstance();
|
||||
engine.accelerometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager,ASENSOR_TYPE_ACCELEROMETER);
|
||||
engine.sensorEventQueue = ASensorManager_createEventQueue(engine.sensorManager,state->looper, LOOPER_ID_USER, nullptr, nullptr);
|
||||
|
||||
if (state->savedState != nullptr)
|
||||
{
|
||||
// We are starting with a previous saved state; restore from it.
|
||||
engine.state = *(struct saved_state*)state->savedState;
|
||||
}
|
||||
|
||||
engine.animating = 1;
|
||||
|
||||
// loop waiting for stuff to do.
|
||||
while (1)
|
||||
{
|
||||
// Read all pending events.
|
||||
int ident;
|
||||
int events;
|
||||
struct android_poll_source* source;
|
||||
|
||||
// If not animating, we will block forever waiting for events.
|
||||
// If animating, we loop until all events are read, then continue
|
||||
// to draw the next frame of animation.
|
||||
while ((ident = ALooper_pollAll(engine.animating ? 0 : -1, nullptr, &events,(void**)&source)) >= 0)
|
||||
{
|
||||
// Process this event.
|
||||
if (source != nullptr)
|
||||
{
|
||||
source->process(state, source);
|
||||
}
|
||||
|
||||
// If a sensor has data, process it now.
|
||||
if (ident == LOOPER_ID_USER)
|
||||
{
|
||||
if (engine.accelerometerSensor != nullptr)
|
||||
{
|
||||
while (ASensorEventQueue_getEvents(engine.sensorEventQueue,&engine->acceleration_event;, 1) > 0)
|
||||
{
|
||||
LOGI("accelerometer: x=%f y=%f z=%f",
|
||||
engine->acceleration_event.acceleration.x,
|
||||
engine->acceleration_event.acceleration.y,
|
||||
engine->acceleration_event.acceleration.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we are exiting.
|
||||
if (state->destroyRequested != 0)
|
||||
{
|
||||
engine_term_display(&engine);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (engine.animating)
|
||||
{
|
||||
// Done with events; draw next animation frame.
|
||||
Cube_update();
|
||||
//if (engine.state.angle > 1) {
|
||||
// engine.state.angle = 0;
|
||||
//}
|
||||
|
||||
// Drawing is throttled to the screen update rate, so there
|
||||
// is no need to do timing here.
|
||||
engine_draw_frame(&engine);
|
||||
}
|
||||
}
|
||||
}
|
29
src/Android/AndroidVulkan.cpp
Normal file
29
src/Android/AndroidVulkan.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
#include"AndroidWindow.h"
|
||||
#include<vulkan/vulkan_android.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
VkSurfaceKHR AndroidWindow::CreateSurface(VkInstance vk_inst)
|
||||
{
|
||||
PFN_vkCreateAndroidSurfaceKHR CreateAndroidSurfaceKHR;
|
||||
|
||||
GET_INSTANCE_PROC_ADDR(vk_inst,CreateAndroidSurfaceKHR);
|
||||
|
||||
if(!CreateAndroidSurfaceKHR)
|
||||
return(nullptr);
|
||||
|
||||
VkAndroidSurfaceCreateInfoKHR createInfo;
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
|
||||
createInfo.pNext = nullptr;
|
||||
createInfo.window = AndroidGetApplicationWindow();
|
||||
|
||||
VkSurfaceKHR surface;
|
||||
|
||||
VkResult res=CreateAndroidSurfaceKHR(vk_inst,&createInfo,nullptr,&surface);
|
||||
|
||||
if(res!=VK_SUCCESS)
|
||||
return(nullptr);
|
||||
|
||||
return(surface);
|
||||
}
|
||||
}//namespace hgl
|
109
src/Android/AssetManage.cpp
Normal file
109
src/Android/AssetManage.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
#include<hgl/filesystem/AssetManage.h>
|
||||
#include<hgl/io/InputStream.h>
|
||||
#include<android/asset_manager.h>
|
||||
#include<android/asset_manager_jni.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace
|
||||
{
|
||||
static AAssetManager *asset_manager=nullptr;
|
||||
|
||||
class AndroidAssetInputStream:public io::InputStream
|
||||
{
|
||||
AAsset *asset;
|
||||
|
||||
public:
|
||||
|
||||
AndroidAssetInputStream(AAsset *a)
|
||||
{
|
||||
asset=a;
|
||||
}
|
||||
|
||||
~AndroidAssetInputStream()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void Close() override
|
||||
{
|
||||
if(!asset)return;
|
||||
|
||||
AAsset_close(asset);
|
||||
asset=nullptr;
|
||||
}
|
||||
|
||||
int64 Read(void *data,int64 size) override
|
||||
{
|
||||
return AAsset_read(asset,data,size);
|
||||
}
|
||||
|
||||
int64 Peek(void *data,int64 size) override
|
||||
{
|
||||
int64 left=Avaiable();
|
||||
|
||||
if(left<size)
|
||||
size=left;
|
||||
|
||||
int64 result=Read(data,size);
|
||||
|
||||
if(result>0)
|
||||
Seek(-result,SeekOrigin::Current);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int64 ReadFully(void *buf,int64 buf_size){return Read(buf,buf_size);} ///<充分读取,保证读取到指定长度的数据(不计算超时)
|
||||
|
||||
bool CanRestart()const override{return(true);}
|
||||
bool CanSeek()const override{return(true);}
|
||||
bool CanSize()const override{return(true);}
|
||||
bool CanPeek()const override{return(false);}
|
||||
|
||||
bool Restart() override
|
||||
{
|
||||
Seek(0,soBegin);
|
||||
return(true);
|
||||
}
|
||||
|
||||
int64 Skip(int64 size) override
|
||||
{
|
||||
return Seek(size,SeekOrigin::Current);
|
||||
}
|
||||
|
||||
int64 Seek(int64 offset,SeekOrigin so) override
|
||||
{
|
||||
return AAsset_seek64(asset,offset,(int)so);
|
||||
}
|
||||
|
||||
int64 Tell()const override
|
||||
{
|
||||
return Seek(0,SeekOrigin::Current);
|
||||
}
|
||||
|
||||
int64 GetSize()const override
|
||||
{
|
||||
return AAsset_getLength64(asset);
|
||||
}
|
||||
|
||||
int64 Available()const override
|
||||
{
|
||||
return AAsset_getRemainingLength64(asset);
|
||||
}
|
||||
};//class AndroidAssetInputStream:public io::InputStream
|
||||
}//namespace
|
||||
|
||||
void InitAssetManager(AAssetManager *am)
|
||||
{
|
||||
asset_manager=am;
|
||||
}
|
||||
|
||||
io::InputStream *OpenAsset(const UTF8String &filename)
|
||||
{
|
||||
AAsset *asset = AAssetManager_open(asset_manager, filename.c_str(), AASSET_MODE_BUFFER);
|
||||
|
||||
if(!asset)return(nullptr);
|
||||
|
||||
return(new AndroidAssetInputStream(asset));
|
||||
}
|
||||
}//namespace hgl
|
25
src/Android/JNISupport.cpp
Normal file
25
src/Android/JNISupport.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include<hgl/platform/Platform.h>
|
||||
#include<jni.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace logger
|
||||
{
|
||||
void SetLocalAppdataPath(const char *fn);
|
||||
}//namespace logger
|
||||
|
||||
void InitAndroidSupport(JNIEnv *env,jobject obj)
|
||||
{
|
||||
jclass cls =env->GetObjectClass(obj);
|
||||
jmethodID getFilesDir =env->GetMethodID(cls, "getFilesDir", "()Ljava/io/File;");
|
||||
jobject dirobj =env->CallObjectMethod(obj,getFilesDir);
|
||||
jclass dir =env->GetObjectClass(dirobj);
|
||||
jmethodID getStoragePath =env->GetMethodID(dir, "getAbsolutePath", "()Ljava/lang/String;");
|
||||
jstring path =(jstring)env->CallObjectMethod(dirobj, getStoragePath);
|
||||
const char *pathstr =env->GetStringUTFChars(path, 0);
|
||||
|
||||
logger::SetLocalAppdataPath(pathstr);
|
||||
|
||||
env->ReleaseStringUTFChars(path, pathstr);
|
||||
}
|
||||
}//namespace hgl
|
146
src/Android/LogConsole.cpp
Normal file
146
src/Android/LogConsole.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
#include<hgl/Logger.h>
|
||||
#include<hgl/CodePage.h>
|
||||
#include<hgl/thread/ThreadMutex.h>
|
||||
#include<unistd.h>
|
||||
#include<pthread.h>
|
||||
|
||||
#ifdef LOG_INFO_TIME
|
||||
#include<hgl/Time.h>
|
||||
#endif//LOG_INFO_TIME
|
||||
|
||||
#include<android/log.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace logger
|
||||
{
|
||||
constexpr uint LOG_BUF_SIZE=4096;
|
||||
|
||||
constexpr android_LogPriority android_priority[]={ ANDROID_LOG_ERROR, //llError
|
||||
ANDROID_LOG_WARN, //llProblem
|
||||
ANDROID_LOG_INFO, //llHint
|
||||
ANDROID_LOG_VERBOSE}; //llLog
|
||||
|
||||
/**
|
||||
* Android控制台日志插件接口
|
||||
*/
|
||||
class LogAndroidConsole:public Logger
|
||||
{
|
||||
char endline;
|
||||
char thread_string[256];
|
||||
char time_string[256];
|
||||
char log_buf[LOG_BUF_SIZE];
|
||||
|
||||
#ifdef LOGINFO_THREAD_MUTEX
|
||||
ThreadMutex mutex;
|
||||
#endif//LOGINFO_THREAD_MUTEX
|
||||
|
||||
android_LogPriority prio;
|
||||
|
||||
public:
|
||||
|
||||
LogAndroidConsole(LogLevel ll):Logger(ll)
|
||||
{
|
||||
prio=android_priority[ll];
|
||||
|
||||
endline='\n';
|
||||
}
|
||||
|
||||
bool Create(const OSString &)
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
|
||||
void Close(){}
|
||||
|
||||
#ifdef LOG_INFO_THREAD
|
||||
void WriteThreadID()
|
||||
{
|
||||
memcpy(thread_string,"[Thread:",8);
|
||||
|
||||
htos(thread_string+8,128-9,pthread_self());
|
||||
strcat(thread_string,LOG_BUF_SIZE,']');
|
||||
}
|
||||
#endif//LOG_INFO_THREAD
|
||||
|
||||
#ifdef LOG_INFO_TIME
|
||||
void WriteTime()
|
||||
{
|
||||
memcpy(time_string,"[Time:",6);
|
||||
|
||||
ftos(time_string+6,128-strlen(time_string),GetDoubleTime());
|
||||
strcat(time_string,LOG_BUF_SIZE,']');
|
||||
}
|
||||
#endif//LOG_INFO_TIME
|
||||
|
||||
void Write(const u16char *str,int size)
|
||||
{
|
||||
#ifdef LOGINFO_THREAD_MUTEX
|
||||
mutex.Lock();
|
||||
#endif//LOGINFO_THREAD_MUTEX
|
||||
|
||||
log_buf[0]=0;
|
||||
|
||||
#ifdef LOG_INFO_THREAD
|
||||
WriteThreadID();
|
||||
strcpy(log_buf,LOG_BUF_SIZE,thread_string);
|
||||
#endif//LOG_INFO_THREAD
|
||||
|
||||
#ifdef LOG_INFO_TIME
|
||||
WriteTime();
|
||||
strcat(log_buf,LOG_BUF_SIZE,time_string);
|
||||
#endif//LOG_INFO_TIME
|
||||
|
||||
int len;
|
||||
|
||||
len=u16_to_u8(log_buf+hgl::strlen(log_buf),LOG_BUF_SIZE,str,size);
|
||||
|
||||
if(len>0)
|
||||
{
|
||||
log_buf[len++]=0;
|
||||
|
||||
__android_log_write(prio,"",log_buf);
|
||||
}
|
||||
#ifdef LOGINFO_THREAD_MUTEX
|
||||
mutex.Unlock();
|
||||
#endif//LOGINFO_THREAD_MUTEX
|
||||
}
|
||||
|
||||
void Write(const char *str,int size)
|
||||
{
|
||||
#ifdef LOGINFO_THREAD_MUTEX
|
||||
mutex.Lock();
|
||||
#endif//LOGINFO_THREAD_MUTEX
|
||||
|
||||
log_buf[0]=0;
|
||||
|
||||
#ifdef LOG_INFO_THREAD
|
||||
WriteThreadID();
|
||||
strcpy(log_buf,LOG_BUF_SIZE,thread_string);
|
||||
#endif//LOG_INFO_THREAD
|
||||
|
||||
#ifdef LOG_INFO_TIME
|
||||
WriteTime();
|
||||
strcat(log_buf,LOG_BUF_SIZE,time_string);
|
||||
#endif//LOG_INFO_TIME
|
||||
|
||||
strcpy(log_buf,LOG_BUF_SIZE,str,size);
|
||||
|
||||
__android_log_write(prio,"",log_buf);
|
||||
|
||||
#ifdef LOGINFO_THREAD_MUTEX
|
||||
mutex.Unlock();
|
||||
#endif//LOGINFO_THREAD_MUTEX
|
||||
}
|
||||
};//class LogAndroidConsole:public Logger
|
||||
|
||||
Logger *CreateLoggerConsole(const OSString &,LogLevel ll)
|
||||
{
|
||||
if(ll<llError)
|
||||
return(nullptr);
|
||||
|
||||
return(new LogAndroidConsole(ll));
|
||||
}
|
||||
}//logger
|
||||
}//namespace hgl
|
||||
|
15
src/Android/NativeActivitySupport.cpp
Normal file
15
src/Android/NativeActivitySupport.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#include<hgl/platform/Platform.h>
|
||||
#include<android/native_activity.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace logger
|
||||
{
|
||||
void SetLocalAppdataPath(const char *fn);
|
||||
}//namespace logger
|
||||
|
||||
void InitAndroidSupport(struct ANativeActivity *native_activity)
|
||||
{
|
||||
logger::SetLocalAppdataPath(native_activity->internalDataPath);
|
||||
}
|
||||
}//namespace hgl
|
75
src/Android/ProgramPath.cpp
Normal file
75
src/Android/ProgramPath.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
#include<hgl/type/BaseString.h>
|
||||
#include<unistd.h>
|
||||
#include<pwd.h>
|
||||
#include<unistd.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
namespace
|
||||
{
|
||||
char files_dir[HGL_MAX_PATH];
|
||||
}
|
||||
|
||||
void SetLocalAppdataPath(const char *fn)
|
||||
{
|
||||
strcpy(files_dir,HGL_MAX_PATH,fn);
|
||||
}
|
||||
|
||||
void GetLocalAppdataPath(char fn[HGL_MAX_PATH])
|
||||
{
|
||||
strcpy(fn,HGL_MAX_PATH,files_dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得当前程序完整路径名称
|
||||
*/
|
||||
bool GetCurrentProgram(OSString &result)
|
||||
{
|
||||
os_char *path=new os_char[HGL_MAX_PATH];
|
||||
|
||||
const int len=readlink("/proc/self/exe",path,HGL_MAX_PATH);
|
||||
|
||||
if(len<=0)
|
||||
{
|
||||
delete[] path;
|
||||
return(false);
|
||||
}
|
||||
|
||||
path[len]=0;
|
||||
result.Set(path,len,true);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得当前程序所在路径
|
||||
*/
|
||||
bool GetCurrentProgramPath(OSString &result)
|
||||
{
|
||||
os_char *path=new os_char[HGL_MAX_PATH];
|
||||
|
||||
const int len=readlink("/proc/self/exe",path,HGL_MAX_PATH);
|
||||
|
||||
if(len<=0)
|
||||
{
|
||||
delete[] path;
|
||||
return(false);
|
||||
}
|
||||
|
||||
os_char *right=hgl::strrchr(path,len,HGL_DIRECTORY_SEPARATOR);
|
||||
|
||||
if(right)
|
||||
*right=0;
|
||||
else
|
||||
path[len]=0;
|
||||
|
||||
result.Set(path,len,true);
|
||||
|
||||
return(true);
|
||||
}
|
||||
}//namespace filesystem
|
||||
}//namespace hgl
|
||||
|
||||
|
42
src/Apple/ProgramPath.mm
Normal file
42
src/Apple/ProgramPath.mm
Normal file
@ -0,0 +1,42 @@
|
||||
#include<hgl/type/BaseString.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
void GetLocalAppdataPath(char fn[HGL_MAX_PATH])
|
||||
{
|
||||
NSFileManager *dfm=[NSFileManager defaultManager];
|
||||
|
||||
const char *str=[[[dfm homeDirectoryForCurrentUser] path] cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
hgl::strcpy(fn,HGL_MAX_PATH,str,strlen(str));
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得当前程序完整路径名称
|
||||
*/
|
||||
bool GetCurrentProgram(UTF8String &result)
|
||||
{
|
||||
NSString *ns_string = [[[[NSBundle mainBundle] bundleURL] URLByDeletingPathExtension] path];
|
||||
|
||||
result.Set([ns_string cStringUsingEncoding:NSUTF8StringEncoding]);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得当前程序所在路径
|
||||
*/
|
||||
bool GetCurrentProgramPath(UTF8String &result)
|
||||
{
|
||||
NSString *ns_string = [[[[NSBundle mainBundle] bundleURL] URLByDeletingLastPathComponent] path];
|
||||
|
||||
result.Set([ns_string cStringUsingEncoding:NSUTF8StringEncoding]);
|
||||
|
||||
return(true);
|
||||
}
|
||||
}//namespace filesystem
|
||||
}//namespace hgl
|
||||
|
78
src/Apple/Semaphore.cpp
Normal file
78
src/Apple/Semaphore.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
#include<hgl/thread/Semaphore.h>
|
||||
#include<hgl/LogInfo.h>
|
||||
#include<pthread.h>
|
||||
#include<dispatch/dispatch.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
void GetWaitTime(struct timespec &,double);
|
||||
|
||||
/**
|
||||
* @param max_count 最大计数
|
||||
*/
|
||||
Semaphore::Semaphore(int max_count)
|
||||
{
|
||||
ptr=dispatch_semaphore_create(0);
|
||||
|
||||
if(!ptr)
|
||||
{
|
||||
LOG_ERROR(OS_TEXT("dispatch_semaphore_create error"));
|
||||
ptr=nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Semaphore::~Semaphore()
|
||||
{
|
||||
if(!ptr)return;
|
||||
|
||||
dispatch_release(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送信号
|
||||
* @param n 发送的信号数量
|
||||
* @return 是否释放成功
|
||||
*/
|
||||
bool Semaphore::Post(int n)
|
||||
{
|
||||
if(!ptr)return(false);
|
||||
if(n<=0)return(false);
|
||||
|
||||
for(int i=0;i<n;i++)
|
||||
dispatch_semaphore_signal(ptr);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试获取一个信号
|
||||
* @return 是否有取得信号
|
||||
*/
|
||||
bool Semaphore::TryAcquire()
|
||||
{
|
||||
if(!ptr)return(false);
|
||||
|
||||
return !dispatch_semaphore_wait(ptr, DISPATCH_TIME_NOW);
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待并获取一个信号
|
||||
* @param t 等待的最长时间,使用0表示无限等待.(单位秒)
|
||||
* @return 是否等待到了,如果超过最长时间,仍未等到即为超时,返回false
|
||||
*/
|
||||
bool Semaphore::Acquire(double t)
|
||||
{
|
||||
if(!ptr)return(false);
|
||||
|
||||
if(t<=0)
|
||||
{
|
||||
return !dispatch_semaphore_wait(ptr, DISPATCH_TIME_FOREVER);
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatch_time_t when=dispatch_time(DISPATCH_TIME_NOW,t*HGL_NANO_SEC_PER_SEC);
|
||||
|
||||
return !dispatch_semaphore_wait(ptr,when);
|
||||
}
|
||||
}
|
||||
}//namespace hgl
|
132
src/CMakeLists.txt
Normal file
132
src/CMakeLists.txt
Normal file
@ -0,0 +1,132 @@
|
||||
IF(UNIX)
|
||||
SET(PLATFORM_FILE_SOURCE UNIX/File.cpp
|
||||
UNIX/FileAccess.cpp
|
||||
UNIX/EnumFile.cpp)
|
||||
|
||||
SET(PLATFORM_SYSTEM_INFO_SOURCE UNIX/SystemInfo.cpp)
|
||||
|
||||
SET(PLATFORM_MULTI_THREAD_SOURCE UNIX/CondVar.cpp
|
||||
UNIX/RWLock.cpp
|
||||
UNIX/Thread.cpp
|
||||
UNIX/ThreadMutex.cpp)
|
||||
|
||||
IF(ANDROID)
|
||||
SET(PLATFORM_LOG_SOURCE Android/LogConsole.cpp)
|
||||
|
||||
SET(PLATFORM_APPLICATION_SOURCE ${PLATFORM_APPLICATION_SOURCE}
|
||||
Android/JNISupport.cpp
|
||||
Android/NativeActivitySupport.cpp)
|
||||
|
||||
SET(PLATFORM_FILE_SOURCE ${PLATFORM_FILE_SOURCE}
|
||||
Android/ProgramPath.cpp
|
||||
Android/AssetManage.cpp)
|
||||
|
||||
SET(PLATFORM_MULTI_THREAD_SOURCE ${PLATFORM_MULTI_THREAD_SOURCE}
|
||||
UNIX/Semaphore.cpp)
|
||||
|
||||
|
||||
SET(PLATFORM_WINDOW_SOURCE Android/AndroidVulkan.cpp)
|
||||
|
||||
ELSE()
|
||||
SET(PLATFORM_CODEPAGE_SOURCE UNIX/CodePage.cpp)
|
||||
SET(PLATFORM_LOG_SOURCE UNIX/LogConsole.cpp)
|
||||
|
||||
IF(APPLE)
|
||||
SET(PLATFORM_MULTI_THREAD_SOURCE ${PLATFORM_MULTI_THREAD_SOURCE}
|
||||
Apple/Semaphore.cpp)
|
||||
|
||||
SET(PLATFORM_FILE_SOURCE ${PLATFORM_FILE_SOURCE}
|
||||
Apple/ProgramPath.mm)
|
||||
ELSE()
|
||||
SET(PLATFORM_MULTI_THREAD_SOURCE ${PLATFORM_MULTI_THREAD_SOURCE}
|
||||
UNIX/Semaphore.cpp)
|
||||
|
||||
SET(PLATFORM_FILE_SOURCE ${PLATFORM_FILE_SOURCE}
|
||||
UNIX/ProgramPath.cpp)
|
||||
|
||||
SET(PLATFORM_WINDOW_SOURCE UNIX/XCBWindow.cpp
|
||||
UNIX/XCBVulkan.cpp)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
SET(PLATFORM_MULTI_PROCESS_SOURCE UNIX/ProcMutex.cpp
|
||||
UNIX/Process.cpp
|
||||
UNIX/Pipe.cpp
|
||||
UNIX/Fifo.cpp)
|
||||
|
||||
SET(PLATFORM_TIME_SOURCE UNIX/Time.cpp
|
||||
UNIX/Exit.cpp
|
||||
UNIX/DateTime.cpp)
|
||||
|
||||
SET(PLATFORM_EXTERNAL_MODULE_SOURCE UNIX/ExternalModule.cpp)
|
||||
|
||||
ENDIF()
|
||||
|
||||
IF(WIN32)
|
||||
SET(PLATFORM_FILE_SOURCE Win/File.cpp
|
||||
Win/FileAccess.cpp
|
||||
Win/EnumFile.cpp
|
||||
Win/EnumVolume.cpp
|
||||
Win/ProgramPath.cpp)
|
||||
|
||||
SET(PLATFORM_CODEPAGE_SOURCE Win/CodePage.cpp)
|
||||
|
||||
SET(PLATFORM_SYSTEM_INFO_SOURCE Win/SystemInfo.cpp)
|
||||
|
||||
SET(PLATFORM_LOG_SOURCE Win/LogConsole.cpp
|
||||
Win/LogDialog.cpp)
|
||||
|
||||
SET(PLATFORM_MULTI_THREAD_SOURCE
|
||||
Win/CondVar.cpp
|
||||
Win/RWLock.cpp
|
||||
Win/Semaphore.cpp
|
||||
Win/Thread.cpp
|
||||
Win/ThreadMutex.cpp)
|
||||
|
||||
SET(PLATFORM_MULTI_PROCESS_SOURCE Win/ProcMutex.cpp
|
||||
Win/Pipe.cpp
|
||||
Win/Fifo.cpp)
|
||||
|
||||
SET(PLATFORM_TIME_SOURCE Win/Time.cpp
|
||||
Win/DateTime.cpp)
|
||||
|
||||
SET(PLATFORM_EXTERNAL_MODULE_SOURCE Win/ExternalModule.cpp)
|
||||
|
||||
SET(PLATFORM_DESKTOP_SOURCE Win/Desktop.cpp)
|
||||
|
||||
SET(PLATFORM_WINDOW_SOURCE Win/WinWindow.h
|
||||
Win/WinWindow.cpp
|
||||
Win/WinMessage.cpp
|
||||
Win/WinVulkan.cpp)
|
||||
ENDIF(WIN32)
|
||||
|
||||
SET(PLATFORM_WINDOW_SOURCE ${PLATFORM_WINDOW_SOURCE} Window.cpp)
|
||||
|
||||
SOURCE_GROUP("InputDevice" FILES ${PLATFORM_INPUT_DEVICE_SOURCE})
|
||||
SOURCE_GROUP("CodePage" FILES ${PLATFORM_CODEPAGE_SOURCE})
|
||||
SOURCE_GROUP("File" FILES ${PLATFORM_FILE_SOURCE})
|
||||
SOURCE_GROUP("SystemInfo" FILES ${PLATFORM_SYSTEM_INFO_SOURCE})
|
||||
SOURCE_GROUP("Application" FILES ${PLATFORM_APPLICATION_SOURCE})
|
||||
SOURCE_GROUP("LogInfo" FILES ${PLATFORM_LOG_SOURCE})
|
||||
SOURCE_GROUP("MultiThread" FILES ${PLATFORM_MULTI_THREAD_SOURCE})
|
||||
SOURCE_GROUP("MultiProcess" FILES ${PLATFORM_MULTI_PROCESS_SOURCE})
|
||||
SOURCE_GROUP("Time" FILES ${PLATFORM_TIME_SOURCE})
|
||||
SOURCE_GROUP("Desktop" FILES ${PLATFORM_DESKTOP_SOURCE})
|
||||
SOURCE_GROUP("Window" FILES ${PLATFORM_WINDOW_SOURCE})
|
||||
|
||||
SET(PLATFORM_SOURCE ${PLATFORM_SOURCE}
|
||||
${PLATFORM_FILE_SOURCE}
|
||||
${PLATFORM_CODEPAGE_SOURCE}
|
||||
#${PLATFORM_SYSTEM_INFO_SOURCE}
|
||||
${PLATFORM_APPLICATION_SOURCE}
|
||||
${PLATFORM_LOG_SOURCE}
|
||||
${PLATFORM_MULTI_THREAD_SOURCE}
|
||||
${PLATFORM_MULTI_PROCESS_SOURCE}
|
||||
${PLATFORM_TIME_SOURCE}
|
||||
${PLATFORM_EXTERNAL_MODULE_SOURCE}
|
||||
${PLATFORM_INPUT_DEVICE_SOURCE}
|
||||
${PLATFORM_WINDOW_SOURCE}
|
||||
)
|
||||
|
||||
add_library(CMPlatform STATIC ${PLATFORM_SOURCE})
|
||||
set_property(TARGET CMPlatform PROPERTY FOLDER "CM")
|
125
src/UNIX/CodePage.cpp
Normal file
125
src/UNIX/CodePage.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
#include<hgl/CodePage.h>
|
||||
|
||||
/**
|
||||
* linux iconv 函数细节说明
|
||||
* by hyz in Friday,March 30,2012
|
||||
*
|
||||
* iconv(icont_t *cd,
|
||||
* char **inbuf,size_t *inbytesleft,
|
||||
* char **outbuf,size_t *outbytesleft);
|
||||
*
|
||||
* ps: 1.转换结果并不在outbuf中,而是在最早传入的指针中,所以inbuf,outbuf一定要备份一份出来用
|
||||
* 2.inbytesleft中得到的是剩下还没有转完的总字节数
|
||||
* 3.outbytesleft中得到的是剩下还没有用完的输出区总字节数
|
||||
*/
|
||||
|
||||
#include<iconv.h>
|
||||
#include<errno.h>
|
||||
namespace hgl
|
||||
{
|
||||
template<typename T,typename S>
|
||||
int CharSetConv(T **out_buf,const CharSetName &out_charset,
|
||||
const S *in_str,int in_str_size,const CharSetName &in_charset)
|
||||
{
|
||||
if(!out_buf||!out_charset||!*out_charset
|
||||
||!in_str||!*in_str||in_str_size==0||!in_charset||!*in_charset)
|
||||
return(-1);
|
||||
|
||||
iconv_t cd=iconv_open(out_charset,in_charset);
|
||||
|
||||
if(cd==(iconv_t)-1)
|
||||
return(-1);
|
||||
|
||||
if(in_str_size<0)
|
||||
in_str_size=strlen(in_str);
|
||||
|
||||
size_t result;
|
||||
|
||||
char *in;
|
||||
char *out;
|
||||
T *out_str;
|
||||
T *out_new;
|
||||
|
||||
size_t in_left;
|
||||
size_t out_left;
|
||||
|
||||
int out_malloc_size=in_str_size;
|
||||
int last_left=-1;
|
||||
|
||||
out_str=new T[out_malloc_size+1];
|
||||
|
||||
in=(char *)in_str;
|
||||
out=(char *)out_str;
|
||||
in_left=in_str_size;
|
||||
out_left=out_malloc_size*sizeof(T);
|
||||
|
||||
while(true)
|
||||
{
|
||||
size_t res=iconv(cd,&in,&in_left,&out,&out_left);
|
||||
|
||||
if(res==(size_t)(-1))
|
||||
{
|
||||
if(errno==E2BIG)
|
||||
{
|
||||
out_new=new T[out_malloc_size*2];
|
||||
|
||||
if(!out_new)
|
||||
return(false);
|
||||
|
||||
result=out-(char *)out_str;
|
||||
|
||||
memcpy(out_new,out_str,result);
|
||||
|
||||
out_malloc_size*=2;
|
||||
|
||||
delete[] out_str;
|
||||
out_str=out_new;
|
||||
|
||||
out=(char *)out_str;
|
||||
out+=result;
|
||||
|
||||
//in_left已经被减了,所以不用处理
|
||||
out_left=(out_malloc_size*sizeof(T))-result;
|
||||
continue;
|
||||
}
|
||||
else if(errno==EILSEQ) //有非法字符,跳过
|
||||
{
|
||||
in++;
|
||||
in_left--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//result=(out_malloc_size-(out_left/sizeof(T));
|
||||
result=((T *)out)-out_str; // 同上一行
|
||||
|
||||
out_str[result]=0;
|
||||
iconv_close(cd);
|
||||
|
||||
*out_buf=out_str;
|
||||
return(result);
|
||||
}
|
||||
|
||||
int to_utf16(const CharSet &cs,u16char **dst,const char *src,const int src_size)
|
||||
{
|
||||
return CharSetConv<u16char,char>(dst,endian::GetCharSet<u16char>(),src,src_size,cs.charset);
|
||||
}
|
||||
|
||||
int utf16_to(const CharSet &cs,char **dst,const u16char *src,const int src_size)
|
||||
{
|
||||
return CharSetConv<char,u16char>(dst,cs.charset,src,src_size,endian::GetCharSet<u16char>());
|
||||
}
|
||||
|
||||
int to_utf8(const CharSet &cs,char **dst,const char *src,const int src_size)
|
||||
{
|
||||
return CharSetConv<char,char>(dst,utf8_charset,src,src_size,cs.charset);
|
||||
}
|
||||
|
||||
int utf8_to(const CharSet &cs,char **dst,const char *src,const int src_size)
|
||||
{
|
||||
return CharSetConv<char,char>(dst,cs.charset,src,src_size,utf8_charset);
|
||||
}
|
||||
}//namespace hgl
|
47
src/UNIX/CondVar.cpp
Normal file
47
src/UNIX/CondVar.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
#include<hgl/thread/CondVar.h>
|
||||
#include<hgl/thread/ThreadMutex.h>
|
||||
#include<pthread.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
void GetWaitTime(struct timespec &,double);
|
||||
|
||||
CondVar::CondVar()
|
||||
{
|
||||
cond_var=new pthread_cond_t;
|
||||
|
||||
pthread_cond_init((pthread_cond_t *)cond_var,nullptr);
|
||||
}
|
||||
|
||||
CondVar::~CondVar()
|
||||
{
|
||||
pthread_cond_destroy((pthread_cond_t *)cond_var);
|
||||
delete (pthread_cond_t *)cond_var;
|
||||
}
|
||||
|
||||
bool CondVar::Wait(ThreadMutex *tm,double t)
|
||||
{
|
||||
if(t>0)
|
||||
{
|
||||
struct timespec abstime;
|
||||
|
||||
GetWaitTime(abstime,t);
|
||||
|
||||
return(!pthread_cond_timedwait((pthread_cond_t *)cond_var,tm->GetThreadMutex(),&abstime));
|
||||
}
|
||||
else
|
||||
{
|
||||
return(!pthread_cond_wait((pthread_cond_t *)cond_var,tm->GetThreadMutex()));
|
||||
}
|
||||
}
|
||||
|
||||
void CondVar::Signal()
|
||||
{
|
||||
pthread_cond_signal((pthread_cond_t *)cond_var);
|
||||
}
|
||||
|
||||
void CondVar::Broadcast()
|
||||
{
|
||||
pthread_cond_broadcast((pthread_cond_t *)cond_var);
|
||||
}
|
||||
}//namespace hgl
|
125
src/UNIX/DateTime.cpp
Normal file
125
src/UNIX/DateTime.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
#include<hgl/type/DataType.h>
|
||||
#include<hgl/type/DateTime.h>
|
||||
|
||||
#include<hgl/io/DataInputStream.h>
|
||||
#include<hgl/io/DataOutputStream.h>
|
||||
|
||||
#include<hgl/thread/RWLock.h>
|
||||
|
||||
#include<time.h>
|
||||
#include<sys/time.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
//和系统时间同步
|
||||
void Time::Sync(const double cur_time)
|
||||
{
|
||||
tm m;
|
||||
time_t tt;
|
||||
|
||||
if(cur_time<=0)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
|
||||
tt=tv.tv_sec;
|
||||
micro_seconds=tv.tv_usec;
|
||||
}
|
||||
else
|
||||
{
|
||||
tt=cur_time;
|
||||
micro_seconds=(cur_time-tt)*HGL_MICRO_SEC_PER_SEC;
|
||||
}
|
||||
|
||||
localtime_r(&tt,&m);
|
||||
|
||||
hours =m.tm_hour;
|
||||
minutes =m.tm_min;
|
||||
seconds =m.tm_sec;
|
||||
week_day =m.tm_wday;
|
||||
|
||||
gmt_off =m.tm_gmtoff;
|
||||
}
|
||||
}//namespace hgl
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
namespace hgl
|
||||
{
|
||||
void Date::Sync(const double cur_time)
|
||||
{
|
||||
tm m;
|
||||
time_t tt;
|
||||
|
||||
if(cur_time<=0)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
|
||||
tt=tv.tv_sec;
|
||||
}
|
||||
else
|
||||
{
|
||||
tt=cur_time;
|
||||
}
|
||||
|
||||
localtime_r(&tt,&m);
|
||||
|
||||
year =m.tm_year+1900;
|
||||
SetMonth(m.tm_mon+1);
|
||||
SetDay (m.tm_mday);
|
||||
week_day=m.tm_wday;
|
||||
year_day=m.tm_yday;
|
||||
}
|
||||
}//namespace hgl
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
void ToDateTime(Date &d,Time &t,const double cur_time)
|
||||
{
|
||||
tm m;
|
||||
time_t tt;
|
||||
uint micro_sec;
|
||||
|
||||
if(cur_time<=0)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
|
||||
tt=tv.tv_sec;
|
||||
micro_sec=tv.tv_usec;
|
||||
}
|
||||
else
|
||||
{
|
||||
tt=cur_time;
|
||||
micro_sec=(cur_time-tt)*HGL_MICRO_SEC_PER_SEC;
|
||||
}
|
||||
|
||||
localtime_r(&tt,&m);
|
||||
|
||||
d.Set(m.tm_year+1900,m.tm_mon+1,m.tm_mday,m.tm_wday,m.tm_yday);
|
||||
t.Set(m.tm_hour,m.tm_min,m.tm_sec,micro_sec,m.tm_wday);
|
||||
t.SetGMT(m.tm_gmtoff);
|
||||
}
|
||||
|
||||
double FromDateTime(const int year,const int month,const int day,
|
||||
const int hour,const int minute,const int second,const int micro_second,
|
||||
const int gmt_off)
|
||||
{
|
||||
tm at;
|
||||
|
||||
hgl_zero(at);
|
||||
|
||||
at.tm_year =year-1900;
|
||||
at.tm_mon =month-1;
|
||||
at.tm_mday =day;
|
||||
|
||||
at.tm_hour =hour;
|
||||
at.tm_min =minute;
|
||||
at.tm_sec =second;
|
||||
|
||||
at.tm_gmtoff=gmt_off;
|
||||
|
||||
double result=mktime(&at);
|
||||
|
||||
return(result + (double(micro_second) / HGL_MICRO_SEC_PER_SEC));
|
||||
}
|
||||
}//namespace hgl
|
141
src/UNIX/EnumFile.cpp
Normal file
141
src/UNIX/EnumFile.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
#include<hgl/filesystem/EnumFile.h>
|
||||
#include<hgl/LogInfo.h>
|
||||
#include<unistd.h>
|
||||
#include<stdlib.h>
|
||||
#include<stdio.h>
|
||||
#include<dirent.h>
|
||||
#include<sys/types.h>
|
||||
#include<sys/stat.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
/**
|
||||
* 枚举一个目录内的所有文件
|
||||
* @param config 枚举配置
|
||||
* @return 查找到文件数据,<0表示失败
|
||||
*/
|
||||
int EnumFile::Enum(EnumFileConfig *config)
|
||||
{
|
||||
if(!config)RETURN_ERROR(-1);
|
||||
|
||||
if(config->folder_name.IsEmpty())RETURN_ERROR(-4);
|
||||
|
||||
OSString fullname;
|
||||
int count=0;
|
||||
|
||||
if(config->folder_name.IsEmpty())
|
||||
{
|
||||
fullname='.';
|
||||
}
|
||||
else
|
||||
{
|
||||
fullname=config->folder_name;
|
||||
}
|
||||
|
||||
DIR *dir;
|
||||
struct_dirent64 *entry;
|
||||
struct_stat64 statbuf;
|
||||
FileInfo fi;
|
||||
char path_buf[HGL_MAX_PATH]={0};
|
||||
getcwd(path_buf,HGL_MAX_PATH);
|
||||
|
||||
chdir(fullname);
|
||||
if((dir = opendir(fullname)) == NULL)
|
||||
return(-1);
|
||||
if((entry = hgl_readdir64(dir)) == NULL)
|
||||
return(-1);
|
||||
|
||||
int sub_count;
|
||||
|
||||
do
|
||||
{
|
||||
if(strcmp(entry->d_name,".")==0
|
||||
||strcmp(entry->d_name,"..")==0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(&statbuf,0,sizeof(struct_stat64));
|
||||
|
||||
if(hgl_lstat64(entry->d_name,&statbuf)==-1)
|
||||
continue;
|
||||
|
||||
if(S_ISDIR(statbuf.st_mode))
|
||||
{
|
||||
if(!config->proc_folder)continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!config->proc_file)continue;
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
memset(&fi,0,sizeof(FileInfo));
|
||||
fi.size=statbuf.st_size;
|
||||
|
||||
fi.can_read =statbuf.st_mode&S_IROTH;
|
||||
fi.can_write=statbuf.st_mode&S_IWOTH;
|
||||
|
||||
fi.is_hiddle=(entry->d_name[0]=='.');
|
||||
|
||||
fi.mtime=statbuf.st_mtime;
|
||||
|
||||
if(S_ISDIR(statbuf.st_mode))
|
||||
{
|
||||
fi.is_file=false;
|
||||
fi.is_directory=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
fi.is_file=true;
|
||||
fi.is_directory=false;
|
||||
}
|
||||
|
||||
strcpy(fi.name,HGL_MAX_PATH,entry->d_name);
|
||||
|
||||
if(config->folder_name.IsEmpty())
|
||||
{
|
||||
strcpy(fi.fullname,HGL_MAX_PATH,fi.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(fi.fullname,HGL_MAX_PATH,config->folder_name);
|
||||
|
||||
if(config->folder_name.GetEndChar()!=HGL_DIRECTORY_SEPARATOR)
|
||||
strcat(fi.fullname,HGL_MAX_PATH,HGL_DIRECTORY_SEPARATOR);
|
||||
|
||||
strcat(fi.fullname,HGL_MAX_PATH,fi.name,HGL_MAX_PATH);
|
||||
}
|
||||
|
||||
if(fi.is_directory)
|
||||
{
|
||||
EnumFileConfig *sub_efc=CreateSubConfig(config,fi);
|
||||
|
||||
if(sub_efc&&config->sub_folder)
|
||||
{
|
||||
sub_count=this->Enum(sub_efc);
|
||||
if(sub_count>0)count+=sub_count;
|
||||
}
|
||||
|
||||
ProcFolder(config,sub_efc,fi);
|
||||
|
||||
if(sub_efc)
|
||||
delete sub_efc;
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcFile(config,fi);
|
||||
}
|
||||
}
|
||||
while((entry=hgl_readdir64(dir)));
|
||||
|
||||
closedir(dir);
|
||||
|
||||
chdir(path_buf);
|
||||
return(count);
|
||||
}
|
||||
}//namespace filesystem
|
||||
}//namespace hgl
|
24
src/UNIX/Exit.cpp
Normal file
24
src/UNIX/Exit.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include<hgl/platform/Exit.h>
|
||||
#include<signal.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
static SignalAppExitFunc app_exit_func=nullptr;
|
||||
|
||||
void exit_signal_proc(int n,siginfo_t *si,void *)
|
||||
{
|
||||
}
|
||||
|
||||
void SetSignalAppExit(SignalAppExitFunc func)
|
||||
{
|
||||
if(!func)return;
|
||||
|
||||
app_exit_func=func;
|
||||
|
||||
struct sigaction act;
|
||||
sigemptyset(&act.sa_mask); /** 清空阻塞信号 **/
|
||||
|
||||
act.sa_flags=SA_SIGINFO; /** 设置SA_SIGINFO 表示传递附加信息到触发函数 **/
|
||||
act.sa_sigaction=exit_signal_proc;
|
||||
}
|
||||
}//namespace hgl
|
43
src/UNIX/ExternalModule.cpp
Normal file
43
src/UNIX/ExternalModule.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include<hgl/platform/ExternalModule.h>
|
||||
#include<hgl/platform/Platform.h>
|
||||
#include<hgl/LogInfo.h>
|
||||
|
||||
#include<dlfcn.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
ExternalModule *LoadExternalModule(const os_char *filename)
|
||||
{
|
||||
ExternalModulePointer fp=dlopen(filename,RTLD_LAZY);
|
||||
|
||||
if(!fp)
|
||||
{
|
||||
LOG_ERROR(OS_TEXT("Load Module <")+OSString(filename)+OS_TEXT("> error! os info: ")+OSString(dlerror()));
|
||||
|
||||
return(nullptr);
|
||||
}
|
||||
|
||||
return(new ExternalModule(fp));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载一个外部模块
|
||||
* @param name 模块文件名称
|
||||
* @return 是否加载成功
|
||||
*/
|
||||
bool ExternalModule::Load(const os_char *name)
|
||||
{
|
||||
Clear();
|
||||
|
||||
fp=dlopen(name,RTLD_LAZY);
|
||||
|
||||
if(!fp)
|
||||
{
|
||||
LOG_ERROR(OS_TEXT("Load Module <")+OSString(name)+OS_TEXT("> error! os info: ")+OSString(dlerror()));
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
}//namespace hgl
|
24
src/UNIX/Fifo.cpp
Normal file
24
src/UNIX/Fifo.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include<hgl/proc/Fifo.h>
|
||||
#include<hgl/Str.h>
|
||||
#include<sys/stat.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
/**
|
||||
* 创建一个管道通信文件
|
||||
* @param fn 简略文件名(请不要带路径)
|
||||
* @return 是否创建成功
|
||||
*/
|
||||
bool Fifo::Create(const char *fn)
|
||||
{
|
||||
if(!fn||!(*fn))
|
||||
return(false);
|
||||
|
||||
hgl::strcpy(filename,HGL_MAX_PATH-5,"/tmp/");
|
||||
hgl::strcpy(filename+5,HGL_MAX_PATH-5,fn);
|
||||
|
||||
fd=mkfifo(filename,0777);
|
||||
|
||||
return(!fd);
|
||||
}
|
||||
}//namespace hgl
|
220
src/UNIX/File.cpp
Normal file
220
src/UNIX/File.cpp
Normal file
@ -0,0 +1,220 @@
|
||||
#include<hgl/filesystem/FileSystem.h>
|
||||
#include<hgl/LogInfo.h>
|
||||
#include<hgl/io/FileInputStream.h>
|
||||
#include<hgl/io/FileOutputStream.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
constexpr int FILE_PROC_BUF_SIZE=HGL_SIZE_1MB;
|
||||
|
||||
/**
|
||||
* 复制一个文件
|
||||
* @param sourcename 源文件名
|
||||
* @param targetname 目标文件名
|
||||
* @return 文件是否复制成功
|
||||
*/
|
||||
bool FileCopy(const OSString &targetname,const OSString &sourcename)
|
||||
{
|
||||
io::FileInputStream fis;
|
||||
io::FileOutputStream fos;
|
||||
|
||||
if(!fis.Open(sourcename))return(false);
|
||||
if(!fos.Create(targetname))return(false);
|
||||
|
||||
size_t buf_size=FILE_PROC_BUF_SIZE;
|
||||
size_t length=fis.GetSize();
|
||||
|
||||
size_t cur;
|
||||
|
||||
if(buf_size>length)
|
||||
buf_size=length;
|
||||
|
||||
SharedPtr<char> buf=new char[buf_size];
|
||||
|
||||
while(length)
|
||||
{
|
||||
if(length>buf_size)
|
||||
cur=buf_size;
|
||||
else
|
||||
cur=length;
|
||||
|
||||
if(fis.Read(buf,cur))
|
||||
if(fos.Write(buf,cur))
|
||||
{
|
||||
length-=cur;
|
||||
continue;
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个文件
|
||||
* @param filename 文件名
|
||||
* @return 文件是否成功删除
|
||||
*/
|
||||
bool FileDelete(const OSString &filename)
|
||||
{
|
||||
return(unlink(filename.c_str())==0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动一个文件
|
||||
* @param sourcename 源文件名
|
||||
* @param targetname 目标文件名
|
||||
* @return 文件是否移动成功
|
||||
*/
|
||||
bool FileMove(const OSString &targetname,const OSString &sourcename)
|
||||
{
|
||||
if(FileCopy(sourcename,targetname))
|
||||
return FileDelete(sourcename);
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改文件名
|
||||
* @param oldname 旧的文件名
|
||||
* @param newname 新的文件名
|
||||
* @return 文件名是否修改成功
|
||||
*/
|
||||
bool FileRename(const OSString &newname,const OSString &oldname)
|
||||
{
|
||||
return(rename(oldname.c_str(),
|
||||
newname.c_str())==0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认文件是否存在
|
||||
* @param filename 要查找的文件名称
|
||||
* @return 这个文件是否存在
|
||||
*/
|
||||
bool FileExist(const OSString &filename)
|
||||
{
|
||||
return access(filename.c_str(),F_OK)>=0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测文件是否可读
|
||||
* @param filename 文件名
|
||||
*/
|
||||
bool FileCanRead(const OSString &filename)
|
||||
{
|
||||
return access(filename.c_str(),R_OK)>=0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测文件是否可写
|
||||
* @param filename 文件名
|
||||
*/
|
||||
bool FileCanWrite(const OSString &filename)
|
||||
{
|
||||
return access(filename.c_str(),W_OK)>=0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测文件是否可执行
|
||||
* @param filename 文件名
|
||||
*/
|
||||
bool FileCanExec(const OSString &filename)
|
||||
{
|
||||
return access(filename.c_str(),X_OK)>=0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前名称是否是一个目录
|
||||
* @param name 名称
|
||||
*/
|
||||
bool IsDirectory(const os_char *name)
|
||||
{
|
||||
struct_stat64 buf;
|
||||
|
||||
memset(&buf,0,sizeof(struct_stat64));
|
||||
|
||||
if(hgl_lstat64(name,&buf)==-1)
|
||||
return(false); //错误,有可能是不能访问
|
||||
|
||||
return S_ISDIR(buf.st_mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前名称是否是一个链接
|
||||
*/
|
||||
bool IsLink(const os_char *name)
|
||||
{
|
||||
struct_stat64 buf;
|
||||
|
||||
memset(&buf,0,sizeof(struct_stat64));
|
||||
|
||||
if(hgl_lstat64(name,&buf)==-1)
|
||||
return(false); //错误,有可能是不能访问
|
||||
|
||||
return S_ISLNK(buf.st_mode);
|
||||
}
|
||||
|
||||
bool MakeDirectory(const os_char *name)
|
||||
{
|
||||
if(!mkdir(name,S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH))return(true);
|
||||
|
||||
LOG_PROBLEM(OS_TEXT("Create Directory <")+OSString(name)+OS_TEXT("> failed,errno: ")+OSString(errno));
|
||||
return(false);
|
||||
}
|
||||
|
||||
os_char *GetRootPath(os_char *str)
|
||||
{
|
||||
if(str[0]==HGL_DIRECTORY_SEPARATOR)
|
||||
return str+1;
|
||||
else
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个子目录
|
||||
* @param name 目录名称
|
||||
* @return 目录是否删除成功
|
||||
*/
|
||||
bool DeletePath(const OSString &name)
|
||||
{
|
||||
return rmdir(name.c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得当前所在目录<br>
|
||||
*/
|
||||
bool GetCurrentPath(OSString &path)
|
||||
{
|
||||
const int len=pathconf(".",_PC_PATH_MAX);
|
||||
|
||||
if(len<=0)return(false);
|
||||
|
||||
char *str=new char[len];
|
||||
|
||||
memset(str,0,len);
|
||||
|
||||
if(!getcwd(str,len))
|
||||
{
|
||||
delete[] str;
|
||||
return(false);
|
||||
}
|
||||
|
||||
path.Set(str,strlen(str),true);
|
||||
return(true);
|
||||
}
|
||||
}//namespace filesystem
|
||||
}//namespace hgl
|
||||
|
||||
|
69
src/UNIX/FileAccess.cpp
Normal file
69
src/UNIX/FileAccess.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
#include<hgl/io/FileAccess.h>
|
||||
#include<hgl/LogInfo.h>
|
||||
#include<unistd.h>
|
||||
#include<stdlib.h>
|
||||
#include<fcntl.h>
|
||||
#include<errno.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
bool FileAccess::CreateTemp()
|
||||
{
|
||||
char template_filename[HGL_MAX_PATH]="/tmp/cm/XXXXXX";
|
||||
|
||||
fp=mkstemps(template_filename,HGL_MAX_PATH);
|
||||
|
||||
if(fp==-1)
|
||||
return(false);
|
||||
|
||||
filename=template_filename;
|
||||
mode=fomCreate;
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
int OpenFile(const os_char *fn,FileOpenMode fom)
|
||||
{
|
||||
int fp;
|
||||
|
||||
if(fom==fomCreate )fp=hgl_open64(fn,O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);else
|
||||
if(fom==fomCreateTrunc )fp=hgl_open64(fn,O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);else
|
||||
if(fom==fomOnlyRead )fp=hgl_open64(fn,O_RDONLY );else
|
||||
if(fom==fomOnlyWrite )fp=hgl_open64(fn,O_WRONLY );else
|
||||
if(fom==fomReadWrite )fp=hgl_open64(fn,O_RDWR );else
|
||||
if(fom==fomAppend )fp=hgl_open64(fn,O_APPEND );else
|
||||
{
|
||||
LOG_ERROR(OS_TEXT("UNIX,FileAccess,OpenFile(")+OSString(fn)+OS_TEXT(" mode error: "+OSString(fom)));
|
||||
RETURN_ERROR(-1);
|
||||
}
|
||||
|
||||
if(fp==-1)
|
||||
{
|
||||
LOG_ERROR(OS_TEXT("UNIX,FileAccess,OpenFile(")+OSString(fn)+OS_TEXT(") open return error: "+OSString(errno)));
|
||||
}
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
void CloseFile(int fp)
|
||||
{
|
||||
close(fp);
|
||||
}
|
||||
|
||||
int64 FileAccess::Read(int64 offset,void *buf,int64 size)
|
||||
{
|
||||
if(!CanRead())return(-1);
|
||||
|
||||
return hgl_pread64(fp,buf,size,offset);
|
||||
}
|
||||
|
||||
int64 FileAccess::Write(int64 offset,const void *buf,int64 size)
|
||||
{
|
||||
if(!CanWrite())return(-1);
|
||||
|
||||
return hgl_pwrite64(fp,buf,size,offset);
|
||||
}
|
||||
}//namespace io
|
||||
}//namespace hgl
|
126
src/UNIX/LogConsole.cpp
Normal file
126
src/UNIX/LogConsole.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
#include<hgl/Logger.h>
|
||||
#include<hgl/CodePage.h>
|
||||
#include<hgl/thread/ThreadMutex.h>
|
||||
#include<unistd.h>
|
||||
#include<pthread.h>
|
||||
|
||||
#ifdef LOG_INFO_TIME
|
||||
#include<hgl/Time.h>
|
||||
#endif//LOG_INFO_TIME
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace logger
|
||||
{
|
||||
constexpr uint LOG_BUF_SIZE=4096;
|
||||
|
||||
/**
|
||||
* unix控制台日志插件接口
|
||||
*/
|
||||
class LogUnixConsole:public Logger
|
||||
{
|
||||
char endline;
|
||||
char log_buf[LOG_BUF_SIZE];
|
||||
|
||||
#ifdef LOGINFO_THREAD_MUTEX
|
||||
ThreadMutex mutex;
|
||||
#endif//LOGINFO_THREAD_MUTEX
|
||||
|
||||
public:
|
||||
|
||||
LogUnixConsole(LogLevel ll):Logger(ll)
|
||||
{
|
||||
endline='\n';
|
||||
}
|
||||
|
||||
bool Create(const OSString &)
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
|
||||
void Close(){}
|
||||
|
||||
#ifdef LOG_INFO_THREAD
|
||||
void WriteThreadID()
|
||||
{
|
||||
memcpy(log_buf,"[Thread:",8);
|
||||
|
||||
htos(log_buf+8,128-9,pthread_self());
|
||||
strcat(log_buf,LOG_BUF_SIZE,']');
|
||||
|
||||
write(STDOUT_FILENO,log_buf,strlen(log_buf));
|
||||
}
|
||||
#endif//LOG_INFO_THREAD
|
||||
|
||||
#ifdef LOG_INFO_TIME
|
||||
void WriteTime()
|
||||
{
|
||||
memcpy(log_buf,"[Time:",6);
|
||||
|
||||
ftos(log_buf+6,128-strlen(log_buf),GetDoubleTime());
|
||||
strcat(log_buf,LOG_BUF_SIZE,']');
|
||||
|
||||
write(STDOUT_FILENO,log_buf,strlen(log_buf));
|
||||
}
|
||||
#endif//LOG_INFO_TIME
|
||||
|
||||
void Write(const u16char *str,int size)
|
||||
{
|
||||
#ifdef LOGINFO_THREAD_MUTEX
|
||||
mutex.Lock();
|
||||
#endif//LOGINFO_THREAD_MUTEX
|
||||
|
||||
#ifdef LOG_INFO_THREAD
|
||||
WriteThreadID();
|
||||
#endif//LOG_INFO_THREAD
|
||||
|
||||
#ifdef LOG_INFO_TIME
|
||||
WriteTime();
|
||||
#endif//LOG_INFO_TIME
|
||||
|
||||
int len;
|
||||
|
||||
len=u16_to_u8(log_buf,LOG_BUF_SIZE,str,size);
|
||||
|
||||
if(len>0)
|
||||
{
|
||||
log_buf[len++]='\n';
|
||||
|
||||
write(STDOUT_FILENO,log_buf,len);
|
||||
}
|
||||
#ifdef LOGINFO_THREAD_MUTEX
|
||||
mutex.Unlock();
|
||||
#endif//LOGINFO_THREAD_MUTEX
|
||||
}
|
||||
|
||||
void Write(const char *str,int size)
|
||||
{
|
||||
#ifdef LOGINFO_THREAD_MUTEX
|
||||
mutex.Lock();
|
||||
#endif//LOGINFO_THREAD_MUTEX
|
||||
|
||||
#ifdef LOG_INFO_THREAD
|
||||
WriteThreadID();
|
||||
#endif//LOG_INFO_THREAD
|
||||
|
||||
#ifdef LOG_INFO_TIME
|
||||
WriteTime();
|
||||
#endif//LOG_INFO_TIME
|
||||
|
||||
write(STDOUT_FILENO,str,size);
|
||||
write(STDOUT_FILENO,&endline,1);
|
||||
#ifdef LOGINFO_THREAD_MUTEX
|
||||
mutex.Unlock();
|
||||
#endif//LOGINFO_THREAD_MUTEX
|
||||
}
|
||||
};//class LogInterface
|
||||
|
||||
Logger *CreateLoggerConsole(const OSString &,LogLevel ll)
|
||||
{
|
||||
if(ll<llError)
|
||||
return(nullptr);
|
||||
|
||||
return(new LogUnixConsole(ll));
|
||||
}
|
||||
}//logger
|
||||
}//namespace hgl
|
13
src/UNIX/Pipe.cpp
Normal file
13
src/UNIX/Pipe.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include<hgl/proc/Pipe.h>
|
||||
#include<unistd.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
bool CreatePipe(pipe_pair &pp)
|
||||
{
|
||||
if(pipe(pp)) // return 0 表示成功
|
||||
return(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
}//namespace hgl
|
62
src/UNIX/ProcMutex.cpp
Normal file
62
src/UNIX/ProcMutex.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
#include<hgl/proc/ProcMutex.h>
|
||||
#include<sys/fcntl.h>
|
||||
#include<sys/stat.h>
|
||||
#include<errno.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
ProcMutex::ProcMutex()
|
||||
{
|
||||
lock = nullptr;
|
||||
}
|
||||
|
||||
bool ProcMutex::Create(const os_char *name)
|
||||
{
|
||||
if (lock != nullptr)return(false);
|
||||
|
||||
lock = sem_open(name, O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO, 1);
|
||||
|
||||
if(lock!=SEM_FAILED)
|
||||
return(true);
|
||||
|
||||
lock = nullptr;
|
||||
return(false);
|
||||
}
|
||||
|
||||
void ProcMutex::Clear()
|
||||
{
|
||||
if (lock == nullptr)return;
|
||||
|
||||
sem_close(lock);
|
||||
|
||||
lock = nullptr;
|
||||
}
|
||||
|
||||
bool ProcMutex::Lock()
|
||||
{
|
||||
if (lock == nullptr)return(false);
|
||||
|
||||
int err;
|
||||
do
|
||||
{
|
||||
err = sem_wait(lock);
|
||||
}
|
||||
while (err && errno == EINTR);
|
||||
|
||||
return !err;
|
||||
}
|
||||
|
||||
bool ProcMutex::TryLock()
|
||||
{
|
||||
if (lock == nullptr)return(false);
|
||||
|
||||
return(sem_trywait(lock)==0);
|
||||
}
|
||||
|
||||
bool ProcMutex::Unlock()
|
||||
{
|
||||
if (lock == nullptr)return(false);
|
||||
|
||||
return(sem_post(lock)==0);
|
||||
}
|
||||
}//namespace hgl
|
85
src/UNIX/Process.cpp
Normal file
85
src/UNIX/Process.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
#include<hgl/proc/Proc.h>
|
||||
#include<hgl/filesystem/FileSystem.h>
|
||||
#include<unistd.h>
|
||||
#include<sys/wait.h>
|
||||
#include<errno.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
using namespace filesystem;
|
||||
|
||||
bool Process::SetWorkPath(const OSString &wp)
|
||||
{
|
||||
if(!IsDirectory(wp))
|
||||
return(false);
|
||||
|
||||
work_path=wp;
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool Process::SetExecFile(const OSString &ef)
|
||||
{
|
||||
if(!FileCanExec(ef))
|
||||
return(false);
|
||||
|
||||
filename=ef;
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool Process::Execute()
|
||||
{
|
||||
pid=fork();
|
||||
|
||||
if(pid<0)
|
||||
_exit(72); //为啥是72,我也不清楚,反正是要退出,多少无所谓。抄的poco
|
||||
|
||||
if(pid==0)
|
||||
{ //fork会复制出一个子进程并从这里开始执行
|
||||
if(chdir(work_path.c_str())!=0)
|
||||
_exit(72);
|
||||
|
||||
char **argv=new char *[args.GetCount()+2];
|
||||
|
||||
argv[0]=filename;
|
||||
for(int i=0;i<args.GetCount();i++)
|
||||
argv[i+1]=args[i].c_str();
|
||||
argv[args.GetCount()+1]=0;
|
||||
|
||||
execvp(filename.c_str(),argv);
|
||||
_exit(72);
|
||||
}
|
||||
else //原本的父进程
|
||||
{
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool Process::Wait()
|
||||
{
|
||||
if(pid<0)return(false);
|
||||
int status;
|
||||
int rc;
|
||||
|
||||
do
|
||||
{
|
||||
rc=waitpid(pid,&status,0);
|
||||
}while(rc<0&&errno==EINTR);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool Process::Kill()
|
||||
{
|
||||
if(pid<0)return(false);
|
||||
|
||||
return !kill(pid,SIGKILL);
|
||||
}
|
||||
|
||||
bool Process::RequestTerminate()
|
||||
{
|
||||
if(pid<0)return(false);
|
||||
|
||||
return !kill(pid,SIGINT);
|
||||
}
|
||||
}//namespace hgl
|
78
src/UNIX/ProgramPath.cpp
Normal file
78
src/UNIX/ProgramPath.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
#include<hgl/type/BaseString.h>
|
||||
#include<unistd.h>
|
||||
#include<pwd.h>
|
||||
#include<unistd.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
void GetLocalAppdataPath(os_char fn[HGL_MAX_PATH])
|
||||
{
|
||||
struct passwd pwd;
|
||||
struct passwd *result;
|
||||
char *buf;
|
||||
size_t bufsize=sysconf(_SC_GETPW_R_SIZE_MAX);
|
||||
|
||||
if(bufsize==-1)
|
||||
bufsize=16384;
|
||||
|
||||
buf=(char *)malloc(bufsize);
|
||||
|
||||
getpwuid_r(getuid(),&pwd,buf,bufsize,&result);
|
||||
|
||||
strcpy(fn,HGL_MAX_PATH,pwd.pw_dir);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得当前程序完整路径名称
|
||||
*/
|
||||
bool GetCurrentProgram(OSString &result)
|
||||
{
|
||||
os_char *path=new os_char[HGL_MAX_PATH];
|
||||
|
||||
const int len=readlink("/proc/self/exe",path,HGL_MAX_PATH);
|
||||
|
||||
if(len<=0)
|
||||
{
|
||||
delete[] path;
|
||||
return(false);
|
||||
}
|
||||
|
||||
path[len]=0;
|
||||
result.Set(path,len,true);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得当前程序所在路径
|
||||
*/
|
||||
bool GetCurrentProgramPath(OSString &result)
|
||||
{
|
||||
os_char *path=new os_char[HGL_MAX_PATH];
|
||||
|
||||
const int len=readlink("/proc/self/exe",path,HGL_MAX_PATH);
|
||||
|
||||
if(len<=0)
|
||||
{
|
||||
delete[] path;
|
||||
return(false);
|
||||
}
|
||||
|
||||
os_char *right=hgl::strrchr(path,len,HGL_DIRECTORY_SEPARATOR);
|
||||
|
||||
if(right)
|
||||
*right=0;
|
||||
else
|
||||
path[len]=0;
|
||||
|
||||
result.Set(path,len,true);
|
||||
|
||||
return(true);
|
||||
}
|
||||
}//namespace filesystem
|
||||
}//namespace hgl
|
||||
|
51
src/UNIX/RWLock.cpp
Normal file
51
src/UNIX/RWLock.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
#include<hgl/thread/RWLock.h>
|
||||
#include<pthread.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
void GetWaitTime(struct timespec &,double);
|
||||
|
||||
RWLock::RWLock()
|
||||
{
|
||||
lock=new pthread_rwlock_t;
|
||||
|
||||
pthread_rwlock_init((pthread_rwlock_t *)lock,nullptr);
|
||||
}
|
||||
|
||||
RWLock::~RWLock()
|
||||
{
|
||||
pthread_rwlock_destroy((pthread_rwlock_t *)lock);
|
||||
}
|
||||
|
||||
bool RWLock::TryReadLock() {return !pthread_rwlock_tryrdlock((pthread_rwlock_t *)lock);}
|
||||
|
||||
#if HGL_OS != HGL_OS_macOS
|
||||
bool RWLock::WaitReadLock(double t)
|
||||
{
|
||||
struct timespec abstime;
|
||||
|
||||
GetWaitTime(abstime,t);
|
||||
|
||||
return !pthread_rwlock_timedrdlock((pthread_rwlock_t *)lock,&abstime);
|
||||
}
|
||||
#endif//HGL_OS != HGL_OS_macOS
|
||||
|
||||
bool RWLock::ReadLock() {return !pthread_rwlock_rdlock((pthread_rwlock_t *)lock);}
|
||||
bool RWLock::ReadUnlock() {return !pthread_rwlock_unlock((pthread_rwlock_t *)lock);}
|
||||
|
||||
bool RWLock::TryWriteLock() {return !pthread_rwlock_trywrlock((pthread_rwlock_t *)lock);}
|
||||
|
||||
#if HGL_OS != HGL_OS_macOS
|
||||
bool RWLock::WaitWriteLock(double t)
|
||||
{
|
||||
struct timespec abstime;
|
||||
|
||||
GetWaitTime(abstime,t);
|
||||
|
||||
return !pthread_rwlock_timedwrlock((pthread_rwlock_t *)lock,&abstime);
|
||||
}
|
||||
#endif//HGL_OS != HGL_OS_macOS
|
||||
|
||||
bool RWLock::WriteLock() {return !pthread_rwlock_wrlock((pthread_rwlock_t *)lock);}
|
||||
bool RWLock::WriteUnlock() {return !pthread_rwlock_unlock((pthread_rwlock_t *)lock);}
|
||||
}//namespace hgl
|
87
src/UNIX/Semaphore.cpp
Normal file
87
src/UNIX/Semaphore.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
#include<hgl/thread/Semaphore.h>
|
||||
#include<hgl/LogInfo.h>
|
||||
#include<pthread.h>
|
||||
#include<semaphore.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
void GetWaitTime(struct timespec &,double);
|
||||
|
||||
/**
|
||||
* @param max_count 最大计数
|
||||
*/
|
||||
Semaphore::Semaphore(int max_count)
|
||||
{
|
||||
ptr=new sem_t;
|
||||
|
||||
if(sem_init((sem_t *)ptr,PTHREAD_PROCESS_PRIVATE,0))
|
||||
{
|
||||
LOG_ERROR(OS_TEXT("sem_init error,max_count=")+OSString(max_count));
|
||||
delete (sem_t *)ptr;
|
||||
ptr=nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Semaphore::~Semaphore()
|
||||
{
|
||||
if(!ptr)return;
|
||||
|
||||
sem_destroy((sem_t *)ptr);
|
||||
delete (sem_t *)ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送信号
|
||||
* @param n 发送的信号数量
|
||||
* @return 是否释放成功
|
||||
*/
|
||||
bool Semaphore::Post(int n)
|
||||
{
|
||||
if(!ptr)return(false);
|
||||
if(n<=0)return(false);
|
||||
|
||||
int result=0;
|
||||
|
||||
for(int i=0;i<n;i++)
|
||||
result+=sem_post((sem_t *)ptr);
|
||||
|
||||
return !result;
|
||||
|
||||
//if(n==1)
|
||||
// return !sem_post((sem_t *)ptr);
|
||||
//else
|
||||
// return !sem_post_multiple((sem_t *)ptr,n); //注:这个函数不是所有os都支持
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试获取一个信号
|
||||
* @return 是否有取得信号
|
||||
*/
|
||||
bool Semaphore::TryAcquire()
|
||||
{
|
||||
if(!ptr)return(false);
|
||||
|
||||
return !sem_trywait((sem_t *)ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待并获取一个信号
|
||||
* @param t 等待的最长时间,使用0表示无限等待.(单位秒)
|
||||
* @return 是否等待到了,如果超过最长时间,仍未等到即为超时,返回false
|
||||
*/
|
||||
bool Semaphore::Acquire(double t)
|
||||
{
|
||||
if(!ptr)return(false);
|
||||
|
||||
if(t<=0)
|
||||
return !sem_wait((sem_t *)ptr);
|
||||
else
|
||||
{
|
||||
struct timespec abstime;
|
||||
|
||||
GetWaitTime(abstime,t);
|
||||
|
||||
return !sem_timedwait((sem_t *)ptr,&abstime);
|
||||
}
|
||||
}
|
||||
}//namespace hgl
|
121
src/UNIX/SystemInfo.cpp
Normal file
121
src/UNIX/SystemInfo.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
#include<hgl/platform/SystemInfo.h>
|
||||
#include<hgl/platform/ConsoleSystemInitInfo.h>
|
||||
#include<hgl/filesystem/FileSystem.h>
|
||||
#include<pwd.h>
|
||||
#include<unistd.h>
|
||||
#include<signal.h>
|
||||
#include<sys/resource.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
using namespace filesystem;
|
||||
|
||||
bool GetCMGDKPath(OSString &cmgdk_path)
|
||||
{
|
||||
constexpr char path_list[][18]=
|
||||
{
|
||||
"/usr/share/cmgdk",
|
||||
"/usr/local/cmgdk"
|
||||
};
|
||||
|
||||
char home_path[HGL_MAX_PATH];
|
||||
|
||||
struct passwd *pwd=getpwuid(getuid());
|
||||
|
||||
memset(home_path,0,sizeof(home_path));
|
||||
|
||||
strcpy(home_path,HGL_MAX_PATH,pwd->pw_dir);
|
||||
strcat(home_path,HGL_MAX_PATH,"/cmgdk",6);
|
||||
|
||||
if(IsDirectory(home_path))
|
||||
{
|
||||
cmgdk_path=home_path;
|
||||
return(true);
|
||||
}
|
||||
|
||||
for(int i=0;i<sizeof(path_list)/sizeof(path_list[0]);i++)
|
||||
{
|
||||
if(IsDirectory(path_list[i]))
|
||||
{
|
||||
cmgdk_path=path_list[i];
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
void GetOSPath(CMGDKPATH &cp)
|
||||
{
|
||||
cp.os =OS_TEXT("/");
|
||||
cp.osfont =OS_TEXT("/usr/share/fonts");
|
||||
|
||||
#if HGL_CPU == HGL_CPU_X86_64
|
||||
cp.library =OS_TEXT("/usr/lib64");
|
||||
#else
|
||||
cp.library =OS_TEXT("/usr/lib");
|
||||
#endif//HGL_CPU == HGL_CPU_X86_64
|
||||
|
||||
cp.common_data =OS_TEXT("/usr/share");
|
||||
cp.local_data =OS_TEXT("/usr/local");
|
||||
|
||||
cp.temp =OS_TEXT("/tmp");
|
||||
|
||||
{
|
||||
struct passwd pwd;
|
||||
struct passwd *result;
|
||||
char *buf;
|
||||
size_t bufsize=sysconf(_SC_GETPW_R_SIZE_MAX);
|
||||
|
||||
if(bufsize==-1)
|
||||
bufsize=16384;
|
||||
|
||||
buf=(char *)malloc(bufsize);
|
||||
|
||||
getpwuid_r(getuid(),&pwd,buf,bufsize,&result);
|
||||
|
||||
cp.mydata =pwd.pw_dir;
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
cp.myprogram =cp.mydata+OS_TEXT("/bin");
|
||||
cp.mydesktop =cp.mydata+OS_TEXT("/Desktop");
|
||||
}
|
||||
|
||||
bool SetLimit(int resource,int count)
|
||||
{
|
||||
struct rlimit64 rl;
|
||||
|
||||
getrlimit64(resource,&rl);
|
||||
|
||||
if(count<=rl.rlim_cur)
|
||||
return(true);
|
||||
|
||||
if(count>rl.rlim_max)
|
||||
rl.rlim_cur=rl.rlim_max;
|
||||
else
|
||||
rl.rlim_cur=count;
|
||||
|
||||
if(setrlimit64(resource,&rl))
|
||||
{
|
||||
LOG_ERROR(OS_TEXT("Set resource ")+OSString(resource)+OS_TEXT(" maximum value to ")+OSString((uint64)(rl.rlim_cur))+OS_TEXT(" failed."));
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool InitOSupport(ConsoleSystemInitInfo *sii)
|
||||
{
|
||||
if(sii->sig.pipe==false)
|
||||
{
|
||||
signal(SIGPIPE,SIG_IGN); //屏蔽管道信号,一般send/recv一个断开的Socket会触发此信号,导致进程退出
|
||||
}
|
||||
|
||||
if(!SetLimit(RLIMIT_NOFILE,sii->max_open_files))
|
||||
return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
}//namespace hgl
|
97
src/UNIX/Thread.cpp
Normal file
97
src/UNIX/Thread.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
#include<hgl/thread/Thread.h>
|
||||
#include<hgl/thread/CondVar.h>
|
||||
#include<hgl/LogInfo.h>
|
||||
#include<signal.h>
|
||||
#include<errno.h>
|
||||
#include<hgl/Str.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
extern THREAD_FUNC ThreadFunc(Thread *tc);
|
||||
|
||||
/**
|
||||
* (线程外部调用)执行当前线程
|
||||
* @return 是否创建线程成功
|
||||
*/
|
||||
bool Thread::Start()
|
||||
{
|
||||
if(tp)
|
||||
{
|
||||
LOG_ERROR(OS_TEXT("Thread::Start() error,tp!=nullptr."));
|
||||
return(false);
|
||||
}
|
||||
|
||||
pthread_attr_t attr;
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
|
||||
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
|
||||
|
||||
exit_lock.Lock();
|
||||
|
||||
if(pthread_create(&tp,&attr,(void *(*)(void *))ThreadFunc,this)) //返回0表示正常
|
||||
{
|
||||
exit_lock.Unlock();
|
||||
tp=0;
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
LOG_ERROR(OS_TEXT("Create Thread (pthread_create) failed.errno:")+OSString(errno));
|
||||
return(false);
|
||||
}
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是当前线程
|
||||
*/
|
||||
bool Thread::IsCurThread()
|
||||
{
|
||||
if(!tp)
|
||||
{
|
||||
LOG_ERROR(OS_TEXT("Thread::IsCurThread() error,tp=nullptr."));
|
||||
return(true);
|
||||
}
|
||||
|
||||
return pthread_equal(pthread_self(),tp); //返回非0表示一致
|
||||
}
|
||||
|
||||
void GetWaitTime(struct timespec &abstime,double t);
|
||||
|
||||
void WaitThreadExit(thread_ptr tp,const double &time_out)
|
||||
{
|
||||
if(!tp)
|
||||
{
|
||||
LOG_ERROR(OS_TEXT("WaitThreadExit error,tp=nullptr."));
|
||||
return;
|
||||
}
|
||||
|
||||
int retval;
|
||||
void *res;
|
||||
|
||||
#if !defined(__ANDROID__)&&!defined(HGL_OS_BSD)
|
||||
if(time_out>0)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
GetWaitTime(ts,time_out);
|
||||
|
||||
retval=pthread_timedjoin_np(tp,&res,&ts);
|
||||
}
|
||||
else
|
||||
#endif//__ANDROID__&&BSD
|
||||
{
|
||||
retval=pthread_join(tp,&res);
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
char thread_addr[(sizeof(thread_ptr)<<1)+1];
|
||||
|
||||
DataToUpperHexStr(thread_addr,(uint8 *)&tp,sizeof(thread_ptr));
|
||||
|
||||
LOG_INFO(U8_TEXT("pthread_timedjoin_np/pthread_join [")+UTF8String(thread_addr)+U8_TEXT("] retval:")+UTF8String(retval));
|
||||
#endif//_DEBUG
|
||||
}
|
||||
}//namespace hgl
|
67
src/UNIX/ThreadMutex.cpp
Normal file
67
src/UNIX/ThreadMutex.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
#include<hgl/thread/ThreadMutex.h>
|
||||
#include<hgl/TypeFunc.h>
|
||||
#include<pthread.h>
|
||||
#include<sys/time.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
void GetWaitTime(struct timespec &,double);
|
||||
|
||||
ThreadMutex::ThreadMutex()
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
pthread_mutexattr_init(&attr);
|
||||
|
||||
pthread_mutex_init(&ptr,&attr);
|
||||
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
}
|
||||
|
||||
ThreadMutex::~ThreadMutex()
|
||||
{
|
||||
pthread_mutex_destroy(&ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得控制权
|
||||
* 如果对象处于排斥状态,则等待
|
||||
*/
|
||||
void ThreadMutex::Lock()
|
||||
{
|
||||
pthread_mutex_lock(&ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试取得控制权
|
||||
* @return 是否成功取得控制权
|
||||
*/
|
||||
bool ThreadMutex::TryLock()
|
||||
{
|
||||
return(!pthread_mutex_trylock(&ptr));
|
||||
}
|
||||
|
||||
#if !defined(__APPLE__)&&!defined(__ANDROID__)
|
||||
/**
|
||||
* 等待并取得控制权
|
||||
* @param time 等待的最大时间,时间为0表示尝试
|
||||
* @return 是否取得控制权
|
||||
*/
|
||||
bool ThreadMutex::WaitLock(double t)
|
||||
{
|
||||
struct timespec abstime;
|
||||
|
||||
GetWaitTime(abstime,t);
|
||||
|
||||
return !pthread_mutex_timedlock(&ptr, &abstime);
|
||||
}
|
||||
#endif//__APPLE__
|
||||
|
||||
/**
|
||||
* 放弃控制权
|
||||
*/
|
||||
void ThreadMutex::Unlock()
|
||||
{
|
||||
pthread_mutex_unlock(&ptr);
|
||||
}
|
||||
}//namespace hgl
|
102
src/UNIX/Time.cpp
Normal file
102
src/UNIX/Time.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
#include<hgl/TypeFunc.h>
|
||||
#include<sys/time.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
void GetWaitTime(struct timespec &abstime,double t)
|
||||
{
|
||||
clock_gettime(CLOCK_REALTIME,&abstime);
|
||||
|
||||
abstime.tv_sec+=t;
|
||||
t-=(long)t;
|
||||
abstime.tv_nsec+=t*HGL_NANO_SEC_PER_SEC;
|
||||
|
||||
if (abstime.tv_nsec >= HGL_NANO_SEC_PER_SEC)
|
||||
{
|
||||
abstime.tv_nsec -= HGL_NANO_SEC_PER_SEC;
|
||||
++abstime.tv_sec;
|
||||
}
|
||||
}
|
||||
}//namespace hgl
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
/**
|
||||
* get current timezone to GMT time offset
|
||||
* @return time offset (second)
|
||||
*/
|
||||
long GetGMTOff()
|
||||
{
|
||||
tzset();
|
||||
//return(-timezone); // linux ok,but BSD don't support
|
||||
|
||||
time_t rawtime;
|
||||
struct tm *timeinfo;
|
||||
|
||||
time(&rawtime);
|
||||
timeinfo=localtime(&rawtime);
|
||||
|
||||
return timeinfo->tm_gmtoff;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得当前时间
|
||||
* @return 当前时间(单位:千分之一秒)
|
||||
*/
|
||||
uint64 GetTime()
|
||||
{
|
||||
// struct timeval tv;
|
||||
// gettimeofday(&tv, nullptr);
|
||||
// return ((tv.tv_sec) * HGL_MILLI_SEC_PRE_SEC) + (tv.tv_usec/1000);
|
||||
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME,&ts);
|
||||
return (ts.tv_sec*HGL_MILLI_SEC_PRE_SEC)+(ts.tv_nsec/1000000);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得当前时间
|
||||
* @return 当前时间(单位:百万分之一秒)
|
||||
*/
|
||||
uint64 GetMicroTime()
|
||||
{
|
||||
// struct timeval tv;
|
||||
// gettimeofday(&tv, nullptr);
|
||||
// return (tv.tv_sec) * HGL_MICRO_SEC_PER_SEC + tv.tv_usec;
|
||||
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME,&ts);
|
||||
return (ts.tv_sec*HGL_MICRO_SEC_PER_SEC)+(ts.tv_nsec/1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得当前时间(双精度)
|
||||
* @return 当前时间(单位:秒)
|
||||
*/
|
||||
double GetDoubleTime() ///<取得当前时间(双精度,单位秒)
|
||||
{
|
||||
// struct timeval tv;
|
||||
// gettimeofday(&tv, nullptr);
|
||||
// return double(tv.tv_sec) + (double(tv.tv_usec)/HGL_MICRO_SEC_PER_SEC);
|
||||
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME,&ts);
|
||||
return double(ts.tv_sec)+double(ts.tv_nsec)/HGL_NANO_SEC_PER_SEC;
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待指定时间
|
||||
* @param time 时间(单位:秒)
|
||||
*/
|
||||
void WaitTime(double t)
|
||||
{
|
||||
if(t<=0)return;
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = t;
|
||||
tv.tv_usec = (t-tv.tv_sec)*HGL_MICRO_SEC_PER_SEC;
|
||||
select(0, nullptr, nullptr, nullptr, &tv);
|
||||
|
||||
//注:不要使用sleep/nanosleep/clock_nanosleep来代替select,因为它们是真正的暂停执行线程。而sleep是挂起等待,可以被信号打断
|
||||
}
|
||||
}//namespace hgl
|
30
src/UNIX/XCBVulkan.cpp
Normal file
30
src/UNIX/XCBVulkan.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
#include<hgl/platform/Vulkan.h>
|
||||
#include"XCBWindow.h"
|
||||
#include<vulkan/vulkan_xcb.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
VkSurfaceKHR CreateVulkanSurface(VkInstance vk_inst,Window *w)
|
||||
{
|
||||
if(vk_inst==VK_NULL_HANDLE)return(VK_NULL_HANDLE);
|
||||
if(!w)return(VK_NULL_HANDLE);
|
||||
|
||||
XCBWindow *win=(XCBWindow *)w;
|
||||
|
||||
VkXcbSurfaceCreateInfoKHR createInfo;
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
|
||||
createInfo.pNext = nullptr;
|
||||
createInfo.flags = 0;
|
||||
createInfo.connection = win->GetConnection();
|
||||
createInfo.window = win->GetWindow();
|
||||
|
||||
VkSurfaceKHR surface;
|
||||
|
||||
VkResult res = vkCreateXcbSurfaceKHR(vk_inst, &createInfo, nullptr, &surface);
|
||||
|
||||
if (res != VK_SUCCESS)
|
||||
return(VK_NULL_HANDLE);
|
||||
|
||||
return(surface);
|
||||
}
|
||||
}//namespace hgl
|
110
src/UNIX/XCBWindow.cpp
Normal file
110
src/UNIX/XCBWindow.cpp
Normal file
@ -0,0 +1,110 @@
|
||||
#include"XCBWindow.h"
|
||||
namespace hgl
|
||||
{
|
||||
bool XCBWindow::InitConnection()
|
||||
{
|
||||
int scr;
|
||||
|
||||
connection=xcb_connect(nullptr,&scr);
|
||||
|
||||
if(!connection||xcb_connection_has_error(connection))
|
||||
return(false);
|
||||
|
||||
const xcb_setup_t *setup=xcb_get_setup(connection);
|
||||
xcb_screen_iterator_t iter=xcb_setup_roots_iterator(setup);
|
||||
|
||||
while(scr-->0)xcb_screen_next(&iter);
|
||||
|
||||
screen=iter.data;
|
||||
return(true);
|
||||
}
|
||||
|
||||
XCBWindow::XCBWindow(const UTF8String &wn):Window(wn)
|
||||
{
|
||||
connection=nullptr;
|
||||
screen=nullptr;
|
||||
atom_wm_delete_window=nullptr;
|
||||
}
|
||||
|
||||
XCBWindow::~XCBWindow()
|
||||
{
|
||||
}
|
||||
|
||||
bool XCBWindow::Create(uint w,uint h)
|
||||
{
|
||||
if(w<=0||h<=0)return(false);
|
||||
if(!InitConnection())return(false);
|
||||
|
||||
window=xcb_generate_id(connection);
|
||||
|
||||
uint32_t value_mask,value_list[32];
|
||||
|
||||
value_mask=XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
|
||||
value_list[0] = screen->black_pixel;
|
||||
value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE;
|
||||
|
||||
width=w;
|
||||
height=h;
|
||||
|
||||
xcb_create_window(connection, XCB_COPY_FROM_PARENT, window, screen->root, 0,0, width, height, 0,
|
||||
XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, value_mask, value_list);
|
||||
|
||||
xcb_intern_atom_cookie_t cookie = xcb_intern_atom(connection, 1, 12, "WM_PROTOCOLS");
|
||||
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, cookie, 0);
|
||||
|
||||
xcb_intern_atom_cookie_t cookie2 = xcb_intern_atom(connection, 0, 16, "WM_DELETE_WINDOW");
|
||||
atom_wm_delete_window = xcb_intern_atom_reply(connection, cookie2, 0);
|
||||
|
||||
xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window, (*reply).atom, 4, 32, 1,
|
||||
&(*atom_wm_delete_window).atom);
|
||||
free(reply);
|
||||
|
||||
xcb_change_property (connection, XCB_PROP_MODE_REPLACE, window,XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
|
||||
win_name.Length(), win_name.c_str());
|
||||
|
||||
xcb_map_window(connection, window);
|
||||
|
||||
const uint32_t coords[] =
|
||||
{
|
||||
(screen->width_in_pixels-width)/2,
|
||||
(screen->height_in_pixels-height)/2
|
||||
};
|
||||
xcb_configure_window(connection, window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords);
|
||||
xcb_flush(connection);
|
||||
|
||||
xcb_generic_event_t *e;
|
||||
while ((e = xcb_wait_for_event(connection))) {
|
||||
if ((e->response_type & ~0x80) == XCB_EXPOSE) break;
|
||||
}
|
||||
}
|
||||
|
||||
void XCBWindow::Close()
|
||||
{
|
||||
xcb_destroy_window(connection,window);
|
||||
xcb_disconnect(connection);
|
||||
}
|
||||
|
||||
void XCBWindow::SetCaption(const OSString &caption)
|
||||
{
|
||||
win_name=caption;
|
||||
xcb_change_property (connection, XCB_PROP_MODE_REPLACE, window,XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
|
||||
win_name.Length(), win_name.c_str());
|
||||
}
|
||||
|
||||
bool XCBWindow::MessageProc()
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool XCBWindow::WaitMessage()
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
|
||||
Window *CreateRenderWindow(const UTF8String &win_name)
|
||||
{
|
||||
return(new XCBWindow(win_name));
|
||||
}
|
||||
|
||||
void InitNativeWindowSystem(){}
|
||||
}//namespace hgl
|
39
src/UNIX/XCBWindow.h
Normal file
39
src/UNIX/XCBWindow.h
Normal file
@ -0,0 +1,39 @@
|
||||
#include<hgl/platform/Window.h>
|
||||
#include<xcb/xcb.h>
|
||||
#include<xcb/xcb_atom.h>
|
||||
namespace hgl
|
||||
{
|
||||
class XCBWindow:public Window
|
||||
{
|
||||
xcb_connection_t *connection;
|
||||
xcb_screen_t *screen;
|
||||
xcb_window_t window;
|
||||
xcb_intern_atom_reply_t *atom_wm_delete_window;
|
||||
|
||||
private:
|
||||
|
||||
bool InitConnection();
|
||||
VkSurfaceKHR CreateSurface(VkInstance) override;
|
||||
|
||||
public:
|
||||
|
||||
XCBWindow(const UTF8String &wn);
|
||||
~XCBWindow();
|
||||
|
||||
bool Create(uint w,uint h)override;
|
||||
bool Create(uint,uint,uint)override{}
|
||||
void Close()override;
|
||||
|
||||
xcb_connection_t *GetConnection(){return connection;}
|
||||
xcb_screen_t *GetScreen(){return screen;}
|
||||
xcb_window_t GetWindow(){return window;}
|
||||
|
||||
void SetCaption(const OSString &caption) override;
|
||||
|
||||
void Show()override{}
|
||||
void Hide()override{}
|
||||
bool MessageProc() override;
|
||||
bool WaitMessage() override;
|
||||
};//class XCBWindow:public Window
|
||||
}//namespace hgl
|
||||
|
43
src/Win/Clipboard.cpp
Normal file
43
src/Win/Clipboard.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include<windows.h>
|
||||
#include<shobjidl.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
void CopyTextToClipboard(const u16char *str)
|
||||
{
|
||||
if(!str||!(*str))return;
|
||||
|
||||
if (!OpenClipboard(nullptr))return;
|
||||
|
||||
EmptyClipboard();
|
||||
|
||||
HGLOBAL clipbuffer;
|
||||
u16char * buffer;
|
||||
|
||||
clipbuffer = GlobalAlloc(GMEM_DDESHARE, strlen(str)+1);
|
||||
buffer = (u16char *)GlobalLock(clipbuffer);
|
||||
|
||||
strcpy(buffer, str);
|
||||
|
||||
GlobalUnlock(clipbuffer);
|
||||
SetClipboardData(CF_UNICODETEXT, clipbuffer);
|
||||
CloseClipboard();
|
||||
}
|
||||
|
||||
const u16char *GetTextFromClipboard()
|
||||
{
|
||||
if (!OpenClipboard(nullptr))
|
||||
return 0;
|
||||
|
||||
u16char * buffer = 0;
|
||||
|
||||
HANDLE hData = GetClipboardData( CF_UNICODETEXT );
|
||||
buffer = (u16char *)GlobalLock( hData );
|
||||
GlobalUnlock( hData );
|
||||
CloseClipboard();
|
||||
return buffer;
|
||||
}
|
||||
}//namespace os
|
||||
}//namespace hgl
|
61
src/Win/CodePage.cpp
Normal file
61
src/Win/CodePage.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
#include<hgl/CodePage.h>
|
||||
|
||||
#include<windows.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
int to_utf16(const CharSet &cs,u16char **dst,const char *src,const int src_size)
|
||||
{
|
||||
const int src_str_size=(src_size==-1)?strlen(src):src_size;
|
||||
|
||||
const int len=MultiByteToWideChar(cs.codepage,0,src,src_str_size,0,0);
|
||||
|
||||
if(len<=0)return(len);
|
||||
|
||||
*dst=new u16char[len];
|
||||
|
||||
return MultiByteToWideChar(cs.codepage,0,src,src_str_size,*dst,len);
|
||||
}
|
||||
|
||||
int to_utf8(const CharSet &cs,char **dst,const char *src,const int src_size)
|
||||
{
|
||||
u16char *u16str;
|
||||
int u16size=to_utf16(cs,&u16str,src,src_size);
|
||||
|
||||
if(u16size<=0)return(u16size);
|
||||
|
||||
int u8_size;
|
||||
*dst = u16_to_u8(u16str, u16size, u8_size);
|
||||
|
||||
delete[] u16str;
|
||||
return u8_size;
|
||||
}
|
||||
|
||||
int utf16_to(const CharSet &cs,char **dst,const u16char *src,const int src_size)
|
||||
{
|
||||
const int src_str_size=(src_size==-1)?strlen(src):src_size;
|
||||
|
||||
const int len=WideCharToMultiByte(cs.codepage,0,src,src_str_size,0,0,0,0);
|
||||
|
||||
if(len<=0)return(len);
|
||||
|
||||
*dst=new char[len];
|
||||
|
||||
return WideCharToMultiByte(cs.codepage,0,src,src_str_size,*dst,len,0,0);
|
||||
}
|
||||
|
||||
int utf8_to(const CharSet &cs,char **dst,const char *src,const int src_size)
|
||||
{
|
||||
int u16str_size;
|
||||
u16char *u16str=u8_to_u16(src,src_size,u16str_size);
|
||||
|
||||
if(!u16str)return(0);
|
||||
|
||||
int result=utf16_to(cs,dst,u16str,u16str_size);
|
||||
|
||||
delete[] u16str;
|
||||
return(result);
|
||||
}
|
||||
}//namespace hgl
|
||||
|
||||
|
38
src/Win/CondVar.cpp
Normal file
38
src/Win/CondVar.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#include<hgl/thread/CondVar.h>
|
||||
#include<hgl/thread/ThreadMutex.h>
|
||||
#include<hgl/thread/RWLock.h>
|
||||
|
||||
#pragma warning(disable:4800) // BOOL -> bool 性能损失警告
|
||||
namespace hgl
|
||||
{
|
||||
CondVar::CondVar()
|
||||
{
|
||||
cond_var = new CONDITION_VARIABLE;
|
||||
InitializeConditionVariable((CONDITION_VARIABLE *)cond_var);
|
||||
}
|
||||
|
||||
CondVar::~CondVar()
|
||||
{
|
||||
delete (CONDITION_VARIABLE *)cond_var;
|
||||
}
|
||||
|
||||
bool CondVar::Wait(ThreadMutex *tm, double time)
|
||||
{
|
||||
return SleepConditionVariableCS((CONDITION_VARIABLE *)cond_var,(CRITICAL_SECTION *)(tm->GetThreadMutex()),(DWORD)(time>0?time*1000:INFINITE));
|
||||
}
|
||||
|
||||
bool CondVar::Wait(RWLock *lock, double time, bool read)
|
||||
{
|
||||
return SleepConditionVariableSRW((CONDITION_VARIABLE *)cond_var,(SRWLOCK *)(lock->GetRWLock()),(DWORD)(time>0?time*1000:INFINITE),read?CONDITION_VARIABLE_LOCKMODE_SHARED:0);
|
||||
}
|
||||
|
||||
void CondVar::Signal()
|
||||
{
|
||||
WakeConditionVariable((CONDITION_VARIABLE *)cond_var);
|
||||
}
|
||||
|
||||
void CondVar::Broadcast()
|
||||
{
|
||||
WakeAllConditionVariable((CONDITION_VARIABLE *)cond_var);
|
||||
}
|
||||
}//namespace hgl
|
154
src/Win/DateTime.cpp
Normal file
154
src/Win/DateTime.cpp
Normal file
@ -0,0 +1,154 @@
|
||||
#include<hgl/type/DataType.h>
|
||||
#include<hgl/type/DateTime.h>
|
||||
|
||||
#include<hgl/io/DataInputStream.h>
|
||||
#include<hgl/io/DataOutputStream.h>
|
||||
|
||||
#include<hgl/thread/RWLock.h>
|
||||
|
||||
#include<time.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace
|
||||
{
|
||||
#define APR_DELTA_EPOCH_IN_USEC 11644473600000000 //转Windows时间到Unix时间的一个差值
|
||||
//Windows是1601.1.1
|
||||
//Unix是1970.1.1
|
||||
//tanks for APR
|
||||
|
||||
static inline void SystemTimeToMicroTime(uint64 *result, SYSTEMTIME *st_input)
|
||||
{
|
||||
FILETIME ft;
|
||||
|
||||
SystemTimeToFileTime(st_input, &ft);
|
||||
|
||||
/* Convert FILETIME one 64 bit number so we can work with it. */
|
||||
*result = ft.dwHighDateTime;
|
||||
*result = (*result) << 32;
|
||||
*result |= ft.dwLowDateTime;
|
||||
*result /= 10; /* Convert from 100 nano-sec periods to micro-seconds. */
|
||||
*result -= APR_DELTA_EPOCH_IN_USEC; /* Convert from Windows epoch to Unix epoch */
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void MicroTimeToFileTime(LPFILETIME pft, uint64 t)
|
||||
{
|
||||
LONGLONG ll;
|
||||
t += APR_DELTA_EPOCH_IN_USEC;
|
||||
ll = t * 10;
|
||||
pft->dwLowDateTime = (DWORD)ll;
|
||||
pft->dwHighDateTime = (DWORD)(ll >> 32);
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void MicroTimeToSystemTime(LPSYSTEMTIME pst, uint64 t)
|
||||
{
|
||||
FILETIME ft;
|
||||
|
||||
MicroTimeToFileTime(&ft, t);
|
||||
|
||||
FileTimeToSystemTime(&ft, pst);
|
||||
}
|
||||
}
|
||||
}//namespace hgl
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
//和系统时间同步
|
||||
void Time::Sync(const double cur_time)
|
||||
{
|
||||
uint64 st64;
|
||||
uint64 lt64;
|
||||
|
||||
SYSTEMTIME st;
|
||||
SYSTEMTIME local_time;
|
||||
TIME_ZONE_INFORMATION time_zone;
|
||||
|
||||
if (cur_time <= 0)
|
||||
{
|
||||
GetSystemTime(&st);
|
||||
SystemTimeToMicroTime(&st64, &st);
|
||||
}
|
||||
else
|
||||
{
|
||||
st64 = cur_time*HGL_MICRO_SEC_PER_SEC;
|
||||
MicroTimeToSystemTime(&st, st64);
|
||||
}
|
||||
|
||||
GetTimeZoneInformation(&time_zone);
|
||||
|
||||
SystemTimeToTzSpecificLocalTime(&time_zone, &st, &local_time);
|
||||
|
||||
hours = local_time.wHour;
|
||||
minutes = local_time.wMinute;
|
||||
seconds = local_time.wSecond;
|
||||
micro_seconds = local_time.wMilliseconds * 1000;
|
||||
week_day = local_time.wDayOfWeek;
|
||||
|
||||
SystemTimeToMicroTime(<64, &local_time);
|
||||
|
||||
gmt_off = lt64 - st64;
|
||||
}
|
||||
}//namespace hgl
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
namespace hgl
|
||||
{
|
||||
void Date::Sync(const double cur_time)
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
|
||||
if (cur_time <= 0)
|
||||
GetLocalTime(&st);
|
||||
else
|
||||
MicroTimeToSystemTime(&st, cur_time*HGL_MICRO_SEC_PER_SEC);
|
||||
|
||||
year = st.wYear;
|
||||
month = st.wMonth;
|
||||
day = st.wDay;
|
||||
|
||||
week_day = st.wDayOfWeek;
|
||||
}
|
||||
}//namespace hgl
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
void ToDateTime(Date &d,Time &t,const double cur_time)
|
||||
{
|
||||
FILETIME ft,local_ft;
|
||||
SYSTEMTIME st;
|
||||
|
||||
MicroTimeToFileTime(&ft, cur_time*HGL_MICRO_SEC_PER_SEC);
|
||||
|
||||
FileTimeToSystemTime(&ft, &st);
|
||||
FileTimeToLocalFileTime(&ft, &local_ft);
|
||||
|
||||
d.Set(st.wYear, st.wMonth, st.wDay, st.wDayOfWeek);
|
||||
t.Set(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds * 1000, st.wDayOfWeek);
|
||||
t.SetGMT((local_ft.dwLowDateTime - ft.dwLowDateTime) / 10);
|
||||
}
|
||||
|
||||
double FromDateTime(const int year,const int month,const int day,
|
||||
const int hour,const int minute,const int second,const int micro_second,
|
||||
const int gmt_off)
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
|
||||
st.wYear = year;
|
||||
st.wMonth = month;
|
||||
st.wDay = day;
|
||||
st.wDayOfWeek = 0;
|
||||
|
||||
st.wHour = hour;
|
||||
st.wMinute = minute;
|
||||
st.wSecond = second;
|
||||
st.wMilliseconds = micro_second / 1000;
|
||||
|
||||
uint64 result;
|
||||
SystemTimeToMicroTime(&result, &st);
|
||||
|
||||
result -= gmt_off;
|
||||
return(double(result) / HGL_MICRO_SEC_PER_SEC);
|
||||
}
|
||||
}//namespace hgl
|
||||
|
141
src/Win/Desktop.cpp
Normal file
141
src/Win/Desktop.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
#include<hgl/type/DataType.h>
|
||||
#include<hgl/type/BaseString.h>
|
||||
#include<hgl/filesystem/FileSystem.h>
|
||||
#include<hgl/Desktop.h>
|
||||
#include<shobjidl.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
/**
|
||||
* 弹出一个网页浏览器,并自动打开指定的网址。示例: PopupWebBrowser(L"http://www.hyzgame.com.cn");
|
||||
* @param url 网址
|
||||
*/
|
||||
void PopupWebBrowser(const wchar_t *url)
|
||||
{
|
||||
ShellExecuteW(nullptr,nullptr,url,nullptr,nullptr,0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 弹出邮件客户端软件,并自动指定收件人的email地址。示例: PopupEmailClient(L"hyz@hyzgame.com.cn",L"您好!");
|
||||
* @param email 电子邮件地址
|
||||
* @param subject 邮件主题
|
||||
*/
|
||||
void PopupEmailClient(const WideString &email,const WideString &subject)
|
||||
{
|
||||
wchar_t url[MAX_PATH]=L"mailto:";
|
||||
|
||||
strcat(url, MAX_PATH, email);
|
||||
|
||||
const wchar_t subject_header[] = L"?Subject=\"";
|
||||
const size_t subject_header_size = sizeof(subject_header)/sizeof(wchar_t);
|
||||
|
||||
strcat(url, MAX_PATH, subject_header, subject_header_size);
|
||||
strcat(url, MAX_PATH, subject);
|
||||
strcat(url, MAX_PATH, L'\"');
|
||||
|
||||
ShellExecuteW(nullptr,nullptr,url,nullptr,nullptr,0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建快捷方式
|
||||
* @param sc 快捷方式配置
|
||||
* @return 是否成功
|
||||
*/
|
||||
bool CreateShortCut(const ShortCut &sc)
|
||||
{
|
||||
IShellLinkW *psl=nullptr;
|
||||
IPersistFile *pPf=nullptr;
|
||||
|
||||
WideString lnk_filename=sc.lnk_filename;
|
||||
|
||||
lnk_filename += L".lnk";
|
||||
|
||||
HRESULT hresult;
|
||||
|
||||
hresult=CoCreateInstance(CLSID_ShellLink,nullptr,CLSCTX_INPROC_SERVER,IID_IShellLinkW,(LPVOID*)&psl);
|
||||
|
||||
if(hresult!=S_OK)
|
||||
return(false);
|
||||
|
||||
hresult=psl->QueryInterface(IID_IPersistFile,(LPVOID*)&pPf);
|
||||
|
||||
if(hresult!=S_OK)
|
||||
return(false);
|
||||
|
||||
if(!sc.work_directory.IsEmpty())
|
||||
{
|
||||
hresult=psl->SetWorkingDirectory(sc.work_directory.c_str());
|
||||
|
||||
if(hresult!=S_OK)
|
||||
return(false);
|
||||
}
|
||||
|
||||
if(!sc.param.IsEmpty())
|
||||
{
|
||||
hresult=psl->SetArguments(sc.param.c_str());
|
||||
|
||||
if(hresult!=S_OK)
|
||||
return(false);
|
||||
}
|
||||
|
||||
hresult=psl->SetPath(sc.filename.c_str());
|
||||
|
||||
if(hresult!=S_OK)
|
||||
return(false);
|
||||
|
||||
if(!sc.icon_filename.IsEmpty())
|
||||
if(filesystem::FileExist(sc.icon_filename))
|
||||
{
|
||||
hresult=psl->SetIconLocation(sc.icon_filename.c_str(),0);
|
||||
|
||||
if(hresult!=S_OK)
|
||||
return(false);
|
||||
}
|
||||
|
||||
if(!sc.descript.IsEmpty())
|
||||
{
|
||||
hresult=psl->SetDescription(sc.descript.c_str());
|
||||
|
||||
if(hresult!=S_OK)
|
||||
return(false);
|
||||
}
|
||||
|
||||
hresult=pPf->Save(lnk_filename.c_str(),TRUE);
|
||||
|
||||
if(hresult!=S_OK)
|
||||
return(false);
|
||||
|
||||
if(pPf)
|
||||
pPf->Release();
|
||||
|
||||
if(psl)
|
||||
psl->Release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//#if (NTDDI_VERSION >= NTDDI_VISTA)
|
||||
// /**
|
||||
// * 取得文件图标
|
||||
// * @param filename 文件名
|
||||
// * @param width 图标宽度
|
||||
// * @param height 图标高度
|
||||
// * @param color 图标色彩数
|
||||
// * @return 图标象素数据(请自行delete[],另返回NULL表示失败)
|
||||
// */
|
||||
// void *GetFileIcon(const wchar_t *filename,int &width,int &height,int &color)
|
||||
// {
|
||||
// IShellItemImageFactory *pShellItemImageFactory = nullptr;
|
||||
// IBindCtx *m_pBindContext;
|
||||
//
|
||||
// //该函数要求ie7.0,但无法确定
|
||||
// if(SHCreateItemFromParsingName(filename
|
||||
// m_pBindContext,
|
||||
// IID_PPV_ARGS(&pShellItemImageFactory)
|
||||
// )!=S_OK)return(false);
|
||||
// }
|
||||
//#endif//NTDDI_VERSION >= NTDDI_VISTA
|
||||
}//namespace os
|
||||
}//namespace hgl
|
131
src/Win/EnumFile.cpp
Normal file
131
src/Win/EnumFile.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
#include<hgl/filesystem/EnumFile.h>
|
||||
#include<hgl/LogInfo.h>
|
||||
|
||||
#include<windows.h>
|
||||
#include<sys/types.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
/**
|
||||
* 枚举一个目录内的所有文件
|
||||
* @param config 枚举配置
|
||||
* @return 查找到文件数据,<0表示失败
|
||||
*/
|
||||
int EnumFile::Enum(EnumFileConfig *config)
|
||||
{
|
||||
if(!config)RETURN_ERROR(-1);
|
||||
|
||||
if(config->folder_name.IsEmpty()
|
||||
&&config->find_name.IsEmpty())RETURN_ERROR(-4);
|
||||
|
||||
OSString full_findname;
|
||||
int count=0;
|
||||
|
||||
if(config->folder_name.IsEmpty())
|
||||
{
|
||||
full_findname=config->find_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
full_findname=MergeFilename(config->folder_name,config->find_name);
|
||||
}
|
||||
|
||||
WIN32_FIND_DATAW FindFileData;
|
||||
HANDLE hFind;
|
||||
|
||||
hFind = FindFirstFileW(full_findname, &FindFileData);
|
||||
if (hFind == INVALID_HANDLE_VALUE)
|
||||
return(-1);
|
||||
|
||||
FileInfo fi;
|
||||
int sub_count;
|
||||
|
||||
do
|
||||
{
|
||||
if(strcmp(FindFileData.cFileName,OS_TEXT("."))==0
|
||||
|| strcmp(FindFileData.cFileName,OS_TEXT(".."))==0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(FindFileData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
if(!config->proc_folder)continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!config->proc_file)continue;
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
memset(&fi,0,sizeof(FileInfo));
|
||||
|
||||
strcpy(fi.name,HGL_MAX_PATH,FindFileData.cFileName);
|
||||
|
||||
if(config->folder_name.IsEmpty())
|
||||
{
|
||||
strcpy(fi.fullname, HGL_MAX_PATH, fi.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(fi.fullname, HGL_MAX_PATH, config->folder_name);
|
||||
|
||||
if(config->folder_name.GetEndChar()!=HGL_DIRECTORY_SEPARATOR)
|
||||
strcat(fi.fullname, HGL_MAX_PATH, HGL_DIRECTORY_SEPARATOR);
|
||||
|
||||
const int rp =config->find_name.FindChar(HGL_DIRECTORY_SEPARATOR);//防止查询名称内仍有路径
|
||||
|
||||
if(rp!=-1)
|
||||
strcat(fi.fullname, HGL_MAX_PATH,config->find_name.c_str(),rp);
|
||||
|
||||
strcat(fi.fullname, HGL_MAX_PATH, fi.name, HGL_MAX_PATH);
|
||||
}
|
||||
|
||||
fi.size = FindFileData.nFileSizeHigh;
|
||||
fi.size <<= 32;
|
||||
fi.size |= FindFileData.nFileSizeLow;
|
||||
|
||||
fi.is_hiddle=FindFileData.dwFileAttributes&FILE_ATTRIBUTE_HIDDEN;
|
||||
|
||||
fi.can_read =true;
|
||||
fi.can_write=!(FindFileData.dwFileAttributes&FILE_ATTRIBUTE_READONLY);
|
||||
|
||||
fi.mtime=*(uint64 *)&FindFileData.ftLastWriteTime;
|
||||
|
||||
if(FindFileData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
fi.is_file=false;
|
||||
fi.is_directory=true;
|
||||
|
||||
EnumFileConfig *sub_efc=CreateSubConfig(config,fi);
|
||||
|
||||
if(sub_efc&&config->sub_folder)
|
||||
{
|
||||
sub_count=this->Enum(sub_efc);
|
||||
if(sub_count>0)count+=sub_count;
|
||||
}
|
||||
|
||||
ProcFolder(config,sub_efc,fi);
|
||||
|
||||
if(sub_efc)
|
||||
delete sub_efc;
|
||||
}
|
||||
else
|
||||
{
|
||||
fi.is_file=true;
|
||||
fi.is_directory=false;
|
||||
|
||||
ProcFile(config,fi);
|
||||
}
|
||||
}
|
||||
while(FindNextFileW(hFind, &FindFileData));
|
||||
|
||||
FindClose(hFind);
|
||||
|
||||
return(count);
|
||||
}
|
||||
}//namespace filesystem
|
||||
}//namespace hgl
|
89
src/Win/EnumVolume.cpp
Normal file
89
src/Win/EnumVolume.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
#include<hgl/filesystem/EnumVolume.h>
|
||||
#include<hgl/type/BaseString.h>
|
||||
#include<hgl/LogInfo.h>
|
||||
#include<windows.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
int EnumVolume(List<VolumeInfo> &vi_list,const VolumeCheckConfig &cfg)
|
||||
{
|
||||
if(cfg.isErrorConfig())
|
||||
return(-1);
|
||||
|
||||
HANDLE handle;
|
||||
u16char volume_name[HGL_MAX_PATH+1];
|
||||
u16char path_name[HGL_MAX_PATH];
|
||||
int count=0;
|
||||
|
||||
handle=FindFirstVolumeW(volume_name,HGL_MAX_PATH);
|
||||
|
||||
if(handle==INVALID_HANDLE_VALUE)return(-2);
|
||||
|
||||
do
|
||||
{
|
||||
hgl::filesystem::VolumeInfo vi;
|
||||
|
||||
memset(&vi,0,sizeof(hgl::filesystem::VolumeInfo));
|
||||
|
||||
DWORD length;
|
||||
|
||||
GetVolumePathNamesForVolumeNameW(volume_name,path_name,HGL_MAX_PATH,&length); //这个函数要win xp/2003才能用
|
||||
|
||||
path_name[length]=0;
|
||||
|
||||
hgl::strcpy(vi.name,HGL_MAX_PATH,volume_name);
|
||||
hgl::strcpy(vi.path,HGL_MAX_PATH,path_name);
|
||||
|
||||
UINT type=GetDriveTypeW(path_name);
|
||||
|
||||
if(type==DRIVE_REMOVABLE){ if(!cfg.removable )continue;vi.driver_type=hgl::filesystem::VolumeInfo::dtRemovable; }else
|
||||
if(type==DRIVE_FIXED ){ if(!cfg.fixed )continue;vi.driver_type=hgl::filesystem::VolumeInfo::dtFixed; }else
|
||||
if(type==DRIVE_REMOTE ){ if(!cfg.remote )continue;vi.driver_type=hgl::filesystem::VolumeInfo::dtRemote; }else
|
||||
if(type==DRIVE_RAMDISK ){ if(!cfg.ram_disk )continue;vi.driver_type=hgl::filesystem::VolumeInfo::dtRamDisk; }else
|
||||
if(type==DRIVE_CDROM ){ if(!cfg.cdrom )continue;vi.driver_type=hgl::filesystem::VolumeInfo::dtCDROM; }else
|
||||
{
|
||||
if(cfg.unknow)vi.driver_type=hgl::filesystem::VolumeInfo::dtNone;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32 file_system_flags;
|
||||
|
||||
if(GetVolumeInformationW(path_name,
|
||||
vi.volume_label,
|
||||
255,
|
||||
(unsigned long *)&vi.serial,
|
||||
(unsigned long *)&vi.filename_max_length,
|
||||
(unsigned long *)&file_system_flags,
|
||||
vi.file_system,
|
||||
255))
|
||||
{
|
||||
vi.unicode=file_system_flags&FILE_UNICODE_ON_DISK;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PROBLEM(U16_TEXT("Get <")+UTF16String(path_name)+U16_TEXT("> info failed!Windows error code: ")+UTF16String((uint)GetLastError()));
|
||||
}
|
||||
|
||||
if(GetDiskFreeSpaceExW(path_name,
|
||||
(ULARGE_INTEGER *)&vi.available_space,
|
||||
(ULARGE_INTEGER *)&vi.total_space,
|
||||
(ULARGE_INTEGER *)&vi.free_space))
|
||||
{
|
||||
vi_list.Add(vi);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PROBLEM(U16_TEXT("Get disk free space <")+UTF16String(path_name)+U16_TEXT("> data failed,Windows error code: ")+UTF16String((uint)GetLastError()));
|
||||
}
|
||||
|
||||
count++;
|
||||
} while(FindNextVolumeW(handle,volume_name,HGL_MAX_PATH));
|
||||
|
||||
FindVolumeClose(handle);
|
||||
|
||||
return(count);
|
||||
}
|
||||
}//namespace filesystem
|
||||
}//namespace hgl
|
54
src/Win/ExternalModule.cpp
Normal file
54
src/Win/ExternalModule.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include<hgl/platform/ExternalModule.h>
|
||||
#include<hgl/platform/Platform.h>
|
||||
#include<hgl/LogInfo.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
ExternalModule *LoadExternalModule(const os_char *filename)
|
||||
{
|
||||
ExternalModulePointer fp=LoadLibraryW(filename);
|
||||
|
||||
if(!fp)
|
||||
{
|
||||
uint dw=GetLastError();
|
||||
os_char *str=nullptr;
|
||||
|
||||
FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,nullptr,dw,
|
||||
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),str,0,nullptr);
|
||||
|
||||
LOG_ERROR(OS_TEXT("LoadModule <")+OSString(filename)+OS_TEXT("> error! os info: ")+OSString(dw)+OSString::charOf(',')+str);
|
||||
|
||||
return(nullptr);
|
||||
}
|
||||
|
||||
return(new ExternalModule(fp));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载一个外部模块
|
||||
* @param name 模块文件名称
|
||||
* @return 是否加载成功
|
||||
*/
|
||||
bool ExternalModule::Load(const os_char *name)
|
||||
{
|
||||
Clear();
|
||||
|
||||
fp=LoadLibraryW(name);
|
||||
|
||||
if(!fp)
|
||||
{
|
||||
const uint dw=GetLastError();
|
||||
u16char *str=nullptr;
|
||||
|
||||
FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,nullptr,dw,
|
||||
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),str,0,nullptr);
|
||||
|
||||
LOG_ERROR(L"LoadModule <"+UTF16String(name)+L"> error! os info: "+UTF16String(dw)+UTF16String::charOf(L',')+str);
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
}//namespace hgl
|
||||
|
0
src/Win/Fifo.cpp
Normal file
0
src/Win/Fifo.cpp
Normal file
217
src/Win/File.cpp
Normal file
217
src/Win/File.cpp
Normal file
@ -0,0 +1,217 @@
|
||||
#include<hgl/filesystem/FileSystem.h>
|
||||
#include<hgl/LogInfo.h>
|
||||
#include<hgl/io/FileInputStream.h>
|
||||
#include<hgl/io/FileOutputStream.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
constexpr int FILE_PROC_BUF_SIZE=HGL_SIZE_1MB;
|
||||
|
||||
/**
|
||||
* 复制一个文件
|
||||
* @param sourcename 源文件名
|
||||
* @param targetname 目标文件名
|
||||
* @return 文件是否复制成功
|
||||
*/
|
||||
bool FileCopy(const OSString &targetname,const OSString &sourcename)
|
||||
{
|
||||
return(::CopyFileW(sourcename,targetname,false));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个文件
|
||||
* @param filename 文件名
|
||||
* @return 文件是否成功删除
|
||||
*/
|
||||
bool FileDelete(const OSString &filename)
|
||||
{
|
||||
return(::DeleteFileW(filename));
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动一个文件
|
||||
* @param sourcename 源文件名
|
||||
* @param targetname 目标文件名
|
||||
* @return 文件是否移动成功
|
||||
*/
|
||||
bool FileMove(const OSString &targetname,const OSString &sourcename)
|
||||
{
|
||||
return(::MoveFileW(sourcename,targetname));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改文件名
|
||||
* @param oldname 旧的文件名
|
||||
* @param newname 新的文件名
|
||||
* @return 文件名是否修改成功
|
||||
*/
|
||||
bool FileRename(const OSString &newname,const OSString &oldname)
|
||||
{
|
||||
return(::MoveFileW(oldname,newname));
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认文件是否存在
|
||||
* @param filename 要查找的文件名称
|
||||
* @return 这个文件是否存在
|
||||
*/
|
||||
bool FileExist(const OSString &filename)
|
||||
{
|
||||
WIN32_FIND_DATAW wfd;
|
||||
HANDLE hFind;
|
||||
|
||||
hFind=FindFirstFileW(filename, &wfd);
|
||||
|
||||
if(hFind==INVALID_HANDLE_VALUE)
|
||||
return(false);
|
||||
|
||||
FindClose(hFind);
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测文件是否可读
|
||||
* @param filename 文件名
|
||||
*/
|
||||
bool FileCanRead(const OSString &filename)
|
||||
{
|
||||
const DWORD attr=GetFileAttributesW(filename);
|
||||
|
||||
if(attr==INVALID_FILE_ATTRIBUTES)
|
||||
return(false);
|
||||
|
||||
if(attr&(FILE_ATTRIBUTE_DEVICE|FILE_ATTRIBUTE_DIRECTORY)) //不是个文件
|
||||
return(false);
|
||||
|
||||
if(attr&FILE_ATTRIBUTE_OFFLINE)
|
||||
return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测文件是否可写
|
||||
* @param filename 文件名
|
||||
*/
|
||||
bool FileCanWrite(const OSString &filename)
|
||||
{
|
||||
const DWORD attr=GetFileAttributesW(filename);
|
||||
|
||||
if(attr==INVALID_FILE_ATTRIBUTES)
|
||||
return(false);
|
||||
|
||||
if(attr&(FILE_ATTRIBUTE_DEVICE|FILE_ATTRIBUTE_DIRECTORY)) //不是个文件
|
||||
return(false);
|
||||
|
||||
if(attr&FILE_ATTRIBUTE_OFFLINE)
|
||||
return(false);
|
||||
|
||||
return (attr&FILE_ATTRIBUTE_READONLY)?false:true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测文件是否可执行
|
||||
* @param filename 文件名
|
||||
*/
|
||||
bool FileCanExec(const OSString &filename)
|
||||
{
|
||||
int index = filename.FindRightChar('.');
|
||||
|
||||
if (index == -1)return(false);
|
||||
|
||||
if (index > filename.Length() - 4)
|
||||
return(false);
|
||||
|
||||
const os_char *ext = filename.c_str() + index + 1;
|
||||
|
||||
if (!ext)return(false);
|
||||
|
||||
if (stricmp(ext, "exe") == 0)return(true);
|
||||
if (stricmp(ext, "com") == 0)return(true);
|
||||
if (stricmp(ext, "bat") == 0)return(true);
|
||||
if (stricmp(ext, "msi") == 0)return(true);
|
||||
if (stricmp(ext, "msp") == 0)return(true);
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前名称是否是一个目录
|
||||
* @param name 名称
|
||||
*/
|
||||
bool IsDirectory(const os_char *name)
|
||||
{
|
||||
DWORD attrib = GetFileAttributesW(name);
|
||||
|
||||
if (attrib == INVALID_FILE_ATTRIBUTES)
|
||||
return(false);
|
||||
|
||||
return attrib&FILE_ATTRIBUTE_DIRECTORY;
|
||||
}
|
||||
|
||||
bool MakeDirectory(const os_char *name)
|
||||
{
|
||||
if(::CreateDirectoryW(name,nullptr))return(true);
|
||||
|
||||
const uint win_error=GetLastError();
|
||||
|
||||
LOG_PROBLEM(OS_TEXT("Create Directory <")+OSString(name)+OS_TEXT("> failed,errno: ")+OSString(win_error));
|
||||
return(false);
|
||||
}
|
||||
|
||||
os_char *GetRootPath(os_char *str)
|
||||
{
|
||||
if(str[1]==OS_TEXT(':'))
|
||||
return str+3;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个子目录
|
||||
* @param name 目录名称
|
||||
* @return 目录是否删除成功
|
||||
*/
|
||||
bool DeletePath(const OSString &name)
|
||||
{
|
||||
return(RemoveDirectoryW(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得当前所在目录<br>
|
||||
*/
|
||||
bool GetCurrentPath(OSString &path)
|
||||
{
|
||||
int len;
|
||||
u16char *dir;
|
||||
|
||||
len=GetCurrentDirectoryW(0,nullptr);
|
||||
|
||||
if(len==0)
|
||||
return(nullptr);
|
||||
|
||||
dir=new u16char[len+1];
|
||||
|
||||
if(GetCurrentDirectoryW(len,dir))
|
||||
{
|
||||
if(len==3&&dir[1]==OS_TEXT(':'))
|
||||
len=2; //如果是"C:\"这种情况,去掉"\"
|
||||
|
||||
dir[len]=0;
|
||||
|
||||
path.Set(dir,len,true);
|
||||
return(true);
|
||||
}
|
||||
|
||||
delete[] dir;
|
||||
return(false);
|
||||
}
|
||||
}//namespace filesystem
|
||||
}//namespace hgl
|
68
src/Win/FileAccess.cpp
Normal file
68
src/Win/FileAccess.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
#include<hgl/io/FileAccess.h>
|
||||
#include<hgl/LogInfo.h>
|
||||
#include<io.h>
|
||||
#include<share.h>
|
||||
#include<fcntl.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
bool FileAccess::CreateTemp()
|
||||
{
|
||||
const uint buf_size=HGL_MAX_PATH;
|
||||
|
||||
u16char PathBuffer[buf_size];
|
||||
u16char TempName[buf_size];
|
||||
|
||||
GetTempPathW(buf_size,PathBuffer);
|
||||
|
||||
GetTempFileNameW(PathBuffer,L"NEW",0,TempName);
|
||||
|
||||
return Open(TempName,fomCreate);
|
||||
}
|
||||
|
||||
int OpenFile(const os_char *fn,FileOpenMode fom)
|
||||
{
|
||||
int fp;
|
||||
|
||||
errno_t result;
|
||||
|
||||
if(fom==fomCreate )result=_wsopen_s(&fp,fn,_O_BINARY|_O_WRONLY|_O_CREAT ,_SH_DENYNO,S_IREAD|_S_IWRITE);else
|
||||
if(fom==fomCreateTrunc )result=_wsopen_s(&fp,fn,_O_BINARY|_O_WRONLY|_O_CREAT|_O_TRUNC ,_SH_DENYNO,S_IREAD|_S_IWRITE);else
|
||||
// if(fom==fomCreateTemp )result=_wsopen_s(&fp,fn,_O_BINARY|_O_WRONLY|_O_CREAT|_O_TEMPORARY ,_SH_DENYNO,S_IREAD|_S_IWRITE);else //某些平台不支持,所以全都不使用fomCreateTemp,统一使用CreateTemp
|
||||
if(fom==fomOnlyRead )result=_wsopen_s(&fp,fn,_O_BINARY|_O_RDONLY ,_SH_DENYNO,S_IREAD|_S_IWRITE);else
|
||||
if(fom==fomOnlyWrite )result=_wsopen_s(&fp,fn,_O_BINARY|_O_WRONLY ,_SH_DENYNO,S_IREAD|_S_IWRITE);else
|
||||
if(fom==fomReadWrite )result=_wsopen_s(&fp,fn,_O_BINARY|_O_RDWR ,_SH_DENYNO,S_IREAD|_S_IWRITE);else
|
||||
if(fom==fomAppend )result=_wsopen_s(&fp,fn,_O_BINARY|_O_APPEND ,_SH_DENYNO,S_IREAD|_S_IWRITE);else
|
||||
RETURN_ERROR(-1);
|
||||
|
||||
return(fp);
|
||||
}
|
||||
|
||||
void CloseFile(int fp)
|
||||
{
|
||||
_close(fp);
|
||||
}
|
||||
|
||||
int64 FileAccess::Read(int64 offset,void *buf,int64 size)
|
||||
{
|
||||
if(!CanRead())return(-1);
|
||||
|
||||
if(_lseeki64(fp,offset,(int)SeekOrigin::Begin)==offset)
|
||||
return _read(fp,buf,size);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
int64 FileAccess::Write(int64 offset,const void *buf,int64 size)
|
||||
{
|
||||
if(!CanWrite())return(-1);
|
||||
|
||||
if(_lseeki64(fp,offset,(int)SeekOrigin::Begin)==offset)
|
||||
return _write(fp,buf,size);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
}//namespace io
|
||||
}//namespace hgl
|
66
src/Win/LogConsole.cpp
Normal file
66
src/Win/LogConsole.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
#include<hgl/Logger.h>
|
||||
#include<hgl/CodePage.h>
|
||||
#include<windows.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace logger
|
||||
{
|
||||
constexpr uint LOG_BUF_SIZE=4096;
|
||||
|
||||
class LogWinConsole:public Logger
|
||||
{
|
||||
private:
|
||||
|
||||
DWORD result;
|
||||
|
||||
void *console_handle;
|
||||
|
||||
u16char buf[LOG_BUF_SIZE];
|
||||
|
||||
public:
|
||||
|
||||
LogWinConsole(LogLevel ll):Logger(ll)
|
||||
{
|
||||
console_handle=GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
}
|
||||
|
||||
bool Create(const UTF16String &)
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
|
||||
~LogWinConsole()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void Close()
|
||||
{
|
||||
CloseHandle(console_handle);
|
||||
}
|
||||
|
||||
void Write(const u16char *str,int size)
|
||||
{
|
||||
WriteConsoleW(console_handle,str,size,&result,nullptr);
|
||||
WriteConsoleW(console_handle,L"\n", 1, &result, nullptr);
|
||||
}
|
||||
|
||||
void Write(const char *str,int size)
|
||||
{
|
||||
const int len=u8_to_u16(buf,LOG_BUF_SIZE,str,size);
|
||||
|
||||
if(len<=0)return;
|
||||
|
||||
buf[len]=L'\n';
|
||||
|
||||
WriteConsoleW(console_handle,buf,len+1,&result,nullptr);
|
||||
}
|
||||
};//class LogWinConsole
|
||||
|
||||
Logger *CreateLoggerConsole(const OSString &,LogLevel ll)
|
||||
{
|
||||
return(new LogWinConsole(ll));
|
||||
}
|
||||
}//namespace logger
|
||||
}//namespace hgl
|
53
src/Win/LogDialog.cpp
Normal file
53
src/Win/LogDialog.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
#include<hgl/Logger.h>
|
||||
#include<hgl/CodePage.h>
|
||||
#include<windows.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace logger
|
||||
{
|
||||
class LogWinDialog:public Logger
|
||||
{
|
||||
UTF16String name;
|
||||
|
||||
u16char buf[4096];
|
||||
|
||||
public:
|
||||
|
||||
LogWinDialog(LogLevel ll):Logger(ll)
|
||||
{
|
||||
name=project_code;
|
||||
}
|
||||
|
||||
bool Create(const UTF16String &)
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
|
||||
void Close()
|
||||
{
|
||||
}
|
||||
|
||||
void Write(const u16char *str,int)
|
||||
{
|
||||
MessageBoxW(nullptr,str,name,MB_OK);
|
||||
}
|
||||
|
||||
void Write(const char *str,int size)
|
||||
{
|
||||
const int len=u8_to_u16(buf,4096,str,size);
|
||||
|
||||
if(len<=0)return;
|
||||
|
||||
buf[len] = 0;
|
||||
|
||||
MessageBoxW(nullptr,buf,name,MB_OK);
|
||||
}
|
||||
};//class LogWinDialog
|
||||
|
||||
Logger *CreateLoggerDialog(const OSString &,LogLevel ll)
|
||||
{
|
||||
return(new LogWinDialog(ll));
|
||||
}
|
||||
}//namespace logger
|
||||
}//namespace hgl
|
16
src/Win/Pipe.cpp
Normal file
16
src/Win/Pipe.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
#include<hgl/proc/Pipe.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
bool CreatePipe(pipe_pair &pp)
|
||||
{
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
|
||||
sa.nLength=sizeof(SECURITY_ATTRIBUTES);
|
||||
sa.bInheritHandle=TRUE;
|
||||
sa.lpSecurityDescriptor=nullptr;
|
||||
|
||||
return CreatePipe(&(pp[0]),&(pp[1]),&sa,0);
|
||||
}
|
||||
}//namespace hgl
|
||||
|
65
src/Win/ProcMutex.cpp
Normal file
65
src/Win/ProcMutex.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
#include<hgl/proc/ProcMutex.h>
|
||||
#include<windows.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
ProcMutex::ProcMutex()
|
||||
{
|
||||
lock = nullptr;
|
||||
}
|
||||
|
||||
bool ProcMutex::Create(const os_char *name)
|
||||
{
|
||||
if (lock != nullptr)return(false);
|
||||
|
||||
lock = CreateMutexW(NULL, FALSE, name);
|
||||
|
||||
if(GetLastError()==ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
CloseHandle(lock);
|
||||
lock=nullptr;
|
||||
}
|
||||
|
||||
return lock;
|
||||
}
|
||||
|
||||
void ProcMutex::Clear()
|
||||
{
|
||||
if (lock == nullptr)return;
|
||||
|
||||
CloseHandle(lock);
|
||||
|
||||
lock = nullptr;
|
||||
}
|
||||
|
||||
bool ProcMutex::Lock()
|
||||
{
|
||||
if (lock == nullptr)return(false);
|
||||
|
||||
DWORD rv = WaitForSingleObject(lock, INFINITE);
|
||||
|
||||
if (rv == WAIT_OBJECT_0 || rv == WAIT_ABANDONED)
|
||||
return(true);
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
bool ProcMutex::TryLock()
|
||||
{
|
||||
if (lock == nullptr)return(false);
|
||||
|
||||
DWORD rv = WaitForSingleObject(lock, 0);
|
||||
|
||||
if (rv == WAIT_OBJECT_0 || rv == WAIT_ABANDONED)
|
||||
return(true);
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
bool ProcMutex::Unlock()
|
||||
{
|
||||
if (lock == nullptr)return(false);
|
||||
|
||||
return(!ReleaseMutex(lock));
|
||||
}
|
||||
}//namespace hgl
|
49
src/Win/ProgramPath.cpp
Normal file
49
src/Win/ProgramPath.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
#include<hgl/type/BaseString.h>
|
||||
#include<windows.h>
|
||||
#include<shlobj.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
void GetLocalAppdataPath(os_char fn[HGL_MAX_PATH])
|
||||
{
|
||||
SHGetFolderPathW(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0, fn);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得当前程序完整路径名称
|
||||
*/
|
||||
bool GetCurrentProgram(OSString &result)
|
||||
{
|
||||
os_char *path=new os_char[HGL_MAX_PATH];
|
||||
|
||||
GetModuleFileNameW(nullptr,path,HGL_MAX_PATH);
|
||||
|
||||
result = path;
|
||||
delete[] path;
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得当前程序所在路径
|
||||
*/
|
||||
bool GetCurrentProgramPath(OSString &result)
|
||||
{
|
||||
os_char *path=new os_char[HGL_MAX_PATH];
|
||||
|
||||
int len=GetModuleFileNameW(nullptr,path,HGL_MAX_PATH);
|
||||
|
||||
os_char *right=hgl::strrchr(path,len,HGL_DIRECTORY_SEPARATOR);
|
||||
|
||||
if(right)
|
||||
*right=0;
|
||||
|
||||
result = path;
|
||||
delete[] path;
|
||||
|
||||
return(true);
|
||||
}
|
||||
}//namespace filesystem
|
||||
}//namespace hgl
|
25
src/Win/RWLock.cpp
Normal file
25
src/Win/RWLock.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include<hgl/thread/RWLock.h>
|
||||
|
||||
#pragma warning(disable:4800) // BOOL -> bool 性能损失警告
|
||||
namespace hgl
|
||||
{
|
||||
RWLock::RWLock()
|
||||
{
|
||||
lock = new SRWLOCK;
|
||||
|
||||
InitializeSRWLock((SRWLOCK *)lock);
|
||||
}
|
||||
|
||||
RWLock::~RWLock()
|
||||
{
|
||||
delete (SRWLOCK *)lock;
|
||||
}
|
||||
|
||||
bool RWLock::TryReadLock() { return TryAcquireSRWLockShared((SRWLOCK *)lock); }
|
||||
bool RWLock::ReadLock() { AcquireSRWLockShared((SRWLOCK *)lock); return(true); }
|
||||
bool RWLock::ReadUnlock() { ReleaseSRWLockShared((SRWLOCK *)lock); return(true); }
|
||||
|
||||
bool RWLock::TryWriteLock() { return TryAcquireSRWLockExclusive((SRWLOCK *)lock); }
|
||||
bool RWLock::WriteLock() { AcquireSRWLockExclusive((SRWLOCK *)lock); return(true); }
|
||||
bool RWLock::WriteUnlock() { ReleaseSRWLockExclusive((SRWLOCK *)lock); return(true); }
|
||||
}//namespace hgl
|
54
src/Win/Semaphore.cpp
Normal file
54
src/Win/Semaphore.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include<hgl/thread/Semaphore.h>
|
||||
#include<hgl/LogInfo.h>
|
||||
|
||||
#include<wchar.h>
|
||||
#pragma warning(disable:4800) // int -> bool 性能损失警告
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
/**
|
||||
* @param max_count 最大计数
|
||||
*/
|
||||
Semaphore::Semaphore(int max_count)
|
||||
{
|
||||
ptr=CreateSemaphore(nullptr,0,max_count,nullptr);
|
||||
|
||||
if(!ptr)
|
||||
LOG_ERROR(OS_TEXT("CreateSemaphore error,max_count=")+OSString(max_count));
|
||||
}
|
||||
|
||||
Semaphore::~Semaphore()
|
||||
{
|
||||
CloseHandle(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送信号
|
||||
* @param n 发送的信号数量
|
||||
* @return 是否释放成功
|
||||
*/
|
||||
bool Semaphore::Post(int n)
|
||||
{
|
||||
if(n<=0)return(false);
|
||||
return(ReleaseSemaphore(ptr,n,nullptr));
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试获取一个信号
|
||||
* @return 是否有取得信号
|
||||
*/
|
||||
bool Semaphore::TryAcquire()
|
||||
{
|
||||
return(WaitForSingleObject(ptr,0)==WAIT_OBJECT_0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待并获取一个信号
|
||||
* @param time 等待的最长时间,使用0表示无限等待.(单位秒)
|
||||
* @return 是否等待到了,如果超过最长时间,仍未等到即为超时,返回false
|
||||
*/
|
||||
bool Semaphore::Acquire(double time_out)
|
||||
{
|
||||
return(WaitForSingleObject(ptr,time_out>0?DWORD(time_out*1000):INFINITE)==WAIT_OBJECT_0);
|
||||
}
|
||||
}//namespace hgl
|
99
src/Win/SystemInfo.cpp
Normal file
99
src/Win/SystemInfo.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
#include<hgl/platform/SystemInfo.h>
|
||||
//#include<hgl/platform/ConsoleSystemInitInfo.h>
|
||||
#include<hgl/LogInfo.h>
|
||||
#include<hgl/PlugIn.h>
|
||||
#include<hgl/filesystem/FileSystem.h>
|
||||
#include<wchar.h>
|
||||
#include<shlobj.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
bool GetTempPath(WideString &temp_path,unsigned long s)
|
||||
{
|
||||
HKEY hKey;
|
||||
DWORD type;
|
||||
|
||||
LONG result = RegOpenKeyExW(HKEY_CURRENT_USER,L"Environment",0,KEY_READ,&hKey);
|
||||
|
||||
if(result==ERROR_SUCCESS)
|
||||
{
|
||||
wchar_t temp[HGL_MAX_PATH];
|
||||
DWORD size=HGL_MAX_PATH;
|
||||
|
||||
result = RegQueryValueExW( hKey,L"TEMP", NULL, &type, (LPBYTE)temp, &size );
|
||||
|
||||
RegCloseKey(hKey);
|
||||
|
||||
if(result==ERROR_SUCCESS)
|
||||
{
|
||||
wchar_t path[HGL_MAX_PATH];
|
||||
|
||||
ExpandEnvironmentStringsW(temp,path,s);
|
||||
temp_path=path;
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
bool GetCMGDKPath(WideString &cmgdk_path)
|
||||
{
|
||||
HKEY hKey;
|
||||
DWORD type;
|
||||
|
||||
LONG result = RegOpenKeyExW(HKEY_CURRENT_USER,L"Environment",0,KEY_READ,&hKey);
|
||||
|
||||
if(result==ERROR_SUCCESS)
|
||||
{
|
||||
wchar_t path[HGL_MAX_PATH];
|
||||
DWORD size=HGL_MAX_PATH;
|
||||
|
||||
result = RegQueryValueExW( hKey,L"CMGDK", NULL, &type, (LPBYTE)path, &size );
|
||||
|
||||
RegCloseKey(hKey);
|
||||
|
||||
cmgdk_path=path;
|
||||
|
||||
return(result==ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
void GetOSPath(CMGDKPATH &cp)
|
||||
{
|
||||
wchar_t path[HGL_MAX_PATH];
|
||||
|
||||
#define GET_FOLDER(str,attrib) SHGetFolderPathW(nullptr,attrib,nullptr,0,path); \
|
||||
cp.str=path;
|
||||
|
||||
GET_FOLDER(os ,CSIDL_WINDOWS );
|
||||
GET_FOLDER(library ,CSIDL_SYSTEM );
|
||||
GET_FOLDER(osfont ,CSIDL_FONTS );
|
||||
|
||||
hgl::GetTempPath(cp.temp,HGL_MAX_PATH);
|
||||
|
||||
GET_FOLDER(common_data ,CSIDL_COMMON_APPDATA );
|
||||
GET_FOLDER(local_data ,CSIDL_LOCAL_APPDATA );
|
||||
|
||||
GET_FOLDER(mydata ,CSIDL_APPDATA );
|
||||
GET_FOLDER(myprogram ,CSIDL_STARTMENU );
|
||||
GET_FOLDER(mydesktop ,CSIDL_DESKTOPDIRECTORY );
|
||||
|
||||
GET_FOLDER(desktop ,CSIDL_COMMON_DESKTOPDIRECTORY );
|
||||
|
||||
#undef GET_FOLDER
|
||||
}
|
||||
|
||||
bool InitOSupport(ConsoleSystemInitInfo *sii)
|
||||
{
|
||||
if(sii->CheckDebugger&&IsDebuggerPresent())
|
||||
{
|
||||
LOG_ERROR(OS_TEXT("本程序不能运行在调试模式下!"));
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
}//namespace hgl
|
63
src/Win/Thread.cpp
Normal file
63
src/Win/Thread.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
#include<hgl/thread/Thread.h>
|
||||
#include<hgl/LogInfo.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
extern THREAD_FUNC ThreadFunc(Thread *tc);
|
||||
|
||||
/**
|
||||
* (线程外部调用)执行当前线程,线程优先级为tplevel
|
||||
* @param tplevel 线程优先级
|
||||
* @return 是否创建线程成功
|
||||
*/
|
||||
bool Thread::Start()
|
||||
{
|
||||
unsigned long threadid;
|
||||
|
||||
exit_lock.Lock();
|
||||
|
||||
tp=::CreateThread(0,0,(PTHREAD_START_ROUTINE)ThreadFunc,this,0,&threadid);
|
||||
|
||||
if(!tp)
|
||||
{
|
||||
exit_lock.Unlock();
|
||||
LOG_ERROR(OS_TEXT("Create Thread failed,Windows ErrorCode: ")+OSString((uint)GetLastError()));
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是当前线程
|
||||
*/
|
||||
bool Thread::IsCurThread()
|
||||
{
|
||||
return(tp==GetCurrentThread());
|
||||
}
|
||||
|
||||
void WaitThreadExit(thread_ptr tp,const double &time_out)
|
||||
{
|
||||
if(!tp)return;
|
||||
|
||||
WaitForSingleObject(tp,time_out>0?time_out*1000:INFINITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待多个线程中的一个完成
|
||||
* @param mt 线程
|
||||
* @param count 线程数量
|
||||
* @param time_out 等待的时间,如果为0表示等到线程运行结束为止。默认为0
|
||||
*/
|
||||
void WaitThread(Thread **mt,int count,double time_out)
|
||||
{
|
||||
void **obj=new void *[count];
|
||||
|
||||
for(int i=0;i<count;i++)
|
||||
obj[i]=mt[i]->tp;
|
||||
|
||||
WaitForMultipleObjects(count,obj,false,time_out>0?time_out*1000:INFINITE);
|
||||
|
||||
delete[] obj;
|
||||
}
|
||||
}//namespace hgl
|
55
src/Win/ThreadMutex.cpp
Normal file
55
src/Win/ThreadMutex.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
#include<hgl/thread/ThreadMutex.h>
|
||||
|
||||
#include<wchar.h>
|
||||
|
||||
#pragma warning(disable:4800) // BOOL -> bool 性能损失警告
|
||||
namespace hgl
|
||||
{
|
||||
ThreadMutex::ThreadMutex()
|
||||
{
|
||||
InitializeCriticalSection(&ptr);
|
||||
}
|
||||
|
||||
ThreadMutex::~ThreadMutex()
|
||||
{
|
||||
Unlock();
|
||||
|
||||
DeleteCriticalSection(&ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得控制权
|
||||
* 如果对象处于排斥状态,则等待
|
||||
*/
|
||||
void ThreadMutex::Lock()
|
||||
{
|
||||
EnterCriticalSection(&ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试取得控制权
|
||||
* @return 是否成功取得控制权
|
||||
*/
|
||||
bool ThreadMutex::TryLock()
|
||||
{
|
||||
return(TryEnterCriticalSection(&ptr));
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待并取得控制权
|
||||
* @param time 等待的最大时间,时间为0表示尝试
|
||||
* @return 是否取得控制权
|
||||
*/
|
||||
bool ThreadMutex::WaitLock(double time_out)
|
||||
{
|
||||
return(!WaitForSingleObject(&ptr,time_out*1000));
|
||||
}
|
||||
|
||||
/**
|
||||
* 放弃控制权
|
||||
*/
|
||||
void ThreadMutex::Unlock()
|
||||
{
|
||||
LeaveCriticalSection(&ptr);
|
||||
}
|
||||
}//namespace hgl
|
90
src/Win/Time.cpp
Normal file
90
src/Win/Time.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
#include<hgl/platform/Platform.h>
|
||||
#include<hgl/TypeFunc.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace
|
||||
{
|
||||
#define APR_DELTA_EPOCH_IN_USEC 11644473600000000 //转Windows时间到Unix时间的一个差值
|
||||
//Windows是1601.1.1
|
||||
//Unix是1970.1.1
|
||||
//tanks for APR
|
||||
|
||||
static inline void FileTimeToMicroTime(uint64 *result, FILETIME *input)
|
||||
{
|
||||
/* Convert FILETIME one 64 bit number so we can work with it. */
|
||||
*result = input->dwHighDateTime;
|
||||
*result = (*result) << 32;
|
||||
*result |= input->dwLowDateTime;
|
||||
*result /= 10; /* Convert from 100 nano-sec periods to micro-seconds. */
|
||||
*result -= APR_DELTA_EPOCH_IN_USEC; /* Convert from Windows epoch to Unix epoch */
|
||||
return;
|
||||
}
|
||||
}//namespace
|
||||
|
||||
long GetGMTOff()
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
FILETIME ft;
|
||||
uint64 local_time;
|
||||
uint64 utc_time;
|
||||
|
||||
GetLocalTime(&st);
|
||||
SystemTimeToFileTime(&st, &ft);
|
||||
FileTimeToMicroTime(&local_time, &ft);
|
||||
|
||||
GetSystemTime(&st);
|
||||
SystemTimeToFileTime(&st, &ft);
|
||||
FileTimeToMicroTime(&utc_time, &ft);
|
||||
|
||||
return(utc_time - local_time);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得当前时间
|
||||
* @return 当前时间(单位:百万分之一秒)
|
||||
*/
|
||||
uint64 GetMicroTime()
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
FILETIME ft;
|
||||
uint64 result;
|
||||
|
||||
GetLocalTime(&st);
|
||||
|
||||
SystemTimeToFileTime(&st, &ft);
|
||||
|
||||
FileTimeToMicroTime(&result, &ft);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得当前时间
|
||||
* @return 当前时间(单位:千分之一秒)
|
||||
*/
|
||||
uint64 GetTime()
|
||||
{
|
||||
return(GetMicroTime() / 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得当前时间(双精度)
|
||||
* @return 当前时间(单位:秒)
|
||||
*/
|
||||
double GetDoubleTime() ///<取得当前时间(双精度,单位秒)
|
||||
{
|
||||
return(double(GetMicroTime()) / HGL_MICRO_SEC_PER_SEC);
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待指定时间
|
||||
* @param time 时间(单位:秒)
|
||||
*/
|
||||
void WaitTime(double t)
|
||||
{
|
||||
if(t<=0)return;
|
||||
|
||||
::Sleep(DWORD(t*HGL_MILLI_SEC_PRE_SEC));
|
||||
}
|
||||
}//namespace hgl
|
328
src/Win/WinMessage.cpp
Normal file
328
src/Win/WinMessage.cpp
Normal file
@ -0,0 +1,328 @@
|
||||
#include"WinWindow.h"
|
||||
#include<hgl/platform/InputDevice.h>
|
||||
#include<Windows.h>
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include<hgl/LogInfo.h>
|
||||
#endif//_DEBUG
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
namespace
|
||||
{
|
||||
static KeyboardButton KeyConvert[256];
|
||||
static void (*WMProc[2048])(WinWindow *,uint32,uint32); //消息处理队列
|
||||
|
||||
uint32 GetMouseKeyFlags(uint32 wflags)
|
||||
{
|
||||
uint32 flag=0;
|
||||
|
||||
if(wflags&MK_LBUTTON)flag|=mbLeft;
|
||||
if(wflags&MK_RBUTTON)flag|=mbRight;
|
||||
if(wflags&MK_MBUTTON)flag|=mbMid;
|
||||
|
||||
if(wflags&MK_XBUTTON1)flag|=mbX1;
|
||||
if(wflags&MK_XBUTTON2)flag|=mbX2;
|
||||
|
||||
if(wflags&MK_SHIFT )flag|=mbShift;
|
||||
if(wflags&MK_CONTROL)flag|=mbCtrl;
|
||||
|
||||
return(flag);
|
||||
}
|
||||
|
||||
void InitKeyConvert()
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(KeyConvert,0,sizeof(KeyConvert));
|
||||
|
||||
KeyConvert[VK_ESCAPE ]=kbEsc;
|
||||
for(i=VK_F1;i<=VK_F12;i++)KeyConvert[i]=(KeyboardButton)(kbF1+i-VK_F1);
|
||||
|
||||
KeyConvert['`' ]=kbGrave;
|
||||
for(i='0';i<='9';i++)KeyConvert[i]=(KeyboardButton)(kb0+i-'0');
|
||||
KeyConvert['-' ]=kbMinus;
|
||||
KeyConvert['=' ]=kbEquals;
|
||||
KeyConvert['\\' ]=kbBackSlash;
|
||||
KeyConvert[VK_BACK ]=kbBackSpace;
|
||||
|
||||
KeyConvert[VK_TAB ]=kbTab;
|
||||
KeyConvert['Q' ]=kbQ;
|
||||
KeyConvert['W' ]=kbW;
|
||||
KeyConvert['E' ]=kbE;
|
||||
KeyConvert['R' ]=kbR;
|
||||
KeyConvert['T' ]=kbT;
|
||||
KeyConvert['Y' ]=kbY;
|
||||
KeyConvert['U' ]=kbU;
|
||||
KeyConvert['I' ]=kbI;
|
||||
KeyConvert['O' ]=kbO;
|
||||
KeyConvert['P' ]=kbP;
|
||||
KeyConvert['[' ]=kbLeftBracket;
|
||||
KeyConvert[']' ]=kbRightBracket;
|
||||
|
||||
KeyConvert[VK_CAPITAL ]=kbCapsLock;
|
||||
KeyConvert['A' ]=kbA;
|
||||
KeyConvert['S' ]=kbS;
|
||||
KeyConvert['D' ]=kbD;
|
||||
KeyConvert['F' ]=kbF;
|
||||
KeyConvert['G' ]=kbG;
|
||||
KeyConvert['H' ]=kbH;
|
||||
KeyConvert['J' ]=kbJ;
|
||||
KeyConvert['K' ]=kbK;
|
||||
KeyConvert['L' ]=kbL;
|
||||
KeyConvert[';' ]=kbSemicolon;
|
||||
KeyConvert['\'' ]=kbApostrophe;
|
||||
KeyConvert[VK_RETURN ]=kbEnter;
|
||||
|
||||
KeyConvert[VK_LSHIFT ]=kbLeftShift;
|
||||
KeyConvert['Z' ]=kbZ;
|
||||
KeyConvert['X' ]=kbX;
|
||||
KeyConvert['C' ]=kbC;
|
||||
KeyConvert['V' ]=kbV;
|
||||
KeyConvert['B' ]=kbB;
|
||||
KeyConvert['N' ]=kbN;
|
||||
KeyConvert['M' ]=kbM;
|
||||
KeyConvert[',' ]=kbComma;
|
||||
KeyConvert['.' ]=kbPeriod;
|
||||
KeyConvert['/' ]=kbSlash;
|
||||
KeyConvert[VK_RSHIFT ]=kbRightShift;
|
||||
|
||||
KeyConvert[VK_LCONTROL ]=kbLeftCtrl;
|
||||
KeyConvert[VK_LWIN ]=kbLeftOS;
|
||||
KeyConvert[VK_LMENU ]=kbLeftAlt;
|
||||
KeyConvert[VK_SPACE ]=kbSpace;
|
||||
KeyConvert[VK_RMENU ]=kbRightAlt;
|
||||
KeyConvert[VK_RWIN ]=kbRightOS;
|
||||
KeyConvert[VK_RCONTROL ]=kbRightCtrl;
|
||||
|
||||
KeyConvert[VK_PAUSE ]=kbPause;
|
||||
// KeyConvert[VK_CLEAR ]=kbClear;
|
||||
|
||||
KeyConvert[VK_NUMPAD0 ]=kbNum0;
|
||||
KeyConvert[VK_NUMPAD1 ]=kbNum1;
|
||||
KeyConvert[VK_NUMPAD2 ]=kbNum2;
|
||||
KeyConvert[VK_NUMPAD3 ]=kbNum3;
|
||||
KeyConvert[VK_NUMPAD4 ]=kbNum4;
|
||||
KeyConvert[VK_NUMPAD5 ]=kbNum5;
|
||||
KeyConvert[VK_NUMPAD6 ]=kbNum6;
|
||||
KeyConvert[VK_NUMPAD7 ]=kbNum7;
|
||||
KeyConvert[VK_NUMPAD8 ]=kbNum8;
|
||||
KeyConvert[VK_NUMPAD9 ]=kbNum9;
|
||||
|
||||
KeyConvert[VK_DECIMAL ]=kbNumDecimal;
|
||||
KeyConvert[VK_DIVIDE ]=kbNumDivide;
|
||||
KeyConvert[VK_MULTIPLY ]=kbNumMultiply;
|
||||
KeyConvert[VK_SUBTRACT ]=kbNumSubtract;
|
||||
KeyConvert[VK_ADD ]=kbNumAdd;
|
||||
|
||||
KeyConvert[VK_UP ]=kbUp;
|
||||
KeyConvert[VK_DOWN ]=kbDown;
|
||||
KeyConvert[VK_LEFT ]=kbLeft;
|
||||
KeyConvert[VK_RIGHT ]=kbRight;
|
||||
|
||||
KeyConvert[VK_INSERT ]=kbInsert;
|
||||
KeyConvert[VK_DELETE ]=kbDelete;
|
||||
KeyConvert[VK_HOME ]=kbHome;
|
||||
KeyConvert[VK_END ]=kbEnd;
|
||||
KeyConvert[VK_PRIOR ]=kbPageUp;
|
||||
KeyConvert[VK_NEXT ]=kbPageDown;
|
||||
|
||||
KeyConvert[VK_NUMLOCK ]=kbNumLock;
|
||||
KeyConvert[VK_SCROLL ]=kbScrollLock;
|
||||
|
||||
//KeyConvert[VK_SHIFT ]=kbLeftShift;
|
||||
//KeyConvert[VK_CONTROL ]=kbLeftCtrl;
|
||||
//KeyConvert[VK_MENU ]=kbLeftAlt;
|
||||
|
||||
KeyConvert[VK_OEM_1 ]=kbSemicolon;
|
||||
KeyConvert[VK_OEM_PLUS ]=kbEquals;
|
||||
KeyConvert[VK_OEM_COMMA ]=kbComma;
|
||||
KeyConvert[VK_OEM_MINUS ]=kbMinus;
|
||||
KeyConvert[VK_OEM_PERIOD]=kbPeriod;
|
||||
KeyConvert[VK_OEM_2 ]=kbSlash;
|
||||
KeyConvert[VK_OEM_3 ]=kbGrave;
|
||||
KeyConvert[VK_OEM_4 ]=kbLeftBracket;
|
||||
KeyConvert[VK_OEM_5 ]=kbBackSlash;
|
||||
KeyConvert[VK_OEM_6 ]=kbRightBracket;
|
||||
KeyConvert[VK_OEM_7 ]=kbApostrophe;
|
||||
}
|
||||
|
||||
KeyboardButton ConvertOSKey(uint key)
|
||||
{
|
||||
if(key>=256)return(kbBeginRange);
|
||||
if(KeyConvert[key]==0)return(kbBeginRange);
|
||||
|
||||
if(key==VK_SHIFT)
|
||||
{
|
||||
if((GetAsyncKeyState(VK_LSHIFT)>>15)&1)
|
||||
return kbLeftShift;
|
||||
else
|
||||
return kbRightShift;
|
||||
}
|
||||
else
|
||||
if(key==VK_CONTROL)
|
||||
{
|
||||
if((GetAsyncKeyState(VK_LCONTROL)>>15)&1)
|
||||
return kbLeftCtrl;
|
||||
else
|
||||
return kbRightCtrl;
|
||||
}
|
||||
if(key==VK_MENU)
|
||||
{
|
||||
if((GetAsyncKeyState(VK_LMENU)>>15)&1)
|
||||
return kbLeftAlt;
|
||||
else
|
||||
return kbRightAlt;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
if(KeyConvert[key]==0)
|
||||
{
|
||||
wchar_t name[64];
|
||||
|
||||
::GetKeyNameTextW(key,name,64);
|
||||
|
||||
LOG_INFO(WideString(L"Unknow Key: " )+WideString(key)
|
||||
+WideString(L" ,name: " )+WideString(name));
|
||||
}
|
||||
#endif _DEBUG
|
||||
|
||||
return KeyConvert[key];
|
||||
}
|
||||
|
||||
void WMProcDestroy(WinWindow *win,uint32,uint32)
|
||||
{
|
||||
win->ProcClose();
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
|
||||
#define WMEF_MOUSE(button,action) void WMProcMouse##button##action(WinWindow *win,uint32 wParam,uint32 lParam) \
|
||||
{ \
|
||||
const int x=LOWORD(lParam); \
|
||||
const int y=HIWORD(lParam); \
|
||||
\
|
||||
win->ProcMouseMove(x,y); \
|
||||
win->ProcMouse##action(x,y,mb##button|GetMouseKeyFlags(wParam)); \
|
||||
}
|
||||
|
||||
WMEF_MOUSE(Left,Down);
|
||||
WMEF_MOUSE(Left,Up);
|
||||
WMEF_MOUSE(Left,DblClick);
|
||||
|
||||
WMEF_MOUSE(Mid,Down);
|
||||
WMEF_MOUSE(Mid,Up);
|
||||
WMEF_MOUSE(Mid,DblClick);
|
||||
|
||||
WMEF_MOUSE(Right,Down);
|
||||
WMEF_MOUSE(Right,Up);
|
||||
WMEF_MOUSE(Right,DblClick);
|
||||
|
||||
void WMProcMouseMove(WinWindow *win,uint32 wParam,uint32 lParam)
|
||||
{
|
||||
win->ProcMouseMove(LOWORD(lParam),HIWORD(lParam));
|
||||
}
|
||||
#undef WMEF_MOUSE
|
||||
|
||||
#define WMEF2(name) void name(WinWindow *win,uint32 wParam,uint32 lParam)
|
||||
WMEF2(WMProcMouseWheel)
|
||||
{
|
||||
int zDelta=GET_WHEEL_DELTA_WPARAM(wParam);
|
||||
uint key=ConvertOSKey(GET_KEYSTATE_WPARAM(wParam));
|
||||
|
||||
win->ProcMouseWheel(zDelta,0,key);
|
||||
}
|
||||
|
||||
WMEF2(WMProcMouseHWheel)
|
||||
{
|
||||
int zDelta=GET_WHEEL_DELTA_WPARAM(wParam);
|
||||
uint key=ConvertOSKey(GET_KEYSTATE_WPARAM(wParam));
|
||||
|
||||
win->ProcMouseWheel(0,zDelta,key);
|
||||
}
|
||||
|
||||
WMEF2(WMProcSize)
|
||||
{
|
||||
win->ProcResize(LOWORD(lParam),HIWORD(lParam));
|
||||
}
|
||||
#undef WMEF2
|
||||
|
||||
#define WMEF1(name) void name(WinWindow *win,uint32 wParam,uint32)
|
||||
WMEF1(WMProcKeyDown)
|
||||
{
|
||||
win->ProcKeyDown(ConvertOSKey(wParam));
|
||||
}
|
||||
|
||||
WMEF1(WMProcKeyUp)
|
||||
{
|
||||
win->ProcKeyUp(ConvertOSKey(wParam));
|
||||
}
|
||||
|
||||
WMEF1(WMProcChar)
|
||||
{
|
||||
win->ProcChar((wchar_t)wParam);
|
||||
}
|
||||
|
||||
WMEF1(WMProcActive)
|
||||
{
|
||||
//if(JoyPlugIn)
|
||||
// JoyInterface.SetInputActive(wParam);
|
||||
|
||||
win->ProcActive(wParam);
|
||||
}
|
||||
#undef WMEF1
|
||||
}//namespace
|
||||
|
||||
void InitMessageProc()
|
||||
{
|
||||
memset(WMProc,0,sizeof(WMProc));
|
||||
InitKeyConvert();
|
||||
|
||||
//if(joy)
|
||||
// LoadJoystick(win->hInstance,win->hWnd);
|
||||
|
||||
#define WM_MAP(wm,func) WMProc[wm]=func;
|
||||
|
||||
WM_MAP(WM_CLOSE ,WMProcDestroy);
|
||||
WM_MAP(WM_LBUTTONDOWN ,WMProcMouseLeftDown);
|
||||
WM_MAP(WM_LBUTTONUP ,WMProcMouseLeftUp);
|
||||
WM_MAP(WM_LBUTTONDBLCLK ,WMProcMouseLeftDblClick);
|
||||
WM_MAP(WM_MBUTTONDOWN ,WMProcMouseMidDown);
|
||||
WM_MAP(WM_MBUTTONUP ,WMProcMouseMidUp);
|
||||
WM_MAP(WM_MBUTTONDBLCLK ,WMProcMouseMidDblClick);
|
||||
WM_MAP(WM_RBUTTONDOWN ,WMProcMouseRightDown);
|
||||
WM_MAP(WM_RBUTTONUP ,WMProcMouseRightUp);
|
||||
WM_MAP(WM_RBUTTONDBLCLK ,WMProcMouseRightDblClick);
|
||||
WM_MAP(WM_MOUSEWHEEL ,WMProcMouseWheel);
|
||||
WM_MAP(WM_MOUSEHWHEEL ,WMProcMouseHWheel);
|
||||
WM_MAP(WM_MOUSEMOVE ,WMProcMouseMove);
|
||||
WM_MAP(WM_KEYDOWN ,WMProcKeyDown);
|
||||
WM_MAP(WM_KEYUP ,WMProcKeyUp);
|
||||
WM_MAP(WM_SYSKEYDOWN ,WMProcKeyDown);
|
||||
WM_MAP(WM_SYSKEYUP ,WMProcKeyUp);
|
||||
WM_MAP(WM_CHAR ,WMProcChar);
|
||||
WM_MAP(WM_SYSCHAR ,WMProcChar);
|
||||
WM_MAP(WM_ACTIVATE ,WMProcActive);
|
||||
WM_MAP(WM_SIZE ,WMProcSize);
|
||||
|
||||
#undef WM_MAP
|
||||
}
|
||||
|
||||
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if(uMsg<2048)
|
||||
if(WMProc[uMsg])
|
||||
{
|
||||
WinWindow *win=(WinWindow *)GetWindowLongPtrW(hWnd,GWLP_USERDATA);
|
||||
|
||||
if(win)
|
||||
WMProc[uMsg](win,wParam,lParam);
|
||||
}
|
||||
|
||||
return (DefWindowProcW(hWnd, uMsg, wParam, lParam));
|
||||
}
|
||||
|
||||
void InitNativeWindowSystem()
|
||||
{
|
||||
InitMessageProc();
|
||||
}
|
||||
}//namespace hgl
|
30
src/Win/WinVulkan.cpp
Normal file
30
src/Win/WinVulkan.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
#include<hgl/platform/Vulkan.h>
|
||||
#include"WinWindow.h"
|
||||
#include<vulkan/vulkan_win32.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
VkSurfaceKHR CreateVulkanSurface(VkInstance vk_inst,Window *w)
|
||||
{
|
||||
if(vk_inst==VK_NULL_HANDLE)return(VK_NULL_HANDLE);
|
||||
if(!w)return(VK_NULL_HANDLE);
|
||||
|
||||
WinWindow *win=(WinWindow *)w;
|
||||
|
||||
VkWin32SurfaceCreateInfoKHR createInfo;
|
||||
createInfo.sType =VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
|
||||
createInfo.pNext =nullptr;
|
||||
createInfo.flags =0;
|
||||
createInfo.hinstance=win->GetInstance();
|
||||
createInfo.hwnd =win->GetWnd();
|
||||
|
||||
VkSurfaceKHR surface;
|
||||
|
||||
VkResult res=vkCreateWin32SurfaceKHR(vk_inst,&createInfo,nullptr,&surface);
|
||||
|
||||
if(res!=VK_SUCCESS)
|
||||
return(VK_NULL_HANDLE);
|
||||
|
||||
return(surface);
|
||||
}
|
||||
}//namespace hgl
|
213
src/Win/WinWindow.cpp
Normal file
213
src/Win/WinWindow.cpp
Normal file
@ -0,0 +1,213 @@
|
||||
#include"WinWindow.h"
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr wchar_t WIN_CLASS_NAME[] = L"CMGameEngine/ULRE Window Class";
|
||||
|
||||
bool RegistryWinClass(HINSTANCE hInstance)
|
||||
{
|
||||
WNDCLASSEXW win_class;
|
||||
|
||||
hgl_zero(win_class);
|
||||
|
||||
win_class.cbSize = sizeof(WNDCLASSEXW);
|
||||
win_class.style = CS_HREDRAW | CS_VREDRAW;
|
||||
win_class.lpfnWndProc = WindowProc;
|
||||
win_class.cbClsExtra = 0;
|
||||
win_class.cbWndExtra = 0;
|
||||
win_class.hInstance = hInstance;
|
||||
win_class.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
|
||||
win_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||
win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
|
||||
win_class.lpszMenuName = nullptr;
|
||||
win_class.lpszClassName = WIN_CLASS_NAME;
|
||||
win_class.hIconSm = LoadIcon(nullptr, IDI_WINLOGO);
|
||||
|
||||
return RegisterClassExW(&win_class);
|
||||
}
|
||||
}//namespace
|
||||
|
||||
bool WinWindow::Create()
|
||||
{
|
||||
constexpr DWORD win_style = WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_SYSMENU ;
|
||||
|
||||
int win_left, win_top;
|
||||
int win_width, win_height;
|
||||
|
||||
{
|
||||
RECT win_rect;
|
||||
|
||||
win_rect.left = 0;
|
||||
win_rect.right = width;
|
||||
win_rect.top = 0;
|
||||
win_rect.bottom = height;
|
||||
|
||||
AdjustWindowRectEx(&win_rect, win_style, false, 0); //计算窗口坐标
|
||||
|
||||
win_width = win_rect.right - win_rect.left;
|
||||
win_height = win_rect.bottom - win_rect.top;
|
||||
}
|
||||
|
||||
if (width && height)
|
||||
{
|
||||
win_left = (GetSystemMetrics(SM_CXSCREEN) - win_width) / 2;
|
||||
win_top = (GetSystemMetrics(SM_CYSCREEN) - win_height) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
win_left = CW_USEDEFAULT;
|
||||
win_top = CW_USEDEFAULT;
|
||||
}
|
||||
|
||||
win_hwnd = CreateWindowExW(0,
|
||||
WIN_CLASS_NAME, // class name
|
||||
win_name.c_str(), // app name
|
||||
win_style, // window style
|
||||
win_left,win_top, // x/y coords
|
||||
win_width, // width
|
||||
win_height, // height
|
||||
nullptr, // handle to parent
|
||||
nullptr, // handle to menu
|
||||
hInstance, // hInstance
|
||||
nullptr); // no extra parameters
|
||||
|
||||
if (!win_hwnd)
|
||||
{
|
||||
UnregisterClassW(WIN_CLASS_NAME, hInstance);
|
||||
return(false);
|
||||
}
|
||||
|
||||
win_dc = GetDC(win_hwnd);
|
||||
SetWindowLongPtrW(win_hwnd, GWLP_USERDATA, (LONG_PTR)this);
|
||||
return(true);
|
||||
}
|
||||
|
||||
WinWindow::~WinWindow()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
bool WinWindow::Create(uint w, uint h)
|
||||
{
|
||||
full_screen=false;
|
||||
width = w;
|
||||
height = h;
|
||||
|
||||
hInstance = GetModuleHandleW(nullptr);
|
||||
|
||||
if (!RegistryWinClass(hInstance))
|
||||
return(false);
|
||||
|
||||
if(!Create())
|
||||
{
|
||||
is_close=true;
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
is_close=false;
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
|
||||
bool WinWindow::Create(uint, uint, uint)
|
||||
{
|
||||
full_screen=true;
|
||||
return(false);
|
||||
}
|
||||
|
||||
void WinWindow::Close()
|
||||
{
|
||||
if(win_hwnd)
|
||||
{
|
||||
if(win_dc)
|
||||
{
|
||||
ReleaseDC(win_hwnd,win_dc);
|
||||
win_dc = nullptr;
|
||||
}
|
||||
|
||||
DestroyWindow(win_hwnd);
|
||||
|
||||
win_hwnd = nullptr;
|
||||
}
|
||||
|
||||
UnregisterClassW(WIN_CLASS_NAME,hInstance);
|
||||
|
||||
is_close = true;
|
||||
}
|
||||
|
||||
void WinWindow::SetCaption(const OSString &caption)
|
||||
{
|
||||
win_name=caption;
|
||||
SetWindowTextW(win_hwnd,caption.c_str());
|
||||
}
|
||||
|
||||
void WinWindow::Show()
|
||||
{
|
||||
ShowWindow(win_hwnd, SW_SHOW);
|
||||
SetForegroundWindow(win_hwnd);
|
||||
SetFocus(win_hwnd);
|
||||
|
||||
UpdateWindow(win_hwnd);
|
||||
}
|
||||
|
||||
void WinWindow::Hide()
|
||||
{
|
||||
ShowWindow(win_hwnd, SW_HIDE);
|
||||
UpdateWindow(win_hwnd);
|
||||
}
|
||||
|
||||
void WinWindow::ToMinWindow()
|
||||
{
|
||||
if(!full_screen)
|
||||
ShowWindow(win_hwnd,SW_MINIMIZE);
|
||||
}
|
||||
|
||||
void WinWindow::ToMaxWindow()
|
||||
{
|
||||
if(!full_screen)
|
||||
ShowWindow(win_hwnd,SW_MAXIMIZE);
|
||||
}
|
||||
|
||||
void WinWindow::SetSystemCursor(bool visible)
|
||||
{
|
||||
::ShowCursor(visible);
|
||||
}
|
||||
|
||||
bool WinWindow::MessageProc()
|
||||
{
|
||||
if(PeekMessage(&win_msg,NULL,0,0,PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&win_msg);
|
||||
DispatchMessage(&win_msg);
|
||||
|
||||
if(win_msg.message==WM_QUIT)
|
||||
ProcClose();
|
||||
|
||||
return(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
//if(JoyPlugIn)
|
||||
//{
|
||||
// JoyInterface.Update();
|
||||
//}
|
||||
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool WinWindow::WaitMessage()
|
||||
{
|
||||
return ::WaitMessage();
|
||||
}
|
||||
|
||||
Window *CreateRenderWindow(const WideString& win_name)
|
||||
{
|
||||
return(new WinWindow(win_name));
|
||||
}
|
||||
}//namespace hgl
|
47
src/Win/WinWindow.h
Normal file
47
src/Win/WinWindow.h
Normal file
@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
#include<hgl/platform/Window.h>
|
||||
#include<Windows.h>
|
||||
namespace hgl
|
||||
{
|
||||
/**
|
||||
* Windows平台窗口实现
|
||||
*/
|
||||
class WinWindow:public Window
|
||||
{
|
||||
HINSTANCE hInstance = nullptr;
|
||||
HWND win_hwnd = nullptr;
|
||||
HDC win_dc = nullptr;
|
||||
|
||||
MSG win_msg;
|
||||
|
||||
protected:
|
||||
|
||||
bool Create();
|
||||
|
||||
public:
|
||||
|
||||
using Window::Window;
|
||||
~WinWindow();
|
||||
|
||||
bool Create(uint w, uint h) override;
|
||||
bool Create(uint, uint, uint) override;
|
||||
void Close() override;
|
||||
|
||||
HINSTANCE GetInstance(){return hInstance;}
|
||||
HWND GetWnd(){return win_hwnd;}
|
||||
HDC GetHDC(){return win_dc;}
|
||||
|
||||
void SetCaption(const OSString &caption) override;
|
||||
|
||||
void Show() override;
|
||||
void Hide() override;
|
||||
|
||||
void ToMinWindow() override;
|
||||
void ToMaxWindow() override;
|
||||
|
||||
void SetSystemCursor(bool visible) override;
|
||||
|
||||
bool MessageProc() override;
|
||||
bool WaitMessage() override;
|
||||
};//class WinWindow :public Window
|
||||
}//namespace win
|
66
src/Window.cpp
Normal file
66
src/Window.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
#include<hgl/platform/Window.h>
|
||||
|
||||
namespace hgl
|
||||
{
|
||||
void Window::ProcKeyDown(KeyboardButton kb)
|
||||
{
|
||||
if(key_push[kb])
|
||||
ProcKeyPress(kb);
|
||||
else
|
||||
key_push[kb]=true;
|
||||
|
||||
SafeCallEvent(OnKeyDown,(kb));
|
||||
}
|
||||
|
||||
void Window::ProcKeyUp(KeyboardButton kb)
|
||||
{
|
||||
key_push[kb]=false;
|
||||
|
||||
SafeCallEvent(OnKeyUp,(kb));
|
||||
}
|
||||
|
||||
void Window::ProcResize(uint w,uint h)
|
||||
{
|
||||
if(w==width&&height==h)
|
||||
return;
|
||||
|
||||
width=w;
|
||||
height=h;
|
||||
|
||||
if(w==0||h==0)
|
||||
{
|
||||
is_min=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
is_min=false;
|
||||
}
|
||||
|
||||
SafeCallEvent(OnResize,(w,h));
|
||||
}
|
||||
|
||||
void Window::ProcActive(bool a)
|
||||
{
|
||||
active=a;
|
||||
SafeCallEvent(OnActive,(a));
|
||||
}
|
||||
|
||||
void Window::ProcClose()
|
||||
{
|
||||
is_close=true;
|
||||
SafeCallEvent(OnClose,());
|
||||
}
|
||||
|
||||
bool Window::Update()
|
||||
{
|
||||
while(MessageProc());
|
||||
|
||||
if(is_close)
|
||||
return(false);
|
||||
|
||||
if(!active||is_min)
|
||||
this->WaitMessage();
|
||||
|
||||
return(true);
|
||||
}
|
||||
}//namespace hgl
|
Loading…
x
Reference in New Issue
Block a user