首页 > 系统相关 >集成 Windows 本地应用到 Eclipse RCP 程序中

集成 Windows 本地应用到 Eclipse RCP 程序中

时间:2023-08-01 15:07:43浏览次数:47  
标签:窗口 Windows Eclipse RCP 应用程序 NULL 我们 sInfo


 

集成 Windows 本地应用到 Eclipse RCP 程序中

集成 Windows 本地应用到 Eclipse RCP 程序中_swt

 

级别: 中级

梁 骞 高级软件工程师, IBM 
辉 李 软件工程师, IBM 中国软件开发中心

2008 年 6 月 05 日

本文主要讨论了如何将一个 Windows 本地应用程序的窗口嵌入到 Eclipse RCP 中的技术。文章给出了实现窗口嵌入的例子代码,同时讨论了嵌入窗口后需要考虑的技术问题以及处理方法。

Windows 应用程序非常丰富,而有时我们的 Eclipse RCP 程序所需要的一些功能已经有一些现有的 Windows 本地应用程序的实现,我们希望能够在我们的 RCP 程序中重用这些功能。一种最简单的重用方法就是直接在我们 RCP 窗口中嵌入本地应用程序窗口。要使得一个 Windows 本地应用程序能够在我们的 RCP 程序中运行,我们可以使用 Windows 提供的 reparent 机制。利用这种机制实现窗口嵌入的主要过程是:首先要在我们的程序中启动要嵌入的 Windows 程序,然后我们设法获取程序启动后的主窗口句柄,再将我们RCP程序的窗口设置成 Windows 程序主窗口的父窗口。

由于我们需要启动 Windows 本地程序并且获取它的主窗口句柄,这些只能使用 Windows 本地调用来实现,所以我们先用 Windows 本地调用实现相应的功能,然后我们再用 JNI 进行调用。

 

JNI 简介

JNI 的全称是 Java Native Interface,JNI 标准是 Java 平台的一部分,它用来将 Java 代码和其他语言写的代码进行交互。下面简单介绍一下使用 JNI 的步骤:

编写带有 native 声明的 java 方法

这里以 HelloWorld 为例:


清单 1. Hello World Java 代码

                
public class HelloWorld {
	static {
		System.loadLibrary(“helloworld”);
	}

	public native void print();

	public static void main(String[] args) {
		HelloWorld hello = new HelloWorld();
		hello.print();
	}
}
      

编译 Java 代码以及生成 c/c++ 头文件:

先编译这个 java 类: javac HelloWorld.java,然后再生成扩展名为 .h 的头文件,java 提供了命令 javah 来生成头文件:javah –jni HelloWorld,下面的清单显示了生成的头文件的内容:


清单 2. Hello World C++ 头文件

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */

#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloWorld
 * Method:    print
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

使用 c/c++ 实现本地方法并编译成动态库文件

前面已经生成了 c/c++ 的头文件,下面要实现头文件中声明的函数,具体的实现代码如下面的清单所示,示例代码中仅仅是输出一行文字“HelloWorld”:


清单 3. Hello World C++ 实现代码

#include "HelloWorld.h"
#include <stdio.h>

JNIEXPORT void JNICALL Java_HelloWorld_print(JNIEnv * env, jobject obj) 
{
	printf("Hello World");
}

接下来要做的就是将这个 c++ 的代码编译成动态库文件,在 HelloWorld.cpp 文件目录下面,使用 VC 的编译器 cl 命令来编译:

cl -I%java_home%/include -I%java_home%/include/win32 -LD HelloWorld.cpp –Fehelloworld.dll

注意:生成的 dll 文件名在选项 -Fe 后面配置,这里是 helloworld.dll,因为前面我们在 HelloWorld.java 文件中 loadLibary 的时候使用的名字是 helloworld。所以要保证这里的名字和前面 load 的名字一致。另外需要将 -I%java_home%/include -I%java_home%/include/win32 参数加上,因为在第四步里面编写本地方法的时候引入了 jni.h 文件,所以在这里需要加入这些头文件的路径。

完成了这些步骤之后就可以运行这个程序:java HelloWorld,运行的结果就是在控制台输出字符串“HelloWorld”。

 

实现窗口 Reparent

前面部分介绍了如何使用 JNI,接下来介绍如何通过 JNI 启动一个 Windows 的本地应用程序并且将其主窗口设置为指定窗口的子窗口。首先创建一个 Java 类,如下面的清单所示:

