concentrate on c/c++ related technology

plan,refactor,daily-build, self-discipline,

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  37 Posts :: 1 Stories :: 12 Comments :: 0 Trackbacks

常用链接

留言簿(9)

我参与的团队

搜索

  •  

最新评论

阅读排行榜

评论排行榜

#

我在MSVC6里的win32 console工程里面写了一段这样的代码,已经去掉了不必要的代码已达到注意重点地目点:
#include  <winbase.h>
#include  <windows.h>
switch( dwWaitResult = ::SignalObjectAndWait(
                                   m_hLogItemSendEvent,
                                   m_hLogItemReceivedEvent,
                                   MUTEX_LOCK_TIMEOUT,
                                   FALSE ) )
    {
    case WAIT_OBJECT_0:
               ::ResetEvent( m_hLogItemReceivedEvent );
               ::ResetEvent( m_hLogItemSendEvent );
    break;
    case WAIT_TIMEOUT:
    throw AutoLock::CAutoLockTimeoutExc( MUTEX_LOCK_TIMEOUT * 10 );
    break;
    default:
    throw AutoLock::CAutoLockWaitExc( dwWaitResult, ::GetLastError() );
    }
编译以后,得到以下两个错误:

error C2039: 'SignalObjectAndWait' : is not a member of '`global namespace''
error C2065: 'SignalObjectAndWait' : undeclared identifier

我在msdn上面已经查找到了SignalObjectAndWait在winbase里面声明,而在windows里面定义的。但是我在上面的代码片断里面已经给出了相关头文件。却在编译的时候出现两个错误。

问题解决如下:
#if(_WIN32_WINNT >= 0x0400)
WINBASEAPI
DWORD
WINAPI
SignalObjectAndWait(
    IN HANDLE hObjectToSignal,
    IN HANDLE hObjectToWaitOn,
    IN DWORD dwMilliseconds,
    IN BOOL bAlertable
    );
#endif /* _WIN32_WINNT >= 0x0400 */
在我英文操作系统里面的版本过低,导致出现无法进入上述条件编译里面,因此需要做的事情是,要么将条件编译注释掉,其实问题也不大,反正以后也不会有什么变动,要么就是在stdafx.h最前面重新定义一个_WIN32_WINNT,并且这个定义值应该要大于或者等于0x0400.这样才是okay的。
一些其他信息:
http://topic.csdn.net/u/20080429/16/c12ef43a-5eba-435e-b0bf-f49233cf1d5e.html
http://www.codeguru.com/forum/showthread.php?t=451931


posted @ 2008-04-29 19:38 jolley 阅读(711) | 评论 (0)编辑 收藏

在vc6里面一般都没有这个头文件的,在后面的版本(.NET)都有相关的说明,不过这个是CString包含的头文件,我之前将open source的代码移植到win32 application平台下面,对方的编译器是vc2003,而我的是用到了vc6,所以就遇到这个问题了,解决办法有两种:
1)在工程里面加入MFCsupport,因为CString是MFC里面的内容。具体做法是project/settings/General/microsoft foundation class处选择using MFC as a shared dll./ static library.
在msdn上面有具体的说明。
可能看起来比较麻烦,不过不好意思,就这样弄过来防止msdn上面这个文章过旧了,又被删除了。

给 ATL EXE 项目添加 MFC 支持



1. 在包括 Atlbase.h 之前,将以下 #include 指令添加到 StdAfx.h:
      #include <afxwin.h>   // MFC core and standard components
            #include <afxext.h>   // MFC extensions
            #include <afxdisp.h>  // MFC Automation extensions
2. 更改项目设置以使用 MFC。 在 Project Settings 对话框中,单击 General 选项卡,然后将 Microsoft Foundation Classes 列表框中的设置更改为 MFC。
3. 添加 CWinApp 衍生类,并声明一个该类型的全局变量,如下所示:
class CMyApp : public CWinApp
            {
            public:
            virtual BOOL InitInstance();
            virtual int ExitInstance();
            protected:
            BOOL m_bRun;
            };
