diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..9b0ae79 --- /dev/null +++ b/CMakeLists.txt @@ -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}) \ No newline at end of file diff --git a/inc/hgl/platform/InputDevice.h b/inc/hgl/platform/InputDevice.h new file mode 100644 index 0000000..382d256 --- /dev/null +++ b/inc/hgl/platform/InputDevice.h @@ -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, /// + +namespace hgl +{ + class Window; + + VkSurfaceKHR CreateVulkanSurface(VkInstance,Window *); +}//namespace hgl +#endif//HGL_PLATFORM_VULKAN_INCLUDE diff --git a/inc/hgl/platform/Window.h b/inc/hgl/platform/Window.h new file mode 100644 index 0000000..adcc7cd --- /dev/null +++ b/inc/hgl/platform/Window.h @@ -0,0 +1,119 @@ +#ifndef HGL_GRAPH_WINDOW_INCLUDE +#define HGL_GRAPH_WINDOW_INCLUDE + +#include +#include + +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 diff --git a/path_config.cmake b/path_config.cmake new file mode 100644 index 0000000..4c0108a --- /dev/null +++ b/path_config.cmake @@ -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() \ No newline at end of file diff --git a/src/Android/AndroidMain.cpp b/src/Android/AndroidMain.cpp new file mode 100644 index 0000000..3b53b6a --- /dev/null +++ b/src/Android/AndroidMain.cpp @@ -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;i0) + { + 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); + } + } +} diff --git a/src/Android/AndroidVulkan.cpp b/src/Android/AndroidVulkan.cpp new file mode 100644 index 0000000..9445716 --- /dev/null +++ b/src/Android/AndroidVulkan.cpp @@ -0,0 +1,29 @@ +#include"AndroidWindow.h" +#include + +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 diff --git a/src/Android/AssetManage.cpp b/src/Android/AssetManage.cpp new file mode 100644 index 0000000..bdca56a --- /dev/null +++ b/src/Android/AssetManage.cpp @@ -0,0 +1,109 @@ +#include +#include +#include +#include + +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(left0) + 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 diff --git a/src/Android/JNISupport.cpp b/src/Android/JNISupport.cpp new file mode 100644 index 0000000..1552be8 --- /dev/null +++ b/src/Android/JNISupport.cpp @@ -0,0 +1,25 @@ +#include +#include + +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 diff --git a/src/Android/LogConsole.cpp b/src/Android/LogConsole.cpp new file mode 100644 index 0000000..7b282c3 --- /dev/null +++ b/src/Android/LogConsole.cpp @@ -0,0 +1,146 @@ +#include +#include +#include +#include +#include + +#ifdef LOG_INFO_TIME +#include +#endif//LOG_INFO_TIME + +#include + +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 +#include + +namespace hgl +{ + namespace logger + { + void SetLocalAppdataPath(const char *fn); + }//namespace logger + + void InitAndroidSupport(struct ANativeActivity *native_activity) + { + logger::SetLocalAppdataPath(native_activity->internalDataPath); + } +}//namespace hgl diff --git a/src/Android/ProgramPath.cpp b/src/Android/ProgramPath.cpp new file mode 100644 index 0000000..d87a548 --- /dev/null +++ b/src/Android/ProgramPath.cpp @@ -0,0 +1,75 @@ +#include +#include +#include +#include + +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 + + diff --git a/src/Apple/ProgramPath.mm b/src/Apple/ProgramPath.mm new file mode 100644 index 0000000..ae6bfec --- /dev/null +++ b/src/Apple/ProgramPath.mm @@ -0,0 +1,42 @@ +#include +#import + +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 + diff --git a/src/Apple/Semaphore.cpp b/src/Apple/Semaphore.cpp new file mode 100644 index 0000000..7e0af7c --- /dev/null +++ b/src/Apple/Semaphore.cpp @@ -0,0 +1,78 @@ +#include +#include +#include +#include + +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 + +/** + * 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 +#include +namespace hgl +{ + template + 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(dst,endian::GetCharSet(),src,src_size,cs.charset); + } + + int utf16_to(const CharSet &cs,char **dst,const u16char *src,const int src_size) + { + return CharSetConv(dst,cs.charset,src,src_size,endian::GetCharSet()); + } + + int to_utf8(const CharSet &cs,char **dst,const char *src,const int src_size) + { + return CharSetConv(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(dst,cs.charset,src,src_size,utf8_charset); + } +}//namespace hgl diff --git a/src/UNIX/CondVar.cpp b/src/UNIX/CondVar.cpp new file mode 100644 index 0000000..395133c --- /dev/null +++ b/src/UNIX/CondVar.cpp @@ -0,0 +1,47 @@ +#include +#include +#include + +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 diff --git a/src/UNIX/DateTime.cpp b/src/UNIX/DateTime.cpp new file mode 100644 index 0000000..ef09d93 --- /dev/null +++ b/src/UNIX/DateTime.cpp @@ -0,0 +1,125 @@ +#include +#include + +#include +#include + +#include + +#include +#include + +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 diff --git a/src/UNIX/EnumFile.cpp b/src/UNIX/EnumFile.cpp new file mode 100644 index 0000000..67c6b5c --- /dev/null +++ b/src/UNIX/EnumFile.cpp @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +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 diff --git a/src/UNIX/Exit.cpp b/src/UNIX/Exit.cpp new file mode 100644 index 0000000..caa4a22 --- /dev/null +++ b/src/UNIX/Exit.cpp @@ -0,0 +1,24 @@ +#include +#include + +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 diff --git a/src/UNIX/ExternalModule.cpp b/src/UNIX/ExternalModule.cpp new file mode 100644 index 0000000..bf1ccc4 --- /dev/null +++ b/src/UNIX/ExternalModule.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include + +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 diff --git a/src/UNIX/Fifo.cpp b/src/UNIX/Fifo.cpp new file mode 100644 index 0000000..5ab161d --- /dev/null +++ b/src/UNIX/Fifo.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +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 diff --git a/src/UNIX/File.cpp b/src/UNIX/File.cpp new file mode 100644 index 0000000..78b0910 --- /dev/null +++ b/src/UNIX/File.cpp @@ -0,0 +1,220 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +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 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()); + } + + /** + * 取得当前所在目录
+ */ + 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 + + diff --git a/src/UNIX/FileAccess.cpp b/src/UNIX/FileAccess.cpp new file mode 100644 index 0000000..f695222 --- /dev/null +++ b/src/UNIX/FileAccess.cpp @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include + +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 diff --git a/src/UNIX/LogConsole.cpp b/src/UNIX/LogConsole.cpp new file mode 100644 index 0000000..3946652 --- /dev/null +++ b/src/UNIX/LogConsole.cpp @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include + +#ifdef LOG_INFO_TIME +#include +#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 +#include + +namespace hgl +{ + bool CreatePipe(pipe_pair &pp) + { + if(pipe(pp)) // return 0 表示成功 + return(false); + + return true; + } +}//namespace hgl diff --git a/src/UNIX/ProcMutex.cpp b/src/UNIX/ProcMutex.cpp new file mode 100644 index 0000000..bd05b7c --- /dev/null +++ b/src/UNIX/ProcMutex.cpp @@ -0,0 +1,62 @@ +#include +#include +#include +#include + +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 diff --git a/src/UNIX/Process.cpp b/src/UNIX/Process.cpp new file mode 100644 index 0000000..5cbeae7 --- /dev/null +++ b/src/UNIX/Process.cpp @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include + +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 +#include +#include +#include + +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 + diff --git a/src/UNIX/RWLock.cpp b/src/UNIX/RWLock.cpp new file mode 100644 index 0000000..26707ff --- /dev/null +++ b/src/UNIX/RWLock.cpp @@ -0,0 +1,51 @@ +#include +#include + +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 diff --git a/src/UNIX/Semaphore.cpp b/src/UNIX/Semaphore.cpp new file mode 100644 index 0000000..ea62c15 --- /dev/null +++ b/src/UNIX/Semaphore.cpp @@ -0,0 +1,87 @@ +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include + +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;irl.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 diff --git a/src/UNIX/Thread.cpp b/src/UNIX/Thread.cpp new file mode 100644 index 0000000..3bdef9a --- /dev/null +++ b/src/UNIX/Thread.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include + +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 diff --git a/src/UNIX/ThreadMutex.cpp b/src/UNIX/ThreadMutex.cpp new file mode 100644 index 0000000..11e6eff --- /dev/null +++ b/src/UNIX/ThreadMutex.cpp @@ -0,0 +1,67 @@ +#include +#include +#include +#include + +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 diff --git a/src/UNIX/Time.cpp b/src/UNIX/Time.cpp new file mode 100644 index 0000000..7516290 --- /dev/null +++ b/src/UNIX/Time.cpp @@ -0,0 +1,102 @@ +#include +#include + +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 diff --git a/src/UNIX/XCBVulkan.cpp b/src/UNIX/XCBVulkan.cpp new file mode 100644 index 0000000..fe8913a --- /dev/null +++ b/src/UNIX/XCBVulkan.cpp @@ -0,0 +1,30 @@ +#include +#include"XCBWindow.h" +#include + +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 diff --git a/src/UNIX/XCBWindow.cpp b/src/UNIX/XCBWindow.cpp new file mode 100644 index 0000000..f1209b5 --- /dev/null +++ b/src/UNIX/XCBWindow.cpp @@ -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 diff --git a/src/UNIX/XCBWindow.h b/src/UNIX/XCBWindow.h new file mode 100644 index 0000000..6df4f21 --- /dev/null +++ b/src/UNIX/XCBWindow.h @@ -0,0 +1,39 @@ +#include +#include +#include +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 + diff --git a/src/Win/Clipboard.cpp b/src/Win/Clipboard.cpp new file mode 100644 index 0000000..67820c6 --- /dev/null +++ b/src/Win/Clipboard.cpp @@ -0,0 +1,43 @@ +#include +#include + +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 diff --git a/src/Win/CodePage.cpp b/src/Win/CodePage.cpp new file mode 100644 index 0000000..2c3f85d --- /dev/null +++ b/src/Win/CodePage.cpp @@ -0,0 +1,61 @@ +#include + +#include + +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 + + diff --git a/src/Win/CondVar.cpp b/src/Win/CondVar.cpp new file mode 100644 index 0000000..49f2f43 --- /dev/null +++ b/src/Win/CondVar.cpp @@ -0,0 +1,38 @@ +#include +#include +#include + +#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 diff --git a/src/Win/DateTime.cpp b/src/Win/DateTime.cpp new file mode 100644 index 0000000..eba071d --- /dev/null +++ b/src/Win/DateTime.cpp @@ -0,0 +1,154 @@ +#include +#include + +#include +#include + +#include + +#include + +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 + diff --git a/src/Win/Desktop.cpp b/src/Win/Desktop.cpp new file mode 100644 index 0000000..f33a665 --- /dev/null +++ b/src/Win/Desktop.cpp @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include + +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 diff --git a/src/Win/EnumFile.cpp b/src/Win/EnumFile.cpp new file mode 100644 index 0000000..fa3018a --- /dev/null +++ b/src/Win/EnumFile.cpp @@ -0,0 +1,131 @@ +#include +#include + +#include +#include + +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 diff --git a/src/Win/EnumVolume.cpp b/src/Win/EnumVolume.cpp new file mode 100644 index 0000000..173e9d2 --- /dev/null +++ b/src/Win/EnumVolume.cpp @@ -0,0 +1,89 @@ +#include +#include +#include +#include + +namespace hgl +{ + namespace filesystem + { + int EnumVolume(List &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 diff --git a/src/Win/ExternalModule.cpp b/src/Win/ExternalModule.cpp new file mode 100644 index 0000000..80c9ed5 --- /dev/null +++ b/src/Win/ExternalModule.cpp @@ -0,0 +1,54 @@ +#include +#include +#include + +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 + diff --git a/src/Win/Fifo.cpp b/src/Win/Fifo.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/Win/File.cpp b/src/Win/File.cpp new file mode 100644 index 0000000..46cb1dc --- /dev/null +++ b/src/Win/File.cpp @@ -0,0 +1,217 @@ +#include +#include +#include +#include + +#include + +#include +#include + +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)); + } + + /** + * 取得当前所在目录
+ */ + 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 diff --git a/src/Win/FileAccess.cpp b/src/Win/FileAccess.cpp new file mode 100644 index 0000000..be8bcda --- /dev/null +++ b/src/Win/FileAccess.cpp @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include + +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 diff --git a/src/Win/LogConsole.cpp b/src/Win/LogConsole.cpp new file mode 100644 index 0000000..9e04a81 --- /dev/null +++ b/src/Win/LogConsole.cpp @@ -0,0 +1,66 @@ +#include +#include +#include + +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 diff --git a/src/Win/LogDialog.cpp b/src/Win/LogDialog.cpp new file mode 100644 index 0000000..9103e41 --- /dev/null +++ b/src/Win/LogDialog.cpp @@ -0,0 +1,53 @@ +#include +#include +#include + +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 diff --git a/src/Win/Pipe.cpp b/src/Win/Pipe.cpp new file mode 100644 index 0000000..f8bfd19 --- /dev/null +++ b/src/Win/Pipe.cpp @@ -0,0 +1,16 @@ +#include + +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 + diff --git a/src/Win/ProcMutex.cpp b/src/Win/ProcMutex.cpp new file mode 100644 index 0000000..403d341 --- /dev/null +++ b/src/Win/ProcMutex.cpp @@ -0,0 +1,65 @@ +#include +#include + +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 diff --git a/src/Win/ProgramPath.cpp b/src/Win/ProgramPath.cpp new file mode 100644 index 0000000..6947a22 --- /dev/null +++ b/src/Win/ProgramPath.cpp @@ -0,0 +1,49 @@ +#include +#include +#include + +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 diff --git a/src/Win/RWLock.cpp b/src/Win/RWLock.cpp new file mode 100644 index 0000000..3a1018b --- /dev/null +++ b/src/Win/RWLock.cpp @@ -0,0 +1,25 @@ +#include + +#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 diff --git a/src/Win/Semaphore.cpp b/src/Win/Semaphore.cpp new file mode 100644 index 0000000..94967c6 --- /dev/null +++ b/src/Win/Semaphore.cpp @@ -0,0 +1,54 @@ +#include +#include + +#include +#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 diff --git a/src/Win/SystemInfo.cpp b/src/Win/SystemInfo.cpp new file mode 100644 index 0000000..b26d4b6 --- /dev/null +++ b/src/Win/SystemInfo.cpp @@ -0,0 +1,99 @@ +#include +//#include +#include +#include +#include +#include +#include + +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 diff --git a/src/Win/Thread.cpp b/src/Win/Thread.cpp new file mode 100644 index 0000000..96079b3 --- /dev/null +++ b/src/Win/Thread.cpp @@ -0,0 +1,63 @@ +#include +#include + +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;itp; + + WaitForMultipleObjects(count,obj,false,time_out>0?time_out*1000:INFINITE); + + delete[] obj; + } +}//namespace hgl diff --git a/src/Win/ThreadMutex.cpp b/src/Win/ThreadMutex.cpp new file mode 100644 index 0000000..8815863 --- /dev/null +++ b/src/Win/ThreadMutex.cpp @@ -0,0 +1,55 @@ +#include + +#include + +#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 diff --git a/src/Win/Time.cpp b/src/Win/Time.cpp new file mode 100644 index 0000000..e680fe0 --- /dev/null +++ b/src/Win/Time.cpp @@ -0,0 +1,90 @@ +#include +#include + +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 diff --git a/src/Win/WinMessage.cpp b/src/Win/WinMessage.cpp new file mode 100644 index 0000000..d277d65 --- /dev/null +++ b/src/Win/WinMessage.cpp @@ -0,0 +1,328 @@ +#include"WinWindow.h" +#include +#include + +#ifdef _DEBUG +#include +#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 diff --git a/src/Win/WinVulkan.cpp b/src/Win/WinVulkan.cpp new file mode 100644 index 0000000..c7c7edb --- /dev/null +++ b/src/Win/WinVulkan.cpp @@ -0,0 +1,30 @@ +#include +#include"WinWindow.h" +#include + +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 \ No newline at end of file diff --git a/src/Win/WinWindow.cpp b/src/Win/WinWindow.cpp new file mode 100644 index 0000000..5301fbc --- /dev/null +++ b/src/Win/WinWindow.cpp @@ -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 diff --git a/src/Win/WinWindow.h b/src/Win/WinWindow.h new file mode 100644 index 0000000..7401847 --- /dev/null +++ b/src/Win/WinWindow.h @@ -0,0 +1,47 @@ +#pragma once +#include +#include +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 diff --git a/src/Window.cpp b/src/Window.cpp new file mode 100644 index 0000000..b0370ea --- /dev/null +++ b/src/Window.cpp @@ -0,0 +1,66 @@ +#include + +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