public class ReparentUtil {
	static{
		System.loadLibrary("reparent");
	}
	public static native int startAndReparent(int parentWnd,
	            String command,String wndClass);
}

其中 System.loadLibrary("reparent") 是用来加载名为 reparent 的动态库,我们会在这个动态库中具体实现方法 startAndReparent(…)。

startAndReparent 定义方法来启动 Windows 程序,并且将其窗口 reparent 到我们指定的窗口。其中:

  • int parentWnd: 父窗口句柄
  • String command:Windows 程序启动命令
  • String wndClass:Windows 程序主窗口类型

由于有的程序启动后会创建多个顶级窗口,所以我们在这里要指定一个主窗口类型来区分不同的顶级窗口。这个方法是一个本地方法,我们会用 C++ 生成为一个叫 reparent.dll 的动态库,这个方法即存在于这个动态库中。

这个 Java 函数对应的的 C++ 函数是 Java_com_reparent_ReparentUtil_startAndReparent(JNIEnv *env, jclass classobj, jint parent, jstring command, jstring wndClass), 这个函数主要实现两部分的功能:

  • 启动 Windows 应用程序;
  • 获取 Windows 应用程序的主窗口句柄;
  • 将 Windows 应用主窗口设置成指定窗口的子窗口。

启动 Windows 应用程序

下面我们来看看启动 Windows 应用程序的实现. 我们先将函数传入的 Java 字符串参数转化成 C 字符串。这个过程主要通过 GetStringChars() 来实现。

JNIEXPORT jint JNICALL Java_com_reparent_ReparentUtil_startAndReparent
     (JNIEnv *env, jclass classobj, jint parent, jstring command, 
                      jstring wndClass){
	jboolean isCopy=FALSE;
	PROCESS_INFORMATION   pInfo;   
	STARTUPINFO                   sInfo; 

	int hParentWnd;

	jsize len = ( *env ).GetStringLength(command);
	const jchar *commandstr = (*env).GetStringChars(command,&isCopy);
	const jchar *wndClassStr = NULL;
	char commandcstr[200];
	int size = 0;
	size = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)commandstr, 
			len, commandcstr,(len*2+1), NULL, NULL );
	(*env).ReleaseStringChars(command, commandstr);
	if(size==0){
		return 0;
	}
	commandcstr[size] = 0;

	if(wndClass!=NULL){
		wndClassStr = (*env).GetStringChars(wndClass,&isCopy);
		if(wndClassStr!=NULL){
			len = (*env).GetStringLength(wndClass);
			size = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)wndClassStr, 
					len, wndClassName,(len*2+1), NULL, NULL );
			wndClassName[size] = 0;
			(*env).ReleaseStringChars(wndClass, wndClassStr);
		}
	}

接着,我们使用 Windows 的 API:CreateProcess 函数来启动我们要集成的应用程序。

sInfo.cb                     =   sizeof(STARTUPINFO);   
    sInfo.lpReserved             =   NULL;   
    sInfo.lpReserved2           =   NULL;   
    sInfo.cbReserved2           =   0;   
    sInfo.lpDesktop               =   NULL;   
    sInfo.lpTitle                   =   NULL;   
    sInfo.dwFlags                   =   0;   
    sInfo.dwX                           =   0;   
    sInfo.dwY                           =   0;   
    sInfo.dwFillAttribute   =   0;   
    sInfo.wShowWindow           =   SW_HIDE;   

    if(!CreateProcess(NULL,commandcstr,NULL,NULL, TRUE,0,NULL,NULL,&sInfo,&pInfo))
   {   
            printf("ERROR:   Cannot   launch   child   process/n");   
			release();
            return 0;
    }   

CreateProcess 函数的定义是:

sInfo.cb                     =   sizeof(STARTUPINFO);   
    sInfo.lpReserved             =   NULL;   
    sInfo.lpReserved2           =   NULL;   
    sInfo.cbReserved2           =   0;   
    sInfo.lpDesktop               =   NULL;   
    sInfo.lpTitle                   =   NULL;   
    sInfo.dwFlags                   =   0;   
    sInfo.dwX                           =   0;   
    sInfo.dwY                           =   0;   
    sInfo.dwFillAttribute   =   0;   
    sInfo.wShowWindow           =   SW_HIDE;   

    if(!CreateProcess(NULL,commandcstr,NULL,NULL, TRUE,0,NULL,NULL,&sInfo,&pInfo))
   {   
            printf("ERROR:   Cannot   launch   child   process/n");   
			release();
            return 0;
    }   