4. 用以下 InitInstance 和 ExitInstance 代码替换 _tWinMain 函数:
BOOL CMyApp::InitInstance()
            {
            // Initialize OLE libraries.
            if (!AfxOleInit())
            {
            AfxMessageBox(_T("OLE Initialization Failed!"));
            return FALSE;
            }
            // Initialize CcomModule.
            _Module.Init(ObjectMap, m_hInstance);
            _Module.dwThreadID = GetCurrentThreadId();
            // Check command line arguments.
            TCHAR szTokens[] = _T("-/");
            m_bRun = TRUE;
            LPCTSTR lpszToken = FindOneOf(m_lpCmdLine, szTokens);
            while (lpszToken != NULL)
            {
            // Register ATL and MFC class factories.
            if (lstrcmpi(lpszToken, _T("Embedding"))==0 ||
            lstrcmpi(lpszToken, _T("Automation"))==0)
            {
            AfxOleSetUserCtrl(FALSE);
            break;
            }
            // Unregister servers.
            // There is no unregistration code for MFC
            // servers. Refer to <LINK TYPE="ARTICLE" VALUE="Q186212">Q186212</LINK> "HOWTO: Unregister MFC
            // Automation Servers" for adding unregistration
            // code.
            else if (lstrcmpi(lpszToken, _T("UnregServer"))==0)
            {
            VERIFY(SUCCEEDED(_Module.UpdateRegistryFromResource(IDR_ServerS2B, FALSE)));
            VERIFY(SUCCEEDED(_Module.UnregisterServer(TRUE)));
            m_bRun = FALSE;
            break;
            }
            // Register ATL and MFC objects in the registry.
            else if (lstrcmpi(lpszToken, _T("RegServer"))==0)
            {
            VERIFY(SUCCEEDED(_Module.UpdateRegistryFromResource(IDR_ServerS2B, TRUE)));
            VERIFY(SUCCEEDED(_Module.RegisterServer(TRUE)));
            COleObjectFactory::UpdateRegistryAll();
            m_bRun = FALSE;
            break;
            }
            lpszToken = FindOneOf(lpszToken, szTokens);
            }
            if (m_bRun)
            {
            // Comment out the next line if not using VC 6-generated
            // code.
            _Module.StartMonitor();
            VERIFY(SUCCEEDED(_Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE)));
            VERIFY(COleObjectFactory::RegisterAll());
            // To run the EXE standalone, you need to create a window
            // and assign the CWnd* to m_pMainWnd.
            LPCTSTR szClass = AfxRegisterWndClass(NULL);
            m_pMainWnd = new CWnd;
            m_pMainWnd->CreateEx(0, szClass, _T("SomeName"), 0, CRect(0, 0, 0, 0), NULL, 1234);
            }
            return TRUE;
            }
            int CMyApp::ExitInstance()
            {
            // MFC's class factories registration is
            // automatically revoked by MFC itself.
            if (m_bRun)
            {
            _Module.RevokeClassObjects();
            Sleep(dwPause); //wait for any threads to finish
            }
            _Module.Term();
            return 0;
            }
