昨天,潘弄了一下午的Solaris10+OpenFiler,iscsiadm无论如何都连不上OpenFiler。
最后,把OpenFiler的Network Access Cinfiguration中NetMask设成了255.255.255.255,然后就连上了。
哈哈哈,这个坑不错,鄙视潘潘一下。
Learn and share.
昨天,潘弄了一下午的Solaris10+OpenFiler,iscsiadm无论如何都连不上OpenFiler。
最后,把OpenFiler的Network Access Cinfiguration中NetMask设成了255.255.255.255,然后就连上了。
哈哈哈,这个坑不错,鄙视潘潘一下。
1、服务端C#
private const String MY_PIPE_NAME = "__MY__PIPE__TEST__";
private const int BUFFER_SIZE = 1024;
NamedPipeServerStream pipe;
StreamWriter writer;
String msg = "Message is comming";
private void PipeCreate()
{
if (pipe != null && pipe.IsConnected)
{
pipe.Close();
}
pipe = new NamedPipeServerStream(MY_PIPE_NAME, PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.None);
if (pipe == null)
{
textBox1.Text = textBox1.Text + "Pipe is null";
return;
}
if (pipe.IsConnected)
{
textBox1.Text = textBox1.Text + "Pipe is already connected";
return;
}
pipe.WaitForConnection();
textBox1.Text = textBox1.Text + "Pipe is ready to connect\r\n";
}
private void PipeWrite()
{
if (pipe!=null && pipe.IsConnected)
{
if(writer==null)
{
//关闭BOM(Byte Order Mark 0xfeff)
UnicodeEncoding unicodeWithoutBom = new System.Text.UnicodeEncoding(false, false);
writer = new StreamWriter(pipe, unicodeWithoutBom);
//写完后直接flush,会阻塞
writer.AutoFlush = true;
}
writer.Write(msg);
textBox1.Text = textBox1.Text + "Pipe message sent \r\n";
}
else
{
textBox1.Text = textBox1.Text + "Pipe is not connected \r\n";
}
}
private void PipeClose()
{
if (pipe!=null && pipe.IsConnected)
{
writer.Close();
pipe.Close();
writer = null;
pipe = null;
}
}
2、客户端C#
private const String MY_PIPE_NAME = "__MY__PIPE__TEST__";
private const int BUFFER_SIZE = 1024;
NamedPipeClientStream pipe;
StreamReader reader;
private void PipeConnect()
{
if (pipe != null && pipe.IsConnected)
{
pipe.Close();
}
pipe = new NamedPipeClientStream(".", MY_PIPE_NAME, PipeDirection.InOut);
if (pipe != null)
{
if (!pipe.IsConnected)
{
pipe.Connect();
textBox1.Text = textBox1.Text + "\r\npipe is connected";
}
else
{
textBox1.Text = textBox1.Text + "\r\npipe is already connected";
}
}
else
{
textBox1.Text = textBox1.Text + "\r\npipe is null";
}
}
private void PipeRead()
{
if (pipe.IsConnected)
{
if (reader == null)
{
reader = new StreamReader(pipe, Encoding.Unicode);
}
char[] buffer = new char[BUFFER_SIZE];
int byteRead = reader.Read(buffer, 0, BUFFER_SIZE);
String msgTxt = new String(buffer, 0, byteRead);
textBox1.Text = textBox1.Text + "\r\nPipe msg received: " + msgTxt;
}
else
{
textBox1.Text = textBox1.Text + "\r\nPipe is not connected";
}
}
private void PipeClose()
{
if (reader != null)
{
reader.Close();
reader = null;
}
if (pipe != null && pipe.IsConnected)
{
pipe.Close();
}
textBox1.Text = textBox1.Text + "\r\npipe is closed";
}
1、服务端MFC
#define MY_PIPE_NAME L"\\\\.\\pipe\\__MY__PIPE__TEST__"
#define BUFSIZE 1024
HANDLE m_hPipe;
BOOL m_bConnected;
int m_bMsgNum;
//使用ConnectNamedPipe会阻塞,直到客户端进行连接
//不使用ConnectNamedPipe则不会阻塞,但一样可以做后续操作
void XXX::PipeCreate()
{
m_hPipe = CreateNamedPipe(
MY_PIPE_NAME, // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
1, // max. instances
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
0, // client time-out
NULL); // default security attribute
if (m_hPipe == INVALID_HANDLE_VALUE)
{
::MessageBox(NULL, L"CreateNamedPipe Error", L"CreateNamedPipe", MB_OK);
}
else
{
::MessageBox(NULL, L"CreateNamedPipe OK", L"CreateNamedPipe", MB_OK);
}
m_bConnected = ConnectNamedPipe(m_hPipe, NULL);
if (m_bConnected)
{
::MessageBox(NULL, L"ConnectNamedPipe OK", L"ConnectNamedPipe", MB_OK);
}
else
{
::MessageBox(NULL, L"ConnectNamedPipe Error", L"ConnectNamedPipe", MB_OK);
}
m_bMsgNum = 0;
}
//WriteFile会阻塞,等待客户端读取完毕
void XXX::PipeWrite()
{
DWORD dwWritten;
TCHAR buffer[BUFSIZE];
int n = sizeof(buffer);
_stprintf_s(buffer, L"This the %d message", m_bMsgNum++);
if (!WriteFile(m_hPipe, buffer, n, &dwWritten, NULL))
{
::MessageBox(NULL, L"WriteFile Failed", L"WriteFile", MB_OK);
}
}
//两边都关闭,才可以重新建立管道
void XXX::PipeClose()
{
if (m_bConnected)
{
DisconnectNamedPipe(m_hPipe);
m_bConnected = FALSE;
}
if (m_hPipe!=NULL && m_hPipe != INVALID_HANDLE_VALUE)
{
CloseHandle(m_hPipe);
m_hPipe=NULL;
}
}
2、客户端MFC
#define MY_PIPE_NAME L"\\\\.\\pipe\\__MY__PIPE__TEST__"
#define BUFSIZE 1024
HANDLE m_hPipe;
BOOL m_bConnected;
//WaitNamedPipe会等待ConnectNamedPipe
void XXX::PipeConnect()
{
if (WaitNamedPipe(MY_PIPE_NAME, NMPWAIT_WAIT_FOREVER) == 0)
{
MessageBox(L"WaitNamedPipe failed");
return;
}
m_hPipe = CreateFile(MY_PIPE_NAME,
GENERIC_READ,
0,
NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (m_hPipe == INVALID_HANDLE_VALUE)
{
m_bConnected = FALSE;
::MessageBox(NULL, L"CreateFile Error", L"CreateNamedPipe", MB_OK);
}
else
{
m_bConnected = TRUE;
::MessageBox(NULL, L"CreateFile OK", L"CreateNamedPipe", MB_OK);
}
}
//ReadFile会阻塞等待写入
void XXX::PipeRead()
{
DWORD dwBytesRead;
TCHAR buffer[BUFSIZE];
int bufsize = sizeof(buffer);
memset(buffer, 0x00, bufsize);
if (m_bConnected)
{
//C#程序不处理的话,第一次读会读到BOM(Byte Order Mark 0xfeff)
if (ReadFile(m_hPipe, buffer, bufsize, &dwBytesRead, NULL))
{
::MessageBox(NULL, buffer, L"ReadFile", MB_OK);
}
}
}
//两边都关闭,才可以重新建立管道
void XXX::PipeClose()
{
if (m_hPipe!=NULL && m_hPipe != INVALID_HANDLE_VALUE)
{
CloseHandle(m_hPipe);
m_hPipe=NULL;
}
}
首先是MFC,注意事项:
1、管道读写是FIFO
2、读写指针,要记得关闭
3、编译时用了UNICODE,但CMD读取回来时ANSI,所以要转换一下字符集
SECURITY_ATTRIBUTES sa;
ZeroMemory(&sa, sizeof(sa));
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
HANDLE hRead, hWrite;
if (!CreatePipe(&hRead, &hWrite, &sa, 0)) {
MessageBox(L"Error On CreatePipe()");
return;
}
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(STARTUPINFO);
GetStartupInfo(&si);
si.hStdError = hWrite;
si.hStdOutput = hWrite;
si.wShowWindow = SW_HIDE;
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
if (!::CreateProcess(L"C:\\Windows\\System32\\cmd.exe", L"/c dir /b D:\\Downloads"
, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi)) {
showMeErrorInfo();
return;
}
CloseHandle(hWrite);
char buffer[4096] = { 0 };
DWORD bytesRead;
while (true) {
if (ReadFile(hRead, buffer, 4095, &bytesRead, NULL) == NULL)
{
break;
}
UINT CodePage = 0;
DWORD dwNum;
dwNum = MultiByteToWideChar(CodePage, 0, buffer, -1, NULL, 0);
if (dwNum)
{
wchar_t *pwText;
pwText = new TCHAR[dwNum];
if (pwText)
{
MultiByteToWideChar(CodePage, 0, buffer, -1, pwText, dwNum);
}
//m_Edit.SetWindowText(pwText);
delete[]pwText;
pwText = NULL;
}
UpdateData(false);
Sleep(200);
}
CloseHandle(hRead);
C#的话,就简单多了:
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = "C:\\Windows\\System32\\cmd.exe";
startInfo.Arguments = "/c dir /b D:\\Downloads";
startInfo.RedirectStandardOutput = true;
//startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = false;
Process p=Process.Start(startInfo);
String cmdOut = "";
while(!p.HasExited)
{
cmdOut = p.StandardOutput.ReadLine();
textBox1.Text += cmdOut + "\r\n";
p.WaitForExit(10);
}
cmdOut = p.StandardOutput.ReadToEnd() + "\r\n";
textBox1.Text += cmdOut ;
请注意:
A、SendMessage在接收方处理完毕前不会返回,会产生严重阻塞
B、由于使用了非托管内存,要注意进行清理
1、发送方WinForm
public const int WM_COPYDATA = 0x004A;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
public IntPtr lpData;
}
public void sendData(String msg, Boolean isUnicode)
{
COPYDATASTRUCT cds = new COPYDATASTRUCT();
cds.cbData = (msg.Length + 1) * (isUnicode ? 2:1);
cds.lpData = (isUnicode ? Marshal.StringToCoTaskMemUni(msg) : Marshal.StringToCoTaskMemAnsi(msg));
IntPtr cdsPtr = Marshal.AllocHGlobal(Marshal.SizeOf(cds));
Marshal.StructureToPtr(cds, cdsPtr, false);
IntPtr clientWnd = Win32Helper.GetCurrentWindowHandle();
SendMessage(clientWnd, WM_COPYDATA, IntPtr.Zero, cdsPtr);
Marshal.FreeHGlobal(cdsPtr);
Marshal.FreeCoTaskMem(cds.lpData);
}
2、接收方WinForm
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
public string lpData;
}
public const int WM_COPYDATA = 0x004A;
protected override void WndProc(ref System.Windows.Forms.Message msg)
{
string msgTxt = "";
COPYDATASTRUCT cds = new COPYDATASTRUCT();
switch (msg.Msg)
{
case WM_COPYDATA:
if(msg.LParam!=IntPtr.Zero)
{
cds = (COPYDATASTRUCT)msg.GetLParam(cds.GetType());
String msgstr = cds.lpData;
//MessageBox.Show(msgstr);
}
break;
default:
base.WndProc(ref msg);
break;
}
}
1、发送方MFC
void XXX::SendCopyDataMessage(CString strWinTitle, CString strMsg)
{
HWND hdlg;
hdlg = ::FindWindow(NULL, strWinTitle);
if (NULL != hdlg)
{
COPYDATASTRUCT cds = { 0 };
cds.dwData = 0;
cds.cbData = (strMsg.GetLength()+1)*sizeof(TCHAR);
cds.lpData = strMsg.GetBuffer(strMsg.GetLength());
::SendMessage(hdlg, WM_COPYDATA, (WPARAM)this->m_hWnd, (LPARAM)&cds);
strMsg.ReleaseBuffer();
}
}
2、接收方MFC
BOOL XXX::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
CString strMsg;
if (pCopyDataStruct && pCopyDataStruct->cbData)
{
strMsg = (LPCTSTR)(pCopyDataStruct->lpData);
MessageBox(strMsg, L"WM_COPYDATA", MB_OK);
}
return CDialogEx::OnCopyData(pWnd, pCopyDataStruct);
}
大家都知道,使用微软的MFC ActiveX控件向导生成的控件类,是基于COleControl的,而COleControl是基于CWnd类。这样很多MFC的特性,如CFrameWnd的特性,CSingleDocTemplate(SDI)的特性等就无法使用了。如果要把用到这些类的MFC程序封装为ActiveX插件,就会有不少麻烦。
其实这个问题,在上个世纪MFC诞生不久,就有人解决了,并提供了完整的示例代码。微软官方的这篇文章《Designing ActiveX Components with the MFC Document/View Model》,在原地址http://www.microsoft.com/mind/0497/mfc.asp已经无法找到了。
但好在这里还有完整的备份《Designing ActiveX Components with the MFC Document/View Model》。
原文的作者,实现了CActiveXDocTemplate和CActiveXDocControl两个类,而用户只需要将控件的基类从COleControl换为CActiveXDocControl,并做简单修改,就可以方便的使用SDI的特性了。
整体思路其实是使用CActiveXDocControl扩展了COleControl。在CActiveXDocControl中,作者初始化了CDocManager,使用CActiveXDocTemplate控制了document、view、frame的生成,处理了OnSize事件,并使用Timer定时获取消息处理更新。
我们使用的时候,主要就是用这两个类,代码如下(两个类相互引用,所以放到了同一文件中):
1、ActivDoc.h
class CActiveXDocTemplate : public CSingleDocTemplate
{
enum { IDR_NOTUSED = 0x7FFF };
CWnd* m_pParentWnd;
CFrameWnd* m_pFrameWnd;
CString m_docFile;
public:
CActiveXDocTemplate(CRuntimeClass* pDocClass,
CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass);
CFrameWnd* CreateDocViewFrame(CWnd* pParentWnd);
void SaveDocumentFile();
virtual CFrameWnd* CreateNewFrame(CDocument* pDoc,
CFrameWnd* pOther);
virtual CDocument* OpenDocumentFile(
LPCTSTR lpszPathName, BOOL bVerifyExists = TRUE);
};
//===================================================
class CActiveXDocControl : public COleControl
{
enum { WM_IDLEUPDATECMDUI = 0x0363 };
static BOOL m_bDocInitialized;
CActiveXDocTemplate* m_pDocTemplate;
CFrameWnd* m_pFrameWnd;
DECLARE_DYNAMIC(CActiveXDocControl)
protected:
void AddDocTemplate(CActiveXDocTemplate* pDocTemplate);
CDocTemplate* GetDocTemplate() { return m_pDocTemplate; }
//{{AFX_MSG(CActiveXDocControl)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnTimer(UINT nIDEvent);
afx_msg void OnDestroy();
//}}AFX_MSG
//{{AFX_DISPATCH(CActiveXDocControl)
//}}AFX_DISPATCH
//{{AFX_EVENT(CActiveXDocControl)
//}}AFX_EVENT
DECLARE_MESSAGE_MAP()
DECLARE_DISPATCH_MAP()
DECLARE_EVENT_MAP()
public:
CActiveXDocControl();
virtual ~CActiveXDocControl();
enum {
//{{AFX_DISP_ID(CActiveXDocControl)
//}}AFX_DISP_ID
};
};
2、ActivDoc.cpp
// ActivDoc.cpp : implementation file
//
#include "stdafx.h"
#include "ActivDoc.h"
CActiveXDocTemplate::CActiveXDocTemplate(CRuntimeClass* pDocClass,
CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass)
: CSingleDocTemplate(IDR_NOTUSED, pDocClass, pFrameClass,
pViewClass)
{
ASSERT(pFrameClass);
}
CFrameWnd* CActiveXDocTemplate::CreateDocViewFrame(CWnd* pParentWnd)
{
ASSERT(pParentWnd && IsWindow(*pParentWnd));
ASSERT_KINDOF(CActiveXDocControl, pParentWnd);
m_pParentWnd = pParentWnd;
m_pFrameWnd = NULL;
// OpenDocumentFile is a virtual method (implemented in
// the CSingleDocTemplate base class) that creates
// the document (either empty or loaded from the specified
// file) and calls our CreateNewFrame function. Passing
// NULL to the function creates a new document. Incidentally,
// the view is created by the CFrameWnd's OnCreateClient()
// method.
if (!OpenDocumentFile(NULL))
return NULL;
// Since OpenDocumentFile sets m_pFrame, we can now use it.
ASSERT(m_pFrameWnd);
ASSERT_KINDOF(CFrameWnd, m_pFrameWnd);
m_pFrameWnd->ShowWindow(SW_SHOWNORMAL);
return m_pFrameWnd;
}
CFrameWnd* CActiveXDocTemplate::CreateNewFrame(CDocument* pDoc,
CFrameWnd* pOther)
{
ASSERT(pOther == NULL);
ASSERT(m_pFrameClass != NULL);
if (pDoc != NULL)
ASSERT_VALID(pDoc);
// Create a frame wired to the specified document
CCreateContext context;
context.m_pCurrentFrame = pOther;
context.m_pCurrentDoc = pDoc;
context.m_pNewViewClass = m_pViewClass;
context.m_pNewDocTemplate = this;
m_pFrameWnd = (CFrameWnd*)m_pFrameClass->CreateObject();
if (m_pFrameWnd == NULL)
{
TRACE1("Warning: Dynamic create of frame %hs failed.\n",
m_pFrameClass->m_lpszClassName);
return NULL;
}
ASSERT_KINDOF(CFrameWnd, m_pFrameWnd);
if (context.m_pNewViewClass == NULL)
TRACE0("Warning: creating frame with no default view.\n");
// The frame is created as a menu-less child of the
// CActiveXDocControl in which it will reside.
ASSERT_KINDOF(CActiveXDocControl, m_pParentWnd);
if (!m_pFrameWnd->Create(NULL, "", WS_CHILD|WS_VISIBLE,
CFrameWnd::rectDefault, m_pParentWnd, NULL, 0, &context))
{
TRACE0("Warning: CDocTemplate couldn't create a frame.\n");
return NULL;
}
return m_pFrameWnd;
}
CDocument* CActiveXDocTemplate::OpenDocumentFile(
LPCTSTR lpszPathName, BOOL bVerifyExists)
{
SaveDocumentFile();
m_docFile = lpszPathName;
if (bVerifyExists)
{
DWORD dwAttrib = GetFileAttributes(m_docFile);
if (dwAttrib == 0xFFFFFFFF ||
dwAttrib == FILE_ATTRIBUTE_DIRECTORY)
{
lpszPathName = NULL;
}
}
return CSingleDocTemplate::OpenDocumentFile(
lpszPathName, TRUE);
}
void CActiveXDocTemplate::SaveDocumentFile()
{
if (m_pOnlyDoc != NULL)
{
if (!m_docFile.IsEmpty())
m_pOnlyDoc->OnSaveDocument(m_docFile);
else
m_pOnlyDoc->SetModifiedFlag(FALSE);
}
}
//===================================================
// CActiveXDocControl
IMPLEMENT_DYNAMIC(CActiveXDocControl, COleControl)
BEGIN_MESSAGE_MAP(CActiveXDocControl, COleControl)
//{{AFX_MSG_MAP(CActiveXDocControl)
ON_WM_CREATE()
ON_WM_SIZE()
ON_WM_TIMER()
ON_WM_DESTROY()
//}}AFX_MSG_MAP
ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()
BEGIN_DISPATCH_MAP(CActiveXDocControl, COleControl)
//{{AFX_DISPATCH_MAP(CActiveXDocControl)
//}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()
BEGIN_EVENT_MAP(CActiveXDocControl, COleControl)
//{{AFX_EVENT_MAP(COleFrameCtrl)
//}}AFX_EVENT_MAP
END_EVENT_MAP()
int CActiveXDocControl::m_bDocInitialized = FALSE;
CActiveXDocControl::CActiveXDocControl()
{
m_pDocTemplate = NULL;
m_pFrameWnd = NULL;
// Since we're in an OCX, CWinApp::InitApplication() is
// not called by the framework. Unfortunately, that method
// performs CDocManager initialization that is necessary
// in order for our DocTemplate to clean up after itself.
// We simulate the same initialization by calling the
// following code the first time we create a control.
if (!m_bDocInitialized)
{
CDocManager docManager;
docManager.AddDocTemplate(NULL);
m_bDocInitialized = TRUE;
}
}
CActiveXDocControl::~CActiveXDocControl()
{
// Note that the frame, the document, and the view are
// all deleted automatically by the framework!
delete m_pDocTemplate;
}
void CActiveXDocControl::AddDocTemplate(CActiveXDocTemplate* pDocTemplate)
{
// I've decided to call this function AddDocTemplate to
// be consistent with naming of CWinApp::AddDocTemplate.
// However, only one DocTemplate is allowed per control.
ASSERT(pDocTemplate);
ASSERT(m_pDocTemplate == NULL);
m_pDocTemplate = pDocTemplate;
}
int CActiveXDocControl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (COleControl::OnCreate(lpCreateStruct) == -1)
return -1;
// The CActiveXDocTemplate object will create the
// document, the view, and the frame inside the
// control. The reason we need a handle to the frame
// is so that we can resize it when the control is
// resized.
ASSERT(m_pDocTemplate); // Set in call to AddDocTemplate
m_pFrameWnd = m_pDocTemplate->CreateDocViewFrame(this);
ASSERT_KINDOF(CFrameWnd, m_pFrameWnd);
// By default, we'll create the control with a border,
// since it looks better for frames containing a toolbar.
SetBorderStyle(TRUE);
SetTimer(WM_IDLEUPDATECMDUI, 300, NULL);
return 0;
}
void CActiveXDocControl::OnSize(UINT nType, int cx, int cy)
{
COleControl::OnSize(nType, cx, cy);
// The CFrameWnd should always fill up the entire client
// area of the control.
if (m_pFrameWnd != NULL)
{
ASSERT(IsWindow(*m_pFrameWnd));
CRect area;
GetClientRect(area);
m_pFrameWnd->MoveWindow(area.left, area.top, area.right,
area.bottom);
}
}
void CActiveXDocControl::OnTimer(UINT nIDEvent)
{
// Since we're in an OCX, we don't control the message loop,
// so CWinThread::OnIdle is never called. That means we have
// to periodically pump the ON_UPDATE_COMMAND_UI messages
// by hand.
SendMessageToDescendants(WM_IDLEUPDATECMDUI, TRUE);
COleControl::OnTimer(nIDEvent);
}
void CActiveXDocControl::OnDestroy()
{
AfxGetApp()->m_pMainWnd = NULL;
m_pDocTemplate->SaveDocumentFile();
COleControl::OnDestroy();
}
困了,回去再写。。。
//获取dll的绝对路径,请根据不同情况自己选用
MessageBox.Show(System.Reflection.Assembly.GetExecutingAssembly().Location);
MessageBox.Show(System.Reflection.Assembly.GetEntryAssembly().Location);
MessageBox.Show(System.Windows.Forms.Application.ExecutablePath);
MessageBox.Show(System.Windows.Forms.Application.StartupPath);
MessageBox.Show(System.Environment.CurrentDirectory);
MessageBox.Show(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
在CS程序中启动其他应用后,要获取进程的主窗体其实很简单:
Process p = Process.Start(exePath);
//p.WaitForInputIdle();
p.Refresh();
IntPtr mainWnd = p.MainWindowHandle;
但是,总有很多特殊的情况,上面的方法根本无法用,所以,要用Windows API来搞定了
1、如果窗口信息很固定而且没有重名的话,可以用Findwindow搞定
[DllImport("User32.dll", EntryPoint = "FindWindow")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
IntPtr clientWnd = FindWindow(null,"FormClient");
2、根据标题枚举窗口句柄
//枚举窗体
[DllImport("User32.dll", EntryPoint = "EnumWindows", SetLastError = true)]
public static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, uint lParam);
//获取窗体标题
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpText, int nCount);
//设置错误状态
[DllImport("kernel32.dll", EntryPoint = "SetLastError")]
public static extern void SetLastError(uint dwErrCode);
//线程主窗口句柄
private static IntPtr processMainWnd = IntPtr.Zero;
//要查找的窗口名称
private static String winTitle = "__Web__Form__Main__";
//声明委托函数
public delegate bool WNDENUMPROC(IntPtr hwnd, uint lParam);
//枚举进程句柄,非线程安全
[SecuritySafeCritical]
public static IntPtr GetCurrentWindowHandle()
{
IntPtr ptrWnd = IntPtr.Zero;
bool bResult = EnumWindows(new WNDENUMPROC(EnumWindowsProc), (uint)0);
if (!bResult && Marshal.GetLastWin32Error() == 0)
{
ptrWnd = processMainWnd;
}
return ptrWnd;
}
//枚举函数,获取主窗口句柄然后退出
[SecuritySafeCritical]
private static bool EnumWindowsProc(IntPtr hwnd, uint lParam)
{
//根据标题获取窗体
var sb = new StringBuilder(50);
GetWindowText(hwnd, sb, sb.Capacity);
if (winTitle.Equals(sb.ToString()))
{
processMainWnd = hwnd;
SetLastError(0);
return false;
}
return true;
}
3、跟进进程id枚举获取主窗体句柄
//枚举窗体
[DllImport("User32.dll", EntryPoint = "EnumWindows", SetLastError = true)]
//获取父窗体
[DllImport("user32.dll", EntryPoint = "GetParent", SetLastError = true)]
//根据窗口获取线程句柄
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowThreadProcessId(IntPtr hwnd, out uint pid);
//设置错误状态
[DllImport("kernel32.dll", EntryPoint = "SetLastError")]
public static extern void SetLastError(uint dwErrCode);
//线程主窗口句柄
private static IntPtr processMainWnd = IntPtr.Zero;
//枚举进程句柄
[SecuritySafeCritical]
public static IntPtr GetCurrentWindowHandle(int processId)
{
IntPtr ptrWnd = IntPtr.Zero;
bool bResult = EnumWindows(new WNDENUMPROC(EnumWindowsProc), (uint)processId);
if (!bResult && Marshal.GetLastWin32Error() == 0)
{
ptrWnd = processMainWnd;
}
return ptrWnd;
}
//枚举函数,获取主窗口句柄然后退出
[SecuritySafeCritical]
private static bool EnumWindowsProc(IntPtr hwnd, uint lParam)
{
uint uiPid = 0;
//根据启动方式不同,这里要有相应修改
if (GetParent(hwnd) == IntPtr.Zero)
{
GetWindowThreadProcessId(hwnd, out uiPid);
if (uiPid == lParam)
{
processMainWnd = hwnd;
SetLastError(0);
return false;
}
}
}
4、跟进窗口WindowsClassName举获取主窗体句柄
//查找桌面
[DllImport("User32.dll", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
public static extern IntPtr GetDesktopWindow();
//获取窗体句柄
[DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
public static extern IntPtr GetWindow(IntPtr hwnd, int wFlag);
//获取窗体类
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
public const int GW_CHILD = 5;
public const int GW_HWNDNEXT = 2;
//枚举桌面窗口,根据WindowsClassName获取句柄
[SecuritySafeCritical]
public static IntPtr GetWinHandleByClasName(String windowClassNmae)
{
//取得桌面窗口,再获取第一个子窗口
IntPtr hwnd = GetDesktopWindow();
hwnd = GetWindow((IntPtr)hwnd, System.Convert.ToInt32(GW_CHILD));
//通过循环来枚举所有的子窗口
while ((long)hwnd != 0)
{
System.Text.StringBuilder ClassName = new System.Text.StringBuilder(256);
GetClassName((IntPtr)hwnd, ClassName, ClassName.Capacity);
String tmpClassName= ClassName.ToString().Trim();
if (tmpClassName.Length > 0)
{
if (tmpClassName.Equals(windowClassNmae))
{
break;
}
}
hwnd = GetWindow((IntPtr)hwnd, System.Convert.ToInt32(GW_HWNDNEXT));
}
return hwnd;
}
由于很变态的中国式需求,我们需要在自己的网站中,嵌入第三方厂商的网站。
而这个第三方的网站中,使用了几层的iFrame,同时使用了基于IE的Activex控件。
由于双方的控件风格差距太大,所以需要替换CSS样式,同时要删掉部分与我们网站冲突的内容。
想了几种方法:
1、说服对方进行调整,但经过接触,了解到其超级不靠谱,只能靠自己了。
2、直接通过iFrame嵌入对方网站,用JS进行修改。可是跨站修改,浏览器不同意啊。
3、自己写个控件,嵌入到自己网页中,在控件中调用对方URL,并通过WebBrowser控件修改CSS及HTML。问题是,IE中,不能再直接嵌入一个WebBrowser控件,主要出于安全考虑。(如果IE允许这样操作的话,我只需要在WebBrowser中指向同一个URL,就可以无限调用,耗光资源,其他的事情,有太多可以做了)自己用很挫的方法实现了这个功能,后来考虑到稳定性,放弃了。
4、使用非基于IE的Web插件,在控件中调用对方URL,并通过控件修改CSS及HTML。比如Flash或者CefSharp,但问题是,非IE核心如何调用Activex控件啊。
5、限制入口,基于WebBrowser定制IE浏览器
最后使用了方法5,说实话,真烦。
这里把通过WebBrowser修改CSS及HTML的方法说一下,下面是我写的一段测试用代码,请按自己的实际情况修改:
//替换样式
//webMain是WebBrowser控件的名称
//NewStyle.css中是要替换的样式
private void modifyStyle()
{
int frameNum = webMain.Document.Window.Frames.Count;
if (frameNum == 2)
{
IHTMLDocument2 leftIFrame = webMain.Document.Window.Frames[0].Document.DomDocument as IHTMLDocument2;
int length = leftIFrame.styleSheets.length;
IHTMLStyleSheet styleSheet = leftIFrame.createStyleSheet(@"", length + 1);
TextReader reader = new StreamReader(Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "NewStyle.css"));
string style = reader.ReadToEnd();
styleSheet.cssText = style;
}
}
//删除tree节点下的div,只保留特定的一个节点
private void delDiv(String flowid)
{
int frameNum = webMain.Document.Window.Frames.Count;
if (frameNum == 2)
{
IHTMLDocument3 leftIFrame = webMain.Document.Window.Frames[0].Document.DomDocument as IHTMLDocument3;
foreach (dynamic e in leftIFrame.getElementById("tree").children)
{
String ret = e.InnerText;
if (!ret.Contains(flowid))
{
e.parentNode.removeChild(e);
}
}
}
}