其中 lpApplicationName:指向一个 NULL 结尾的、用来指定可执行模块的字符串。lpCommandLine:指向一个 NULL 结尾的、用来指定要运行的命令行。lpProcessAttributes: 指向一个 SECURITY_ATTRIBUTES 结构体,这个结构体决定是否返回的句柄可以被子进程继承。lpThreadAttributes: 指向一个 SECURITY_ATTRIBUTES 结构体,这个结构体决定是否返回的句柄可以被子进程继承。bInheritHandles:指示新进程是否从调用进程处继承了句柄。dwCreationFlags:指定附加的、用来控制优先类和进程的创建的标志。lpEnvironment:指向一个新进程的环境块。lpCurrentDirectory:指向一个以 NULL 结尾的字符串,这个字符串用来指定子进程的工作路径。lpStartupInfo:指向一个用于决定新进程的主窗体如何显示的 STARTUPINFO 结构体。lpProcessInformation:指向一个用来接收新进程的识别信息的 PROCESS_INFORMATION 结构体。

获取应用程序的主窗口句柄

为了获取启动后的程序的主窗口句柄,在调用 CreateProcess() 之前,我们需要使用一个 Windows 的系统钩子来截获窗口创建的事件:

hHook = SetWindowsHookEx(WH_SHELL, ShellProc,(HINSTANCE)hDllHandle,NULL);

这里,我们使用的钩子类型是 WH_SHELL。这种钩子可以截获所有顶级窗口创建或者激活的事件。函数的第二个参数是事件处理函数。我们的处理函数叫 ShellProc。我们之后会介绍。

启动应用程序之后,我们需要获取应用程序的主窗口之后才能继续运行。这里需要实现进程间的同步。在我们的主进程中,我们需要等待,当应用程序的主窗口创建之后,我们发一个消息,通知我们的主进程继续执行。

我们这里使用 Windows 的 Event 来实现同步。我们首先调用 CreateEvent 来创建一个事件,然后调用 WaitForSingleObject()等待事件的状态改变。在我们的 ShellProc 处理函数中,我们一旦获取应用程序主窗口句柄,我们会改变事件的状态以通知主进程继续执行。

以下是创建事件的代码,我们创建了一个名为 Global/WaitWindowCreatedEvent 的事件:

SECURITY_ATTRIBUTES secuAtt;
	secuAtt.bInheritHandle = TRUE;
	secuAtt.lpSecurityDescriptor = NULL;
	secuAtt.nLength = sizeof(SECURITY_ATTRIBUTES);
	hEvent = CreateEvent(&secuAtt,FALSE,FALSE,TEXT("Global/WaitWindowCreatedEvent"));

等待事件状态变化可以调用以下代码:

	WaitForSingleObject(hEvent,1000*60);

为了避免无限的等待下去,我们设置了一个最长的等待时间,为60秒。

下面我们再来看 ShellProc 的处理代码。这个函数中,我们主要是要获取应用程序的主窗口。根据 Windows 系统 WH_SHELL 钩子的定义,钩子的处理函数的第一个参数是事件类型,第二个参数是窗口句柄。我们首先判断窗口的类型是否是 HSHELL_WINDOWCREATED,然后判断对应窗口所属的进程号是否等于我们所启动的应用程序,如果需要还要判断窗口类型。一旦我们找到了应用程序主窗口,我们通过调用 SetEvent 来通知主进程继续执行。

LRESULT CALLBACK ShellProc(int nCode,WPARAM wParam,LPARAM lParam){
	if(nCode==HSHELL_WINDOWCREATED && childInstanceId!=0){
		HWND hwnd=HWND(wParam);
		DWORD pid;
		HANDLE childEvent;
		char classname[100];
		GetWindowThreadProcessId(hwnd,&pid);
		if(pid==childInstanceId){
			if(wndClassName[0]!=0){
				int count = GetClassName(hwnd,classname,100);
				classname[count] = 0;
				if(strcmp(classname,wndClassName)!=0){
				  return CallNextHookEx(hHook, nCode,
				                        wParam, lParam);
				}
			}
			hChildWnd = hwnd;
			ShowWindow(hChildWnd,SW_HIDE);
			childEvent = OpenEvent(EVENT_ALL_ACCESS,
			            TRUE,TEXT("Global/WaitWindowCreatedEvent"));
			if(childEvent!=0){
				SetEvent(childEvent);
			}
		}
	}
	return CallNextHookEx(hHook, nCode, wParam, lParam);
}