5. 对于 Unicode 版本,请确保进入点被设置为 wWinMainCRTStartup,该设置在 Project Settings 对话框中 Link 字段的 Output 类别中。 有关其它信息,请参见 Microsoft Knowledge Base 中的下列文章:
125750 (http://support.microsoft.com/kb/125750/EN-US/) PRB: 错误 LNK2001: “_WinMain@16”: 不能解析的外部符号
6. 将以下代码行添加到 COM 接口、窗口过程和导出函数的每个成员函数的开头:
AFX_MANAGE_STATE(AfxGetAppModuleState());
有关 AFX_MANAGE_STATE 的详细信息,请查询 VC++ 联机文档。
有关将 MFC 支持添加到 ATL COM AppWizard 项目的详细信息,请参见下面的 Microsoft Knowledge Base 文章:

181505 (http://support.microsoft.com/kb/181505/EN-US/) PRB: ATL COM AppWizard 不提供对 .EXE 的 MFC 支持

回到顶端

将 MFC 支持添加到 ATL DLL 项目



执行上面的步骤 1 到步骤 3。

1. 将 AppWizard 生成的 DllMain 的 DLL_PROCESS_ATTACH 和 DLL_PROCESS_DETACH 中的代码移到 CMyApp 的 InitInstance 和 ExitInstance,并删除 DllMain,如下所示:
      BOOL CMyApp::InitInstance()
            {
            _Module.Init(ObjectMap, m_hInstance);
            return CWinApp::InitInstance();
            }
            int CMyApp::ExitInstance()
            {
            // MFC's class factories registration is
            // automatically revoked by MFC itself.
            if (m_bRun)
            _Module.RevokeClassObjects();
            
2. 将以下代码行添加到 COM 接口、窗口过程和导出函数的每个成员函数的开头:
AFX_MANAGE_STATE(AfxGetStaticModuleState());
有关其它信息,请参见 Microsoft Knowledge Base 中的下列文章:
140850 (http://support.microsoft.com/kb/140850/EN-US/) HOWTO: 转换 DLLTRACE 以使用共享库中的 MFC

另外一种办法就是将atlstr废掉,采用其他办法
因为atlstr实际起作用的是CString,而如果能够找到CString的替代方案,就可以了。
替代方案在这里:
http://www.codeguru.com/forum/showthread.php?t=402543
一般建议用std::string来完成这些不依赖微软某种技术的做法。
在我的项目里面,因为采用的是win32 application工程,并且该项目已经很大了,不想因为这个而在那里增加一些方案1的处理,我采用了方案2。
posted @ 2008-04-29 10:14 jolley 阅读(7999) | 评论 (0)编辑 收藏

进程1:

#define BUF_SIZE 256
char fileMapObjectName[] = "FileMappingObject";
class Sample
{
public:
 void set_x(int x){this->xx = x;}
 int get_x(){return this->xx;}
 Sample(){}
private:
 int xx;
};

class EmulatorWindow
{
public:
 void set_ew(Sample s){this->sample = s;}
 Sample get_ew(){return this->sample;}
 EmulatorWindow(){}
private:
 Sample sample;
};

int main()
{
 HANDLE fileMap = CreateFileMapping(
  (HANDLE)0xFFFFFFFF,
  NULL,
  PAGE_READWRITE,
  0,
  BUF_SIZE,
  fileMapObjectName);
 if (NULL == fileMap || GetLastError() == ERROR_ALREADY_EXISTS)
 {
  printf("create file mapping fails! the error code is (%d)",GetLastError());
  return 0;
 }
 Sample s;
 s.set_x(112);
 EmulatorWindow* buffer = (EmulatorWindow*)MapViewOfFile(
  fileMap,
  FILE_MAP_ALL_ACCESS,
  0,
  0,
  BUF_SIZE);
 if (NULL == buffer)
 {
  printf("mapping view of file fails! the error code is (%d)",GetLastError());
  return 1;
 }

 EmulatorWindow ew;
 ew.set_ew(s);

 CopyMemory(buffer,&ew,BUF_SIZE);
 getchar();

 FlushViewOfFile(fileMap,BUF_SIZE);

 UnmapViewOfFile(buffer);
 buffer = NULL;

 CloseHandle(fileMap);
 fileMap = NULL;
 
 return 2;
}  
进程2:
#define BUF_SIZE 256
char fileMapObjectName[] = "FileMappingObject";

class Sample
{
public:
 void set_x(int x){this->xx = x;}
 int get_x(){return this->xx;}
 Sample(){}
private:
 int xx;
};

class EmulatorWindow
{
public:
 void set_ew(Sample s){this->sample = s;}
 Sample get_ew(){return this->sample;}
 EmulatorWindow(){}
private:
 Sample sample;
};

int main()
{
 HANDLE fileMap = OpenFileMapping(
  FILE_MAP_ALL_ACCESS,
  TRUE,
  fileMapObjectName);
 if (NULL == fileMap)
 {
  printf("opening file mapping fails! the error code is (%d)",GetLastError());
  return 0;
 }
  
 EmulatorWindow* sharedMemory = (EmulatorWindow*)MapViewOfFile(
  fileMap,
  FILE_MAP_ALL_ACCESS,
  0,
  0,
  0);
 if (NULL == sharedMemory )
 {
  printf("mapping view of file fails! the error code is (%d)",GetLastError());
  return 1;
 }

 Sample s = sharedMemory->get_ew();
 int x = s.get_x();

 char buffer[100];
 memset(buffer,0,100);
 sprintf(buffer,"message box is:(%d)",x);
 MessageBox(NULL,buffer,NULL,MB_OK);

 UnmapViewOfFile(sharedMemory);
 sharedMemory = NULL;

 CloseHandle(fileMap);
 fileMap = NULL;

 return 3;

}
1)
这是两个比较简单的文件映射例子,其中进程1为源进程,而进程2为目的进程。进程1与进程2进行通信,并且共享一个窗口对象,记得在游戏里面会有很多窗口对象的,因此,在与游戏进行通信的时候就可以共享窗口对象。前段时间在做自动化测试的时候,就经常要与客户端进行一些交互操作,比如,获得某个窗口的按钮状态,以及文本的信息等,不过这样做的代价是两个进程要共享一部分头文件,起码像我两个进程里面都用到了两段相同的头文件代码,不然可能就出现某个窗口对象或者控件对象未声明或者未定义。

2)
另外值得说明的是进程1里面的getchar()用法,很多时候,这个用来延迟操作,并且防止运行过快,特别是在很简单的结果输出中,结果会一闪而过,这个时候getchar就起作用了。这里的getchar所起的作用也是延迟的,不过如果将这个getchar()去掉的话,那么你就很可能得到GetLastError()错误代码为2。ERROR_FILE_NOT_FOUND.这个原因是在建立文件对象以后,没有一段时间缓冲的话,那么进程2有可能找不到在进程空间里面的文件映射,因此就会说ERROR_FILE_NOT_FOUND的错误。

3)
之前认为共享内存嘛,应该是可以共享任何对象的,但是我在共享一个deque的时候,发现错了,后来才发现文件映射不能共享指针的,deque是STL的一个序列式容器,而其内部都是一系列的指针组成的,后来在msdn上面发现了一段这样的话,很震惊:

Do not store pointers in the memory mapped file; store offsets from the base of the file mapping so that the mapping can be used at any address.
可以共享的是非指针的用户自定义类型, 以及内建类型等,不包括含有指针的各种类型。


   


 

posted @ 2008-04-24 17:04 jolley 阅读(1412) | 评论 (0)编辑 收藏

     摘要: 绘制管线
应用程序阶段
几何阶段 模型和视点变换/光照/投影/裁减/屏幕映射
光栅阶段
  阅读全文
posted @ 2008-04-24 09:12 jolley 阅读(695) | 评论 (1)编辑 收藏

这回贴上来自codeguru上面的一篇讨论,感觉很舒服:
   

I’ve created a very simple Win32 DLL. It only has one exported function called “Test” whose declaration looks like this:-

#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif


MYDLL_API HRESULT Test(void);
Then in the source file:-

MYDLL_API HRESULT Test(void)
{
return (HRESULT) 66;
}


Now in my executable, I’ve done this:-

static HMODULE hDLL;
typedef HRESULT (STDAPICALLTYPE * LPFNTEST) (void);
LPFNTEST _pfnTest;

Then I load the DLL:-

hDLL = LoadLibrary("MyDLL.dll");

All the above works fine and hDLL gets a non-NULL value . Now I come to obtain the proc address for function “Test”:-

_pfnTest = (LPFNTEST)::GetProcAddress(hDLL, "Test");
but _pfnTest ends up as NULL and GetLastError() returns 127 (ERROR_PROC_NOT_FOUND). What have I done wrong?? I haven't implemented any code yet in DllMain(). For example, I haven't initialised anything. Should I have done?


Siddhartha

February 20th, 2006, 11:18 AM

but _pfnTest ends up as NULL and GetLastError() returns 127 (ERROR_PROC_NOT_FOUND). What have I done wrong?? You have not accounted for the name decoration that the VC++ Compiler has subjected your DLL's Exported Functions to.

To know exactly what it has done, open the DLL in Dependency Walker and observe exported function names...

www.dependencywalker.com (http://www.dependencywalker.com) (for latest version)
You either need to GetProcAddress of the functions using their decorated names, or better - create entries in your DLL Project's DEF File that define the names of the exported functions the way you would like to see them as.

Something like this -
LIBRARY "MYDLL"

EXPORTS
Test PRIVATE


Bornish

February 20th, 2006, 11:18 AM

Your function is exported using the C++ decorated name. Use extern "C" before the function prototype, or use a *.def file in your project containing:EXPORTS
TestTo know for sure that your function is exported with an undecorated name, use Dependency Viewer to list its exports.

Note: I've noticed another potential problem, which will not affect this test function since has no parameters, but your dll declares the function as __cdecl (depending on your project's default settings), and the exe tries to use it with STDAPICALLTYPE which I assume stands for __stdcall calling convention.

Regards,


John E

February 20th, 2006, 11:31 AM

Thanks guys. It's ages since I wrote a DLL. It's all starting to come back to me now!! :wave:


John E

February 23rd, 2006, 04:51 PM

Hmmm.... this still isn't quite right. According to this MSDN article (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccelng/htm/msmod_20.asp) the use of dllimport and dllexport should eliminate the need to specify exported functions in a module definition file (.DEF)

However, in my case, that's not working. I'm finding that I still need to list the functions as EXPORTS in a .DEF file - even though I'm correctly defining __declspec(dllimport) and __declspec(dllexport). Any ideas about what I might be doing wrong?


Paul McKenzie

February 23rd, 2006, 05:06 PM

Hmmm.... this still isn't quite right. According to this MSDN article (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccelng/htm/msmod_20.asp) the use of dllimport and dllexport should eliminate the need to specify exported functions in a module definition file (.DEF)Only if you are linking with the export library, in other words, you're using Visual C++ and you add the .lib to your project.

If you're using LoadLibrary() and GetProcAddress(), there is no .lib file to help the linker resolve the name. You must either use the *exact* name you see in the exported function list when you ran Dependency Walker, or you use a def file and rebuild your DLL to get a totally "clean" function name.

Regards,

Paul McKenzie


Bornish

February 23rd, 2006, 05:07 PM

If you use __declspec(dllexport) you don't need the def file.
In fact, with only a def file you might get into an ambiguous name situation (like it happen to me before), when a class declared a method with the same name of the global exported function. The solution was to use __declspec(dllexport) for the global function.
The problem we suggested you might have was that your function was exported with a C++ decorated name. Thus, you need to use extern "C" before __declspec(dllexport).
Got to go now... :)
Regards,


