/*--------------------------------------------------------
STRPROG.C -- Program using STRLIB dynamic-link library
(c) Charles Petzold, 1998
--------------------------------------------------------*/
#include <windows.h>
#include "strlib.h"
#include "resource.h"
typedef struct
{
HDC hdc ;
int xText ;
int yText ;
int xStart ;
int yStart ;
int xIncr ;
int yIncr ;
int xMax ;
int yMax ;
}
CBPARAM ;
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
TCHAR szAppName [] = TEXT ("StrProg") ;
TCHAR szString [MAX_LENGTH + 1] ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = szAppName ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("DLL Demonstration Program"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
BOOL CALLBACK DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
// 向对话框中的文本输入控件发送EM_LIMITTEXT消息,规定用户最大输入字符数为MAX_LENGTH常量
SendDlgItemMessage (hDlg, IDC_STRING, EM_LIMITTEXT, MAX_LENGTH, 0) ;
return TRUE ;
case WM_COMMAND:
switch (wParam)
{
case IDOK:
// 读取文本输入控件中的字符串到szString全局缓冲区中
GetDlgItemText (hDlg, IDC_STRING, szString, MAX_LENGTH) ;
EndDialog (hDlg, TRUE) ;
return TRUE ;
case IDCANCEL:
EndDialog (hDlg, FALSE) ;
return TRUE ;
}
}
return FALSE ;
}
BOOL CALLBACK GetStrCallBack (PTSTR pString, CBPARAM * pcbp)
{
// 输出字符串
TextOut (pcbp->hdc, pcbp->xText, pcbp->yText,
pString, lstrlen (pString)) ;
// 输出y坐标递增一个字符高度,并与窗口可输出最大行比较
// 如果输出行已到最大行,则执行
if ((pcbp->yText += pcbp->yIncr) > pcbp->yMax)
{
// 使y坐标指向第一行
pcbp->yText = pcbp->yStart ;
// x坐标增加一行字符串最大宽度,并与可输出最大列比较
// 如果输出已到最大行和最大列,则返回FALSE
if ((pcbp->xText += pcbp->xIncr) > pcbp->xMax)
return FALSE ;
}
return TRUE ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HINSTANCE hInst ;
static int cxChar, cyChar, cxClient, cyClient ;
static UINT iDataChangeMsg ;
CBPARAM cbparam ;
HDC hdc ;
PAINTSTRUCT ps ;
TEXTMETRIC tm ;
switch (message)
{
case WM_CREATE:
hInst = ((LPCREATESTRUCT) lParam)->hInstance ;
hdc = GetDC (hwnd) ;
GetTextMetrics (hdc, &tm) ;
cxChar = (int) tm.tmAveCharWidth ;
cyChar = (int) (tm.tmHeight + tm.tmExternalLeading) ;
ReleaseDC (hwnd, hdc) ;
// 注册字符串更改消息
iDataChangeMsg = RegisterWindowMessage (TEXT ("StrProgDataChange")) ;
return 0 ;
case WM_COMMAND:
switch (wParam)
{
case IDM_ENTER:
// 创建输入对话框
if (DialogBox (hInst, TEXT ("EnterDlg"), hwnd, &DlgProc))
{
// 添加用户输入的字符串到共享内存的字符串数组中
if (AddString (szString))
// 将程序注册的消息发送给所有窗口,用于通知使用共享内存的其它程序
PostMessage (HWND_BROADCAST, iDataChangeMsg, 0, 0) ;
else
MessageBeep (0) ;
}
break ;
case IDM_DELETE:
// 创建删除对话框
if (DialogBox (hInst, TEXT ("DeleteDlg"), hwnd, &DlgProc))
{
if (DeleteString (szString))
PostMessage (HWND_BROADCAST, iDataChangeMsg, 0, 0) ;
else
MessageBeep (0) ;
}
break ;
}
return 0 ;
case WM_SIZE:
cxClient = (int) LOWORD (lParam) ;
cyClient = (int) HIWORD (lParam) ;
return 0 ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
// 初始化输出字符串所需要的数据
cbparam.hdc = hdc ;
cbparam.xText = cbparam.xStart = cxChar ;
cbparam.yText = cbparam.yStart = cyChar ;
cbparam.xIncr = cxChar * MAX_LENGTH ;
cbparam.yIncr = cyChar ;
cbparam.xMax = cbparam.xIncr * (1 + cxClient / cbparam.xIncr) ;
cbparam.yMax = cyChar * (cyClient / cyChar - 1) ;
// 输出字符串
GetStrings ((GETSTRCB) GetStrCallBack, (PVOID) &cbparam) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
default:
// 广播消息,刷新客户区
if (message == iDataChangeMsg)
InvalidateRect (hwnd, NULL, TRUE) ;
break ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
/*------------------------------------------------
STRLIB.C -- Library module for STRPROG program
(c) Charles Petzold, 1998
------------------------------------------------*/
#include <windows.h>
#include <wchar.h> // for wide-character string functions
#include "strlib.h"
// 创建名为shared的共享数据段
#pragma data_seg ("shared")
// 必须对数据初始化,否则编译器将把它们放在普通的未初始化数据段中
int iTotal = 0 ;
WCHAR szStrings [MAX_STRINGS][MAX_LENGTH + 1] = { '/0' } ;
#pragma data_seg () // 共享数据段结束
//#pragma comment(linker,"/SECTION:shared,RWS")
int WINAPI DllMain (HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
{
return TRUE ;
}
EXPORT BOOL CALLBACK AddStringA (PCSTR pStringIn)
{
BOOL bReturn ;
int iLength ;
PWSTR pWideStr ;
/* MultiByteToWideChar 映射一个字符串到一个宽字符(unicode)的字符串
CP_ACP:ANSI代码页;
参数二: 一组位标记用以指出是否未转换成预作或宽字符(若组合形式存在)
是否使用象形文字替代控制字符,以及如何处理无效字符
缺省动作是转换成预作的形式;
pStringIn 指向将被转换字符串的字符;
-1 字符串将被设定为以NULL为结束符的字符串,并且自动计算长度;
NULL 为指定用于接收的缓冲区;
0 函数返回缓冲区所必需的宽字符数 */
iLength = MultiByteToWideChar (CP_ACP, 0, pStringIn, -1, NULL, 0) ;
// 分配内存,实际转换
pWideStr = malloc (iLength) ;
MultiByteToWideChar (CP_ACP, 0, pStringIn, -1, pWideStr, iLength) ;
// 调用自定义宽字符处理函数做实际处理
bReturn = AddStringW (pWideStr) ;
free (pWideStr) ;
return bReturn ;
}
EXPORT BOOL CALLBACK AddStringW (PCWSTR pStringIn)
{
PWSTR pString ;
int i, iLength ;
// 依字符串总数做有效性检查
if (iTotal == MAX_STRINGS - 1)
return FALSE ;
// 返回宽字符串长度,并做有效性检查
if ((iLength = wcslen (pStringIn)) == 0)
return FALSE ;
// 分配字符串内存
pString = malloc (sizeof (WCHAR) * (1 + iLength)) ;
// 复制字符串
wcscpy (pString, pStringIn) ;
// 将复制的字符串转换为大写
_wcsupr (pString) ;
// Alphabetize the strings
for (i = iTotal ; i > 0 ; i--)
{
// 如果pString 大于或等于 szStrings[i - 1] ,则退出排序
if (wcscmp (pString, szStrings[i - 1]) >= 0)
break ;
// 字符串数组预留位置
wcscpy (szStrings[i], szStrings[i - 1]) ;
}
// 复制新字符串到字符串数组
wcscpy (szStrings[i], pString) ;
// 字符串计数加一
iTotal++ ;
free (pString) ;
return TRUE ;
}
EXPORT BOOL CALLBACK DeleteStringA (PCSTR pStringIn)
{
BOOL bReturn ;
int iLength ;
PWSTR pWideStr ;
// 和添加函数一样,转换字符串为宽字符串,并使用宽字符串处理函数来实作
iLength = MultiByteToWideChar (CP_ACP, 0, pStringIn, -1, NULL, 0) ;
pWideStr = malloc (iLength) ;
MultiByteToWideChar (CP_ACP, 0, pStringIn, -1, pWideStr, iLength) ;
bReturn = DeleteStringW (pWideStr) ;
free (pWideStr) ;
return bReturn ;
}
EXPORT BOOL CALLBACK DeleteStringW (PCWSTR pStringIn)
{
int i, j ;
// 判断是否输入字符串
if (0 == wcslen (pStringIn))
return FALSE ;
for (i = 0 ; i < iTotal ; i++)
{
// 如果 szStrings[i] 等于 pStringIn ,_wcsicmp的返回值为0
if (_wcsicmp (szStrings[i], pStringIn) == 0)
break ;
}
// 如果因为循环判断公式错误而退出循环,表明给定的字符串不在列表中
if (i == iTotal)
return FALSE ;
// 否者从找到的字符串开始,向下重排
for (j = i ; j < iTotal ; j++)
wcscpy (szStrings[j], szStrings[j + 1]) ;
// 删除之前的字符串数组尾,调整字符串计数
szStrings[iTotal--][0] = '/0' ;
return TRUE ;
}
EXPORT int CALLBACK GetStringsA (GETSTRCB pfnGetStrCallBack, PVOID pParam)
{
BOOL bReturn ;
int i, iLength ;
PSTR pAnsiStr ;
for (i = 0 ; i < iTotal ; i++)
{
// 转换成宽字符串
iLength = WideCharToMultiByte (CP_ACP, 0, szStrings[i], -1, NULL, 0,
NULL, NULL) ;
pAnsiStr = malloc (iLength) ;
WideCharToMultiByte (CP_ACP, 0, szStrings[i], -1, pAnsiStr, iLength,
NULL, NULL) ;
// 调用主程序的回调函数
bReturn = pfnGetStrCallBack (pAnsiStr, pParam) ;
// 如果输出超出屏幕大小,则退出函数
if (bReturn == FALSE)
return i + 1 ;
free (pAnsiStr) ;
}
return iTotal ;
}
EXPORT int CALLBACK GetStringsW (GETSTRCB pfnGetStrCallBack, PVOID pParam)
{
BOOL bReturn ;
int i ;
for (i = 0 ; i < iTotal ; i++)
{
bReturn = pfnGetStrCallBack (szStrings[i], pParam) ;
if (bReturn == FALSE)
return i + 1 ;
}
return iTotal ;
}
/*----------------------
STRLIB.H header file
----------------------*/
// 如果程序是CPP程序
#ifdef __cplusplus
// 告诉编译器用C的方式来链接
#define EXPORT extern "C" __declspec (dllexport)
#else
/* __declspec(dllexport) 声明一个导出函数,一般用于dll中
__declspec(dllimport) 声明一个导入函数,一般用于使用某个dll的exe中 */
#define EXPORT __declspec (dllexport)
#endif
// The maximum number of strings STRLIB will store and their lengths
#define MAX_STRINGS 256
#define MAX_LENGTH 64
// The callback function type definition uses generic strings
typedef BOOL (CALLBACK * GETSTRCB) (PCTSTR, PVOID) ;
// Each function has ANSI and Unicode versions
EXPORT BOOL CALLBACK AddStringA (PCSTR) ;
EXPORT BOOL CALLBACK AddStringW (PCWSTR) ;
EXPORT BOOL CALLBACK DeleteStringA (PCSTR) ;
EXPORT BOOL CALLBACK DeleteStringW (PCWSTR) ;
EXPORT int CALLBACK GetStringsA (GETSTRCB, PVOID) ;
EXPORT int CALLBACK GetStringsW (GETSTRCB, PVOID) ;
// Use the correct version depending on the UNICODE identifier
#ifdef UNICODE
#define AddString AddStringW
#define DeleteString DeleteStringW
#define GetStrings GetStringsW
#else
#define AddString AddStringA
#define DeleteString DeleteStringA
#define GetStrings GetStringsA
#endif
//资源文件
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/
#undef APSTUDIO_READONLY_SYMBOLS
/
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h/0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""/r/n"
"/0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"/r/n"
"/0"
END
#endif // APSTUDIO_INVOKED
/
//
// Dialog
//
ENTERDLG DIALOG DISCARDABLE 20, 20, 186, 47
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Enter"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "&Enter:",IDC_STATIC,7,7,26,9
EDITTEXT IDC_STRING,31,7,148,12,ES_AUTOHSCROLL
DEFPUSHBUTTON "OK",IDOK,32,26,50,14
PUSHBUTTON "Cancel",IDCANCEL,104,26,50,14
END
DELETEDLG DIALOG DISCARDABLE 20, 20, 186, 47
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Delete"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "&Delete:",IDC_STATIC,7,7,26,9
EDITTEXT IDC_STRING,31,7,148,12,ES_AUTOHSCROLL
DEFPUSHBUTTON "OK",IDOK,32,26,50,14
PUSHBUTTON "Cancel",IDCANCEL,104,26,50,14
END
/
//
// Menu
//
STRPROG MENU DISCARDABLE
BEGIN
MENUITEM "&Enter!", IDM_ENTER
MENUITEM "&Delete!", IDM_DELETE
END
/
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
"ENTERDLG", DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 40
END
"DELETEDLG", DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 40
END
END
#endif // APSTUDIO_INVOKED
#endif // English (U.S.) resources
/
#ifndef APSTUDIO_INVOKED
/
//
// Generated from the TEXTINCLUDE 3 resource.
//
/
#endif // not APSTUDIO_INVOKED
VS2010 项目配置
修改项目的依赖关系
在项目名称上点击右键,选择项目依赖项。如图:
设置项目的DLL文件依赖
在主程序的项目名称上点击右键,选择属性。在新窗口中点击 配置属性->链接器->输入,右边的 附加依赖项 中写入需要引入的DLL文件的链接文件(*.lib)。如图:
设置共享内存节的特性
选择 DLL 项目的属性,配置属性->链接器->常规->指定节特性。如图:
字母 RWS 表示数据段具有读、写和共享属性。
也可以直接用DLL原始码指定连结选项
#pragma comment(linker,"/SECTION:shared,RWS")