将 Windows 应用主窗口设置成指定窗口的子窗口

获取应用程序的主窗口句柄之后,在 Java_com_reparent_ReparentUtil_startAndReparent 函数的最后,我们通过调用 Windows 的 SetParent 函数将其设置成我们的子窗口,同时调整一下应用程序窗口的大小以使其能刚好显示在我们的窗口中。为了避免窗口的闪烁,我们先将窗口隐藏,reparent 之后再显示。为了去掉应用程序的窗口栏,我们需要将应用程序的窗口类型改为 WS_POPUP。


 

if(hChildWnd!=0){
		RECT rect;
		GetWindowRect((HWND)hParentWnd,&rect);
		ShowWindow(hChildWnd,SW_HIDE);
		SetParent(hChildWnd,(HWND)hParentWnd);
		SetWindowPos(hChildWnd,(HWND)0,0,0,
		              rect.right-rect.left,rect.bottom-rect.top,
			SWP_NOZORDER | SWP_NOACTIVATE | SWP_ASYNCWINDOWPOS | 
			SWP_SHOWWINDOW | SWP_NOSENDCHANGING | SWP_DEFERERASE);
		SetWindowLong(hChildWnd,GWL_STYLE,WS_POPUP);
		ShowWindow(hChildWnd,SW_SHOW);
}

包装 Windows 应用程序窗口到 SWT 控件

实现了 startAndReparent 方法后,只要将我们 SWT 窗口句柄传入,我们就可以将一个 Windows 本地应用嵌到我们的 SWT 窗口中了。为了方便使用,我们可以将 Windows 本地应用包装到一个 SWT Control 中,这样我们就可以象使用普通 SWT Control 一样使用 Windows 应用程序的窗口。下面我们来看如何实现对 Windows 应用程序窗口的包装。

首先我们定义一个 Control,它从 Canvas 继承而来。我们用它来作为本地应用程序窗口的父窗口,同时实现对它的管理。我们主要要实现以下几个方面的管理:

  • 窗口的创建:当我们 SWT 窗口创建时,我们需要将本地应用程序窗口创建出来
  • 窗口的销毁:当我们 SWT 窗口销毁时,我们也要将本地应用程序窗口销毁。
  • 焦点控制:当我们的 SWT 窗口获取到焦点时,我们要将焦点设置到本地应用程序窗口中。
  • 窗口大小的变化:当我们的 SWT 窗口的位置或大小发生变化时,我们要通知本地应用程序窗口改变它的位置或大小。

首先我们来看窗口的创建和销毁。我们需要监听 SWT 窗口的 Paint 事件和 Dispose 事件,在响应 Paint 事件中创建本地应用程序窗口,在响应 Dispose 事件中关闭本地应用程序窗口。需要注意的是,我们创建本地应用窗口可能需要花较长的时间,为了避免阻塞 UI 线程,我们将其放在一个线程中执行。如下面的清单所示:

public class NativeControl extends Canvas{
	private int childWnd = 0;
	private String startCommand = null;
	private String wndClassName = null;
	
	private boolean isCreatingNative = false;