John E

February 23rd, 2006, 05:22 PM

Only if you are linking with the export library, in other words, you're using Visual C++ and you add the .lib to your project.You mean if I link statically, rather than dynamically?

Surely if I link statically, there's no need to mess about with dllimport and dllexport at all??


VladimirF

February 23rd, 2006, 05:28 PM

Paul wasn't talking about static link, he compared dynamic linking with on-demand GetProcAddress() call.


kirants

February 23rd, 2006, 05:36 PM

Hmmm.... this still isn't quite right. According to this MSDN article (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccelng/htm/msmod_20.asp) the use of dllimport and dllexport should eliminate the need to specify exported functions in a module definition file (.DEF)

However, in my case, that's not working.

I don't think that is the case. It is not working because you are doing a GetProcAddress with non-mangled name while using dllexport without using a def file causes name mangling and hence the failure.

The reason it works when you add the .def file with the names is because you are putting the name in unmangled form in it and that is what you are using in GetProcAddress.

So, summary si this:
if you use dllexport approach without def file, please understand that the Visual C++ compiler mangles the name and this is the form in which your function will be exported. For e.g. your Test function will be exported as , ?Test@XWZ or something of that form. So, if you do a GetProcAddress, make sure you use "?Test@XWZ" and not "Test".
If you use dllexport, but also supply a .def file with the undeclared names, the linker is gonna put that in the dll export section. So, you can now use GetProcAddress(hMod,"Test")
If you do use .def file, there is no need to use dllexport directive
If you do not want to use .def file and still want to use dllexport directive, wrap those functions with

extern "C"
{

}


kirants

February 23rd, 2006, 05:38 PM

You mean if I link statically, rather than dynamically?

A dll is always dynamically linked. What Paul was referring to was implicit linking versus explicit linking via LoadLibrary/GetprocAddress


John E

February 23rd, 2006, 05:48 PM

Thanks for the help. I did realise that the problem was because of decorated names. What I didn't realise was that I had to link to the lib if I used __declspec(dllexport).... I've managed to get it to work now, without the DEF file :wave:


kirants

February 23rd, 2006, 05:52 PM

What I didn't realise was that I had to link to the lib if I used __declspec(dllexport)
No. using dllexport does not mean you have to link to the .lib file.

Whether you use dllexport or def file, you will always be able to use LoadLibrary/GetProcAddress approach , provided you pass the right export name to GetProcAddress


John E

February 23rd, 2006, 05:55 PM

Oops... one other thing, just before I shoot myself in the foot...!

Ultimately, this DLL will be going to someone who'll be calling it from Visual Basic .NET. This means that my lib file would be useless to them. Therefore, I guess I'm better off sticking to the .DEF approach on this occasion because I don't really want the names to be mangled.


MikeAThon

February 23rd, 2006, 11:59 PM

A dll is always dynamically linked. What Paul was referring to was implicit linking versus explicit linking via LoadLibrary/GetprocAddress
I think that Microsoft refers to these as "run-time dynamic linking" vs. "load-time dynamic linking". See http://msdn.microsoft.com/library/en-us/dllproc/base/using_dynamic_link_libraries.asp

Mike


kirants

February 24th, 2006, 12:29 AM

Interesting, Mike.. ... Microsoft seems to be using different terms for the same :)

For e.g. see here
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_core_determine_which_linking_method_to_use.asp


MikeAThon

February 24th, 2006, 01:28 AM

You're right: that is the same thing, and Microsoft is using different terminology for it.

Mike


gopal.srini

February 24th, 2006, 02:49 AM