	public NativeControl(Composite parent, int style) {
		super(parent, style);
		this.addPaintListener(new PaintListener(){

			public void paintControl(PaintEvent arg0) {
		this.addPaintListener(new PaintListener(){

			public void paintControl(PaintEvent arg0) {
				if(childWnd==0 && !isCreatingNative){
					isCreatingNative = true;
					Thread thread = new Thread(){
						public void run(){
						childWnd = ReparentUtil.startAndReparent(
			NativeControl.this.handle,startCommand,wndClassName);
							
						}
					};
					thread.start();
				}
			}
		});
			}
		});
		this.addDisposeListener(new DisposeListener(){

			public void widgetDisposed(DisposeEvent arg0) {
				if(childWnd!=0){
					OS.SendMessage(childWnd, OS.WM_CLOSE, 0, 0);
				}
			}
			
		});

在 paintControl(PaintEvent arg0) 函数中调用 ReparentUtil.startAndReparent(NativeControl.this.handle,startCommand,wndClassName) 来启动 Windows 应用程序并将应用程序窗口显示到 SWT 控件中。当 SWT 空间销毁的时候也要将 Windows 应用程序的窗口销毁。SWT 的 OS 类提供了 SendMessage 方法来实现将窗口销毁:OS.SendMessage(childWnd, OS.WM_CLOSE, 0, 0);childWnd 就是要销毁的窗口的句柄。

窗口焦点的控制和窗口的销毁比较类似,我们先监听父窗口的焦点事件,一旦获取焦点,我们将焦点设置到本地应用程序的窗口中。同时,我们需要加一个键盘事件监听器,这样当用户按“Tab”键时,焦点才能跳转到我们的父窗口控件。如下面的清单所示:

this.addFocusListener(new FocusListener(){

			public void focusGained(FocusEvent arg0) {
				if(childWnd!=0){
					OS.SetForegroundWindow(childWnd);
				}
			}

			public void focusLost(FocusEvent arg0) {
				
			}
			
		});
		this.addKeyListener(new KeyListener(){

			public void keyPressed(KeyEvent arg0) {
				
				
			}

			public void keyReleased(KeyEvent arg0) {
				
				
			}
			
		});

SWT 的 OS 类提供了 SetForegroundWindow 函数来将焦点设置到某个窗口上,函数的参数指定要设置焦点的窗口句柄。

窗口的大小的控制也是类似的。我们需要监听父窗口的窗口事件,一旦有窗口大小变化,我们就调整本地应用程序的窗口大小。

this.addControlListener(new ControlListener(){
			
  public void controlMoved(ControlEvent arg0) {
			
	}
			
  public void controlResized(ControlEvent arg0) {
	if(childWnd!=0){
		Rectangle rect = ((Composite)(arg0.widget)).getClientArea();
		OS.SetWindowPos(childWnd, 0, rect.x, rect.y, rect.width, rect.height, 
		OS.SWP_NOZORDER| OS.SWP_NOACTIVATE | OS.SWP_ASYNCWINDOWPOS);
		}
		}
			
		});

同样的我们利用 SWT 提供的函数来设置窗口的大小和位置,SetWindowPos 的参数分别是要设置的窗口句柄以及窗口位置大小。

最后我们需要添加一些方法,让用户可以设置启动应用程序的命令以及应用程序的窗口类型。

public void setStartParameters(String startCommand,String wndClassName){
		this.startCommand = startCommand;
		this.wndClassName = wndClassName;
	}

	public String getStartCommand() {
		return startCommand;
	}



	public void setStartCommand(String startCommand) {
		this.startCommand = startCommand;
	}



	public String getWndClassName() {
		return wndClassName;
	}



	public void setWndClassName(String wndClassName) {
		this.wndClassName = wndClassName;
	}

这样我们就开发了一个 SWT 的控件,它可以将指定的 Windows 本地应用程序启动并将程序的窗口嵌入到控件中。对这个控件的使用和普通 SWT 的控件一样,唯一的区别就是要在窗口显示前调用 setStartParameters() 方法设置 Windows 本地应用程序的启动命令和窗口的类型。

下面是一个简单的例子,把 Windows Messager 嵌入到了我们的 SWT 的窗口中。

public class ReparentTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Display display = new Display();
		Shell shell = new Shell(display);
		shell.setText("Test dialog");
		GridLayout layout = new GridLayout();
		layout.numColumns = 1;
		shell.setLayout(layout);
		
		Button button = new Button(shell,SWT.None);
		button.setLayoutData(new GridData());
		button.setText("Test");
		NativeControl control = new NativeControl(shell,SWT.NONE);
		GridData data = new GridData(GridData.FILL_BOTH);
		data.widthHint = 200;
		data.heightHint = 200;
		data.grabExcessHorizontalSpace = true;
		data.grabExcessVerticalSpace = true;
		control.setLayoutData(data);
		control.setStartParameters
		    ("C://Program Files//Messenger//Msmsgs.exe","MSBLClass");
		shell.open();
		while(!shell.isDisposed()){
			if(!display.readAndDispatch()){
				display.sleep();
			}
		}
	}
	
}

通过 setStartParameters() 方法来设置要启动的程序的路径以及该程序的窗口类型,在这里我们启动 MSN,对应的窗口类型是 MSBLClass:

control.setStartParameters("C://Program Files//Messenger//Msmsgs.exe","MSBLClass");


以下是代码显示的结果。我们可以拉伸改变窗口的大小,这时里面的 Messager 的窗口大小也会随之而变化。当焦点在 Test 按钮上时,按“Tab”键,焦点也会跳转到 Messager 的窗口上。


图 1. 图片示例


 

小结