Hi

Continuing with this topic, could any one please tell me how to call a method from ddao35.dll, say - OpenDatabase whose return type is class- CdbDatabase - using __declspec( dllexport ), they have exported this function available in dbdao.h file

I tried the follwoing but in vain

typedef UINT (CALLBACK* LPFNDLLFUNC1)(LPCTSTR,BOOL,BOOL,LPCTSTR);
LPFNDLLFUNC1 lpfnDllFunc1;
char *get_ver = "?OpenDatabase@CdbDBEngine@@QAE?
AVCdbDatabase@@PBDHH0@Z";

if(hDLL)
{
lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL,"?OpenDatabase@CdbDBEngine@@QAE?AVCdbDatabase@@PBDHH0@Z");


if (!lpfnDllFunc1)
{
// handle the error
FreeLibrary(hDLL);
return 0;
}
else
{
lpfnDllFunc1("TestDB.mdb",0L,FALSE,NULL);
printf("success");

}

I am getting unhandled exception in my.exe(ddao35.dll) 0xc0000005 Access violation

Any help?

Regards
Gopal


kirants

February 24th, 2006, 03:40 AM

gopal.srini, please start a new thread, since this seems to be a different problem and unrelated to the original question


gopal.srini

February 24th, 2006, 04:09 AM

ok..sorry..

Thanks
Gopal


wshcdr

February 24th, 2006, 01:09 PM

To use LoadLibrary(...),GetProcAddr(...) ,you must write a DEF file,


Bornish

February 25th, 2006, 09:56 AM

To use LoadLibrary(...),GetProcAddr(...) ,you must write a DEF file, :eek: This is somehow correct, if one needs undecorated names to be exported.
I thought using __declspec(dllexport) can eliminate the need of a *.def file. :blush:
I've tried exporting a function Test from a DLL that doesn't make use of a def file, so I've wrote this:extern "C" __declspec(dllexport) int __stdcall Test(int x) {
return ++x;
}The result was an export named _Test@4 (C++ decorated), thus extern "C" having no effect. I've tried several other variations... even using the obselete keyword _export in a *.c file instead of a *.cpp file. Still didn't find a way to export my function as Test without using a def file. It seems to be the only way to define alias names when exporting functions or to export only by ordinal (NONAME)... else you'll get the C++ decorated name _Test@4.
Conclusion:
If you don't care less about the name used in GetProcAddress, then you don't need a def file... else, use a def and keep your _declspec(dllexport) to avoid ambiguities. An article from MSDN recomends writing in a def file both the alias name and the decorated name to avoid ambiguities:EXPORTS
Test = _Test@4This way, when another namespace or class defines a function Test, the linker won't have a dilemma in choosing the function to export.
Best regards,


John E

February 25th, 2006, 10:21 AM

You've pretty much confirmed what I found myself. The only way to guarantee that the names don't get decorated is to put them in a .DEF file.

If you go the __declspec(dllexport) route - together with __declspec(dllimport) - then, providing you use Paul's suggestion of linking to the DLL's associated lib file, you can call the functions as though they weren't decorated - but in fact, they still are.

I assume that what the lib must do is simply to translate calls to each function's undecorated name into the corresponding call with the decorated name.

 

 

 

posted @ 2008-04-02 16:29 jolley 阅读(470) | 评论 (0)编辑 收藏

 

今天第一次写DLL

DLL里面有三种类型,win32 DLL, 标准MFC DLL,以及非标准MFC DLL

他们的区别是,win32 DLL里面主要是用C/C++编写的,不能调用MFC里面的函数之类的。

而标准MFC DLL里面可以使用MFC,但是却不能输出。

非标准MFC DLL里面可以使用MFC,并且可以输出。

下面是一个简单的例子

头文件

#pragma once

 

#ifdef DLLUSAGE_EXPORTS

     #define SIMPLE_API __declspec(dllexport)

#else

     #define SIMPLE_API __declspec(dllimport)

#endif

 

SIMPLE_API int AddTwoNumbers(int lhs, int rhs);

 

实现文件

SIMPLE_API int AddTwoNumbers(int lhs, int rhs)

{

Return lhs + rhs;

}

 

在生成 my.DLL 以后,再用

typedef int (*ADD)(int,int);

HINSTANCE instance = LoadLibrary("E:\\dllusage.dll");

if ( NULL == instance)

{

         MessageBox(NULL,"加载DLL错误",NULL,MB_OK);

         return 1;    

}

ADD myadd = (ADD)GetProcAddress(instance,TEXT("?AddTwoNumbers@@YAHHH@Z"));

if (NULL == myadd)

{

         MessageBox(NULL, "获取函数地址错误",NULL,MB_OK);

         return 2;

}

int result = myadd(5, 6);

 

这里值得说明的一点是:

在第二个参数里面采用的是AddTwoNumbersDLL里面的名称?AddTwoNumbers@@YAHHH@Z,相当于是DLL里面提供给我们调用的接口,如果不采用这样的写法,就会出现127错误

ERROR_PROC_NOT_FOUND

The specified procedure could not be found

因此我使用那种比较笨的办法,用view denpends来查找到AddTwoNumbersDLL里面的入口地址,然后再去调用这个这个入口地址。

或者是采用这样的方法:

Extern c

{

     SIMPLE_API int AddTwoNumbers(int lhs, int rhs);

}

这样一来的好处就是:

ADD myadd = (ADD)GetProcAddress(instance,TEXT("AddTwoNumbers "));

你会发现这样看起来要舒服一点,这个时候,你用view depends来查看DLL中该函数对应的地址,就会发现变成了AddTwoNumbers

posted @ 2008-04-02 16:23 jolley 阅读(302) | 评论 (1)编辑 收藏

// 摘自代码大全2第九章
创建类和子程序的步骤概述.
1 开始
2 创建类的总体设计
3 创建类中的子程序
4 复查并测试整个类
5 完成
其中3与4之间要进行交互,这种交互主要是针对审查子程序进行的,并且2与3之间也要进行交互,这种交互主要针对子程序在类中的总体设计.
一个思想是:细化跟迭代,并且即使反馈直到类功能和子程序功能都清晰,再到5.
创建一个类的步骤
1)创建类的总体设计:
设计一个类的过程中包含一些特有的设计任务--定义类的特定职责,定义类所要隐藏的秘密,以及精确地定义类的接口所代表的抽象概念,决定这个类是否要从其他类派生而来,以及是否允许其它类再从它派生,指出这个类中关键的公用方法,标识并设计出类所需用到的重要数据成员.
2)创建类中的子程序
在前述第一个步骤中标识出类的主要子程序之后,还需要创建这些子程序.在编写各个程序时通常还会引出更多的或重要,或次要的子程序,创建这些新加入的子程序的过程往往还会反过来波及类的总体设计
3)复审并测试整个类
通常情况下,子程序在创建的同时也经过了测试,在整个类可以工作之后,应该再对其整体进行复查和测试,以便发现那些在子程序的独立测试层次上无法测出的问题.
在创建类的过程中,2),3)还是要求反复进行的,直到类的总体设计是最优的.
创建子程序的步骤
创建子程序的过程中涉及到的主要活动: 设计子程序,检查设计,编写子程序的代码,检查代码.
1 开始
2 设计子程序(主要借助于伪代码)
3 检查设计(主要是检查伪代码)
4 编写子程序的代码
5 复审并测试代码
6 完成
其中2与3是要进行交互的,主要是保证伪代码的质量,4与5也是要进行交互的,这样主要保证子程序的质量.
伪代码
伪代码的指导原则:
1) 用类似英语的语句来精确描述特定的操作
2) 避免使用目标编程语言中的语法元素
3) 在本意的层面上编写代码,用伪代码去描述解决问题的方法的意图,而不是去写如何在目标语言中实现这个方法.
4) 在一个足够低的层次上编写代码,以便可以近乎自动地从它生成代码.
通过伪代码编程过程创建子程序
检查先决条件
在动手去做子程序本身的任何工作之前,应该先查看一下该子程序要做的工作是不是已经定义好了,是不是能够与整体设计相匹配.另外要结合项目的需求,检查这个子程序是否真正必须的,至少是间接需要的.
定义子程序要解决的问题
陈述出该子程序将要解决的问题,叙述要足够详细,以便能去创建这个子程序,如果高层的设计已经足够详细,那么这项工作可能已经完成了,在这个高层的设计里至少应该详细说明下列信息.
1) 这一子程序将要隐藏的信息
2) 传给这个子程序的各项输入
3) 从该子程序得到的输出
4) 在调用程序之前确保有关的前条件成立(输入数据的取值位于特定范围之中,有关的流已经初始化,文件已经打开或者关闭,缓冲区已经填满或者清空)
5) 在子程序将控制权交回调用方程序之前,确保其后条件的成立(如输出数据位于特定范围之内,流已经初始化,文件已经打开或者关闭,缓冲区已填满或清空)
其中4和5一般通过判断前驱和后继条件来进行的。前者是保证调用的条件是否成立,而后者是保证程序的返回值是否是合法的。
为子程序命名
一般地子程序已经有一个清晰的,无二义性的名字,如果在命名这个子程序的名字的时候,有点困难,那么就说明,对该子程序的设计不是很清楚,而要去改善设计了。
决定如何测试子程序
在编写一个子程序的时候,要想一想怎么才能测试它。这在以后的C/C++测试中都可以部署单元测试工具Xunit.
在标准库中搜寻可用的功能
想用提高代码的质量和生产率,有一个最重要的途径就是重用好的代码。
考虑错误处理
考虑在子程序中可能出错的环节,子程序可以用多种方式来处理错误,应该特别注意去选择处理错误的方式。
考虑效率问题
主要是两个方面的考虑,一是效率,而另一方面是性能。
研究算法和数据类型
如果在可用的程序库里没有所需的功能,它也许会在某本算法书中介绍过,决定从头开始编写一段复杂的代码之前,查一下算法书看看有什么可用的内容。如果采用一个已有明确定义的算法,则要保证这个算法正确地转换为你所用的编程语言。
编写伪代码
前面的那些步骤主要是为确定一个思路,这在真正编写程序的时候是很有帮助的,在完成前面的准备工作以后,就可以开始用高层次的伪代码来写程序。
一般是从写子程序的注释开始进行编制,主要是说明子程序的功能和目的。
考虑数据
在整个过程中的几个不同环节对子程序所用的数据进行设计。
检查伪代码
在写完伪代码并设计完数据之后,花上几分钟时间复杂你写的伪代码,然后抛揩这些代码,想想你该如何向别人解释这些代码。
在伪代码中试验一些想法,留下最好的想法
在你开始编写代码之前,应尽可能用伪代码去尝试更多的想法。
编写子程序的代码
1 以伪代码开始
2 写出子程序的声明
3 编写第一条和最后一条语句,然后将伪代码转换为高层次的注释。
4 每条注释下面填充代码
5 检查代码
6 收尾工作
7 完成
其中3,4,5可以按照需求进行重复。
写出子程序的声明
首先要写出子程序的接口声明,即C++中的函数声明
把伪代码转变为高层次的注释
接下来,把第一条和最后一条语句写出来,在C++中也就是"{"和"}".然后将伪代码转变成注释.
在每条注释下面填充代码
在伪代码注释中的每一句话下面填写代码。
检查代码是否需要进一步分解
方法1:把这段注释下面的代码重构(refactor)成一个新的子程序。
方法2:递归地应用伪代码编程过程。
检查代码
1) 在脑海里检查程序中的错误。
理解每行代码所起的作用,理解为什么需要这行代码,没有什么东西会仅仅因为它看上去可行就是正确的。
编译子程序
完成检查之后,就可以编译这个程序了。
最大地发挥编译子程序所产生的指导建议
1)把编译器的警告级别调到最高,通过让编译器来检测错误,你可以很容易地查出大量细微的错误。
2)使用验证工具,可以通过使用类似lint这样的工具来对C语言这类语言的编译器所做的检查结果进行补充检查。
3)消除产生错误消息和警告的所有根源。
在调试器中逐步执行代码
程序编译通过了之后,要在调试器中逐行执行,以确保每行代码都在按照你所期望的方式执行。
测试代码
使用你在开发该子程序期间计划写的或者已写成的测试用例来测试代码。你可能需要开发一些脚手架来支持你的测试用例
消除程序中的错误
一旦检测到错误,就一定要把它除掉。
收尾工作
检查子程序的接口
确定所有的输入,输出数据都参与了计算,并且所有的参数也都用到了。
检查整体的设计质量
检查子程序中的变量
检查子程序的语句和逻辑
检查子程序的布局
检查子程序的文档
除去冗余的注释。
小结:
之前一直在写程序,但是发现时不时思路很乱,也没有有层次地,有系统地去思考这些类和子程序的设计,只是去实现一个功能,并且能够达到所要的目的就可以了,后来发现经常出问题,很常见的就是考虑不周全,在编制代码以后,才开始反悔,后悔当初的设计,然后对程序产生了消极的情绪,让我感觉不爽,看了代码大全,发现提供了可行的方法.而且思路比以前清晰多了,感觉这个方法很有效,所以记录在这里.


 

posted @ 2008-03-01 12:09 jolley 阅读(980) | 评论 (0)编辑 收藏

仅列出标题
共4页: 1 2 3 4