本文介绍了将一个本地应用程序窗口集成到 Eclipse RCP 窗口中的相关技术。文中主要讨论的集成第三方的应用程序,由于我们不掌握第三方应用程序的代码,这种集成方式还是比较简单。例如本地应用程序的菜单还是显示在我们的SWT父窗口中,而不是显示在 Eclipse RCP 应用程序的主菜单中。有时,我们也需要将我们自己开发本地应用程序集成到 Eclipse RCP 程序中。其实现原理也和本文讲述的一样。不同的是,我们可以实现更多的对我们本地应用程序的控制,从而实现更紧密的集成。例如,我们的本地应用程序可以提供 API 让 RCP 程序获取自己的主菜单,并且将其主菜单显示在 RCP 程序的主菜单中。




下载



参考资料



作者简介

 

http://www.ibm.com/developerworks/cn/opensource/os-cn-eclrcp/index.html

标签:窗口,Windows,Eclipse,RCP,应用程序,NULL,我们,sInfo
From: https://blog.51cto.com/u_13538361/6922047

相关文章

  • Windows 消息的优先级
    众所周知,windows窗口程序是基于消息的,其最底层维护者一个死循环如下:while((bRet=GetMessage(&msg,NULL,0,0))!=0){if(bRet==-1){//handletheerrorandpossiblyexit}else{TranslateMessage(&msg);Dispa......
  • Windows计划任务执行路径的问题(转载)
    Windows计划任务定时执行可执行程序的时候,如果程序内加载资源文件有相对路径的存在,那么当运行计划任务的时候就会报出一个路径找不到的错误(手动执行可执行程序则无任何问题)。如下图那么在设置计划任务的时候只需要做如下修改就可以避免此类错误的出现,在操作的tab页,起始于:将程序......
  • windows安装redis
    前言RemoteDictionaryServer(Redis)是一个开源的使用ANSIC语言编写、遵守BSD协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提供多种语言的API,是跨平台的非关系型数据库。Redis通常被称为数据结构服务器,因为值(value)可以是字符串(Stri......
  • Windows提权小结
    当获取主机权限时,希望可以将普通用户提升为管理员用户,以便获得高权限完全控制目标主机。Windows常用的提权方式有:内核提权、数据库提权、系统配置错误提权、BypassUAC提权、令牌窃取提权等姿势。个人认为在提权方面内核提权、土豆系列提权是比较效率而且成功率较高的,其他的提权方......
  • 难以相信Windows 10竟然每月有5亿活跃用户
    微软的Build大会开始之初,CEOSatyaNadella上台后的第一件事,照例是公布一下Windows的增长情况。根据官方统计,目前Windows10的月活跃用户数已经达到了5亿人,这项数据去年九月的时候还是4亿,提升速度可谓非常之稳定(当然,这样的增速跟当初微软宣布免费升级后的那段时间肯定......
  • 在Windows中运行Filebeat(Running Filebeat in windows)
     我最近使用这些说明在Windows上设置了filebeathttps://www.elastic.co/downloads/beats/filebeat但它迫使我保持​​cmd提示打开运行命令filebeat.exe-cfilebeat.yml我想知道是否有办法将其作为后台进程运行?谢谢。Isetupfilebeatonwindowsrecentlyusingt......
  • Windows 实例如何开放端口
    矩池云Windows实例相比于Linux实例,除了在租用机器的时候自定义端口外,还需要在Windows防火墙中添加入口规则。接下来将教大家如何设置Windows防火墙,启用端口。租用成功后通过RDP链接连接服务器,然后搜索防火墙,点击搜索结果中的WindowsDefender防火墙。在设置页面,点击......
  • windows配置本地ssl证书
    打开php.ini文件,搜索curl.cainfo,替换为一下文件,cacert.pem是证书 curl.cainfo=D:\web\phpEnv\cacert.pem  ......
  • Eclipse转IDEA开发java项目spring+mybaits项目踩坑记录
    久了不用一个东西总有遗忘,记录是你快速找回状态之本。今天将原来eclipse写的spring+mybatisDemo在idea上跑起来,花了不少时间。这里将坑记录下:一、IDEA创建项目   1.IDEA中项目project等价于Eclipse中workspace, eclipse的workspace中可以创建多个工程;在IDEA中达到相......
  • 开发者也不知道?Windows 8/7…
    导读:Windows/Windows8/WinPhone7/WinPhone8/SurfaceRT/SurfacePro/WindowsPhoneMarketplace/WindowsStore之间的关系和区别。前几天流行一个段子:@师北宸:我如果招聘科技编辑的话,就让面试的人谈一个问题:Windows/Windows8/WinPhone7/WinPhone8/SurfaceRT/Su......